Wip setream carving
This commit is contained in:
parent
438c9d726c
commit
f5dad284e6
11 changed files with 287 additions and 387 deletions
137
main.cpp
137
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());
|
||||
|
||||
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";
|
||||
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";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue