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
00048 #include <arrow_detection/findArrow.h>
00049
00050
00051
00052
00053
00054
00055 bool findArrow::found_new_point=false;
00056
00057
00058
00059 const unsigned int findArrow::EROSION_SIZE=1;
00060 const unsigned int findArrow::EROSION_SIZE_MIN=1;
00061 const unsigned int findArrow::THRESH = 100;
00062 const unsigned int findArrow::MAX_THRESH = 255;
00063 const unsigned int findArrow::LINE_THICKNESS = 2;
00064
00065
00066 const unsigned short findArrow::VAL_MAX_LENGTH= 500;
00067 const unsigned short findArrow::VAL_MIN_LENGTH = 100;
00068 const float findArrow::VAL_MIN_RELATION_LENGTH = 1.3;
00069 const float findArrow::VAL_MAX_RELATION_LENGTH = 3.1;
00070
00071
00072 const double findArrow::BBCA_MIN = 1.3;
00073 const double findArrow::BBCA_MAX = 1.9;
00074 const double findArrow::BBCL_MIN = 7;
00075 const double findArrow::BBCL_MAX = 35;
00076 const double findArrow::CACL_MIN = 4;
00077 const double findArrow::CACL_MAX = 22;
00078 const double findArrow::AREA_MIN = 500;
00079
00080
00081 const unsigned short findArrow::CONVEX_HULL_CORNERS = 5;
00082
00083
00084 const unsigned short findArrow::CONVEX_ARROW_CORNERS = 7;
00085
00086 Point findArrow::calculate_center_contour(Point2f contour[],unsigned int size_contour)
00087 {
00088
00096 assert (size_contour>0);
00097 unsigned int cont=0;
00098 double xx=0,yy=0;
00099 Point result;
00100 for(cont=0;cont<size_contour;cont++)
00101 {
00102 xx+=contour[cont].x;
00103 yy+=contour[cont].y;
00104 }
00105 result.x=xx/cont+1;
00106 result.y=yy/cont+1;
00107
00108 return result;
00109 }
00110
00112 void findArrow::Opening(Mat & src, Mat & dest,unsigned int erosion_size)
00113 {
00123 assert(erosion_size > 0);
00124 Mat element = getStructuringElement( MORPH_RECT,Size( 2*erosion_size + 1, 2*erosion_size+1 ),
00125 Point( erosion_size, erosion_size ) );
00126
00127 dilate( src, dest, element );
00128 erode( dest, dest, element );
00129 }
00130
00132 void findArrow::closing(Mat & src, Mat & dest,unsigned int erosion_size)
00133 {
00143 assert(erosion_size > 0);
00144 Mat element = getStructuringElement( MORPH_RECT,Size( 2*erosion_size + 1, 2*erosion_size+1 ),
00145 Point( erosion_size, erosion_size ) );
00146
00147 erode( src, dest, element );
00148 dilate( dest, dest, element );
00149 }
00150
00151 void findArrow::boundig_box( Mat & src_tresh, Mat & threshold_output)
00152 {
00163 vector<vector<Point> > contours;
00164 vector<Vec4i> hierarchy;
00165
00166 RNG rng(12345);
00168 findContours( src_tresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
00169
00171 vector<vector<Point> > contours_poly( contours.size() );
00172 vector<Rect> boundRect( contours.size() );
00173 vector<Point2f>center( contours.size() );
00174 vector<float>radius( contours.size() );
00175
00176 for( unsigned i = 0; i < contours.size(); i++ )
00177 { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
00178 boundRect[i] = boundingRect( Mat(contours_poly[i]) );
00179 minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
00180 }
00181
00183 Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
00184
00185 for( unsigned i = 0; i< contours.size(); i++ )
00186 {
00187 Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
00188 drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
00189 rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
00190 circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );
00191 }
00192
00194
00195
00196
00197 }
00198
00199
00200
00202 void findArrow::descritor( Mat & img_object, Mat & img_scene)
00203 {
00204
00205
00207
00208
00209
00210
00211 int minHessian = 1000;
00212
00213 SurfFeatureDetector detector( minHessian );
00214
00215 std::vector<KeyPoint> keypoints_object, keypoints_scene;
00216
00217 detector.detect( img_object, keypoints_object );
00218 detector.detect( img_scene, keypoints_scene );
00219
00220
00221 SurfDescriptorExtractor extractor;
00222
00223 Mat descriptors_object, descriptors_scene;
00224
00225 extractor.compute( img_object, keypoints_object, descriptors_object );
00226 extractor.compute( img_scene, keypoints_scene, descriptors_scene );
00227
00228
00229 FlannBasedMatcher matcher;
00230 std::vector< DMatch > matches;
00231 matcher.match( descriptors_object, descriptors_scene, matches );
00232
00233 double max_dist = 0; double min_dist = 100;
00234
00235
00236 for( int i = 0; i < descriptors_object.rows; i++ )
00237 { double dist = matches[i].distance;
00238 if( dist < min_dist ) min_dist = dist;
00239 if( dist > max_dist ) max_dist = dist;
00240 }
00241
00242 printf("-- Max dist : %f \n", max_dist );
00243 printf("-- Min dist : %f \n", min_dist );
00244
00245
00246 std::vector< DMatch > good_matches;
00247
00248 for( int i = 0; i < descriptors_object.rows; i++ )
00249 { if( matches[i].distance < 2*min_dist )
00250 { good_matches.push_back( matches[i]); }
00251 }
00252
00253 Mat img_matches;
00254 drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
00255 good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
00256 vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
00257
00258
00259 std::vector<Point2f> obj;
00260 std::vector<Point2f> scene;
00261
00262 for(unsigned int i = 0; i < good_matches.size(); i++ )
00263 {
00264
00265 obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
00266 scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
00267 }
00268
00269 cout<<"Obj "<<obj.size()<<" scene: "<<scene.size()<<endl;
00270
00271 if(obj.size()>=4 && scene.size()>=4)
00272 {
00273
00274 Mat H = findHomography( obj, scene, CV_RANSAC );
00275
00276
00277 std::vector<Point2f> obj_corners(4);
00278 obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
00279 obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
00280 std::vector<Point2f> scene_corners(4);
00281
00282 perspectiveTransform( obj_corners, scene_corners, H);
00283
00284
00285 line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
00286 line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
00287 line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
00288 line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
00289
00290 }
00291
00292 imshow( "Good Matches & Object detection", img_matches );
00293
00294 }
00295
00296
00297 bool findArrow::validate_contour_Area_Length(vector<Point> contours,vector<double> bbox_points,
00298 const double bbca_min,
00299 const double bbca_max,const double bbcl_min, const double bbcl_max,
00300 const double cacl_min,const double cacl_max)
00301 {
00313 double bb_length = bbox_points[0];
00314 double bb_Width = bbox_points[3];
00315 double bba = bb_Width*bb_length;
00316
00317 double ca = contourArea(contours);
00318 double cl = arcLength( contours, true );
00319
00320 double bb_ca = bba/ca;
00321 double bb_cl = bba/cl;
00322 double ca_cl = ca/cl;
00323
00324 return ((bb_ca > bbca_min && bb_ca < bbca_max) && (bb_cl > bbcl_min && bb_cl < bbcl_max) &&
00325 (ca_cl > cacl_min && ca_cl < cacl_max) && ca > AREA_MIN);
00326
00327 }
00328
00330 vector<double> findArrow::sort_points(Point2f rect_points[])
00331 {
00332 vector<double> res(4);
00333
00334 for(unsigned short w=0; w<4 ; w++)
00335 {
00336 res[w]= norm(Mat(rect_points[w]),Mat(rect_points[(w+1)%4]));
00337 }
00338 std::sort(res.begin(),res.end());
00339
00340 return res;
00341 }
00342
00343
00344 bool findArrow::validate_lengths(Point2f rect_points[], const unsigned short max_length,
00345 const unsigned short min_length, const float min_relation_length,
00346 const float max_relation_length)
00347 {
00358 assert((max_length > 0) && (min_length >0) && (min_relation_length > 0) && (max_relation_length > 0));
00359 vector<double> res(4);
00360 res = sort_points(rect_points);
00361
00362 double relation_lengths = res[3]/res[0];
00363
00364 return (res[3]<max_length && (res[0]+res[3])>min_length &&
00365 relation_lengths>min_relation_length && relation_lengths< max_relation_length);
00366
00367 }
00368
00369 bool findArrow::validate_corners_arrow(vector<Point> contours,
00370 const unsigned short convex_arrow_corners)
00371 {
00372 assert(convex_arrow_corners > 0);
00373 vector<Point> arrow_corners;
00374 vector<Point> hull( contours.size() );
00375
00376 approxPolyDP(contours, arrow_corners, arcLength(Mat(contours), true) * 0.02, true );
00377
00378 return(arrow_corners.size() == convex_arrow_corners);
00379 }
00380
00381
00382 bool findArrow::validate_convexHull(vector<Point> contours,
00383 const unsigned short convex_hull_corners)
00384 {
00385 vector<Point> approx_hull;
00386 vector<Point> hull( contours.size() );
00387 convexHull( Mat(contours), hull, false );
00388
00389 approxPolyDP(Mat(hull), approx_hull, arcLength(Mat(hull), true) * 0.02, true );
00390
00391 return(approx_hull.size() == convex_hull_corners);
00392 }
00393
00394 float findArrow::innerAngle(float px1, float py1, float px2, float py2, float cx1, float cy1)
00395 {
00397 float dist1 = sqrt( (px1-cx1)*(px1-cx1) + (py1-cy1)*(py1-cy1) );
00398 float dist2 = sqrt( (px2-cx1)*(px2-cx1) + (py2-cy1)*(py2-cy1) );
00399
00400 float Ax, Ay;
00401 float Bx, By;
00402 float Cx, Cy;
00403
00404
00405
00406
00407 Cx = cx1;
00408 Cy = cy1;
00409 if(dist1 < dist2)
00410 {
00411 Bx = px1;
00412 By = py1;
00413 Ax = px2;
00414 Ay = py2;
00415
00416
00417 }else{
00418 Bx = px2;
00419 By = py2;
00420 Ax = px1;
00421 Ay = py1;
00422 }
00423
00424 float Q1 = Cx - Ax;
00425 float Q2 = Cy - Ay;
00426 float P1 = Bx - Ax;
00427 float P2 = By - Ay;
00428
00429
00430 float A = acos( (P1*Q1 + P2*Q2) / ( sqrt(P1*P1+P2*P2) * sqrt(Q1*Q1+Q2*Q2) ) );
00431
00432 A = A*180/CV_PI;
00433
00434 return A;
00435 }
00436
00437
00438 double findArrow::angle(cv::Point pt1, cv::Point pt2, cv::Point pt0)
00439 {
00444 double dx1 = pt1.x - pt0.x;
00445 double dy1 = pt1.y - pt0.y;
00446 double dx2 = pt2.x - pt0.x;
00447 double dy2 = pt2.y - pt0.y;
00448 return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
00449 }
00450
00451
00452 void findArrow::setLabel(cv::Mat& im, const std::string label, std::vector<cv::Point>& contour)
00453 {
00457 int fontface = cv::FONT_HERSHEY_SIMPLEX;
00458 double scale = 0.4;
00459 int thickness = 1;
00460 int baseline = 0;
00461
00462 cv::Size text = cv::getTextSize(label, fontface, scale, thickness, &baseline);
00463 cv::Rect r = cv::boundingRect(contour);
00464
00465 cv::Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));
00466 cv::rectangle(im, pt + cv::Point(0, baseline), pt + cv::Point(text.width, -text.height), CV_RGB(255,255,255), CV_FILLED);
00467 cv::putText(im, label, pt, fontface, scale, CV_RGB(0,0,0), thickness, 8);
00468 }
00469
00470
00471
00472
00473 int findArrow::find_arrow(cv::Mat frame,cv::Point & center_point)
00474 {
00475
00501
00502
00503
00504
00505
00506
00507 Mat edges,edges_b;
00508
00509
00510
00511
00512
00513 edges=frame;
00514
00515
00516
00517 equalizeHist( edges, edges );
00518
00519
00520 imshow("antes", edges);
00521 adaptiveThreshold(edges,edges_b, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY,7,5);
00522 imshow("depois", edges_b);
00523
00524 threshold(edges, edges, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
00525
00526
00527 edges = edges & edges_b;
00528
00529
00530
00531
00532
00533
00534
00535 vector<vector<Point> > contour = find_contours(edges, edges, LINE_THICKNESS);
00536 cv::imshow("imagem_teste2", edges);
00537 cv::waitKey(20);
00538
00539
00540 edges = edges > 128;
00541
00542
00543
00544 vector<RotatedRect> pontos_retangulos = boundig_box_small( edges,edges,contour,center_point);
00545 imshow("imagem_teste4", (edges));
00546
00547
00548
00549
00552
00553
00554
00555
00557
00558
00560
00561
00562 return 0;
00563 }
00564
00565
00566 vector<vector<Point> > findArrow::find_contours(Mat & src, Mat & dest,const unsigned int & line_thinckness)
00567 {
00589 vector<vector<Point> > contours,contours2;
00590 vector<Vec4i> hierarchy;
00591 findContours(src, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, Point(0,0) );
00592 Mat drawing = Mat::zeros( dest.size(), CV_8U );
00593
00594 for (unsigned int i=0; i<contours.size(); i++)
00595 {
00596
00597 if ((hierarchy[i][3] >= 0) && contourArea(contours[i])>AREA_MIN)
00598 {
00599
00600 drawContours(drawing, contours, i, Scalar(255, 0, 0), line_thinckness, 8);
00601
00602 contours2.push_back(contours[i]);
00603
00604
00605 }
00606 }
00607 dest=drawing;
00608
00609 return contours;
00610 }
00611
00612
00613 vector<RotatedRect> findArrow::boundig_box_small( Mat & src_tresh, Mat & threshold_output,vector<vector<Point> > contours,
00614 cv::Point & src_centre)
00615 {
00625 bool control=true;
00626 vector<vector<Point> > contours2;
00627 vector<Vec4i> hierarchy;
00628 RNG rng(12345);
00630
00631 findContours( src_tresh, contours2, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE,
00632 Point(0, 0) );
00633
00634 contours=contours2;
00635
00636
00638 vector<vector<Point> > contours_poly( contours.size() );
00639 vector<Rect> boundRect( contours.size() );
00640 vector<Point2f>center( contours.size() );
00641 vector<float>radius( contours.size() );
00642
00644 vector<RotatedRect> minRect( contours.size() );
00645 vector<RotatedRect> minEllipse( contours.size() );
00646
00647 for( size_t i = 0; i < contours.size(); i++ )
00648 {
00649
00650 minRect[i] = minAreaRect( Mat(contours[i]) );
00651 if( contours[i].size() > 5 )
00652 {
00653 minEllipse[i] = fitEllipse( Mat(contours[i]) );
00654 }
00655 }
00656
00658
00660 Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
00661
00662 vector<Point> approx;
00663 vector<Point> approx_hull;
00664 vector<vector<Point> >hull( contours.size() );
00665
00666 for( size_t i = 0; i< contours.size(); i++ )
00667 {
00668 Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
00669
00670 Point2f rect_points[4];
00671 minRect[i].points( rect_points );
00672 vector<double> bbox_points;
00673 bbox_points = sort_points(rect_points);
00674
00676 control=true;
00677
00678 if(contours[i].size()<7)
00679 {
00680 control=false;
00681 }
00683 if(control)if(!validate_contour_Area_Length(contours[i],bbox_points))
00684 {
00685 control=false;
00686 }
00688 if(control)if(!validate_lengths(rect_points))
00689 {
00690 control=false;
00691 }
00693 if(control)if(!validate_corners_arrow(contours[i]))
00694 {
00695 control=false;
00696 }
00699 if(control)if(!validate_convexHull(contours[i]))
00700 {
00701 control=false;
00702 }
00703
00704 if(control)
00705 {
00706
00707
00708
00709
00710
00711 src_centre=calculate_center_contour(rect_points,4);
00712
00713
00714
00715
00716
00717
00718 found_new_point = true;
00719 ellipse(drawing,Point(round(src_centre.x),round(src_centre.y)),Size
00720 (1,1),0,0,360,Scalar(102,0,255),3);
00721
00722 for( int j = 0; j < 4; j++ )
00723 {
00724 line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
00725 }
00726
00727
00728 Moments centre_arrow;
00729 centre_arrow = moments( contours[i], false );
00730
00731
00732 Point2f mc;
00733
00734 mc = Point2f( centre_arrow.m10/centre_arrow.m00 , centre_arrow.m01/centre_arrow.m00 );
00735
00736 ellipse(drawing,mc,Size(1,1),0,0,360,Scalar(255,255,255),3);
00737 drawContours(drawing, contours, i, Scalar(255, 0, 0), 1, 8);
00738
00739
00740 }
00741 }
00742
00743 threshold_output=drawing;
00744
00745 return minRect;
00746 }