二值图像连通区域标记:Seed Filling(种子填充法)

原文: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 ;

}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值