原文:http://blog.csdn.net/icvpr/article/details/10259577
上述文章的种子填充法并不能运行,经过我修改后顺利执行。
测试图如下:
侧视图经过matlab 的bwlabel函数测是,在4连通情况下有3087个连通域,8连通下有2471个连通域。
以下程序采用4联通域。前景元素为255,背景元素为0。
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
void icvprCcaBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
// connected component analysis (4-component)
// use seed filling algorithm
// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0
if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return ;
}
_lableImg.release() ;
_binImg.convertTo(_lableImg, CV_32SC1) ;
int label = 0 ; // start by 1
int rows = _binImg.rows ;
int cols = _binImg.cols ;
Mat mask(rows,cols,CV_8UC1);
mask.setTo(0);
int * lableptr;
for (int i = 0; i < rows; i++)
{
int* data= _lableImg.ptr<int>(i) ;
uchar *maskptr=mask.ptr<uchar>(i);
for (int j =0; j < cols; j++)
{
if (data[j] == 255&&mask.at<uchar>(i,j)!=1)
{
mask.at<uchar>(i,j)=1;
std::stack<std::pair<int,int>> neighborPixels ;
neighborPixels.push(std::pair<int,int>(i,j)) ; // pixel position: <i,j>
++label ; // begin with a new label
while (!neighborPixels.empty())
{
// get the top pixel on the stack and label it with the same label
std::pair<int,int> curPixel = neighborPixels.top() ;
int curY = curPixel.first ;
int curX = curPixel.second ;
_lableImg.at<int>(curY, curX) = label ;
// pop the top pixel
neighborPixels.pop() ;
// push the 4-neighbors (foreground pixels)
if(curX-1>=0)
{
if (_lableImg.at<int>(curY, curX-1) == 255&&mask.at<uchar>(curY,curX-1)!=1)
// left pixel
{
neighborPixels.push(std::pair<int,int>(curY, curX-1)) ;
mask.at<uchar>(curY,curX-1)=1;
}
}
if(curX+1<=cols-1)
{
if (_lableImg.at<int>(curY, curX+1) == 255&&mask.at<uchar>(curY,curX+1)!=1)
// right pixel
{
neighborPixels.push(std::pair<int,int>(curY, curX+1)) ;
mask.at<uchar>(curY,curX+1)=1;
}
}
if(curY-1>=0)
{
if (_lableImg.at<int>(curY-1, curX) == 255&&mask.at<uchar>(curY-1,curX)!=1)
// up pixel
{
neighborPixels.push(std::pair<int,int>(curY-1, curX)) ;
mask.at<uchar>(curY-1,curX)=1;
}
}
if(curY+1<=rows-1)
{
if (_lableImg.at<int>(curY+1, curX) == 255&&mask.at<uchar>(curY+1,curX)!=1)
// down pixel
{
neighborPixels.push(std::pair<int,int>(curY+1, curX)) ;
mask.at<uchar>(curY+1,curX)=1;
}
}
}
}
}
}
}
颜色标注函数:
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)
{
int num=0;
if (_labelImg.empty() ||
_labelImg.type() != CV_32SC1)
{
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) ;
_colorLabelImg.setTo(Scalar(0,0,0));
for (int i = 0; i < rows; i++)
{
const int* data_src = (int*)_labelImg.ptr<int>(i) ;
uchar* data_dst = _colorLabelImg.ptr<uchar>(i) ;
for (int j = 0; j < cols; j++)
{
int pixelValue = data_src[j] ;
if (pixelValue >=1)
{
if (colors.count(pixelValue)==0)
{
colors[pixelValue] = icvprGetRandomColor() ;
num++;
}
cv::Scalar color = colors[pixelValue] ;
*data_dst++ = color[0] ;
*data_dst++ = color[1] ;
*data_dst++ = color[2] ;
}
else
{
data_dst++ ;
data_dst++ ;
data_dst++ ;
}
}
}
cout<<"color num"<<num<<endl;
}
主函数:
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
void icvprCcaBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg);
void icvprCcaByTwoPass(const cv::Mat& _binImg, cv::Mat& _lableImg);
cv::Scalar icvprGetRandomColor();
void icvprLabelColor(const cv::Mat& _labelImg, cv::Mat& _colorLabelImg);
int main(int argc, char** argv)
{
//Mat binImage = cv::imread("C:/Users/samsung/Desktop/201504013/mask/bmask_png_13.png", 0) ;
Mat binImage=imread("C:/Users/samsung/Desktop/20140823152639484.png",0);
//cv::threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY) ;
// connected component labeling
cv::Mat labelImg ;
double time= getTickCount();
icvprCcaBySeedFill(binImage, labelImg) ;
//icvprCcaByTwoPass(binImage,labelImg) ;
time=getTickCount()-time;
cout<<time/getTickFrequency()*1000<<"ms"<<endl;
// show result
//cv::Mat grayImg ;
//labelImg *= 10 ;
//labelImg.convertTo(grayImg, CV_8UC1) ;
//cv::imshow("labelImg", grayImg) ;
cv::Mat colorLabelImg ;
icvprLabelColor(labelImg, colorLabelImg) ;
cv::imshow("colorImg", colorLabelImg) ;
imwrite("C:/Users/samsung/Desktop/2014.png",colorLabelImg);
double minval,maxval;
minMaxLoc(labelImg,&minval,&maxval);
cout<<"minval"<<minval<<endl;
cout<<"maxval"<<maxval<<endl;
cv::waitKey(0);
getchar();
return 0 ;
}