|
|
|
@ -279,49 +279,6 @@ static void _filterTooCloseCandidates(const vector< vector< Point2f > > &candida |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ParallelLoopBody class for the parallelization of the basic candidate detections using |
|
|
|
|
* different threhold window sizes. Called from function _detectInitialCandidates() |
|
|
|
|
*/ |
|
|
|
|
class DetectInitialCandidatesParallel : public ParallelLoopBody { |
|
|
|
|
public: |
|
|
|
|
DetectInitialCandidatesParallel(const Mat *_grey, |
|
|
|
|
vector< vector< vector< Point2f > > > *_candidatesArrays, |
|
|
|
|
vector< vector< vector< Point > > > *_contoursArrays, |
|
|
|
|
const Ptr<DetectorParameters> &_params) |
|
|
|
|
: grey(_grey), candidatesArrays(_candidatesArrays), contoursArrays(_contoursArrays), |
|
|
|
|
params(_params) {} |
|
|
|
|
|
|
|
|
|
void operator()(const Range &range) const CV_OVERRIDE { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for(int i = begin; i < end; i++) { |
|
|
|
|
int currScale = |
|
|
|
|
params->adaptiveThreshWinSizeMin + i * params->adaptiveThreshWinSizeStep; |
|
|
|
|
// threshold
|
|
|
|
|
Mat thresh; |
|
|
|
|
_threshold(*grey, thresh, currScale, params->adaptiveThreshConstant); |
|
|
|
|
|
|
|
|
|
// detect rectangles
|
|
|
|
|
_findMarkerContours(thresh, (*candidatesArrays)[i], (*contoursArrays)[i], |
|
|
|
|
params->minMarkerPerimeterRate, params->maxMarkerPerimeterRate, |
|
|
|
|
params->polygonalApproxAccuracyRate, params->minCornerDistanceRate, |
|
|
|
|
params->minDistanceToBorder); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
DetectInitialCandidatesParallel &operator=(const DetectInitialCandidatesParallel &); |
|
|
|
|
|
|
|
|
|
const Mat *grey; |
|
|
|
|
vector< vector< vector< Point2f > > > *candidatesArrays; |
|
|
|
|
vector< vector< vector< Point > > > *contoursArrays; |
|
|
|
|
const Ptr<DetectorParameters> ¶ms; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Initial steps on finding square candidates |
|
|
|
|
*/ |
|
|
|
@ -341,21 +298,23 @@ static void _detectInitialCandidates(const Mat &grey, vector< vector< Point2f > |
|
|
|
|
vector< vector< vector< Point > > > contoursArrays((size_t) nScales); |
|
|
|
|
|
|
|
|
|
////for each value in the interval of thresholding window sizes
|
|
|
|
|
// for(int i = 0; i < nScales; i++) {
|
|
|
|
|
// int currScale = params.adaptiveThreshWinSizeMin + i*params.adaptiveThreshWinSizeStep;
|
|
|
|
|
// // treshold
|
|
|
|
|
// Mat thresh;
|
|
|
|
|
// _threshold(grey, thresh, currScale, params.adaptiveThreshConstant);
|
|
|
|
|
// // detect rectangles
|
|
|
|
|
// _findMarkerContours(thresh, candidatesArrays[i], contoursArrays[i],
|
|
|
|
|
// params.minMarkerPerimeterRate,
|
|
|
|
|
// params.maxMarkerPerimeterRate, params.polygonalApproxAccuracyRate,
|
|
|
|
|
// params.minCornerDistance, params.minDistanceToBorder);
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
// this is the parallel call for the previous commented loop (result is equivalent)
|
|
|
|
|
parallel_for_(Range(0, nScales), DetectInitialCandidatesParallel(&grey, &candidatesArrays, |
|
|
|
|
&contoursArrays, params)); |
|
|
|
|
parallel_for_(Range(0, nScales), [&](const Range& range) { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for (int i = begin; i < end; i++) { |
|
|
|
|
int currScale = params->adaptiveThreshWinSizeMin + i * params->adaptiveThreshWinSizeStep; |
|
|
|
|
// threshold
|
|
|
|
|
Mat thresh; |
|
|
|
|
_threshold(grey, thresh, currScale, params->adaptiveThreshConstant); |
|
|
|
|
|
|
|
|
|
// detect rectangles
|
|
|
|
|
_findMarkerContours(thresh, candidatesArrays[i], contoursArrays[i], |
|
|
|
|
params->minMarkerPerimeterRate, params->maxMarkerPerimeterRate, |
|
|
|
|
params->polygonalApproxAccuracyRate, params->minCornerDistanceRate, |
|
|
|
|
params->minDistanceToBorder); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// join candidates
|
|
|
|
|
for(int i = 0; i < nScales; i++) { |
|
|
|
@ -545,46 +504,6 @@ static bool _identifyOneCandidate(const Ptr<Dictionary>& dictionary, InputArray |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ParallelLoopBody class for the parallelization of the marker identification step |
|
|
|
|
* Called from function _identifyCandidates() |
|
|
|
|
*/ |
|
|
|
|
class IdentifyCandidatesParallel : public ParallelLoopBody { |
|
|
|
|
public: |
|
|
|
|
IdentifyCandidatesParallel(const Mat& _grey, vector< vector< Point2f > >& _candidates, |
|
|
|
|
const Ptr<Dictionary> &_dictionary, |
|
|
|
|
vector< int >& _idsTmp, vector< char >& _validCandidates, |
|
|
|
|
const Ptr<DetectorParameters> &_params) |
|
|
|
|
: grey(_grey), candidates(_candidates), dictionary(_dictionary), |
|
|
|
|
idsTmp(_idsTmp), validCandidates(_validCandidates), params(_params) {} |
|
|
|
|
|
|
|
|
|
void operator()(const Range &range) const CV_OVERRIDE { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for(int i = begin; i < end; i++) { |
|
|
|
|
int currId; |
|
|
|
|
if(_identifyOneCandidate(dictionary, grey, candidates[i], currId, params)) { |
|
|
|
|
validCandidates[i] = 1; |
|
|
|
|
idsTmp[i] = currId; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
IdentifyCandidatesParallel &operator=(const IdentifyCandidatesParallel &); // to quiet MSVC
|
|
|
|
|
|
|
|
|
|
const Mat &grey; |
|
|
|
|
vector< vector< Point2f > >& candidates; |
|
|
|
|
const Ptr<Dictionary> &dictionary; |
|
|
|
|
vector< int > &idsTmp; |
|
|
|
|
vector< char > &validCandidates; |
|
|
|
|
const Ptr<DetectorParameters> ¶ms; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Copy the contents of a corners vector to an OutputArray, settings its size. |
|
|
|
|
*/ |
|
|
|
@ -645,19 +564,18 @@ static void _identifyCandidates(InputArray _image, vector< vector< Point2f > >& |
|
|
|
|
vector< char > validCandidates(ncandidates, 0); |
|
|
|
|
|
|
|
|
|
//// Analyze each of the candidates
|
|
|
|
|
// for (int i = 0; i < ncandidates; i++) {
|
|
|
|
|
// int currId = i;
|
|
|
|
|
// Mat currentCandidate = _candidates.getMat(i);
|
|
|
|
|
// if (_identifyOneCandidate(dictionary, grey, currentCandidate, currId, params)) {
|
|
|
|
|
// validCandidates[i] = 1;
|
|
|
|
|
// idsTmp[i] = currId;
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
// this is the parallel call for the previous commented loop (result is equivalent)
|
|
|
|
|
parallel_for_(Range(0, ncandidates), |
|
|
|
|
IdentifyCandidatesParallel(grey, _candidates, _dictionary, idsTmp, |
|
|
|
|
validCandidates, params)); |
|
|
|
|
parallel_for_(Range(0, ncandidates), [&](const Range &range) { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for(int i = begin; i < end; i++) { |
|
|
|
|
int currId; |
|
|
|
|
if(_identifyOneCandidate(_dictionary, grey, _candidates[i], currId, params)) { |
|
|
|
|
validCandidates[i] = 1; |
|
|
|
|
idsTmp[i] = currId; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < ncandidates; i++) { |
|
|
|
|
if(validCandidates[i] == 1) { |
|
|
|
@ -772,40 +690,6 @@ static void _getSingleMarkerObjectPoints(float markerLength, OutputArray _objPoi |
|
|
|
|
objPoints.ptr< Vec3f >(0)[3] = Vec3f(-markerLength / 2.f, -markerLength / 2.f, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ParallelLoopBody class for the parallelization of the marker corner subpixel refinement |
|
|
|
|
* Called from function detectMarkers() |
|
|
|
|
*/ |
|
|
|
|
class MarkerSubpixelParallel : public ParallelLoopBody { |
|
|
|
|
public: |
|
|
|
|
MarkerSubpixelParallel(const Mat *_grey, OutputArrayOfArrays _corners, |
|
|
|
|
const Ptr<DetectorParameters> &_params) |
|
|
|
|
: grey(_grey), corners(_corners), params(_params) {} |
|
|
|
|
|
|
|
|
|
void operator()(const Range &range) const CV_OVERRIDE { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for(int i = begin; i < end; i++) { |
|
|
|
|
cornerSubPix(*grey, corners.getMat(i), |
|
|
|
|
Size(params->cornerRefinementWinSize, params->cornerRefinementWinSize), |
|
|
|
|
Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, |
|
|
|
|
params->cornerRefinementMaxIterations, |
|
|
|
|
params->cornerRefinementMinAccuracy)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
MarkerSubpixelParallel &operator=(const MarkerSubpixelParallel &); // to quiet MSVC
|
|
|
|
|
|
|
|
|
|
const Mat *grey; |
|
|
|
|
OutputArrayOfArrays corners; |
|
|
|
|
const Ptr<DetectorParameters> ¶ms; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Line fitting A * B = C :: Called from function refineCandidateLines |
|
|
|
|
* @param nContours, contour-container |
|
|
|
@ -948,34 +832,6 @@ static void _refineCandidateLines(std::vector<Point>& nContours, std::vector<Poi |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ParallelLoopBody class for the parallelization of the marker corner contour refinement |
|
|
|
|
* Called from function detectMarkers() |
|
|
|
|
*/ |
|
|
|
|
class MarkerContourParallel : public ParallelLoopBody { |
|
|
|
|
public: |
|
|
|
|
MarkerContourParallel( vector< vector< Point > >& _contours, vector< vector< Point2f > >& _candidates, const Mat& _camMatrix, const Mat& _distCoeff) |
|
|
|
|
: contours(_contours), candidates(_candidates), camMatrix(_camMatrix), distCoeff(_distCoeff){} |
|
|
|
|
|
|
|
|
|
void operator()(const Range &range) const CV_OVERRIDE { |
|
|
|
|
|
|
|
|
|
for(int i = range.start; i < range.end; i++) { |
|
|
|
|
_refineCandidateLines(contours[i], candidates[i], camMatrix, distCoeff); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
MarkerContourParallel &operator=(const MarkerContourParallel &){ |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vector< vector< Point > >& contours; |
|
|
|
|
vector< vector< Point2f > >& candidates; |
|
|
|
|
const Mat& camMatrix; |
|
|
|
|
const Mat& distCoeff; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#ifdef APRIL_DEBUG |
|
|
|
|
static void _darken(const Mat &im){ |
|
|
|
|
for (int y = 0; y < im.rows; y++) { |
|
|
|
@ -1152,17 +1008,19 @@ void detectMarkers(InputArray _image, const Ptr<Dictionary> &_dictionary, Output |
|
|
|
|
_params->cornerRefinementMinAccuracy > 0); |
|
|
|
|
|
|
|
|
|
//// do corner refinement for each of the detected markers
|
|
|
|
|
// for (unsigned int i = 0; i < _corners.cols(); i++) {
|
|
|
|
|
// cornerSubPix(grey, _corners.getMat(i),
|
|
|
|
|
// Size(params.cornerRefinementWinSize, params.cornerRefinementWinSize),
|
|
|
|
|
// Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
|
|
|
|
|
// params.cornerRefinementMaxIterations,
|
|
|
|
|
// params.cornerRefinementMinAccuracy));
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
// this is the parallel call for the previous commented loop (result is equivalent)
|
|
|
|
|
parallel_for_(Range(0, _corners.cols()), |
|
|
|
|
MarkerSubpixelParallel(&grey, _corners, _params)); |
|
|
|
|
parallel_for_(Range(0, _corners.cols()), [&](const Range& range) { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for (int i = begin; i < end; i++) { |
|
|
|
|
cornerSubPix(grey, _corners.getMat(i), |
|
|
|
|
Size(_params->cornerRefinementWinSize, _params->cornerRefinementWinSize), |
|
|
|
|
Size(-1, -1), |
|
|
|
|
TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, |
|
|
|
|
_params->cornerRefinementMaxIterations, |
|
|
|
|
_params->cornerRefinementMinAccuracy)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// STEP 4, Optional : Corner refinement :: use contour container
|
|
|
|
@ -1171,7 +1029,12 @@ void detectMarkers(InputArray _image, const Ptr<Dictionary> &_dictionary, Output |
|
|
|
|
if(! _ids.empty()){ |
|
|
|
|
|
|
|
|
|
// do corner refinement using the contours for each detected markers
|
|
|
|
|
parallel_for_(Range(0, _corners.cols()), MarkerContourParallel(contours, candidates, camMatrix.getMat(), distCoeff.getMat())); |
|
|
|
|
parallel_for_(Range(0, _corners.cols()), [&](const Range& range) { |
|
|
|
|
for (int i = range.start; i < range.end; i++) { |
|
|
|
|
_refineCandidateLines(contours[i], candidates[i], camMatrix.getMat(), |
|
|
|
|
distCoeff.getMat()); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// copy the corners to the output array
|
|
|
|
|
_copyVector2Output(candidates, _corners); |
|
|
|
@ -1179,42 +1042,6 @@ void detectMarkers(InputArray _image, const Ptr<Dictionary> &_dictionary, Output |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ParallelLoopBody class for the parallelization of the single markers pose estimation |
|
|
|
|
* Called from function estimatePoseSingleMarkers() |
|
|
|
|
*/ |
|
|
|
|
class SinglePoseEstimationParallel : public ParallelLoopBody { |
|
|
|
|
public: |
|
|
|
|
SinglePoseEstimationParallel(Mat& _markerObjPoints, InputArrayOfArrays _corners, |
|
|
|
|
InputArray _cameraMatrix, InputArray _distCoeffs, |
|
|
|
|
Mat& _rvecs, Mat& _tvecs) |
|
|
|
|
: markerObjPoints(_markerObjPoints), corners(_corners), cameraMatrix(_cameraMatrix), |
|
|
|
|
distCoeffs(_distCoeffs), rvecs(_rvecs), tvecs(_tvecs) {} |
|
|
|
|
|
|
|
|
|
void operator()(const Range &range) const CV_OVERRIDE { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for(int i = begin; i < end; i++) { |
|
|
|
|
solvePnP(markerObjPoints, corners.getMat(i), cameraMatrix, distCoeffs, |
|
|
|
|
rvecs.at<Vec3d>(i), tvecs.at<Vec3d>(i)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
SinglePoseEstimationParallel &operator=(const SinglePoseEstimationParallel &); // to quiet MSVC
|
|
|
|
|
|
|
|
|
|
Mat& markerObjPoints; |
|
|
|
|
InputArrayOfArrays corners; |
|
|
|
|
InputArray cameraMatrix, distCoeffs; |
|
|
|
|
Mat& rvecs, tvecs; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/ |
|
|
|
|
void estimatePoseSingleMarkers(InputArrayOfArrays _corners, float markerLength, |
|
|
|
@ -1232,15 +1059,16 @@ void estimatePoseSingleMarkers(InputArrayOfArrays _corners, float markerLength, |
|
|
|
|
Mat rvecs = _rvecs.getMat(), tvecs = _tvecs.getMat(); |
|
|
|
|
|
|
|
|
|
//// for each marker, calculate its pose
|
|
|
|
|
// for (int i = 0; i < nMarkers; i++) {
|
|
|
|
|
// solvePnP(markerObjPoints, _corners.getMat(i), _cameraMatrix, _distCoeffs,
|
|
|
|
|
// _rvecs.getMat(i), _tvecs.getMat(i));
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
// this is the parallel call for the previous commented loop (result is equivalent)
|
|
|
|
|
parallel_for_(Range(0, nMarkers), |
|
|
|
|
SinglePoseEstimationParallel(markerObjPoints, _corners, _cameraMatrix, |
|
|
|
|
_distCoeffs, rvecs, tvecs)); |
|
|
|
|
parallel_for_(Range(0, nMarkers), [&](const Range& range) { |
|
|
|
|
const int begin = range.start; |
|
|
|
|
const int end = range.end; |
|
|
|
|
|
|
|
|
|
for (int i = begin; i < end; i++) { |
|
|
|
|
solvePnP(markerObjPoints, _corners.getMat(i), _cameraMatrix, _distCoeffs, rvecs.at<Vec3d>(i), |
|
|
|
|
tvecs.at<Vec3d>(i)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if(_objPoints.needed()){ |
|
|
|
|
markerObjPoints.convertTo(_objPoints, -1); |
|
|
|
|
} |
|
|
|
|