00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <aruco/markerdetector.h>
00029 #include <aruco/subpixelcorner.h>
00030 #include <aruco/arucofidmarkers.h>
00031 #include <aruco/ar_omp.h>
00032 #include <opencv/cv.h>
00033 #include <opencv/highgui.h>
00034 #include <iostream>
00035 #include <fstream>
00036 #include <valarray>
00037 using namespace std;
00038 using namespace cv;
00039
00040 namespace aruco
00041 {
00042
00043
00044
00045
00046
00047
00048 MarkerDetector::MarkerDetector()
00049 {
00050 _doErosion=false;
00051 _thresMethod=ADPT_THRES;
00052 _thresParam1=_thresParam2=7;
00053 _cornerMethod=LINES;
00054 _markerWarpSize=56;
00055 _speed=0;
00056 markerIdDetector_ptrfunc=aruco::FiducidalMarkers::detect;
00057 pyrdown_level=0;
00058 _minSize=0.04;
00059 _maxSize=0.5;
00060
00061 _borderDistThres=0.01;
00062 }
00063
00064
00065
00066
00067
00068
00069
00070 MarkerDetector::~MarkerDetector()
00071 {
00072
00073 }
00074
00075
00076
00077
00078
00079
00080
00081 void MarkerDetector::setDesiredSpeed ( int val )
00082 {
00083 if ( val<0 ) val=0;
00084 else if ( val>3 ) val=2;
00085
00086 _speed=val;
00087 switch ( _speed )
00088 {
00089
00090 case 0:
00091 _markerWarpSize=56;
00092 _cornerMethod=SUBPIX;
00093 _doErosion=true;
00094 break;
00095
00096 case 1:
00097 case 2:
00098 _markerWarpSize=28;
00099 _cornerMethod=NONE;
00100 break;
00101 };
00102 }
00103
00104
00105
00106
00107
00108
00109
00110 void MarkerDetector::detect ( const cv::Mat &input,std::vector<Marker> &detectedMarkers, CameraParameters camParams ,float markerSizeMeters ,bool setYPerpendicular) throw ( cv::Exception )
00111 {
00112 detect ( input, detectedMarkers,camParams.CameraMatrix ,camParams.Distorsion, markerSizeMeters ,setYPerpendicular);
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122 void MarkerDetector::detect ( const cv::Mat &input,vector<Marker> &detectedMarkers,Mat camMatrix ,Mat distCoeff ,float markerSizeMeters ,bool setYPerpendicular) throw ( cv::Exception )
00123 {
00124
00125
00126
00127 if ( input.type() ==CV_8UC3 ) cv::cvtColor ( input,grey,CV_BGR2GRAY );
00128 else grey=input;
00129
00130
00131
00132
00133
00134 detectedMarkers.clear();
00135
00136
00137 cv::Mat imgToBeThresHolded=grey;
00138 double ThresParam1=_thresParam1,ThresParam2=_thresParam2;
00139
00140 if ( pyrdown_level!=0 )
00141 {
00142 reduced=grey;
00143 for ( int i=0;i<pyrdown_level;i++ )
00144 {
00145 cv::Mat tmp;
00146 cv::pyrDown ( reduced,tmp );
00147 reduced=tmp;
00148 }
00149 int red_den=pow ( 2.0f,pyrdown_level );
00150 imgToBeThresHolded=reduced;
00151 ThresParam1/=float ( red_den );
00152 ThresParam2/=float ( red_den );
00153 }
00154
00156 thresHold ( _thresMethod,imgToBeThresHolded,thres,ThresParam1,ThresParam2 );
00157
00158 if ( _doErosion )
00159 {
00160 erode ( thres,thres2,cv::Mat() );
00161 thres2.copyTo(thres);
00162 }
00163
00164 vector<MarkerCandidate > MarkerCanditates;
00165 detectRectangles ( thres,MarkerCanditates );
00166
00167 if ( pyrdown_level!=0 )
00168 {
00169 float red_den=pow ( 2.0f,pyrdown_level );
00170 float offInc= ( ( pyrdown_level/2. )-0.5 );
00171 for ( unsigned int i=0;i<MarkerCanditates.size();i++ ) {
00172 for ( int c=0;c<4;c++ )
00173 {
00174 MarkerCanditates[i][c].x=MarkerCanditates[i][c].x*red_den+offInc;
00175 MarkerCanditates[i][c].y=MarkerCanditates[i][c].y*red_den+offInc;
00176 }
00177
00178 for ( int c=0;c<MarkerCanditates[i].contour.size();c++ )
00179 {
00180 MarkerCanditates[i].contour[c].x=MarkerCanditates[i].contour[c].x*red_den+offInc;
00181 MarkerCanditates[i].contour[c].y=MarkerCanditates[i].contour[c].y*red_den+offInc;
00182 }
00183 }
00184 }
00185
00186
00188 vector<vector<Marker> >markers_omp(omp_get_max_threads());
00189 vector<vector < std::vector<cv::Point2f> > >candidates_omp(omp_get_max_threads());
00190 #pragma omp parallel for
00191 for ( unsigned int i=0;i<MarkerCanditates.size();i++ )
00192 {
00193
00194 Mat canonicalMarker;
00195 bool resW=false;
00196 resW=warp ( grey,canonicalMarker,Size ( _markerWarpSize,_markerWarpSize ),MarkerCanditates[i] );
00197 if (resW) {
00198 int nRotations;
00199 int id= ( *markerIdDetector_ptrfunc ) ( canonicalMarker,nRotations );
00200 if ( id!=-1 )
00201 {
00202 if(_cornerMethod==LINES)
00203 refineCandidateLines( MarkerCanditates[i], camMatrix, distCoeff );
00204 markers_omp[omp_get_thread_num()].push_back ( MarkerCanditates[i] );
00205 markers_omp[omp_get_thread_num()].back().id=id;
00206
00207 std::rotate ( markers_omp[omp_get_thread_num()].back().begin(),markers_omp[omp_get_thread_num()].back().begin() +4-nRotations,markers_omp[omp_get_thread_num()].back().end() );
00208 }
00209 else candidates_omp[omp_get_thread_num()].push_back ( MarkerCanditates[i] );
00210 }
00211
00212 }
00213
00214 joinVectors(markers_omp,detectedMarkers,true);
00215 joinVectors(candidates_omp,_candidates,true);
00216
00217
00218
00220 if ( detectedMarkers.size() >0 && _cornerMethod!=NONE && _cornerMethod!=LINES )
00221 {
00222 vector<Point2f> Corners;
00223 for ( unsigned int i=0;i<detectedMarkers.size();i++ )
00224 for ( int c=0;c<4;c++ )
00225 Corners.push_back ( detectedMarkers[i][c] );
00226
00227 if ( _cornerMethod==HARRIS )
00228 findBestCornerInRegion_harris ( grey, Corners,7 );
00229 else if ( _cornerMethod==SUBPIX )
00230 cornerSubPix ( grey, Corners,cvSize ( 5,5 ), cvSize ( -1,-1 ) ,cvTermCriteria ( CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,3,0.05 ) );
00231
00232
00233 for ( unsigned int i=0;i<detectedMarkers.size();i++ )
00234 for ( int c=0;c<4;c++ ) detectedMarkers[i][c]=Corners[i*4+c];
00235 }
00236
00237 std::sort ( detectedMarkers.begin(),detectedMarkers.end() );
00238
00239
00240 int borderDistThresX=_borderDistThres*float(input.cols);
00241 int borderDistThresY=_borderDistThres*float(input.rows);
00242 vector<bool> toRemove ( detectedMarkers.size(),false );
00243 for ( int i=0;i<int ( detectedMarkers.size() )-1;i++ )
00244 {
00245 if ( detectedMarkers[i].id==detectedMarkers[i+1].id && !toRemove[i+1] )
00246 {
00247
00248 if ( perimeter ( detectedMarkers[i] ) >perimeter ( detectedMarkers[i+1] ) ) toRemove[i+1]=true;
00249 else toRemove[i]=true;
00250 }
00251
00252 for(size_t c=0;c<detectedMarkers[i].size();c++){
00253 if ( detectedMarkers[i][c].x<borderDistThresX ||
00254 detectedMarkers[i][c].y<borderDistThresY ||
00255 detectedMarkers[i][c].x>input.cols-borderDistThresX ||
00256 detectedMarkers[i][c].y>input.rows-borderDistThresY ) toRemove[i]=true;
00257
00258 }
00259
00260
00261 }
00262
00263 removeElements ( detectedMarkers, toRemove );
00264
00266 if ( camMatrix.rows!=0 && markerSizeMeters>0 )
00267 {
00268 for ( unsigned int i=0;i<detectedMarkers.size();i++ )
00269 detectedMarkers[i].calculateExtrinsics ( markerSizeMeters,camMatrix,distCoeff,setYPerpendicular );
00270 }
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280 void MarkerDetector::detectRectangles ( const cv::Mat &thres,vector<std::vector<cv::Point2f> > &MarkerCanditates )
00281 {
00282 vector<MarkerCandidate> candidates;
00283 detectRectangles(thres,candidates);
00284
00285 MarkerCanditates.resize(candidates.size());
00286 for (size_t i=0;i<MarkerCanditates.size();i++)
00287 MarkerCanditates[i]=candidates[i];
00288 }
00289
00290 void MarkerDetector::detectRectangles(const cv::Mat &thresImg,vector<MarkerCandidate> & OutMarkerCanditates)
00291 {
00292 vector<MarkerCandidate> MarkerCanditates;
00293
00294 int minSize=_minSize*std::max(thresImg.cols,thresImg.rows)*4;
00295 int maxSize=_maxSize*std::max(thresImg.cols,thresImg.rows)*4;
00296 std::vector<std::vector<cv::Point> > contours2;
00297 std::vector<cv::Vec4i> hierarchy2;
00298
00299 thresImg.copyTo ( thres2 );
00300 cv::findContours ( thres2 , contours2, hierarchy2,CV_RETR_LIST, CV_CHAIN_APPROX_NONE );
00301 vector<Point> approxCurve;
00303
00304 for ( unsigned int i=0;i<contours2.size();i++ )
00305 {
00306
00307
00308
00309 if ( minSize< contours2[i].size() &&contours2[i].size()<maxSize )
00310 {
00311
00312 approxPolyDP ( contours2[i] ,approxCurve , double ( contours2[i].size() ) *0.05 , true );
00313
00314
00315 if ( approxCurve.size() ==4 )
00316 {
00317
00318
00319
00320
00321
00322
00323 if ( isContourConvex ( Mat ( approxCurve ) ) )
00324 {
00325
00326
00327 float minDist=1e10;
00328 for ( int j=0;j<4;j++ )
00329 {
00330 float d= std::sqrt ( ( float ) ( approxCurve[j].x-approxCurve[ ( j+1 ) %4].x ) * ( approxCurve[j].x-approxCurve[ ( j+1 ) %4].x ) +
00331 ( approxCurve[j].y-approxCurve[ ( j+1 ) %4].y ) * ( approxCurve[j].y-approxCurve[ ( j+1 ) %4].y ) );
00332
00333 if ( d<minDist ) minDist=d;
00334 }
00335
00336 if ( minDist>10 )
00337 {
00338
00339
00340 MarkerCanditates.push_back ( MarkerCandidate() );
00341 MarkerCanditates.back().idx=i;
00342 for ( int j=0;j<4;j++ )
00343 {
00344 MarkerCanditates.back().push_back ( Point2f ( approxCurve[j].x,approxCurve[j].y ) );
00345 }
00346 }
00347 }
00348 }
00349 }
00350 }
00351
00352
00353
00354
00356 valarray<bool> swapped(false,MarkerCanditates.size());
00357 for ( unsigned int i=0;i<MarkerCanditates.size();i++ )
00358 {
00359
00360
00361
00362 double dx1 = MarkerCanditates[i][1].x - MarkerCanditates[i][0].x;
00363 double dy1 = MarkerCanditates[i][1].y - MarkerCanditates[i][0].y;
00364 double dx2 = MarkerCanditates[i][2].x - MarkerCanditates[i][0].x;
00365 double dy2 = MarkerCanditates[i][2].y - MarkerCanditates[i][0].y;
00366 double o = ( dx1*dy2 )- ( dy1*dx2 );
00367
00368 if ( o < 0.0 )
00369 {
00370 swap ( MarkerCanditates[i][1],MarkerCanditates[i][3] );
00371 swapped[i]=true;
00372
00373
00374
00375 }
00376 }
00377
00379
00380
00381 vector< vector<pair<int,int> > > TooNearCandidates_omp(omp_get_max_threads());
00382 #pragma omp parallel for
00383 for ( unsigned int i=0;i<MarkerCanditates.size();i++ )
00384 {
00385
00386
00387 for ( unsigned int j=i+1;j<MarkerCanditates.size();j++ )
00388 {
00389 float dist=0;
00390 for ( int c=0;c<4;c++ )
00391 dist+= sqrt ( ( MarkerCanditates[i][c].x-MarkerCanditates[j][c].x ) * ( MarkerCanditates[i][c].x-MarkerCanditates[j][c].x ) + ( MarkerCanditates[i][c].y-MarkerCanditates[j][c].y ) * ( MarkerCanditates[i][c].y-MarkerCanditates[j][c].y ) );
00392 dist/=4;
00393
00394 if ( dist< 10 )
00395 {
00396 TooNearCandidates_omp[omp_get_thread_num()].push_back ( pair<int,int> ( i,j ) );
00397 }
00398 }
00399 }
00400
00401 vector<pair<int,int> > TooNearCandidates;
00402 joinVectors( TooNearCandidates_omp,TooNearCandidates);
00403
00404 valarray<bool> toRemove ( false,MarkerCanditates.size() );
00405 for ( unsigned int i=0;i<TooNearCandidates.size();i++ )
00406 {
00407 if ( perimeter ( MarkerCanditates[TooNearCandidates[i].first ] ) >perimeter ( MarkerCanditates[ TooNearCandidates[i].second] ) )
00408 toRemove[TooNearCandidates[i].second]=true;
00409 else toRemove[TooNearCandidates[i].first]=true;
00410 }
00411
00412
00413
00414
00415 OutMarkerCanditates.reserve(MarkerCanditates.size());
00416 for (size_t i=0;i<MarkerCanditates.size();i++) {
00417 if (!toRemove[i]) {
00418 OutMarkerCanditates.push_back(MarkerCanditates[i]);
00419 OutMarkerCanditates.back().contour=contours2[ MarkerCanditates[i].idx];
00420 if (swapped[i] )
00421 reverse(OutMarkerCanditates.back().contour.begin(),OutMarkerCanditates.back().contour.end());
00422 }
00423 }
00424
00425 }
00426
00427
00428
00429
00430
00431
00432
00433 void MarkerDetector::thresHold ( int method,const Mat &grey,Mat &out,double param1,double param2 ) throw ( cv::Exception )
00434 {
00435
00436 if (param1==-1) param1=_thresParam1;
00437 if (param2==-1) param2=_thresParam2;
00438
00439 if ( grey.type() !=CV_8UC1 ) throw cv::Exception ( 9001,"grey.type()!=CV_8UC1","MarkerDetector::thresHold",__FILE__,__LINE__ );
00440 switch ( method )
00441 {
00442 case FIXED_THRES:
00443 cv::threshold ( grey, out, param1,255, CV_THRESH_BINARY_INV );
00444 break;
00445 case ADPT_THRES:
00446
00447 if ( param1<3 ) param1=3;
00448 else if ( ( ( int ) param1 ) %2 !=1 ) param1= ( int ) ( param1+1 );
00449
00450 cv::adaptiveThreshold ( grey,out,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY_INV,param1,param2 );
00451 break;
00452 case CANNY:
00453 {
00454
00455
00456
00457
00458 cv::Canny ( grey, out, 10, 220 );
00459
00460
00461
00462
00463
00464 }
00465 break;
00466 }
00467 }
00468
00469
00470
00471
00472
00473
00474 bool MarkerDetector::warp ( Mat &in,Mat &out,Size size, vector<Point2f> points ) throw ( cv::Exception )
00475 {
00476
00477 if ( points.size() !=4 ) throw cv::Exception ( 9001,"point.size()!=4","MarkerDetector::warp",__FILE__,__LINE__ );
00478
00479 Point2f pointsRes[4],pointsIn[4];
00480 for ( int i=0;i<4;i++ ) pointsIn[i]=points[i];
00481 pointsRes[0]= ( Point2f ( 0,0 ) );
00482 pointsRes[1]= Point2f ( size.width-1,0 );
00483 pointsRes[2]= Point2f ( size.width-1,size.height-1 );
00484 pointsRes[3]= Point2f ( 0,size.height-1 );
00485 Mat M=getPerspectiveTransform ( pointsIn,pointsRes );
00486 cv::warpPerspective ( in, out, M, size,cv::INTER_NEAREST );
00487 return true;
00488 }
00489
00490 void findCornerPointsInContour(const vector<cv::Point2f>& points,const vector<cv::Point> &contour,vector<int> &idxs)
00491 {
00492 assert(points.size()==4);
00493 int idxSegments[4]={-1,-1,-1,-1};
00494
00495 cv::Point points2i[4];
00496 for (int i=0;i<4;i++) {
00497 points2i[i].x=points[i].x;
00498 points2i[i].y=points[i].y;
00499 }
00500
00501 for (size_t i=0;i<contour.size();i++) {
00502 if (idxSegments[0]==-1)
00503 if (contour[i]==points2i[0]) idxSegments[0]=i;
00504 if (idxSegments[1]==-1)
00505 if (contour[i]==points2i[1]) idxSegments[1]=i;
00506 if (idxSegments[2]==-1)
00507 if (contour[i]==points2i[2]) idxSegments[2]=i;
00508 if (idxSegments[3]==-1)
00509 if (contour[i]==points2i[3]) idxSegments[3]=i;
00510 }
00511 idxs.resize(4);
00512 for (int i=0;i<4;i++) idxs[i]=idxSegments[i];
00513 }
00514
00515 int findDeformedSidesIdx(const vector<cv::Point> &contour,const vector<int> &idxSegments)
00516 {
00517 float distSum[4]={0,0,0,0};
00518 cv::Scalar colors[4]={cv::Scalar(0,0,255),cv::Scalar(255,0,0),cv::Scalar(0,255,0),cv::Scalar(111,111,0)};
00519
00520 for (int i=0;i<3;i++) {
00521 cv::Point p1=contour[ idxSegments[i]];
00522 cv::Point p2=contour[ idxSegments[i+1]];
00523 float inv_den=1./ sqrt(float(( p2.x-p1.x)*(p2.x-p1.x)+ (p2.y-p1.y)*(p2.y-p1.y)));
00524
00525
00526 for (size_t j=idxSegments[i];j<idxSegments[i+1];j++) {
00527 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;
00528 distSum[i]+=dist;
00529
00530
00531 }
00532 distSum[i]/=float(idxSegments[i+1]-idxSegments[i]);
00533
00534 }
00535
00536
00537
00538 cv::Point p1=contour[ idxSegments[0]];
00539 cv::Point p2=contour[ idxSegments[3]];
00540 float inv_den=1./ std::sqrt(float(( p2.x-p1.x)*(p2.x-p1.x)+ (p2.y-p1.y)*(p2.y-p1.y)));
00541
00542 for (size_t j=0;j<idxSegments[0];j++)
00543 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;
00544 for (size_t j=idxSegments[3];j<contour.size();j++)
00545 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;
00546
00547 distSum[3]/=float( idxSegments[0]+ (contour.size()-idxSegments[3]));
00548
00549
00550
00551
00552 if ( distSum[0]+distSum[2]> distSum[1]+distSum[3])
00553 return 0;
00554 else return 1;
00555 }
00556
00557 void setPointIntoImage(cv::Point2f &p,cv::Size s) {
00558 if (p.x<0) p.x=0;
00559 else if (p.x>=s.width )p.x=s.width-1;
00560 if (p.y<0)p.y=0;
00561 else if (p.y>=s.height)p.y=s.height-1;
00562
00563 }
00564
00565 void setPointIntoImage(cv::Point &p,cv::Size s) {
00566 if (p.x<0) p.x=0;
00567 else if (p.x>=s.width )p.x=s.width-1;
00568 if (p.y<0)p.y=0;
00569 else if (p.y>=s.height)p.y=s.height-1;
00570
00571 }
00572
00573
00574
00575
00576
00577
00578 bool MarkerDetector::warp_cylinder ( Mat &in,Mat &out,Size size, MarkerCandidate& mcand ) throw ( cv::Exception )
00579 {
00580
00581 if ( mcand.size() !=4 ) throw cv::Exception ( 9001,"point.size()!=4","MarkerDetector::warp",__FILE__,__LINE__ );
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591 vector<int> idxSegments;
00592 findCornerPointsInContour(mcand,mcand.contour,idxSegments);
00593
00594 int minIdx=0;
00595 for (int i=1;i<4;i++)
00596 if (idxSegments[i] <idxSegments[minIdx]) minIdx=i;
00597
00598 std::rotate(idxSegments.begin(),idxSegments.begin()+minIdx,idxSegments.end());
00599 std::rotate(mcand.begin(),mcand.begin()+minIdx,mcand.end());
00600
00601
00602
00603 int defrmdSide=findDeformedSidesIdx(mcand.contour,idxSegments);
00604
00605
00606
00607
00608 cv::Point2f center=mcand.getCenter();
00609 Point2f enlargedRegion[4];
00610 for (int i=0;i<4;i++) enlargedRegion[i]=mcand[i];
00611 if (defrmdSide==0) {
00612 enlargedRegion[0]=mcand[0]+(mcand[3]-mcand[0])*1.2;
00613 enlargedRegion[1]=mcand[1]+(mcand[2]-mcand[1])*1.2;
00614 enlargedRegion[2]=mcand[2]+(mcand[1]-mcand[2])*1.2;
00615 enlargedRegion[3]=mcand[3]+(mcand[0]-mcand[3])*1.2;
00616 }
00617 else {
00618 enlargedRegion[0]=mcand[0]+(mcand[1]-mcand[0])*1.2;
00619 enlargedRegion[1]=mcand[1]+(mcand[0]-mcand[1])*1.2;
00620 enlargedRegion[2]=mcand[2]+(mcand[3]-mcand[2])*1.2;
00621 enlargedRegion[3]=mcand[3]+(mcand[2]-mcand[3])*1.2;
00622 }
00623 for (size_t i=0;i<4;i++)
00624 setPointIntoImage(enlargedRegion[i],in.size());
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 Point2f pointsRes[4],pointsIn[4];
00642 for ( int i=0;i<4;i++ ) pointsIn[i]=mcand[i];
00643
00644 cv::Size enlargedSize=size;
00645 enlargedSize.width+=2*enlargedSize.width*0.2;
00646 pointsRes[0]= ( Point2f ( 0,0 ) );
00647 pointsRes[1]= Point2f ( enlargedSize.width-1,0 );
00648 pointsRes[2]= Point2f ( enlargedSize.width-1,enlargedSize.height-1 );
00649 pointsRes[3]= Point2f ( 0,enlargedSize.height-1 );
00650
00651 if (defrmdSide==0) rotate(pointsRes,pointsRes+1,pointsRes+4);
00652 cv::Mat imAux,imAux2(enlargedSize,CV_8UC1);
00653 Mat M=getPerspectiveTransform ( enlargedRegion,pointsRes );
00654 cv::warpPerspective ( in, imAux, M, enlargedSize,cv::INTER_NEAREST);
00655
00656
00657 vector<cv::Point> pointsCO(mcand.contour.size());
00658 assert(M.type()==CV_64F);
00659 assert(M.cols==3 && M.rows==3);
00660
00661 double *mptr=M.ptr<double>(0);
00662 imAux2.setTo(cv::Scalar::all(0));
00663
00664
00665 for (size_t i=0;i<mcand.contour.size();i++) {
00666 float inX=mcand.contour[i].x;
00667 float inY=mcand.contour[i].y;
00668 float w= inX * mptr[6]+inY * mptr[7]+mptr[8];
00669 cv::Point2f pres;
00670 pointsCO[i].x=( (inX * mptr[0]+inY* mptr[1]+mptr[2])/w)+0.5;
00671 pointsCO[i].y=( (inX * mptr[3]+inY* mptr[4]+mptr[5])/w)+0.5;
00672
00673 setPointIntoImage(pointsCO[i],imAux.size());
00674
00675 imAux2.at<uchar>(pointsCO[i].y,pointsCO[i].x)=255;
00676 if (pointsCO[i].y>0)
00677 imAux2.at<uchar>(pointsCO[i].y-1,pointsCO[i].x)=255;
00678 if (pointsCO[i].y<imAux2.rows-1 )
00679 imAux2.at<uchar>(pointsCO[i].y+1,pointsCO[i].x)=255;
00680 }
00681
00682 cv::Mat outIm(enlargedSize,CV_8UC1);
00683 outIm.setTo(cv::Scalar::all(0));
00684
00685 for (int y=0;y<imAux2.rows;y++) {
00686 uchar *_offInfo=imAux2.ptr<uchar>(y);
00687 int start=-1,end=-1;
00688
00689 for (int x=0;x<imAux.cols;x++) {
00690 if (_offInfo[x]) {
00691 if (start==-1) start=x;
00692 else end=x;
00693 }
00694 }
00695
00696
00697 assert(start!=-1 && end!=-1 && (end-start)> size.width>>1);
00698 uchar *In_image=imAux.ptr<uchar>(y);
00699 uchar *Out_image=outIm.ptr<uchar>(y);
00700 memcpy(Out_image,In_image+start,imAux.cols-start );
00701 }
00702
00703
00704
00705
00706 cv::Mat centerReg=outIm(cv::Range::all(),cv::Range(0,size.width));
00707 out=centerReg.clone();
00708
00709
00710
00711
00712
00713 return true;
00714 }
00715
00716
00717
00718
00719
00720
00721 bool MarkerDetector::isInto ( Mat &contour,vector<Point2f> &b )
00722 {
00723
00724 for ( unsigned int i=0;i<b.size();i++ )
00725 if ( pointPolygonTest ( contour,b[i],false ) >0 ) return true;
00726 return false;
00727 }
00728
00729
00730
00731
00732
00733
00734 int MarkerDetector:: perimeter ( vector<Point2f> &a )
00735 {
00736 int sum=0;
00737 for ( unsigned int i=0;i<a.size();i++ )
00738 {
00739 int i2= ( i+1 ) %a.size();
00740 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 ) ) ;
00741 }
00742 return sum;
00743 }
00744
00745
00750 void MarkerDetector::findBestCornerInRegion_harris ( const cv::Mat & grey,vector<cv::Point2f> & Corners,int blockSize )
00751 {
00752 SubPixelCorner Subp;
00753 Subp.RefineCorner(grey,Corners);
00754
00755 }
00756
00757
00762 void MarkerDetector::refineCandidateLines(MarkerDetector::MarkerCandidate& candidate, const cv::Mat &camMatrix, const cv::Mat &distCoeff)
00763 {
00764
00765 vector<unsigned int> cornerIndex;
00766 cornerIndex.resize(4);
00767 for(unsigned int j=0; j<candidate.contour.size(); j++) {
00768 for(unsigned int k=0; k<4; k++) {
00769 if(candidate.contour[j].x==candidate[k].x && candidate.contour[j].y==candidate[k].y) {
00770 cornerIndex[k] = j;
00771 }
00772 }
00773 }
00774
00775
00776 bool inverse;
00777 if( (cornerIndex[1] > cornerIndex[0]) && (cornerIndex[2]>cornerIndex[1] || cornerIndex[2]<cornerIndex[0]) )
00778 inverse = false;
00779 else if( cornerIndex[2]>cornerIndex[1] && cornerIndex[2]<cornerIndex[0] )
00780 inverse = false;
00781 else inverse = true;
00782
00783
00784
00785 int inc = 1;
00786 if(inverse) inc = -1;
00787
00788
00789 vector<Point2f> contour2f;
00790 for(unsigned int i=0; i<candidate.contour.size(); i++)
00791 contour2f.push_back( cv::Point2f(candidate.contour[i].x, candidate.contour[i].y) );
00792 if(!camMatrix.empty() && !distCoeff.empty())
00793 cv::undistortPoints(contour2f, contour2f, camMatrix, distCoeff, cv::Mat(), camMatrix);
00794
00795
00796 vector<std::vector<cv::Point2f> > contourLines;
00797 contourLines.resize(4);
00798 for(unsigned int l=0; l<4; l++) {
00799 for(int j=(int)cornerIndex[l]; j!=(int)cornerIndex[(l+1)%4]; j+=inc) {
00800 if(j==(int)candidate.contour.size() && !inverse) j=0;
00801 else if(j==0 && inverse) j=candidate.contour.size()-1;
00802 contourLines[l].push_back(contour2f[j]);
00803 if(j==(int)cornerIndex[(l+1)%4]) break;
00804 }
00805
00806 }
00807
00808
00809 vector<Point3f> lines;
00810 lines.resize(4);
00811 for(unsigned int j=0; j<lines.size(); j++) interpolate2Dline(contourLines[j], lines[j]);
00812
00813
00814 vector<Point2f> crossPoints;
00815 crossPoints.resize(4);
00816 for(unsigned int i=0; i<4; i++)
00817 crossPoints[i] = getCrossPoint( lines[(i-1)%4], lines[i] );
00818
00819
00820 if(!camMatrix.empty() && !distCoeff.empty())
00821 distortPoints(crossPoints, crossPoints, camMatrix, distCoeff);
00822
00823
00824 for(unsigned int j=0; j<4; j++)
00825 candidate[j] = crossPoints[j];
00826 }
00827
00828
00831 void MarkerDetector::interpolate2Dline( const std::vector< Point2f >& inPoints, Point3f& outLine)
00832 {
00833
00834 float minX, maxX, minY, maxY;
00835 minX = maxX = inPoints[0].x;
00836 minY = maxY = inPoints[0].y;
00837 for(unsigned int i=1; i<inPoints.size(); i++) {
00838 if(inPoints[i].x < minX) minX = inPoints[i].x;
00839 if(inPoints[i].x > maxX) maxX = inPoints[i].x;
00840 if(inPoints[i].y < minY) minY = inPoints[i].y;
00841 if(inPoints[i].y > maxY) maxY = inPoints[i].y;
00842 }
00843
00844
00845 Mat A(inPoints.size(),2,CV_32FC1, Scalar(0));
00846 Mat B(inPoints.size(),1,CV_32FC1, Scalar(0));
00847 Mat X;
00848
00849
00850
00851 if( maxX-minX > maxY-minY ) {
00852
00853 for (int i=0; i<inPoints.size(); i++) {
00854
00855 A.at<float>(i, 0) = inPoints[i].x;
00856 A.at<float>(i, 1) = 1.;
00857 B.at<float>(i, 0) = inPoints[i].y;
00858
00859 }
00860
00861
00862 solve(A,B,X, DECOMP_SVD);
00863
00864 outLine = Point3f(X.at<float>(0,0), -1., X.at<float>(1,0));
00865 }
00866 else {
00867
00868 for (int i=0; i<inPoints.size(); i++) {
00869
00870 A.at<float>(i, 0) = inPoints[i].y;
00871 A.at<float>(i, 1) = 1.;
00872 B.at<float>(i, 0) = inPoints[i].x;
00873
00874 }
00875
00876
00877 solve(A,B,X, DECOMP_SVD);
00878
00879 outLine = Point3f(-1., X.at<float>(0,0), X.at<float>(1,0));
00880 }
00881
00882 }
00883
00886 Point2f MarkerDetector::getCrossPoint(const cv::Point3f& line1, const cv::Point3f& line2)
00887 {
00888
00889
00890 Mat A(2,2,CV_32FC1, Scalar(0));
00891 Mat B(2,1,CV_32FC1, Scalar(0));
00892 Mat X;
00893
00894 A.at<float>(0, 0) = line1.x;
00895 A.at<float>(0, 1) = line1.y;
00896 B.at<float>(0, 0) = -line1.z;
00897
00898 A.at<float>(1, 0) = line2.x;
00899 A.at<float>(1, 1) = line2.y;
00900 B.at<float>(1, 0) = -line2.z;
00901
00902
00903 solve(A,B,X, DECOMP_SVD);
00904 return Point2f(X.at<float>(0,0), X.at<float>(1,0));
00905
00906 }
00907
00908
00911 void MarkerDetector::distortPoints(vector<cv::Point2f> in, vector<cv::Point2f> &out, const Mat& camMatrix, const Mat& distCoeff)
00912 {
00913
00914 cv::Mat Rvec = cv::Mat(3,1,CV_32FC1, cv::Scalar::all(0));
00915 cv::Mat Tvec = Rvec.clone();
00916
00917 vector<cv::Point3f> cornersPoints3d;
00918 for(unsigned int i=0; i<in.size(); i++)
00919 cornersPoints3d.push_back( cv::Point3f(
00920 (in[i].x-camMatrix.at<float>(0,2))/camMatrix.at<float>(0,0),
00921 (in[i].y-camMatrix.at<float>(1,2))/camMatrix.at<float>(1,1),
00922 1 ) );
00923 cv::projectPoints(cornersPoints3d, Rvec, Tvec, camMatrix, distCoeff, out);
00924 }
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934 void MarkerDetector::drawAllContours ( Mat input, std::vector<std::vector<cv::Point> > &contours )
00935 {
00936 drawContours ( input, contours, -1,Scalar ( 255,0,255 ) );
00937 }
00938
00939
00940
00941
00942
00943
00944
00945 void MarkerDetector:: drawContour ( Mat &in,vector<Point> &contour,Scalar color )
00946 {
00947 for ( unsigned int i=0;i<contour.size();i++ )
00948 {
00949 cv::rectangle ( in,contour[i],contour[i],color );
00950 }
00951 }
00952
00953 void MarkerDetector:: drawApproxCurve ( Mat &in,vector<Point> &contour,Scalar color )
00954 {
00955 for ( unsigned int i=0;i<contour.size();i++ )
00956 {
00957 cv::line ( in,contour[i],contour[ ( i+1 ) %contour.size() ],color );
00958 }
00959 }
00960
00961
00962
00963
00964
00965
00966
00967 void MarkerDetector::draw ( Mat out,const vector<Marker> &markers )
00968 {
00969 for ( unsigned int i=0;i<markers.size();i++ )
00970 {
00971 cv::line ( out,markers[i][0],markers[i][1],cvScalar ( 255,0,0 ),2,CV_AA );
00972 cv::line ( out,markers[i][1],markers[i][2],cvScalar ( 255,0,0 ),2,CV_AA );
00973 cv::line ( out,markers[i][2],markers[i][3],cvScalar ( 255,0,0 ),2,CV_AA );
00974 cv::line ( out,markers[i][3],markers[i][0],cvScalar ( 255,0,0 ),2,CV_AA );
00975 }
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 void MarkerDetector::glGetProjectionMatrix ( CameraParameters & CamMatrix,cv::Size orgImgSize, cv::Size size,double proj_matrix[16],double gnear,double gfar,bool invert ) throw ( cv::Exception )
01010 {
01011 cerr<<"MarkerDetector::glGetProjectionMatrix . This a deprecated function. Use CameraParameters::glGetProjectionMatrix instead. "<<__FILE__<<" "<<__LINE__<<endl;
01012 CamMatrix.glGetProjectionMatrix ( orgImgSize,size,proj_matrix,gnear,gfar,invert );
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022 void MarkerDetector::setMinMaxSize(float min ,float max )throw(cv::Exception)
01023 {
01024 if (min<=0 || min>1) throw cv::Exception(1," min parameter out of range","MarkerDetector::setMinMaxSize",__FILE__,__LINE__);
01025 if (max<=0 || max>1) throw cv::Exception(1," max parameter out of range","MarkerDetector::setMinMaxSize",__FILE__,__LINE__);
01026 if (min>max) throw cv::Exception(1," min>max","MarkerDetector::setMinMaxSize",__FILE__,__LINE__);
01027 _minSize=min;
01028 _maxSize=max;
01029 }
01030
01031
01032
01033
01034
01035
01036
01037
01038 void MarkerDetector::setWarpSize(int val) throw(cv::Exception)
01039 {
01040 if (val<10) throw cv::Exception(1," invalid canonical image size","MarkerDetector::setWarpSize",__FILE__,__LINE__);
01041 _markerWarpSize = val;
01042 }
01043
01044
01045 };
01046