78 #define MAX_CONTOUR_APPROX 7 83 CImage& thresh_img,
const int dilations, IplConvKernel* kernel_cross,
84 IplConvKernel* kernel_rect, IplConvKernel* kernel_diag1,
85 IplConvKernel* kernel_diag2, IplConvKernel* kernel_horz,
86 IplConvKernel* kernel_vert)
95 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_cross, 1);
97 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_rect, 1);
99 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_cross, 1);
101 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_rect, 1);
103 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_cross, 1);
105 cvDilate( thresh_img.
getAs<IplImage>(), thresh_img.
getAs<IplImage>(), kernel_rect, 1);
109 IplImage* ipl = thresh_img.
getAs<IplImage>();
116 cvDilate(ipl, ipl, kernel_cross, 1);
120 cvErode(ipl, ipl, kernel_rect, 1);
123 cvDilate(ipl, ipl, kernel_vert, 1);
126 cvDilate(ipl, ipl, kernel_vert, 1);
129 cvDilate(ipl, ipl, kernel_vert, 1);
132 cvDilate(ipl, ipl, kernel_vert, 1);
135 cvDilate(ipl, ipl, kernel_vert, 1);
139 cvDilate(ipl, ipl, kernel_cross, 1);
142 cvErode(ipl, ipl, kernel_rect, 1);
145 cvDilate(ipl, ipl, kernel_horz, 1);
148 cvDilate(ipl, ipl, kernel_horz, 1);
151 cvDilate(ipl, ipl, kernel_horz, 1);
154 cvDilate(ipl, ipl, kernel_horz, 1);
157 cvDilate(ipl, ipl, kernel_horz, 1);
161 cvDilate(ipl, ipl, kernel_diag2, 1);
164 cvDilate(ipl, ipl, kernel_diag1, 1);
167 cvDilate(ipl, ipl, kernel_diag2, 1);
170 cvDilate(ipl, ipl, kernel_diag1, 1);
173 cvDilate(ipl, ipl, kernel_diag2, 1);
176 cvDilate(ipl, ipl, kernel_diag1, 1);
180 cvDilate(ipl, ipl, kernel_diag2, 1);
183 cvDilate(ipl, ipl, kernel_diag2, 1);
186 cvDilate(ipl, ipl, kernel_diag2, 1);
189 cvDilate(ipl, ipl, kernel_diag2, 1);
193 cvDilate(ipl, ipl, kernel_diag1, 1);
196 cvDilate(ipl, ipl, kernel_diag1, 1);
199 cvDilate(ipl, ipl, kernel_diag1, 1);
202 cvDilate(ipl, ipl, kernel_diag1, 1);
206 cvDilate(ipl, ipl, kernel_cross, 1);
209 cvErode(ipl, ipl, kernel_rect, 1);
212 cvDilate(ipl, ipl, kernel_cross, 1);
215 cvDilate(ipl, ipl, kernel_diag2, 1);
219 cvDilate(ipl, ipl, kernel_diag1, 1);
222 cvDilate(ipl, ipl, kernel_rect, 1);
225 cvErode(ipl, ipl, kernel_cross, 1);
228 cvDilate(ipl, ipl, kernel_rect, 1);
231 cvDilate(ipl, ipl, kernel_cross, 1);
247 const CImage& img_, CvSize pattern_size,
248 std::vector<CvPoint2D32f>& out_corners)
254 size_t max_count = 0;
255 int max_dilation_run_ID = -1;
260 vector<CvCBQuad::Ptr> quads;
261 vector<CvCBQuad::Ptr> quad_group;
262 vector<CvCBCorner::Ptr> corners;
263 vector<CvCBQuad::Ptr>
270 int quad_count, group_idx;
272 if (pattern_size.width < 2 || pattern_size.height < 2)
274 std::cerr <<
"Pattern should have at least 2x2 size" << endl;
277 if (pattern_size.width > 127 || pattern_size.height > 127)
279 std::cerr <<
"Pattern should not have a size larger than 127 x 127" 288 img.getWidth(),
img.getHeight(),
291 img.getWidth(),
img.getHeight(),
295 IplConvKernel* kernel_cross =
296 cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_CROSS,
nullptr);
297 IplConvKernel* kernel_rect =
298 cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT,
nullptr);
300 static int kernel_diag1_vals[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
301 IplConvKernel* kernel_diag1 = cvCreateStructuringElementEx(
302 3, 3, 1, 1, CV_SHAPE_CUSTOM, kernel_diag1_vals);
303 static int kernel_diag2_vals[9] = {0, 0, 1, 0, 1, 0, 1, 0, 0};
304 IplConvKernel* kernel_diag2 = cvCreateStructuringElementEx(
305 3, 3, 1, 1, CV_SHAPE_CUSTOM, kernel_diag2_vals);
306 static int kernel_horz_vals[9] = {0, 0, 0, 1, 1, 1, 0, 0, 0};
307 IplConvKernel* kernel_horz = cvCreateStructuringElementEx(
308 3, 3, 1, 1, CV_SHAPE_CUSTOM, kernel_horz_vals);
309 static int kernel_vert_vals[9] = {0, 1, 0, 0, 1, 0, 0, 1, 0};
310 IplConvKernel* kernel_vert = cvCreateStructuringElementEx(
311 3, 3, 1, 1, CV_SHAPE_CUSTOM, kernel_vert_vals);
317 block_size = cvRound(MIN(
img.getWidth(),
img.getHeight()) * 0.2) | 1;
320 img.getAs<IplImage>(), thresh_img.getAs<IplImage>(), 255,
321 CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, block_size, 0);
323 cvCopy(thresh_img.getAs<IplImage>(), thresh_img_save.getAs<IplImage>());
328 img.saveToFile(
"./DBG_OrigImg.png");
341 bool last_dilation =
false;
343 for (
int dilations = 0; !last_dilation; dilations++)
347 cvCopy(thresh_img_save.getAs<IplImage>(), thresh_img.getAs<IplImage>());
351 thresh_img, dilations, kernel_cross, kernel_rect, kernel_diag1,
352 kernel_diag2, kernel_horz, kernel_vert);
355 thresh_img.saveToFile(
364 thresh_img.getAs<IplImage>(), cvPoint(0, 0),
365 cvPoint(thresh_img.getWidth() - 1, thresh_img.getHeight() - 1),
366 CV_RGB(255, 255, 255), 3, 8);
371 quads, corners, thresh_img, flags, dilations,
true);
372 if (quad_count <= 0)
continue;
381 IplImage* imageCopy22 =
382 cvCreateImage(cvGetSize(thresh_img.getAs<IplImage>()), 8, 3);
385 IplImage* imageCopy2 =
386 cvCreateImage(cvGetSize(thresh_img.getAs<IplImage>()), 8, 1);
387 cvCopy(thresh_img.getAs<IplImage>(), imageCopy2);
388 cvCvtColor(imageCopy2, imageCopy22, CV_GRAY2BGR);
390 for (
int kkk = 0; kkk < quad_count; kkk++)
394 pt[0].x = (int)print_quad->corners[0]->pt.x;
395 pt[0].y = (
int)print_quad->corners[0]->pt.y;
396 pt[1].x = (int)print_quad->corners[1]->pt.x;
397 pt[1].y = (
int)print_quad->corners[1]->pt.y;
398 pt[2].x = (int)print_quad->corners[2]->pt.x;
399 pt[2].y = (
int)print_quad->corners[2]->pt.y;
400 pt[3].x = (int)print_quad->corners[3]->pt.x;
401 pt[3].y = (
int)print_quad->corners[3]->pt.y;
402 cvLine(imageCopy22, pt[0], pt[1], CV_RGB(255, 255, 0), 1, 8);
403 cvLine(imageCopy22, pt[1], pt[2], CV_RGB(255, 255, 0), 1, 8);
404 cvLine(imageCopy22, pt[2], pt[3], CV_RGB(255, 255, 0), 1, 8);
405 cvLine(imageCopy22, pt[3], pt[0], CV_RGB(255, 255, 0), 1, 8);
410 mrpt::format(
"./DBG_dilation=%i_quads.png", (
int)dilations)
415 IplImage* imageCopy3 =
416 cvCreateImage(cvGetSize(thresh_img.getAs<IplImage>()), 8, 3);
417 cvCopy(imageCopy22, imageCopy3);
420 int line_type = CV_AA;
421 CvScalar
color = {{0, 0, 255}};
422 for (
int kkk = 0; kkk < quad_count; kkk++)
425 for (
int kkkk = 0; kkkk < 4; kkkk++)
427 if (print_quad2->neighbors[kkkk])
429 pt.x = (int)(print_quad2->corners[kkkk]->pt.x);
430 pt.y = (int)(print_quad2->corners[kkkk]->pt.y);
431 cvCircle(imageCopy3, pt, 3,
color, 1, line_type,
scale);
436 mrpt::format(
"./DBG_allFoundNeighbors_%05i.png", cnt).c_str(),
450 for (group_idx = 0;; group_idx++)
454 if (quad_group.empty())
break;
457 size_t count = quad_group.size();
463 if (
count > max_count)
470 max_dilation_run_ID = dilations;
485 IplImage* imageCopy11 = cvCreateImage(
486 cvGetSize(thresh_img.getAs<IplImage>()), 8, 3);
487 cvCopy(imageCopy22, imageCopy11);
492 int min_column = -15;
494 for (
int i = min_row; i <= max_row; i++)
496 for (
int j = min_column; j <= max_column; j++)
498 for (
size_t k = 0; k <
count; k++)
500 for (
size_t l = 0; l < 4; l++)
502 if (((quad_group[k])->corners[l]->
row == i) &&
503 ((quad_group[k])->corners[l]->
column == j))
510 &font, CV_FONT_HERSHEY_SIMPLEX, 0.2,
514 (int)quad_group[k]->corners[l]->pt.x;
516 (
int)quad_group[k]->corners[l]->pt.y;
522 ->needsNeighbor ==
false)
525 imageCopy11, str, ptt, &font,
531 imageCopy11, str, ptt, &font,
543 format(
"./DBG_CornersIncreasingOrder_%05i.png", cnt++)
560 output_quad_group = quad_group;
572 found =
myQuads2Points(output_quad_group, pattern_size, out_corners);
576 if (found != -1 && found != 1)
588 bool last_dilation =
false;
589 for (
int dilations = 0; !last_dilation; dilations++)
597 thresh_img_save.getAs<IplImage>(),
598 thresh_img.getAs<IplImage>());
602 thresh_img, dilations, kernel_cross, kernel_rect, kernel_diag1,
603 kernel_diag2, kernel_horz, kernel_vert);
606 thresh_img.getAs<IplImage>(), cvPoint(0, 0),
607 cvPoint(thresh_img.getWidth() - 1, thresh_img.getHeight() - 1),
608 CV_RGB(255, 255, 255), 3, 8);
613 IplImage* imageCopy23 =
614 cvCreateImage(cvGetSize(thresh_img.getAs<IplImage>()), 8, 3);
615 cvCvtColor(thresh_img.getAs<IplImage>(), imageCopy23, CV_GRAY2BGR);
618 for (
size_t kkk = 0; kkk < max_count; kkk++)
621 for (
size_t kkkk = 0; kkkk < 4; kkkk++)
623 pt[kkkk].x = (int)print_quad2->corners[kkkk]->pt.x;
624 pt[kkkk].y = (
int)print_quad2->corners[kkkk]->pt.y;
629 CV_RGB(255 * 0.1, 255 * 0.25, 255 * 0.6));
633 sprintf(str,
"Dilation Run No.: %i", dilations);
635 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 2);
640 cvSaveImage(
"./DBG_part2Start.png", imageCopy23);
646 quads, corners, thresh_img, flags, dilations,
false);
647 if (quad_count <= 0)
continue;
652 for (
int kkk = 0; kkk < quad_count; kkk++)
657 pt[0].x = (int)print_quad->corners[0]->pt.x;
658 pt[0].y = (
int)print_quad->corners[0]->pt.y;
659 pt[1].x = (int)print_quad->corners[1]->pt.x;
660 pt[1].y = (
int)print_quad->corners[1]->pt.y;
661 pt[2].x = (int)print_quad->corners[2]->pt.x;
662 pt[2].y = (
int)print_quad->corners[2]->pt.y;
663 pt[3].x = (int)print_quad->corners[3]->pt.x;
664 pt[3].y = (
int)print_quad->corners[3]->pt.y;
665 cvLine(imageCopy23, pt[0], pt[1], CV_RGB(255, 0, 0), 1, 8);
666 cvLine(imageCopy23, pt[1], pt[2], CV_RGB(255, 0, 0), 1, 8);
667 cvLine(imageCopy23, pt[2], pt[3], CV_RGB(255, 0, 0), 1, 8);
668 cvLine(imageCopy23, pt[3], pt[0], CV_RGB(255, 0, 0), 1, 8);
686 for (
size_t kkk = 0; kkk < max_count; kkk++)
691 pt[0].x = (int)print_quad->corners[0]->pt.x;
692 pt[0].y = (
int)print_quad->corners[0]->pt.y;
693 pt[1].x = (int)print_quad->corners[1]->pt.x;
694 pt[1].y = (
int)print_quad->corners[1]->pt.y;
695 pt[2].x = (int)print_quad->corners[2]->pt.x;
696 pt[2].y = (
int)print_quad->corners[2]->pt.y;
697 pt[3].x = (int)print_quad->corners[3]->pt.x;
698 pt[3].y = (
int)print_quad->corners[3]->pt.y;
717 cvSaveImage(
"./DBG_part2StartAndNewQuads.png", imageCopy23);
733 while (feedBack == -1)
736 quads, dilations, output_quad_group, max_dilation_run_ID);
743 for (
size_t kkk = max_count; kkk < max_count + 1; kkk++)
746 remember_quad = print_quad;
748 pt[0].x = (int)print_quad->corners[0]->pt.x;
749 pt[0].y = (
int)print_quad->corners[0]->pt.y;
750 pt[1].x = (int)print_quad->corners[1]->pt.x;
751 pt[1].y = (
int)print_quad->corners[1]->pt.y;
752 pt[2].x = (int)print_quad->corners[2]->pt.x;
753 pt[2].y = (
int)print_quad->corners[2]->pt.y;
754 pt[3].x = (int)print_quad->corners[3]->pt.x;
755 pt[3].y = (
int)print_quad->corners[3]->pt.y;
757 imageCopy23, pt[0], pt[1], CV_RGB(255, 0, 0), 2, 8);
759 imageCopy23, pt[1], pt[2], CV_RGB(255, 0, 0), 2, 8);
761 imageCopy23, pt[2], pt[3], CV_RGB(255, 0, 0), 2, 8);
763 imageCopy23, pt[3], pt[0], CV_RGB(255, 0, 0), 2, 8);
769 for (
size_t kkk = 0; kkk < max_count; kkk++)
772 output_quad_group[kkk];
774 for (
size_t kkkk = 0; kkkk < 4; kkkk++)
776 if (print_quad->neighbors[kkkk] == remember_quad)
779 pt[0].x = (int)print_quad->corners[0]->pt.x;
780 pt[0].y = (
int)print_quad->corners[0]->pt.y;
781 pt[1].x = (int)print_quad->corners[1]->pt.x;
782 pt[1].y = (
int)print_quad->corners[1]->pt.y;
783 pt[2].x = (int)print_quad->corners[2]->pt.x;
784 pt[2].y = (
int)print_quad->corners[2]->pt.y;
785 pt[3].x = (int)print_quad->corners[3]->pt.x;
786 pt[3].y = (
int)print_quad->corners[3]->pt.y;
788 imageCopy23, pt[0], pt[1],
789 CV_RGB(255, 0, 0), 2, 8);
791 imageCopy23, pt[1], pt[2],
792 CV_RGB(255, 0, 0), 2, 8);
794 imageCopy23, pt[2], pt[3],
795 CV_RGB(255, 0, 0), 2, 8);
797 imageCopy23, pt[3], pt[0],
798 CV_RGB(255, 0, 0), 2, 8);
804 "./DBG_part2StartAndSelectedQuad.png", imageCopy23);
814 max_count = max_count + 1;
820 output_quad_group, pattern_size, out_corners);
823 if (found == -1 || found == 1)
839 cvReleaseStructuringElement(&kernel_cross);
840 cvReleaseStructuringElement(&kernel_rect);
841 cvReleaseStructuringElement(&kernel_diag1);
842 cvReleaseStructuringElement(&kernel_diag2);
843 cvReleaseStructuringElement(&kernel_horz);
844 cvReleaseStructuringElement(&kernel_vert);
855 std::cerr <<
"While linking the corners a problem was encountered. No " 856 "corner sequence is returned. " 870 double x0,
double y0,
double x1,
double y1,
double x2,
double y2)
872 return std::abs(0.5 * (x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)));
875 double median(
const std::vector<double>& vec)
877 std::vector<double>
v = vec;
878 const size_t n =
v.size() / 2;
879 nth_element(
v.begin(),
v.begin() +
n,
v.end());
889 std::vector<CvCBQuad::Ptr>& quad_group,
const CvSize& pattern_size)
891 #if CV_MAJOR_VERSION == 1 892 CvMemStorage* temp_storage =
nullptr;
894 cv::MemStorage temp_storage;
897 CvPoint2D32f center = cvPoint2D32f(0, 0);
900 const size_t expected_quads_count =
901 ((pattern_size.width + 1) * (pattern_size.height + 1) + 1) / 2;
906 const size_t nQuads = quad_group.size();
907 if (nQuads <= expected_quads_count)
return;
910 vector<CvPoint2D32f> centers(nQuads);
911 #if CV_MAJOR_VERSION == 1 912 temp_storage = cvCreateMemStorage(0);
914 temp_storage = cv::MemStorage(cvCreateMemStorage(0));
920 std::vector<double> quad_areas(nQuads);
921 double min_area = DBL_MAX, max_area = -DBL_MAX, mean_area = 0.0;
923 for (
size_t i = 0; i < nQuads; i++)
925 CvPoint2D32f ci = cvPoint2D32f(0, 0);
928 for (
size_t j = 0; j < 4; j++)
930 CvPoint2D32f pt =
q->corners[j]->pt;
941 q->corners[0]->pt.x,
q->corners[0]->pt.y,
q->corners[1]->pt.x,
942 q->corners[1]->pt.y,
q->corners[2]->pt.x,
q->corners[2]->pt.y) +
944 q->corners[0]->pt.x,
q->corners[0]->pt.y,
q->corners[2]->pt.x,
945 q->corners[2]->pt.y,
q->corners[3]->pt.x,
q->corners[3]->pt.y);
950 if (
a < min_area) min_area =
a;
951 if (
a > max_area) max_area =
a;
962 const double median_area =
median(quad_areas);
965 for (
size_t i = 0; i < nQuads; i++)
967 quad_group[i]->area_ratio = quad_group[i]->area / median_area;
982 while (quad_group.size() > expected_quads_count)
984 double min_box_area = DBL_MAX;
985 int min_box_area_index = -1;
988 int most_outlier_idx = -1;
989 double most_outlier_ratio = 1.0;
990 for (
size_t skip = 0; skip < quad_group.size(); skip++)
992 double ar = quad_group[skip]->area_ratio;
993 if (ar > 1.0) ar = 1.0 / ar;
995 if (ar < most_outlier_ratio)
997 most_outlier_ratio = ar;
998 most_outlier_idx = skip;
1002 if (most_outlier_idx >= 0)
1004 min_box_area_index = most_outlier_idx;
1007 if (min_box_area_index == -1)
1010 for (
size_t skip = 0; skip < quad_group.size(); skip++)
1013 CvPoint2D32f temp = centers[skip];
1014 centers[skip] = center;
1016 cvMat(1, quad_group.size(), CV_32FC2, ¢ers[0]);
1018 cvConvexHull2(&pointMat, temp_storage, CV_CLOCKWISE, 1);
1019 centers[skip] = temp;
1020 double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
1023 if (hull_area < min_box_area)
1025 min_box_area = hull_area;
1026 min_box_area_index = skip;
1028 cvClearMemStorage(temp_storage);
1035 for (
size_t i = 0; i < quad_group.size(); i++)
1039 for (
size_t j = 0; j < 4; j++)
1041 if (
q->neighbors[j] == q0)
1043 q->neighbors[j].reset();
1045 for (
size_t k = 0; k < 4; k++)
1046 if (q0->neighbors[k] ==
q)
1048 q0->neighbors[k].reset();
1058 quad_group.erase(quad_group.begin() + min_box_area_index);
1059 centers.erase(centers.begin() + min_box_area_index);
1063 #if CV_MAJOR_VERSION == 1 1064 cvReleaseMemStorage(&temp_storage);
1072 std::vector<CvCBQuad::Ptr>& quad, std::vector<CvCBQuad::Ptr>& out_group,
1073 const int group_idx,
const int dilation)
1079 const size_t quad_count = quad.size();
1082 for (
size_t i = 0; i < quad_count; i++)
1084 if (quad[i]->
count < 0 || quad[i]->group_idx >= 0)
continue;
1090 std::stack<CvCBQuad::Ptr> seqStack;
1094 q->group_idx = group_idx;
1095 out_group.push_back(
q);
1097 while (!seqStack.empty())
1102 for (
size_t k = 0; k < 4; k++)
1108 if (neighbor && neighbor->count > 0 && neighbor->group_idx < 0)
1110 neighbor->group_idx = group_idx;
1111 seqStack.push(neighbor);
1112 out_group.push_back(
1126 std::vector<CvCBQuad::Ptr>& quad_group,
const CvSize& pattern_size,
1129 const size_t count = quad_group.size();
1132 if (firstRun ==
true)
1137 int max_number = -1;
1138 for (
size_t i = 0; i <
count; i++)
1141 if (
q->count > max_number)
1143 max_number =
q->count;
1146 if (max_number == 4)
break;
1156 q->corners[0]->row = 0;
1157 q->corners[0]->column = 0;
1158 q->corners[1]->row = 0;
1159 q->corners[1]->column = 1;
1160 q->corners[2]->row = 1;
1161 q->corners[2]->column = 1;
1162 q->corners[3]->row = 1;
1163 q->corners[3]->column = 0;
1167 bool flag_changed =
true;
1168 while (flag_changed ==
true)
1171 flag_changed =
false;
1175 for (
int i =
int(
count - 1); i >= 0; i--)
1178 if ((quad_group[i])->labeled ==
false)
1182 for (
size_t j = 0; j < 4; j++)
1186 if ((quad_group[i])->neighbors[j])
1189 quad_group[i]->neighbors[j];
1192 if (quadNeighborJ->labeled ==
true)
1198 int connectedNeighborCornerId = -1;
1199 for (
int k = 0; k < 4; k++)
1201 if (quadNeighborJ->neighbors[k] ==
1204 connectedNeighborCornerId = k;
1217 ->corners[connectedNeighborCornerId];
1220 ->corners[(connectedNeighborCornerId + 1) %
1224 ->corners[(connectedNeighborCornerId + 2) %
1228 ->corners[(connectedNeighborCornerId + 3) %
1231 (quad_group[i])->corners[j]->
row = conCorner->row;
1232 (quad_group[i])->corners[j]->column =
1234 (quad_group[i])->corners[(j + 1) % 4]->row =
1235 conCorner->row - conCornerCW2->row +
1237 (quad_group[i])->corners[(j + 1) % 4]->column =
1238 conCorner->column - conCornerCW2->column +
1239 conCornerCW3->column;
1240 (quad_group[i])->corners[(j + 2) % 4]->row =
1241 conCorner->row + conCorner->row -
1243 (quad_group[i])->corners[(j + 2) % 4]->column =
1244 conCorner->column + conCorner->column -
1245 conCornerCW2->column;
1246 (quad_group[i])->corners[(j + 3) % 4]->row =
1247 conCorner->row - conCornerCW2->row +
1249 (quad_group[i])->corners[(j + 3) % 4]->column =
1250 conCorner->column - conCornerCW2->column +
1251 conCornerCW1->column;
1254 (quad_group[i])->labeled =
true;
1257 flag_changed =
true;
1276 int min_column = 127;
1277 int max_column = -127;
1279 for (
size_t i = 0; i <
count; i++)
1283 for (
size_t j = 0; j < 4; j++)
1285 if ((
q->corners[j])->row > max_row) max_row = (
q->corners[j])->row;
1287 if ((
q->corners[j])->row < min_row) min_row = (
q->corners[j])->row;
1289 if ((
q->corners[j])->column > max_column)
1290 max_column = (
q->corners[j])->column;
1292 if ((
q->corners[j])->column < min_column)
1293 min_column = (
q->corners[j])->column;
1300 for (
int i = min_row; i <= max_row; i++)
1302 for (
int j = min_column; j <= max_column; j++)
1312 for (
size_t k = 0; k <
count; k++)
1314 for (
size_t l = 0; l < 4; l++)
1316 if (((quad_group[k])->corners[l]->row == i) &&
1317 ((quad_group[k])->corners[l]->column == j))
1322 (quad_group[k])->corners[l]->needsNeighbor =
false;
1323 (quad_group[quadID])
1325 ->needsNeighbor =
false;
1331 (quad_group[k])->corners[l]->needsNeighbor =
true;
1348 for (
int i = min_row; i <= max_row; i++)
1350 for (
int j = min_column; j <= max_column; j++)
1363 for (
size_t k = 0; k <
count; k++)
1365 for (
size_t l = 0; l < 4; l++)
1367 if (((quad_group[k])->corners[l]->row == i) &&
1368 ((quad_group[k])->corners[l]->column == j))
1377 else if (number == 2)
1383 (quad_group[k])->corners[l]->pt.x -
1384 (quad_group[quadID])->corners[cornerID]->pt.x;
1386 (quad_group[k])->corners[l]->pt.y -
1387 (quad_group[quadID])->corners[cornerID]->pt.y;
1389 if (delta_x != 0 || delta_y != 0)
1392 (quad_group[k])->corners[l]->pt.x =
1393 (quad_group[k])->corners[l]->pt.x -
1395 (quad_group[quadID])->corners[cornerID]->pt.x =
1396 (quad_group[quadID])
1400 (quad_group[k])->corners[l]->pt.y =
1401 (quad_group[k])->corners[l]->pt.y -
1403 (quad_group[quadID])->corners[cornerID]->pt.y =
1404 (quad_group[quadID])
1410 else if (number > 2)
1418 number = number + 1;
1434 int largerDimPattern = max(pattern_size.height, pattern_size.width);
1435 int smallerDimPattern =
min(pattern_size.height, pattern_size.width);
1436 bool flagSmallerDim1 =
false;
1437 bool flagSmallerDim2 =
false;
1439 if ((largerDimPattern + 1) == max_column - min_column)
1441 flagSmallerDim1 =
true;
1446 for (
size_t k = 0; k <
count; k++)
1448 for (
size_t l = 0; l < 4; l++)
1450 if ((quad_group[k])->corners[l]->
column == min_column ||
1451 (quad_group[k])->corners[l]->
column == max_column)
1454 (quad_group[k])->corners[l]->needsNeighbor =
false;
1460 if ((largerDimPattern + 1) == max_row - min_row)
1462 flagSmallerDim2 =
true;
1467 for (
size_t k = 0; k <
count; k++)
1469 for (
size_t l = 0; l < 4; l++)
1471 if ((quad_group[k])->corners[l]->row == min_row ||
1472 (quad_group[k])->corners[l]->
row == max_row)
1475 (quad_group[k])->corners[l]->needsNeighbor =
false;
1493 if ((flagSmallerDim1 ==
false && flagSmallerDim2 ==
true))
1498 if ((smallerDimPattern + 1) == max_column - min_column)
1500 for (
size_t k = 0; k <
count; k++)
1502 for (
int l = 0; l < 4; l++)
1504 if ((quad_group[k])->corners[l]->column == min_column ||
1505 (quad_group[k])->corners[l]->
column == max_column)
1508 (quad_group[k])->corners[l]->needsNeighbor =
false;
1515 if ((flagSmallerDim1 ==
true && flagSmallerDim2 ==
false))
1520 if ((smallerDimPattern + 1) == max_row - min_row)
1522 for (
size_t k = 0; k <
count; k++)
1524 for (
size_t l = 0; l < 4; l++)
1526 if ((quad_group[k])->corners[l]->row == min_row ||
1527 (quad_group[k])->corners[l]->
row == max_row)
1530 (quad_group[k])->corners[l]->needsNeighbor =
false;
1537 if ((flagSmallerDim1 ==
false && flagSmallerDim2 ==
false) &&
1538 smallerDimPattern + 1 < max_column - min_column)
1543 if ((smallerDimPattern + 1) == max_row - min_row)
1545 for (
size_t k = 0; k <
count; k++)
1547 for (
size_t l = 0; l < 4; l++)
1549 if ((quad_group[k])->corners[l]->row == min_row ||
1550 (quad_group[k])->corners[l]->
row == max_row)
1553 (quad_group[k])->corners[l]->needsNeighbor =
false;
1560 if ((flagSmallerDim1 ==
false && flagSmallerDim2 ==
false) &&
1561 smallerDimPattern + 1 < max_row - min_row)
1566 if ((smallerDimPattern + 1) == max_column - min_column)
1568 for (
size_t k = 0; k <
count; k++)
1570 for (
size_t l = 0; l < 4; l++)
1572 if ((quad_group[k])->corners[l]->column == min_column ||
1573 (quad_group[k])->corners[l]->
column == max_column)
1576 (quad_group[k])->corners[l]->needsNeighbor =
false;
1596 const float thresh_dilation = (float)(2 * dilation + 3) *
1597 (2 * dilation + 3) *
1602 const size_t quad_count = quads.size();
1605 for (
size_t idx = 0; idx < quad_count; idx++)
1611 for (
size_t i = 0; i < 4; i++)
1614 float min_dist = FLT_MAX;
1615 int closest_corner_idx = -1;
1618 if (cur_quad->neighbors[i])
continue;
1620 pt = cur_quad->corners[i]->pt;
1623 for (
size_t k = 0; k < quad_count; k++)
1625 if (k == idx)
continue;
1627 for (
size_t j = 0; j < 4; j++)
1630 if (quads[k]->neighbors[j])
continue;
1632 dx = pt.x - quads[k]->corners[j]->pt.x;
1633 dy = pt.y - quads[k]->corners[j]->pt.y;
1634 dist = dx * dx + dy * dy;
1639 if (dist < min_dist &&
1640 dist <= (cur_quad->edge_len + thresh_dilation) &&
1641 dist <= (quads[k]->edge_len + thresh_dilation))
1646 float x1 = (cur_quad->corners[i]->pt.x +
1647 cur_quad->corners[(i + 1) % 4]->pt.x) /
1649 float y1 = (cur_quad->corners[i]->pt.y +
1650 cur_quad->corners[(i + 1) % 4]->pt.y) /
1652 float x2 = (cur_quad->corners[(i + 2) % 4]->pt.x +
1653 cur_quad->corners[(i + 3) % 4]->pt.x) /
1655 float y2 = (cur_quad->corners[(i + 2) % 4]->pt.y +
1656 cur_quad->corners[(i + 3) % 4]->pt.y) /
1659 float x3 = (cur_quad->corners[i]->pt.x +
1660 cur_quad->corners[(i + 3) % 4]->pt.x) /
1662 float y3 = (cur_quad->corners[i]->pt.y +
1663 cur_quad->corners[(i + 3) % 4]->pt.y) /
1665 float x4 = (cur_quad->corners[(i + 1) % 4]->pt.x +
1666 cur_quad->corners[(i + 2) % 4]->pt.x) /
1668 float y4 = (cur_quad->corners[(i + 1) % 4]->pt.y +
1669 cur_quad->corners[(i + 2) % 4]->pt.y) /
1680 float c11 = cur_quad->corners[i]->pt.x - x2;
1681 float d11 = cur_quad->corners[i]->pt.y - y2;
1683 float c12 = quads[k]->corners[j]->pt.x - x2;
1684 float d12 = quads[k]->corners[j]->pt.y - y2;
1685 float sign11 =
a1 * d11 - c11 *
b1;
1686 float sign12 =
a1 * d12 - c12 *
b1;
1691 float c21 = cur_quad->corners[i]->pt.x - x4;
1692 float d21 = cur_quad->corners[i]->pt.y - y4;
1694 float c22 = quads[k]->corners[j]->pt.x - x4;
1695 float d22 = quads[k]->corners[j]->pt.y - y4;
1696 float sign21 =
a2 * d21 - c21 *
b2;
1697 float sign22 =
a2 * d22 - c22 *
b2;
1707 float c13 = quads[k]->corners[(j + 2) % 4]->pt.x - x2;
1708 float d13 = quads[k]->corners[(j + 2) % 4]->pt.y - y2;
1709 float c23 = quads[k]->corners[(j + 2) % 4]->pt.x - x4;
1710 float d23 = quads[k]->corners[(j + 2) % 4]->pt.y - y4;
1711 float sign13 =
a1 * d13 - c13 *
b1;
1712 float sign23 =
a2 * d23 - c23 *
b2;
1717 float u1 = (quads[k]->corners[j]->pt.x +
1718 quads[k]->corners[(j + 1) % 4]->pt.x) /
1720 float v1 = (quads[k]->corners[j]->pt.y +
1721 quads[k]->corners[(j + 1) % 4]->pt.y) /
1723 float u2 = (quads[k]->corners[(j + 2) % 4]->pt.x +
1724 quads[k]->corners[(j + 3) % 4]->pt.x) /
1726 float v2 = (quads[k]->corners[(j + 2) % 4]->pt.y +
1727 quads[k]->corners[(j + 3) % 4]->pt.y) /
1730 float u3 = (quads[k]->corners[j]->pt.x +
1731 quads[k]->corners[(j + 3) % 4]->pt.x) /
1733 float v3 = (quads[k]->corners[j]->pt.y +
1734 quads[k]->corners[(j + 3) % 4]->pt.y) /
1736 float u4 = (quads[k]->corners[(j + 1) % 4]->pt.x +
1737 quads[k]->corners[(j + 2) % 4]->pt.x) /
1739 float v4 = (quads[k]->corners[(j + 1) % 4]->pt.y +
1740 quads[k]->corners[(j + 2) % 4]->pt.y) /
1752 float c31 = cur_quad->corners[i]->pt.x -
u2;
1753 float d31 = cur_quad->corners[i]->pt.y -
v2;
1755 float c32 = quads[k]->corners[j]->pt.x -
u2;
1756 float d32 = quads[k]->corners[j]->pt.y -
v2;
1757 float sign31 =
a3 * d31 - c31 *
b3;
1758 float sign32 =
a3 * d32 - c32 *
b3;
1763 float c41 = cur_quad->corners[i]->pt.x - u4;
1764 float d41 = cur_quad->corners[i]->pt.y - v4;
1766 float c42 = quads[k]->corners[j]->pt.x - u4;
1767 float d42 = quads[k]->corners[j]->pt.y - v4;
1768 float sign41 = a4 * d41 - c41 * b4;
1769 float sign42 = a4 * d42 - c42 * b4;
1779 float c33 = cur_quad->corners[(i + 2) % 4]->pt.x -
u2;
1780 float d33 = cur_quad->corners[(i + 2) % 4]->pt.y -
v2;
1781 float c43 = cur_quad->corners[(i + 2) % 4]->pt.x - u4;
1782 float d43 = cur_quad->corners[(i + 2) % 4]->pt.y - v4;
1783 float sign33 =
a3 * d33 - c33 *
b3;
1784 float sign43 = a4 * d43 - c43 * b4;
1787 if (((sign11 < 0 && sign12 < 0) ||
1788 (sign11 > 0 && sign12 > 0)) &&
1789 ((sign21 < 0 && sign22 < 0) ||
1790 (sign21 > 0 && sign22 > 0)) &&
1791 ((sign31 < 0 && sign32 < 0) ||
1792 (sign31 > 0 && sign32 > 0)) &&
1793 ((sign41 < 0 && sign42 < 0) ||
1794 (sign41 > 0 && sign42 > 0)) &&
1795 ((sign11 < 0 && sign13 < 0) ||
1796 (sign11 > 0 && sign13 > 0)) &&
1797 ((sign21 < 0 && sign23 < 0) ||
1798 (sign21 > 0 && sign23 > 0)) &&
1799 ((sign31 < 0 && sign33 < 0) ||
1800 (sign31 > 0 && sign33 > 0)) &&
1801 ((sign41 < 0 && sign43 < 0) ||
1802 (sign41 > 0 && sign43 > 0)))
1805 closest_corner_idx = j;
1806 closest_quad = quads[k];
1814 if (closest_corner_idx >= 0 && min_dist < FLT_MAX)
1817 closest_quad->corners[closest_corner_idx];
1822 for (
size_t j = 0; !skip && j < 4; j++)
1823 skip = closest_quad->neighbors[j] == cur_quad;
1828 closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
1829 closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
1832 cur_quad->neighbors[i] = closest_quad;
1833 cur_quad->corners[i] = closest_corner;
1835 closest_quad->count++;
1836 closest_quad->neighbors[closest_corner_idx] = cur_quad;
1837 closest_quad->corners[closest_corner_idx] = closest_corner;
1851 std::vector<CvCBQuad::Ptr>& new_quads,
int new_dilation,
1852 std::vector<CvCBQuad::Ptr>& old_quads,
int old_dilation)
1862 const float thresh_dilation =
1863 (float)(2 * new_dilation + 3) * (2 * old_dilation + 3) * 2;
1867 for (
size_t idx = 0; idx < old_quads.size(); idx++)
1872 for (
int i = 0; i < 4; i++)
1875 float min_dist = FLT_MAX;
1876 int closest_corner_idx = -1;
1881 if (cur_quad->corners[i]->needsNeighbor ==
false)
continue;
1883 pt = cur_quad->corners[i]->pt;
1886 for (
size_t k = 0; k < new_quads.size(); k++)
1889 if (new_quads[k]->labeled ==
true)
continue;
1891 for (
int j = 0; j < 4; j++)
1895 dx = pt.x - new_quads[k]->corners[j]->pt.x;
1896 dy = pt.y - new_quads[k]->corners[j]->pt.y;
1897 dist = dx * dx + dy * dy;
1899 if ((dist < min_dist) &&
1900 dist <= (cur_quad->edge_len + thresh_dilation) &&
1901 dist <= (new_quads[k]->edge_len + thresh_dilation))
1906 float x1 = (cur_quad->corners[i]->pt.x +
1907 cur_quad->corners[(i + 1) % 4]->pt.x) /
1909 float y1 = (cur_quad->corners[i]->pt.y +
1910 cur_quad->corners[(i + 1) % 4]->pt.y) /
1912 float x2 = (cur_quad->corners[(i + 2) % 4]->pt.x +
1913 cur_quad->corners[(i + 3) % 4]->pt.x) /
1915 float y2 = (cur_quad->corners[(i + 2) % 4]->pt.y +
1916 cur_quad->corners[(i + 3) % 4]->pt.y) /
1919 float x3 = (cur_quad->corners[i]->pt.x +
1920 cur_quad->corners[(i + 3) % 4]->pt.x) /
1922 float y3 = (cur_quad->corners[i]->pt.y +
1923 cur_quad->corners[(i + 3) % 4]->pt.y) /
1925 float x4 = (cur_quad->corners[(i + 1) % 4]->pt.x +
1926 cur_quad->corners[(i + 2) % 4]->pt.x) /
1928 float y4 = (cur_quad->corners[(i + 1) % 4]->pt.y +
1929 cur_quad->corners[(i + 2) % 4]->pt.y) /
1940 float c11 = cur_quad->corners[i]->pt.x - x2;
1941 float d11 = cur_quad->corners[i]->pt.y - y2;
1943 float c12 = new_quads[k]->corners[j]->pt.x - x2;
1944 float d12 = new_quads[k]->corners[j]->pt.y - y2;
1945 float sign11 =
a1 * d11 - c11 *
b1;
1946 float sign12 =
a1 * d12 - c12 *
b1;
1951 float c21 = cur_quad->corners[i]->pt.x - x4;
1952 float d21 = cur_quad->corners[i]->pt.y - y4;
1954 float c22 = new_quads[k]->corners[j]->pt.x - x4;
1955 float d22 = new_quads[k]->corners[j]->pt.y - y4;
1956 float sign21 =
a2 * d21 - c21 *
b2;
1957 float sign22 =
a2 * d22 - c22 *
b2;
1968 new_quads[k]->corners[(j + 2) % 4]->pt.x - x2;
1970 new_quads[k]->corners[(j + 2) % 4]->pt.y - y2;
1972 new_quads[k]->corners[(j + 2) % 4]->pt.x - x4;
1974 new_quads[k]->corners[(j + 2) % 4]->pt.y - y4;
1975 float sign13 =
a1 * d13 - c13 *
b1;
1976 float sign23 =
a2 * d23 - c23 *
b2;
1981 float u1 = (new_quads[k]->corners[j]->pt.x +
1982 new_quads[k]->corners[(j + 1) % 4]->pt.x) /
1984 float v1 = (new_quads[k]->corners[j]->pt.y +
1985 new_quads[k]->corners[(j + 1) % 4]->pt.y) /
1987 float u2 = (new_quads[k]->corners[(j + 2) % 4]->pt.x +
1988 new_quads[k]->corners[(j + 3) % 4]->pt.x) /
1990 float v2 = (new_quads[k]->corners[(j + 2) % 4]->pt.y +
1991 new_quads[k]->corners[(j + 3) % 4]->pt.y) /
1994 float u3 = (new_quads[k]->corners[j]->pt.x +
1995 new_quads[k]->corners[(j + 3) % 4]->pt.x) /
1997 float v3 = (new_quads[k]->corners[j]->pt.y +
1998 new_quads[k]->corners[(j + 3) % 4]->pt.y) /
2000 float u4 = (new_quads[k]->corners[(j + 1) % 4]->pt.x +
2001 new_quads[k]->corners[(j + 2) % 4]->pt.x) /
2003 float v4 = (new_quads[k]->corners[(j + 1) % 4]->pt.y +
2004 new_quads[k]->corners[(j + 2) % 4]->pt.y) /
2015 float c31 = cur_quad->corners[i]->pt.x -
u2;
2016 float d31 = cur_quad->corners[i]->pt.y -
v2;
2018 float c32 = new_quads[k]->corners[j]->pt.x -
u2;
2019 float d32 = new_quads[k]->corners[j]->pt.y -
v2;
2020 float sign31 =
a3 * d31 - c31 *
b3;
2021 float sign32 =
a3 * d32 - c32 *
b3;
2026 float c41 = cur_quad->corners[i]->pt.x - u4;
2027 float d41 = cur_quad->corners[i]->pt.y - v4;
2029 float c42 = new_quads[k]->corners[j]->pt.x - u4;
2030 float d42 = new_quads[k]->corners[j]->pt.y - v4;
2031 float sign41 = a4 * d41 - c41 * b4;
2032 float sign42 = a4 * d42 - c42 * b4;
2042 float c33 = cur_quad->corners[(i + 2) % 4]->pt.x -
u2;
2043 float d33 = cur_quad->corners[(i + 2) % 4]->pt.y -
v2;
2044 float c43 = cur_quad->corners[(i + 2) % 4]->pt.x - u4;
2045 float d43 = cur_quad->corners[(i + 2) % 4]->pt.y - v4;
2046 float sign33 =
a3 * d33 - c33 *
b3;
2047 float sign43 = a4 * d43 - c43 * b4;
2055 float x5 = cur_quad->corners[i]->pt.x;
2056 float y5 = cur_quad->corners[i]->pt.y;
2057 float x6 = cur_quad->corners[(i + 1) % 4]->pt.x;
2058 float y6 = cur_quad->corners[(i + 1) % 4]->pt.y;
2062 float x8 = cur_quad->corners[(i + 3) % 4]->pt.x;
2063 float y8 = cur_quad->corners[(i + 3) % 4]->pt.y;
2074 float c51 = cur_quad->corners[(i + 2) % 4]->pt.x - x5;
2075 float d51 = cur_quad->corners[(i + 2) % 4]->pt.y - y5;
2077 float c52 = new_quads[k]->corners[j]->pt.x - x5;
2078 float d52 = new_quads[k]->corners[j]->pt.y - y5;
2079 float sign51 = a5 * d51 - c51 * b5;
2080 float sign52 = a5 * d52 - c52 * b5;
2085 float c61 = cur_quad->corners[(i + 2) % 4]->pt.x - x7;
2086 float d61 = cur_quad->corners[(i + 2) % 4]->pt.y - y7;
2088 float c62 = new_quads[k]->corners[j]->pt.x - x7;
2089 float d62 = new_quads[k]->corners[j]->pt.y - y7;
2090 float sign61 = a6 * d61 - c61 * b6;
2091 float sign62 = a6 * d62 - c62 * b6;
2096 float u5 = new_quads[k]->corners[j]->pt.x;
2097 float v5 = new_quads[k]->corners[j]->pt.y;
2098 float u6 = new_quads[k]->corners[(j + 1) % 4]->pt.x;
2099 float v6 = new_quads[k]->corners[(j + 1) % 4]->pt.y;
2103 float u8 = new_quads[k]->corners[(j + 3) % 4]->pt.x;
2104 float v8 = new_quads[k]->corners[(j + 3) % 4]->pt.y;
2115 float c71 = cur_quad->corners[i]->pt.x - u5;
2116 float d71 = cur_quad->corners[i]->pt.y - v5;
2119 new_quads[k]->corners[(j + 2) % 4]->pt.x - u5;
2121 new_quads[k]->corners[(j + 2) % 4]->pt.y - v5;
2122 float sign71 = a7 * d71 - c71 * b7;
2123 float sign72 = a7 * d72 - c72 * b7;
2128 float c81 = cur_quad->corners[i]->pt.x - u7;
2129 float d81 = cur_quad->corners[i]->pt.y - v7;
2132 new_quads[k]->corners[(j + 2) % 4]->pt.x - u7;
2134 new_quads[k]->corners[(j + 2) % 4]->pt.y - v7;
2135 float sign81 = a8 * d81 - c81 * b8;
2136 float sign82 = a8 * d82 - c82 * b8;
2139 if (((sign11 < 0 && sign12 < 0) ||
2140 (sign11 > 0 && sign12 > 0)) &&
2141 ((sign21 < 0 && sign22 < 0) ||
2142 (sign21 > 0 && sign22 > 0)) &&
2143 ((sign31 < 0 && sign32 < 0) ||
2144 (sign31 > 0 && sign32 > 0)) &&
2145 ((sign41 < 0 && sign42 < 0) ||
2146 (sign41 > 0 && sign42 > 0)) &&
2147 ((sign11 < 0 && sign13 < 0) ||
2148 (sign11 > 0 && sign13 > 0)) &&
2149 ((sign21 < 0 && sign23 < 0) ||
2150 (sign21 > 0 && sign23 > 0)) &&
2151 ((sign31 < 0 && sign33 < 0) ||
2152 (sign31 > 0 && sign33 > 0)) &&
2153 ((sign41 < 0 && sign43 < 0) ||
2154 (sign41 > 0 && sign43 > 0)) &&
2155 ((sign51 < 0 && sign52 > 0) ||
2156 (sign51 > 0 && sign52 < 0)) &&
2157 ((sign61 < 0 && sign62 > 0) ||
2158 (sign61 > 0 && sign62 < 0)) &&
2159 ((sign71 < 0 && sign72 > 0) ||
2160 (sign71 > 0 && sign72 < 0)) &&
2161 ((sign81 < 0 && sign82 > 0) ||
2162 (sign81 > 0 && sign82 < 0)))
2164 closest_corner_idx = j;
2165 closest_quad = new_quads[k];
2173 if (closest_corner_idx >= 0 && min_dist < FLT_MAX)
2176 closest_quad->corners[closest_corner_idx];
2177 closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
2178 closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
2183 cur_quad->corners[i]->pt.x = closest_corner->pt.x;
2184 cur_quad->corners[i]->pt.y = closest_corner->pt.y;
2185 cur_quad->neighbors[i] = closest_quad;
2186 closest_quad->corners[closest_corner_idx]->pt.x =
2187 closest_corner->pt.x;
2188 closest_quad->corners[closest_corner_idx]->pt.y =
2189 closest_corner->pt.y;
2193 closest_quad->labeled =
true;
2199 newQuad->edge_len = closest_quad->edge_len;
2200 newQuad->group_idx =
2201 cur_quad->group_idx;
2202 newQuad->labeled =
false;
2206 newQuad->neighbors[closest_corner_idx] = cur_quad;
2207 newQuad->neighbors[(closest_corner_idx + 1) % 4]
2209 newQuad->neighbors[(closest_corner_idx + 2) % 4]
2211 newQuad->neighbors[(closest_corner_idx + 3) % 4]
2214 for (
int j = 0; j < 4; j++)
2217 newQuad->corners[j]->pt.x = closest_quad->corners[j]->pt.x;
2218 newQuad->corners[j]->pt.y = closest_quad->corners[j]->pt.y;
2221 old_quads.push_back(newQuad);
2222 cur_quad->neighbors[i] = newQuad;
2238 vector<CvCBQuad::Ptr>& out_quads, vector<CvCBCorner::Ptr>& out_corners,
2239 const CImage&
image,
int flags,
int dilation,
bool firstRun)
2247 #if CV_MAJOR_VERSION == 1 2248 CvMemStorage* temp_storage = cvCreateMemStorage(0);
2250 cv::MemStorage temp_storage = cv::MemStorage(cvCreateMemStorage(0));
2253 CvSeq* src_contour = 0;
2256 CvContourScanner scanner;
2260 const int min_size =
2261 cvRound(
image.getWidth() *
image.getHeight() * .03 * 0.01 * 0.92 * 0.1);
2263 root = cvCreateSeq(0,
sizeof(CvSeq),
sizeof(CvSeq*), temp_storage);
2266 scanner = cvStartFindContours(
2267 const_cast<IplImage*>(
image.getAs<IplImage>()), temp_storage,
2268 sizeof(
CvContourEx), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
2271 while ((src_contour = cvFindNextContour(scanner)) != 0)
2273 CvSeq* dst_contour = 0;
2274 CvRect rect = ((CvContour*)src_contour)->rect;
2287 if (CV_IS_SEQ_HOLE(src_contour) && rect.width * rect.height >= min_size)
2289 int min_approx_level = 2, max_approx_level;
2290 if (firstRun ==
true)
2291 max_approx_level = 3;
2295 for (approx_level = min_approx_level;
2296 approx_level <= max_approx_level; approx_level++)
2298 dst_contour = cvApproxPoly(
2299 src_contour,
sizeof(CvContour), temp_storage,
2300 CV_POLY_APPROX_DP, (
float)approx_level);
2304 dst_contour = cvApproxPoly(
2305 dst_contour,
sizeof(CvContour), temp_storage,
2306 CV_POLY_APPROX_DP, (
float)approx_level);
2308 if (dst_contour->total == 4)
break;
2312 if (dst_contour->total == 4 && cvCheckContourConvexity(dst_contour))
2319 for (
int i = 0; i < 4; i++)
2320 pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
2348 dst_contour->v_prev = (CvSeq*)parent;
2349 cvSeqPush(root, &dst_contour);
2356 cvEndFindContours(&scanner);
2360 for (
int q = 0;
q < root->total;
q++)
2363 out_corners.clear();
2364 for (
int q = 0;
q < 4 * root->total;
q++)
2368 for (
int idx = 0; idx < root->total; idx++)
2371 src_contour = *(CvSeq**)cvGetSeqElem(root, idx);
2372 if ((flags & cv::CALIB_CB_FILTER_QUADS) &&
2373 src_contour->v_prev != (CvSeq*)board)
2379 assert(src_contour->total == 4);
2380 for (
int i = 0; i < 4; i++)
2383 cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
2385 out_corners[quad_count * 4 +
2390 q->corners[i] = corner;
2392 q->edge_len = FLT_MAX;
2393 for (
int i = 0; i < 4; i++)
2395 float dx =
q->corners[i]->pt.x -
q->corners[(i + 1) & 3]->pt.x;
2396 float dy =
q->corners[i]->pt.y -
q->corners[(i + 1) & 3]->pt.y;
2397 float d = dx * dx + dy * dy;
2398 if (
q->edge_len > d)
q->edge_len = d;
2403 if (cvGetErrStatus() < 0)
2407 out_corners.clear();
2413 #if CV_MAJOR_VERSION == 1 2414 cvReleaseMemStorage(&temp_storage);
2422 const std::vector<CvCBQuad::Ptr>& output_quads,
const CvSize& pattern_size,
2423 std::vector<CvPoint2D32f>& out_corners)
2426 out_corners.clear();
2428 bool flagRow =
false;
2429 bool flagColumn =
false;
2430 int maxPattern_sizeRow = -1;
2431 int maxPattern_sizeColumn = -1;
2437 int min_column = 127;
2438 int max_column = -127;
2440 for (
size_t i = 0; i < output_quads.size(); i++)
2444 for (
int j = 0; j < 4; j++)
2446 if ((
q->corners[j])->row > max_row) max_row = (
q->corners[j])->row;
2447 if ((
q->corners[j])->row < min_row) min_row = (
q->corners[j])->row;
2448 if ((
q->corners[j])->column > max_column)
2449 max_column = (
q->corners[j])->column;
2450 if ((
q->corners[j])->column < min_column)
2451 min_column = (
q->corners[j])->column;
2459 for (
size_t i = 0; i < output_quads.size(); i++)
2463 for (
int j = 0; j < 4; j++)
2465 if ((
q->corners[j])->column == max_column &&
2466 (
q->corners[j])->
row != min_row &&
2467 (
q->corners[j])->row != max_row)
2469 if ((
q->corners[j]->needsNeighbor) ==
false)
2476 if ((
q->corners[j])->row == max_row &&
2477 (
q->corners[j])->
column != min_column &&
2478 (
q->corners[j])->column != max_column)
2480 if ((
q->corners[j]->needsNeighbor) ==
false)
2490 if (flagColumn ==
true)
2492 if (max_column - min_column == pattern_size.width + 1)
2494 maxPattern_sizeColumn = pattern_size.width;
2495 maxPattern_sizeRow = pattern_size.height;
2499 maxPattern_sizeColumn = pattern_size.height;
2500 maxPattern_sizeRow = pattern_size.width;
2503 else if (flagRow ==
true)
2505 if (max_row - min_row == pattern_size.width + 1)
2507 maxPattern_sizeRow = pattern_size.width;
2508 maxPattern_sizeColumn = pattern_size.height;
2512 maxPattern_sizeRow = pattern_size.height;
2513 maxPattern_sizeColumn = pattern_size.width;
2521 maxPattern_sizeColumn = max(pattern_size.width, pattern_size.height);
2522 maxPattern_sizeRow = max(pattern_size.width, pattern_size.height);
2526 if (maxPattern_sizeRow * maxPattern_sizeColumn !=
2527 pattern_size.width * pattern_size.height)
2531 bool do_swap_col_row = maxPattern_sizeRow != pattern_size.height;
2533 if (do_swap_col_row)
2535 std::swap(min_row, min_column);
2536 std::swap(maxPattern_sizeRow, maxPattern_sizeColumn);
2541 for (
int i = min_row + 1; i < maxPattern_sizeRow + min_row + 1; i++)
2543 for (
int j = min_column + 1; j < maxPattern_sizeColumn + min_column + 1;
2549 for (
size_t k = 0; k < output_quads.size(); k++)
2551 for (
int l = 0; l < 4; l++)
2553 int r = output_quads[k]->corners[l]->row;
2554 int c = output_quads[k]->corners[l]->column;
2555 if (do_swap_col_row) std::swap(
r,
c);
2557 if (
r == i &&
c == j)
2566 out_corners.push_back(
2567 output_quads[k]->corners[l]->pt);
2577 if (iter > 2)
return -1;
2586 if (iter == 1 || iter == 2)
2597 return (out_corners.size() ==
2598 size_t(pattern_size.width * pattern_size.height))
2607 std::map<CvCBQuad*, size_t> pointer2index;
2608 for (
size_t i = 0; i < quads.size(); i++) pointer2index[quads[i].
get()] = i;
2610 vector<std::array<size_t, 4>> neig_indices(quads.size());
2611 for (
size_t i = 0; i < quads.size(); i++)
2612 for (
size_t j = 0; j < 4; j++)
2613 neig_indices[i][j] = pointer2index[quads[i]->neighbors[j].
get()];
2615 std::vector<CvCBQuad::Ptr> new_quads = quads;
2616 std::for_each(new_quads.begin(), new_quads.end(), [](
CvCBQuad::Ptr& ptr) {
2619 for (
size_t i = 0; i < new_quads.size(); i++)
2620 for (
size_t j = 0; j < 4; j++)
2621 new_quads[i]->neighbors[j] = new_quads[neig_indices[i][j]];
2628 #endif // MRPT_HAS_OPENCV void mrFindQuadNeighbors2(std::vector< CvCBQuad::Ptr > &quads, int dilation)
std::shared_ptr< CvCBCorner > Ptr
GLuint GLuint GLsizei count
const T * getAs() const
Returns a pointer to a const T* containing the image - the idea is to call like "img.getAs<IplImage>()" so we can avoid here including OpenCV's headers.
GLenum GLenum GLenum GLenum GLenum scale
void mrLabelQuadGroup(std::vector< CvCBQuad::Ptr > &quad_group, const CvSize &pattern_size, bool firstRun)
GLdouble GLdouble GLdouble GLdouble q
void icvCleanFoundConnectedQuads(std::vector< CvCBQuad::Ptr > &quad_group, const CvSize &pattern_size)
GLenum GLsizei GLenum GLenum const GLvoid * image
int icvGenerateQuads(vector< CvCBQuad::Ptr > &out_quads, vector< CvCBCorner::Ptr > &out_corners, const CImage &image, int flags, int dilation, bool firstRun)
int mrAugmentBestRun(std::vector< CvCBQuad::Ptr > &new_quads, int new_dilation, std::vector< CvCBQuad::Ptr > &old_quads, int old_dilation)
This base provides a set of functions for maths stuff.
double median(const std::vector< double > &vec)
bool do_special_dilation(CImage &thresh_img, const int dilations, IplConvKernel *kernel_cross, IplConvKernel *kernel_rect, IplConvKernel *kernel_diag1, IplConvKernel *kernel_diag2, IplConvKernel *kernel_horz, IplConvKernel *kernel_vert)
double triangleArea(double x0, double y0, double x1, double y1, double x2, double y2)
int myQuads2Points(const std::vector< CvCBQuad::Ptr > &output_quads, const CvSize &pattern_size, std::vector< CvPoint2D32f > &out_corners)
GLfloat GLfloat GLfloat GLfloat v3
#define MAX_CONTOUR_APPROX
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
GLdouble GLdouble GLdouble r
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
GLenum GLenum GLvoid * row
void icvFindConnectedQuads(std::vector< CvCBQuad::Ptr > &quad, std::vector< CvCBQuad::Ptr > &out_group, const int group_idx, const int dilation)
std::shared_ptr< CvCBQuad > Ptr
GLfloat GLfloat GLfloat v2
void quadListMakeUnique(std::vector< CvCBQuad::Ptr > &quads)
GLenum GLenum GLvoid GLvoid * column
int cvFindChessboardCorners3(const CImage &img_, CvSize pattern_size, std::vector< CvPoint2D32f > &out_corners)
GLubyte GLubyte GLubyte a
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
A class for storing images as grayscale or RGB bitmaps.
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.