Merge pull request #19079 from alalek:issue_18713

This commit is contained in:
Alexander Alekhin 2020-12-11 19:15:26 +00:00
commit 1bfc75ac23
4 changed files with 110 additions and 60 deletions

View File

@ -1453,6 +1453,7 @@ struct CV_EXPORTS_W_SIMPLE CirclesGridFinderParameters2 : public CirclesGridFind
- **CALIB_CB_CLUSTERING** uses a special algorithm for grid detection. It is more robust to
perspective distortions but much more sensitive to background clutter.
@param blobDetector feature detector that finds blobs like dark circles on light background.
If `blobDetector` is NULL then `image` represents Point2f array of candidates.
@param parameters struct for finding circles in a grid pattern.
The function attempts to determine whether the input image contains a grid of circles. If it is, the

View File

@ -2178,13 +2178,6 @@ void drawChessboardCorners( InputOutputArray image, Size patternSize,
}
}
static int quiet_error(int /*status*/, const char* /*func_name*/,
const char* /*err_msg*/, const char* /*file_name*/,
int /*line*/, void* /*userdata*/)
{
return 0;
}
bool findCirclesGrid(InputArray image, Size patternSize,
OutputArray centers, int flags,
const Ptr<FeatureDetector> &blobDetector,
@ -2205,15 +2198,22 @@ bool findCirclesGrid2(InputArray _image, Size patternSize,
bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false;
CV_Assert(isAsymmetricGrid ^ isSymmetricGrid);
Mat image = _image.getMat();
std::vector<Point2f> centers;
std::vector<KeyPoint> keypoints;
blobDetector->detect(image, keypoints);
std::vector<Point2f> points;
for (size_t i = 0; i < keypoints.size(); i++)
if (blobDetector)
{
points.push_back (keypoints[i].pt);
std::vector<KeyPoint> keypoints;
blobDetector->detect(_image, keypoints);
for (size_t i = 0; i < keypoints.size(); i++)
{
points.push_back(keypoints[i].pt);
}
}
else
{
CV_CheckTypeEQ(_image.type(), CV_32FC2, "blobDetector must be provided or image must contains Point2f array (std::vector<Point2f>) with candidates");
_image.copyTo(points);
}
if(flags & CALIB_CB_ASYMMETRIC_GRID)
@ -2229,64 +2229,59 @@ bool findCirclesGrid2(InputArray _image, Size patternSize,
return !centers.empty();
}
bool isValid = false;
const int attempts = 2;
const size_t minHomographyPoints = 4;
Mat H;
for (int i = 0; i < attempts; i++)
{
centers.clear();
CirclesGridFinder boxFinder(patternSize, points, parameters);
bool isFound = false;
#define BE_QUIET 1
#if BE_QUIET
void* oldCbkData;
ErrorCallback oldCbk = redirectError(quiet_error, 0, &oldCbkData); // FIXIT not thread safe
#endif
try
{
isFound = boxFinder.findHoles();
}
catch (const cv::Exception &)
{
}
#if BE_QUIET
redirectError(oldCbk, oldCbkData);
#endif
if (isFound)
{
switch(parameters.gridType)
centers.clear();
CirclesGridFinder boxFinder(patternSize, points, parameters);
try
{
case CirclesGridFinderParameters::SYMMETRIC_GRID:
boxFinder.getHoles(centers);
break;
case CirclesGridFinderParameters::ASYMMETRIC_GRID:
boxFinder.getAsymmetricHoles(centers);
break;
default:
CV_Error(Error::StsBadArg, "Unknown pattern type");
bool isFound = boxFinder.findHoles();
if (isFound)
{
switch(parameters.gridType)
{
case CirclesGridFinderParameters::SYMMETRIC_GRID:
boxFinder.getHoles(centers);
break;
case CirclesGridFinderParameters::ASYMMETRIC_GRID:
boxFinder.getAsymmetricHoles(centers);
break;
default:
CV_Error(Error::StsBadArg, "Unknown pattern type");
}
isValid = true;
break; // done, return result
}
}
catch (const cv::Exception& e)
{
CV_UNUSED(e);
CV_LOG_DEBUG(NULL, "findCirclesGrid2: attempt=" << i << ": " << e.what());
// nothing, next attempt
}
if (i != 0)
boxFinder.getHoles(centers);
if (i != attempts - 1)
{
Mat orgPointsMat;
transform(centers, orgPointsMat, H.inv());
convertPointsFromHomogeneous(orgPointsMat, centers);
if (centers.size() < minHomographyPoints)
break;
H = CirclesGridFinder::rectifyGrid(boxFinder.getDetectedGridSize(), centers, points, points);
}
Mat(centers).copyTo(_centers);
return true;
}
}
boxFinder.getHoles(centers);
if (i != attempts - 1)
{
if (centers.size() < minHomographyPoints)
break;
H = CirclesGridFinder::rectifyGrid(boxFinder.getDetectedGridSize(), centers, points, points);
}
if (!H.empty()) // undone rectification
{
Mat orgPointsMat;
transform(centers, orgPointsMat, H.inv());
convertPointsFromHomogeneous(orgPointsMat, centers);
}
Mat(centers).copyTo(_centers);
return false;
return isValid;
}
bool findCirclesGrid(InputArray _image, Size patternSize,

View File

@ -1622,7 +1622,7 @@ size_t CirclesGridFinder::getFirstCorner(std::vector<Point> &largeCornerIndices,
int cornerIdx = 0;
bool waitOutsider = true;
for(;;)
for (size_t i = 0; i < cornersCount * 2; ++i)
{
if (waitOutsider)
{
@ -1632,11 +1632,11 @@ size_t CirclesGridFinder::getFirstCorner(std::vector<Point> &largeCornerIndices,
else
{
if (isInsider[(cornerIdx + 1) % cornersCount])
break;
return cornerIdx;
}
cornerIdx = (cornerIdx + 1) % cornersCount;
}
return cornerIdx;
CV_Error(Error::StsNoConv, "isInsider array has the same values");
}

View File

@ -487,5 +487,59 @@ TEST(Calib3d_CirclesPatternDetectorWithClustering, accuracy)
ASSERT_LE(error, precise_success_error_level);
}
TEST(Calib3d_AsymmetricCirclesPatternDetector, regression_18713)
{
float pts_[][2] = {
{ 166.5, 107 }, { 146, 236 }, { 147, 92 }, { 184, 162 }, { 150, 185.5 },
{ 215, 105 }, { 270.5, 186 }, { 159, 142 }, { 6, 205.5 }, { 32, 148.5 },
{ 126, 163.5 }, { 181, 208.5 }, { 240.5, 62 }, { 84.5, 76.5 }, { 190, 120.5 },
{ 10, 189 }, { 266, 104 }, { 307.5, 207.5 }, { 97, 184 }, { 116.5, 210 },
{ 114, 139 }, { 84.5, 233 }, { 269.5, 139 }, { 136, 126.5 }, { 120, 107.5 },
{ 129.5, 65.5 }, { 212.5, 140.5 }, { 204.5, 60.5 }, { 207.5, 241 }, { 61.5, 94.5 },
{ 186.5, 61.5 }, { 220, 63 }, { 239, 120.5 }, { 212, 186 }, { 284, 87.5 },
{ 62, 114.5 }, { 283, 61.5 }, { 238.5, 88.5 }, { 243, 159 }, { 245, 208 },
{ 298.5, 158.5 }, { 57, 129 }, { 156.5, 63.5 }, { 192, 90.5 }, { 281, 235.5 },
{ 172, 62.5 }, { 291.5, 119.5 }, { 90, 127 }, { 68.5, 166.5 }, { 108.5, 83.5 },
{ 22, 176 }
};
Mat candidates(51, 1, CV_32FC2, (void*)pts_);
Size patternSize(4, 9);
std::vector< Point2f > result;
bool res = false;
// issue reports about hangs
EXPECT_NO_THROW(res = findCirclesGrid(candidates, patternSize, result, CALIB_CB_ASYMMETRIC_GRID, Ptr<FeatureDetector>()/*blobDetector=NULL*/));
EXPECT_FALSE(res);
if (cvtest::debugLevel > 0)
{
std::cout << Mat(candidates) << std::endl;
std::cout << Mat(result) << std::endl;
Mat img(Size(400, 300), CV_8UC3, Scalar::all(0));
std::vector< Point2f > centers;
candidates.copyTo(centers);
for (size_t i = 0; i < centers.size(); i++)
{
const Point2f& pt = centers[i];
//printf("{ %g, %g }, \n", pt.x, pt.y);
circle(img, pt, 5, Scalar(0, 255, 0));
}
for (size_t i = 0; i < result.size(); i++)
{
const Point2f& pt = result[i];
circle(img, pt, 10, Scalar(0, 0, 255));
}
imwrite("test_18713.png", img);
if (cvtest::debugLevel >= 10)
{
imshow("result", img);
waitKey();
}
}
}
}} // namespace
/* End of file. */