29 #include <opencv2/core/core.hpp> 30 #include <opencv2/features2d/features2d.hpp> 31 #include <opencv2/imgproc/imgproc.hpp> 32 #include <opencv2/calib3d/calib3d.hpp> 33 #include <opencv2/highgui/highgui.hpp> 50 MarkerDetector::MarkerDetector() {
54 if (markerIdDetector->getBestInputSize()!=-1)setWarpSize(markerIdDetector->getBestInputSize());
66 MarkerDetector::~MarkerDetector() {}
77 std::vector<aruco::Marker> MarkerDetector::detect(
const cv::Mat &input )
throw(cv::Exception) {
78 std::vector< Marker > detectedMarkers;
79 detect(input,detectedMarkers);
80 return detectedMarkers;
83 std::vector<aruco::Marker> MarkerDetector::detect(
const cv::Mat &input,
const CameraParameters &camParams,
float markerSizeMeters ,
bool setYPerperdicular )
throw(cv::Exception){
84 std::vector< Marker > detectedMarkers;
85 detect(input,detectedMarkers,camParams,markerSizeMeters,setYPerperdicular);
86 return detectedMarkers;
96 void MarkerDetector::detect(
const cv::Mat &input, std::vector< Marker > &detectedMarkers,
CameraParameters camParams,
float markerSizeMeters,
97 bool setYPerpendicular)
throw(cv::Exception) {
98 if ( camParams.CamSize!=input.size() && camParams.isValid() && markerSizeMeters>0){
101 cp_aux.
resize(input.size());
102 detect(input, detectedMarkers, cp_aux.
CameraMatrix, cp_aux.
Distorsion, markerSizeMeters, setYPerpendicular);
105 detect(input, detectedMarkers, camParams.CameraMatrix, camParams.Distorsion, markerSizeMeters, setYPerpendicular);
117 void MarkerDetector::detect(
const cv::Mat &input, vector< Marker > &detectedMarkers, Mat camMatrix, Mat distCoeff,
float markerSizeMeters,
118 bool setYPerpendicular)
throw(cv::Exception) {
121 if (input.type() == CV_8UC3)
122 cv::cvtColor(input, grey, CV_BGR2GRAY);
126 imagePyramid.clear();
127 imagePyramid.push_back(grey);
128 while(imagePyramid.back().cols>120){
130 cv::pyrDown(imagePyramid.back(),pyrd);
131 imagePyramid.push_back(pyrd);
137 detectedMarkers.clear();
140 cv::Mat imgToBeThresHolded = grey;
144 int n_param1 = 2 * _params._thresParam1_range + 1;
145 vector< cv::Mat > thres_images;
150 vector<int> p1_values;
151 for(
int i=std::max(3.,_params._thresParam1-2*_params._thresParam1_range);i<=_params._thresParam1+2*_params._thresParam1_range;i+=2)p1_values.push_back(i);
152 thres_images.resize(p1_values.size());
153 #pragma omp parallel for 154 for (
int i = 0; i < int(p1_values.size()); i++)
155 thresHold(_params._thresMethod, imgToBeThresHolded, thres_images[i], p1_values[i], _params._thresParam2);
156 thres = thres_images[n_param1 / 2];
161 vector< MarkerCandidate > MarkerCanditates;
162 detectRectangles(thres_images, MarkerCanditates);
165 float desiredarea=_params._markerWarpSize*_params._markerWarpSize;
173 #pragma omp parallel for 174 for (
int i = 0; i < int(MarkerCanditates.size()); i++) {
182 for(
size_t p=1;p<imagePyramid.size();p++){
183 if (MarkerCanditates[i].getArea() /
pow(4,p) >= desiredarea ) imgPyrIdx=p;
187 vector<cv::Point2f> points2d_pyr=MarkerCanditates[i];
188 for(
auto &p:points2d_pyr) p*=1./
pow(2,imgPyrIdx);
189 resW = warp(imagePyramid[imgPyrIdx], canonicalMarker, Size(_params._markerWarpSize, _params._markerWarpSize), points2d_pyr);
194 if (markerIdDetector->detect(canonicalMarker,
id,nRotations)) {
195 if (_params._cornerMethod == LINES)
196 refineCandidateLines(MarkerCanditates[i], camMatrix, distCoeff);
206 joinVectors(markers_omp, detectedMarkers,
true);
207 joinVectors(candidates_omp, _candidates,
true);
215 if (detectedMarkers.size() > 0 && _params._cornerMethod !=
NONE && _params._cornerMethod != LINES) {
217 vector< Point2f > Corners;
218 for (
unsigned int i = 0; i < detectedMarkers.size(); i++)
219 for (
int c = 0; c < 4; c++)
220 Corners.push_back(detectedMarkers[i][c]);
223 if (_params._cornerMethod == SUBPIX) {
224 cornerSubPix(grey, Corners, cvSize(_params._subpix_wsize, _params._subpix_wsize), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 12, 0.005));
227 for (
unsigned int i = 0; i < detectedMarkers.size(); i++)
228 for (
int c = 0; c < 4; c++)
229 detectedMarkers[i][c] = Corners[i * 4 + c];
234 std::sort(detectedMarkers.begin(), detectedMarkers.end());
237 vector< bool > toRemove(detectedMarkers.size(),
false);
239 for (
int i = 0; i < int(detectedMarkers.size()) - 1; i++) {
240 for (
int j = i+1; j < int(detectedMarkers.size()) && !toRemove[i] ; j++) {
241 if (detectedMarkers[i].
id == detectedMarkers[j].
id) {
243 if (perimeter(detectedMarkers[i]) < perimeter(detectedMarkers[j]))
254 int borderDistThresX = _params._borderDistThres * float(input.cols);
255 int borderDistThresY = _params._borderDistThres * float(input.rows);
256 for (
size_t i = 0; i < detectedMarkers.size(); i++) {
258 for (
size_t c = 0; c < detectedMarkers[i].size(); c++) {
259 if (detectedMarkers[i][c].x < borderDistThresX || detectedMarkers[i][c].
y < borderDistThresY ||
260 detectedMarkers[i][c].x > input.cols - borderDistThresX || detectedMarkers[i][c].y > input.rows - borderDistThresY) {
268 removeElements(detectedMarkers, toRemove);
271 if (camMatrix.rows != 0 && markerSizeMeters > 0) {
272 for (
unsigned int i = 0; i < detectedMarkers.size(); i++)
273 detectedMarkers[i].calculateExtrinsics(markerSizeMeters, camMatrix, distCoeff, setYPerpendicular);
290 const float d0=p1[0]-at(idx_p2).x;
291 const float d1=p1[1]-at(idx_p2).y;
300 return dim==0? at(idx).x:at(idx).y;
306 template <
class BBOX>
317 void MarkerDetector::detectRectangles(
const cv::Mat &thres, vector< std::vector< cv::Point2f > > &MarkerCanditates) {
318 vector< MarkerCandidate > candidates;
319 vector< cv::Mat > thres_v;
320 thres_v.push_back(thres);
321 detectRectangles(thres_v, candidates);
323 MarkerCanditates.resize(candidates.size());
324 for (
size_t i = 0; i < MarkerCanditates.size(); i++)
325 MarkerCanditates[i] = candidates[i];
328 void MarkerDetector::detectRectangles(vector< cv::Mat > &thresImgv, vector< MarkerCandidate > &OutMarkerCanditates) {
333 int maxSize = _params._maxSize * std::max(thresImgv[0].cols, thresImgv[0].rows) * 4;
334 int minSize= std::min (
float(_params._minSize_pix) , _params._minSize* std::max(thresImgv[0].cols, thresImgv[0].rows) * 4 );
337 #pragma omp parallel for 338 for (
int img_idx = 0; img_idx < int(thresImgv.size()); img_idx++) {
339 std::vector< cv::Vec4i > hierarchy2;
340 std::vector< std::vector< cv::Point > > contours2;
342 thresImgv[img_idx].copyTo(thres2);
343 cv::findContours(thres2, contours2, hierarchy2, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
345 vector< Point > approxCurve;
347 for (
unsigned int i = 0; i < contours2.size(); i++) {
350 if (minSize <
int(contours2[i].size()) && int(contours2[i].size()) < maxSize) {
352 approxPolyDP(contours2[i], approxCurve,
double(contours2[i].size()) * 0.05,
true);
355 if (approxCurve.size() == 4) {
362 if (isContourConvex(Mat(approxCurve))) {
365 float minDist = 1e10;
366 for (
int j = 0; j < 4; j++) {
367 float d =
std::sqrt((
float)(approxCurve[j].x - approxCurve[(j + 1) % 4].x) * (approxCurve[j].x - approxCurve[(j + 1) % 4].x) +
368 (approxCurve[j].
y - approxCurve[(j + 1) % 4].
y) * (approxCurve[j].
y - approxCurve[(j + 1) % 4].
y));
370 if (d < minDist) minDist = d;
378 if (_params._cornerMethod==LINES)
380 for (
int j = 0; j < 4; j++)
381 MarkerCanditatesV[
omp_get_thread_num()].back().push_back(Point2f(approxCurve[j].x, approxCurve[j].
y));
390 vector< MarkerCandidate > MarkerCanditates;
392 for (
size_t i = 0; i < MarkerCanditatesV.size(); i++)
393 for (
size_t j = 0; j < MarkerCanditatesV[i].size(); j++) {
394 MarkerCanditates.push_back(MarkerCanditatesV[i][j]);
398 valarray< bool > swapped(
false, MarkerCanditates.size());
399 for (
unsigned int i = 0; i < MarkerCanditates.size(); i++) {
403 double dx1 = MarkerCanditates[i][1].x - MarkerCanditates[i][0].x;
404 double dy1 = MarkerCanditates[i][1].y - MarkerCanditates[i][0].y;
405 double dx2 = MarkerCanditates[i][2].x - MarkerCanditates[i][0].x;
406 double dy2 = MarkerCanditates[i][2].y - MarkerCanditates[i][0].y;
407 double o = (dx1 * dy2) - (dy1 * dx2);
410 swap(MarkerCanditates[i][1], MarkerCanditates[i][3]);
419 #pragma omp parallel for 420 for (
unsigned int i = 0; i < MarkerCanditates.size(); i++) {
422 for (
unsigned int j = i + 1; j < MarkerCanditates.size(); j++) {
423 valarray< float > vdist(4);
424 for (
int c = 0; c < 4; c++)
425 vdist[c] =
sqrt((MarkerCanditates[i][c].x - MarkerCanditates[j][c].x) * (MarkerCanditates[i][c].x - MarkerCanditates[j][c].x) +
426 (MarkerCanditates[i][c].
y - MarkerCanditates[j][c].
y) * (MarkerCanditates[i][c].y - MarkerCanditates[j][c].y));
429 if (vdist[0] < 6 && vdist[1] < 6 && vdist[2] < 6 && vdist[3] < 6) {
437 vector< pair< int, int > > TooNearCandidates;
438 joinVectors(TooNearCandidates_omp, TooNearCandidates);
440 valarray< bool > toRemove(
false, MarkerCanditates.size());
441 for (
unsigned int i = 0; i < TooNearCandidates.size(); i++) {
442 if (perimeter(MarkerCanditates[TooNearCandidates[i].first]) > perimeter(MarkerCanditates[TooNearCandidates[i].second]))
443 toRemove[TooNearCandidates[i].second] =
true;
445 toRemove[TooNearCandidates[i].first] =
true;
450 OutMarkerCanditates.reserve(MarkerCanditates.size());
451 for (
size_t i = 0; i < MarkerCanditates.size(); i++) {
453 OutMarkerCanditates.push_back(MarkerCanditates[i]);
455 if (swapped[i] && OutMarkerCanditates.back().contour.size()>1)
456 reverse(OutMarkerCanditates.back().contour.begin(), OutMarkerCanditates.back().contour.end());
477 void MarkerDetector::adpt_threshold_multi(
const Mat &grey, std::vector<Mat> &outThresImages,
double param1 ,
double param1_range ,
double param2,
double param2_range ){
480 int start_p1 = std::max(3.,param1-2*param1_range);
481 int end_p1 = param1+2*param1_range;
482 int start_p2 = std::max(3.,param2-2*param2_range);
483 int end_p2 = param2+2*param2_range;
484 vector<std::pair<int,int> > p1_2_values;
485 for(
int i=start_p1;i<=end_p1;i+=2)
486 for(
int j=start_p2;j<=end_p2;j+=2)
487 p1_2_values.push_back(std::pair<int,int>(i,j));
488 outThresImages.resize(p1_2_values.size());
491 cv::integral(grey,intimg);
493 #pragma omp parallel for 494 for(
int i=0;i<int(p1_2_values.size());i++){
497 float inv_area=1./(p1_2_values[i].first*p1_2_values[i].first);
498 int wsize_2=p1_2_values[i].first/2;
499 outThresImages[i].create(grey.size(),grey.type() );
501 for(
int y=wsize_2;
y<grey.rows-wsize_2;
y++){
502 int *_y1=intimg.ptr<
int>(
y-wsize_2);
503 int *_y2=intimg.ptr<
int>(
y+wsize_2+1);
504 uchar *out= outThresImages[i].ptr<uchar>(
y);
505 for(
int x=wsize_2;x<grey.cols-wsize_2;x++){
509 float mean=float( _y2[x2]-_y2[x1]-_y1[x2]+_y1[x1])* inv_area ;
510 if ( mean- grey.at<uchar>(
y,x)>p1_2_values[i].second)
526 void MarkerDetector::thresHold(
int method,
const Mat &grey, Mat &out,
double param1,
double param2)
throw(cv::Exception) {
529 param1 = _params._thresParam1;
531 param2 = _params._thresParam2;
533 if (grey.type() != CV_8UC1)
534 throw cv::Exception(9001,
"grey.type()!=CV_8UC1",
"MarkerDetector::thresHold", __FILE__, __LINE__);
537 cv::threshold(grey, out, param1, 255, CV_THRESH_BINARY_INV);
543 else if (((
int)param1) % 2 != 1)
544 param1 = (int)(param1 + 1);
546 cv::adaptiveThreshold(grey, out, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, param1, param2);
553 cv::Canny(grey, out, 10, 220);
568 bool MarkerDetector::warp(Mat &in, Mat &out, Size size, vector< Point2f > points)
throw(cv::Exception) {
570 if (points.size() != 4)
571 throw cv::Exception(9001,
"point.size()!=4",
"MarkerDetector::warp", __FILE__, __LINE__);
573 Point2f pointsRes[4], pointsIn[4];
574 for (
int i = 0; i < 4; i++)
575 pointsIn[i] = points[i];
576 pointsRes[0] = (Point2f(0, 0));
577 pointsRes[1] = Point2f(size.width - 1, 0);
578 pointsRes[2] = Point2f(size.width - 1, size.height - 1);
579 pointsRes[3] = Point2f(0, size.height - 1);
580 Mat M = getPerspectiveTransform(pointsIn, pointsRes);
581 cv::warpPerspective(in, out, M, size, cv::INTER_NEAREST);
586 assert(points.size() == 4);
587 int idxSegments[4] = {-1, -1, -1, -1};
589 cv::Point points2i[4];
590 for (
int i = 0; i < 4; i++) {
591 points2i[i].x = points[i].x;
592 points2i[i].y = points[i].y;
595 for (
size_t i = 0; i < contour.size(); i++) {
596 if (idxSegments[0] == -1)
597 if (contour[i] == points2i[0])
599 if (idxSegments[1] == -1)
600 if (contour[i] == points2i[1])
602 if (idxSegments[2] == -1)
603 if (contour[i] == points2i[2])
605 if (idxSegments[3] == -1)
606 if (contour[i] == points2i[3])
610 for (
int i = 0; i < 4; i++)
611 idxs[i] = idxSegments[i];
615 float distSum[4] = {0, 0, 0, 0};
618 for (
int i = 0; i < 3; i++) {
619 cv::Point p1 = contour[idxSegments[i]];
620 cv::Point p2 = contour[idxSegments[i + 1]];
621 float inv_den = 1. /
sqrt(
float((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)));
624 for (
int j = idxSegments[i]; j < idxSegments[i + 1]; j++) {
625 float dist = std::fabs(
float((p2.x - p1.x) * (p1.y - contour[j].y) - (p1.x - contour[j].x) * (p2.y - p1.y))) * inv_den;
630 distSum[i] /= float(idxSegments[i + 1] - idxSegments[i]);
636 cv::Point p1 = contour[idxSegments[0]];
637 cv::Point p2 = contour[idxSegments[3]];
638 float inv_den = 1. /
std::sqrt(
float((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)));
640 for (
int j = 0; j < idxSegments[0]; j++)
641 distSum[3] += std::fabs(
float((p2.x - p1.x) * (p1.y - contour[j].y) - (p1.x - contour[j].x) * (p2.y - p1.y))) * inv_den;
642 for (
size_t j =
size_t(idxSegments[3]); j < contour.size(); j++)
643 distSum[3] += std::fabs(
float((p2.x - p1.x) * (p1.y - contour[j].y) - (p1.x - contour[j].x) * (p2.y - p1.y))) * inv_den;
645 distSum[3] /= float(idxSegments[0] + (contour.size() - idxSegments[3]));
650 if (distSum[0] + distSum[2] > distSum[1] + distSum[3])
659 else if (p.x >= s.width)
663 else if (p.y >= s.height)
670 else if (p.x >= s.width)
674 else if (p.y >= s.height)
683 bool MarkerDetector::warp_cylinder(Mat &in, Mat &out, Size size,
MarkerCandidate &mcand)
throw(cv::Exception) {
685 if (mcand.size() != 4)
686 throw cv::Exception(9001,
"point.size()!=4",
"MarkerDetector::warp", __FILE__, __LINE__);
696 vector< int > idxSegments;
700 for (
int i = 1; i < 4; i++)
701 if (idxSegments[i] < idxSegments[minIdx])
704 std::rotate(idxSegments.begin(), idxSegments.begin() + minIdx, idxSegments.end());
705 std::rotate(mcand.begin(), mcand.begin() + minIdx, mcand.end());
715 Point2f enlargedRegion[4];
716 for (
int i = 0; i < 4; i++)
717 enlargedRegion[i] = mcand[i];
718 if (defrmdSide == 0) {
719 enlargedRegion[0] = mcand[0] + (mcand[3] - mcand[0]) * 1.2;
720 enlargedRegion[1] = mcand[1] + (mcand[2] - mcand[1]) * 1.2;
721 enlargedRegion[2] = mcand[2] + (mcand[1] - mcand[2]) * 1.2;
722 enlargedRegion[3] = mcand[3] + (mcand[0] - mcand[3]) * 1.2;
724 enlargedRegion[0] = mcand[0] + (mcand[1] - mcand[0]) * 1.2;
725 enlargedRegion[1] = mcand[1] + (mcand[0] - mcand[1]) * 1.2;
726 enlargedRegion[2] = mcand[2] + (mcand[3] - mcand[2]) * 1.2;
727 enlargedRegion[3] = mcand[3] + (mcand[2] - mcand[3]) * 1.2;
729 for (
size_t i = 0; i < 4; i++)
747 Point2f pointsRes[4], pointsIn[4];
748 for (
int i = 0; i < 4; i++)
749 pointsIn[i] = mcand[i];
751 cv::Size enlargedSize = size;
752 enlargedSize.width += 2 * enlargedSize.width * 0.2;
753 pointsRes[0] = (Point2f(0, 0));
754 pointsRes[1] = Point2f(enlargedSize.width - 1, 0);
755 pointsRes[2] = Point2f(enlargedSize.width - 1, enlargedSize.height - 1);
756 pointsRes[3] = Point2f(0, enlargedSize.height - 1);
759 rotate(pointsRes, pointsRes + 1, pointsRes + 4);
760 cv::Mat imAux, imAux2(enlargedSize, CV_8UC1);
761 Mat M = cv::getPerspectiveTransform(enlargedRegion, pointsRes);
762 cv::warpPerspective(in, imAux, M, enlargedSize, cv::INTER_NEAREST);
765 vector< cv::Point > pointsCO(mcand.contour.size());
766 assert(M.type() == CV_64F);
767 assert(M.cols == 3 && M.rows == 3);
769 double *mptr = M.ptr<
double >(0);
770 imAux2.setTo(cv::Scalar::all(0));
773 for (
size_t i = 0; i < mcand.contour.size(); i++) {
774 float inX = mcand.contour[i].x;
775 float inY = mcand.contour[i].y;
776 float w = inX * mptr[6] + inY * mptr[7] + mptr[8];
778 pointsCO[i].x = ((inX * mptr[0] + inY * mptr[1] + mptr[2]) / w) + 0.5;
779 pointsCO[i].y = ((inX * mptr[3] + inY * mptr[4] + mptr[5]) / w) + 0.5;
783 imAux2.at< uchar >(pointsCO[i].y, pointsCO[i].x) = 255;
784 if (pointsCO[i].
y > 0)
785 imAux2.at< uchar >(pointsCO[i].y - 1, pointsCO[i].x) = 255;
786 if (pointsCO[i].
y < imAux2.rows - 1)
787 imAux2.at< uchar >(pointsCO[i].y + 1, pointsCO[i].x) = 255;
790 cv::Mat outIm(enlargedSize, CV_8UC1);
791 outIm.setTo(cv::Scalar::all(0));
793 for (
int y = 0;
y < imAux2.rows;
y++) {
794 uchar *_offInfo = imAux2.ptr< uchar >(
y);
795 int start = -1, end = -1;
797 for (
int x = 0; x < imAux.cols; x++) {
807 assert(start != -1 && end != -1 && (end - start) > size.width >> 1);
808 uchar *In_image = imAux.ptr< uchar >(
y);
809 uchar *Out_image = outIm.ptr< uchar >(
y);
810 memcpy(Out_image, In_image + start, imAux.cols - start);
816 cv::Mat centerReg = outIm(cv::Range::all(), cv::Range(0, size.width));
817 out = centerReg.clone();
831 bool MarkerDetector::isInto(Mat &contour, vector< Point2f > &b) {
833 for (
unsigned int i = 0; i < b.size(); i++)
834 if (pointPolygonTest(contour, b[i],
false) > 0)
844 int MarkerDetector::perimeter(vector< Point2f > &a) {
846 for (
unsigned int i = 0; i < a.size(); i++) {
847 int i2 = (i + 1) % a.size();
848 sum +=
sqrt((a[i].x - a[i2].x) * (a[i].x - a[i2].x) + (a[i].
y - a[i2].
y) * (a[i].y - a[i2].y));
863 vector< int > cornerIndex(4,-1);
864 for (
unsigned int j = 0; j < candidate.
contour.size(); j++) {
865 for (
unsigned int k = 0; k < 4; k++) {
866 if (candidate.
contour[j].x == candidate[k].x && candidate.
contour[j].y == candidate[k].y) {
874 if ((cornerIndex[1] > cornerIndex[0]) && (cornerIndex[2] > cornerIndex[1] || cornerIndex[2] < cornerIndex[0]))
876 else if (cornerIndex[2] > cornerIndex[1] && cornerIndex[2] < cornerIndex[0])
888 vector< Point2f > contour2f;
889 if(!camMatrix.empty() && !distCoeff.empty()){
890 for (
unsigned int i = 0; i < candidate.
contour.size(); i++)
891 contour2f.push_back(cv::Point2f(candidate.
contour[i].x, candidate.
contour[i].y));
892 if (!camMatrix.empty() && !distCoeff.empty())
893 cv::undistortPoints(contour2f, contour2f, camMatrix, distCoeff, cv::Mat(), camMatrix);
897 contour2f.reserve(candidate.
contour.size());
899 contour2f.push_back(cv::Point2f(p.x,p.y));
902 vector< std::vector< cv::Point2f > > contourLines;
903 contourLines.resize(4);
904 for (
unsigned int l = 0; l < 4; l++) {
905 for (
int j = (
int)cornerIndex[l]; j != (int)cornerIndex[(l + 1) % 4]; j += inc) {
908 else if (j == 0 && inverse)
909 j = candidate.
contour.size() - 1;
910 contourLines[l].push_back(contour2f[j]);
911 if (j == (
int)cornerIndex[(l + 1) % 4])
917 vector< Point3f > lines;
919 for (
unsigned int j = 0; j < lines.size(); j++)
920 interpolate2Dline(contourLines[j], lines[j]);
923 vector< Point2f > crossPoints;
924 crossPoints.resize(4);
925 for (
unsigned int i = 0; i < 4; i++)
926 crossPoints[i] = getCrossPoint(lines[(i - 1) % 4], lines[i]);
929 if (!camMatrix.empty() && !distCoeff.empty())
930 distortPoints(crossPoints, crossPoints, camMatrix, distCoeff);
933 for (
unsigned int j = 0; j < 4; j++)
934 candidate[j] = crossPoints[j];
940 void MarkerDetector::interpolate2Dline(
const std::vector< Point2f > &inPoints, Point3f &outLine) {
942 float minX, maxX, minY, maxY;
943 minX = maxX = inPoints[0].x;
944 minY = maxY = inPoints[0].y;
945 for (
unsigned int i = 1; i < inPoints.size(); i++) {
946 if (inPoints[i].x < minX)
947 minX = inPoints[i].x;
948 if (inPoints[i].x > maxX)
949 maxX = inPoints[i].x;
950 if (inPoints[i].
y < minY)
951 minY = inPoints[i].y;
952 if (inPoints[i].
y > maxY)
953 maxY = inPoints[i].y;
957 Mat A(inPoints.size(), 2, CV_32FC1, Scalar(0));
958 Mat B(inPoints.size(), 1, CV_32FC1, Scalar(0));
963 if (maxX - minX > maxY - minY) {
965 for (
size_t i = 0; i < inPoints.size(); i++) {
967 A.at<
float >(i, 0) = inPoints[i].x;
968 A.at<
float >(i, 1) = 1.;
969 B.at<
float >(i, 0) = inPoints[i].
y;
973 solve(A, B, X, DECOMP_SVD);
975 outLine = Point3f(X.at<
float >(0, 0), -1., X.at<
float >(1, 0));
978 for (
size_t i = 0; i < inPoints.size(); i++) {
980 A.at<
float >(i, 0) = inPoints[i].
y;
981 A.at<
float >(i, 1) = 1.;
982 B.at<
float >(i, 0) = inPoints[i].x;
986 solve(A, B, X, DECOMP_SVD);
988 outLine = Point3f(-1., X.at<
float >(0, 0), X.at<
float >(1, 0));
994 Point2f MarkerDetector::getCrossPoint(
const cv::Point3f &line1,
const cv::Point3f &line2) {
997 Mat A(2, 2, CV_32FC1, Scalar(0));
998 Mat B(2, 1, CV_32FC1, Scalar(0));
1001 A.at<
float >(0, 0) = line1.x;
1002 A.at<
float >(0, 1) = line1.y;
1003 B.at<
float >(0, 0) = -line1.z;
1005 A.at<
float >(1, 0) = line2.x;
1006 A.at<
float >(1, 1) = line2.y;
1007 B.at<
float >(1, 0) = -line2.z;
1010 solve(A, B, X, DECOMP_SVD);
1011 return Point2f(X.at<
float >(0, 0), X.at<
float >(1, 0));
1017 void MarkerDetector::distortPoints(vector< cv::Point2f > in, vector< cv::Point2f > &out,
const Mat &camMatrix,
const Mat &distCoeff) {
1019 cv::Mat Rvec = cv::Mat(3, 1, CV_32FC1, cv::Scalar::all(0));
1020 cv::Mat Tvec = Rvec.clone();
1022 vector< cv::Point3f > cornersPoints3d;
1023 for (
unsigned int i = 0; i < in.size(); i++)
1024 cornersPoints3d.push_back(cv::Point3f((in[i].x - camMatrix.at<
float >(0, 2)) / camMatrix.at<
float >(0, 0),
1025 (in[i].y - camMatrix.at<
float >(1, 2)) / camMatrix.at<
float >(1, 1),
1027 cv::projectPoints(cornersPoints3d, Rvec, Tvec, camMatrix, distCoeff, out);
1038 void MarkerDetector::drawAllContours(Mat input, std::vector< std::vector< cv::Point > > &contours) { drawContours(input, contours, -1, Scalar(255, 0, 255)); }
1046 void MarkerDetector::drawContour(Mat &in, vector< Point > &contour, Scalar color) {
1047 for (
unsigned int i = 0; i < contour.size(); i++) {
1048 cv::rectangle(in, contour[i], contour[i], color);
1052 void MarkerDetector::drawApproxCurve(Mat &in, vector< Point > &contour, Scalar color) {
1053 for (
unsigned int i = 0; i < contour.size(); i++) {
1054 cv::line(in, contour[i], contour[(i + 1) % contour.size()], color);
1064 void MarkerDetector::draw(Mat out,
const vector< Marker > &markers) {
1065 for (
unsigned int i = 0; i < markers.size(); i++) {
1066 cv::line(out, markers[i][0], markers[i][1], cvScalar(255, 0, 0), 2, CV_AA);
1067 cv::line(out, markers[i][1], markers[i][2], cvScalar(255, 0, 0), 2, CV_AA);
1068 cv::line(out, markers[i][2], markers[i][3], cvScalar(255, 0, 0), 2, CV_AA);
1069 cv::line(out, markers[i][3], markers[i][0], cvScalar(255, 0, 0), 2, CV_AA);
1099 void MarkerDetector::findCornerMaxima(vector< cv::Point2f > &Corners,
const cv::Mat &grey,
int wsize) {
1102 #pragma omp parallel for 1104 for (
size_t i = 0; i < Corners.size(); i++) {
1105 cv::Point2f minLimit(std::max(0,
int(Corners[i].x - wsize)), std::max(0,
int(Corners[i].
y - wsize)));
1106 cv::Point2f maxLimit(std::min(grey.cols,
int(Corners[i].x + wsize)), std::min(grey.rows,
int(Corners[i].y + wsize)));
1108 cv::Mat reg = grey(cv::Range(minLimit.y, maxLimit.y), cv::Range(minLimit.x, maxLimit.x));
1109 cv::Mat harr, harrint;
1110 cv::cornerHarris(reg, harr, 3, 3, 0.04);
1113 cv::integral(harr, harrint);
1115 for (
int y = bls_a;
y < harr.rows - bls_a;
y++) {
1116 float *h = harr.ptr<
float >(
y);
1117 for (
int x = bls_a; x < harr.cols - bls_a; x++)
1118 h[x] = harrint.at<
double >(
y + bls_a, x + bls_a) - harrint.at<
double >(
y + bls_a, x) - harrint.at<
double >(
y, x + bls_a) +
1119 harrint.at<
double >(
y, x);
1124 cv::Point2f best(-1, -1);
1125 cv::Point2f center(reg.cols / 2, reg.rows / 2);
1128 for (
int i = 0; i < harr.rows; i++) {
1130 float *har = harr.ptr<
float >(i);
1131 for (
int x = 0; x < harr.cols; x++) {
1132 float d = float(fabs(center.x - x) + fabs(center.y - i)) / float(reg.cols / 2 + reg.rows / 2);
1134 if (w * har[x] > maxv) {
1136 best = cv::Point2f(x, i);
1140 Corners[i] = best + minLimit;
1145 void MarkerDetector::setMarkerLabeler(cv::Ptr<MarkerLabeler> detector)
throw(cv::Exception){
1146 markerIdDetector=detector;
1147 if (markerIdDetector->getBestInputSize()!=-1)setWarpSize(markerIdDetector->getBestInputSize());
1152 markerIdDetector= MarkerLabeler::create(dict_type,error_correction_rate);
1153 if (markerIdDetector->getBestInputSize()!=-1)setWarpSize(markerIdDetector->getBestInputSize());
1155 void MarkerDetector::setDictionary(
string dict_type,
float error_correction_rate)
throw(cv::Exception){
1156 markerIdDetector= MarkerLabeler::create(Dictionary::getTypeFromString( dict_type),error_correction_rate);
1157 if (markerIdDetector->getBestInputSize()!=-1)setWarpSize(markerIdDetector->getBestInputSize());
void findCornerPointsInContour(const vector< cv::Point2f > &points, const vector< cv::Point > &contour, vector< int > &idxs)
void resize(cv::Size size)
int findDeformedSidesIdx(const vector< cv::Point > &contour, const vector< int > &idxSegments)
float kdtree_get_pt(const size_t idx, int dim) const
void setPointIntoImage(cv::Point &p, cv::Size s)
const CwiseUnaryOp< internal::scalar_inverse_op< Scalar >, const Derived > inverse() const
void swap(Bag &a, Bag &b)
int omp_get_max_threads()
Parameters of the camera.
static cv::Ptr< MarkerLabeler > create(Dictionary::DICT_TYPES dict_type, float error_correction_rate=0)
bool kdtree_get_bbox(BBOX &bb) const
float kdtree_distance(const float *p1, const size_t idx_p2, size_t size) const
size_t kdtree_get_point_count() const
vector< cv::Point > contour
const CwiseUnaryOp< internal::scalar_pow_op< Scalar >, const Derived > pow(const Scalar &exponent) const
const CwiseUnaryOp< internal::scalar_sqrt_op< Scalar >, const Derived > sqrt() const