mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
Add Grana's connected components algorithm for 8-way connectivity. (#6823)
* Add Grana's connected components algorithm for 8-way connectivity. That algorithm is faster than Wu's one (currently implemented in opencv). For more details see https://github.com/prittt/YACCLAB. * New functions signature and distance transform compatibility * Add tests to imgproc/test/test_connectedcomponents.cpp * Change of test_connectedcomponents.cpp for c++98 support
This commit is contained in:
parent
4f0f5a24ef
commit
5ddd25313f
@ -413,6 +413,13 @@ enum ConnectedComponentsTypes {
|
|||||||
CC_STAT_MAX = 5
|
CC_STAT_MAX = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! connected components algorithm
|
||||||
|
enum ConnectedComponentsAlgorithmsTypes {
|
||||||
|
CCL_WU = 0, //!< SAUF algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
|
||||||
|
CCL_DEFAULT = -1, //!< BBDT algortihm for 8-way connectivity, SAUF algorithm for 4-way connectivity
|
||||||
|
CCL_GRANA = 1 //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
|
||||||
|
};
|
||||||
|
|
||||||
//! mode of the contour retrieval algorithm
|
//! mode of the contour retrieval algorithm
|
||||||
enum RetrievalModes {
|
enum RetrievalModes {
|
||||||
/** retrieves only the extreme outer contours. It sets `hierarchy[i][2]=hierarchy[i][3]=-1` for
|
/** retrieves only the extreme outer contours. It sets `hierarchy[i][2]=hierarchy[i][3]=-1` for
|
||||||
@ -3648,16 +3655,56 @@ CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ,
|
|||||||
image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0
|
image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0
|
||||||
represents the background label. ltype specifies the output label image type, an important
|
represents the background label. ltype specifies the output label image type, an important
|
||||||
consideration based on the total number of labels or alternatively the total number of pixels in
|
consideration based on the total number of labels or alternatively the total number of pixels in
|
||||||
the source image.
|
the source image. ccltype specifies the connected components labeling algorithm to use, currently
|
||||||
|
Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes
|
||||||
|
for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not.
|
||||||
|
|
||||||
@param image the 8-bit single-channel image to be labeled
|
@param image the 8-bit single-channel image to be labeled
|
||||||
@param labels destination labeled image
|
@param labels destination labeled image
|
||||||
@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
|
@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
|
||||||
@param ltype output image label type. Currently CV_32S and CV_16U are supported.
|
@param ltype output image label type. Currently CV_32S and CV_16U are supported.
|
||||||
*/
|
@param ccltype connected components algorithm type (see the cv::ConnectedComponentsAlgorithmsTypes).
|
||||||
|
*/
|
||||||
|
CV_EXPORTS_AS(connectedComponentsWithAlgorithm) int connectedComponents(InputArray image, OutputArray labels,
|
||||||
|
int connectivity, int ltype, int ccltype);
|
||||||
|
|
||||||
|
|
||||||
|
/** @overload
|
||||||
|
|
||||||
|
@param image the 8-bit single-channel image to be labeled
|
||||||
|
@param labels destination labeled image
|
||||||
|
@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
|
||||||
|
@param ltype output image label type. Currently CV_32S and CV_16U are supported.
|
||||||
|
*/
|
||||||
CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels,
|
CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels,
|
||||||
int connectivity = 8, int ltype = CV_32S);
|
int connectivity = 8, int ltype = CV_32S);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief computes the connected components labeled image of boolean image and also produces a statistics output for each label
|
||||||
|
|
||||||
|
image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0
|
||||||
|
represents the background label. ltype specifies the output label image type, an important
|
||||||
|
consideration based on the total number of labels or alternatively the total number of pixels in
|
||||||
|
the source image. ccltype specifies the connected components labeling algorithm to use, currently
|
||||||
|
Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes
|
||||||
|
for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not.
|
||||||
|
|
||||||
|
|
||||||
|
@param image the 8-bit single-channel image to be labeled
|
||||||
|
@param labels destination labeled image
|
||||||
|
@param stats statistics output for each label, including the background label, see below for
|
||||||
|
available statistics. Statistics are accessed via stats(label, COLUMN) where COLUMN is one of
|
||||||
|
cv::ConnectedComponentsTypes. The data type is CV_32S.
|
||||||
|
@param centroids centroid output for each label, including the background label. Centroids are
|
||||||
|
accessed via centroids(label, 0) for x and centroids(label, 1) for y. The data type CV_64F.
|
||||||
|
@param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
|
||||||
|
@param ltype output image label type. Currently CV_32S and CV_16U are supported.
|
||||||
|
@param ccltype connected components algorithm type (see the cv::ConnectedComponentsAlgorithmsTypes).
|
||||||
|
*/
|
||||||
|
CV_EXPORTS_AS(connectedComponentsWithStatsWithAlgorithm) int connectedComponentsWithStats(InputArray image, OutputArray labels,
|
||||||
|
OutputArray stats, OutputArray centroids,
|
||||||
|
int connectivity, int ltype, int ccltype);
|
||||||
|
|
||||||
/** @overload
|
/** @overload
|
||||||
@param image the 8-bit single-channel image to be labeled
|
@param image the 8-bit single-channel image to be labeled
|
||||||
@param labels destination labeled image
|
@param labels destination labeled image
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -827,7 +827,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
|
|||||||
if( labelType == CV_DIST_LABEL_CCOMP )
|
if( labelType == CV_DIST_LABEL_CCOMP )
|
||||||
{
|
{
|
||||||
Mat zpix = src == 0;
|
Mat zpix = src == 0;
|
||||||
connectedComponents(zpix, labels, 8, CV_32S);
|
connectedComponents(zpix, labels, 8, CV_32S, CCL_WU);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "test_precomp.hpp"
|
#include "test_precomp.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -58,49 +59,81 @@ protected:
|
|||||||
CV_ConnectedComponentsTest::CV_ConnectedComponentsTest() {}
|
CV_ConnectedComponentsTest::CV_ConnectedComponentsTest() {}
|
||||||
CV_ConnectedComponentsTest::~CV_ConnectedComponentsTest() {}
|
CV_ConnectedComponentsTest::~CV_ConnectedComponentsTest() {}
|
||||||
|
|
||||||
|
// This function force a row major order for the labels
|
||||||
|
void normalizeLabels(Mat1i& imgLabels, int iNumLabels) {
|
||||||
|
vector<int> vecNewLabels(iNumLabels + 1, 0);
|
||||||
|
int iMaxNewLabel = 0;
|
||||||
|
|
||||||
|
for (int r = 0; r<imgLabels.rows; ++r) {
|
||||||
|
for (int c = 0; c<imgLabels.cols; ++c) {
|
||||||
|
int iCurLabel = imgLabels(r, c);
|
||||||
|
if (iCurLabel>0) {
|
||||||
|
if (vecNewLabels[iCurLabel] == 0) {
|
||||||
|
vecNewLabels[iCurLabel] = ++iMaxNewLabel;
|
||||||
|
}
|
||||||
|
imgLabels(r, c) = vecNewLabels[iCurLabel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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 };
|
||||||
|
|
||||||
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);
|
||||||
Mat orig = imread(string(ts->get_data_path()) + "connectedcomponents/concentric_circles.png", 0);
|
Mat orig = imread(string(ts->get_data_path()) + "connectedcomponents/concentric_circles.png", 0);
|
||||||
|
|
||||||
if (orig.empty())
|
if (orig.empty())
|
||||||
{
|
{
|
||||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat bw = orig > 128;
|
Mat bw = orig > 128;
|
||||||
Mat labelImage;
|
|
||||||
int nLabels = connectedComponents(bw, labelImage, 8, CV_32S);
|
|
||||||
|
|
||||||
for(int r = 0; r < labelImage.rows; ++r){
|
for (uint cclt = 0; cclt < sizeof(ccltype)/sizeof(int); ++cclt)
|
||||||
for(int c = 0; c < labelImage.cols; ++c){
|
{
|
||||||
int l = labelImage.at<int>(r, c);
|
|
||||||
bool pass = l >= 0 && l <= nLabels;
|
Mat1i labelImage;
|
||||||
if(!pass){
|
int nLabels = connectedComponents(bw, labelImage, 8, CV_32S, ccltype[cclt]);
|
||||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
|
||||||
return;
|
normalizeLabels(labelImage, nLabels);
|
||||||
|
|
||||||
|
// Validate test results
|
||||||
|
for (int r = 0; r < labelImage.rows; ++r){
|
||||||
|
for (int c = 0; c < labelImage.cols; ++c){
|
||||||
|
int l = labelImage.at<int>(r, c);
|
||||||
|
bool pass = l >= 0 && l <= nLabels;
|
||||||
|
if (!pass){
|
||||||
|
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (exp.empty() || orig.size() != exp.size())
|
||||||
|
{
|
||||||
|
imwrite(exp_path, labelImage);
|
||||||
|
exp = labelImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != cvtest::norm(labelImage > 0, exp > 0, NORM_INF))
|
||||||
|
{
|
||||||
|
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (nLabels != cvtest::norm(labelImage, NORM_INF) + 1)
|
||||||
|
{
|
||||||
|
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( exp.empty() || orig.size() != exp.size() )
|
|
||||||
{
|
|
||||||
imwrite(exp_path, labelImage);
|
|
||||||
exp = labelImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != cvtest::norm(labelImage > 0, exp > 0, NORM_INF))
|
|
||||||
{
|
|
||||||
ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nLabels != cvtest::norm(labelImage, NORM_INF)+1)
|
|
||||||
{
|
|
||||||
ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ts->set_failed_test_info(cvtest::TS::OK);
|
ts->set_failed_test_info(cvtest::TS::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user