mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 15:53:03 +04:00
calib3d: fix findCirclesGrid hang
- detect case with infinite loop and raise NoConv exception - handle such exception - add support for case with missing `blobDetector` (image contains Point2f array of candidates) - add regression test - undone rectification for "failed" detections too - drop redirectError() usage
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user