Wip setream carving

This commit is contained in:
Carl Philipp Klemm 2023-06-29 19:25:31 +02:00
parent 438c9d726c
commit f5dad284e6
11 changed files with 287 additions and 387 deletions

View file

@ -5,7 +5,7 @@ find_package(OpenCV REQUIRED)
set(CMAKE_CXX_STANDARD 17)
set(SRC_FILES main.cpp yolo.cpp tokenize.cpp log.cpp seamcarvingvert.cpp seamcarvinghoriz.cpp seamcarving.cpp utils.cpp intelligentroi.cpp)
set(SRC_FILES main.cpp yolo.cpp tokenize.cpp log.cpp seamcarving.cpp utils.cpp intelligentroi.cpp)
add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} -ltbb)

80
classes.txt Normal file
View file

@ -0,0 +1,80 @@
person, 10
bicycle, 4
car, 3
motorcycle, 4
airplane, 4
bus, 4
train, 4
truck, 3
boat, 4
traffic light, 1
fire hydrant, 1
stop sign, 1
parking meter, 1
bench, 2
bird, 5
cat, 6
dog, 5
horse, 4
sheep, 5
cow, 4
elephant, 5
bear, 5
zebra, 5
giraffe, 5
backpack, 3
umbrella, 3
handbag, 3
tie, 3
suitcase, 2
frisbee, 3
skis, 3
snowboard, 3
sports ball, 3
kite, 4
baseball bat, 3
baseball glove, 3
skateboard, 3
surfboard, 3
tennis racket, 3
bottle, 2
wine glass, 2
cup, 2
fork, 1
knife, 1
spoon, 1
bowl, 1
banana, 1
apple, 1
sandwich,1
orange, 1
broccoli, 1
carrot, 1
hot dog, 1
pizza, 1
donut, 2
cake, 2
chair, 1
couch, 1
potted plant, 1
bed, 1
dining table, 1
toilet, 1
tv, 1
laptop, 1
mouse, 1
remote, 1
keyboard, 1
cell phone, 1
microwave, 1
oven, 1
toaster, 1
sink, 1
refrigerator, 1
book, 1
clock, 1
vase, 1
scissors, 1
teddy bear, 1
hair drier, 1
toothbrush, 1

View file

@ -84,12 +84,21 @@ cv::Rect InteligentRoi::getCropRectangle(const std::vector<Yolo::Detection>& det
{
int priority = detections[i].priority;
if(detections[i].class_id == personId)
corners.push_back({detections[i].box.tl()+cv::Point2i(detections[i].box.width/2, 0), priority+1});
{
corners.push_back({detections[i].box.tl()+cv::Point2i(detections[i].box.width/2, 0), priority+2});
corners.push_back({detections[i].box.tl(), priority+1});
corners.push_back({detections[i].box.br(), priority});
corners.push_back({detections[i].box.tl()+cv::Point2i(detections[i].box.width, 0), priority+1});
corners.push_back({detections[i].box.br()+cv::Point2i(0-detections[i].box.width, 0), priority});
}
else
{
corners.push_back({detections[i].box.tl(), priority});
corners.push_back({detections[i].box.br(), priority});
corners.push_back({detections[i].box.tl()+cv::Point2i(detections[i].box.width, 0), priority});
corners.push_back({detections[i].box.br()+cv::Point2i(0-detections[i].box.width, 0), priority});
}
}
return maxRect(imageSize, corners);
}

125
main.cpp
View file

@ -10,6 +10,7 @@
#include "options.h"
#include "utils.h"
#include "intelligentroi.h"
#include "seamcarving.h"
const Yolo::Detection* pointInDetectionHoriz(int x, const std::vector<Yolo::Detection>& detections, const Yolo::Detection* ignore = nullptr)
{
@ -141,26 +142,74 @@ std::vector<std::pair<cv::Mat, bool>> cutImageIntoVertRegions(cv::Mat& image, co
return out;
}
bool seamCarveResize(cv::Mat& image, const std::vector<Yolo::Detection>& detections, double targetAspectRatio = 1.0)
cv::Mat assembleFromSlicesVert(const std::vector<std::pair<cv::Mat, bool>>& slices)
{
assert(!slices.empty());
int rows = 0;
for(const std::pair<cv::Mat, bool>& slice : slices)
rows += slice.first.rows;
cv::Mat image(slices[0].first.cols, rows, slices[0].first.type());
Log(Log::DEBUG)<<__func__<<" assembled image size "<<image.size;
int row = 0;
for(const std::pair<cv::Mat, bool>& slice : slices)
{
cv::Rect rect(0, row, slice.first.cols, slice.first.rows);
slice.first.copyTo(image(rect));
row += slice.first.rows;
}
return image;
}
cv::Mat assembleFromSlicesHoriz(const std::vector<std::pair<cv::Mat, bool>>& slices)
{
assert(!slices.empty());
int cols = 0;
for(const std::pair<cv::Mat, bool>& slice : slices)
cols += slice.first.cols;
cv::Mat image(cols, slices[0].first.rows, slices[0].first.type());
int col = 0;
for(const std::pair<cv::Mat, bool>& slice : slices)
{
cv::Rect rect(col, 0, slice.first.cols, slice.first.rows);
slice.first.copyTo(image(rect));
col += slice.first.cols;
}
return image;
}
bool seamCarveResize(cv::Mat& image, std::vector<Yolo::Detection> detections, double targetAspectRatio = 1.0)
{
detections.erase(std::remove_if(detections.begin(), detections.end(), [](const Yolo::Detection& detection){return detection.priority < 3;}), detections.end());
double aspectRatio = image.cols/static_cast<double>(image.rows);
Log(Log::DEBUG)<<"Image size "<<image.size()<<" aspect ratio "<<aspectRatio<<" target aspect ratio "<<targetAspectRatio;
bool vertical = false;
cv::Mat workImage;
if(aspectRatio > targetAspectRatio)
vertical = true;
int requiredLines = 0;
if(!vertical)
requiredLines = workImage.rows*targetAspectRatio - workImage.cols;
requiredLines = image.rows*targetAspectRatio - image.cols;
else
requiredLines = workImage.cols/targetAspectRatio - workImage.rows;
requiredLines = image.cols/targetAspectRatio - image.rows;
Log(Log::DEBUG)<<__func__<<' '<<requiredLines<<" lines are required in "<<(vertical ? "vertical" : "horizontal")<<" direction";
if(!vertical)
{
std::vector<std::pair<cv::Mat, bool>> slices = cutImageIntoHorzRegions(image, detections);
Log(Log::DEBUG)<<"Image has "<<slices.size()<<" slices";
int totalResizableSize = 0;
for(const std::pair<cv::Mat, bool>& slice : slices)
{
@ -168,30 +217,68 @@ bool seamCarveResize(cv::Mat& image, const std::vector<Yolo::Detection>& detecti
totalResizableSize += slice.first.cols;
}
std::vector<int> seamsForSlice(slices.size());
if(totalResizableSize < requiredLines/10)
{
Log(Log::WARN)<<"Unable to seam carve as there are only "<<totalResizableSize<<" unfrozen cols";
return false;
}
for(size_t i = 0; i < slices.size(); ++i)
{
seamsForSlice[i] = (static_cast<double>(slices[i].first.cols)/totalResizableSize)*requiredLines;
if(slices[i].second)
{
int seamsForSlice = (static_cast<double>(slices[i].first.cols)/totalResizableSize)*requiredLines;
bool ret = SeamCarving::strechImage(image, seamsForSlice, true);
if(!ret)
return false;
}
}
image = assembleFromSlicesHoriz(slices);
}
else
{
int totalResizableSize = 0;
std::vector<std::pair<cv::Mat, bool>> slices = cutImageIntoVertRegions(image, detections);
Log(Log::DEBUG)<<"Image has "<<slices.size()<<" slices";
int totalResizableSize = 0;
for(const std::pair<cv::Mat, bool>& slice : slices)
{
if(slice.second)
totalResizableSize += slice.first.rows;
}
if(totalResizableSize < requiredLines/10)
{
Log(Log::WARN)<<"Unable to seam carve as there are only "<<totalResizableSize<<" unfrozen rows";
return false;
}
for(size_t i = 0; i < slices.size(); ++i)
{
if(slices[i].second)
{
int seamsForSlice = (static_cast<double>(slices[i].first.rows)/totalResizableSize)*requiredLines;
bool ret = SeamCarving::strechImageVert(image, seamsForSlice, true);
if(!ret)
return false;
}
}
image = assembleFromSlicesVert(slices);
}
return true;
}
void drawDebugInfo(cv::Mat &image, const cv::Rect& rect, const std::vector<Yolo::Detection>& detections)
{
for(const Yolo::Detection& detection : detections)
{
cv::rectangle(image, detection.box, detection.color, 4);
cv::rectangle(image, detection.box, detection.color, 3);
std::string label = detection.className + ' ' + std::to_string(detection.confidence).substr(0, 4);
cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_DUPLEX, 3, 2, 0);
cv::Rect textBox(detection.box.x, detection.box.y - 80, labelSize.width + 10, labelSize.height + 20);
cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_DUPLEX, 1, 1, 0);
cv::Rect textBox(detection.box.x, detection.box.y - 40, labelSize.width + 10, labelSize.height + 20);
cv::rectangle(image, textBox, detection.color, cv::FILLED);
cv::putText(image, label, cv::Point(detection.box.x + 5, detection.box.y - 10), cv::FONT_HERSHEY_DUPLEX, 3, cv::Scalar(0, 0, 0), 2, 0);
cv::putText(image, label, cv::Point(detection.box.x + 5, detection.box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 1, 0);
}
cv::rectangle(image, rect, cv::Scalar(0, 0, 255), 8);
@ -221,6 +308,10 @@ int main(int argc, char* argv[])
for(const std::filesystem::path& path : config.imagePaths)
getImageFiles(path, imagePaths);
Log(Log::DEBUG)<<"Images:";
for(const::std::filesystem::path& path: imagePaths)
Log(Log::DEBUG)<<path;
if(imagePaths.empty())
{
Log(Log::ERROR)<<"no image was found\n";
@ -257,6 +348,7 @@ int main(int argc, char* argv[])
if(std::max(image.cols, image.rows) > 1024)
{
Log(Log::DEBUG, false)<<"Image is "<<image.size();
if(image.cols > image.rows)
{
double ratio = 1024.0/image.cols;
@ -267,6 +359,7 @@ int main(int argc, char* argv[])
double ratio = 1024.0/image.rows;
cv::resize(image, image, {static_cast<int>(image.cols*ratio), 1024}, 0, 0, cv::INTER_CUBIC);
}
Log(Log::DEBUG)<<" resized to "<<image.size();
}
std::vector<Yolo::Detection> detections = yolo.runInference(image);
@ -275,19 +368,27 @@ int main(int argc, char* argv[])
for(const Yolo::Detection& detection : detections)
Log(Log::DEBUG)<<detection.class_id<<": "<<detection.className<<" at "<<detection.box<<" with prio "<<detection.priority;
if(config.seamCarving)
{
Log(Log::INFO)<<"Trying seam resize";
seamCarveResize(image, detections, 1);
}
cv::Rect crop = intRoi.getCropRectangle(detections, image.size());
if(config.debug)
{
cv::Mat debugImage = image.clone();
drawDebugInfo(debugImage, crop, detections);
bool ret = cv::imwrite(debugOutputPath/path.filename(), debugImage);
if(!ret)
Log(Log::WARN)<<"could not save debug image to "<<debugOutputPath/path.filename()<<" skipping";
}
cv::Mat croppedImage = image(crop);
cv::Mat resizedImage;
cv::resize(croppedImage, resizedImage, {512, 512}, 0, 0, cv::INTER_CUBIC);
ret = cv::imwrite(config.outputDir/path.filename(), resizedImage);
bool ret = cv::imwrite(config.outputDir/path.filename(), resizedImage);
if(!ret)
Log(Log::WARN)<<"could not save image to "<<config.outputDir/path.filename()<<" skipping";
}

View file

@ -9,7 +9,7 @@
const char *argp_program_version = "AIImagePreprocesses";
const char *argp_program_bug_address = "<carl@uvos.xyz>";
static char doc[] = "Application that trainsforms images into formats, sizes and aspect ratios required for ai training";
static char args_doc[] = "[IMAGES]";
static char args_doc[] = "FILE(S)";
static struct argp_option options[] =
{
@ -19,7 +19,7 @@ static struct argp_option options[] =
{"classes", 'c', "[FILENAME]", 0, "classes text file to use" },
{"out", 'o', "[DIRECTORY]", 0, "directory whre images are to be saved" },
{"debug", 'd', 0, 0, "output debug images" },
{"seam-carving", 's', 0, 0, "model to train: "}
{"seam-carving", 's', 0, 0, "model to train"}
};
struct Config

View file

@ -1,253 +1,63 @@
#include "seamcarving.h"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#if __cplusplus >= 201703L
#include <filesystem>
#endif
#include <cfloat>
#include <vector>
#include "log.h"
SeamCarving::SeamCarving(const cv::Mat &img, int seams, bool grow) :
image(img), seams(seams), grow(grow) {}
void SeamCarving::init()
bool SeamCarving::strechImage(cv::Mat& image, int seams, bool grow, std::vector<std::vector<int>>* seamsVect)
{
cv::Mat newFrame = image.clone();
for(int i = 0; i < seams; i++)
{
Log(Log::DEBUG)<<"Seam "<<i<<" of "<<seams;
//Gradient Magnitude for intensity of image.
cv::Mat gradientMagnitude = computeGradientMagnitude(newFrame);
cv::Mat gradientMagnitude = computeGradientMagnitude(image);
//Use DP to create the real energy map that is used for path calculation.
// Strictly using vertical paths for testing simplicity.
cv::Mat pathIntensityMat = computePathIntensityMat(gradientMagnitude);
if(pathIntensityMat.rows == 0 && pathIntensityMat.cols == 0)
{
finalImage = image;
break;
}
return false;
std::vector<int> seam = getLeastImportantPath(pathIntensityMat);
vecSeams.push_back(seam);
if(seamsVect)
seamsVect->push_back(seam);
newFrame = removeLeastImportantPath(newFrame,seam);
if(newFrame.rows == 0 && newFrame.cols == 0)
{
finalImage = image;
break;
}
}
if (grow)
{
cv::Mat growMat = image.clone();
for (int i = 0; i < vecSeams.size(); i++)
{
growMat = addLeastImportantPath(growMat,vecSeams[i]);
}
finalImage = growMat;
}
if(!grow)
image = removeLeastImportantPath(image, seam);
else
{
finalImage = newFrame;
image = addLeastImportantPath(image, seam);
if(image.rows == 0 && image.cols == 0)
return false;
}
sliderPos = seams;
return true;
}
void SeamCarving::computeNewFinalImage(int sliderPos)
bool SeamCarving::strechImageVert(cv::Mat& image, int seams, bool grow, std::vector<std::vector<int>>* seamsVect)
{
if(sliderPos == 0)
{
finalImage = image;
return;
}
if(sliderPos < 1 || sliderPos >= sliderMax-1)
{
return;
}
if(sliderPos > vecSeams.size())
{
cv::Mat newFrame = finalImage.clone();
for(int i = vecSeams.size()-1; i < sliderPos; i++)
{
//Gradient Magnitude for intensity of image.
cv::Mat gradientMagnitude = computeGradientMagnitude(newFrame);
//Use DP to create the real energy map that is used for path calculation.
// Strictly using vertical paths for testing simplicity.
cv::Mat pathIntensityMat = computePathIntensityMat(gradientMagnitude);
if(pathIntensityMat.rows == 0 && pathIntensityMat.cols == 0)
{
finalImage = image;
break;
}
std::vector<int> seam = getLeastImportantPath(pathIntensityMat);
vecSeams.push_back(seam);
newFrame = removeLeastImportantPath(newFrame,seam);
if(newFrame.rows == 0 && newFrame.cols == 0)
{
finalImage = image;
break;
}
}
if (grow)
{
cv::Mat growMat = image.clone();
for (int i = 0; i < vecSeams.size(); i++)
{
growMat = addLeastImportantPath(growMat,vecSeams[i]);
}
finalImage = growMat;
}
else
{
finalImage = newFrame;
}
}
else if (sliderPos < vecSeams.size())
{
cv::Mat newFrame = image.clone();
for(int i = 0; i < sliderPos; i++) // TODO check if it is faster to add seams back (probably not)
{
if (grow)
{
newFrame = addLeastImportantPath(newFrame,vecSeams[i]);
}
else
{
newFrame = removeLeastImportantPath(newFrame,vecSeams[i]);
}
if(newFrame.rows == 0 && newFrame.cols == 0)
{
finalImage = image;
break;
}
}
finalImage = newFrame;
}
image = image.t();
bool ret = strechImage(image, seams, grow, seamsVect);
image = image.t();
return ret;
}
const cv::Mat& SeamCarving::getFinalImage()
bool SeamCarving::strechImageWithSeamsImage(cv::Mat& image, cv::Mat& seamsImage, int seams, bool grow)
{
return finalImage;
}
std::vector<std::vector<int>> seamsVect;
seamsImage = image.clone();
void SeamCarving::showSeamsImg()
{
cv::Mat seamsFrame = image.clone();
//std::cout << "sliderPos: " << sliderPos << std::endl;
for(int i = 0; i < sliderPos; i++)
{
seamsFrame = drawSeam(seamsFrame, vecSeams[i]);
}
cv::imwrite("output/seams_image.jpg", seamsFrame);
cv::imshow( "Image Seams", seamsFrame);
}
bool ret = SeamCarving::strechImage(image, seams, grow, &seamsVect);
if(!ret)
return false;
static void onChange( int pos, void* object )
{
SeamCarving* sc = (SeamCarving*)(object);
/*if(sc->getBlockUpdateStatus()) {
return;
}*/
sc->computeNewFinalImage(pos);
imshow("Final Image", sc->getFinalImage());
#if DEBUG
sc->showSeamsImg();
#endif
}
static void onMouse( int event, int x, int y, int, void* object)
{
SeamCarving* sc = (SeamCarving*)(object);
if( event == cv::EVENT_LBUTTONDOWN ||
event == cv::EVENT_RBUTTONDOWN ||
event == cv::EVENT_MBUTTONDOWN
)
{
sc->setBlockUpdate(true);
}
else if(event == cv::EVENT_LBUTTONUP ||
event == cv::EVENT_RBUTTONUP ||
event == cv::EVENT_MBUTTONUP)
{
sc->setBlockUpdate(false);
}
}
void SeamCarving::setBlockUpdate(bool bUpdate)
{
blockUpdate = bUpdate;
}
bool SeamCarving::getBlockUpdateStatus()
{
return blockUpdate;
}
void SeamCarving::showImage()
{
#if __cplusplus >= 201703L
if(!std::filesystem::exists("output"))
{
std::filesystem::create_directory("output");
}
#endif
if( image.empty() )
{
std::cout << "Could not open raw image" << std::endl ;
return;
}
namedWindow( "Raw Image", cv::WINDOW_AUTOSIZE );
cv::imshow( "Raw Image", image );
if( finalImage.empty() )
{
std::cout << "Could not open final image" << std::endl ;
return;
}
#if DEBUG
namedWindow( "gradient Image", cv::WINDOW_AUTOSIZE );
cv::Mat gradient = computeGradientMagnitude(image);
cv::Mat u8_image;
gradient.convertTo(u8_image, CV_8U);
cv::imwrite("output/gradient_image.jpg", u8_image);
cv::imshow("gradient Image", u8_image);
namedWindow( "intensity Image", cv::WINDOW_AUTOSIZE );
cv::Mat u8_image2;
cv::Mat intensityMat = computePathIntensityMat(gradient);
cv::Mat dst;
cv::normalize(intensityMat, dst, 0, 255, cv::NORM_MINMAX);
dst.convertTo(u8_image2, CV_8U);
cv::imwrite("output/intensity_image.jpg", u8_image2);
cv::imshow( "intensity Image", u8_image2);
//cv::Mat engImg = GetEnergyImg(image);
//namedWindow("energy Image", cv::WINDOW_AUTOSIZE);
//cv::Mat u8_image3;
//engImg.convertTo(u8_image3, CV_8U);
//cv::imshow( "energy Image", u8_image3);
namedWindow("Image Seams", cv::WINDOW_AUTOSIZE);
showSeamsImg();
#endif
namedWindow( "Final Image", cv::WINDOW_AUTOSIZE );
cv::createTrackbar("Seams", "Final Image", &sliderPos, sliderMax, onChange, this);
//cv::setMouseCallback("Final Image", onMouse, this );
cv::imwrite("output/final_image.jpg", finalImage);
cv::imshow("Final Image", finalImage);
cv::waitKey(0);
for(size_t i = 0; i < seamsVect.size(); ++i)
seamsImage = drawSeam(seamsImage, seamsVect[i]);
return true;
}
cv::Mat SeamCarving::GetEnergyImg(const cv::Mat &img)
@ -392,9 +202,7 @@ cv::Mat SeamCarving::removeLeastImportantPath(const cv::Mat &original, const std
cv::Size size = cv::Size(orgSize.width-1, orgSize.height);
cv::Mat newMat = cv::Mat(size, original.type());
unsigned char *rawOrig = original.data;
unsigned char *rawOutput = newMat.data;
for(int row = 0; row < seam.size(); row++)
for(size_t row = 0; row < seam.size(); row++)
{
removePixel(original, newMat, row, seam[row]);
}
@ -460,9 +268,7 @@ cv::Mat SeamCarving::addLeastImportantPath(const cv::Mat &original, const std::v
cv::Size size = cv::Size(orgSize.width+1, orgSize.height);
cv::Mat newMat = cv::Mat(size, original.type());
unsigned char *rawOrig = original.data;
unsigned char *rawOutput = newMat.data;
for(int row = 0; row < seam.size(); row++)
for(size_t row = 0; row < seam.size(); row++)
{
//std::cout << "row: " << row << ", col: " << seam[row] << std::endl;
addPixel(original, newMat, row, seam[row]);
@ -518,3 +324,18 @@ void SeamCarving::addPixel(const cv::Mat &original, cv::Mat &outputMat, int row,
rawOutput[newRowStart + leftPixel*channels+2] = (unsigned char) ((byte3 + byte3L)/2);
}
}
cv::Mat SeamCarving::drawSeam(const cv::Mat &frame, const std::vector<int> &seam)
{
cv::Mat retMat = frame.clone();
for(int row = 0; row < frame.rows; row++)
{
for(int col = 0; col < frame.cols; col++)
{
retMat.at<cv::Vec3b>(row, seam[row])[0] = 0;
retMat.at<cv::Vec3b>(row, seam[row])[1] = 255;
retMat.at<cv::Vec3b>(row, seam[row])[2] = 0;
}
}
return retMat;
}

View file

@ -1,61 +1,24 @@
#ifndef __SEAM__CARVING_HPP__
#define __SEAM__CARVING_HPP__
#pragma once
#include <opencv2/core/core.hpp>
#define DEBUG 0
#include <vector>
class SeamCarving {
public:
void showImage();
const cv::Mat& getFinalImage();
virtual void computeNewFinalImage(int pos);
void setBlockUpdate(bool bUpdate);
bool getBlockUpdateStatus();
virtual void showSeamsImg();
protected:
SeamCarving(const cv::Mat &img, int seams, bool grow);
void init();
virtual cv::Mat drawSeam(const cv::Mat &frame, const std::vector<int> &seam) = 0;
cv::Mat image;
cv::Mat finalImage;
int seams;
bool grow;
int sliderMax;
int sliderPos;
std::vector<std::vector<int>> vecSeams;
private:
cv::Mat GetEnergyImg(const cv::Mat &img);
cv::Mat computeGradientMagnitude(const cv::Mat &frame);
float intensity(float currIndex, int start, int end);
cv::Mat computePathIntensityMat(const cv::Mat &rawEnergyMap);
std::vector<int> getLeastImportantPath(const cv::Mat &importanceMap);
cv::Mat removeLeastImportantPath(const cv::Mat &original, const std::vector<int> &seam);
void removePixel(const cv::Mat &original, cv::Mat &outputMap, int row, int minCol);
cv::Mat addLeastImportantPath(const cv::Mat &original, const std::vector<int> &seam);
void addPixel(const cv::Mat &original, cv::Mat &outputMat, int row, int minCol);
bool blockUpdate = false;
};
class SeamCarvingHorizontal : public SeamCarving
class SeamCarving
{
public:
SeamCarvingHorizontal(char* fileName, int seams=100, bool grow=false);
protected:
virtual cv::Mat drawSeam(const cv::Mat &frame, const std::vector<int> &seam) override;
};
private:
static cv::Mat GetEnergyImg(const cv::Mat &img);
static cv::Mat computeGradientMagnitude(const cv::Mat &frame);
static float intensity(float currIndex, int start, int end);
static cv::Mat computePathIntensityMat(const cv::Mat &rawEnergyMap);
static std::vector<int> getLeastImportantPath(const cv::Mat &importanceMap);
static cv::Mat removeLeastImportantPath(const cv::Mat &original, const std::vector<int> &seam);
static void removePixel(const cv::Mat &original, cv::Mat &outputMap, int row, int minCol);
static cv::Mat addLeastImportantPath(const cv::Mat &original, const std::vector<int> &seam);
static void addPixel(const cv::Mat &original, cv::Mat &outputMat, int row, int minCol);
static cv::Mat drawSeam(const cv::Mat &frame, const std::vector<int> &seam);
class SeamCarvingVertical : public SeamCarving {
public:
SeamCarvingVertical(char* fileName, int seams=100, bool grow=false);
virtual void computeNewFinalImage(int pos) override;
#if DEBUG
virtual void showSeamsImg() override;
#endif
protected:
virtual cv::Mat drawSeam(const cv::Mat &frame, const std::vector<int> &seam) override;
public:
static bool strechImage(cv::Mat& image, int seams, bool grow, std::vector<std::vector<int>>* seamsVect = nullptr);
static bool strechImageVert(cv::Mat& image, int seams, bool grow, std::vector<std::vector<int>>* seamsVect = nullptr);
static bool strechImageWithSeamsImage(cv::Mat& image, cv::Mat& seamsImage, int seams, bool grow);
};
#endif // __SEAM__CARVING_HPP__

View file

@ -1,28 +0,0 @@
#include "seamcarving.h"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <cfloat>
cv::Mat SeamCarvingHorizontal::drawSeam(const cv::Mat &frame, const std::vector<int> &seam)
{
cv::Mat retMat = frame.clone();
for(int row = 0; row < frame.rows; row++)
{
for(int col = 0; col < frame.cols; col++)
{
retMat.at<cv::Vec3b>(row, seam[row])[0] = 0;
retMat.at<cv::Vec3b>(row, seam[row])[1] = 255;
retMat.at<cv::Vec3b>(row, seam[row])[2] = 0;
}
}
return retMat;
}
SeamCarvingHorizontal::SeamCarvingHorizontal(char* fileName, int seams, bool grow) :
SeamCarving( cv::imread(fileName, cv::IMREAD_COLOR), seams, grow)
{
sliderMax = image.cols;
init();
}

View file

@ -1,51 +0,0 @@
#include "seamcarving.h"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <cfloat>
SeamCarvingVertical::SeamCarvingVertical(char* fileName, int seams, bool grow) :
SeamCarving( cv::imread(fileName, cv::IMREAD_COLOR), seams, grow)
{
sliderMax = image.rows;
cv::Mat oldImage = image;
image = image.t();
init();
image = oldImage;
finalImage = finalImage.t();
}
cv::Mat SeamCarvingVertical::drawSeam(const cv::Mat &frame, const std::vector<int> &seam)
{
cv::Mat retMat = frame.clone();
for(int col = 0; col < frame.cols; col++)
{
for(int row = 0; row < frame.rows; row++)
{
retMat.at<cv::Vec3b>(seam[col], col)[0] = 0;
retMat.at<cv::Vec3b>(seam[col], col)[1] = 255;
retMat.at<cv::Vec3b>(seam[col], col)[2] = 0;
}
}
return retMat;
}
void SeamCarvingVertical::computeNewFinalImage(int pos)
{
cv::Mat oldImage = image;
image = image.t();
SeamCarving::computeNewFinalImage(pos);
image = oldImage;
finalImage = finalImage.t();
}
#if DEBUG
void SeamCarvingVertical::showSeamsImg()
{
cv::Mat oldImage = this->image;
this->image = this->image.t();
SeamCarving::showImage();
this->image = oldImage;
}
#endif

View file

@ -22,6 +22,7 @@ Yolo::Yolo(const std::filesystem::path &onnxModelPath, const cv::Size &modelInpu
if(classesTxtFilePath.empty())
{
Log(Log::INFO)<<"Using builtin classes";
loadClasses(rdefaultClassesData);
}
else
@ -31,10 +32,14 @@ Yolo::Yolo(const std::filesystem::path &onnxModelPath, const cv::Size &modelInpu
}
if(!modelPath.empty())
{
net = cv::dnn::readNetFromONNX(modelPath);
}
else
{
Log(Log::INFO)<<"Using builtin yolo model";
net = cv::dnn::readNetFromONNX((const char*)rdefaultModelData, rdefaultModelSize);
}
if(runWithOCl)
{
std::cout << "\nRunning on OCV" << std::endl;

BIN
yolov8x.onnx Normal file

Binary file not shown.