Skip to content

Commit

Permalink
Converted the internal representation of the labels from unsigned cha…
Browse files Browse the repository at this point in the history
…r to int, in order to support larger no of connected components.
  • Loading branch information
Saburo Okita authored and Saburo Okita committed Jun 7, 2014
1 parent 4963e5e commit b7fdc6c
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 44 deletions.
46 changes: 27 additions & 19 deletions ConnectedComponent/ConnectedComponent/ConnectedComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,59 @@
//

#include "ConnectedComponent.h"
#include <stdexcept>

using namespace std;
using namespace cv;

ConnectedComponent::ConnectedComponent(){
ConnectedComponent::ConnectedComponent( int max_component )
: maxComponent( max_component ){
}

ConnectedComponent::~ConnectedComponent(){
}

/**
* Apply connected component labelling
* it only works for maximum 255 connected components
* Apply connected component labeling
* it only works for predefined maximum no of connected components
* and currently treat black color as background
*/
Mat ConnectedComponent::apply( const Mat& image ) {
CV_Assert( image.type() == CV_8UC1 );

Mat result = image.clone();

/* First pass, labelling the regions incrementally */
result.convertTo( result, CV_32SC1 );

/* First pass, labeling the regions incrementally */
nextLabel = 1;
vector<uchar> linked(255);

uchar * prev_ptr = NULL;
vector<int> linked(maxComponent);
int * prev_ptr = NULL;
for( int y = 0; y < result.rows; y++ ) {
uchar * curr_ptr = result.ptr<uchar>(y);
int * curr_ptr = result.ptr<int>(y);

for( int x = 0; x < result.cols; x++ ) {

if( curr_ptr[x] != 0 ) {
vector<uchar> neighbors = getNeighbors( curr_ptr, prev_ptr, x, y, result.cols );
vector<int> neighbors = getNeighbors( curr_ptr, prev_ptr, x, y, result.cols );

if( neighbors.empty() ) {
curr_ptr[x] = nextLabel;
nextLabel++;

CV_Assert( nextLabel < 255 );
if( nextLabel >= maxComponent ) {
stringstream ss;
ss << "Current label count [" << (int) nextLabel
<< "] exceeds maximum no of components [" << maxComponent << "]";
throw std::runtime_error( ss.str() );
}
}
else {
/* Use the minimum label out from the neighbors */
int min_index = (int) (min_element( neighbors.begin(), neighbors.end() ) - neighbors.begin());
curr_ptr[x] = neighbors[min_index];

for( uchar neighbor: neighbors )
for( int neighbor: neighbors )
disjointUnion( curr_ptr[x], neighbor, linked );
}
}
Expand All @@ -61,9 +69,9 @@ Mat ConnectedComponent::apply( const Mat& image ) {

/* Second pass merge the equivalent labels */
nextLabel = 1;
vector<uchar> temp, labels_set(255);
vector<int> temp, labels_set(maxComponent);
for( int y = 0; y < result.rows; y++ ) {
uchar * curr_ptr = result.ptr<uchar>(y);
int * curr_ptr = result.ptr<int>(y);

for( int x = 0; x < result.cols; x++ ) {
if( curr_ptr[x] != 0 ) {
Expand Down Expand Up @@ -95,7 +103,7 @@ int ConnectedComponent::getComponentsCount() {
* Disjoint set union function, taken from
* https://courses.cs.washington.edu/courses/cse576/02au/homework/hw3/ConnectComponent.java
*/
void ConnectedComponent::disjointUnion( uchar a, uchar b, vector<uchar>& parent ) {
void ConnectedComponent::disjointUnion( int a, int b, vector<int>& parent ) {
while( parent[a] > 0 )
a = parent[a];
while( parent[b] > 0 )
Expand All @@ -113,7 +121,7 @@ void ConnectedComponent::disjointUnion( uchar a, uchar b, vector<uchar>& parent
* Disjoint set find function, taken from
* https://courses.cs.washington.edu/courses/cse576/02au/homework/hw3/ConnectComponent.java
*/
uchar ConnectedComponent::disjointFind( uchar a, vector<uchar>& parent, vector<uchar>& labels ) {
int ConnectedComponent::disjointFind( int a, vector<int>& parent, vector<int>& labels ) {
while( parent[a] > 0 )
a = parent[a];
if( labels[a] == 0 )
Expand All @@ -129,8 +137,8 @@ uchar ConnectedComponent::disjointFind( uchar a, vector<uchar>& parent, vector<u
*
* returns a vector of that contains unique neighbor labels
*/
vector<uchar> ConnectedComponent::getNeighbors( uchar * curr_ptr, uchar * prev_ptr, int x, int y, int cols ) {
vector<uchar> neighbors;
vector<int> ConnectedComponent::getNeighbors( int * curr_ptr, int * prev_ptr, int x, int y, int cols ) {
vector<int> neighbors;

/* Actually we only consider pixel 1, 2, 3, and 4 */
/* At this point of time, the logic hasn't traversed thru 5, 6, 7, 8 */
Expand All @@ -151,7 +159,7 @@ vector<uchar> ConnectedComponent::getNeighbors( uchar * curr_ptr, uchar * prev_p

/* Reduce to unique labels */
/* This is because I'm not using set (it doesn't have random element access) */
vector<uchar> result;
vector<int> result;
if( !neighbors.empty() ) {
std::sort( neighbors.begin(), neighbors.end() );
std::unique_copy( neighbors.begin(), neighbors.end(), std::back_inserter( result ) );
Expand Down
17 changes: 9 additions & 8 deletions ConnectedComponent/ConnectedComponent/ConnectedComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,28 @@


/**
* Connected component labelling using 8-connected neighbors, based on
* Connected component labeling using 8-connected neighbors, based on
* http://en.wikipedia.org/wiki/Connected-component_labeling
*
* with disjoint union and find functions adapted from :
* https://courses.cs.washington.edu/courses/cse576/02au/homework/hw3/ConnectComponent.java
*/
class ConnectedComponent {
public:
ConnectedComponent();
ConnectedComponent( int max_component = 1000 );
virtual ~ConnectedComponent();
cv::Mat apply( const cv::Mat& image );
int getComponentsCount();

protected:
void disjointUnion( uchar a, uchar b, std::vector<uchar>& parent );
uchar disjointFind( uchar a, std::vector<uchar>& parent, std::vector<uchar>& labels );
std::vector<uchar> getNeighbors( uchar * curr_ptr, uchar * prev_ptr, int x, int y, int cols );

void disjointUnion( int a, int b, std::vector<int>& parent );
int disjointFind( int a, std::vector<int>& parent, std::vector<int>& labels );
std::vector<int> getNeighbors( int * curr_ptr, int * prev_ptr, int x, int y, int cols );
private:
uchar nextLabel;
std::vector<uchar> labels;
int maxComponent;
int nextLabel;
std::vector<int> labels;
};

#endif /* defined(__RobustTextDetection__ConnectedComponent__) */
38 changes: 21 additions & 17 deletions ConnectedComponent/ConnectedComponent/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ void test1() {

/* Apply connected component labelling */
ConnectedComponent conn_comp;
Mat label = conn_comp.apply( image );
cvtColor( label, label, CV_GRAY2BGR );
Mat labels = conn_comp.apply( image );

/* Recolor the labels */
for( int y = 0; y < label.rows; y++ ) {
Vec3b * ptr = label.ptr<Vec3b>(y);
for( int x = 0; x < label.cols; x++ )
ptr[x] = color_map[ptr[x][0] % color_map.size()];
Mat colored( image.size(), CV_8UC3, Scalar::all(0) );
for( int y = 0; y < labels.rows; y++ ) {
Vec3b * ptr = colored.ptr<Vec3b>(y);
int * label_ptr = labels.ptr<int>(y);

for( int x = 0; x < labels.cols; x++ )
ptr[x] = color_map[ label_ptr[x] % color_map.size() ];
}

resize( label, label, Size(), 30.0, 30.0, CV_INTER_NN );

resize( colored, colored, Size(), 30.0, 30.0, CV_INTER_NN );

/* Convert our original image into appropriate size and type */
image = image * 255;
Expand All @@ -60,7 +63,7 @@ void test1() {
/* Append the two images together side by side */
Mat appended( image.rows, image.cols * 2, CV_8UC3 );
image.copyTo( Mat( appended, Rect(0, 0, image.cols, image.rows) ) );
label.copyTo( Mat( appended, Rect(image.cols, 0, image.cols, image.rows) ) );
colored.copyTo( Mat( appended, Rect(image.cols, 0, image.cols, image.rows) ) );

imshow("", appended);
while( waitKey(10) != 'q' );
Expand All @@ -74,22 +77,23 @@ void test2() {
threshold( image, binary, 200.0, 1.0, CV_THRESH_BINARY_INV );

ConnectedComponent conn_comp;
Mat label = conn_comp.apply( binary );

cvtColor( label, label, CV_GRAY2BGR );

Mat labels = conn_comp.apply( binary );

/* Recolor the labels */
for( int y = 0; y < label.rows; y++ ) {
Vec3b * ptr = label.ptr<Vec3b>(y);
for( int x = 0; x < label.cols; x++ )
ptr[x] = color_map[ptr[x][0] % color_map.size()];
Mat colored( image.size(), CV_8UC3, Scalar::all(0) );
for( int y = 0; y < labels.rows; y++ ) {
Vec3b * ptr = colored.ptr<Vec3b>(y);
int * label_ptr = labels.ptr<int>(y);

for( int x = 0; x < labels.cols; x++ )
ptr[x] = color_map[ label_ptr[x] % color_map.size() ];
}

cvtColor( image, image, CV_GRAY2BGR );
/* Append the two images together side by side */
Mat appended( image.rows, image.cols * 2, CV_8UC3 );
image.copyTo( Mat( appended, Rect(0, 0, image.cols, image.rows) ) );
label.copyTo( Mat( appended, Rect(image.cols, 0, image.cols, image.rows) ) );
colored.copyTo( Mat( appended, Rect(image.cols, 0, image.cols, image.rows) ) );

imshow( "", appended );
while( waitKey(10) != 'q' );
Expand Down

0 comments on commit b7fdc6c

Please sign in to comment.