Undo multi dict functionality of refineDetectedMarkers method

This commit is contained in:
Benjamin Knecht 2025-02-20 15:27:19 +01:00
parent 1f9d6aa6cf
commit 364eedb87e

View File

@ -1240,6 +1240,7 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Board& _board
InputOutputArrayOfArrays _rejectedCorners, InputArray _cameraMatrix, InputOutputArrayOfArrays _rejectedCorners, InputArray _cameraMatrix,
InputArray _distCoeffs, OutputArray _recoveredIdxs) const { InputArray _distCoeffs, OutputArray _recoveredIdxs) const {
DetectorParameters& detectorParams = arucoDetectorImpl->detectorParams; DetectorParameters& detectorParams = arucoDetectorImpl->detectorParams;
const Dictionary& dictionary = arucoDetectorImpl->dictionaries.at(0);
RefineParameters& refineParams = arucoDetectorImpl->refineParams; RefineParameters& refineParams = arucoDetectorImpl->refineParams;
CV_Assert(refineParams.minRepDistance > 0); CV_Assert(refineParams.minRepDistance > 0);
@ -1262,6 +1263,10 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Board& _board
// list of missing markers indicating if they have been assigned to a candidate // list of missing markers indicating if they have been assigned to a candidate
vector<bool > alreadyIdentified(_rejectedCorners.total(), false); vector<bool > alreadyIdentified(_rejectedCorners.total(), false);
// maximum bits that can be corrected
int maxCorrectionRecalculated =
int(double(dictionary.maxCorrectionBits) * refineParams.errorCorrectionRate);
Mat grey; Mat grey;
_convertToGrey(_image, grey); _convertToGrey(_image, grey);
@ -1277,112 +1282,106 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Board& _board
} }
vector<int> recoveredIdxs; // original indexes of accepted markers in _rejectedCorners vector<int> recoveredIdxs; // original indexes of accepted markers in _rejectedCorners
for (const auto& dictionary : arucoDetectorImpl->dictionaries) { // for each missing marker, try to find a correspondence
// maximum bits that can be corrected for(unsigned int i = 0; i < undetectedMarkersIds.size(); i++) {
int maxCorrectionRecalculated =
int(double(dictionary.maxCorrectionBits) * refineParams.errorCorrectionRate);
// for each missing marker, try to find a correspondence // best match at the moment
for(unsigned int i = 0; i < undetectedMarkersIds.size(); i++) { int closestCandidateIdx = -1;
double closestCandidateDistance = refineParams.minRepDistance * refineParams.minRepDistance + 1;
Mat closestRotatedMarker;
// best match at the moment for(unsigned int j = 0; j < _rejectedCorners.total(); j++) {
int closestCandidateIdx = -1; if(alreadyIdentified[j]) continue;
double closestCandidateDistance = refineParams.minRepDistance * refineParams.minRepDistance + 1;
Mat closestRotatedMarker;
for(unsigned int j = 0; j < _rejectedCorners.total(); j++) { // check distance
if(alreadyIdentified[j]) continue; double minDistance = closestCandidateDistance + 1;
bool valid = false;
// check distance int validRot = 0;
double minDistance = closestCandidateDistance + 1; for(int c = 0; c < 4; c++) { // first corner in rejected candidate
bool valid = false; double currentMaxDistance = 0;
int validRot = 0; for(int k = 0; k < 4; k++) {
for(int c = 0; c < 4; c++) { // first corner in rejected candidate Point2f rejCorner = _rejectedCorners.getMat(j).ptr<Point2f>()[(c + k) % 4];
double currentMaxDistance = 0; Point2f distVector = undetectedMarkersCorners[i][k] - rejCorner;
for(int k = 0; k < 4; k++) { double cornerDist = distVector.x * distVector.x + distVector.y * distVector.y;
Point2f rejCorner = _rejectedCorners.getMat(j).ptr<Point2f>()[(c + k) % 4]; currentMaxDistance = max(currentMaxDistance, cornerDist);
Point2f distVector = undetectedMarkersCorners[i][k] - rejCorner;
double cornerDist = distVector.x * distVector.x + distVector.y * distVector.y;
currentMaxDistance = max(currentMaxDistance, cornerDist);
}
// if distance is better than current best distance
if(currentMaxDistance < closestCandidateDistance) {
valid = true;
validRot = c;
minDistance = currentMaxDistance;
}
if(!refineParams.checkAllOrders) break;
} }
// if distance is better than current best distance
if(!valid) continue; if(currentMaxDistance < closestCandidateDistance) {
valid = true;
// apply rotation validRot = c;
Mat rotatedMarker; minDistance = currentMaxDistance;
if(refineParams.checkAllOrders) {
rotatedMarker = Mat(4, 1, CV_32FC2);
for(int c = 0; c < 4; c++)
rotatedMarker.ptr<Point2f>()[c] =
_rejectedCorners.getMat(j).ptr<Point2f>()[(c + 4 + validRot) % 4];
}
else rotatedMarker = _rejectedCorners.getMat(j);
// last filter, check if inner code is close enough to the assigned marker code
int codeDistance = 0;
// if errorCorrectionRate, dont check code
if(refineParams.errorCorrectionRate >= 0) {
// extract bits
Mat bits = _extractBits(
grey, rotatedMarker, dictionary.markerSize, detectorParams.markerBorderBits,
detectorParams.perspectiveRemovePixelPerCell,
detectorParams.perspectiveRemoveIgnoredMarginPerCell, detectorParams.minOtsuStdDev);
Mat onlyBits =
bits.rowRange(detectorParams.markerBorderBits, bits.rows - detectorParams.markerBorderBits)
.colRange(detectorParams.markerBorderBits, bits.rows - detectorParams.markerBorderBits);
codeDistance =
dictionary.getDistanceToId(onlyBits, undetectedMarkersIds[i], false);
}
// if everythin is ok, assign values to current best match
if(refineParams.errorCorrectionRate < 0 || codeDistance < maxCorrectionRecalculated) {
closestCandidateIdx = j;
closestCandidateDistance = minDistance;
closestRotatedMarker = rotatedMarker;
} }
if(!refineParams.checkAllOrders) break;
} }
// if at least one good match, we have rescue the missing marker if(!valid) continue;
if(closestCandidateIdx >= 0) {
// subpixel refinement // apply rotation
if(detectorParams.cornerRefinementMethod == (int)CORNER_REFINE_SUBPIX) { Mat rotatedMarker;
CV_Assert(detectorParams.cornerRefinementWinSize > 0 && if(refineParams.checkAllOrders) {
detectorParams.cornerRefinementMaxIterations > 0 && rotatedMarker = Mat(4, 1, CV_32FC2);
detectorParams.cornerRefinementMinAccuracy > 0); for(int c = 0; c < 4; c++)
rotatedMarker.ptr<Point2f>()[c] =
std::vector<Point2f> marker(closestRotatedMarker.begin<Point2f>(), closestRotatedMarker.end<Point2f>()); _rejectedCorners.getMat(j).ptr<Point2f>()[(c + 4 + validRot) % 4];
int cornerRefinementWinSize = std::max(1, cvRound(detectorParams.relativeCornerRefinmentWinSize*
getAverageModuleSize(marker, dictionary.markerSize, detectorParams.markerBorderBits)));
cornerRefinementWinSize = min(cornerRefinementWinSize, detectorParams.cornerRefinementWinSize);
cornerSubPix(grey, closestRotatedMarker,
Size(cornerRefinementWinSize, cornerRefinementWinSize),
Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
detectorParams.cornerRefinementMaxIterations,
detectorParams.cornerRefinementMinAccuracy));
}
// remove from rejected
alreadyIdentified[closestCandidateIdx] = true;
// add to detected
finalAcceptedCorners.push_back(closestRotatedMarker);
finalAcceptedIds.push_back(undetectedMarkersIds[i]);
// add the original index of the candidate
recoveredIdxs.push_back(closestCandidateIdx);
} }
else rotatedMarker = _rejectedCorners.getMat(j);
// last filter, check if inner code is close enough to the assigned marker code
int codeDistance = 0;
// if errorCorrectionRate, dont check code
if(refineParams.errorCorrectionRate >= 0) {
// extract bits
Mat bits = _extractBits(
grey, rotatedMarker, dictionary.markerSize, detectorParams.markerBorderBits,
detectorParams.perspectiveRemovePixelPerCell,
detectorParams.perspectiveRemoveIgnoredMarginPerCell, detectorParams.minOtsuStdDev);
Mat onlyBits =
bits.rowRange(detectorParams.markerBorderBits, bits.rows - detectorParams.markerBorderBits)
.colRange(detectorParams.markerBorderBits, bits.rows - detectorParams.markerBorderBits);
codeDistance =
dictionary.getDistanceToId(onlyBits, undetectedMarkersIds[i], false);
}
// if everythin is ok, assign values to current best match
if(refineParams.errorCorrectionRate < 0 || codeDistance < maxCorrectionRecalculated) {
closestCandidateIdx = j;
closestCandidateDistance = minDistance;
closestRotatedMarker = rotatedMarker;
}
}
// if at least one good match, we have rescue the missing marker
if(closestCandidateIdx >= 0) {
// subpixel refinement
if(detectorParams.cornerRefinementMethod == (int)CORNER_REFINE_SUBPIX) {
CV_Assert(detectorParams.cornerRefinementWinSize > 0 &&
detectorParams.cornerRefinementMaxIterations > 0 &&
detectorParams.cornerRefinementMinAccuracy > 0);
std::vector<Point2f> marker(closestRotatedMarker.begin<Point2f>(), closestRotatedMarker.end<Point2f>());
int cornerRefinementWinSize = std::max(1, cvRound(detectorParams.relativeCornerRefinmentWinSize*
getAverageModuleSize(marker, dictionary.markerSize, detectorParams.markerBorderBits)));
cornerRefinementWinSize = min(cornerRefinementWinSize, detectorParams.cornerRefinementWinSize);
cornerSubPix(grey, closestRotatedMarker,
Size(cornerRefinementWinSize, cornerRefinementWinSize),
Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
detectorParams.cornerRefinementMaxIterations,
detectorParams.cornerRefinementMinAccuracy));
}
// remove from rejected
alreadyIdentified[closestCandidateIdx] = true;
// add to detected
finalAcceptedCorners.push_back(closestRotatedMarker);
finalAcceptedIds.push_back(undetectedMarkersIds[i]);
// add the original index of the candidate
recoveredIdxs.push_back(closestCandidateIdx);
} }
} }