From dde9181117afcc6733d9eaf42b4486ee218bbe20 Mon Sep 17 00:00:00 2001 From: Ilya Lysenkov Date: Fri, 6 May 2011 09:40:18 +0000 Subject: [PATCH] Added a fast algorithm for the symmetric circles grid detection --- modules/calib3d/src/calibinit.cpp | 8 ++- modules/calib3d/src/circlesgrid.cpp | 105 +++++++++++++++++++--------- modules/calib3d/src/circlesgrid.hpp | 10 ++- 3 files changed, 86 insertions(+), 37 deletions(-) diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp index 074b917fb8..7200b126b2 100644 --- a/modules/calib3d/src/calibinit.cpp +++ b/modules/calib3d/src/calibinit.cpp @@ -1929,6 +1929,10 @@ void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize, bool cv::findCirclesGrid( const InputArray& _image, Size patternSize, OutputArray _centers, int flags ) { + bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID); + bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID); + CV_Assert(isAsymmetricGrid ^ isSymmetricGrid); + Mat image = _image.getMat(); vector centers; SimpleBlobDetector::Params params; @@ -1947,9 +1951,9 @@ bool cv::findCirclesGrid( const InputArray& _image, Size patternSize, points.push_back (keypoints[i].pt); } - if((flags & CALIB_CB_CLUSTERING) && (flags & CALIB_CB_ASYMMETRIC_GRID)) + if(flags & CALIB_CB_CLUSTERING) { - CirclesGridClusterFinder circlesGridClusterFinder; + CirclesGridClusterFinder circlesGridClusterFinder(isAsymmetricGrid); circlesGridClusterFinder.findGrid(points, patternSize, centers); Mat(centers).copyTo(_centers); return !centers.empty(); diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp index 413ef27511..afe30e6a6e 100644 --- a/modules/calib3d/src/circlesgrid.cpp +++ b/modules/calib3d/src/circlesgrid.cpp @@ -73,7 +73,7 @@ void CirclesGridClusterFinder::hierarchicalClustering(const vector poin } int patternClusterIdx = 0; - while((int)clusters[patternClusterIdx].size() < patternSize.area() && countNonZero(distsMask == 255) > 0) + while(clusters[patternClusterIdx].size() < static_cast(patternSize.area()) && countNonZero(distsMask == 255) > 0) { Point minLoc; minMaxLoc(dists, 0, 0, &minLoc, 0, distsMask); @@ -93,7 +93,8 @@ void CirclesGridClusterFinder::hierarchicalClustering(const vector poin } patternPoints.clear(); - if((int)clusters[patternClusterIdx].size() != patternSize.area()) + + if(clusters[patternClusterIdx].size() != static_cast(patternSize.area())) { return; } @@ -104,8 +105,9 @@ void CirclesGridClusterFinder::hierarchicalClustering(const vector poin } } -void CirclesGridClusterFinder::findGrid(const std::vector points, cv::Size patternSize, vector& centers) +void CirclesGridClusterFinder::findGrid(const std::vector points, cv::Size _patternSize, vector& centers) { + patternSize = _patternSize; centers.clear(); if(points.empty()) { @@ -121,7 +123,7 @@ void CirclesGridClusterFinder::findGrid(const std::vector points, c vector hull2f; convexHull(Mat(patternPoints), hull2f, false); - const size_t cornersCount = 6; + const size_t cornersCount = isAsymmetricGrid ? 6 : 4; if(hull2f.size() < cornersCount) return; @@ -130,23 +132,24 @@ void CirclesGridClusterFinder::findGrid(const std::vector points, c if(corners.size() != cornersCount) return; - vector outsideCorners; - findOutsideCorners(corners, outsideCorners); - const size_t outsideCornersCount = 2; - if(outsideCorners.size() != outsideCornersCount) - return; - - vector sortedCorners; + vector outsideCorners, sortedCorners; + if(isAsymmetricGrid) + { + findOutsideCorners(corners, outsideCorners); + const size_t outsideCornersCount = 2; + if(outsideCorners.size() != outsideCornersCount) + return; + } getSortedCorners(hull2f, corners, outsideCorners, sortedCorners); if(sortedCorners.size() != cornersCount) return; vector rectifiedPatternPoints; - rectifyPatternPoints(patternSize, patternPoints, sortedCorners, rectifiedPatternPoints); + rectifyPatternPoints(patternPoints, sortedCorners, rectifiedPatternPoints); if(patternPoints.size() != rectifiedPatternPoints.size()) return; - parsePatternPoints(patternSize, patternPoints, rectifiedPatternPoints, centers); + parsePatternPoints(patternPoints, rectifiedPatternPoints, centers); } void CirclesGridClusterFinder::findCorners(const std::vector &hull2f, std::vector &corners) @@ -167,7 +170,7 @@ void CirclesGridClusterFinder::findCorners(const std::vector &hull2 Mat sortedIndices; sortIdx(anglesMat, sortedIndices, CV_SORT_EVERY_COLUMN + CV_SORT_DESCENDING); CV_Assert(sortedIndices.type() == CV_32SC1); - const int cornersCount = 6; + const int cornersCount = isAsymmetricGrid ? 6 : 4; corners.clear(); for(int i=0; i void CirclesGridClusterFinder::getSortedCorners(const std::vector &hull2f, const std::vector &corners, const std::vector &outsideCorners, std::vector &sortedCorners) { - Point2f center = std::accumulate(corners.begin(), corners.end(), Point2f(0.0f, 0.0f)); - center *= 1.0 / corners.size(); - - vector centerToCorners; - for(size_t i=0; i 0 - bool isClockwise = crossProduct > 0; - Point2f firstCorner = isClockwise ? outsideCorners[1] : outsideCorners[0]; + vector centerToCorners; + for(size_t i=0; i 0 + bool isClockwise = crossProduct > 0; + firstCorner = isClockwise ? outsideCorners[1] : outsideCorners[0]; + } + else + { + firstCorner = corners[0]; + } std::vector::const_iterator firstCornerIterator = std::find(hull2f.begin(), hull2f.end(), firstCorner); sortedCorners.clear(); @@ -257,16 +268,34 @@ void CirclesGridClusterFinder::getSortedCorners(const std::vector & sortedCorners.push_back(*it); } } + + if(!isAsymmetricGrid) + { + double dist1 = norm(sortedCorners[0] - sortedCorners[1]); + double dist2 = norm(sortedCorners[1] - sortedCorners[2]); + + if((dist1 > dist2 && patternSize.height > patternSize.width) || (dist1 < dist2 && patternSize.height < patternSize.width)) + { + for(size_t i=0; i &patternPoints, const std::vector &sortedCorners, std::vector &rectifiedPatternPoints) +void CirclesGridClusterFinder::rectifyPatternPoints(const std::vector &patternPoints, const std::vector &sortedCorners, std::vector &rectifiedPatternPoints) { //indices of corner points in pattern vector trueIndices; trueIndices.push_back(Point(0, 0)); trueIndices.push_back(Point(patternSize.width - 1, 0)); - trueIndices.push_back(Point(patternSize.width - 1, 1)); - trueIndices.push_back(Point(patternSize.width - 1, patternSize.height - 2)); + if(isAsymmetricGrid) + { + trueIndices.push_back(Point(patternSize.width - 1, 1)); + trueIndices.push_back(Point(patternSize.width - 1, patternSize.height - 2)); + } trueIndices.push_back(Point(patternSize.width - 1, patternSize.height - 1)); trueIndices.push_back(Point(0, patternSize.height - 1)); @@ -275,7 +304,14 @@ void CirclesGridClusterFinder::rectifyPatternPoints(const cv::Size &patternSize, { int i = trueIndices[idx].y; int j = trueIndices[idx].x; - idealPoints.push_back(Point2f((2*j + i % 2)*squareSize, i*squareSize)); + if(isAsymmetricGrid) + { + idealPoints.push_back(Point2f((2*j + i % 2)*squareSize, i*squareSize)); + } + else + { + idealPoints.push_back(Point2f(j*squareSize, i*squareSize)); + } } Mat homography = findHomography(Mat(sortedCorners), Mat(idealPoints), 0); @@ -285,7 +321,7 @@ void CirclesGridClusterFinder::rectifyPatternPoints(const cv::Size &patternSize, convertPointsFromHomogeneous(rectifiedPointsMat, rectifiedPatternPoints); } -void CirclesGridClusterFinder::parsePatternPoints(const cv::Size &patternSize, const std::vector &patternPoints, const std::vector &rectifiedPatternPoints, std::vector ¢ers) +void CirclesGridClusterFinder::parsePatternPoints(const std::vector &patternPoints, const std::vector &rectifiedPatternPoints, std::vector ¢ers) { flann::LinearIndexParams flannIndexParams; flann::Index flannIndex(Mat(rectifiedPatternPoints).reshape(1), flannIndexParams); @@ -295,7 +331,12 @@ void CirclesGridClusterFinder::parsePatternPoints(const cv::Size &patternSize, c { for( int j = 0; j < patternSize.width; j++ ) { - Point2f idealPt((2*j + i % 2)*squareSize, i*squareSize); + Point2f idealPt; + if(isAsymmetricGrid) + idealPt = Point2f((2*j + i % 2)*squareSize, i*squareSize); + else + idealPt = Point2f(j*squareSize, i*squareSize); + vector query = Mat(idealPt); int knn = 1; vector indices(knn); diff --git a/modules/calib3d/src/circlesgrid.hpp b/modules/calib3d/src/circlesgrid.hpp index 90b38cb051..5cd5295c72 100644 --- a/modules/calib3d/src/circlesgrid.hpp +++ b/modules/calib3d/src/circlesgrid.hpp @@ -53,8 +53,9 @@ class CirclesGridClusterFinder { public: - CirclesGridClusterFinder() + CirclesGridClusterFinder(bool _isAsymmetricGrid) { + isAsymmetricGrid = _isAsymmetricGrid; squareSize = 1.0f; maxRectifiedDistance = squareSize / 2.0; } @@ -66,10 +67,13 @@ private: void findCorners(const std::vector &hull2f, std::vector &corners); void findOutsideCorners(const std::vector &corners, std::vector &outsideCorners); void getSortedCorners(const std::vector &hull2f, const std::vector &corners, const std::vector &outsideCorners, std::vector &sortedCorners); - void rectifyPatternPoints(const cv::Size &patternSize, const std::vector &patternPoints, const std::vector &sortedCorners, std::vector &rectifiedPatternPoints); - void parsePatternPoints(const cv::Size &patternSize, const std::vector &patternPoints, const std::vector &rectifiedPatternPoints, std::vector ¢ers); + void rectifyPatternPoints(const std::vector &patternPoints, const std::vector &sortedCorners, std::vector &rectifiedPatternPoints); + void parsePatternPoints(const std::vector &patternPoints, const std::vector &rectifiedPatternPoints, std::vector ¢ers); float squareSize, maxRectifiedDistance; + bool isAsymmetricGrid; + + cv::Size patternSize; }; class Graph