未验证 提交 96951658 编写于 作者: F Federico Bolelli 提交者: GitHub

Merge pull request #19631 from prittt:sota-ccl

* Add Spaghetti algorithm for CCL

* Add stat tests for new and old algorithms

* Switch license header to short version
上级 1a855fed
...@@ -110,6 +110,29 @@ ...@@ -110,6 +110,29 @@
year = {2010}, year = {2010},
url = {http://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf} url = {http://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf}
} }
@inproceedings{Bolelli2017,
title = {{Two More Strategies to Speed Up Connected Components Labeling Algorithms}},
author = {Bolelli, Federico and Cancilla, Michele and Grana, Costantino},
year = 2017,
booktitle = {Image Analysis and Processing - ICIAP 2017},
publisher = {Springer},
volume = 10485,
pages = {48--58},
doi = {10.1007/978-3-319-68548-9_5},
isbn = {978-3-319-68547-2}
}
@article{Bolelli2019,
title = {{Spaghetti Labeling: Directed Acyclic Graphs for Block-Based Connected Components Labeling}},
author = {Bolelli, Federico and Allegretti, Stefano and Baraldi, Lorenzo and Grana, Costantino},
year = 2019,
journal = {IEEE Transactions on Image Processing},
publisher = {IEEE},
volume = 29,
number = 1,
pages = {1999--2012},
doi = {10.1109/TIP.2019.2946979},
issn = {1057-7149}
}
@article{Borgefors86, @article{Borgefors86,
author = {Borgefors, Gunilla}, author = {Borgefors, Gunilla},
title = {Distance transformations in digital images}, title = {Distance transformations in digital images},
...@@ -420,6 +443,16 @@ ...@@ -420,6 +443,16 @@
volume = {51}, volume = {51},
pages = {378-384} pages = {378-384}
} }
@article{Grana2010,
title = {{Optimized Block-Based Connected Components Labeling With Decision Trees}},
author = {Grana, Costantino and Borghesani, Daniele and Cucchiara, Rita},
year = 2010,
journal = {IEEE Transactions on Image Processing},
volume = 19,
number = 6,
pages = {1596--1609},
doi = {10.1109/TIP.2010.2044963}
}
@article{taubin1991, @article{taubin1991,
abstract = {The author addresses the problem of parametric representation and estimation of complex planar curves in 2-D surfaces in 3-D, and nonplanar space curves in 3-D. Curves and surfaces can be defined either parametrically or implicitly, with the latter representation used here. A planar curve is the set of zeros of a smooth function of two variables <e1>x</e1>-<e1>y</e1>, a surface is the set of zeros of a smooth function of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1>, and a space curve is the intersection of two surfaces, which are the set of zeros of two linearly independent smooth functions of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1> For example, the surface of a complex object in 3-D can be represented as a subset of a single implicit surface, with similar results for planar and space curves. It is shown how this unified representation can be used for object recognition, object position estimation, and segmentation of objects into meaningful subobjects, that is, the detection of `interest regions' that are more complex than high curvature regions and, hence, more useful as features for object recognition}, abstract = {The author addresses the problem of parametric representation and estimation of complex planar curves in 2-D surfaces in 3-D, and nonplanar space curves in 3-D. Curves and surfaces can be defined either parametrically or implicitly, with the latter representation used here. A planar curve is the set of zeros of a smooth function of two variables <e1>x</e1>-<e1>y</e1>, a surface is the set of zeros of a smooth function of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1>, and a space curve is the intersection of two surfaces, which are the set of zeros of two linearly independent smooth functions of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1> For example, the surface of a complex object in 3-D can be represented as a subset of a single implicit surface, with similar results for planar and space curves. It is shown how this unified representation can be used for object recognition, object position estimation, and segmentation of objects into meaningful subobjects, that is, the detection of `interest regions' that are more complex than high curvature regions and, hence, more useful as features for object recognition},
author = {Taubin, Gabriel}, author = {Taubin, Gabriel},
......
...@@ -406,9 +406,13 @@ enum ConnectedComponentsTypes { ...@@ -406,9 +406,13 @@ enum ConnectedComponentsTypes {
//! connected components algorithm //! connected components algorithm
enum ConnectedComponentsAlgorithmsTypes { enum ConnectedComponentsAlgorithmsTypes {
CCL_WU = 0, //!< SAUF @cite Wu2009 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity CCL_DEFAULT = -1, //!< BBDT @cite Grana2010 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for both BBDT and SAUF.
CCL_DEFAULT = -1, //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity CCL_WU = 0, //!< SAUF @cite Wu2009 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for SAUF.
CCL_GRANA = 1 //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity CCL_GRANA = 1, //!< BBDT @cite Grana2010 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. The parallel implementation described in @cite Bolelli2017 is available for both BBDT and SAUF.
CCL_BOLELLI = 2, //!< Spaghetti @cite Bolelli2019 algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity.
CCL_SAUF = 3, //!< Same as CCL_WU. It is preferable to use the flag with the name of the algorithm (CCL_SAUF) rather than the one with the name of the first author (CCL_WU).
CCL_BBDT = 4, //!< Same as CCL_GRANA. It is preferable to use the flag with the name of the algorithm (CCL_BBDT) rather than the one with the name of the first author (CCL_GRANA).
CCL_SPAGHETTI = 5, //!< Same as CCL_BOLELLI. It is preferable to use the flag with the name of the algorithm (CCL_SPAGHETTI) rather than the one with the name of the first author (CCL_BOLELLI).
}; };
//! mode of the contour retrieval algorithm //! mode of the contour retrieval algorithm
......
此差异已折叠。
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// 2021 Federico Bolelli <federico.bolelli@unimore.it>
// 2021 Stefano Allegretti <stefano.allegretti@unimore.it>
// 2021 Costantino Grana <costantino.grana@unimore.it>
//
// This file has been automatically generated using GRAPHGEN (https://github.com/prittt/GRAPHGEN)
// and taken from the YACCLAB repository (https://github.com/prittt/YACCLAB).
fl_tree_0: if ((c+=2) >= w - 2) { if (c > w - 2) { goto fl_break_0_0; } else { goto fl_break_1_0; } }
if (CONDITION_O) {
NODE_253:
if (CONDITION_P) {
ACTION_2
goto fl_tree_1;
}
else {
ACTION_2
goto fl_tree_2;
}
}
else {
if (CONDITION_S){
goto NODE_253;
}
else {
NODE_255:
if (CONDITION_P) {
ACTION_2
goto fl_tree_1;
}
else {
if (CONDITION_T) {
ACTION_2
goto fl_tree_1;
}
else {
ACTION_1
goto fl_tree_0;
}
}
}
}
fl_tree_1: if ((c+=2) >= w - 2) { if (c > w - 2) { goto fl_break_0_1; } else { goto fl_break_1_1; } }
if (CONDITION_O) {
NODE_257:
if (CONDITION_P) {
ACTION_6
goto fl_tree_1;
}
else {
ACTION_6
goto fl_tree_2;
}
}
else {
if (CONDITION_S){
goto NODE_257;
}
else{
goto NODE_255;
}
}
fl_tree_2: if ((c+=2) >= w - 2) { if (c > w - 2) { goto fl_break_0_2; } else { goto fl_break_1_2; } }
if (CONDITION_O) {
if (CONDITION_R){
goto NODE_257;
}
else{
goto NODE_253;
}
}
else {
if (CONDITION_S) {
if (CONDITION_P) {
if (CONDITION_R) {
ACTION_6
goto fl_tree_1;
}
else {
ACTION_2
goto fl_tree_1;
}
}
else {
if (CONDITION_R) {
ACTION_6
goto fl_tree_2;
}
else {
ACTION_2
goto fl_tree_2;
}
}
}
else{
goto NODE_255;
}
}
fl_break_0_0:
if (CONDITION_O) {
ACTION_2
}
else {
if (CONDITION_S) {
ACTION_2
}
else {
ACTION_1
}
}
goto end_fl;
fl_break_0_1:
if (CONDITION_O) {
ACTION_6
}
else {
if (CONDITION_S) {
ACTION_6
}
else {
ACTION_1
}
}
goto end_fl;
fl_break_0_2:
if (CONDITION_O) {
NODE_266:
if (CONDITION_R) {
ACTION_6
}
else {
ACTION_2
}
}
else {
if (CONDITION_S){
goto NODE_266;
}
else {
ACTION_1
}
}
goto end_fl;
fl_break_1_0:
if (CONDITION_O) {
NODE_268:
if (CONDITION_P) {
ACTION_2
}
else {
ACTION_2
}
}
else {
if (CONDITION_S){
goto NODE_268;
}
else {
NODE_270:
if (CONDITION_P) {
ACTION_2
}
else {
if (CONDITION_T) {
ACTION_2
}
else {
ACTION_1
}
}
}
}
goto end_fl;
fl_break_1_1:
if (CONDITION_O) {
NODE_272:
if (CONDITION_P) {
ACTION_6
}
else {
ACTION_6
}
}
else {
if (CONDITION_S){
goto NODE_272;
}
else{
goto NODE_270;
}
}
goto end_fl;
fl_break_1_2:
if (CONDITION_O) {
if (CONDITION_R){
goto NODE_272;
}
else{
goto NODE_268;
}
}
else {
if (CONDITION_S) {
if (CONDITION_P){
goto NODE_266;
}
else{
goto NODE_266;
}
}
else{
goto NODE_270;
}
}
goto end_fl;
end_fl:;
此差异已折叠。
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// 2021 Federico Bolelli <federico.bolelli@unimore.it>
// 2021 Stefano Allegretti <stefano.allegretti@unimore.it>
// 2021 Costantino Grana <costantino.grana@unimore.it>
//
// This file has been automatically generated using GRAPHGEN (https://github.com/prittt/GRAPHGEN)
// and taken from the YACCLAB repository (https://github.com/prittt/YACCLAB).
sl_tree_0: if ((c+=2) >= w - 2) { if (c > w - 2) { goto sl_break_0_0; } else { goto sl_break_1_0; } }
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_2
goto sl_tree_1;
}
else {
ACTION_2
goto sl_tree_0;
}
}
else {
NODE_372:
if (CONDITION_P) {
ACTION_2
goto sl_tree_1;
}
else {
ACTION_1
goto sl_tree_0;
}
}
sl_tree_1: if ((c+=2) >= w - 2) { if (c > w - 2) { goto sl_break_0_1; } else { goto sl_break_1_1; } }
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_6
goto sl_tree_1;
}
else {
ACTION_6
goto sl_tree_0;
}
}
else{
goto NODE_372;
}
sl_break_0_0:
if (CONDITION_O) {
ACTION_2
}
else {
ACTION_1
}
goto end_sl;
sl_break_0_1:
if (CONDITION_O) {
ACTION_6
}
else {
ACTION_1
}
goto end_sl;
sl_break_1_0:
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_2
}
else {
ACTION_2
}
}
else {
NODE_375:
if (CONDITION_P) {
ACTION_2
}
else {
ACTION_1
}
}
goto end_sl;
sl_break_1_1:
if (CONDITION_O) {
if (CONDITION_P) {
ACTION_6
}
else {
ACTION_6
}
}
else{
goto NODE_375;
}
goto end_sl;
end_sl:;
...@@ -74,11 +74,10 @@ void normalizeLabels(Mat1i& imgLabels, int iNumLabels) { ...@@ -74,11 +74,10 @@ void normalizeLabels(Mat1i& imgLabels, int iNumLabels) {
} }
} }
void CV_ConnectedComponentsTest::run( int /* start_from */) void CV_ConnectedComponentsTest::run( int /* start_from */)
{ {
int ccltype[] = { cv::CCL_WU, cv::CCL_DEFAULT, cv::CCL_GRANA }; int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
string exp_path = string(ts->get_data_path()) + "connectedcomponents/ccomp_exp.png"; string exp_path = string(ts->get_data_path()) + "connectedcomponents/ccomp_exp.png";
Mat exp = imread(exp_path, 0); Mat exp = imread(exp_path, 0);
...@@ -150,7 +149,6 @@ TEST(Imgproc_ConnectedComponents, grana_buffer_overflow) ...@@ -150,7 +149,6 @@ TEST(Imgproc_ConnectedComponents, grana_buffer_overflow)
EXPECT_EQ(1, nbComponents); EXPECT_EQ(1, nbComponents);
} }
static cv::Mat createCrashMat(int numThreads) { static cv::Mat createCrashMat(int numThreads) {
const int h = numThreads * 4 * 2 + 8; const int h = numThreads * 4 * 2 + 8;
const double nParallelStripes = std::max(1, std::min(h / 2, numThreads * 4)); const double nParallelStripes = std::max(1, std::min(h / 2, numThreads * 4));
...@@ -239,5 +237,124 @@ TEST(Imgproc_ConnectedComponents, missing_background_pixels) ...@@ -239,5 +237,124 @@ TEST(Imgproc_ConnectedComponents, missing_background_pixels)
EXPECT_TRUE(std::isnan(centroids.at<double>(0, 1))); EXPECT_TRUE(std::isnan(centroids.at<double>(0, 1)));
} }
TEST(Imgproc_ConnectedComponents, spaghetti_bbdt_sauf_stats)
{
cv::Mat1b img(16, 16);
img << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1;
cv::Mat1i labels;
cv::Mat1i stats;
cv::Mat1d centroids;
int ccltype[] = { cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI };
for (uint cclt = 0; cclt < sizeof(ccltype) / sizeof(int); ++cclt) {
EXPECT_NO_THROW(cv::connectedComponentsWithStats(img, labels, stats, centroids, 8, CV_32S, ccltype[cclt]));
EXPECT_EQ(stats(0, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(0, cv::CC_STAT_TOP), 0);
EXPECT_EQ(stats(0, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(0, cv::CC_STAT_HEIGHT), 15);
EXPECT_EQ(stats(0, cv::CC_STAT_AREA), 144);
EXPECT_EQ(stats(1, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(1, cv::CC_STAT_TOP), 1);
EXPECT_EQ(stats(1, cv::CC_STAT_WIDTH), 3);
EXPECT_EQ(stats(1, cv::CC_STAT_HEIGHT), 3);
EXPECT_EQ(stats(1, cv::CC_STAT_AREA), 9);
EXPECT_EQ(stats(2, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(2, cv::CC_STAT_TOP), 1);
EXPECT_EQ(stats(2, cv::CC_STAT_WIDTH), 8);
EXPECT_EQ(stats(2, cv::CC_STAT_HEIGHT), 7);
EXPECT_EQ(stats(2, cv::CC_STAT_AREA), 40);
EXPECT_EQ(stats(3, cv::CC_STAT_LEFT), 10);
EXPECT_EQ(stats(3, cv::CC_STAT_TOP), 2);
EXPECT_EQ(stats(3, cv::CC_STAT_WIDTH), 5);
EXPECT_EQ(stats(3, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(3, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(4, cv::CC_STAT_LEFT), 11);
EXPECT_EQ(stats(4, cv::CC_STAT_TOP), 5);
EXPECT_EQ(stats(4, cv::CC_STAT_WIDTH), 3);
EXPECT_EQ(stats(4, cv::CC_STAT_HEIGHT), 3);
EXPECT_EQ(stats(4, cv::CC_STAT_AREA), 9);
EXPECT_EQ(stats(5, cv::CC_STAT_LEFT), 2);
EXPECT_EQ(stats(5, cv::CC_STAT_TOP), 9);
EXPECT_EQ(stats(5, cv::CC_STAT_WIDTH), 1);
EXPECT_EQ(stats(5, cv::CC_STAT_HEIGHT), 1);
EXPECT_EQ(stats(5, cv::CC_STAT_AREA), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_LEFT), 12);
EXPECT_EQ(stats(6, cv::CC_STAT_TOP), 9);
EXPECT_EQ(stats(6, cv::CC_STAT_WIDTH), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_HEIGHT), 1);
EXPECT_EQ(stats(6, cv::CC_STAT_AREA), 1);
// Labels' order could be different!
if (cclt == cv::CCL_WU || cclt == cv::CCL_SAUF) {
// CCL_SAUF, CCL_WU
EXPECT_EQ(stats(9, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(9, cv::CC_STAT_TOP), 11);
EXPECT_EQ(stats(9, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(9, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(9, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(7, cv::CC_STAT_LEFT), 6);
EXPECT_EQ(stats(7, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(7, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(7, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(7, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(8, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(8, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(8, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(8, cv::CC_STAT_HEIGHT), 6);
EXPECT_EQ(stats(8, cv::CC_STAT_AREA), 21);
}
else {
// CCL_BBDT, CCL_GRANA, CCL_SPAGHETTI, CCL_BOLELLI
EXPECT_EQ(stats(7, cv::CC_STAT_LEFT), 1);
EXPECT_EQ(stats(7, cv::CC_STAT_TOP), 11);
EXPECT_EQ(stats(7, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(7, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(7, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(8, cv::CC_STAT_LEFT), 6);
EXPECT_EQ(stats(8, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(8, cv::CC_STAT_WIDTH), 4);
EXPECT_EQ(stats(8, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(8, cv::CC_STAT_AREA), 8);
EXPECT_EQ(stats(9, cv::CC_STAT_LEFT), 0);
EXPECT_EQ(stats(9, cv::CC_STAT_TOP), 10);
EXPECT_EQ(stats(9, cv::CC_STAT_WIDTH), 16);
EXPECT_EQ(stats(9, cv::CC_STAT_HEIGHT), 6);
EXPECT_EQ(stats(9, cv::CC_STAT_AREA), 21);
}
EXPECT_EQ(stats(10, cv::CC_STAT_LEFT), 9);
EXPECT_EQ(stats(10, cv::CC_STAT_TOP), 12);
EXPECT_EQ(stats(10, cv::CC_STAT_WIDTH), 5);
EXPECT_EQ(stats(10, cv::CC_STAT_HEIGHT), 2);
EXPECT_EQ(stats(10, cv::CC_STAT_AREA), 7);
}
}
}} // namespace }} // namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册