diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp index 81693941de..c27604873c 100644 --- a/modules/calib3d/src/circlesgrid.cpp +++ b/modules/calib3d/src/circlesgrid.cpp @@ -178,7 +178,7 @@ void CirclesGridClusterFinder::findGrid(const std::vector &points, if(outsideCorners.size() != outsideCornersCount) return; } - getSortedCorners(hull2f, corners, outsideCorners, sortedCorners); + getSortedCorners(hull2f, patternPoints, corners, outsideCorners, sortedCorners); if(sortedCorners.size() != cornersCount) return; @@ -295,7 +295,18 @@ void CirclesGridClusterFinder::findOutsideCorners(const std::vector #endif } -void CirclesGridClusterFinder::getSortedCorners(const std::vector &hull2f, const std::vector &corners, const std::vector &outsideCorners, std::vector &sortedCorners) +namespace { +double pointLineDistance(const cv::Point2f &p, const cv::Vec4f &line) +{ + Vec3f pa( line[0], line[1], 1 ); + Vec3f pb( line[2], line[3], 1 ); + Vec3f l = pa.cross(pb); + return std::abs((p.x * l[0] + p.y * l[1] + l[2])) * 1.0 / + std::sqrt(double(l[0] * l[0] + l[1] * l[1])); +} +} + +void CirclesGridClusterFinder::getSortedCorners(const std::vector &hull2f, const std::vector &patternPoints, const std::vector &corners, const std::vector &outsideCorners, std::vector &sortedCorners) { Point2f firstCorner; if(isAsymmetricGrid) @@ -341,10 +352,26 @@ void CirclesGridClusterFinder::getSortedCorners(const std::vector & if(!isAsymmetricGrid) { - double dist1 = norm(sortedCorners[0] - sortedCorners[1]); - double dist2 = norm(sortedCorners[1] - sortedCorners[2]); + double dist01 = norm(sortedCorners[0] - sortedCorners[1]); + double dist12 = norm(sortedCorners[1] - sortedCorners[2]); + // Use half the average distance between circles on the shorter side as threshold for determining whether a point lies on an edge. + double thresh = min(dist01, dist12) / min(patternSize.width, patternSize.height) / 2; + + size_t circleCount01 = 0; + size_t circleCount12 = 0; + Vec4f line01( sortedCorners[0].x, sortedCorners[0].y, sortedCorners[1].x, sortedCorners[1].y ); + Vec4f line12( sortedCorners[1].x, sortedCorners[1].y, sortedCorners[2].x, sortedCorners[2].y ); + // Count the circles along both edges. + for (size_t i = 0; i < patternPoints.size(); i++) + { + if (pointLineDistance(patternPoints[i], line01) < thresh) + circleCount01++; + if (pointLineDistance(patternPoints[i], line12) < thresh) + circleCount12++; + } - if((dist1 > dist2 && patternSize.height > patternSize.width) || (dist1 < dist2 && patternSize.height < patternSize.width)) + // Ensure that the edge from sortedCorners[0] to sortedCorners[1] is the one with more circles (i.e. it is interpreted as the pattern's width). + if ((circleCount01 > circleCount12 && patternSize.height > patternSize.width) || (circleCount01 < circleCount12 && patternSize.height < patternSize.width)) { for(size_t i=0; i &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 getSortedCorners(const std::vector &hull2f, const std::vector &patternPoints, const std::vector &corners, const std::vector &outsideCorners, std::vector &sortedCorners); 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); diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp index e55d069de0..73e91e1942 100644 --- a/modules/calib3d/test/test_chesscorners.cpp +++ b/modules/calib3d/test/test_chesscorners.cpp @@ -468,5 +468,24 @@ TEST(Calib3d_AsymmetricCirclesPatternDetector, accuracy) { CV_ChessboardDetector TEST(Calib3d_AsymmetricCirclesPatternDetectorWithClustering, accuracy) { CV_ChessboardDetectorTest test( ASYMMETRIC_CIRCLES_GRID, CALIB_CB_CLUSTERING ); test.safe_run(); } #endif +TEST(Calib3d_CirclesPatternDetectorWithClustering, accuracy) +{ + cv::String dataDir = string(TS::ptr()->get_data_path()) + "cv/cameracalibration/circles/"; + + cv::Mat expected; + FileStorage fs(dataDir + "circles_corners15.dat", FileStorage::READ); + fs["corners"] >> expected; + fs.release(); + + cv::Mat image = cv::imread(dataDir + "circles15.png"); + + std::vector centers; + cv::findCirclesGrid(image, Size(10, 8), centers, CALIB_CB_SYMMETRIC_GRID | CALIB_CB_CLUSTERING); + ASSERT_EQ(expected.total(), centers.size()); + + double error = calcError(centers, expected); + ASSERT_LE(error, precise_success_error_level); +} + }} // namespace /* End of file. */