Skip to content

Commit 1bfc75a

Browse files
committed
Merge pull request opencv#19079 from alalek:issue_18713
2 parents def6795 + 175cd03 commit 1bfc75a

File tree

4 files changed

+111
-61
lines changed

4 files changed

+111
-61
lines changed

modules/calib3d/include/opencv2/calib3d.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,7 @@ struct CV_EXPORTS_W_SIMPLE CirclesGridFinderParameters2 : public CirclesGridFind
14531453
- **CALIB_CB_CLUSTERING** uses a special algorithm for grid detection. It is more robust to
14541454
perspective distortions but much more sensitive to background clutter.
14551455
@param blobDetector feature detector that finds blobs like dark circles on light background.
1456+
If `blobDetector` is NULL then `image` represents Point2f array of candidates.
14561457
@param parameters struct for finding circles in a grid pattern.
14571458
14581459
The function attempts to determine whether the input image contains a grid of circles. If it is, the

modules/calib3d/src/calibinit.cpp

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,13 +2178,6 @@ void drawChessboardCorners( InputOutputArray image, Size patternSize,
21782178
}
21792179
}
21802180

2181-
static int quiet_error(int /*status*/, const char* /*func_name*/,
2182-
const char* /*err_msg*/, const char* /*file_name*/,
2183-
int /*line*/, void* /*userdata*/)
2184-
{
2185-
return 0;
2186-
}
2187-
21882181
bool findCirclesGrid(InputArray image, Size patternSize,
21892182
OutputArray centers, int flags,
21902183
const Ptr<FeatureDetector> &blobDetector,
@@ -2205,15 +2198,22 @@ bool findCirclesGrid2(InputArray _image, Size patternSize,
22052198
bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false;
22062199
CV_Assert(isAsymmetricGrid ^ isSymmetricGrid);
22072200

2208-
Mat image = _image.getMat();
22092201
std::vector<Point2f> centers;
22102202

2211-
std::vector<KeyPoint> keypoints;
2212-
blobDetector->detect(image, keypoints);
22132203
std::vector<Point2f> points;
2214-
for (size_t i = 0; i < keypoints.size(); i++)
2204+
if (blobDetector)
2205+
{
2206+
std::vector<KeyPoint> keypoints;
2207+
blobDetector->detect(_image, keypoints);
2208+
for (size_t i = 0; i < keypoints.size(); i++)
2209+
{
2210+
points.push_back(keypoints[i].pt);
2211+
}
2212+
}
2213+
else
22152214
{
2216-
points.push_back (keypoints[i].pt);
2215+
CV_CheckTypeEQ(_image.type(), CV_32FC2, "blobDetector must be provided or image must contains Point2f array (std::vector<Point2f>) with candidates");
2216+
_image.copyTo(points);
22172217
}
22182218

22192219
if(flags & CALIB_CB_ASYMMETRIC_GRID)
@@ -2229,64 +2229,59 @@ bool findCirclesGrid2(InputArray _image, Size patternSize,
22292229
return !centers.empty();
22302230
}
22312231

2232+
bool isValid = false;
22322233
const int attempts = 2;
22332234
const size_t minHomographyPoints = 4;
22342235
Mat H;
22352236
for (int i = 0; i < attempts; i++)
22362237
{
2237-
centers.clear();
2238-
CirclesGridFinder boxFinder(patternSize, points, parameters);
2239-
bool isFound = false;
2240-
#define BE_QUIET 1
2241-
#if BE_QUIET
2242-
void* oldCbkData;
2243-
ErrorCallback oldCbk = redirectError(quiet_error, 0, &oldCbkData); // FIXIT not thread safe
2244-
#endif
2245-
try
2246-
{
2247-
isFound = boxFinder.findHoles();
2248-
}
2249-
catch (const cv::Exception &)
2250-
{
2251-
2252-
}
2253-
#if BE_QUIET
2254-
redirectError(oldCbk, oldCbkData);
2255-
#endif
2256-
if (isFound)
2257-
{
2258-
switch(parameters.gridType)
2238+
centers.clear();
2239+
CirclesGridFinder boxFinder(patternSize, points, parameters);
2240+
try
22592241
{
2260-
case CirclesGridFinderParameters::SYMMETRIC_GRID:
2261-
boxFinder.getHoles(centers);
2262-
break;
2263-
case CirclesGridFinderParameters::ASYMMETRIC_GRID:
2264-
boxFinder.getAsymmetricHoles(centers);
2265-
break;
2266-
default:
2267-
CV_Error(Error::StsBadArg, "Unknown pattern type");
2242+
bool isFound = boxFinder.findHoles();
2243+
if (isFound)
2244+
{
2245+
switch(parameters.gridType)
2246+
{
2247+
case CirclesGridFinderParameters::SYMMETRIC_GRID:
2248+
boxFinder.getHoles(centers);
2249+
break;
2250+
case CirclesGridFinderParameters::ASYMMETRIC_GRID:
2251+
boxFinder.getAsymmetricHoles(centers);
2252+
break;
2253+
default:
2254+
CV_Error(Error::StsBadArg, "Unknown pattern type");
2255+
}
2256+
2257+
isValid = true;
2258+
break; // done, return result
2259+
}
2260+
}
2261+
catch (const cv::Exception& e)
2262+
{
2263+
CV_UNUSED(e);
2264+
CV_LOG_DEBUG(NULL, "findCirclesGrid2: attempt=" << i << ": " << e.what());
2265+
// nothing, next attempt
22682266
}
22692267

2270-
if (i != 0)
2268+
boxFinder.getHoles(centers);
2269+
if (i != attempts - 1)
22712270
{
2272-
Mat orgPointsMat;
2273-
transform(centers, orgPointsMat, H.inv());
2274-
convertPointsFromHomogeneous(orgPointsMat, centers);
2271+
if (centers.size() < minHomographyPoints)
2272+
break;
2273+
H = CirclesGridFinder::rectifyGrid(boxFinder.getDetectedGridSize(), centers, points, points);
22752274
}
2276-
Mat(centers).copyTo(_centers);
2277-
return true;
2278-
}
2279-
2280-
boxFinder.getHoles(centers);
2281-
if (i != attempts - 1)
2282-
{
2283-
if (centers.size() < minHomographyPoints)
2284-
break;
2285-
H = CirclesGridFinder::rectifyGrid(boxFinder.getDetectedGridSize(), centers, points, points);
2286-
}
2275+
}
2276+
2277+
if (!H.empty()) // undone rectification
2278+
{
2279+
Mat orgPointsMat;
2280+
transform(centers, orgPointsMat, H.inv());
2281+
convertPointsFromHomogeneous(orgPointsMat, centers);
22872282
}
22882283
Mat(centers).copyTo(_centers);
2289-
return false;
2284+
return isValid;
22902285
}
22912286

22922287
bool findCirclesGrid(InputArray _image, Size patternSize,

modules/calib3d/src/circlesgrid.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,7 +1622,7 @@ size_t CirclesGridFinder::getFirstCorner(std::vector<Point> &largeCornerIndices,
16221622
int cornerIdx = 0;
16231623
bool waitOutsider = true;
16241624

1625-
for(;;)
1625+
for (size_t i = 0; i < cornersCount * 2; ++i)
16261626
{
16271627
if (waitOutsider)
16281628
{
@@ -1632,11 +1632,11 @@ size_t CirclesGridFinder::getFirstCorner(std::vector<Point> &largeCornerIndices,
16321632
else
16331633
{
16341634
if (isInsider[(cornerIdx + 1) % cornersCount])
1635-
break;
1635+
return cornerIdx;
16361636
}
16371637

16381638
cornerIdx = (cornerIdx + 1) % cornersCount;
16391639
}
16401640

1641-
return cornerIdx;
1641+
CV_Error(Error::StsNoConv, "isInsider array has the same values");
16421642
}

modules/calib3d/test/test_chesscorners.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,5 +487,59 @@ TEST(Calib3d_CirclesPatternDetectorWithClustering, accuracy)
487487
ASSERT_LE(error, precise_success_error_level);
488488
}
489489

490+
TEST(Calib3d_AsymmetricCirclesPatternDetector, regression_18713)
491+
{
492+
float pts_[][2] = {
493+
{ 166.5, 107 }, { 146, 236 }, { 147, 92 }, { 184, 162 }, { 150, 185.5 },
494+
{ 215, 105 }, { 270.5, 186 }, { 159, 142 }, { 6, 205.5 }, { 32, 148.5 },
495+
{ 126, 163.5 }, { 181, 208.5 }, { 240.5, 62 }, { 84.5, 76.5 }, { 190, 120.5 },
496+
{ 10, 189 }, { 266, 104 }, { 307.5, 207.5 }, { 97, 184 }, { 116.5, 210 },
497+
{ 114, 139 }, { 84.5, 233 }, { 269.5, 139 }, { 136, 126.5 }, { 120, 107.5 },
498+
{ 129.5, 65.5 }, { 212.5, 140.5 }, { 204.5, 60.5 }, { 207.5, 241 }, { 61.5, 94.5 },
499+
{ 186.5, 61.5 }, { 220, 63 }, { 239, 120.5 }, { 212, 186 }, { 284, 87.5 },
500+
{ 62, 114.5 }, { 283, 61.5 }, { 238.5, 88.5 }, { 243, 159 }, { 245, 208 },
501+
{ 298.5, 158.5 }, { 57, 129 }, { 156.5, 63.5 }, { 192, 90.5 }, { 281, 235.5 },
502+
{ 172, 62.5 }, { 291.5, 119.5 }, { 90, 127 }, { 68.5, 166.5 }, { 108.5, 83.5 },
503+
{ 22, 176 }
504+
};
505+
Mat candidates(51, 1, CV_32FC2, (void*)pts_);
506+
Size patternSize(4, 9);
507+
508+
std::vector< Point2f > result;
509+
bool res = false;
510+
511+
// issue reports about hangs
512+
EXPECT_NO_THROW(res = findCirclesGrid(candidates, patternSize, result, CALIB_CB_ASYMMETRIC_GRID, Ptr<FeatureDetector>()/*blobDetector=NULL*/));
513+
EXPECT_FALSE(res);
514+
515+
if (cvtest::debugLevel > 0)
516+
{
517+
std::cout << Mat(candidates) << std::endl;
518+
std::cout << Mat(result) << std::endl;
519+
Mat img(Size(400, 300), CV_8UC3, Scalar::all(0));
520+
521+
std::vector< Point2f > centers;
522+
candidates.copyTo(centers);
523+
524+
for (size_t i = 0; i < centers.size(); i++)
525+
{
526+
const Point2f& pt = centers[i];
527+
//printf("{ %g, %g }, \n", pt.x, pt.y);
528+
circle(img, pt, 5, Scalar(0, 255, 0));
529+
}
530+
for (size_t i = 0; i < result.size(); i++)
531+
{
532+
const Point2f& pt = result[i];
533+
circle(img, pt, 10, Scalar(0, 0, 255));
534+
}
535+
imwrite("test_18713.png", img);
536+
if (cvtest::debugLevel >= 10)
537+
{
538+
imshow("result", img);
539+
waitKey();
540+
}
541+
}
542+
}
543+
490544
}} // namespace
491545
/* End of file. */

0 commit comments

Comments
 (0)