diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index d402ea91c3..e6285bdecd 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -261,13 +261,24 @@ namespace cv{ template inline static - void flattenL(LabelT *P, const int start, const int nElem, LabelT& k){ + void checkLabelTypeOverflowBeforeIncrement(const LabelT numLabels) { + constexpr LabelT maxLabelTypeValue = std::numeric_limits::max(); + CV_CheckLT( + numLabels, + maxLabelTypeValue, + "Total number of labels overflowed label type. Try using CV_32S instead of CV_16U as ltype"); + } + + template + inline static + void flattenLParallel(LabelT *P, const int start, const int nElem, LabelT& k){ for (int i = start; i < start + nElem; ++i){ if (P[i] < i){//node that point to root P[i] = P[P[i]]; } else{ //for root node P[i] = k; + checkLabelTypeOverflowBeforeIncrement(k); k = k + 1; } } @@ -353,6 +364,7 @@ namespace cv{ // Action 2: New label (the block has foreground pixels and is not connected to anything else) #define ACTION_2 img_labels_row[c] = label; \ P_[label] = label; \ + checkLabelTypeOverflowBeforeIncrement(label); \ label = label + 1; //Action 3: Assign label of block P #define ACTION_3 img_labels_row[c] = img_labels_row_prev_prev[c - 2]; @@ -1160,7 +1172,7 @@ namespace cv{ LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]) { CV_DbgAssert(i + 1 < chunksSizeAndLabelsSize); - flattenL(P.data(), stripeFirstLabel8Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); + flattenLParallel(P.data(), stripeFirstLabel8Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics data @@ -1261,6 +1273,7 @@ namespace cv{ // Action 2: New label (the block has foreground pixels and is not connected to anything else) #define ACTION_2 img_labels_row[c] = lunique; \ P[lunique] = lunique; \ + checkLabelTypeOverflowBeforeIncrement(lunique); \ lunique = lunique + 1; //Action 3: Assign label of block P #define ACTION_3 img_labels_row[c] = img_labels_row_prev_prev[c - 2]; @@ -1789,7 +1802,7 @@ namespace cv{ mergeLabels(imgLabels, P, chunksSizeAndLabels.data()); for (int i = 0; i < h; i = chunksSizeAndLabels[i]) { - flattenL(P, stripeFirstLabel4Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); + flattenLParallel(P, stripeFirstLabel4Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics dataof threads @@ -1854,6 +1867,7 @@ namespace cv{ #define ACTION_1 img_labels_row[c] = 0; #define ACTION_2 img_labels_row[c] = lunique; \ P[lunique] = lunique; \ + checkLabelTypeOverflowBeforeIncrement(lunique); \ lunique = lunique + 1; // new label #define ACTION_3 img_labels_row[c] = img_labels_row_prev[c]; // x <- q #define ACTION_4 img_labels_row[c] = img_labels_row[c - 1]; // x <- s @@ -2052,6 +2066,7 @@ namespace cv{ //new label imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; } } @@ -2135,6 +2150,7 @@ namespace cv{ //new label imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; } } @@ -2320,7 +2336,7 @@ namespace cv{ mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels.data()); for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, stripeFirstLabel8Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); + flattenLParallel(P, stripeFirstLabel8Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); } } else{ @@ -2331,7 +2347,7 @@ namespace cv{ mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels.data()); for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, stripeFirstLabel4Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); + flattenLParallel(P, stripeFirstLabel4Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); } } @@ -2433,6 +2449,7 @@ namespace cv{ //new label imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; } } @@ -2483,6 +2500,7 @@ namespace cv{ //new label imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; } } @@ -3108,6 +3126,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; continue; } @@ -3130,6 +3149,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; continue; } @@ -3483,6 +3503,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; continue; } @@ -3507,6 +3528,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; continue; } @@ -3550,6 +3572,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; continue; } @@ -3561,6 +3584,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; P_[label] = label; + checkLabelTypeOverflowBeforeIncrement(label); label = label + 1; continue; } @@ -4260,7 +4284,7 @@ namespace cv{ LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ CV_DbgAssert(i + 1 < chunksSizeAndLabelsSize); - flattenL(P.data(), stripeFirstLabel8Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); + flattenLParallel(P.data(), stripeFirstLabel8Connectivity(i, w), chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics data @@ -4865,6 +4889,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; continue; } @@ -4887,6 +4912,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; continue; } @@ -5240,6 +5266,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; continue; } @@ -5264,6 +5291,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; continue; } @@ -5307,6 +5335,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; continue; } @@ -5318,6 +5347,7 @@ namespace cv{ //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; + checkLabelTypeOverflowBeforeIncrement(lunique); lunique = lunique + 1; continue; } diff --git a/modules/imgproc/test/test_connectedcomponents.cpp b/modules/imgproc/test/test_connectedcomponents.cpp index 8717217cdf..7c4cebaa76 100644 --- a/modules/imgproc/test/test_connectedcomponents.cpp +++ b/modules/imgproc/test/test_connectedcomponents.cpp @@ -798,7 +798,47 @@ TEST(Imgproc_ConnectedComponents, 4conn_regression_21366) } } +TEST(Imgproc_ConnectedComponents, regression_27568) +{ + Mat image = Mat::zeros(Size(512, 512), CV_8UC1); + for (int row = 0; row < image.rows; row += 2) + { + for (int col = 0; col < image.cols; col += 2) + { + image.at(row, col) = 1; + } + } + for (const int connectivity : {4, 8}) + { + for (const int ccltype : {CCL_DEFAULT, CCL_WU, CCL_GRANA, CCL_BOLELLI, CCL_SAUF, CCL_BBDT, CCL_SPAGHETTI}) + { + { + Mat labels, stats, centroids; + try + { + connectedComponentsWithStats( + image, labels, stats, centroids, connectivity, CV_16U, ccltype); + ADD_FAILURE(); + } + catch (const Exception& exception) + { + EXPECT_TRUE( + strstr( + exception.what(), + "Total number of labels overflowed label type. Try using CV_32S instead of CV_16U as ltype")); + } + } + + { + Mat labels, stats, centroids; + EXPECT_NO_THROW( + connectedComponentsWithStats( + image, labels, stats, centroids, connectivity, CV_32S, ccltype)); + } + } + } +} } } // namespace