From 0ef4ff89251d02d78ed6f53f34acb4ab29e0b4b5 Mon Sep 17 00:00:00 2001 From: Ilya Lysenkov Date: Tue, 20 Sep 2011 12:47:24 +0000 Subject: [PATCH] Improved robustness of the findCirclesGrid() to affine distortions. --- modules/calib3d/src/circlesgrid.cpp | 116 +++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 29 deletions(-) diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp index 952b8f5..405e409 100644 --- a/modules/calib3d/src/circlesgrid.cpp +++ b/modules/calib3d/src/circlesgrid.cpp @@ -50,6 +50,16 @@ using namespace cv; using namespace std; +#ifdef DEBUG_CIRCLES +void drawPoints(const vector &points, Mat &outImage, int radius = 2, Scalar color = Scalar::all(255), int thickness = -1) +{ + for(size_t i=0; i points, const Size &patternSize, vector &patternPoints) { #ifdef HAVE_TEGRA_OPTIMIZATION @@ -106,6 +116,12 @@ void CirclesGridClusterFinder::hierarchicalClustering(const vector poin patternClusterIdx = minIdx; } + //the largest cluster can have more than pn points -- we need to filter out such situations + if(clusters[patternClusterIdx].size() != static_cast(patternSize.area())) + { + return; + } + patternPoints.reserve(clusters[patternClusterIdx].size()); for(std::list::iterator it = clusters[patternClusterIdx].begin(); it != clusters[patternClusterIdx].end(); it++) { @@ -129,6 +145,12 @@ void CirclesGridClusterFinder::findGrid(const std::vector points, c return; } +#ifdef DEBUG_CIRCLES + Mat patternPointsImage(1024, 1248, CV_8UC1, Scalar(0)); + drawPoints(patternPoints, patternPointsImage); + imshow("pattern points", patternPointsImage); +#endif + vector hull2f; convexHull(Mat(patternPoints), hull2f, false); const size_t cornersCount = isAsymmetricGrid ? 6 : 4; @@ -178,60 +200,93 @@ 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); + CV_Assert(sortedIndices.cols == 1); const int cornersCount = isAsymmetricGrid ? 6 : 4; + Mat cornersIndices; + cv::sort(sortedIndices.rowRange(0, cornersCount), cornersIndices, CV_SORT_EVERY_COLUMN + CV_SORT_ASCENDING); corners.clear(); for(int i=0; i(i, 0)]); + corners.push_back(hull2f[cornersIndices.at(i, 0)]); } } void CirclesGridClusterFinder::findOutsideCorners(const std::vector &corners, std::vector &outsideCorners) { + outsideCorners.clear(); //find two pairs of the most nearest corners double min1 = std::numeric_limits::max(); double min2 = std::numeric_limits::max(); Point minLoc1, minLoc2; int i, j, n = (int)corners.size(); +#ifdef DEBUG_CIRCLES + Mat cornersImage(1024, 1248, CV_8UC1, Scalar(0)); + drawPoints(corners, cornersImage); + imshow("corners", cornersImage); +#endif + + vector tangentVectors(corners.size()); + for(size_t k=0; k<=corners.size(); k++) + { + Point2f diff = corners[(k + 1) % corners.size()] - corners[k]; + tangentVectors[k] = diff * (1.0f / norm(diff)); + } + + //compute angles between all sides + Mat cosAngles(n, n, CV_32FC1, 0.0f); for(i = 0; i < n; i++) { - for(j = i+1; j < n; j++) + for(j = i + 1; j < n; j++) { - double dist = norm(corners[i] - corners[j]); - Point loc(j, i); - if(dist < min1) - { - min2 = min1; - minLoc2 = minLoc1; - min1 = dist; - minLoc1 = loc; - } - else - { - if(dist < min2) - { - min2 = dist; - minLoc2 = loc; - } - } + float val = fabs(tangentVectors[i].dot(tangentVectors[j])); + cosAngles.at(i, j) = val; + cosAngles.at(j, i) = val; } } - std::set outsideCornersIndices; - for(i = 0; i < n; i++) + + //find two parallel sides to which outside corners belong + Point maxLoc; + minMaxLoc(cosAngles, 0, 0, 0, &maxLoc); + const int diffBetweenFalseLines = 3; + if(abs(maxLoc.x - maxLoc.y) == diffBetweenFalseLines) { - outsideCornersIndices.insert(i); + cosAngles.row(maxLoc.x).setTo(0.0f); + cosAngles.col(maxLoc.x).setTo(0.0f); + cosAngles.row(maxLoc.y).setTo(0.0f); + cosAngles.col(maxLoc.y).setTo(0.0f); + minMaxLoc(cosAngles, 0, 0, 0, &maxLoc); } - outsideCornersIndices.erase(minLoc1.x); - outsideCornersIndices.erase(minLoc1.y); - outsideCornersIndices.erase(minLoc2.x); - outsideCornersIndices.erase(minLoc2.y); - outsideCorners.clear(); - for(std::set::iterator it = outsideCornersIndices.begin(); it != outsideCornersIndices.end(); it++) +#ifdef DEBUG_CIRCLES + Mat linesImage(1024, 1248, CV_8UC1, Scalar(0)); + line(linesImage, corners[maxLoc.y], corners[(maxLoc.y + 1) % n], Scalar(255)); + line(linesImage, corners[maxLoc.x], corners[(maxLoc.x + 1) % n], Scalar(255)); + imshow("lines", linesImage); +#endif + + int maxIdx = std::max(maxLoc.x, maxLoc.y); + int minIdx = std::min(maxLoc.x, maxLoc.y); + const int bigDiff = 4; + if(maxIdx - minIdx == bigDiff) + { + minIdx += n; + std::swap(maxIdx, minIdx); + } + if(maxIdx - minIdx != n - bigDiff) { - outsideCorners.push_back(corners[*it]); + return; } + + int outsidersSegmentIdx = (minIdx + maxIdx) / 2; + + outsideCorners.push_back(corners[outsidersSegmentIdx % n]); + outsideCorners.push_back(corners[(outsidersSegmentIdx + 1) % n]); + +#ifdef DEBUG_CIRCLES + drawPoints(outsideCorners, cornersImage, 2, Scalar(128)); + imshow("corners", outsideCornersImage); +#endif } void CirclesGridClusterFinder::getSortedCorners(const std::vector &hull2f, const std::vector &corners, const std::vector &outsideCorners, std::vector &sortedCorners) @@ -355,6 +410,9 @@ void CirclesGridClusterFinder::parsePatternPoints(const std::vector if(dists[0] > maxRectifiedDistance) { +#ifdef DEBUG_CIRCLES + cout << "Pattern not detected: too large rectified distance" << endl; +#endif centers.clear(); return; } -- 2.7.4