From dea266853c155ab5f019edcc53cf427158db1eee Mon Sep 17 00:00:00 2001 From: "y.qiu" Date: Sun, 25 Aug 2024 18:03:33 +0800 Subject: [PATCH] misc --- grayMatch.cpp | 144 +++++++++++++++++++++++++++++++++++--------------- grayMatch.h | 3 +- main.cpp | 10 ++-- 3 files changed, 107 insertions(+), 50 deletions(-) diff --git a/grayMatch.cpp b/grayMatch.cpp index f880086..ab32c10 100644 --- a/grayMatch.cpp +++ b/grayMatch.cpp @@ -157,6 +157,33 @@ struct Candidate { } }; +inline cv::Point2d transform(const cv::Point2d &point, const cv::Mat &rotate) { + const auto ptr = rotate.ptr(); + + auto x = point.x * ptr[ 0 ] + point.y * ptr[ 1 ] + ptr[ 2 ]; + auto y = point.x * ptr[ 3 ] + point.y * ptr[ 4 ] + ptr[ 5 ]; + + return {x, y}; +} + +inline cv::Point2d transform(const cv::Point2d &point, const cv::Point ¢er, double angle) { + const auto rotate = cv::getRotationMatrix2D(center, angle, 1.); + + return transform(point, rotate); +} + +inline cv::Point2d sizeCenter(const cv::Size &size) { + return {(size.width - 1.) / 2., (size.height - 1.) / 2.}; +} + +inline cv::Point2d sizeCenter(const cv::Size2d &size) { + return {(size.width - 1.) / 2., (size.height - 1.) / 2.}; +} + +inline double sizeAngleStep(const cv::Size &size) { + return atan(2. / std::max(size.width, size.height)) * 180. / CV_PI; +} + int computeLayers(const int width, const int height, const int minArea) { assert(width > 0 && height > 0 && minArea > 0); @@ -170,6 +197,32 @@ int computeLayers(const int width, const int height, const int minArea) { return layer; } +cv::Rect2d boundingRect(const std::vector &points) { + if (points.empty()) { + return {}; + } + + cv::Point2d min = points[ 0 ]; + cv::Point2d max = points[ 0 ]; + for (const auto &point : points) { + if (point.x < min.x) { + min.x = point.x; + } + if (point.y < min.y) { + min.y = point.y; + } + + if (point.x > max.x) { + max.x = point.x; + } + if (point.y > max.y) { + max.y = point.y; + } + } + + return {min, max}; +} + cv::Size computeRotationSize(const cv::Size &dstSize, const cv::Size &templateSize, double angle, const cv::Mat &rotate) { if (angle > 360) { @@ -193,24 +246,9 @@ cv::Size computeRotationSize(const cv::Size &dstSize, const cv::Size &templateSi {static_cast(dstSize.width) - 1, static_cast(dstSize.height) - 1}}; std::vector trans; cv::transform(points, trans, rotate); - - cv::Point2d min = trans[ 0 ]; - cv::Point2d max = trans[ 0 ]; - for (const auto &point : trans) { - if (point.x < min.x) { - min.x = point.x; - } - if (point.y < min.y) { - min.y = point.y; - } - - if (point.x > max.x) { - max.x = point.x; - } - if (point.y > max.y) { - max.y = point.y; - } - } + auto rect = boundingRect(trans); + auto max = rect.br(); + auto min = rect.tl(); if (angle > 0 && angle < 90) { ; @@ -228,7 +266,7 @@ cv::Size computeRotationSize(const cv::Size &dstSize, const cv::Size &templateSi const auto width = templateSize.width * dx * dy; const auto height = templateSize.height * dx * dy; - const auto center = cv::Point2d((dstSize.width - 1.) / 2., (dstSize.height - 1.) / 2.); + const auto center = sizeCenter(dstSize); const auto halfHeight = static_cast(ceil(max.y - center.y - width)); const auto halfWidth = static_cast(ceil(max.x - center.x - height)); @@ -372,25 +410,6 @@ void nextMaxLoc(cv::Mat &score, const cv::Point &pos, const cv::Size templateSiz cv::minMaxLoc(score, nullptr, &maxScore, nullptr, &maxPos); } -inline cv::Point2d transform(const cv::Point2d &point, const cv::Mat &rotate) { - const auto ptr = rotate.ptr(); - - auto x = point.x * ptr[ 0 ] + point.y * ptr[ 1 ] + ptr[ 2 ]; - auto y = point.x * ptr[ 3 ] + point.y * ptr[ 4 ] + ptr[ 5 ]; - - return {x, y}; -} - -inline cv::Point2d transform(const cv::Point2d &point, const cv::Point ¢er, double angle) { - const auto rotate = cv::getRotationMatrix2D(center, angle, 1.); - - return transform(point, rotate); -} - -inline cv::Point2d sizeCenter(const cv::Size &size) { - return {(size.width - 1.) / 2., (size.height - 1.) / 2.}; -} - void cropRotatedRoi(const cv::Mat &src, const cv::Size &templateSize, const cv::Point2d topLeft, const cv::Mat &rotate, cv::Mat &roi) { const auto point = transform(topLeft, rotate); @@ -449,7 +468,10 @@ void filterOverlap(std::vector &candidates, const std::vector::epsilon(); auto normal = sqrt(stdNormal) / sqrt(invArea); + auto currentAngleStep = sizeAngleStep(pyramid.size()); + auto center = sizeCenter(pyramid.size()); + const auto count = static_cast(spanAngle / currentAngleStep) + 1; + std::vector points{{0., 0.}, + {pyramid.cols - 1., 0.}, + {pyramid.cols - 1., pyramid.rows - 1.}, + {0., pyramid.rows - 1.}}; + for (int i = 0; i < count; i++) { + auto angle = startAngle + currentAngleStep * i; + auto rotate = cv::getRotationMatrix2D(center, angle, 1.0); + + std::vector trans; + cv::transform(points, trans, rotate); + auto rect = boundingRect(trans); + + auto center2 = sizeCenter(rect.size()); + auto offset = center2 - center; + rotate.at(0, 2) += offset.x; + rotate.at(1, 2) += offset.y; + + cv::Mat rotated; + cv::warpAffine(pyramid, rotated, rotate, rect.size(), cv::INTER_LINEAR, + cv::BORDER_DEFAULT, cv::Scalar(model.borderColor)); + + // if background area less than 1 percent, just match rotated image + auto rate = static_cast(area) / rotated.size().area(); + if (rate > 0.9) { + continue; + } + + // draw rotated rect line, then encode with run-length-encode + + if (rotated.empty()) { + continue; + } + } + model.equal1.push_back(equal1); model.invArea.push_back(invArea); model.mean.push_back(mean); @@ -493,10 +553,6 @@ Model *trainModel(const cv::Mat &src, int level) { return result; } -inline double sizeAngleStep(const cv::Size &size) { - return atan(2. / std::max(size.width, size.height)) * 180. / CV_PI; -} - std::vector matchTopLevel(const cv::Mat &dstTop, double startAngle, double spanAngle, double maxOverlap, double minScore, int maxCount, const Model *model, int level) { diff --git a/grayMatch.h b/grayMatch.h index 044050d..aacab76 100644 --- a/grayMatch.h +++ b/grayMatch.h @@ -12,7 +12,8 @@ struct Pose { float score; }; -Model *trainModel(const cv::Mat &src, int level); +Model *trainModel(const cv::Mat &src, int level, double startAngle, double spanAngle, + double anglgStep); std::vector matchModel(const cv::Mat &dst, const Model *model, int level, double startAngle, double spanAngle, double maxOverlap, double minScore, int maxCount, diff --git a/main.cpp b/main.cpp index b570fba..cf796f4 100644 --- a/main.cpp +++ b/main.cpp @@ -7,21 +7,21 @@ int main() { auto src = cv::imread("C:/Users/qiuyong/Desktop/test/template/model3.bmp", cv::IMREAD_GRAYSCALE); auto dst = - cv::imread("C:/Users/qiuyong/Desktop/test/template/model3_src1.bmp", cv::IMREAD_GRAYSCALE); + cv::imread("C:/Users/qiuyong/Desktop/test/template/model3_src2.bmp", cv::IMREAD_GRAYSCALE); auto t0 = cv::getTickCount(); - auto model = trainModel(src, -1); + auto model = trainModel(src, -1, 0, 360, -1); auto t1 = cv::getTickCount(); auto poses = matchModel(dst, model, -1, 0, 360, 0, 0.5, 70, 1); auto t2 = cv::getTickCount(); - auto trainCost = double(t1 - t0) / cv::getTickFrequency(); - auto matchCost = double(t2 - t1) / cv::getTickFrequency(); + const auto trainCost = static_cast(t1 - t0) / cv::getTickFrequency(); + const auto matchCost = static_cast(t2 - t1) / cv::getTickFrequency(); std::cout << "train(s):" << trainCost << " match(s):" << matchCost << std::endl; cv::Mat color; cv::cvtColor(dst, color, cv::COLOR_GRAY2RGB); - for (auto &pose : poses) { + for (const auto &pose : poses) { cv::RotatedRect rect(cv::Point2f(pose.x, pose.y), src.size(), -pose.angle); std::vector pts;