Fix signed integer overflow in connected components
authorGil Shotan <gilsho@cs.stanford.edu>
Thu, 10 Sep 2020 23:47:53 +0000 (02:47 +0300)
committerGil Shotan <gilsho@cs.stanford.edu>
Sun, 13 Sep 2020 11:20:42 +0000 (11:20 +0000)
modules/imgproc/src/connectedcomponents.cpp
modules/imgproc/test/test_connectedcomponents.cpp

index 2e06be4f98a70afeeabd838089f340cfd224e3af..c3a3f6f75b124f786522a00a8f209000471a036e 100644 (file)
@@ -145,14 +145,21 @@ namespace cv{
         void finish(){
             for (int l = 0; l < statsv.rows; ++l){
                 int *row =& statsv.at<int>(l, 0);
-                row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1;
-                row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1;
-
-                Point2ui64& integral = integrals[l];
-                double *centroid = &centroidsv.at<double>(l, 0);
                 double area = ((unsigned*)row)[CC_STAT_AREA];
-                centroid[0] = double(integral.x) / area;
-                centroid[1] = double(integral.y) / area;
+                double *centroid = &centroidsv.at<double>(l, 0);
+                if (area > 0){
+                    row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1;
+                    row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1;
+                    Point2ui64& integral = integrals[l];
+                    centroid[0] = double(integral.x) / area;
+                    centroid[1] = double(integral.y) / area;
+                } else {
+                    row[CC_STAT_WIDTH] = 0;
+                    row[CC_STAT_HEIGHT] = 0;
+                    row[CC_STAT_LEFT] = -1;
+                    centroid[0] = std::numeric_limits<double>::quiet_NaN();
+                    centroid[1] = std::numeric_limits<double>::quiet_NaN();
+                }
             }
         }
 
index 5952577691077df2368fc52347b33837752f29f4..bc5c9f0a23c93810a0b8dd1884d86ce8064fa3bc 100644 (file)
@@ -225,5 +225,19 @@ TEST(Imgproc_ConnectedComponents, parallel_wu_labels)
     EXPECT_EQ(nbPixels, area);
 }
 
+TEST(Imgproc_ConnectedComponents, missing_background_pixels)
+{
+    cv::Mat m = Mat::ones(10, 10, CV_8U);
+    cv::Mat labels;
+    cv::Mat stats;
+    cv::Mat centroids;
+    EXPECT_NO_THROW(cv::connectedComponentsWithStats(m, labels, stats, centroids, 8, CV_32S, cv::CCL_WU) );
+    EXPECT_EQ(stats.at<int32_t>(0, cv::CC_STAT_WIDTH), 0);
+    EXPECT_EQ(stats.at<int32_t>(0, cv::CC_STAT_HEIGHT), 0);
+    EXPECT_EQ(stats.at<int32_t>(0, cv::CC_STAT_LEFT), -1);
+    EXPECT_TRUE(std::isnan(centroids.at<double>(0, 0)));
+    EXPECT_TRUE(std::isnan(centroids.at<double>(0, 1)));
+}
+
 
 }} // namespace