Wip setream carving
This commit is contained in:
parent
438c9d726c
commit
f5dad284e6
|
@ -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
80
classes.txt
Normal 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
|
|
@ -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
125
main.cpp
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
275
seamcarving.cpp
275
seamcarving.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
7
yolo.cpp
7
yolo.cpp
|
@ -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
BIN
yolov8x.onnx
Normal file
Binary file not shown.
Loading…
Reference in a new issue