TWO-PASS连通域标记实现

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <map>
#include <cassert>
#include <iostream>
using namespace std;
using namespace cv;

const int max_size = 1000;
int parent[max_size] = {0};

// 找到label x的根节点
int find(int x, int parent[]){
	assert(x < max_size);
	int i = x;
	while(0 != parent[i])
		i = parent[i];
	return i;
}

// 将label x 和 label y合并到同一个连通域
void union_label(int x, int y, int parent[]){
	assert(x < max_size && y < max_size);
	int i = x;
	int j = y;
	while(0 != parent[i])
		i = parent[i];
	while(0 != parent[j])
		j = parent[j];
	if(i != j)
		parent[i] = j;
}


void myConnectedComponentLabelingTwoPass(
	Mat& binary, Mat& label){
	CV_Assert(binary.data);
	CV_Assert(binary.depth() == CV_8U);
	CV_Assert(binary.channels() == 1);
	
	// create label image
	label.create(binary.size(), binary.type());

	// initialize label value
	int label_value = 0;

	// first pass
	for(int y = 1; y < binary.rows; y++){
		uchar* p_binary = binary.ptr<uchar>(y);
		uchar* p_binary_up = binary.ptr<uchar>(y-1);
		uchar* p_label = label.ptr<uchar>(y);
		uchar* p_label_up = label.ptr<uchar>(y-1);
		for(int x = 0;  x < label.cols; x++){
			p_label[x] = 0;
		}
		for(int x = 1;  x < binary.cols; x++){
			if(255 == p_binary[x]){
				if(0 == p_binary[x-1] && 0 == p_binary_up[x]){
					label_value += 1;
					p_label[x] = (int)label_value;
				}
				else if(255 == p_binary[x-1] && 0 == p_binary_up[x])
					p_label[x] = p_label[x-1];
				else if(0 == p_binary[x-1] && 255 == p_binary_up[x])
					p_label[x] = p_label_up[x]; 
				else if(255 == p_binary[x-1] && 255 == p_binary_up[x]){
					p_label[x] = p_label[x-1];
					union_label(p_label[x-1], p_label_up[x], parent);
				}else{	
					cout << " p_binary[x-1] = " << (int)p_binary[x-1] <<
						" p_binary_up[x] = " << (int)p_binary_up[x] << endl;
				}
			}
		}
	}

	// second pass
	for(int y = 1; y < binary.rows-1; y++){
		uchar* p_label = label.ptr<uchar>(y);
		for(int x = 1;  x < binary.cols-1; x++){
			if(p_label[x] > 0){
				p_label[x] = find(p_label[x], parent);
			}
		}
	}
}

//  Connected Component Analysis/Labeling -- Color Labeling 
//  Author:  www.icvpr.com  
//  Blog  :  http://blog.csdn.net/icvpr 
cv::Scalar icvprGetRandomColor()
{
	uchar r = 255 * (rand()/(1.0 + RAND_MAX));
	uchar g = 255 * (rand()/(1.0 + RAND_MAX));
	uchar b = 255 * (rand()/(1.0 + RAND_MAX));
	return cv::Scalar(b,g,r) ;
}

void icvprLabelColor(const cv::Mat& _labelImg, cv::Mat& _colorLabelImg) 
{
	if (_labelImg.empty() ||
		_labelImg.type() != CV_8UC1)
	{
		return ;
	}

	std::map<int, cv::Scalar> colors ;

	int rows = _labelImg.rows ;
	int cols = _labelImg.cols ;

	_colorLabelImg.release() ;
	_colorLabelImg.create(rows, cols, CV_8UC3) ;
	_colorLabelImg = cv::Scalar::all(0) ;

	for (int i = 0; i < rows; i++)
	{
		uchar* data_src = (uchar*)_labelImg.ptr<uchar>(i) ;
		uchar* data_dst = _colorLabelImg.ptr<uchar>(i) ;
		for (int j = 0; j < cols; j++)
		{
			int pixelValue = data_src[j] ;
			if (pixelValue > 0)
			{
				if (colors.count(pixelValue) <= 0)
				{
					colors[pixelValue] = icvprGetRandomColor() ;
				}
				cv::Scalar color = colors[pixelValue] ;
				*data_dst++   = color[0] ;
				*data_dst++ = color[1] ;
				*data_dst++ = color[2] ;
			}
			else
			{
				data_dst++ ;
				data_dst++ ;
				data_dst++ ;
			}
		}
	}
}

int main(){
	// load image
	char* imageName = "binary.png";
	Mat image;
	image = imread(imageName,1);
	if(!image.data){
		cout << "No image data" << endl;
		getchar();
		return -1;
	}

	// convert to gray
	cvtColor( image, image, CV_RGB2GRAY );// convert 3-channel image to 1-channel image

	// threshold
	Mat thresh;
	threshold(image, thresh, 100, 255, THRESH_BINARY);

	// label
	Mat label;
	myConnectedComponentLabelingTwoPass(thresh, label);
	
	// color labeling
	Mat color_label;
	icvprLabelColor(label, color_label);

	// show
	imshow("image", image);
	imshow("thresh", thresh);
	imshow("label", label);
	imshow("color_label", color_label);
	waitKey(0);
}

 


参考文献:

Shapiro, L., and Stockman, G. (2002). Computer Vision. Prentice Hall. pp. 69–73.

http://blog.csdn.net/icvpr/article/details/10259577

你可能感兴趣的:(TWO-PASS连通域标记实现)