From b3c2d585aed27f03e11b9d4aed0529be29d5b3cf Mon Sep 17 00:00:00 2001 From: uvos Date: Fri, 30 Jun 2023 00:48:56 +0200 Subject: [PATCH] paralleization wip --- intelligentroi.cpp | 56 +++---- intelligentroi.h | 4 +- main.cpp | 367 +++++++++++++++++++++------------------------ options.h | 5 +- seamcarving.cpp | 35 +++-- 5 files changed, 230 insertions(+), 237 deletions(-) diff --git a/intelligentroi.cpp b/intelligentroi.cpp index 03cebd6..ddb4606 100644 --- a/intelligentroi.cpp +++ b/intelligentroi.cpp @@ -31,11 +31,12 @@ void InteligentRoi::slideRectToPoint(cv::Rect& rect, const cv::Point2i& point) } } -cv::Rect InteligentRoi::maxRect(const cv::Size2i& imageSize, std::vector> mustInclude) +cv::Rect InteligentRoi::maxRect(bool& incompleate, const cv::Size2i& imageSize, std::vector> mustInclude) { - int radius = std::min(imageSize.height, imageSize.width)/2; + incompleate = false; + int diameter = std::min(imageSize.height, imageSize.width); cv::Point2i point(imageSize.width/2, imageSize.height/2); - cv::Rect candiate(point.x-radius, point.y-radius, radius*2, radius*2); + cv::Rect candiate(point.x-diameter/2, point.y-diameter/2, diameter, diameter); std::sort(mustInclude.begin(), mustInclude.end(), [&point](const std::pair& a, const std::pair& b){return compPointPrio(a, b, point);}); @@ -43,8 +44,9 @@ cv::Rect InteligentRoi::maxRect(const cv::Size2i& imageSize, std::vector radius || includeRect.height-2 > radius) + if(includeRect.width-2 > diameter || includeRect.height-2 > diameter) { + incompleate = true; slideRectToPoint(candiate, mustInclude.back().first); mustInclude.pop_back(); Log(Log::DEBUG)<<"cant fill"; @@ -52,7 +54,9 @@ cv::Rect InteligentRoi::maxRect(const cv::Size2i& imageSize, std::vector& includePoint : mustInclude) @@ -75,34 +79,30 @@ InteligentRoi::InteligentRoi(const Yolo& yolo) personId = yolo.getClassForStr("person"); } -cv::Rect InteligentRoi::getCropRectangle(const std::vector& detections, const cv::Size2i& imageSize) +bool InteligentRoi::getCropRectangle(cv::Rect& out, const std::vector& detections, const cv::Size2i& imageSize) { - if(!detections.empty()) + std::vector> corners; + for(size_t i = 0; i < detections.size(); ++i) { - std::vector> corners; - for(size_t i = 0; i < detections.size(); ++i) + int priority = detections[i].priority; + if(detections[i].class_id == personId) { - 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+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}); - } + 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); } - Log(Log::DEBUG)<<"Using center crop as there are no detections"; - return maxRect(imageSize); + bool incompleate; + out = maxRect(incompleate, imageSize, corners); + return incompleate; } diff --git a/intelligentroi.h b/intelligentroi.h index de09402..188cd9e 100644 --- a/intelligentroi.h +++ b/intelligentroi.h @@ -10,9 +10,9 @@ private: int personId; static bool compPointPrio(const std::pair& a, const std::pair& b, const cv::Point2i& center); static void slideRectToPoint(cv::Rect& rect, const cv::Point2i& point); - static cv::Rect maxRect(const cv::Size2i& imageSize, std::vector> mustInclude = {}); + static cv::Rect maxRect(bool& incompleate, const cv::Size2i& imageSize, std::vector> mustInclude = {}); public: InteligentRoi(const Yolo& yolo); - cv::Rect getCropRectangle(const std::vector& detections, const cv::Size2i& imageSize); + bool getCropRectangle(cv::Rect& out, const std::vector& detections, const cv::Size2i& imageSize); }; diff --git a/main.cpp b/main.cpp index 27fa9ba..640cf2e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,13 @@ #include #include +#include #include #include +#include #include +#include #include +#include #include "yolo.h" #include "log.h" @@ -17,10 +21,10 @@ const Yolo::Detection* pointInDetectionHoriz(int x, const std::vector= x) { if(!inDetection || detection.box.br().x > inDetection->box.br().x) inDetection = &detection; @@ -33,6 +37,8 @@ bool findRegionEndpointHoriz(int& x, const std::vector& detecti { const Yolo::Detection* inDetection = pointInDetectionHoriz(x, detections); + Log(Log::DEBUG, false)<<__func__<<" point "<& detecti x = closest->box.x; else x = imgSizeX; + + Log(Log::DEBUG)<<" is not in any box and will be moved to "<className : "null")<<") is"; return false; } else { x = inDetection->box.br().x; + Log(Log::DEBUG, false)<<" is in a box and will be moved to its end "<box.br().x > x) + { + Log(Log::DEBUG)<<"it is again in a box"; return findRegionEndpointHoriz(x, detections, imgSizeX); + } else + { + Log(Log::DEBUG)<<"it is not in a box"; return true; + } } } @@ -65,106 +80,25 @@ std::vector> cutImageIntoHorzRegions(cv::Mat& image, co { std::vector> out; + std::cout<<__func__<<' '<& detections, const Yolo::Detection* ignore = nullptr) -{ - const Yolo::Detection* inDetection = nullptr; - for(const Yolo::Detection& detection : detections) - { - if(!ignore || ignore != &detection) - continue; - - if(detection.box.y <= y && detection.box.y+detection.box.height <= y) - { - if(!inDetection || detection.box.br().y > inDetection->box.br().y) - inDetection = &detection; - } - } - return inDetection; -} - -bool findRegionEndpointVert(int& y, const std::vector& detections, int imgSizeY) -{ - const Yolo::Detection* inDetection = pointInDetectionVert(y, detections); - - if(!inDetection) - { - const Yolo::Detection* closest = nullptr; - for(const Yolo::Detection& detection : detections) - { - if(detection.box.y > y) - { - if(closest == nullptr || detection.box.y-y > closest->box.y-y) - closest = &detection; - } - } - if(closest) - y = closest->box.y; - else - y = imgSizeY; - return false; - } - else - { - y = inDetection->box.br().y; - const Yolo::Detection* candidateDetection = pointInDetectionVert(y, detections, inDetection); - if(candidateDetection && candidateDetection->box.br().y > y) - return findRegionEndpointVert(y, detections, imgSizeY); - else - return true; - } -} - -std::vector> cutImageIntoVertRegions(cv::Mat& image, const std::vector& detections) -{ - std::vector> out; - - for(int y = 0; y < image.rows; ++y) - { - int start = y; - bool frozen = findRegionEndpointVert(y, detections, image.rows); - - cv::Mat slice = image(cv::Rect(0, start, image.cols, y-start)); - out.push_back({slice, frozen}); - } - - return out; -} - -cv::Mat assembleFromSlicesVert(const std::vector>& slices) -{ - assert(!slices.empty()); - - int rows = 0; - for(const std::pair& 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 "<& 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>& slices) { assert(!slices.empty()); @@ -173,19 +107,33 @@ cv::Mat assembleFromSlicesHoriz(const std::vector>& sli for(const std::pair& slice : slices) cols += slice.first.cols; + cv::Mat image(cols, slices[0].first.rows, slices[0].first.type()); + Log(Log::DEBUG)<<__func__<<' '<& slice : slices) { cv::Rect rect(col, 0, slice.first.cols, slice.first.rows); + Log(Log::DEBUG)<<__func__<<' '< detections, double targetAspectRatio = 1.0) { detections.erase(std::remove_if(detections.begin(), detections.end(), [](const Yolo::Detection& detection){return detection.priority < 3;}), detections.end()); @@ -206,66 +154,67 @@ bool seamCarveResize(cv::Mat& image, std::vector detections, do Log(Log::DEBUG)<<__func__<<' '<> slices = cutImageIntoHorzRegions(image, detections); - Log(Log::DEBUG)<<"Image has "<& slice : slices) - { - if(slice.second) - totalResizableSize += slice.first.cols; - } + cv::transpose(image, image); + for(Yolo::Detection& detection : detections) + transposeRect(detection.box); + } - if(totalResizableSize < requiredLines/10) - { - Log(Log::WARN)<<"Unable to seam carve as there are only "<> slices = cutImageIntoHorzRegions(image, detections); + Log(Log::DEBUG)<<"Image has "<& slice : slices) + { + Log(Log::DEBUG)<<"a "<<(slice.second ? "frozen" : "unfrozen")<<" slice of size "< seamsForSlice(slices.size(), 0); + for(size_t i = 0; i < slices.size(); ++i) + { + if(!slices[i].second) + seamsForSlice[i] = (static_cast(slices[i].first.cols)/totalResizableSize)*requiredLines; + } + + int residual = requiredLines - std::accumulate(seamsForSlice.begin(), seamsForSlice.end(), decltype(seamsForSlice)::value_type(0));; + for(ssize_t i = slices.size()-1; i >= 0; --i) + { + if(!slices[i].second) { - if(slices[i].second) + seamsForSlice[i] += residual; + break; + } + } + + for(size_t i = 0; i < slices.size(); ++i) + { + if(seamsForSlice[i] != 0) + { + bool ret = SeamCarving::strechImage(slices[i].first, seamsForSlice[i], true); + if(!ret) { - int seamsForSlice = (static_cast(slices[i].first.cols)/totalResizableSize)*requiredLines; - bool ret = SeamCarving::strechImage(image, seamsForSlice, true); - if(!ret) - return false; + if(vertical) + transpose(image, image); + return false; } } - - image = assembleFromSlicesHoriz(slices); } - else - { - std::vector> slices = cutImageIntoVertRegions(image, detections); - Log(Log::DEBUG)<<"Image has "<& slice : slices) - { - if(slice.second) - totalResizableSize += slice.first.rows; - } - if(totalResizableSize < requiredLines/10) - { - Log(Log::WARN)<<"Unable to seam carve as there are only "<(slices[i].first.rows)/totalResizableSize)*requiredLines; - bool ret = SeamCarving::strechImageVert(image, seamsForSlice, true); - if(!ret) - return false; - } - } + if(vertical) + cv::transpose(image, image); - image = assembleFromSlicesVert(slices); - } return true; } @@ -284,6 +233,85 @@ void drawDebugInfo(cv::Mat &image, const cv::Rect& rect, const std::vector longTargetSize) + { + if(image.cols > image.rows) + { + double ratio = static_cast(longTargetSize)/image.cols; + cv::resize(image, image, {longTargetSize, static_cast(image.rows*ratio)}, 0, 0, cv::INTER_CUBIC); + } + else + { + double ratio = static_cast(longTargetSize)/image.rows; + cv::resize(image, image, {static_cast(image.cols*ratio), longTargetSize}, 0, 0, cv::INTER_CUBIC); + } + } +} + +void pipeline(const std::filesystem::path& path, const Config& config, Yolo& yolo, const std::filesystem::path& debugOutputPath) +{ + InteligentRoi intRoi(yolo); + cv::Mat image = cv::imread(path); + if(!image.data) + { + Log(Log::WARN)<<"could not load image "< detections = yolo.runInference(image); + + Log(Log::DEBUG)<<"Got "< 1024) - { - Log(Log::DEBUG, false)<<"Image is "< image.rows) - { - double ratio = 1024.0/image.cols; - cv::resize(image, image, {1024, static_cast(image.rows*ratio)}, 0, 0, cv::INTER_CUBIC); - } - else - { - double ratio = 1024.0/image.rows; - cv::resize(image, image, {static_cast(image.cols*ratio), 1024}, 0, 0, cv::INTER_CUBIC); - } - Log(Log::DEBUG)<<" resized to "< detections = yolo.runInference(image); - - Log(Log::DEBUG)<<"Got "< #include #include +#include #include "log.h" const char *argp_program_version = "AIImagePreprocesses"; @@ -19,7 +20,8 @@ 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"}, + {0} }; struct Config @@ -30,6 +32,7 @@ struct Config std::filesystem::path outputDir; bool seamCarving = false; bool debug = false; + cv::Size targetSize = cv::Size(512, 512); }; static error_t parse_opt (int key, char *arg, struct argp_state *state) diff --git a/seamcarving.cpp b/seamcarving.cpp index 7de60b4..dabd0f1 100644 --- a/seamcarving.cpp +++ b/seamcarving.cpp @@ -11,38 +11,53 @@ bool SeamCarving::strechImage(cv::Mat& image, int seams, bool grow, std::vector>* seamsVect) { + cv::Mat newFrame = image.clone(); + assert(!newFrame.empty()); + std::vector> vecSeams; + for(int i = 0; i < seams; i++) { - Log(Log::DEBUG)<<"Seam "< seam = getLeastImportantPath(pathIntensityMat); + vecSeams.push_back(seam); if(seamsVect) seamsVect->push_back(seam); - if(!grow) - image = removeLeastImportantPath(image, seam); - else - image = addLeastImportantPath(image, seam); + newFrame = removeLeastImportantPath(newFrame, seam); - if(image.rows == 0 && image.cols == 0) + if(newFrame.rows == 0 || newFrame.cols == 0) return false; } + + if (grow) + { + cv::Mat growMat = image.clone(); + + for(size_t i = 0; i < vecSeams.size(); i++) + { + growMat = addLeastImportantPath(growMat,vecSeams[i]); + } + image = growMat; + } + else + { + image = newFrame; + } return true; } bool SeamCarving::strechImageVert(cv::Mat& image, int seams, bool grow, std::vector>* seamsVect) { - image = image.t(); + cv::transpose(image, image); bool ret = strechImage(image, seams, grow, seamsVect); - image = image.t(); + cv::transpose(image, image); return ret; }