#include "grayMatch.h" #include #include #include constexpr int MIN_AREA = 256; constexpr double TOLERANCE = 0.0000001; constexpr int CANDIDATE = 5; constexpr double INVALID = -1.; struct Model { std::vector pyramids; std::vector mean; std::vector normal; std::vector invArea; std::vector equal1; uchar borderColor = 0; void clear() { pyramids.clear(); normal.clear(); invArea.clear(); mean.clear(); equal1.clear(); } void resize(const std::size_t size) { normal.resize(size); invArea.resize(size); mean.resize(size); equal1.resize(size); } void reserve(const std::size_t size) { normal.reserve(size); invArea.reserve(size); mean.reserve(size); equal1.reserve(size); } }; struct BlockMax { struct Block { cv::Rect rect; cv::Point maxPos; double maxScore; Block() : maxScore(0) {} Block(const cv::Rect &rect_, const cv::Point &maxPos_, const double maxScore_) : rect(rect_) , maxPos(maxPos_) , maxScore(maxScore_) {} Block(Block &&rhs) noexcept { maxScore = rhs.maxScore; maxPos = rhs.maxPos; maxScore = rhs.maxScore; } bool operator<(const Block &rhs) const { return this->maxScore > rhs.maxScore; } }; std::vector blocks; cv::Mat score; BlockMax(cv::Mat score_, cv::Size templateSize) { score = std::move(score_); // divide source image to blocks then compute max auto blockWidth = templateSize.width * 2; auto blockHeight = templateSize.height * 2; auto nWidth = score.size().width / blockWidth; auto nHeight = score.size().height / blockHeight; auto hRemained = score.size().width % blockWidth; auto vRemained = score.size().height % blockHeight; blocks.reserve(nWidth * nHeight); for (int y = 0; y < nHeight; y++) { for (int x = 0; x < nWidth; x++) { cv::Rect rect(x * blockWidth, y * blockHeight, blockWidth, blockHeight); Block block; block.rect = rect; cv::minMaxLoc(score(rect), nullptr, &block.maxScore, nullptr, &block.maxPos); block.maxPos += rect.tl(); blocks.push_back(std::move(block)); } } if (hRemained) { cv::Rect rightRect(nWidth * blockWidth, 0, hRemained, score.size().height); Block rightBlock; rightBlock.rect = rightRect; cv::minMaxLoc(score(rightRect), nullptr, &rightBlock.maxScore, nullptr, &rightBlock.maxPos); rightBlock.maxPos += rightRect.tl(); blocks.push_back(std::move(rightBlock)); } if (vRemained) { auto width = hRemained ? nWidth * blockWidth : score.size().width; if (width < 1) { return; } cv::Rect bottomRect(0, nHeight * blockHeight, width, vRemained); Block bottomBlock; bottomBlock.rect = bottomRect; cv::minMaxLoc(score(bottomRect), nullptr, &bottomBlock.maxScore, nullptr, &bottomBlock.maxPos); bottomBlock.maxPos += bottomRect.tl(); blocks.push_back(std::move(bottomBlock)); } } void update(const cv::Rect &rect) { for (auto &block : blocks) { auto intersection = block.rect & rect; if (intersection.empty()) { continue; } // update cv::minMaxLoc(score(block.rect), nullptr, &block.maxScore, nullptr, &block.maxPos); block.maxPos += block.rect.tl(); } } void maxValueLoc(double &maxScore, cv::Point &maxPos) { const auto max = std::max_element(blocks.begin(), blocks.end()); maxScore = max->maxScore; maxPos = max->maxPos; } }; struct Candidate { cv::Point2d pos; double angle; double score; Candidate() : angle(0) , score(0) {} Candidate(const cv::Point2d &pos_, const double angle_, const double score_) : pos(pos_) , angle(angle_) , score(score_) {} bool operator<(const Candidate &rhs) const { return this->score > rhs.score; } }; struct RLE { int row = -1; int startColumn = -1; int length = 0; }; using Region = std::vector; struct Template { cv::Mat img; Region region; cv::RotatedRect rect; }; struct Layer { double angleStep = 0; double mean = 0; double normal = 0; double invArea = 0; std::vector