From fd4af21350c21c5bf096ed47311d180fc7e38ac2 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 6 Oct 2023 16:44:09 +0300 Subject: [PATCH] add dynamic window in aruco cornerRefinement --- .../opencv2/objdetect/aruco_detector.hpp | 21 ++++++++++- .../objdetect/src/aruco/aruco_detector.cpp | 35 ++++++++++++++----- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp b/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp index f885a2af87..6f8330bcd4 100644 --- a/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp +++ b/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp @@ -36,6 +36,7 @@ struct CV_EXPORTS_W_SIMPLE DetectorParameters { minMarkerDistanceRate = 0.05; cornerRefinementMethod = (int)CORNER_REFINE_NONE; cornerRefinementWinSize = 5; + relativeCornerRefinmentWinSize = 0.3f; cornerRefinementMaxIterations = 30; cornerRefinementMinAccuracy = 0.1; markerBorderBits = 1; @@ -108,9 +109,27 @@ struct CV_EXPORTS_W_SIMPLE DetectorParameters { /** @brief default value CORNER_REFINE_NONE */ CV_PROP_RW int cornerRefinementMethod; - /// window size for the corner refinement process (in pixels) (default 5). + /** @brief maximum window size for the corner refinement process (in pixels) (default 5). + * + * The window size may decrease if the ArUco marker is too small, check relativeCornerRefinmentWinSize. + * The final window size is calculated as: + * min(cornerRefinementWinSize, averageArucoModuleSize*relativeCornerRefinmentWinSize), + * where averageArucoModuleSize is average module size of ArUco marker in pixels. + * (ArUco marker is composed of black and white modules) + */ CV_PROP_RW int cornerRefinementWinSize; + /** @brief Dynamic window size for corner refinement relative to Aruco module size (default 0.3). + * + * The final window size is calculated as: + * min(cornerRefinementWinSize, averageArucoModuleSize*relativeCornerRefinmentWinSize), + * where averageArucoModuleSize is average module size of ArUco marker in pixels. + * (ArUco marker is composed of black and white modules) + * In the case of markers located far from each other, it may be useful to increase the value of the parameter to 0.4-0.5. + * In the case of markers located close to each other, it may be useful to decrease the parameter value to 0.1-0.2. + */ + CV_PROP_RW float relativeCornerRefinmentWinSize; + /// maximum number of iterations for stop criteria of the corner refinement process (default 30). CV_PROP_RW int cornerRefinementMaxIterations; diff --git a/modules/objdetect/src/aruco/aruco_detector.cpp b/modules/objdetect/src/aruco/aruco_detector.cpp index b18ddd98ba..2ecb19cc11 100644 --- a/modules/objdetect/src/aruco/aruco_detector.cpp +++ b/modules/objdetect/src/aruco/aruco_detector.cpp @@ -35,6 +35,8 @@ static inline bool readWrite(DetectorParameters ¶ms, const FileNode* readNod check |= readWriteParameter("minMarkerDistanceRate", params.minMarkerDistanceRate, readNode, writeStorage); check |= readWriteParameter("cornerRefinementMethod", params.cornerRefinementMethod, readNode, writeStorage); check |= readWriteParameter("cornerRefinementWinSize", params.cornerRefinementWinSize, readNode, writeStorage); + check |= readWriteParameter("relativeCornerRefinmentWinSize", params.relativeCornerRefinmentWinSize, readNode, + writeStorage); check |= readWriteParameter("cornerRefinementMaxIterations", params.cornerRefinementMaxIterations, readNode, writeStorage); check |= readWriteParameter("cornerRefinementMinAccuracy", params.cornerRefinementMinAccuracy, @@ -847,6 +849,16 @@ struct ArucoDetector::ArucoDetectorImpl { const RefineParameters& _refineParams): dictionary(_dictionary), detectorParams(_detectorParams), refineParams(_refineParams) {} + float getAverageArucoPinSize(vector markerCorners) { + float averageArucoModuleSize = 0.f; + int numPins = dictionary.markerSize + detectorParams.markerBorderBits * 2; + for (size_t i = 0ull; i < markerCorners.size(); i++) { + averageArucoModuleSize += sqrt(normL2Sqr(Point2f(markerCorners[i] - markerCorners[(i+1ull)%markerCorners.size()]))); + } + averageArucoModuleSize /= ((float)markerCorners.size()*numPins); + return averageArucoModuleSize; +} + }; ArucoDetector::ArucoDetector(const Dictionary &_dictionary, @@ -951,13 +963,15 @@ void ArucoDetector::detectMarkers(InputArray _image, OutputArrayOfArrays _corner const float scale_init = (float) grey_pyramid[closest_pyr_image_idx].cols / grey.cols; findCornerInPyrImage(scale_init, closest_pyr_image_idx, grey_pyramid, Mat(candidates[i]), detectorParams); } - else - cornerSubPix(grey, Mat(candidates[i]), - Size(detectorParams.cornerRefinementWinSize, detectorParams.cornerRefinementWinSize), - Size(-1, -1), - TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, - detectorParams.cornerRefinementMaxIterations, - detectorParams.cornerRefinementMinAccuracy)); + else { + int cornerRefinementWinSize = std::max(1, cvRound(detectorParams.relativeCornerRefinmentWinSize* + arucoDetectorImpl->getAverageArucoPinSize(candidates[i]))); + cornerRefinementWinSize = min(cornerRefinementWinSize, detectorParams.cornerRefinementWinSize); + cornerSubPix(grey, Mat(candidates[i]), Size(cornerRefinementWinSize, cornerRefinementWinSize), Size(-1, -1), + TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, + detectorParams.cornerRefinementMaxIterations, + detectorParams.cornerRefinementMinAccuracy)); + } } }); } @@ -1223,8 +1237,13 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Board& _board CV_Assert(detectorParams.cornerRefinementWinSize > 0 && detectorParams.cornerRefinementMaxIterations > 0 && detectorParams.cornerRefinementMinAccuracy > 0); + + std::vector marker(closestRotatedMarker.begin(), closestRotatedMarker.end()); + int cornerRefinementWinSize = std::max(1, cvRound(detectorParams.relativeCornerRefinmentWinSize* + arucoDetectorImpl->getAverageArucoPinSize(marker))); + cornerRefinementWinSize = min(cornerRefinementWinSize, detectorParams.cornerRefinementWinSize); cornerSubPix(grey, closestRotatedMarker, - Size(detectorParams.cornerRefinementWinSize, detectorParams.cornerRefinementWinSize), + Size(cornerRefinementWinSize, cornerRefinementWinSize), Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, detectorParams.cornerRefinementMaxIterations, detectorParams.cornerRefinementMinAccuracy));