41 #include <opencv2/core.hpp> 42 #include <opencv2/imgproc.hpp> 49 #include "opencv2/imgcodecs.hpp" 62 : adaptiveThreshWinSizeMin(3),
63 adaptiveThreshWinSizeMax(23),
64 adaptiveThreshWinSizeStep(10),
65 adaptiveThreshConstant(7),
66 minMarkerPerimeterRate(0.03),
67 maxMarkerPerimeterRate(4.),
68 polygonalApproxAccuracyRate(0.03),
69 minCornerDistanceRate(0.05),
70 minDistanceToBorder(3),
71 minMarkerDistanceRate(0.05),
73 cornerRefinementWinSize(5),
74 cornerRefinementMaxIterations(30),
75 cornerRefinementMinAccuracy(0.1),
77 perspectiveRemovePixelPerCell(4),
78 perspectiveRemoveIgnoredMarginPerCell(0.13),
79 maxErroneousBitsInBorderRate(0.35),
81 errorCorrectionRate(0.6),
82 aprilTagQuadDecimate(0.0),
83 aprilTagQuadSigma(0.0),
84 aprilTagMinClusterPixels(5),
85 aprilTagMaxNmaxima(10),
86 aprilTagCriticalRad( (float)(10* CV_PI /180) ),
87 aprilTagMaxLineFitMse(10.0),
88 aprilTagMinWhiteBlackDiff(5),
90 detectInvertedMarker(false){}
97 Ptr<DetectorParameters> params = makePtr<DetectorParameters>();
107 CV_Assert(_in.type() == CV_8UC1 || _in.type() == CV_8UC3);
109 if(_in.type() == CV_8UC3)
110 cvtColor(_in, _out, COLOR_BGR2GRAY);
119 static void _threshold(InputArray _in, OutputArray _out,
int winSize,
double constant) {
121 CV_Assert(winSize >= 3);
122 if(winSize % 2 == 0) winSize++;
123 adaptiveThreshold(_in, _out, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, winSize, constant);
132 vector< vector< Point > > &contoursOut,
double minPerimeterRate,
133 double maxPerimeterRate,
double accuracyRate,
136 CV_Assert(minPerimeterRate > 0 && maxPerimeterRate > 0 && accuracyRate > 0 &&
137 minCornerDistanceRate >= 0 && minDistanceToBorder >= 0);
140 unsigned int minPerimeterPixels =
141 (
unsigned int)(minPerimeterRate *
max(_in.getMat().cols, _in.getMat().rows));
142 unsigned int maxPerimeterPixels =
143 (
unsigned int)(maxPerimeterRate *
max(_in.getMat().cols, _in.getMat().rows));
146 _in.getMat().copyTo(contoursImg);
147 vector< vector< Point > > contours;
148 findContours(contoursImg, contours, RETR_LIST, CHAIN_APPROX_NONE);
150 for(
unsigned int i = 0; i < contours.size(); i++) {
152 if(contours[i].size() < minPerimeterPixels || contours[i].size() > maxPerimeterPixels)
156 vector< Point > approxCurve;
157 approxPolyDP(contours[i], approxCurve,
double(contours[i].size()) * accuracyRate,
true);
158 if(approxCurve.size() != 4 || !isContourConvex(approxCurve))
continue;
162 max(contoursImg.cols, contoursImg.rows) *
max(contoursImg.cols, contoursImg.rows);
163 for(
int j = 0; j < 4; j++) {
164 double d = (double)(approxCurve[j].x - approxCurve[(j + 1) % 4].x) *
165 (
double)(approxCurve[j].x - approxCurve[(j + 1) % 4].x) +
166 (double)(approxCurve[j].y - approxCurve[(j + 1) % 4].y) *
167 (
double)(approxCurve[j].y - approxCurve[(j + 1) % 4].y);
168 minDistSq =
min(minDistSq, d);
171 if(minDistSq < minCornerDistancePixels * minCornerDistancePixels)
continue;
174 bool tooNearBorder =
false;
175 for(
int j = 0; j < 4; j++) {
176 if(approxCurve[j].x < minDistanceToBorder || approxCurve[j].y < minDistanceToBorder ||
177 approxCurve[j].x > contoursImg.cols - 1 - minDistanceToBorder ||
178 approxCurve[j].y > contoursImg.rows - 1 - minDistanceToBorder)
179 tooNearBorder =
true;
181 if(tooNearBorder)
continue;
184 vector< Point2f > currentCandidate;
185 currentCandidate.resize(4);
186 for(
int j = 0; j < 4; j++) {
187 currentCandidate[j] = Point2f((
float)approxCurve[j].x, (
float)approxCurve[j].y);
189 candidates.push_back(currentCandidate);
190 contoursOut.push_back(contours[i]);
200 for(
unsigned int i = 0; i < candidates.size(); i++) {
201 double dx1 = candidates[i][1].x - candidates[i][0].x;
202 double dy1 = candidates[i][1].y - candidates[i][0].y;
203 double dx2 = candidates[i][2].x - candidates[i][0].x;
204 double dy2 = candidates[i][2].y - candidates[i][0].y;
205 double crossProduct = (dx1 * dy2) - (dy1 * dx2);
207 if(crossProduct < 0.0) {
208 swap(candidates[i][1], candidates[i][3]);
218 vector< vector< Point2f > > &candidatesOut,
219 const vector< vector< Point > > &contoursIn,
220 vector< vector< Point > > &contoursOut,
223 CV_Assert(minMarkerDistanceRate >= 0);
225 vector< pair< int, int > > nearCandidates;
226 for(
unsigned int i = 0; i < candidatesIn.size(); i++) {
227 for(
unsigned int j = i + 1; j < candidatesIn.size(); j++) {
229 int minimumPerimeter =
min((
int)contoursIn[i].size(), (
int)contoursIn[j].size() );
232 for(
int fc = 0; fc < 4; fc++) {
234 for(
int c = 0; c < 4; c++) {
236 int modC = (c + fc) % 4;
237 distSq += (candidatesIn[i][modC].x - candidatesIn[j][c].x) *
238 (candidatesIn[i][modC].x - candidatesIn[j][c].x) +
239 (candidatesIn[i][modC].y - candidatesIn[j][c].y) *
240 (candidatesIn[i][modC].y - candidatesIn[j][c].y);
246 if(distSq < minMarkerDistancePixels * minMarkerDistancePixels) {
247 nearCandidates.push_back(pair< int, int >(i, j));
255 vector< bool > toRemove(candidatesIn.size(),
false);
256 for(
unsigned int i = 0; i < nearCandidates.size(); i++) {
258 if(toRemove[nearCandidates[i].
first] || toRemove[nearCandidates[i].second])
continue;
259 size_t perimeter1 = contoursIn[nearCandidates[i].first].size();
260 size_t perimeter2 = contoursIn[nearCandidates[i].second].size();
261 if(perimeter1 > perimeter2)
262 toRemove[nearCandidates[i].second] =
true;
264 toRemove[nearCandidates[i].first] =
true;
268 candidatesOut.clear();
269 unsigned long totalRemaining = 0;
270 for(
unsigned int i = 0; i < toRemove.size(); i++)
271 if(!toRemove[i]) totalRemaining++;
272 candidatesOut.resize(totalRemaining);
273 contoursOut.resize(totalRemaining);
274 for(
unsigned int i = 0, currIdx = 0; i < candidatesIn.size(); i++) {
275 if(toRemove[i])
continue;
276 candidatesOut[currIdx] = candidatesIn[i];
277 contoursOut[currIdx] = contoursIn[i];
290 vector< vector< vector< Point2f > > > *_candidatesArrays,
291 vector< vector< vector< Point > > > *_contoursArrays,
292 const Ptr<DetectorParameters> &_params)
293 : grey(_grey), candidatesArrays(_candidatesArrays), contoursArrays(_contoursArrays),
297 const int begin = range.start;
298 const int end = range.end;
300 for(
int i = begin; i < end; i++) {
302 params->adaptiveThreshWinSizeMin + i * params->adaptiveThreshWinSizeStep;
305 _threshold(*grey, thresh, currScale, params->adaptiveThreshConstant);
309 params->minMarkerPerimeterRate, params->maxMarkerPerimeterRate,
310 params->polygonalApproxAccuracyRate, params->minCornerDistanceRate,
311 params->minDistanceToBorder);
329 vector< vector< Point > > &contours,
330 const Ptr<DetectorParameters> ¶ms) {
332 CV_Assert(params->adaptiveThreshWinSizeMin >= 3 && params->adaptiveThreshWinSizeMax >= 3);
333 CV_Assert(params->adaptiveThreshWinSizeMax >= params->adaptiveThreshWinSizeMin);
334 CV_Assert(params->adaptiveThreshWinSizeStep > 0);
337 int nScales = (params->adaptiveThreshWinSizeMax - params->adaptiveThreshWinSizeMin) /
338 params->adaptiveThreshWinSizeStep + 1;
340 vector< vector< vector< Point2f > > > candidatesArrays((
size_t) nScales);
341 vector< vector< vector< Point > > > contoursArrays((
size_t) nScales);
358 &contoursArrays, params));
361 for(
int i = 0; i < nScales; i++) {
362 for(
unsigned int j = 0; j < candidatesArrays[i].size(); j++) {
363 candidates.push_back(candidatesArrays[i][j]);
364 contours.push_back(contoursArrays[i][j]);
374 vector< vector< Point > >& contoursOut,
const Ptr<DetectorParameters> &_params) {
376 Mat image = _image.getMat();
377 CV_Assert(image.total() != 0);
383 vector< vector< Point2f > > candidates;
384 vector< vector< Point > > contours;
393 _params->minMarkerDistanceRate);
403 double minStdDevOtsu) {
405 CV_Assert(_image.getMat().channels() == 1);
406 CV_Assert(_corners.total() == 4);
407 CV_Assert(markerBorderBits > 0 && cellSize > 0 && cellMarginRate >= 0 && cellMarginRate <= 1);
408 CV_Assert(minStdDevOtsu >= 0);
412 int cellMarginPixels = int(cellMarginRate * cellSize);
415 int resultImgSize = markerSizeWithBorders * cellSize;
416 Mat resultImgCorners(4, 1, CV_32FC2);
417 resultImgCorners.ptr< Point2f >(0)[0] = Point2f(0, 0);
418 resultImgCorners.ptr< Point2f >(0)[1] = Point2f((
float)resultImgSize - 1, 0);
419 resultImgCorners.ptr< Point2f >(0)[2] =
420 Point2f((
float)resultImgSize - 1, (float)resultImgSize - 1);
421 resultImgCorners.ptr< Point2f >(0)[3] = Point2f(0, (
float)resultImgSize - 1);
424 Mat transformation = getPerspectiveTransform(_corners, resultImgCorners);
425 warpPerspective(_image, resultImg, transformation, Size(resultImgSize, resultImgSize),
429 Mat bits(markerSizeWithBorders, markerSizeWithBorders, CV_8UC1, Scalar::all(0));
435 Mat innerRegion = resultImg.colRange(cellSize / 2, resultImg.cols - cellSize / 2)
436 .rowRange(cellSize / 2, resultImg.rows - cellSize / 2);
437 meanStdDev(innerRegion, mean, stddev);
438 if(stddev.ptr<
double >(0)[0] < minStdDevOtsu) {
440 if(mean.ptr<
double >(0)[0] > 127)
448 threshold(resultImg, resultImg, 125, 255, THRESH_BINARY | THRESH_OTSU);
451 for(
int y = 0; y < markerSizeWithBorders; y++) {
452 for(
int x = 0; x < markerSizeWithBorders; x++) {
453 int Xstart = x * (cellSize) + cellMarginPixels;
454 int Ystart = y * (cellSize) + cellMarginPixels;
455 Mat square = resultImg(Rect(Xstart, Ystart, cellSize - 2 * cellMarginPixels,
456 cellSize - 2 * cellMarginPixels));
458 size_t nZ = (size_t) countNonZero(square);
459 if(nZ > square.total() / 2) bits.at<
unsigned char >(y, x) = 1;
473 int sizeWithBorders = markerSize + 2 * borderSize;
475 CV_Assert(markerSize > 0 && bits.cols == sizeWithBorders && bits.rows == sizeWithBorders);
478 for(
int y = 0; y < sizeWithBorders; y++) {
479 for(
int k = 0; k < borderSize; k++) {
480 if(bits.ptr<
unsigned char >(y)[k] != 0) totalErrors++;
481 if(bits.ptr<
unsigned char >(y)[sizeWithBorders - 1 - k] != 0) totalErrors++;
484 for(
int x = borderSize; x < sizeWithBorders - borderSize; x++) {
485 for(
int k = 0; k < borderSize; k++) {
486 if(bits.ptr<
unsigned char >(k)[x] != 0) totalErrors++;
487 if(bits.ptr<
unsigned char >(sizeWithBorders - 1 - k)[x] != 0) totalErrors++;
498 vector<Point2f>& _corners,
int& idx,
499 const Ptr<DetectorParameters>& params)
501 CV_Assert(_corners.size() == 4);
502 CV_Assert(_image.getMat().total() != 0);
503 CV_Assert(params->markerBorderBits > 0);
507 _extractBits(_image, _corners, dictionary->markerSize, params->markerBorderBits,
508 params->perspectiveRemovePixelPerCell,
509 params->perspectiveRemoveIgnoredMarginPerCell, params->minOtsuStdDev);
512 int maximumErrorsInBorder =
513 int(dictionary->markerSize * dictionary->markerSize * params->maxErroneousBitsInBorderRate);
515 _getBorderErrors(candidateBits, dictionary->markerSize, params->markerBorderBits);
518 if(params->detectInvertedMarker){
520 Mat invertedImg = ~candidateBits-254;
521 int invBError =
_getBorderErrors(invertedImg, dictionary->markerSize, params->markerBorderBits);
523 if(invBError<borderErrors){
524 borderErrors = invBError;
525 invertedImg.copyTo(candidateBits);
528 if(borderErrors > maximumErrorsInBorder)
return false;
532 candidateBits.rowRange(params->markerBorderBits,
533 candidateBits.rows - params->markerBorderBits)
534 .colRange(params->markerBorderBits, candidateBits.rows - params->markerBorderBits);
538 if(!dictionary->identify(onlyBits, idx, rotation, params->errorCorrectionRate))
543 std::rotate(_corners.begin(), _corners.begin() + 4 - rotation, _corners.end());
556 const Ptr<Dictionary> &_dictionary,
557 vector< int >& _idsTmp, vector< char >& _validCandidates,
558 const Ptr<DetectorParameters> &_params)
559 : grey(_grey), candidates(_candidates), dictionary(_dictionary),
560 idsTmp(_idsTmp), validCandidates(_validCandidates), params(_params) {}
563 const int begin = range.start;
564 const int end = range.end;
566 for(
int i = begin; i < end; i++) {
569 validCandidates[i] = 1;
592 out.create((
int)vec.size(), 1, CV_32FC2);
594 if(out.isMatVector()) {
595 for (
unsigned int i = 0; i < vec.size(); i++) {
596 out.create(4, 1, CV_32FC2, i);
597 Mat &m = out.getMatRef(i);
598 Mat(Mat(vec[i]).
t()).copyTo(m);
601 else if(out.isUMatVector()) {
602 for (
unsigned int i = 0; i < vec.size(); i++) {
603 out.create(4, 1, CV_32FC2, i);
604 UMat &m = out.getUMatRef(i);
605 Mat(Mat(vec[i]).
t()).copyTo(m);
608 else if(out.kind() == _OutputArray::STD_VECTOR_VECTOR){
609 for (
unsigned int i = 0; i < vec.size(); i++) {
610 out.create(4, 1, CV_32FC2, i);
611 Mat m = out.getMat(i);
612 Mat(Mat(vec[i]).
t()).copyTo(m);
616 CV_Error(cv::Error::StsNotImplemented,
617 "Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
627 vector< vector<Point> >& _contours,
const Ptr<Dictionary> &_dictionary,
628 vector< vector< Point2f > >& _accepted, vector< int >&
ids,
629 const Ptr<DetectorParameters> ¶ms,
630 OutputArrayOfArrays _rejected = noArray()) {
632 int ncandidates = (int)_candidates.size();
634 vector< vector< Point2f > > accepted;
635 vector< vector< Point2f > > rejected;
637 vector< vector< Point > > contours;
639 CV_Assert(_image.getMat().total() != 0);
644 vector< int > idsTmp(ncandidates, -1);
645 vector< char > validCandidates(ncandidates, 0);
658 parallel_for_(Range(0, ncandidates),
660 validCandidates, params));
662 for(
int i = 0; i < ncandidates; i++) {
663 if(validCandidates[i] == 1) {
664 accepted.push_back(_candidates[i]);
665 ids.push_back(idsTmp[i]);
667 contours.push_back(_contours[i]);
670 rejected.push_back(_candidates[i]);
675 _accepted = accepted;
679 if(_rejected.needed()) {
688 static void _filterDetectedMarkers(vector< vector< Point2f > >& _corners, vector< int >& _ids, vector< vector< Point> >& _contours) {
690 CV_Assert(_corners.size() == _ids.size());
691 if(_corners.empty())
return;
694 vector< bool > toRemove(_corners.size(),
false);
695 bool atLeastOneRemove =
false;
698 for(
unsigned int i = 0; i < _corners.size() - 1; i++) {
699 for(
unsigned int j = i + 1; j < _corners.size(); j++) {
700 if(_ids[i] != _ids[j])
continue;
704 for(
unsigned int p = 0; p < 4; p++) {
705 Point2f point = _corners[j][p];
706 if(pointPolygonTest(_corners[i], point,
false) < 0) {
713 atLeastOneRemove =
true;
719 for(
unsigned int p = 0; p < 4; p++) {
720 Point2f point = _corners[i][p];
721 if(pointPolygonTest(_corners[j], point,
false) < 0) {
728 atLeastOneRemove =
true;
735 if(atLeastOneRemove) {
736 vector< vector< Point2f > >::iterator filteredCorners = _corners.begin();
737 vector< int >::iterator filteredIds = _ids.begin();
739 vector< vector< Point > >::iterator filteredContours = _contours.begin();
741 for(
unsigned int i = 0; i < toRemove.size(); i++) {
743 *filteredCorners++ = _corners[i];
744 *filteredIds++ = _ids[i];
746 *filteredContours++ = _contours[i];
750 _ids.erase(filteredIds, _ids.end());
751 _corners.erase(filteredCorners, _corners.end());
753 _contours.erase(filteredContours, _contours.end());
764 CV_Assert(markerLength > 0);
766 _objPoints.create(4, 1, CV_32FC3);
767 Mat objPoints = _objPoints.getMat();
769 objPoints.ptr< Vec3f >(0)[0] = Vec3f(-markerLength / 2.
f, markerLength / 2.
f, 0);
770 objPoints.ptr< Vec3f >(0)[1] = Vec3f(markerLength / 2.
f, markerLength / 2.
f, 0);
771 objPoints.ptr< Vec3f >(0)[2] = Vec3f(markerLength / 2.
f, -markerLength / 2.
f, 0);
772 objPoints.ptr< Vec3f >(0)[3] = Vec3f(-markerLength / 2.
f, -markerLength / 2.
f, 0);
785 const Ptr<DetectorParameters> &_params)
786 : grey(_grey), corners(_corners), params(_params) {}
789 const int begin = range.start;
790 const int end = range.end;
792 for(
int i = begin; i < end; i++) {
793 cornerSubPix(*grey, corners.getMat(i),
794 Size(params->cornerRefinementWinSize, params->cornerRefinementWinSize),
795 Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
796 params->cornerRefinementMaxIterations,
797 params->cornerRefinementMinAccuracy));
814 float minX, minY, maxX, maxY;
815 minX = maxX = nContours[0].x;
816 minY = maxY = nContours[0].y;
818 for(
unsigned int i = 0; i< nContours.size(); i++){
819 minX = nContours[i].x < minX ? nContours[i].x : minX;
820 minY = nContours[i].y < minY ? nContours[i].y : minY;
821 maxX = nContours[i].x > maxX ? nContours[i].x : maxX;
822 maxY = nContours[i].y > maxY ? nContours[i].y : maxY;
825 Mat A = Mat::ones((
int)nContours.size(), 2, CV_32F);
826 Mat B((
int)nContours.size(), 1, CV_32F);
829 if(maxX - minX > maxY - minY){
830 for(
unsigned int i =0; i < nContours.size(); i++){
831 A.at<
float>(i,0)= nContours[i].x;
832 B.at<
float>(i,0)= nContours[i].y;
835 solve(A, B, C, DECOMP_NORMAL);
837 return Point3f(C.at<
float>(0, 0), -1., C.at<
float>(1, 0));
840 for(
unsigned int i =0; i < nContours.size(); i++){
841 A.at<
float>(i,0)= nContours[i].y;
842 B.at<
float>(i,0)= nContours[i].x;
845 solve(A, B, C, DECOMP_NORMAL);
847 return Point3f(-1., C.at<
float>(0, 0), C.at<
float>(1, 0));
859 Matx22f A(nLine1.x, nLine1.y, nLine2.x, nLine2.y);
860 Vec2f B(-nLine1.z, -nLine2.z);
861 return Vec2f(A.solve(B).val);
864 static void _distortPoints(vector<cv::Point2f>& in,
const Mat& camMatrix,
const Mat& distCoeff) {
870 vector<cv::Point3f> cornersPoints3d;
871 for (
unsigned int i = 0; i < in.size(); i++){
872 float x= (in[i].x - float(camMatrix.at<
double>(0, 2))) /
float(camMatrix.at<
double>(0, 0));
873 float y= (in[i].y - float(camMatrix.at<
double>(1, 2))) /
float(camMatrix.at<
double>(1, 1));
874 cornersPoints3d.push_back(Point3f(x,y,1));
876 cv::projectPoints(cornersPoints3d, Rvec, Tvec, camMatrix, distCoeff, in);
886 static void _refineCandidateLines(std::vector<Point>& nContours, std::vector<Point2f>& nCorners,
const Mat& camMatrix,
const Mat& distCoeff){
887 vector<Point2f> contour2f(nContours.begin(), nContours.end());
889 if(!camMatrix.empty() && !distCoeff.empty()){
890 undistortPoints(contour2f, contour2f, camMatrix, distCoeff);
897 vector<Point2f> cntPts[5];
898 int cornerIndex[4]={-1};
901 for (
unsigned int i =0; i < nContours.size(); i++ ) {
902 for(
unsigned int j=0; j<4; j++){
903 if ( nCorners[j] == contour2f[i] ){
908 cntPts[group].push_back(contour2f[i]);
912 if( !cntPts[4].empty() ){
913 for(
unsigned int i=0; i < cntPts[4].size() ; i++ )
914 cntPts[group].push_back(cntPts[4].at(i));
921 inc = ( (cornerIndex[0] > cornerIndex[1]) && (cornerIndex[3] > cornerIndex[0]) ) ? -1:inc;
922 inc = ( (cornerIndex[2] > cornerIndex[3]) && (cornerIndex[1] > cornerIndex[2]) ) ? -1:inc;
926 for(
int i=0; i<4; i++){
928 if (cntPts[i].size() < 2)
return;
941 for(
int i=0; i < 4; i++){
948 if(!camMatrix.empty() && !distCoeff.empty()){
960 MarkerContourParallel( vector< vector< Point > >& _contours, vector< vector< Point2f > >& _candidates,
const Mat& _camMatrix,
const Mat& _distCoeff)
961 : contours(_contours), candidates(_candidates), camMatrix(_camMatrix), distCoeff(_distCoeff){}
965 for(
int i = range.start; i < range.end; i++) {
982 static void _darken(
const Mat &im){
983 for (
int y = 0; y < im.rows; y++) {
984 for (
int x = 0; x < im.cols; x++) {
985 im.data[im.cols*y+x] /= 2;
998 static void _apriltag(Mat im_orig,
const Ptr<DetectorParameters> & _params, std::vector< std::vector< Point2f > > &candidates,
999 std::vector< std::vector< Point > > &contours){
1005 im_orig.copyTo(quad_im);
1007 if (_params->aprilTagQuadDecimate > 1){
1008 resize(im_orig, quad_im, Size(), 1/_params->aprilTagQuadDecimate, 1/_params->aprilTagQuadDecimate, INTER_AREA );
1012 if (_params->aprilTagQuadSigma != 0) {
1022 float sigma = fabsf((
float) _params->aprilTagQuadSigma);
1024 int ksz = cvFloor(4 * sigma);
1028 if (_params->aprilTagQuadSigma > 0)
1029 GaussianBlur(quad_im, quad_im, Size(ksz, ksz), sigma, sigma, BORDER_REPLICATE);
1032 quad_im.copyTo(orig);
1033 GaussianBlur(quad_im, quad_im, Size(ksz, ksz), sigma, sigma, BORDER_REPLICATE);
1036 for (
int y = 0; y < orig.rows; y++) {
1037 for (
int x = 0; x < orig.cols; x++) {
1038 int vorig = orig.data[y*orig.step + x];
1039 int vblur = quad_im.data[y*quad_im.step + x];
1041 int v = 2*vorig - vblur;
1047 quad_im.data[y*quad_im.step + x] = (uint8_t) v;
1055 imwrite(
"1.1 debug_preprocess.pnm", quad_im);
1062 CV_Assert(quads != NULL);
1066 if (_params->aprilTagQuadDecimate > 1) {
1070 for (
int j = 0; j < 4; j++) {
1071 q->
p[j][0] *= _params->aprilTagQuadDecimate;
1072 q->
p[j][1] *= _params->aprilTagQuadDecimate;
1078 Mat im_quads = im_orig.clone();
1079 im_quads = im_quads*0.5;
1086 const int bias = 100;
1087 int color = bias + (
random() % (255-bias));
1089 line(im_quads,
Point(quad->
p[0][0], quad->
p[0][1]),
Point(quad->
p[1][0], quad->
p[1][1]), color, 1);
1090 line(im_quads,
Point(quad->
p[1][0], quad->
p[1][1]),
Point(quad->
p[2][0], quad->
p[2][1]), color, 1);
1091 line(im_quads,
Point(quad->
p[2][0], quad->
p[2][1]),
Point(quad->
p[3][0], quad->
p[3][1]), color, 1);
1092 line(im_quads,
Point(quad->
p[3][0], quad->
p[3][1]),
Point(quad->
p[0][0], quad->
p[0][1]), color, 1);
1094 imwrite(
"1.2 debug_quads_raw.pnm", im_quads);
1103 std::vector< Point2f > corners;
1104 corners.push_back(Point2f(quad->
p[3][0], quad->
p[3][1]));
1105 corners.push_back(Point2f(quad->
p[0][0], quad->
p[0][1]));
1106 corners.push_back(Point2f(quad->
p[1][0], quad->
p[1][1]));
1107 corners.push_back(Point2f(quad->
p[2][0], quad->
p[2][1]));
1109 candidates.push_back(corners);
1118 void detectMarkers(InputArray _image,
const Ptr<Dictionary> &_dictionary, OutputArrayOfArrays _corners,
1119 OutputArray _ids,
const Ptr<DetectorParameters> &_params,
1120 OutputArrayOfArrays _rejectedImgPoints, InputArrayOfArrays camMatrix, InputArrayOfArrays distCoeff) {
1122 CV_Assert(!_image.empty());
1128 vector< vector< Point2f > > candidates;
1129 vector< vector< Point > > contours;
1134 _apriltag(grey, _params, candidates, contours);
1142 _rejectedImgPoints);
1149 Mat(ids).copyTo(_ids);
1153 CV_Assert(_params->cornerRefinementWinSize > 0 && _params->cornerRefinementMaxIterations > 0 &&
1154 _params->cornerRefinementMinAccuracy > 0);
1166 parallel_for_(Range(0, _corners.cols()),
1176 parallel_for_(Range(0, _corners.cols()),
MarkerContourParallel(contours, candidates, camMatrix.getMat(), distCoeff.getMat()));
1193 InputArray _cameraMatrix, InputArray _distCoeffs,
1194 Mat& _rvecs, Mat& _tvecs)
1195 : markerObjPoints(_markerObjPoints), corners(_corners),
cameraMatrix(_cameraMatrix),
1199 const int begin = range.start;
1200 const int end = range.end;
1202 for(
int i = begin; i < end; i++) {
1223 InputArray _cameraMatrix, InputArray _distCoeffs,
1224 OutputArray _rvecs, OutputArray _tvecs, OutputArray _objPoints) {
1226 CV_Assert(markerLength > 0);
1228 Mat markerObjPoints;
1230 int nMarkers = (int)_corners.total();
1231 _rvecs.create(nMarkers, 1, CV_64FC3);
1232 _tvecs.create(nMarkers, 1, CV_64FC3);
1234 Mat
rvecs = _rvecs.getMat(),
tvecs = _tvecs.getMat();
1243 parallel_for_(Range(0, nMarkers),
1245 _distCoeffs, rvecs,
tvecs));
1246 if(_objPoints.needed()){
1247 markerObjPoints.convertTo(_objPoints, -1);
1254 InputArray detectedIds, OutputArray objPoints, OutputArray imgPoints) {
1256 CV_Assert(board->ids.size() == board->objPoints.size());
1257 CV_Assert(detectedIds.total() == detectedCorners.total());
1259 size_t nDetectedMarkers = detectedIds.total();
1261 vector< Point3f > objPnts;
1262 objPnts.reserve(nDetectedMarkers);
1264 vector< Point2f > imgPnts;
1265 imgPnts.reserve(nDetectedMarkers);
1268 for(
unsigned int i = 0; i < nDetectedMarkers; i++) {
1269 int currentId = detectedIds.getMat().ptr<
int >(0)[i];
1270 for(
unsigned int j = 0; j < board->ids.size(); j++) {
1271 if(currentId == board->ids[j]) {
1272 for(
int p = 0; p < 4; p++) {
1273 objPnts.push_back(board->objPoints[j][p]);
1274 imgPnts.push_back(detectedCorners.getMat(i).ptr< Point2f >(0)[p]);
1281 Mat(objPnts).copyTo(objPoints);
1282 Mat(imgPnts).copyTo(imgPoints);
1291 InputOutputArray _detectedIds, InputArray _cameraMatrix,
1292 InputArray _distCoeffs,
1293 vector< vector< Point2f > >& _undetectedMarkersProjectedCorners,
1294 OutputArray _undetectedMarkersIds) {
1298 int boardDetectedMarkers;
1300 _cameraMatrix, _distCoeffs, rvec, tvec);
1303 if(boardDetectedMarkers == 0)
return;
1306 vector< vector< Point2f > > undetectedCorners;
1307 vector< int > undetectedIds;
1308 for(
unsigned int i = 0; i < _board->ids.size(); i++) {
1310 for(
unsigned int j = 0; j < _detectedIds.total(); j++) {
1311 if(_board->ids[i] == _detectedIds.getMat().ptr<
int >()[j]) {
1318 if(foundIdx == -1) {
1319 undetectedCorners.push_back(vector< Point2f >());
1320 undetectedIds.push_back(_board->ids[i]);
1321 projectPoints(_board->objPoints[i], rvec, tvec, _cameraMatrix, _distCoeffs,
1322 undetectedCorners.back());
1328 Mat(undetectedIds).copyTo(_undetectedMarkersIds);
1329 _undetectedMarkersProjectedCorners = undetectedCorners;
1339 InputOutputArray _detectedIds,
1340 vector< vector< Point2f > >& _undetectedMarkersProjectedCorners,
1341 OutputArray _undetectedMarkersIds) {
1345 CV_Assert(_board->objPoints.size() > 0);
1346 CV_Assert(_board->objPoints[0].size() > 0);
1347 float boardZ = _board->objPoints[0][0].z;
1348 for(
unsigned int i = 0; i < _board->objPoints.size(); i++) {
1349 for(
unsigned int j = 0; j < _board->objPoints[i].size(); j++) {
1350 CV_Assert(boardZ == _board->objPoints[i][j].z);
1354 vector< Point2f > detectedMarkersObj2DAll;
1356 vector< Point2f > imageCornersAll;
1357 vector< vector< Point2f > > undetectedMarkersObj2D;
1359 vector< int > undetectedMarkersIds;
1361 for(
unsigned int j = 0; j < _board->ids.size(); j++) {
1363 for(
unsigned int i = 0; i < _detectedIds.total(); i++) {
1364 if(_detectedIds.getMat().ptr<
int >()[i] == _board->ids[j]) {
1365 for(
int c = 0; c < 4; c++) {
1366 imageCornersAll.push_back(_detectedCorners.getMat(i).ptr< Point2f >()[c]);
1367 detectedMarkersObj2DAll.push_back(
1368 Point2f(_board->objPoints[j][c].x, _board->objPoints[j][c].y));
1375 undetectedMarkersObj2D.push_back(vector< Point2f >());
1376 for(
int c = 0; c < 4; c++) {
1377 undetectedMarkersObj2D.back().push_back(
1378 Point2f(_board->objPoints[j][c].x, _board->objPoints[j][c].y));
1380 undetectedMarkersIds.push_back(_board->ids[j]);
1383 if(imageCornersAll.size() == 0)
return;
1386 Mat transformation = findHomography(detectedMarkersObj2DAll, imageCornersAll);
1388 _undetectedMarkersProjectedCorners.resize(undetectedMarkersIds.size());
1391 for(
unsigned int i = 0; i < undetectedMarkersObj2D.size(); i++) {
1392 perspectiveTransform(undetectedMarkersObj2D[i], _undetectedMarkersProjectedCorners[i], transformation);
1395 Mat(undetectedMarkersIds).copyTo(_undetectedMarkersIds);
1403 InputOutputArrayOfArrays _detectedCorners, InputOutputArray _detectedIds,
1404 InputOutputArrayOfArrays _rejectedCorners, InputArray _cameraMatrix,
1406 bool checkAllOrders, OutputArray _recoveredIdxs,
1407 const Ptr<DetectorParameters> &_params) {
1409 CV_Assert(minRepDistance > 0);
1411 if(_detectedIds.total() == 0 || _rejectedCorners.total() == 0)
return;
1416 vector< vector< Point2f > > undetectedMarkersCorners;
1417 vector< int > undetectedMarkersIds;
1418 if(_cameraMatrix.total() != 0) {
1421 undetectedMarkersCorners, undetectedMarkersIds);
1426 undetectedMarkersIds);
1430 vector< bool > alreadyIdentified(_rejectedCorners.total(),
false);
1433 Dictionary &dictionary = *(_board->dictionary);
1434 int maxCorrectionRecalculated =
1435 int(
double(dictionary.maxCorrectionBits) * errorCorrectionRate);
1441 vector< Mat > finalAcceptedCorners;
1442 vector< int > finalAcceptedIds;
1444 finalAcceptedCorners.resize(_detectedCorners.total());
1445 finalAcceptedIds.resize(_detectedIds.total());
1446 for(
unsigned int i = 0; i < _detectedIds.total(); i++) {
1447 finalAcceptedCorners[i] = _detectedCorners.getMat(i).clone();
1448 finalAcceptedIds[i] = _detectedIds.getMat().ptr<
int >()[i];
1450 vector< int > recoveredIdxs;
1453 for(
unsigned int i = 0; i < undetectedMarkersIds.size(); i++) {
1456 int closestCandidateIdx = -1;
1457 double closestCandidateDistance = minRepDistance * minRepDistance + 1;
1458 Mat closestRotatedMarker;
1460 for(
unsigned int j = 0; j < _rejectedCorners.total(); j++) {
1461 if(alreadyIdentified[j])
continue;
1464 double minDistance = closestCandidateDistance + 1;
1467 for(
int c = 0; c < 4; c++) {
1468 double currentMaxDistance = 0;
1469 for(
int k = 0; k < 4; k++) {
1470 Point2f rejCorner = _rejectedCorners.getMat(j).ptr< Point2f >()[(c + k) % 4];
1471 Point2f distVector = undetectedMarkersCorners[i][k] - rejCorner;
1472 double cornerDist = distVector.x * distVector.x + distVector.y * distVector.y;
1473 currentMaxDistance =
max(currentMaxDistance, cornerDist);
1476 if(currentMaxDistance < closestCandidateDistance) {
1479 minDistance = currentMaxDistance;
1481 if(!checkAllOrders)
break;
1484 if(!valid)
continue;
1488 if(checkAllOrders) {
1489 rotatedMarker = Mat(4, 1, CV_32FC2);
1490 for(
int c = 0; c < 4; c++)
1491 rotatedMarker.ptr< Point2f >()[c] =
1492 _rejectedCorners.getMat(j).ptr< Point2f >()[(c + 4 + validRot) % 4];
1494 else rotatedMarker = _rejectedCorners.getMat(j);
1497 int codeDistance = 0;
1499 if(errorCorrectionRate >= 0) {
1512 dictionary.getDistanceToId(onlyBits, undetectedMarkersIds[i],
false);
1516 if(errorCorrectionRate < 0 || codeDistance < maxCorrectionRecalculated) {
1517 closestCandidateIdx = j;
1518 closestCandidateDistance = minDistance;
1519 closestRotatedMarker = rotatedMarker;
1524 if(closestCandidateIdx >= 0) {
1531 cornerSubPix(grey, closestRotatedMarker,
1533 Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
1539 alreadyIdentified[closestCandidateIdx] =
true;
1542 finalAcceptedCorners.push_back(closestRotatedMarker);
1543 finalAcceptedIds.push_back(undetectedMarkersIds[i]);
1546 recoveredIdxs.push_back(closestCandidateIdx);
1551 if(finalAcceptedIds.size() != _detectedIds.total()) {
1552 _detectedCorners.clear();
1553 _detectedIds.clear();
1556 Mat(finalAcceptedIds).copyTo(_detectedIds);
1558 _detectedCorners.create((
int)finalAcceptedCorners.size(), 1, CV_32FC2);
1559 for(
unsigned int i = 0; i < finalAcceptedCorners.size(); i++) {
1560 _detectedCorners.create(4, 1, CV_32FC2, i,
true);
1561 for(
int j = 0; j < 4; j++) {
1562 _detectedCorners.getMat(i).ptr< Point2f >()[j] =
1563 finalAcceptedCorners[i].ptr< Point2f >()[j];
1568 vector< Mat > finalRejected;
1569 for(
unsigned int i = 0; i < alreadyIdentified.size(); i++) {
1570 if(!alreadyIdentified[i]) {
1571 finalRejected.push_back(_rejectedCorners.getMat(i).clone());
1575 _rejectedCorners.clear();
1576 _rejectedCorners.create((
int)finalRejected.size(), 1, CV_32FC2);
1577 for(
unsigned int i = 0; i < finalRejected.size(); i++) {
1578 _rejectedCorners.create(4, 1, CV_32FC2, i,
true);
1579 for(
int j = 0; j < 4; j++) {
1580 _rejectedCorners.getMat(i).ptr< Point2f >()[j] =
1581 finalRejected[i].ptr< Point2f >()[j];
1585 if(_recoveredIdxs.needed()) {
1586 Mat(recoveredIdxs).copyTo(_recoveredIdxs);
1597 InputArray _cameraMatrix, InputArray _distCoeffs, OutputArray _rvec,
1598 OutputArray _tvec,
bool useExtrinsicGuess) {
1600 CV_Assert(_corners.total() == _ids.total());
1603 Mat objPoints, imgPoints;
1606 CV_Assert(imgPoints.total() == objPoints.total());
1608 if(objPoints.total() == 0)
1611 solvePnP(objPoints, imgPoints, _cameraMatrix, _distCoeffs, _rvec, _tvec, useExtrinsicGuess);
1614 return (
int)objPoints.total() / 4;
1629 Ptr<Board>
Board::create(InputArrayOfArrays objPoints,
const Ptr<Dictionary> &dictionary, InputArray ids) {
1631 CV_Assert(objPoints.total() == ids.total());
1632 CV_Assert(objPoints.type() == CV_32FC3 || objPoints.type() == CV_32FC1);
1634 std::vector< std::vector< Point3f > > obj_points_vector;
1635 for (
unsigned int i = 0; i < objPoints.total(); i++) {
1636 std::vector<Point3f> corners;
1637 Mat corners_mat = objPoints.getMat(i);
1639 if(corners_mat.type() == CV_32FC1)
1640 corners_mat = corners_mat.reshape(3);
1641 CV_Assert(corners_mat.total() == 4);
1643 for (
int j = 0; j < 4; j++) {
1644 corners.push_back(corners_mat.at<Point3f>(j));
1646 obj_points_vector.push_back(corners);
1649 Ptr<Board> res = makePtr<Board>();
1650 ids.copyTo(res->ids);
1651 res->objPoints = obj_points_vector;
1652 res->dictionary = cv::makePtr<Dictionary>(dictionary);
1658 Ptr<GridBoard>
GridBoard::create(
int markersX,
int markersY,
float markerLength,
float markerSeparation,
1659 const Ptr<Dictionary> &dictionary,
int firstMarker) {
1661 CV_Assert(markersX > 0 && markersY > 0 && markerLength > 0 && markerSeparation > 0);
1663 Ptr<GridBoard> res = makePtr<GridBoard>();
1665 res->_markersX = markersX;
1666 res->_markersY = markersY;
1667 res->_markerLength = markerLength;
1668 res->_markerSeparation = markerSeparation;
1669 res->dictionary = dictionary;
1671 size_t totalMarkers = (size_t) markersX * markersY;
1672 res->ids.resize(totalMarkers);
1673 res->objPoints.reserve(totalMarkers);
1676 for(
unsigned int i = 0; i < totalMarkers; i++) {
1677 res->ids[i] = i + firstMarker;
1681 float maxY = (float)markersY * markerLength + (markersY - 1) * markerSeparation;
1682 for(
int y = 0; y < markersY; y++) {
1683 for(
int x = 0; x < markersX; x++) {
1684 vector< Point3f > corners;
1686 corners[0] = Point3f(x * (markerLength + markerSeparation),
1687 maxY - y * (markerLength + markerSeparation), 0);
1688 corners[1] = corners[0] + Point3f(markerLength, 0, 0);
1689 corners[2] = corners[0] + Point3f(markerLength, -markerLength, 0);
1690 corners[3] = corners[0] + Point3f(0, -markerLength, 0);
1691 res->objPoints.push_back(corners);
1703 InputArray _ids, Scalar borderColor) {
1706 CV_Assert(_image.getMat().total() != 0 &&
1707 (_image.getMat().channels() == 1 || _image.getMat().channels() == 3));
1708 CV_Assert((_corners.total() == _ids.total()) || _ids.total() == 0);
1711 Scalar textColor, cornerColor;
1712 textColor = cornerColor = borderColor;
1713 swap(textColor.val[0], textColor.val[1]);
1714 swap(cornerColor.val[1], cornerColor.val[2]);
1716 int nMarkers = (int)_corners.total();
1717 for(
int i = 0; i < nMarkers; i++) {
1718 Mat currentMarker = _corners.getMat(i);
1719 CV_Assert(currentMarker.total() == 4 && currentMarker.type() == CV_32FC2);
1722 for(
int j = 0; j < 4; j++) {
1724 p0 = currentMarker.ptr< Point2f >(0)[j];
1725 p1 = currentMarker.ptr< Point2f >(0)[(j + 1) % 4];
1726 line(_image, p0, p1, borderColor, 1);
1729 rectangle(_image, currentMarker.ptr< Point2f >(0)[0] - Point2f(3, 3),
1730 currentMarker.ptr< Point2f >(0)[0] + Point2f(3, 3), cornerColor, 1, LINE_AA);
1733 if(_ids.total() != 0) {
1735 for(
int p = 0; p < 4; p++)
1736 cent += currentMarker.ptr< Point2f >(0)[p];
1739 s <<
"id=" << _ids.getMat().ptr<
int >(0)[i];
1740 putText(_image, s.str(), cent, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 2);
1749 void drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs, InputArray _rvec,
1750 InputArray _tvec,
float length)
1758 void drawMarker(
const Ptr<Dictionary> &dictionary,
int id,
int sidePixels, OutputArray _img,
int borderBits) {
1759 dictionary->drawMarker(
id, sidePixels, _img, borderBits);
1768 CV_Assert(outSize.height > 0 && outSize.width > 0);
1769 CV_Assert(marginSize >= 0);
1771 _img.create(outSize, CV_8UC1);
1772 Mat out = _img.getMat();
1773 out.setTo(Scalar::all(255));
1774 out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize);
1777 CV_Assert(_board->
objPoints.size() > 0);
1778 float minX, maxX, minY, maxY;
1779 minX = maxX = _board->
objPoints[0][0].x;
1780 minY = maxY = _board->
objPoints[0][0].y;
1782 for(
unsigned int i = 0; i < _board->
objPoints.size(); i++) {
1783 for(
int j = 0; j < 4; j++) {
1791 float sizeX = maxX - minX;
1792 float sizeY = maxY - minY;
1795 float xReduction = sizeX / float(out.cols);
1796 float yReduction = sizeY / float(out.rows);
1799 if(xReduction > yReduction) {
1800 int nRows = int(sizeY / xReduction);
1801 int rowsMargins = (out.rows - nRows) / 2;
1802 out.adjustROI(-rowsMargins, -rowsMargins, 0, 0);
1804 int nCols = int(sizeX / yReduction);
1805 int colsMargins = (out.cols - nCols) / 2;
1806 out.adjustROI(0, 0, -colsMargins, -colsMargins);
1812 Point2f outCorners[3];
1813 Point2f inCorners[3];
1814 for(
unsigned int m = 0; m < _board->
objPoints.size(); m++) {
1816 for(
int j = 0; j < 3; j++) {
1819 pf -= Point2f(minX, minY);
1820 pf.x = pf.x / sizeX * float(out.cols);
1821 pf.y = (1.0f - pf.y / sizeY) *
float(out.rows);
1826 Size dst_sz(outCorners[2] - outCorners[0]);
1827 dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height);
1828 dictionary.
drawMarker(_board->
ids[m], dst_sz.width, marker, borderBits);
1830 if((outCorners[0].y == outCorners[1].y) && (outCorners[1].x == outCorners[2].x)) {
1832 marker.copyTo(out(Rect(outCorners[0], dst_sz)));
1837 inCorners[0] = Point2f(-0.5
f, -0.5
f);
1838 inCorners[1] = Point2f(marker.cols - 0.5f, -0.5f);
1839 inCorners[2] = Point2f(marker.cols - 0.5f, marker.rows - 0.5f);
1842 Mat transformation = getAffineTransform(inCorners, outCorners);
1843 warpAffine(marker, out, transformation, out.size(), INTER_LINEAR,
1844 BORDER_TRANSPARENT);
1852 void drawPlanarBoard(
const Ptr<Board> &_board, Size outSize, OutputArray _img,
int marginSize,
1862 const Ptr<Board> &
board, Size
imageSize, InputOutputArray _cameraMatrix,
1863 InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs,
1864 OutputArrayOfArrays _tvecs,
1865 OutputArray _stdDeviationsIntrinsics,
1866 OutputArray _stdDeviationsExtrinsics,
1867 OutputArray _perViewErrors,
1872 vector< Mat > processedObjectPoints, processedImagePoints;
1873 size_t nFrames = _counter.total();
1874 int markerCounter = 0;
1875 for(
size_t frame = 0; frame < nFrames; frame++) {
1876 int nMarkersInThisFrame = _counter.getMat().ptr<
int >()[frame];
1877 vector< Mat > thisFrameCorners;
1878 vector< int > thisFrameIds;
1880 CV_Assert(nMarkersInThisFrame > 0);
1882 thisFrameCorners.reserve((
size_t) nMarkersInThisFrame);
1883 thisFrameIds.reserve((
size_t) nMarkersInThisFrame);
1884 for(
int j = markerCounter; j < markerCounter + nMarkersInThisFrame; j++) {
1885 thisFrameCorners.push_back(_corners.getMat(j));
1886 thisFrameIds.push_back(_ids.getMat().ptr<
int >()[j]);
1888 markerCounter += nMarkersInThisFrame;
1889 Mat currentImgPoints, currentObjPoints;
1892 if(currentImgPoints.total() > 0 && currentObjPoints.total() > 0) {
1893 processedImagePoints.push_back(currentImgPoints);
1894 processedObjectPoints.push_back(currentObjPoints);
1898 return calibrateCamera(processedObjectPoints, processedImagePoints, imageSize, _cameraMatrix,
1899 _distCoeffs, _rvecs, _tvecs, _stdDeviationsIntrinsics, _stdDeviationsExtrinsics,
1900 _perViewErrors, flags, criteria);
1908 const Ptr<Board> &
board, Size
imageSize, InputOutputArray _cameraMatrix,
1909 InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs,
1910 OutputArrayOfArrays _tvecs,
int flags, TermCriteria
criteria) {
1911 return calibrateCameraAruco(_corners, _ids, _counter, board, imageSize, _cameraMatrix, _distCoeffs, _rvecs, _tvecs,
1912 noArray(), noArray(), noArray(), flags, criteria);
static CV_WRAP Ptr< GridBoard > create(int markersX, int markersY, float markerLength, float markerSeparation, const Ptr< Dictionary > &dictionary, int firstMarker=0)
Create a GridBoard object.
static Point3f _interpolate2Dline(const std::vector< cv::Point2f > &nContours)
MarkerContourParallel(vector< vector< Point > > &_contours, vector< vector< Point2f > > &_candidates, const Mat &_camMatrix, const Mat &_distCoeff)
CV_PROP_RW double minOtsuStdDev
ArUco approach and refine the corners locations using the contour-points line fitting.
CV_EXPORTS_W void getBoardObjectAndImagePoints(const Ptr< Board > &board, InputArrayOfArrays detectedCorners, InputArray detectedIds, OutputArray objPoints, OutputArray imgPoints)
Given a board configuration and a set of detected markers, returns the corresponding image points and...
DetectInitialCandidatesParallel(const Mat *_grey, vector< vector< vector< Point2f > > > *_candidatesArrays, vector< vector< vector< Point > > > *_contoursArrays, const Ptr< DetectorParameters > &_params)
const Ptr< DetectorParameters > & params
Parameters for the detectMarker process:
static void _copyVector2Output(vector< vector< Point2f > > &vec, OutputArrayOfArrays out)
Copy the contents of a corners vector to an OutputArray, settings its size.
static void _reorderCandidatesCorners(vector< vector< Point2f > > &candidates)
Assure order of candidate corners is clockwise direction.
static void _distortPoints(vector< cv::Point2f > &in, const Mat &camMatrix, const Mat &distCoeff)
static void _detectInitialCandidates(const Mat &grey, vector< vector< Point2f > > &candidates, vector< vector< Point > > &contours, const Ptr< DetectorParameters > ¶ms)
Initial steps on finding square candidates.
CV_PROP_RW int perspectiveRemovePixelPerCell
static void _zarray_destroy(zarray_t *za)
MarkerSubpixelParallel(const Mat *_grey, OutputArrayOfArrays _corners, const Ptr< DetectorParameters > &_params)
static void _projectUndetectedMarkers(const Ptr< Board > &_board, InputOutputArrayOfArrays _detectedCorners, InputOutputArray _detectedIds, InputArray _cameraMatrix, InputArray _distCoeffs, vector< vector< Point2f > > &_undetectedMarkersProjectedCorners, OutputArray _undetectedMarkersIds)
ArUco approach and refine the corners locations using corner subpixel accuracy.
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray cameraMatrix
InputArrayOfArrays const Ptr< CharucoBoard > Size imageSize
const Ptr< Dictionary > & dictionary
static CV_WRAP Ptr< Board > create(InputArrayOfArrays objPoints, const Ptr< Dictionary > &dictionary, InputArray ids)
Provide way to create Board by passing necessary data. Specially needed in Python.
static Mat _extractBits(InputArray _image, InputArray _corners, int markerSize, int markerBorderBits, int cellSize, double cellMarginRate, double minStdDevOtsu)
Given an input image and candidate corners, extract the bits of the candidate, including the border b...
CV_WRAP void drawMarker(int id, int sidePixels, OutputArray _img, int borderBits=1) const
Draw a canonical marker image.
const Ptr< DetectorParameters > & params
CV_PROP_RW double minMarkerDistanceRate
void operator()(const Range &range) const CV_OVERRIDE
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray InputOutputArray distCoeffs
CV_PROP_RW int cornerRefinementMaxIterations
geometry_msgs::TransformStamped t
Tag and corners detection based on the ArUco approach.
zarray_t * apriltag_quad_thresh(const Ptr< DetectorParameters > ¶meters, const Mat &mImg, std::vector< std::vector< Point > > &contours)
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray InputOutputArray OutputArrayOfArrays OutputArrayOfArrays OutputArray OutputArray OutputArray int TermCriteria criteria
static void _apriltag(Mat im_orig, const Ptr< DetectorParameters > &_params, std::vector< std::vector< Point2f > > &candidates, std::vector< std::vector< Point > > &contours)
CV_PROP Ptr< Dictionary > dictionary
the dictionary of markers employed for this board
Tag and corners detection based on the AprilTag 2 approach .
vector< vector< vector< Point2f > > > * candidatesArrays
CV_PROP_RW int cornerRefinementWinSize
CV_PROP_RW int minDistanceToBorder
OutputArrayOfArrays corners
CvImagePtr cvtColor(const CvImageConstPtr &source, const std::string &encoding)
static void _refineCandidateLines(std::vector< Point > &nContours, std::vector< Point2f > &nCorners, const Mat &camMatrix, const Mat &distCoeff)
vector< vector< Point2f > > & candidates
static void _threshold(InputArray _in, OutputArray _out, int winSize, double constant)
Threshold input image using adaptive thresholding.
MarkerContourParallel & operator=(const MarkerContourParallel &)
const Ptr< DetectorParameters > & params
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray InputOutputArray OutputArrayOfArrays OutputArrayOfArrays OutputArray OutputArray OutputArray int flags
void threshold(const Mat mIm, const Ptr< DetectorParameters > ¶meters, Mat &mThresh)
static void _convertToGrey(InputArray _in, OutputArray _out)
Convert input image to gray if it is a 3-channels image.
vector< vector< Point > > & contours
static void _detectCandidates(InputArray _image, vector< vector< Point2f > > &candidatesOut, vector< vector< Point > > &contoursOut, const Ptr< DetectorParameters > &_params)
Detect square candidates in the input image.
double min(double a, double b)
CV_EXPORTS_W double calibrateCameraAruco(InputArrayOfArrays corners, InputArray ids, InputArray counter, const Ptr< Board > &board, Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs, OutputArrayOfArrays rvecs=noArray(), OutputArrayOfArrays tvecs=noArray(), int flags=0, TermCriteria criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON))
It's the same function as calibrateCameraAruco but without calibration error estimation.
static Point2f _getCrossPoint(Point3f nLine1, Point3f nLine2)
static void _filterTooCloseCandidates(const vector< vector< Point2f > > &candidatesIn, vector< vector< Point2f > > &candidatesOut, const vector< vector< Point > > &contoursIn, vector< vector< Point > > &contoursOut, double minMarkerDistanceRate)
Check candidates that are too close to each other and remove the smaller one.
CV_PROP std::vector< std::vector< Point3f > > objPoints
static void _zarray_get_volatile(const zarray_t *za, int idx, void *p)
void _drawPlanarBoardImpl(Board *board, Size outSize, OutputArray img, int marginSize=0, int borderBits=1)
Implementation of drawPlanarBoard that accepts a raw Board pointer.
CV_PROP_RW double minCornerDistanceRate
static bool _identifyOneCandidate(const Ptr< Dictionary > &dictionary, InputArray _image, vector< Point2f > &_corners, int &idx, const Ptr< DetectorParameters > ¶ms)
Tries to identify one candidate given the dictionary.
CV_PROP_RW int markerBorderBits
CV_PROP_RW double cornerRefinementMinAccuracy
CV_PROP_RW double perspectiveRemoveIgnoredMarginPerCell
CV_EXPORTS_W void refineDetectedMarkers(InputArray image, const Ptr< Board > &board, InputOutputArrayOfArrays detectedCorners, InputOutputArray detectedIds, InputOutputArrayOfArrays rejectedCorners, InputArray cameraMatrix=noArray(), InputArray distCoeffs=noArray(), float minRepDistance=10.f, float errorCorrectionRate=3.f, bool checkAllOrders=true, OutputArray recoveredIdxs=noArray(), const Ptr< DetectorParameters > ¶meters=DetectorParameters::create())
Refind not detected markers based on the already detected and the board layout.
void operator()(const Range &range) const CV_OVERRIDE
CV_EXPORTS_W void drawMarker(const Ptr< Dictionary > &dictionary, int id, int sidePixels, OutputArray img, int borderBits=1)
Draw a canonical marker image.
CV_EXPORTS_W void drawDetectedMarkers(InputOutputArray image, InputArrayOfArrays corners, InputArray ids=noArray(), Scalar borderColor=Scalar(0, 255, 0))
Draw detected markers in image.
static int _zarray_size(const zarray_t *za)
void operator()(const Range &range) const CV_OVERRIDE
IdentifyCandidatesParallel(const Mat &_grey, vector< vector< Point2f > > &_candidates, const Ptr< Dictionary > &_dictionary, vector< int > &_idsTmp, vector< char > &_validCandidates, const Ptr< DetectorParameters > &_params)
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray InputOutputArray OutputArrayOfArrays rvecs
CV_EXPORTS_W void estimatePoseSingleMarkers(InputArrayOfArrays corners, float markerLength, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvecs, OutputArray tvecs, OutputArray _objPoints=noArray())
Pose estimation for single markers.
vector< vector< Point2f > > & candidates
static CV_WRAP Ptr< DetectorParameters > create()
Create a new set of DetectorParameters with default values.
static int _getBorderErrors(const Mat &bits, int markerSize, int borderSize)
Return number of erroneous bits in border, i.e. number of white bits in border.
static void _filterDetectedMarkers(vector< vector< Point2f > > &_corners, vector< int > &_ids, vector< vector< Point > > &_contours)
Final filter of markers after its identification.
CV_WRAP void draw(Size outSize, OutputArray img, int marginSize=0, int borderBits=1)
Draw a GridBoard.
CV_EXPORTS_W int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Ptr< Board > &board, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess=false)
Pose estimation for a board of markers.
void operator()(const Range &range) const CV_OVERRIDE
InputArrayOfArrays corners
void operator()(const Range &range) const CV_OVERRIDE
CV_PROP_RW double errorCorrectionRate
static void _getSingleMarkerObjectPoints(float markerLength, OutputArray _objPoints)
Return object points for the system centered in a single marker, given the marker length...
CV_PROP std::vector< int > ids
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray InputOutputArray OutputArrayOfArrays OutputArrayOfArrays tvecs
CV_EXPORTS_W void detectMarkers(InputArray image, const Ptr< Dictionary > &dictionary, OutputArrayOfArrays corners, OutputArray ids, const Ptr< DetectorParameters > ¶meters=DetectorParameters::create(), OutputArrayOfArrays rejectedImgPoints=noArray(), InputArray cameraMatrix=noArray(), InputArray distCoeff=noArray())
Basic marker detection.
void swap(scoped_ptr< T > &, scoped_ptr< T > &)
static void _findMarkerContours(InputArray _in, vector< vector< Point2f > > &candidates, vector< vector< Point > > &contoursOut, double minPerimeterRate, double maxPerimeterRate, double accuracyRate, double minCornerDistanceRate, int minDistanceToBorder)
Given a tresholded image, find the contours, calculate their polygonal approximation and take those t...
double max(double a, double b)
IMETHOD void random(Vector &a)
static void _identifyCandidates(InputArray _image, vector< vector< Point2f > > &_candidates, vector< vector< Point > > &_contours, const Ptr< Dictionary > &_dictionary, vector< vector< Point2f > > &_accepted, vector< int > &ids, const Ptr< DetectorParameters > ¶ms, OutputArrayOfArrays _rejected=noArray())
Identify square candidates according to a marker dictionary.
Dictionary/Set of markers. It contains the inner codification.
vector< char > & validCandidates
vector< vector< vector< Point > > > * contoursArrays
SinglePoseEstimationParallel(Mat &_markerObjPoints, InputArrayOfArrays _corners, InputArray _cameraMatrix, InputArray _distCoeffs, Mat &_rvecs, Mat &_tvecs)
InputArrayOfArrays const Ptr< CharucoBoard > & board
CV_EXPORTS_W void drawAxis(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, InputArray rvec, InputArray tvec, float length)
Draw coordinate system axis from pose estimation.
CV_EXPORTS_W void drawPlanarBoard(const Ptr< Board > &board, Size outSize, OutputArray img, int marginSize=0, int borderBits=1)
Draw a planar board.