您当前的位置:首页 > 精选知识 > 正文

分水岭算法 理论+opencv实现

分水岭算法 理论+opencv实现

图像是用一维坐标表示的,但是二维和三维绘图比较困难,所以我得用matlab。我可以不要用它,意思可以表达到位。

第一步:找到图像的局部最低点。方法有很多。你可以用一个内核去找,或者一个一个比较。实现起来并不难。

第二步:从最低点开始充水,水开始充互联网(形象的叫梯度法),其中那些最低点已经做了标记,不会被淹没,而那些中间点被淹没。

第三步:找到局部最高点,也就是图中位置3对应的两点。

步骤4:基于局部最小值和找到的局部最大值,可以分割图像。

分类图

模拟结果图

你觉得上面的方法很好很简单吗?然后看下图:

利用上面的步骤,第一步找到了三个点,然后第二步开始泛滥。所有三个点都被记录下来,并且发现了两个局部极大值。

这是我们想要的吗?

答案是否定的!我们不中间不需要最小值,因为它这只是一点噪音,我们不不需要如此仔细地分割图像。

缺陷暴露了吗?这不没关系。我们下面的opencv已经解决了这个问题。

模拟分类图

模拟结果图

Opencv改进分水岭算法;

针对以上问题,我们想的是,能否把这个小细节标记出来,让它不属于我们要找的最小点?

Opencv采用人工标记的方法对其进行了改进。我们标记了一些点,基于这些点来指导分水岭算法,效果很好!

例如,我们在上图中标记了两个三角形。第一步,我们找到三个局部极小点。第二步,淹没的时候三个点都被淹没了。但是如果中间的一个没有做标记,就淹死了(没有救生圈),另外两个点保留下来,这样才能达到我们想要的结果。

注意:这里的标记是用不同的标签做的,为了方便我用了同一个三角形。因为标记是用来分类的,所以不同的标记标注不同!这反映在下面的opencv程序中。

模拟分类图

模拟结果图

注意:具体实现没有完成,理解原理就可以用了。需要深入的时候,可以研究算法。当你用的比较浅,明白了原理,就要稍微改一下。它面试后完全没问题!哈哈~ ~

Opencv实现:

#包括

#包括

使用名称空间cv;

使用命名空间std

void water segment(input array _ src,OutputArray _dst,int nooffsegment);

int main(int argc,char** argv) {

mat input image=im read(coins.jpg );

断言(!input image . data);

Mat graImage,outputImage

利息抵消;

水分割(输入图像、输出图像、偏移图像);

wait key(0);

返回0;

}

void water segment(input array _ src,OutputArray _dst,int noOfSegment)

{

mat src=_ src . getmat();//dst=_ dst . getmat();

Mat灰度图像;

cvtColor(src,grayImage,CV _ bgr 2 gray);

threshold(灰度图像,灰度图像,0,255,THRESH _ BINARY | THRESH _ OTSU);

mat kernel=getStructuringElement(MORPH _ RECT,Size(9,9),Point(-1,-1));

morphologyEx(灰度图像,灰度图像,MORPH_CLOSE,内核);

distanceTransform(灰度图像,灰度图像,DIST_L2,MASK _面具_3,5);

normalize(grayImage,grayImage,0,1,NORM _ MINMAX);

grayImage.convertTo(grayImage,CV _ 8uc 1);

threshold(灰度图像,灰度图像,0,255,THRESH _ BINARY | THRESH _ OTSU);

morphologyEx(灰度图像,灰度图像,MORPH_CLOSE,内核);

向量轮廓;

向量层次结构;

Mat show image=Mat:zeros(gray image . size()、CV _ 32 SC1);

findContours(grayImage,Contours,hierarchy,RETR树,CHAIN_APPROX_SIMPLE,Point(-1,-1));

for(size _ t I=0;I contours . size();我)

{

//这里用static_cast(i 1)来区别标记分水岭。地区1、2、3。只有这样才能分。

drawContours(showImage,Contours,static_cast(i),Scalar:all(static_cast(i 1)),2);

}

mat k=getStructuringElement(MORPH _ RECT,Size(3,3),Point(-1,-1));

morphologyEx(src,src,MORPH_ERODE,k);

分水岭(src,show image);

//随机分配颜色

矢量颜色;

for(size _ t I=0;I轮廓。size();i ) {

int r=theRNG().制服(0,255);

int g=theRNG().制服(0,255);

int b=theRNG().制服(0,255);

颜色。push _ back(Vec3b((uchar)b,(uchar)g,(uchar)r));

}

//显示

Mat dst=Mat:zeros(显示图像。size()、CV _ 8uc 3);

int index=0;

for(int row=0;row showImage.rowsrow ) {

for(int col=0;col show image . cols coll){

index=showImage.at(row,col);

if(索引0索引=等高线。size()){

dst.at(row,col)=colors[index-1];

}

else if (index==-1)

{

dst.at(row,col)=Vec3b(255,255,255);

}

否则{

dst.at(row,col)=Vec3b(0,0,0);

}

}

}

}

分水岭合并代码:

void segMerge(Mat image,Mat segments,int numSeg)

{

向量样本;

int newNumSeg=numSeg

//初始化变量长度的矢量

for(size _ t I=0;我是纽姆塞格我)

{

垫样;

samples.push_back示例);

}

for(size _ t I=0;我段。行;我)

{

for(size _ t j=0;j segments.colsj)

{

int index=segments.at(i,j);

if (index=0 index=newNumSeg)//把同一个区域的点合并到一个垫子中

{

如果(!样本[索引]。数据)//数据为空不能合并,否则报错

{

样本[索引]=image(Rect(j,I,1,1));

}

else//按行合并

{

vconcat(samples[index],image(Rect(j,I,2,1)),samples[index]);

}

}

//if (index=0 index=newNumSeg)

//样本[索引]。push_back(image(Rect(j,I,1,1));

}

}

向量历史_基础

Mat hsv _ base

int h _ bins=35

int s _ bins=30

int histSize[2]={ h_bins,s _ bins };

float h_range[2]={ 0,256 };

float s_range[2]={ 0,180 };

const float* range[2]={ h_range,s _ range };

int channels[2]={ 0,1 };

Mat历史_基础

for(size _ t I=1;我numSeg我)

{

如果(样本【我】。dims 0)

{

颜色(样本[i],hsv_base,CV _ bgr 2 HSV);

calcHist(hsv_base,1,channels,Mat(),hist_base,2,histSize,range);

normalize(hist_base,hist_base,0,1,NORM _ MINMAX);

历史基础。push _ back(历史_基础);

}

其他

{

历史基础。push _ back(Mat());

}

}

双重相似度=0;

矢量合并;//是否合并的标志位

for(size _ t I=0;我有历史基础。size();我)

{

for(size _ t j=I 1;j历史_基础。size();j)

{

如果(!merged[j])//未合并的区域进行相似性判断

{

if (hist_bases[i]).dims 0 hist_bases[j].dims 0)//这里维数判断没必要,直接用个数据就可以了

{

相似度=compareHist(hist_bases[i],hist_bases[j],hist CMP _ BHATTACHARYYA);

如果(相似度0.8)

{

merged[j]=true;//被合并的区域标志位真实的

如果(我!=j)//这里没必要,我不可能等于j

{

newNumSeg-;//分割部分减少

for(size _ t p=0;p段。行;p)

{

for(size _ t k=0;k段. colsk)

{

int index=segments.at(p,k);

if (index==j) segments.at(p,k)=I;

}

}

}

}

}

}

}

}

numSeg=newNumSeg//返回合并之后的区域数量

}

标签:图像sizej


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 大闸蟹的做法和吃法?大闸蟹的做法和吃法有哪些

下一篇: 推荐这四款好用的api测试工具有哪些(推荐这四款好用的API测试工具)



推荐阅读