66 #define MAX_CONTOUR_APPROX 7
71 IplConvKernel *kernel_cross,
72 IplConvKernel *kernel_rect,
73 IplConvKernel *kernel_diag1,
74 IplConvKernel *kernel_diag2,
75 IplConvKernel *kernel_horz,
76 IplConvKernel *kernel_vert
86 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_cross, 1);
88 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_rect, 1);
90 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_cross, 1);
92 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_rect, 1);
94 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_cross, 1);
96 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_rect, 1);
100 IplImage *ipl = thresh_img.
getAs<IplImage>();
106 case 37: cvDilate(ipl,ipl, kernel_cross , 1); isLast =
true;
108 case 36: cvErode (ipl,ipl, kernel_rect , 1);
110 case 35: cvDilate(ipl,ipl, kernel_vert , 1);
112 case 34: cvDilate(ipl,ipl, kernel_vert , 1);
114 case 33: cvDilate(ipl,ipl, kernel_vert , 1);
116 case 32: cvDilate(ipl,ipl, kernel_vert , 1);
118 case 31: cvDilate(ipl,ipl, kernel_vert , 1);
break;
120 case 30: cvDilate(ipl,ipl, kernel_cross , 1);
122 case 29: cvErode (ipl,ipl, kernel_rect , 1);
124 case 28: cvDilate(ipl,ipl, kernel_horz , 1);
126 case 27: cvDilate(ipl,ipl, kernel_horz , 1);
128 case 26: cvDilate(ipl,ipl, kernel_horz , 1);
130 case 25: cvDilate(ipl,ipl, kernel_horz , 1);
132 case 24: cvDilate(ipl,ipl, kernel_horz , 1);
break;
134 case 23: cvDilate(ipl,ipl, kernel_diag2 , 1);
136 case 22: cvDilate(ipl,ipl, kernel_diag1 , 1);
138 case 21: cvDilate(ipl,ipl, kernel_diag2 , 1);
140 case 20: cvDilate(ipl,ipl, kernel_diag1 , 1);
142 case 19: cvDilate(ipl,ipl, kernel_diag2 , 1);
144 case 18: cvDilate(ipl,ipl, kernel_diag1 , 1);
break;
146 case 17: cvDilate(ipl,ipl, kernel_diag2 , 1);
148 case 16: cvDilate(ipl,ipl, kernel_diag2 , 1);
150 case 15: cvDilate(ipl,ipl, kernel_diag2 , 1);
152 case 14: cvDilate(ipl,ipl, kernel_diag2 , 1);
break;
154 case 13: cvDilate(ipl,ipl, kernel_diag1 , 1);
156 case 12: cvDilate(ipl,ipl, kernel_diag1 , 1);
158 case 11: cvDilate(ipl,ipl, kernel_diag1 , 1);
160 case 10: cvDilate(ipl,ipl, kernel_diag1 , 1);
break;
162 case 9: cvDilate(ipl,ipl, kernel_cross , 1);
164 case 8: cvErode (ipl,ipl, kernel_rect , 1);
166 case 7: cvDilate(ipl,ipl, kernel_cross , 1);
168 case 6: cvDilate(ipl,ipl, kernel_diag2 , 1); isLast =
true;
170 case 5: cvDilate(ipl,ipl, kernel_diag1 , 1);
172 case 4: cvDilate(ipl,ipl, kernel_rect , 1);
174 case 3: cvErode (ipl,ipl, kernel_cross , 1);
176 case 2: cvDilate(ipl,ipl, kernel_rect , 1);
178 case 1: cvDilate(ipl,ipl, kernel_cross , 1);
199 size_t max_count = 0;
200 int max_dilation_run_ID = -1;
205 vector<CvCBQuadPtr> quads;
206 vector<CvCBQuadPtr> quad_group;
207 vector<CvCBCornerPtr> corners;
208 vector<CvCBQuadPtr> output_quad_group;
214 int quad_count, group_idx;
216 if( pattern_size.width < 2 || pattern_size.height < 2 )
218 std::cerr <<
"Pattern should have at least 2x2 size" << endl;
221 if( pattern_size.width > 127 || pattern_size.height > 127 )
223 std::cerr <<
"Pattern should not have a size larger than 127 x 127" << endl;
234 IplConvKernel *kernel_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL);
235 IplConvKernel *kernel_rect = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
237 static int kernel_diag1_vals[9] = {
241 IplConvKernel *kernel_diag1 = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CUSTOM,kernel_diag1_vals);
242 static int kernel_diag2_vals[9] = {
246 IplConvKernel *kernel_diag2 = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CUSTOM,kernel_diag2_vals);
247 static int kernel_horz_vals[9] = {
251 IplConvKernel *kernel_horz = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CUSTOM,kernel_horz_vals);
252 static int kernel_vert_vals[9] = {
256 IplConvKernel *kernel_vert = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CUSTOM,kernel_vert_vals);
262 block_size = cvRound(
MIN(
img.getWidth(),
img.getHeight())*0.2)|1;
264 cvAdaptiveThreshold(
img.getAs<IplImage>(), thresh_img.
getAs<IplImage>(), 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, block_size, 0 );
266 cvCopy( thresh_img.
getAs<IplImage>(), thresh_img_save.
getAs<IplImage>());
271 img.saveToFile(
"./DBG_OrigImg.png");
284 bool last_dilation =
false;
286 for(
int dilations = 0; !last_dilation; dilations++ )
289 cvCopy( thresh_img_save.
getAs<IplImage>(), thresh_img.
getAs<IplImage>() );
292 last_dilation =
do_special_dilation(thresh_img, dilations,kernel_cross,kernel_rect,kernel_diag1,kernel_diag2, kernel_horz,kernel_vert);
302 cvRectangle( thresh_img.
getAs<IplImage>(), cvPoint(0,0),
304 CV_RGB(255,255,255), 3, 8);
308 quad_count =
icvGenerateQuads( quads, corners, thresh_img, flags, dilations,
true );
309 if( quad_count <= 0 )
319 IplImage* imageCopy22 = cvCreateImage( cvGetSize(thresh_img.
getAs<IplImage>()), 8, 3 );
322 IplImage* imageCopy2 = cvCreateImage( cvGetSize(thresh_img.
getAs<IplImage>()), 8, 1 );
323 cvCopy( thresh_img.
getAs<IplImage>(), imageCopy2);
324 cvCvtColor( imageCopy2, imageCopy22, CV_GRAY2BGR );
326 for(
int kkk = 0; kkk < quad_count; kkk++ )
330 pt[0].x = (int)print_quad->corners[0]->pt.x;
331 pt[0].y = (
int)print_quad->corners[0]->pt.y;
332 pt[1].x = (int)print_quad->corners[1]->pt.x;
333 pt[1].y = (
int)print_quad->corners[1]->pt.y;
334 pt[2].x = (int)print_quad->corners[2]->pt.x;
335 pt[2].y = (
int)print_quad->corners[2]->pt.y;
336 pt[3].x = (int)print_quad->corners[3]->pt.x;
337 pt[3].y = (
int)print_quad->corners[3]->pt.y;
338 cvLine( imageCopy22, pt[0], pt[1], CV_RGB(255,255,0), 1, 8 );
339 cvLine( imageCopy22, pt[1], pt[2], CV_RGB(255,255,0), 1, 8 );
340 cvLine( imageCopy22, pt[2], pt[3], CV_RGB(255,255,0), 1, 8 );
341 cvLine( imageCopy22, pt[3], pt[0], CV_RGB(255,255,0), 1, 8 );
345 cvSaveImage(
mrpt::format(
"./DBG_dilation=%i_quads.png",(
int)dilations).c_str(), imageCopy22);
348 IplImage* imageCopy3 = cvCreateImage( cvGetSize(thresh_img.
getAs<IplImage>()), 8, 3 );
349 cvCopy( imageCopy22, imageCopy3);
352 int line_type = CV_AA;
353 CvScalar
color = {{0,0,255}};
354 for(
int kkk = 0; kkk < quad_count; kkk++ )
357 for(
int kkkk = 0; kkkk < 4; kkkk++ )
359 if( print_quad2->neighbors[kkkk] )
361 pt.x = (int)(print_quad2->corners[kkkk]->pt.x);
362 pt.y = (int)(print_quad2->corners[kkkk]->pt.y);
363 cvCircle( imageCopy3, pt, 3,
color, 1, line_type,
scale);
367 cvSaveImage(
mrpt::format(
"./DBG_allFoundNeighbors_%05i.png",cnt).c_str(), imageCopy3);
380 for( group_idx = 0; ; group_idx++ )
384 if( quad_group.empty() )
388 size_t count = quad_group.size();
394 if(
count > max_count)
400 max_dilation_run_ID = dilations;
416 IplImage* imageCopy11 = cvCreateImage( cvGetSize(thresh_img.
getAs<IplImage>()), 8, 3 );
417 cvCopy( imageCopy22, imageCopy11);
422 int min_column = -15;
424 for(
int i = min_row; i <= max_row; i++)
426 for(
int j = min_column; j <= max_column; j++)
428 for(
size_t k = 0; k <
count; k++)
430 for(
size_t l = 0; l < 4; l++)
432 if( ((quad_group[k])->corners[l]->
row == i) && ((quad_group[k])->corners[l]->
column == j) )
438 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.2, 0.2, 0, 1);
440 ptt.x = (int) quad_group[k]->corners[l]->pt.x;
441 ptt.y = (
int) quad_group[k]->corners[l]->pt.y;
444 if ((quad_group[k])->corners[l]->needsNeighbor ==
false)
446 cvPutText(imageCopy11, str, ptt, &font, CV_RGB(0,255,0));
450 cvPutText(imageCopy11, str, ptt, &font, CV_RGB(255,0,0));
459 cvSaveImage(
format(
"./DBG_CornersIncreasingOrder_%05i.png",cnt++).c_str(), imageCopy11);
471 output_quad_group = quad_group;
480 found =
myQuads2Points( output_quad_group, pattern_size,out_corners);
483 if (found != -1 && found != 1)
493 bool last_dilation =
false;
494 for(
int dilations = 0; !last_dilation; dilations++ )
500 cvCopy( thresh_img_save.
getAs<IplImage>(), thresh_img.
getAs<IplImage>());
503 last_dilation =
do_special_dilation(thresh_img, dilations,kernel_cross,kernel_rect,kernel_diag1,kernel_diag2, kernel_horz,kernel_vert);
505 cvRectangle( thresh_img.
getAs<IplImage>(), cvPoint(0,0),
507 CV_RGB(255,255,255), 3, 8);
512 IplImage* imageCopy23 = cvCreateImage( cvGetSize(thresh_img.
getAs<IplImage>()), 8, 3 );
513 cvCvtColor( thresh_img.
getAs<IplImage>(), imageCopy23, CV_GRAY2BGR );
516 for(
size_t kkk = 0; kkk < max_count; kkk++ )
518 const CvCBQuadPtr & print_quad2 = output_quad_group[kkk];
519 for(
size_t kkkk = 0; kkkk < 4; kkkk++ )
521 pt[kkkk].x = (int) print_quad2->corners[kkkk]->pt.x;
522 pt[kkkk].y = (
int) print_quad2->corners[kkkk]->pt.y;
525 cvFillConvexPoly ( imageCopy23, pt, 4, CV_RGB(255*0.1,255*0.25,255*0.6));
529 sprintf(str,
"Dilation Run No.: %i",dilations);
531 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 2);
535 cvSaveImage(
"./DBG_part2Start.png", imageCopy23);
540 quad_count =
icvGenerateQuads( quads, corners, thresh_img, flags, dilations,
false );
541 if( quad_count <= 0 )
548 for(
int kkk = 0; kkk < quad_count; kkk++ )
553 pt[0].x = (int)print_quad->corners[0]->pt.x;
554 pt[0].y = (
int)print_quad->corners[0]->pt.y;
555 pt[1].x = (int)print_quad->corners[1]->pt.x;
556 pt[1].y = (
int)print_quad->corners[1]->pt.y;
557 pt[2].x = (int)print_quad->corners[2]->pt.x;
558 pt[2].y = (
int)print_quad->corners[2]->pt.y;
559 pt[3].x = (int)print_quad->corners[3]->pt.x;
560 pt[3].y = (
int)print_quad->corners[3]->pt.y;
561 cvLine( imageCopy23, pt[0], pt[1], CV_RGB(255,0,0), 1, 8 );
562 cvLine( imageCopy23, pt[1], pt[2], CV_RGB(255,0,0), 1, 8 );
563 cvLine( imageCopy23, pt[2], pt[3], CV_RGB(255,0,0), 1, 8 );
564 cvLine( imageCopy23, pt[3], pt[0], CV_RGB(255,0,0), 1, 8 );
581 for(
size_t kkk = 0; kkk < max_count; kkk++ )
583 const CvCBQuadPtr & print_quad = output_quad_group[kkk];
586 pt[0].x = (int)print_quad->corners[0]->pt.x;
587 pt[0].y = (
int)print_quad->corners[0]->pt.y;
588 pt[1].x = (int)print_quad->corners[1]->pt.x;
589 pt[1].y = (
int)print_quad->corners[1]->pt.y;
590 pt[2].x = (int)print_quad->corners[2]->pt.x;
591 pt[2].y = (
int)print_quad->corners[2]->pt.y;
592 pt[3].x = (int)print_quad->corners[3]->pt.x;
593 pt[3].y = (
int)print_quad->corners[3]->pt.y;
611 cvSaveImage(
"./DBG_part2StartAndNewQuads.png", imageCopy23);
626 while ( feedBack == -1)
629 output_quad_group, max_dilation_run_ID );
637 for(
size_t kkk = max_count; kkk < max_count+1; kkk++ )
640 remember_quad = print_quad;
642 pt[0].x = (int)print_quad->corners[0]->pt.x;
643 pt[0].y = (
int)print_quad->corners[0]->pt.y;
644 pt[1].x = (int)print_quad->corners[1]->pt.x;
645 pt[1].y = (
int)print_quad->corners[1]->pt.y;
646 pt[2].x = (int)print_quad->corners[2]->pt.x;
647 pt[2].y = (
int)print_quad->corners[2]->pt.y;
648 pt[3].x = (int)print_quad->corners[3]->pt.x;
649 pt[3].y = (
int)print_quad->corners[3]->pt.y;
650 cvLine( imageCopy23, pt[0], pt[1], CV_RGB(255,0,0), 2, 8 );
651 cvLine( imageCopy23, pt[1], pt[2], CV_RGB(255,0,0), 2, 8 );
652 cvLine( imageCopy23, pt[2], pt[3], CV_RGB(255,0,0), 2, 8 );
653 cvLine( imageCopy23, pt[3], pt[0], CV_RGB(255,0,0), 2, 8 );
659 for(
size_t kkk = 0; kkk < max_count; kkk++ )
661 const CvCBQuadPtr &print_quad = output_quad_group[kkk];
663 for(
size_t kkkk = 0; kkkk < 4; kkkk++)
665 if(print_quad->neighbors[kkkk] == remember_quad)
668 pt[0].x = (int)print_quad->corners[0]->pt.x;
669 pt[0].y = (
int)print_quad->corners[0]->pt.y;
670 pt[1].x = (int)print_quad->corners[1]->pt.x;
671 pt[1].y = (
int)print_quad->corners[1]->pt.y;
672 pt[2].x = (int)print_quad->corners[2]->pt.x;
673 pt[2].y = (
int)print_quad->corners[2]->pt.y;
674 pt[3].x = (int)print_quad->corners[3]->pt.x;
675 pt[3].y = (
int)print_quad->corners[3]->pt.y;
676 cvLine( imageCopy23, pt[0], pt[1], CV_RGB(255,0,0), 2, 8 );
677 cvLine( imageCopy23, pt[1], pt[2], CV_RGB(255,0,0), 2, 8 );
678 cvLine( imageCopy23, pt[2], pt[3], CV_RGB(255,0,0), 2, 8 );
679 cvLine( imageCopy23, pt[3], pt[0], CV_RGB(255,0,0), 2, 8 );
684 cvSaveImage(
"./DBG_part2StartAndSelectedQuad.png", imageCopy23);
695 max_count = max_count + 1;
701 found =
myQuads2Points( output_quad_group, pattern_size,out_corners);
703 if (found == -1 || found == 1)
706 last_dilation =
true;
718 cvReleaseStructuringElement(&kernel_cross);
719 cvReleaseStructuringElement(&kernel_rect);
720 cvReleaseStructuringElement(&kernel_diag1);
721 cvReleaseStructuringElement(&kernel_diag2);
722 cvReleaseStructuringElement(&kernel_horz);
723 cvReleaseStructuringElement(&kernel_vert);
733 std::cerr <<
"While linking the corners a problem was encountered. No corner sequence is returned. " << endl;
749 double x2,
double y2 )
751 return std::abs( 0.5*(x0*(y1-y2)+x1*(y2-y0)+x2*(y0-y1)) );
754 double median(
const std::vector<double> &vec)
756 std::vector<double>
v = vec;
757 const size_t n =
v.size() / 2;
758 nth_element(
v.begin(),
v.begin()+
n,
v.end());
769 #if CV_MAJOR_VERSION==1
770 CvMemStorage* temp_storage = NULL;
772 cv::MemStorage temp_storage;
775 CvPoint2D32f center = cvPoint2D32f(0,0);
778 const size_t expected_quads_count = ((pattern_size.width + 1)*(pattern_size.height + 1) + 1)/2;
783 const size_t nQuads = quad_group.size();
784 if(nQuads <= expected_quads_count )
789 vector<CvPoint2D32f> centers( nQuads );
790 #if CV_MAJOR_VERSION==1
791 temp_storage = cvCreateMemStorage(0);
793 temp_storage = cv::MemStorage(cvCreateMemStorage(0));
798 std::vector<double> quad_areas(nQuads);
799 double min_area = DBL_MAX, max_area=-DBL_MAX, mean_area = 0.0;
801 for(
size_t i = 0; i < nQuads; i++ )
803 CvPoint2D32f ci = cvPoint2D32f(0,0);
806 for(
size_t j = 0; j < 4; j++ )
808 CvPoint2D32f pt =
q->corners[j]->pt;
819 q->corners[0]->pt.x,
q->corners[0]->pt.y,
820 q->corners[1]->pt.x,
q->corners[1]->pt.y,
821 q->corners[2]->pt.x,
q->corners[2]->pt.y )
824 q->corners[0]->pt.x,
q->corners[0]->pt.y,
825 q->corners[2]->pt.x,
q->corners[2]->pt.y,
826 q->corners[3]->pt.x,
q->corners[3]->pt.y );
831 if (
a<min_area) min_area=
a;
832 if (
a>max_area) max_area=
a;
843 const double median_area =
median(quad_areas);
846 for(
size_t i = 0; i < nQuads; i++ )
848 quad_group[i]->area_ratio = quad_group[i]->area / median_area;
863 while( quad_group.size() > expected_quads_count )
865 double min_box_area = DBL_MAX;
866 int min_box_area_index = -1;
869 int most_outlier_idx = -1;
870 double most_outlier_ratio = 1.0;
871 for(
size_t skip = 0; skip < quad_group.size(); skip++ )
873 double ar = quad_group[skip]->area_ratio;
874 if (ar>1.0) ar=1.0/ar;
876 if (ar<most_outlier_ratio)
878 most_outlier_ratio=ar;
879 most_outlier_idx = skip;
883 if (most_outlier_idx>=0)
885 min_box_area_index=most_outlier_idx;
888 if (min_box_area_index==-1)
891 for(
size_t skip = 0; skip < quad_group.size(); skip++ )
894 CvPoint2D32f temp = centers[skip];
895 centers[skip] = center;
896 CvMat pointMat = cvMat(1, quad_group.size(), CV_32FC2, ¢ers[0]);
897 CvSeq *hull = cvConvexHull2( &pointMat, temp_storage , CV_CLOCKWISE, 1 );
898 centers[skip] = temp;
899 double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
903 if( hull_area < min_box_area )
905 min_box_area = hull_area;
906 min_box_area_index = skip;
908 cvClearMemStorage( temp_storage );
916 for(
size_t i = 0; i < quad_group.size(); i++ )
920 for(
size_t j = 0; j < 4; j++ )
922 if(
q->neighbors[j] == q0 )
924 q->neighbors[j].reset();
926 for(
size_t k = 0; k < 4; k++ )
927 if( q0->neighbors[k] ==
q )
929 q0->neighbors[k].reset();
939 quad_group.erase( quad_group.begin() + min_box_area_index);
940 centers.erase(centers.begin() + min_box_area_index );
944 #if CV_MAJOR_VERSION==1
945 cvReleaseMemStorage(&temp_storage);
954 std::vector<CvCBQuadPtr> &quad,
955 std::vector<CvCBQuadPtr> &out_group,
963 const size_t quad_count = quad.size();
966 for(
size_t i = 0; i < quad_count; i++ )
968 if( quad[i]->
count < 0 || quad[i]->group_idx >= 0)
975 std::stack<CvCBQuadPtr> seqStack;
979 q->group_idx = group_idx;
980 out_group.push_back(
q );
982 while( !seqStack.empty() )
987 for(
size_t k = 0; k < 4; k++ )
993 if( neighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
995 neighbor->group_idx = group_idx;
996 seqStack.push(neighbor);
997 out_group.push_back( neighbor );
1011 void mrLabelQuadGroup( std::vector<CvCBQuadPtr> &quad_group,
const CvSize &pattern_size,
bool firstRun )
1013 const size_t count = quad_group.size();
1016 if (firstRun ==
true)
1021 int max_number = -1;
1022 for(
size_t i = 0; i <
count; i++ )
1025 if(
q->count > max_number)
1030 if (max_number == 4)
1042 q->corners[0]->row = 0;
1043 q->corners[0]->column = 0;
1044 q->corners[1]->row = 0;
1045 q->corners[1]->column = 1;
1046 q->corners[2]->row = 1;
1047 q->corners[2]->column = 1;
1048 q->corners[3]->row = 1;
1049 q->corners[3]->column = 0;
1053 bool flag_changed =
true;
1054 while( flag_changed ==
true )
1057 flag_changed =
false;
1062 for(
int i =
int(
count-1); i >= 0; i-- )
1065 if ( (quad_group[i])->labeled ==
false )
1069 for(
size_t j = 0; j < 4; j++ )
1073 if( (quad_group[i])->neighbors[j] )
1075 CvCBQuadPtr &quadNeighborJ = quad_group[i]->neighbors[j];
1079 if( quadNeighborJ->labeled ==
true)
1085 int connectedNeighborCornerId = -1;
1086 for(
int k = 0; k < 4; k++)
1088 if( quadNeighborJ->neighbors[k] == quad_group[i] )
1090 connectedNeighborCornerId = k;
1103 CvCBCornerPtr &conCorner = quadNeighborJ->corners[connectedNeighborCornerId];
1104 CvCBCornerPtr &conCornerCW1 = quadNeighborJ->corners[(connectedNeighborCornerId+1)%4];
1105 CvCBCornerPtr &conCornerCW2 = quadNeighborJ->corners[(connectedNeighborCornerId+2)%4];
1106 CvCBCornerPtr &conCornerCW3 = quadNeighborJ->corners[(connectedNeighborCornerId+3)%4];
1108 (quad_group[i])->corners[j]->
row = conCorner->row;
1109 (quad_group[i])->corners[j]->column = conCorner->column;
1110 (quad_group[i])->corners[(j+1)%4]->row = conCorner->row - conCornerCW2->row + conCornerCW3->row;
1111 (quad_group[i])->corners[(j+1)%4]->column = conCorner->column - conCornerCW2->column + conCornerCW3->column;
1112 (quad_group[i])->corners[(j+2)%4]->row = conCorner->row + conCorner->row - conCornerCW2->row;
1113 (quad_group[i])->corners[(j+2)%4]->column = conCorner->column + conCorner->column - conCornerCW2->column;
1114 (quad_group[i])->corners[(j+3)%4]->row = conCorner->row - conCornerCW2->row + conCornerCW1->row;
1115 (quad_group[i])->corners[(j+3)%4]->column = conCorner->column - conCornerCW2->column + conCornerCW1->column;
1119 (quad_group[i])->labeled =
true;
1123 flag_changed =
true;
1142 int min_column = 127;
1143 int max_column = -127;
1145 for(
size_t i = 0; i <
count; i++ )
1149 for(
size_t j = 0; j < 4; j++ )
1151 if( (
q->corners[j])->row > max_row)
1152 max_row = (
q->corners[j])->row;
1154 if( (
q->corners[j])->row < min_row)
1155 min_row = (
q->corners[j])->row;
1157 if( (
q->corners[j])->column > max_column)
1158 max_column = (
q->corners[j])->column;
1160 if( (
q->corners[j])->column < min_column)
1161 min_column = (
q->corners[j])->column;
1168 for(
int i = min_row; i <= max_row; i++)
1170 for(
int j = min_column; j <= max_column; j++)
1181 for(
size_t k = 0; k <
count; k++)
1183 for(
size_t l = 0; l < 4; l++)
1185 if( ((quad_group[k])->corners[l]->row == i) && ((quad_group[k])->corners[l]->column == j) )
1191 (quad_group[k])->corners[l]->needsNeighbor =
false;
1192 (quad_group[quadID])->corners[cornerID]->needsNeighbor =
false;
1198 (quad_group[k])->corners[l]->needsNeighbor =
true;
1217 for(
int i = min_row; i <= max_row; i++)
1219 for(
int j = min_column; j <= max_column; j++)
1233 for(
size_t k = 0; k <
count; k++)
1235 for(
size_t l = 0; l < 4; l++)
1237 if( ((quad_group[k])->corners[l]->row == i) && ((quad_group[k])->corners[l]->column == j) )
1247 else if (number == 2)
1252 float delta_x = (quad_group[k])->corners[l]->pt.x - (quad_group[quadID])->corners[cornerID]->pt.x;
1253 float delta_y = (quad_group[k])->corners[l]->pt.y - (quad_group[quadID])->corners[cornerID]->pt.y;
1255 if (delta_x != 0 || delta_y != 0)
1258 (quad_group[k])->corners[l]->pt.x = (quad_group[k])->corners[l]->pt.x - delta_x/2;
1259 (quad_group[quadID])->corners[cornerID]->pt.x = (quad_group[quadID])->corners[cornerID]->pt.x + delta_x/2;
1260 (quad_group[k])->corners[l]->pt.y = (quad_group[k])->corners[l]->pt.y - delta_y/2;
1261 (quad_group[quadID])->corners[cornerID]->pt.y = (quad_group[quadID])->corners[cornerID]->pt.y + delta_y/2;
1264 else if (number > 2)
1272 number = number + 1;
1286 int largerDimPattern = max(pattern_size.height,pattern_size.width);
1287 int smallerDimPattern =
min(pattern_size.height,pattern_size.width);
1288 bool flagSmallerDim1 =
false;
1289 bool flagSmallerDim2 =
false;
1291 if((largerDimPattern + 1) == max_column - min_column)
1293 flagSmallerDim1 =
true;
1297 for(
size_t k = 0; k <
count; k++ )
1299 for(
size_t l = 0; l < 4; l++ )
1301 if ( (quad_group[k])->corners[l]->
column == min_column || (quad_group[k])->corners[l]->
column == max_column)
1304 (quad_group[k])->corners[l]->needsNeighbor =
false;
1310 if((largerDimPattern + 1) == max_row - min_row)
1312 flagSmallerDim2 =
true;
1316 for(
size_t k = 0; k <
count; k++ )
1318 for(
size_t l = 0; l < 4; l++ )
1320 if ( (quad_group[k])->corners[l]->row == min_row || (quad_group[k])->corners[l]->
row == max_row)
1323 (quad_group[k])->corners[l]->needsNeighbor =
false;
1338 if( (flagSmallerDim1 ==
false && flagSmallerDim2 ==
true) )
1342 if((smallerDimPattern + 1) == max_column - min_column)
1344 for(
size_t k = 0; k <
count; k++ )
1346 for(
int l = 0; l < 4; l++ )
1348 if ( (quad_group[k])->corners[l]->column == min_column || (quad_group[k])->corners[l]->
column == max_column)
1351 (quad_group[k])->corners[l]->needsNeighbor =
false;
1358 if( (flagSmallerDim1 ==
true && flagSmallerDim2 ==
false) )
1362 if((smallerDimPattern + 1) == max_row - min_row)
1364 for(
size_t k = 0; k <
count; k++ )
1366 for(
size_t l = 0; l < 4; l++ )
1368 if ( (quad_group[k])->corners[l]->row == min_row || (quad_group[k])->corners[l]->
row == max_row)
1371 (quad_group[k])->corners[l]->needsNeighbor =
false;
1378 if( (flagSmallerDim1 ==
false && flagSmallerDim2 ==
false) && smallerDimPattern + 1 < max_column - min_column )
1382 if((smallerDimPattern + 1) == max_row - min_row)
1384 for(
size_t k = 0; k <
count; k++ )
1386 for(
size_t l = 0; l < 4; l++ )
1388 if ( (quad_group[k])->corners[l]->row == min_row || (quad_group[k])->corners[l]->
row == max_row)
1391 (quad_group[k])->corners[l]->needsNeighbor =
false;
1398 if( (flagSmallerDim1 ==
false && flagSmallerDim2 ==
false) && smallerDimPattern + 1 < max_row - min_row )
1402 if((smallerDimPattern + 1) == max_column - min_column)
1404 for(
size_t k = 0; k <
count; k++ )
1406 for(
size_t l = 0; l < 4; l++ )
1408 if ( (quad_group[k])->corners[l]->column == min_column || (quad_group[k])->corners[l]->
column == max_column)
1411 (quad_group[k])->corners[l]->needsNeighbor =
false;
1435 const float thresh_dilation = (float)(2*dilation+3)*(2*dilation+3)*2;
1439 const size_t quad_count = quads.size();
1442 for(
size_t idx = 0; idx < quad_count; idx++ )
1449 for(
size_t i = 0; i < 4; i++ )
1452 float min_dist = FLT_MAX;
1453 int closest_corner_idx = -1;
1456 if( cur_quad->neighbors[i] )
1459 pt = cur_quad->corners[i]->pt;
1463 for(
size_t k = 0; k < quad_count; k++ )
1468 for(
size_t j = 0; j < 4; j++ )
1471 if( quads[k]->neighbors[j] )
1474 dx = pt.x - quads[k]->corners[j]->pt.x;
1475 dy = pt.y - quads[k]->corners[j]->pt.y;
1476 dist = dx * dx + dy * dy;
1482 if( dist < min_dist &&
1483 dist <= (cur_quad->edge_len + thresh_dilation) &&
1484 dist <= (quads[k]->edge_len + thresh_dilation) )
1488 float x1 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+1)%4]->pt.x)/2;
1489 float y1 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+1)%4]->pt.y)/2;
1490 float x2 = (cur_quad->corners[(i+2)%4]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
1491 float y2 = (cur_quad->corners[(i+2)%4]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;
1493 float x3 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
1494 float y3 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;
1495 float x4 = (cur_quad->corners[(i+1)%4]->pt.x + cur_quad->corners[(i+2)%4]->pt.x)/2;
1496 float y4 = (cur_quad->corners[(i+1)%4]->pt.y + cur_quad->corners[(i+2)%4]->pt.y)/2;
1506 float c11 = cur_quad->corners[i]->pt.x - x2;
1507 float d11 = cur_quad->corners[i]->pt.y - y2;
1509 float c12 = quads[k]->corners[j]->pt.x - x2;
1510 float d12 = quads[k]->corners[j]->pt.y - y2;
1511 float sign11 =
a1*d11 - c11*
b1;
1512 float sign12 =
a1*d12 - c12*
b1;
1517 float c21 = cur_quad->corners[i]->pt.x - x4;
1518 float d21 = cur_quad->corners[i]->pt.y - y4;
1520 float c22 = quads[k]->corners[j]->pt.x - x4;
1521 float d22 = quads[k]->corners[j]->pt.y - y4;
1522 float sign21 =
a2*d21 - c21*
b2;
1523 float sign22 =
a2*d22 - c22*
b2;
1531 float c13 = quads[k]->corners[(j+2)%4]->pt.x - x2;
1532 float d13 = quads[k]->corners[(j+2)%4]->pt.y - y2;
1533 float c23 = quads[k]->corners[(j+2)%4]->pt.x - x4;
1534 float d23 = quads[k]->corners[(j+2)%4]->pt.y - y4;
1535 float sign13 =
a1*d13 - c13*
b1;
1536 float sign23 =
a2*d23 - c23*
b2;
1541 float u1 = (quads[k]->corners[j]->pt.x + quads[k]->corners[(j+1)%4]->pt.x)/2;
1542 float v1 = (quads[k]->corners[j]->pt.y + quads[k]->corners[(j+1)%4]->pt.y)/2;
1543 float u2 = (quads[k]->corners[(j+2)%4]->pt.x + quads[k]->corners[(j+3)%4]->pt.x)/2;
1544 float v2 = (quads[k]->corners[(j+2)%4]->pt.y + quads[k]->corners[(j+3)%4]->pt.y)/2;
1546 float u3 = (quads[k]->corners[j]->pt.x + quads[k]->corners[(j+3)%4]->pt.x)/2;
1547 float v3 = (quads[k]->corners[j]->pt.y + quads[k]->corners[(j+3)%4]->pt.y)/2;
1548 float u4 = (quads[k]->corners[(j+1)%4]->pt.x + quads[k]->corners[(j+2)%4]->pt.x)/2;
1549 float v4 = (quads[k]->corners[(j+1)%4]->pt.y + quads[k]->corners[(j+2)%4]->pt.y)/2;
1559 float c31 = cur_quad->corners[i]->pt.x -
u2;
1560 float d31 = cur_quad->corners[i]->pt.y -
v2;
1562 float c32 = quads[k]->corners[j]->pt.x -
u2;
1563 float d32 = quads[k]->corners[j]->pt.y -
v2;
1564 float sign31 =
a3*d31-c31*
b3;
1565 float sign32 =
a3*d32-c32*
b3;
1570 float c41 = cur_quad->corners[i]->pt.x - u4;
1571 float d41 = cur_quad->corners[i]->pt.y - v4;
1573 float c42 = quads[k]->corners[j]->pt.x - u4;
1574 float d42 = quads[k]->corners[j]->pt.y - v4;
1575 float sign41 = a4*d41-c41*b4;
1576 float sign42 = a4*d42-c42*b4;
1584 float c33 = cur_quad->corners[(i+2)%4]->pt.x -
u2;
1585 float d33 = cur_quad->corners[(i+2)%4]->pt.y -
v2;
1586 float c43 = cur_quad->corners[(i+2)%4]->pt.x - u4;
1587 float d43 = cur_quad->corners[(i+2)%4]->pt.y - v4;
1588 float sign33 =
a3*d33-c33*
b3;
1589 float sign43 = a4*d43-c43*b4;
1593 if ( ((sign11 < 0 && sign12 < 0) || (sign11 > 0 && sign12 > 0)) &&
1594 ((sign21 < 0 && sign22 < 0) || (sign21 > 0 && sign22 > 0)) &&
1595 ((sign31 < 0 && sign32 < 0) || (sign31 > 0 && sign32 > 0)) &&
1596 ((sign41 < 0 && sign42 < 0) || (sign41 > 0 && sign42 > 0)) &&
1597 ((sign11 < 0 && sign13 < 0) || (sign11 > 0 && sign13 > 0)) &&
1598 ((sign21 < 0 && sign23 < 0) || (sign21 > 0 && sign23 > 0)) &&
1599 ((sign31 < 0 && sign33 < 0) || (sign31 > 0 && sign33 > 0)) &&
1600 ((sign41 < 0 && sign43 < 0) || (sign41 > 0 && sign43 > 0)) )
1603 closest_corner_idx = j;
1604 closest_quad = quads[k];
1612 if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
1614 CvCBCornerPtr &closest_corner = closest_quad->corners[closest_corner_idx];
1620 for(
size_t j = 0; !skip && j < 4; j++ )
1621 skip = closest_quad->neighbors[j] == cur_quad;
1627 closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
1628 closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
1631 cur_quad->neighbors[i] = closest_quad;
1632 cur_quad->corners[i] = closest_corner;
1634 closest_quad->count++;
1635 closest_quad->neighbors[closest_corner_idx] = cur_quad;
1636 closest_quad->corners[closest_corner_idx] = closest_corner;
1653 std::vector<CvCBQuadPtr> &new_quads,
int new_dilation,
1654 std::vector<CvCBQuadPtr> &old_quads,
int old_dilation )
1661 const float thresh_dilation = (float)(2*new_dilation+3)*(2*old_dilation+3)*2;
1667 for(
size_t idx = 0; idx < old_quads.size(); idx++ )
1673 for(
int i = 0; i < 4; i++ )
1676 float min_dist = FLT_MAX;
1677 int closest_corner_idx = -1;
1683 if( cur_quad->corners[i]->needsNeighbor ==
false )
1686 pt = cur_quad->corners[i]->pt;
1690 for(
size_t k = 0; k < new_quads.size(); k++ )
1693 if( new_quads[k]->labeled ==
true)
1696 for(
int j = 0; j < 4; j++ )
1701 dx = pt.x - new_quads[k]->corners[j]->pt.x;
1702 dy = pt.y - new_quads[k]->corners[j]->pt.y;
1703 dist = dx * dx + dy * dy;
1705 if( (dist < min_dist) &&
1706 dist <= (cur_quad->edge_len + thresh_dilation) &&
1707 dist <= (new_quads[k]->edge_len + thresh_dilation) )
1712 float x1 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+1)%4]->pt.x)/2;
1713 float y1 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+1)%4]->pt.y)/2;
1714 float x2 = (cur_quad->corners[(i+2)%4]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
1715 float y2 = (cur_quad->corners[(i+2)%4]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;
1717 float x3 = (cur_quad->corners[i]->pt.x + cur_quad->corners[(i+3)%4]->pt.x)/2;
1718 float y3 = (cur_quad->corners[i]->pt.y + cur_quad->corners[(i+3)%4]->pt.y)/2;
1719 float x4 = (cur_quad->corners[(i+1)%4]->pt.x + cur_quad->corners[(i+2)%4]->pt.x)/2;
1720 float y4 = (cur_quad->corners[(i+1)%4]->pt.y + cur_quad->corners[(i+2)%4]->pt.y)/2;
1730 float c11 = cur_quad->corners[i]->pt.x - x2;
1731 float d11 = cur_quad->corners[i]->pt.y - y2;
1733 float c12 = new_quads[k]->corners[j]->pt.x - x2;
1734 float d12 = new_quads[k]->corners[j]->pt.y - y2;
1735 float sign11 =
a1*d11 - c11*
b1;
1736 float sign12 =
a1*d12 - c12*
b1;
1741 float c21 = cur_quad->corners[i]->pt.x - x4;
1742 float d21 = cur_quad->corners[i]->pt.y - y4;
1744 float c22 = new_quads[k]->corners[j]->pt.x - x4;
1745 float d22 = new_quads[k]->corners[j]->pt.y - y4;
1746 float sign21 =
a2*d21 - c21*
b2;
1747 float sign22 =
a2*d22 - c22*
b2;
1754 float c13 = new_quads[k]->corners[(j+2)%4]->pt.x - x2;
1755 float d13 = new_quads[k]->corners[(j+2)%4]->pt.y - y2;
1756 float c23 = new_quads[k]->corners[(j+2)%4]->pt.x - x4;
1757 float d23 = new_quads[k]->corners[(j+2)%4]->pt.y - y4;
1758 float sign13 =
a1*d13 - c13*
b1;
1759 float sign23 =
a2*d23 - c23*
b2;
1765 float u1 = (new_quads[k]->corners[j]->pt.x + new_quads[k]->corners[(j+1)%4]->pt.x)/2;
1766 float v1 = (new_quads[k]->corners[j]->pt.y + new_quads[k]->corners[(j+1)%4]->pt.y)/2;
1767 float u2 = (new_quads[k]->corners[(j+2)%4]->pt.x + new_quads[k]->corners[(j+3)%4]->pt.x)/2;
1768 float v2 = (new_quads[k]->corners[(j+2)%4]->pt.y + new_quads[k]->corners[(j+3)%4]->pt.y)/2;
1770 float u3 = (new_quads[k]->corners[j]->pt.x + new_quads[k]->corners[(j+3)%4]->pt.x)/2;
1771 float v3 = (new_quads[k]->corners[j]->pt.y + new_quads[k]->corners[(j+3)%4]->pt.y)/2;
1772 float u4 = (new_quads[k]->corners[(j+1)%4]->pt.x + new_quads[k]->corners[(j+2)%4]->pt.x)/2;
1773 float v4 = (new_quads[k]->corners[(j+1)%4]->pt.y + new_quads[k]->corners[(j+2)%4]->pt.y)/2;
1783 float c31 = cur_quad->corners[i]->pt.x -
u2;
1784 float d31 = cur_quad->corners[i]->pt.y -
v2;
1786 float c32 = new_quads[k]->corners[j]->pt.x -
u2;
1787 float d32 = new_quads[k]->corners[j]->pt.y -
v2;
1788 float sign31 =
a3*d31-c31*
b3;
1789 float sign32 =
a3*d32-c32*
b3;
1794 float c41 = cur_quad->corners[i]->pt.x - u4;
1795 float d41 = cur_quad->corners[i]->pt.y - v4;
1797 float c42 = new_quads[k]->corners[j]->pt.x - u4;
1798 float d42 = new_quads[k]->corners[j]->pt.y - v4;
1799 float sign41 = a4*d41-c41*b4;
1800 float sign42 = a4*d42-c42*b4;
1807 float c33 = cur_quad->corners[(i+2)%4]->pt.x -
u2;
1808 float d33 = cur_quad->corners[(i+2)%4]->pt.y -
v2;
1809 float c43 = cur_quad->corners[(i+2)%4]->pt.x - u4;
1810 float d43 = cur_quad->corners[(i+2)%4]->pt.y - v4;
1811 float sign33 =
a3*d33-c33*
b3;
1812 float sign43 = a4*d43-c43*b4;
1821 float x5 = cur_quad->corners[i]->pt.x;
1822 float y5 = cur_quad->corners[i]->pt.y;
1823 float x6 = cur_quad->corners[(i+1)%4]->pt.x;
1824 float y6 = cur_quad->corners[(i+1)%4]->pt.y;
1828 float x8 = cur_quad->corners[(i+3)%4]->pt.x;
1829 float y8 = cur_quad->corners[(i+3)%4]->pt.y;
1839 float c51 = cur_quad->corners[(i+2)%4]->pt.x - x5;
1840 float d51 = cur_quad->corners[(i+2)%4]->pt.y - y5;
1842 float c52 = new_quads[k]->corners[j]->pt.x - x5;
1843 float d52 = new_quads[k]->corners[j]->pt.y - y5;
1844 float sign51 = a5*d51 - c51*b5;
1845 float sign52 = a5*d52 - c52*b5;
1850 float c61 = cur_quad->corners[(i+2)%4]->pt.x - x7;
1851 float d61 = cur_quad->corners[(i+2)%4]->pt.y - y7;
1853 float c62 = new_quads[k]->corners[j]->pt.x - x7;
1854 float d62 = new_quads[k]->corners[j]->pt.y - y7;
1855 float sign61 = a6*d61 - c61*b6;
1856 float sign62 = a6*d62 - c62*b6;
1862 float u5 = new_quads[k]->corners[j]->pt.x;
1863 float v5 = new_quads[k]->corners[j]->pt.y;
1864 float u6 = new_quads[k]->corners[(j+1)%4]->pt.x;
1865 float v6 = new_quads[k]->corners[(j+1)%4]->pt.y;
1869 float u8 = new_quads[k]->corners[(j+3)%4]->pt.x;
1870 float v8 = new_quads[k]->corners[(j+3)%4]->pt.y;
1880 float c71 = cur_quad->corners[i]->pt.x - u5;
1881 float d71 = cur_quad->corners[i]->pt.y - v5;
1883 float c72 = new_quads[k]->corners[(j+2)%4]->pt.x - u5;
1884 float d72 = new_quads[k]->corners[(j+2)%4]->pt.y - v5;
1885 float sign71 = a7*d71-c71*b7;
1886 float sign72 = a7*d72-c72*b7;
1891 float c81 = cur_quad->corners[i]->pt.x - u7;
1892 float d81 = cur_quad->corners[i]->pt.y - v7;
1894 float c82 = new_quads[k]->corners[(j+2)%4]->pt.x - u7;
1895 float d82 = new_quads[k]->corners[(j+2)%4]->pt.y - v7;
1896 float sign81 = a8*d81-c81*b8;
1897 float sign82 = a8*d82-c82*b8;
1904 if ( ((sign11 < 0 && sign12 < 0) || (sign11 > 0 && sign12 > 0)) &&
1905 ((sign21 < 0 && sign22 < 0) || (sign21 > 0 && sign22 > 0)) &&
1906 ((sign31 < 0 && sign32 < 0) || (sign31 > 0 && sign32 > 0)) &&
1907 ((sign41 < 0 && sign42 < 0) || (sign41 > 0 && sign42 > 0)) &&
1908 ((sign11 < 0 && sign13 < 0) || (sign11 > 0 && sign13 > 0)) &&
1909 ((sign21 < 0 && sign23 < 0) || (sign21 > 0 && sign23 > 0)) &&
1910 ((sign31 < 0 && sign33 < 0) || (sign31 > 0 && sign33 > 0)) &&
1911 ((sign41 < 0 && sign43 < 0) || (sign41 > 0 && sign43 > 0)) &&
1912 ((sign51 < 0 && sign52 > 0) || (sign51 > 0 && sign52 < 0)) &&
1913 ((sign61 < 0 && sign62 > 0) || (sign61 > 0 && sign62 < 0)) &&
1914 ((sign71 < 0 && sign72 > 0) || (sign71 > 0 && sign72 < 0)) &&
1915 ((sign81 < 0 && sign82 > 0) || (sign81 > 0 && sign82 < 0)) )
1917 closest_corner_idx = j;
1918 closest_quad = new_quads[k];
1926 if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
1928 CvCBCornerPtr &closest_corner = closest_quad->corners[closest_corner_idx];
1929 closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
1930 closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
1936 cur_quad->corners[i]->pt.x = closest_corner->pt.x;
1937 cur_quad->corners[i]->pt.y = closest_corner->pt.y;
1938 cur_quad->neighbors[i] = closest_quad;
1939 closest_quad->corners[closest_corner_idx]->pt.x = closest_corner->pt.x;
1940 closest_quad->corners[closest_corner_idx]->pt.y = closest_corner->pt.y;
1945 closest_quad->labeled =
true;
1952 newQuad->edge_len = closest_quad->edge_len;
1953 newQuad->group_idx = cur_quad->group_idx;
1954 newQuad->labeled =
false;
1958 newQuad->neighbors[closest_corner_idx] = cur_quad;
1959 newQuad->neighbors[(closest_corner_idx+1)%4].
reset();
1960 newQuad->neighbors[(closest_corner_idx+2)%4].
reset();
1961 newQuad->neighbors[(closest_corner_idx+3)%4].
reset();
1963 for (
int j = 0; j < 4; j++)
1966 newQuad->corners[j]->pt.x = closest_quad->corners[j]->pt.x;
1967 newQuad->corners[j]->pt.y = closest_quad->corners[j]->pt.y;
1970 old_quads.push_back(newQuad);
1971 cur_quad->neighbors[i] = newQuad;
1997 #if CV_MAJOR_VERSION==1
1998 CvMemStorage* temp_storage = cvCreateMemStorage(0);
2000 cv::MemStorage temp_storage = cv::MemStorage(cvCreateMemStorage(0));
2003 CvSeq *src_contour = 0;
2006 CvContourScanner scanner;
2010 const int min_size = cvRound(
image.getWidth() *
image.getHeight() * .03 * 0.01 * 0.92 * 0.1);
2013 root = cvCreateSeq( 0,
sizeof(CvSeq),
sizeof(CvSeq*), temp_storage );
2016 scanner = cvStartFindContours(
const_cast<IplImage*
>(
image.getAs<IplImage>()), temp_storage,
sizeof(
CvContourEx), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
2019 while( (src_contour = cvFindNextContour( scanner )) != 0 )
2021 CvSeq *dst_contour = 0;
2022 CvRect rect = ((CvContour*)src_contour)->rect;
2031 if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
2033 int min_approx_level = 2, max_approx_level;
2034 if (firstRun ==
true)
2035 max_approx_level = 3;
2039 for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
2041 dst_contour = cvApproxPoly( src_contour,
sizeof(CvContour), temp_storage,
2042 CV_POLY_APPROX_DP, (
float)approx_level );
2047 dst_contour = cvApproxPoly( dst_contour,
sizeof(CvContour), temp_storage,
2048 CV_POLY_APPROX_DP, (
float)approx_level );
2050 if( dst_contour->total == 4 )
2056 if(dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
2063 for(
int i = 0; i < 4; i++ )
2064 pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
2091 dst_contour->v_prev = (CvSeq*)parent;
2092 cvSeqPush( root, &dst_contour );
2100 cvEndFindContours( &scanner );
2105 for (
int q=0;
q<root->total;
q++)
2108 out_corners.clear();
2109 for (
int q=0;
q< 4 * root->total;
q++)
2113 for(
int idx = 0; idx < root->total; idx++ )
2116 src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
2117 if( (flags & cv::CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
2123 assert( src_contour->total == 4 );
2124 for(
int i = 0; i < 4; i++ )
2126 CvPoint2D32f pt = cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
2131 q->corners[i] = corner;
2133 q->edge_len = FLT_MAX;
2134 for(
int i = 0; i < 4; i++ )
2136 float dx =
q->corners[i]->pt.x -
q->corners[(i+1)&3]->pt.x;
2137 float dy =
q->corners[i]->pt.y -
q->corners[(i+1)&3]->pt.y;
2138 float d = dx*dx + dy*dy;
2139 if(
q->edge_len > d )
2146 if( cvGetErrStatus() < 0 )
2150 out_corners.clear();
2156 #if CV_MAJOR_VERSION==1
2157 cvReleaseMemStorage(&temp_storage);
2165 int myQuads2Points(
const std::vector<CvCBQuadPtr> &output_quads,
const CvSize &pattern_size, std::vector<CvPoint2D32f> &out_corners)
2168 out_corners.clear();
2170 bool flagRow =
false;
2171 bool flagColumn =
false;
2172 int maxPattern_sizeRow = -1;
2173 int maxPattern_sizeColumn = -1;
2179 int min_column = 127;
2180 int max_column = -127;
2182 for(
size_t i = 0; i < output_quads.size(); i++ )
2186 for(
int j = 0; j < 4; j++ )
2188 if( (
q->corners[j])->row > max_row)
2189 max_row = (
q->corners[j])->
row;
2190 if( (
q->corners[j])->row < min_row)
2191 min_row = (
q->corners[j])->row;
2192 if( (
q->corners[j])->column > max_column)
2193 max_column = (
q->corners[j])->column;
2194 if( (
q->corners[j])->column < min_column)
2195 min_column = (
q->corners[j])->column;
2203 for(
size_t i = 0; i < output_quads.size(); i++ )
2207 for(
int j = 0; j < 4; j++ )
2209 if( (
q->corners[j])->column == max_column && (
q->corners[j])->
row != min_row && (
q->corners[j])->row != max_row )
2211 if( (
q->corners[j]->needsNeighbor) ==
false)
2218 if( (
q->corners[j])->row == max_row && (
q->corners[j])->
column != min_column && (
q->corners[j])->column != max_column )
2220 if( (
q->corners[j]->needsNeighbor) ==
false)
2230 if( flagColumn ==
true)
2232 if( max_column - min_column == pattern_size.width + 1)
2234 maxPattern_sizeColumn = pattern_size.width;
2235 maxPattern_sizeRow = pattern_size.height;
2239 maxPattern_sizeColumn = pattern_size.height;
2240 maxPattern_sizeRow = pattern_size.width;
2243 else if( flagRow ==
true)
2245 if( max_row - min_row == pattern_size.width + 1)
2247 maxPattern_sizeRow = pattern_size.width;
2248 maxPattern_sizeColumn = pattern_size.height;
2252 maxPattern_sizeRow = pattern_size.height;
2253 maxPattern_sizeColumn = pattern_size.width;
2261 maxPattern_sizeColumn = max(pattern_size.width, pattern_size.height);
2262 maxPattern_sizeRow = max(pattern_size.width, pattern_size.height);
2266 if (maxPattern_sizeRow * maxPattern_sizeColumn != pattern_size.width * pattern_size.height )
2269 bool do_swap_col_row = maxPattern_sizeRow != pattern_size.height;
2271 if (do_swap_col_row)
2273 std::swap(min_row,min_column);
2274 std::swap(maxPattern_sizeRow, maxPattern_sizeColumn);
2279 for(
int i = min_row + 1; i < maxPattern_sizeRow + min_row + 1; i++)
2281 for(
int j = min_column + 1; j < maxPattern_sizeColumn + min_column + 1; j++)
2286 for(
size_t k = 0; k < output_quads.size(); k++ )
2288 for(
int l = 0; l < 4; l++)
2290 int r = output_quads[k]->corners[l]->row;
2291 int c = output_quads[k]->corners[l]->column;
2292 if (do_swap_col_row)
2295 if(
r == i &&
c == j)
2302 out_corners.push_back( output_quads[k]->corners[l]->pt );
2318 if (iter == 1 || iter == 2)
2329 return (out_corners.size() ==
size_t( pattern_size.width * pattern_size.height) ) ? 1:0;
2335 std::map<CvCBQuad*,size_t> pointer2index;
2336 for (
size_t i=0;i<quads.size();i++)
2337 pointer2index[quads[i].get()] = i;
2339 vector<CArray<size_t,4> > neig_indices(quads.size());
2340 for (
size_t i=0;i<quads.size();i++)
2341 for (
size_t j=0;j<4;j++)
2342 neig_indices[i][j] = pointer2index[ quads[i]->neighbors[j].get() ];
2344 std::vector<CvCBQuadPtr> new_quads = quads;
2347 new_quads.begin(), new_quads.end(),
2348 [](
CvCBQuadPtr&
p) { p = std::make_shared<CvCBQuad>(*p); }
2350 for (
size_t i=0;i<new_quads.size();i++)
2351 for (
size_t j=0;j<4;j++)
2352 new_quads[i]->neighbors[j] = new_quads[ neig_indices[i][j] ];
#define MAX_CONTOUR_APPROX
double median(const std::vector< double > &vec)
void mrFindQuadNeighbors2(std::vector< CvCBQuadPtr > &quads, int dilation)
int myQuads2Points(const std::vector< CvCBQuadPtr > &output_quads, const CvSize &pattern_size, std::vector< CvPoint2D32f > &out_corners)
double triangleArea(double x0, double y0, double x1, double y1, double x2, double y2)
int mrAugmentBestRun(std::vector< CvCBQuadPtr > &new_quads, int new_dilation, std::vector< CvCBQuadPtr > &old_quads, int old_dilation)
void quadListMakeUnique(std::vector< CvCBQuadPtr > &quads)
int icvGenerateQuads(vector< CvCBQuadPtr > &out_quads, vector< CvCBCornerPtr > &out_corners, const mrpt::utils::CImage &image, int flags, int dilation, bool firstRun)
bool do_special_dilation(mrpt::utils::CImage &thresh_img, const int dilations, IplConvKernel *kernel_cross, IplConvKernel *kernel_rect, IplConvKernel *kernel_diag1, IplConvKernel *kernel_diag2, IplConvKernel *kernel_horz, IplConvKernel *kernel_vert)
int cvFindChessboardCorners3(const mrpt::utils::CImage &img_, CvSize pattern_size, std::vector< CvPoint2D32f > &out_corners)
void icvCleanFoundConnectedQuads(std::vector< CvCBQuadPtr > &quad_group, const CvSize &pattern_size)
void icvFindConnectedQuads(std::vector< CvCBQuadPtr > &quad, std::vector< CvCBQuadPtr > &out_group, const int group_idx, const int dilation)
void mrLabelQuadGroup(std::vector< CvCBQuadPtr > &quad_group, const CvSize &pattern_size, bool firstRun)
std::shared_ptr< CvCBQuad > CvCBQuadPtr
std::shared_ptr< CvCBCorner > CvCBCornerPtr
A class for storing images as grayscale or RGB bitmaps.
size_t getHeight() const MRPT_OVERRIDE
Returns the height of the image in pixels.
const T * getAs() const
Returns a pointer to a const T* containing the image - the idea is to call like "img....
size_t getWidth() const MRPT_OVERRIDE
Returns the width of the image in pixels.
bool saveToFile(const std::string &fileName, int jpeg_quality=95) const
Save the image to a file, whose format is determined from the extension (internally uses OpenCV).
GLenum GLenum GLvoid * row
GLenum GLenum GLenum GLenum GLenum scale
GLenum GLenum GLvoid GLvoid * column
GLenum GLsizei GLenum GLenum const GLvoid * image
GLuint GLuint GLsizei count
GLfloat GLfloat GLfloat v2
GLdouble GLdouble GLdouble r
GLubyte GLubyte GLubyte a
GLfloat GLfloat GLfloat GLfloat v3
GLdouble GLdouble GLdouble GLdouble q
int BASE_IMPEXP sprintf(char *buf, size_t bufSize, const char *format,...) MRPT_NO_THROWS MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
This base provides a set of functions for maths stuff.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
@ FAST_REF_OR_CONVERT_TO_GRAY
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.