From 618f4b566cf463f65d80fff7b714bf5929240fcd Mon Sep 17 00:00:00 2001 From: abc Date: Sat, 24 Aug 2024 00:03:55 +0800 Subject: [PATCH] misc --- CMakeLists.txt | 17 ++-- grayMatch.cpp | 229 ++++++++++++++++++++++++++++--------------------- main.cpp | 28 +++++- 3 files changed, 164 insertions(+), 110 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e8277..b850454 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,11 +2,16 @@ cmake_minimum_required(VERSION 3.12) project(match) find_package(OpenCV REQUIRED) -add_executable(match -main.cpp -grayMatch.h -grayMatch.cpp +add_executable(${PROJECT_NAME} + main.cpp + grayMatch.h + grayMatch.cpp ) -target_include_directories(match PRIVATE ${OpenCV_INCLUDE_DIRS}) -target_link_libraries(match ${OpenCV_LIBRARIES}) \ No newline at end of file +target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES}) +target_compile_options(${PROJECT_NAME} PRIVATE + $<$:/W4 /WX /external:W0> + $<$:-fPIC -fvisibility=hidden -Wall -Wextra -Wpedantic -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion -Werror> + $<$,$>:/W4 /WX /external:W0> +) diff --git a/grayMatch.cpp b/grayMatch.cpp index f0e9ebd..9b5baa8 100644 --- a/grayMatch.cpp +++ b/grayMatch.cpp @@ -1,5 +1,7 @@ #include "grayMatch.h" +#include + const int MIN_AREA = 256; const double TOLERANCE = 0.0000001; const int CANDIDATE = 5; @@ -219,8 +221,8 @@ cv::Size computeRotationSize(const cv::Size &dstSize, const cv::Size &templateSi cv::Size size(halfWidth * 2, halfHeight * 2); auto wrongSize = (templateSize.width < size.width && templateSize.height > size.height) || - (templateSize.width > size.width && templateSize.height < size.height || - templateSize.area() > size.area()); + (templateSize.width > size.width && templateSize.height < size.height) || + templateSize.area() > size.area(); if (wrongSize) { size = {int(max.x - min.x + 0.5), int(max.y - min.y + 0.5)}; } @@ -228,7 +230,7 @@ cv::Size computeRotationSize(const cv::Size &dstSize, const cv::Size &templateSi return size; } -void coeffDenominator(cv::Mat &src, cv::Size &templateSize, cv::Mat &result, double mean, +void coeffDenominator(const cv::Mat &src, const cv::Size &templateSize, cv::Mat &result, double mean, double normal, double invArea, bool equal1) { if (equal1) { result = cv::Scalar::all(1); @@ -281,13 +283,41 @@ void coeffDenominator(cv::Mat &src, cv::Size &templateSize, cv::Mat &result, dou } } +float convSimd(uchar* kernel, uchar* src, int kernelWidth){ + auto blockSize = cv::VTraits::vlanes(); + auto vSum = cv::vx_setall_u32(0) ; + int i = 0; + for(; i < kernelWidth - blockSize; i += blockSize){ + vSum += cv::v_dotprod_expand(cv::v_load(kernel+i), cv::v_load(src+i)); + } + auto sum = cv::v_reduce_sum(vSum); + + for(;i(y); + for(int x = 0; x < src.cols; x++){ + auto &score = resultPtr[x]; + for(int templateRow = 0; templateRow < templateImg.rows; templateRow++){ + auto* srcPtr = src.ptr(y + templateRow) + x; + auto* temPtr = templateImg.ptr(templateRow); + score += convSimd(temPtr, srcPtr, templateImg.cols); + } + } + } } void matchTemplate(cv::Mat &src, cv::Mat &result, Model *model, int level) { #ifdef CV_SIMD - matchTemplateSimd(src, , result); + matchTemplateSimd(src, model->pyramids[ level ], result); #else cv::matchTemplate(src, model->pyramids[ level ], result, cv::TM_CCORR); #endif @@ -355,14 +385,14 @@ void cropRotatedRoi(const cv::Mat &src, const cv::Size &templateSize, cv::Point2 void filterOverlap(std::vector &candidates, std::vector &rects, double maxOverlap) { auto size = candidates.size(); - for (int i = 0; i < size; i++) { + for (std::size_t i = 0; i < size; i++) { auto &candidate = candidates[ i ]; auto &rect = rects[ i ]; if (candidate.score < 0) { continue; } - for (int j = i + 1; j < size; j++) { + for (std::size_t j = i + 1; j < size; j++) { auto &refCandidate = candidates[ j ]; auto &refRect = rects[ j ]; if (refCandidate.score < 0) { @@ -449,99 +479,94 @@ Model *trainModel(const cv::Mat &src, int level) { std::vector matchModel(const cv::Mat &dst, Model *model, int level, double startAngle, double spanAngle, double maxOverlap, double minScore, int maxCount, int subpixel) { - if (dst.empty() || nullptr == model) { - return {}; - } + //prepare + { + if (dst.empty() || nullptr == model) { + return {}; + } - auto &templateImg = model->pyramids.front(); - if (dst.cols < templateImg.cols || dst.rows < templateImg.rows || - dst.size().area() < templateImg.size().area()) { - return {}; - } + auto &templateImg = model->pyramids.front(); + if (dst.cols < templateImg.cols || dst.rows < templateImg.rows || + dst.size().area() < templateImg.size().area()) { + return {}; + } - if (level < 0 || level > model->pyramids.size() - 1) { - // level must grater than 1 - level = model->pyramids.size() - 1; + auto templateLevel = static_cast(model->pyramids.size() - 1); + if (level < 0 || level > templateLevel) { + // level must grater than 1 + level = templateLevel; + } } std::vector pyramids; cv::buildPyramid(dst, pyramids, level); // compute top - const auto &templateTop = model->pyramids[ level ]; - auto angleStep = atan(2. / std::max(templateTop.cols, templateTop.rows)) * 180. / CV_PI; - - const auto &dstTop = pyramids.back(); - cv::Point2d center = sizeCenter(dstTop.size()); - bool calMaxByBlock = (dstTop.size().area() / templateTop.size().area() > 500) && maxCount > 10; - const auto topScoreThreshold = minScore * pow(0.9, level); - std::vector candidates; + { + const auto &templateTop = model->pyramids[ level ]; + auto angleStep = atan(2. / std::max(templateTop.cols, templateTop.rows)) * 180. / CV_PI; - // std::vector angles; - // for (double angle = 0; angle < 180. + angleStep; angle += angleStep) { - // angles.push_back(angle); - // } - // for (double angle = -angleStep; angle > -180. - angleStep; angle -= angleStep) { - // angles.push_back(angle); - // } + const auto &dstTop = pyramids.back(); + cv::Point2d center = sizeCenter(dstTop.size()); + bool calMaxByBlock = (dstTop.size().area() / templateTop.size().area() > 500) && maxCount > 10; + const auto topScoreThreshold = minScore * pow(0.9, level); - for (auto angle = startAngle; angle < startAngle + spanAngle + angleStep; angle += angleStep) { - // for (auto angle : angles) { + for (auto angle = startAngle; angle < startAngle + spanAngle + angleStep; angle += angleStep) { + auto rotate = cv::getRotationMatrix2D(center, angle, 1.); + auto size = computeRotationSize(dstTop.size(), templateTop.size(), angle, rotate); - auto rotate = cv::getRotationMatrix2D(center, angle, 1.); - auto size = computeRotationSize(dstTop.size(), templateTop.size(), angle, rotate); + auto tx = (size.width - 1) / 2. - center.x; + auto ty = (size.height - 1) / 2. - center.y; + rotate.at(0, 2) += tx; + rotate.at(1, 2) += ty; + cv::Point2d offset(tx, ty); - auto tx = (size.width - 1) / 2. - center.x; - auto ty = (size.height - 1) / 2. - center.y; - rotate.at(0, 2) += tx; - rotate.at(1, 2) += ty; - cv::Point2d offset(tx, ty); + cv::Mat rotated; + cv::warpAffine(dstTop, rotated, rotate, size, cv::INTER_LINEAR, cv::BORDER_CONSTANT, + model->borderColor); - cv::Mat rotated; - cv::warpAffine(dstTop, rotated, rotate, size, cv::INTER_LINEAR, cv::BORDER_CONSTANT, - model->borderColor); - - cv::Mat result; - matchTemplate(rotated, result, model, level); - if (calMaxByBlock) { - BlockMax block(result, templateTop.size()); - double maxScore; - cv::Point maxPos; - block.maxValueLoc(maxScore, maxPos); - if (maxScore < topScoreThreshold) { - continue; - } - - candidates.emplace_back(cv::Point2d(maxPos) - offset, angle, maxScore); - for (int j = 0; j < maxCount + CANDIDATE - 1; j++) { - nextMaxLoc(maxPos, templateTop.size(), maxOverlap, block, maxScore, maxPos); + cv::Mat result; + matchTemplate(rotated, result, model, level); + if (calMaxByBlock) { + BlockMax block(result, templateTop.size()); + double maxScore; + cv::Point maxPos; + block.maxValueLoc(maxScore, maxPos); if (maxScore < topScoreThreshold) { - break; + continue; } candidates.emplace_back(cv::Point2d(maxPos) - offset, angle, maxScore); - } - } else { - double maxScore; - cv::Point maxPos; - cv::minMaxLoc(result, 0, &maxScore, 0, &maxPos); - if (maxScore < topScoreThreshold) { - continue; - } + for (int j = 0; j < maxCount + CANDIDATE - 1; j++) { + nextMaxLoc(maxPos, templateTop.size(), maxOverlap, block, maxScore, maxPos); + if (maxScore < topScoreThreshold) { + break; + } - candidates.emplace_back(cv::Point2d(maxPos) - offset, angle, maxScore); - for (int j = 0; j < maxCount + CANDIDATE - 1; j++) { - nextMaxLoc(result, maxPos, templateTop.size(), maxOverlap, maxScore, maxPos); + candidates.emplace_back(cv::Point2d(maxPos) - offset, angle, maxScore); + } + } else { + double maxScore; + cv::Point maxPos; + cv::minMaxLoc(result, 0, &maxScore, 0, &maxPos); if (maxScore < topScoreThreshold) { - break; + continue; } candidates.emplace_back(cv::Point2d(maxPos) - offset, angle, maxScore); + for (int j = 0; j < maxCount + CANDIDATE - 1; j++) { + nextMaxLoc(result, maxPos, templateTop.size(), maxOverlap, maxScore, maxPos); + if (maxScore < topScoreThreshold) { + break; + } + + candidates.emplace_back(cv::Point2d(maxPos) - offset, angle, maxScore); + } } } + std::sort(candidates.begin(), candidates.end()); } - std::sort(candidates.begin(), candidates.end()); // match candidate each level std::vector levelMatched; @@ -624,39 +649,43 @@ std::vector matchModel(const cv::Mat &dst, Model *model, int level, double // filter overlap std::vector rects; - rects.reserve(levelMatched.size()); - auto size = model->pyramids.front().size(); - cv::Point2f topRight(size.width, 0.f); - cv::Point2f bottomRight(size.width, size.height); - for (const auto &candidate : levelMatched) { - std::vector points{topRight + cv::Point2f(candidate.pos), - bottomRight + cv::Point2f(candidate.pos)}; - auto rotate = cv::getRotationMatrix2D(candidate.pos, -candidate.angle, 1.); - std::vector rotatedPoints; - cv::transform(points, rotatedPoints, rotate); + { + rects.reserve(levelMatched.size()); + auto size = model->pyramids.front().size(); + cv::Point2f topRight((float)size.width, 0.f); + cv::Point2f bottomRight((float)size.width, (float)size.height); + for (const auto &candidate : levelMatched) { + std::vector points{topRight + cv::Point2f(candidate.pos), + bottomRight + cv::Point2f(candidate.pos)}; + auto rotate = cv::getRotationMatrix2D(candidate.pos, -candidate.angle, 1.); + std::vector rotatedPoints; + cv::transform(points, rotatedPoints, rotate); - rects.emplace_back( - cv::RotatedRect{cv::Point2f(candidate.pos), rotatedPoints[ 0 ], rotatedPoints[ 1 ]}); + rects.emplace_back( + cv::RotatedRect{cv::Point2f(candidate.pos), rotatedPoints[ 0 ], rotatedPoints[ 1 ]}); + } + filterOverlap(levelMatched, rects, maxOverlap); } - filterOverlap(levelMatched, rects, maxOverlap); std::vector result; - auto count = levelMatched.size(); - for (int i = 0; i < count; i++) { - auto &candidate = levelMatched[ i ]; - auto &rect = rects[ i ]; + { + auto count = levelMatched.size(); + for (std::size_t i = 0; i < count; i++) { + auto &candidate = levelMatched[ i ]; + auto &rect = rects[ i ]; - if (candidate.score < 0) { - continue; + if (candidate.score < 0) { + continue; + } + + auto center = rect.center; + result.emplace_back( + Pose{center.x, center.y, (float)-candidate.angle, (float)candidate.score}); } - auto center = rect.center; - result.emplace_back( - Pose{center.x, center.y, (float)-candidate.angle, (float)candidate.score}); + std::sort(result.begin(), result.end(), + [](const Pose &a, const Pose &b) { return a.score > b.score; }); } - std::sort(result.begin(), result.end(), - [](const Pose &a, const Pose &b) { return a.score > b.score; }); - return result; -} \ No newline at end of file +} diff --git a/main.cpp b/main.cpp index 839f990..f081ae7 100644 --- a/main.cpp +++ b/main.cpp @@ -1,15 +1,35 @@ #include "grayMatch.h" #include +#include int main() { auto src = - cv::imread("C:/Users/qiuyong/Desktop/test/template/model3.bmp", cv::IMREAD_GRAYSCALE); + cv::imread("/home/abc/project/ShapeMatch/ShapeMatchTest/TestImage/3.bmp", cv::IMREAD_GRAYSCALE); auto dst = - cv::imread("C:/Users/qiuyong/Desktop/test/template/model3_src2.bmp", cv::IMREAD_GRAYSCALE); + cv::imread("/home/abc/project/ShapeMatch/ShapeMatchTest/TestImage/l.bmp", cv::IMREAD_GRAYSCALE); auto model = trainModel(src, -1); - auto poses = matchModel(dst, model, -1, 0, 360, 0, 0.5, 70, 1); + auto poses = matchModel(dst, model, 3, 0, 360, 0, 0.5, 70, 1); + + cv::Mat color; + cv::cvtColor(dst, color, cv::COLOR_GRAY2RGB); + for(auto &pose : poses){ + cv::RotatedRect rect(cv::Point2f(pose.x, pose.y), src.size(), -pose.angle); + + std::vector pts; + rect.points(pts); + + cv::line(color, pts[0], pts[1], cv::Scalar(255, 0 , 0), 1, cv::LINE_AA); + cv::line(color, pts[1], pts[2], cv::Scalar(255, 0 , 0), 1, cv::LINE_AA); + cv::line(color, pts[2], pts[3], cv::Scalar(255, 0 , 0), 1, cv::LINE_AA); + cv::line(color, pts[3], pts[0], cv::Scalar(255, 0 , 0), 1, cv::LINE_AA); + + std::cout << pose.x << "," << pose.y << "," << pose.angle << "," <