@@ -40,13 +40,13 @@ static uint64_t getTimestamp()
4040typedef struct {
4141 double dx;
4242 double dy;
43-
43+
4444 double x;
4545 double y;
46-
46+
4747 double angle;
4848 double dist;
49-
49+
5050 int contourIndex;
5151 int contourSize;
5252} FinderPoint;
@@ -119,11 +119,11 @@ void dilation(Mat &src, Mat &out, size_t dilation_size)
119119 Mat element = getStructuringElement (MORPH_CROSS,
120120 Size2i (2 * dilation_size + 1 , 2 * dilation_size + 1 ),
121121 Point2i (dilation_size, dilation_size));
122-
122+
123123 dilate (src, out, element);
124124}
125125
126- void unsharpMask (cv::Mat &im)
126+ void unsharpMask (cv::Mat &im)
127127{
128128 cv::Mat tmp;
129129 cv::GaussianBlur (im, tmp, cv::Size (0 , 0 ), 2 );
@@ -157,16 +157,16 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
157157 // start by masking off the region where we expect to find the finder
158158 // ring (between 1.22 and 1.525 times the size of the inner circle)
159159 Mat finder_point_range = Mat::zeros (whitish.size (), whitish.type ());
160-
160+
161161 inner_ring.size .width *= 1.525 ;
162162 inner_ring.size .height *= 1.525 ;
163-
163+
164164 START_DEBUG_TIMING (efp_ellipse_region);
165165 ellipse (finder_point_range, inner_ring, Scalar (255 , 255 , 255 ), -1 );
166-
166+
167167 inner_ring.size .width *= 0.805 ;
168168 inner_ring.size .height *= 0.805 ;
169-
169+
170170 ellipse (finder_point_range, inner_ring, Scalar (0 , 0 , 0 ), -1 );
171171
172172 if (debug) {
@@ -176,7 +176,7 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
176176
177177 imwrite (filename, finder_point_range);
178178 }
179-
179+
180180 END_DEBUG_TIMING (timing, efp_ellipse_region);
181181 Point2i last_point;
182182
@@ -195,12 +195,12 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
195195
196196 vector<vector<Point2i> > contours;
197197 vector<Vec4i> hierarchy;
198-
198+
199199 // detect all blobs within the candidate region
200200 START_DEBUG_TIMING (efp_contours);
201201 findContours (candidate_region, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE, Point2i (0 , 0 ));
202202 END_DEBUG_TIMING (timing, efp_contours);
203-
203+
204204 // compute the image moments for each blob in the candidate region, we use these
205205 // moments to look and the relative angles between the **centers** of each blob
206206 START_DEBUG_TIMING (efp_moments);
@@ -240,50 +240,50 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
240240 START_DEBUG_TIMING (efp_extraction);
241241 for (int i = 0 ; i < contours.size (); ++i) {
242242 vector<Point2i> &contour = contours[i];
243-
243+
244244 Point2i point = mc[i];
245-
245+
246246 double dist = sqrt (pow (point.x - last_point.x , 2.0 ) + pow (point.y - last_point.y , 2.0 ));
247-
247+
248248 if (dist < 2 ) {
249249 continue ;
250250 }
251-
251+
252252 last_point = point;
253-
253+
254254 if (contour.size () > 1 ) {
255255 if (mc[i].y > 0 && mc[i].x > 0 ) {
256256 if (finder_point_range.at <char >(mc[i].y , mc[i].x ) != 0 ) {
257257 FinderPoint finder;
258-
258+
259259 finder.x = mc[i].x ;
260260 finder.y = mc[i].y ;
261-
261+
262262 finder.dx = finder.x - inner_ring.center .x ;
263263 finder.dy = finder.y - inner_ring.center .y ;
264-
264+
265265 finder.contourIndex = i;
266266
267267 finder.contourSize = contour.size ();
268-
268+
269269 finder.dist = sqrt (finder.dx * finder.dx + finder.dy * finder.dy );
270-
270+
271271 finder.angle = atan2 (finder.dy , finder.dx );
272-
272+
273273 finder_points.push_back (finder);
274274 }
275275 }
276276 }
277277 }
278278 END_DEBUG_TIMING (timing, efp_extraction);
279-
279+
280280 START_DEBUG_TIMING (efp_filter_and_sort);
281281 if (finder_points.size () > 0 ) {
282282 // disard small shards that were erroneously picked up
283283 sort (finder_points.begin (), finder_points.end (), compareFinderPointsSize);
284284
285285 int p90_size = finder_points[finder_points.size () * 0.9 ].contourSize ;
286-
286+
287287 for (int i = 0 ; i < finder_points.size (); ++i) {
288288 if (finder_points[i].contourSize < p90_size / 5 ) {
289289 finder_points.erase (finder_points.begin () + i);
@@ -316,18 +316,18 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
316316 if (finder_points.size () != sizeof (finder_deltas) / sizeof (double ) + 1 ) {
317317 return false ;
318318 }
319-
319+
320320 // sort the finder points into a clockwise winding based on the angle of the computed vector
321321 sort (finder_points.begin (), finder_points.end (), compareFinderPoints);
322322 END_DEBUG_TIMING (timing, efp_filter_and_sort);
323-
323+
324324 vector<double > point_deltas (finder_points.size ());
325-
325+
326326 START_DEBUG_TIMING (efp_check_ratio);
327327 // compute the relative angles between each neighbouring pair of finder points
328328 for (int j = 0 ; j < finder_points.size (); ++j) {
329329 point_deltas[j] = finder_points[(j + 1 ) % finder_points.size ()].angle - finder_points[j].angle ;
330-
330+
331331 while (point_deltas[j] < 0.0 ) {
332332 point_deltas[j] += 2 * M_PI;
333333 }
@@ -340,13 +340,13 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
340340 // the given starting offset
341341 for (int j = 0 ; j < point_deltas.size (); ++j) {
342342 bool found = true ;
343-
343+
344344 for (int k = 0 ; k < sizeof (finder_deltas) / sizeof (double ); ++k) {
345345 double pointRatio = point_deltas[(j + k) % point_deltas.size ()];
346-
346+
347347 double lower_bound = finder_deltas[k] - 0.25 ;
348348 double upper_bound = finder_deltas[k] + 0.25 ;
349-
349+
350350 if (pointRatio < lower_bound) {
351351 found = false ;
352352 break ;
@@ -356,7 +356,7 @@ bool extractFinderPoints(int ellipse_id, bool check_high, RotatedRect inner_ring
356356 break ;
357357 }
358358 }
359-
359+
360360 if (found) {
361361 offset = j;
362362 break ;
@@ -445,7 +445,7 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
445445
446446 if (out_progress) {
447447 Mat rgb_colour;
448-
448+
449449 cvtColor (greyscale, rgb_colour, COLOR_GRAY2RGB);
450450
451451 progress = rgb_colour;
@@ -479,11 +479,11 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
479479#endif
480480
481481 Mat contour_mat = whitish.clone ();
482-
482+
483483 // extract the contours and blobs from the thresholded image
484484 vector<vector<Point2i> > contours;
485485 vector<Vec4i> hierarchy;
486-
486+
487487 START_DEBUG_TIMING (contours_1);
488488 findContours (contour_mat, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE, Point2i (0 , 0 ));
489489 END_DEBUG_TIMING (timing, contours_1);
@@ -499,16 +499,16 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
499499 imwrite (" 03_contours.jpg" , contour_debug);
500500 }
501501#endif
502-
502+
503503 // compute the moments of each contour to search for large, roundish, blobs
504504 vector<Moments> mu (contours.size ());
505505 vector<Point2f> mc (contours.size ());
506-
506+
507507 START_DEBUG_TIMING (moment_pass_1);
508508
509509 // find ellipses
510510 Mat ellipse_boundaries = Mat::zeros (contour_mat.size (), CV_8UC1);
511-
511+
512512 for (int i = 0 ; i < contours.size (); ++i) {
513513 vector<Point2i> &contour = contours[i];
514514
@@ -531,7 +531,7 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
531531 }
532532
533533 Moments moment = mu[i];
534-
534+
535535 // the contour must be...
536536 // large enough
537537 const double minimum_ellipse_area = 220 * scaling_rate;
@@ -645,7 +645,7 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
645645#endif
646646
647647 END_DEBUG_TIMING (timing, ellipse_fitting_1);
648-
648+
649649 // only keep edges that share edges with the fitted ellipses
650650 Mat matches_near_ellipses;
651651
@@ -664,7 +664,8 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
664664 for (int j = 0 ; j < contour.size (); ++j) {
665665 Point2i &point = contour[j];
666666
667- if (matches_near_ellipses.at <char >(point.y , point.x ) != 0 ) {
667+ if (point.x >= 0 && point.y >= 0 && point.x < matches_near_ellipses.cols && point.y < matches_near_ellipses.rows
668+ && matches_near_ellipses.at <char >(point.y , point.x ) != 0 ) {
668669 pruned_contour.push_back (point);
669670 }
670671 }
@@ -674,7 +675,7 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
674675
675676 vector<vector<Point2i> > contours2 = pruned_contours;
676677 vector<Vec4i> hierarchy2;
677-
678+
678679 // search the limited edges to find strong ellipse matches
679680 vector<RotatedRect> ellipses;
680681 vector<size_t > contour_indices;
@@ -693,15 +694,15 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
693694
694695 vector<RotatedRect> potential_ellipses;
695696 vector<size_t > potential_contour_indices;
696-
697+
697698 // re-fit the ellipses based on only the filtered points
698699 // and only if the contours have enough points to be useful
699700 // (ellipse fitting requires 5 reference points at a minimum)
700701 START_DEBUG_TIMING (ellipse_fitting_2);
701702 // find all ellipses in the search space by estimating the fit
702703 for (int i = 0 ; i < contours2.size (); ++i) {
703704 vector<Point2i> &contour = contours2[i];
704-
705+
705706 // the contour must be sufficiently dense
706707 // and the mass of the moment must be large enough
707708 if (contour.size () > 5 ) {
@@ -752,7 +753,7 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
752753 imwrite (" 06_candidates.jpg" , candidates);
753754 }
754755#endif
755-
756+
756757 // iterate over each candidate ring and determine if it's really the
757758 // center of a Kik code
758759 START_DEBUG_TIMING (ellipse_search);
@@ -770,12 +771,12 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
770771
771772 size_t dark_count = 0 ;
772773
773- for (int j = 0 ; j < contour.size (); ++j) {
774- Point2i point = contour[j];
774+ for (auto point : contour) {
775775 int x = 0.9 * (point.x - candidate_center.center .x ) + candidate_center.center .x ;
776776 int y = 0.9 * (point.y - candidate_center.center .y ) + candidate_center.center .y ;
777777
778- if (whitish.at <char >(y, x) == 0 ) {
778+ if (x >= 0 && y >= 0 && x < whitish.cols && y < whitish.rows
779+ && whitish.at <char >(y, x) == 0 ) {
779780 ++dark_count;
780781 }
781782 }
@@ -800,7 +801,7 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
800801 if (finder_points.size () != FINDER_POINT_COUNT) {
801802 continue ;
802803 }
803-
804+
804805 double current_angle = M_PI / 16 - M_PI / 2 ;
805806 vector<Point2f> object_finder_points;
806807 vector<Point2f> scene_finder_points;
@@ -811,17 +812,17 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
811812 float modifier = 42 ;
812813 float offset_x = 195.0 ;
813814 float offset_y = 195.0 ;
814-
815+
815816 // create the set of scene points and object points for computing the homography to map
816817 // our exemplar Kik code onto the scene
817818 START_DEBUG_TIMING (generate_scene_points);
818819 for (int j = 0 ; j < finder_points.size (); ++j) {
819820 object_finder_points.push_back (
820821 Point2f (modifier * 2.025 * cos (current_angle) + offset_x, modifier * 2.025 * sin (current_angle) + offset_y));
821-
822+
822823 current_angle += finder_deltas[j];
823824 }
824-
825+
825826 for (int j = 0 ; j < finder_points.size (); ++j) {
826827 FinderPoint point = finder_points[(j+offset) % finder_points.size ()];
827828 scene_finder_points.push_back (Point2f (point.x , point.y ));
@@ -833,29 +834,29 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
833834 START_DEBUG_TIMING (find_homography);
834835 Mat H = findHomography (object_finder_points, scene_finder_points, FM_RANSAC);
835836 END_DEBUG_TIMING (timing, find_homography);
836-
837+
837838 START_DEBUG_TIMING (transform_finder_points);
838839 vector<Point2f> scene_corners (object_finder_points.size ());
839-
840+
840841 perspectiveTransform (object_finder_points, scene_corners, H);
841842 END_DEBUG_TIMING (timing, transform_finder_points);
842843
843844 START_DEBUG_TIMING (transform_all_points);
844845 vector<Point2f> all_points;
845846 vector<Point2f> scene_points;
846-
847+
847848 // generate all positions on the Kik code in the object space
848849 for (int r = 1 ; r < 6 ; ++r) {
849850 size_t n = 32 + 8 * r;
850-
851+
851852 for (int j = 0 ; j < n; ++j) {
852853 double angle = j * M_PI / n * 2 - M_PI / 2 ;
853854 double radius = modifier * ((r + 1 ) * 0.4 + 1.8 );
854-
855+
855856 all_points.push_back (Point2f (radius * cos (angle) + offset_x, radius * sin (angle) + offset_y));
856857 }
857858 }
858-
859+
859860 // map each position in the object-space Kik code on to the scene space
860861 perspectiveTransform (all_points, scene_points, H);
861862 END_DEBUG_TIMING (timing, transform_all_points);
@@ -865,14 +866,14 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
865866 // we always have the finder pattern in the first 32 bits
866867 memset (scan_data, 0 , sizeof (scan_data));
867868 memcpy (scan_data, finder_bytes, sizeof (finder_bytes));
868-
869+
869870 // use the scene-space points to determine the data contained in the Kik code
870871 for (int j = 0 ; j < scene_points.size (); ++j) {
871872 int x = (int )floor (scene_points[j].x );
872873 int y = (int )floor (scene_points[j].y );
873874
874875 size_t pos = j + 32 ;
875-
876+
876877 // at each position, if the data is white (black in the case of inverted-colour
877878 // codes), it's a 1, otherwise it's a 0
878879 if (x >= 0 && y >= 0 && x < whitish.cols && y < whitish.rows ) {
0 commit comments