#include #include #include #include #include #include #include "yolo.h" #include "log.h" #include "options.h" #include "utils.h" #include "intelligentroi.h" const Yolo::Detection* pointInDetectionHoriz(int x, const std::vector& 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.x <= x && detection.box.x+detection.box.width <= x) { if(!inDetection || detection.box.br().x > inDetection->box.br().x) inDetection = &detection; } } return inDetection; } bool findRegionEndpointHoriz(int& x, const std::vector& detections, int imgSizeX) { const Yolo::Detection* inDetection = pointInDetectionHoriz(x, detections); if(!inDetection) { const Yolo::Detection* closest = nullptr; for(const Yolo::Detection& detection : detections) { if(detection.box.x > x) { if(closest == nullptr || detection.box.x-x > closest->box.x-x) closest = &detection; } } if(closest) x = closest->box.x; else x = imgSizeX; return false; } else { x = inDetection->box.br().x; const Yolo::Detection* candidateDetection = pointInDetectionHoriz(x, detections, inDetection); if(candidateDetection && candidateDetection->box.br().x > x) return findRegionEndpointHoriz(x, detections, imgSizeX); else return true; } } std::vector> cutImageIntoHorzRegions(cv::Mat& image, const std::vector& detections) { std::vector> out; for(int x = 0; x < image.cols; ++x) { int start = x; bool frozen = findRegionEndpointHoriz(x, detections, image.cols); cv::Mat slice = image(cv::Rect(start, 0, x-start, image.rows)); out.push_back({slice, frozen}); } return out; } const Yolo::Detection* pointInDetectionVert(int y, const std::vector& 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; } bool seamCarveResize(cv::Mat& image, const std::vector& detections, double targetAspectRatio = 1.0) { double aspectRatio = image.cols/static_cast(image.rows); bool vertical = false; cv::Mat workImage; if(aspectRatio > targetAspectRatio) vertical = true; int requiredLines = 0; if(!vertical) requiredLines = workImage.rows*targetAspectRatio - workImage.cols; else requiredLines = workImage.cols/targetAspectRatio - workImage.rows; Log(Log::DEBUG)<<__func__<<' '<> slices = cutImageIntoHorzRegions(image, detections); int totalResizableSize = 0; for(const std::pair& slice : slices) { if(slice.second) totalResizableSize += slice.first.cols; } std::vector seamsForSlice(slices.size()); for(size_t i = 0; i < slices.size(); ++i) { seamsForSlice[i] = (static_cast(slices[i].first.cols)/totalResizableSize)*requiredLines; } } else { int totalResizableSize = 0; std::vector> slices = cutImageIntoVertRegions(image, detections); } } void drawDebugInfo(cv::Mat &image, const cv::Rect& rect, const std::vector& detections) { for(const Yolo::Detection& detection : detections) { cv::rectangle(image, detection.box, detection.color, 4); 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::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::rectangle(image, rect, cv::Scalar(0, 0, 255), 8); } int main(int argc, char* argv[]) { Log::level = Log::INFO; Config config; argp_parse(&argp, argc, argv, 0, 0, &config); if(config.outputDir.empty()) { Log(Log::ERROR)<<"a output path \"-o\" is required"; return 1; } if(config.imagePaths.empty()) { Log(Log::ERROR)<<"at least one input image or directory is required"; return 1; } std::vector imagePaths; for(const std::filesystem::path& path : config.imagePaths) getImageFiles(path, imagePaths); if(imagePaths.empty()) { Log(Log::ERROR)<<"no image was found\n"; return 1; } Yolo yolo(config.modelPath, {640, 480}, config.classesPath, false); InteligentRoi intRoi(yolo); if(!std::filesystem::exists(config.outputDir)) { if(!std::filesystem::create_directory(config.outputDir)) { Log(Log::ERROR)<<"could not create directory at "< 1024) { if(image.cols > 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); } } std::vector detections = yolo.runInference(image); Log(Log::DEBUG)<<"Got "<