Merge pull request #19951 from stal12:3.4
authorStefano Allegretti <stefano.allegretti94@gmail.com>
Thu, 22 Apr 2021 18:20:12 +0000 (20:20 +0200)
committerGitHub <noreply@github.com>
Thu, 22 Apr 2021 18:20:12 +0000 (18:20 +0000)
* Fix #4363 - wrong hierarchy (CV_RETR_TREE) in findContours

* Add regression test for findContours

* use C++11 => C++98 on 3.4 branch

modules/imgproc/src/contours.cpp
modules/imgproc/test/test_contours.cpp

index e433cdb514eba4f9f9f6b1e60b49206650f5492a..241f1443f5c862dd15f89fbcd5e74ac7d69c80db 100644 (file)
@@ -625,7 +625,8 @@ icvFetchContour( schar                  *ptr,
 
 /*
    trace contour until certain point is met.
-   returns 1 if met, 0 else.
+   returns 1 if met and this is the last contour
+   encountered by a raster scan reaching the point, 0 else.
 */
 static int
 icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
@@ -668,14 +669,39 @@ icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
                     break;
             }
 
-            if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
+            if (i3 == stop_ptr) {
+                if (!(*i3 & 0x80)) {
+                    /* it's the only contour */
+                    return 1;
+                }
+
+                /* check if this is the last contour */
+                /* encountered during a raster scan  */
+                schar *i5;
+                int t = s;
+                while (true)
+                {
+                    t = (t - 1) & 7;
+                    i5 = i3 + deltas[t];
+                    if (*i5 != 0)
+                        break;
+                    if (t == 0)
+                        return 1;
+                }
+            }
+
+            if( (i4 == i0 && i3 == i1) )
                 break;
 
             i3 = i4;
             s = (s + 4) & 7;
         }                       /* end of border following loop */
     }
-    return i3 == stop_ptr;
+    else {
+        return i3 == stop_ptr;
+    }
+
+    return 0;
 }
 
 
index a5c924829de7eafdb1fc0298f28146b180873fe0..c07d19098b8915b734e53145df5a88a4342ff716 100644 (file)
@@ -485,6 +485,55 @@ TEST(Imgproc_FindContours, border)
     ASSERT_EQ(0, cvtest::norm(img, img_draw_contours, NORM_INF));
 }
 
+TEST(Imgproc_FindContours, regression_4363_shared_nbd)
+{
+    // Create specific test image
+    Mat1b img(12, 69, (const uchar&)0);
+
+    img(1, 1) = 1;
+
+    // Vertical rectangle with hole sharing the same NBD
+    for (int r = 1; r <= 10; ++r) {
+        for (int c = 3; c <= 5; ++c) {
+            img(r, c) = 1;
+        }
+    }
+    img(9, 4) = 0;
+
+    // 124 small CCs
+    for (int r = 1; r <= 7; r += 2) {
+        for (int c = 7; c <= 67; c += 2) {
+            img(r, c) = 1;
+        }
+    }
+
+    // Last CC
+    img(9, 7) = 1;
+
+    vector< vector<Point> > contours;
+    vector<Vec4i> hierarchy;
+    findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
+
+    bool found = false;
+    size_t index = 0;
+    for (vector< vector<Point> >::const_iterator i = contours.begin(); i != contours.end(); ++i)
+    {
+        const vector<Point>& c = *i;
+        if (!c.empty() && c[0] == Point(7, 9))
+        {
+            found = true;
+            index = (size_t)(i - contours.begin());
+            break;
+        }
+    }
+    EXPECT_TRUE(found) << "Desired result: point (7,9) is a contour - Actual result: point (7,9) is not a contour";
+
+    if (found)
+    {
+        EXPECT_LT(hierarchy[index][3], 0) << "Desired result: (7,9) has no parent - Actual result: parent of (7,9) is another contour. index = " << index;
+    }
+}
+
 TEST(Imgproc_PointPolygonTest, regression_10222)
 {
     vector<Point> contour;