0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

分水岭算法(理论+opencv实现)

lviY_AI_shequ 来源:未知 作者:李建兵 2018-03-17 11:06 次阅读

‍‍‍把图像用一维坐标表示,二维和三维不好画,必须用matlab了,我不会用,意思可以表述到位

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

第二步:从最低点开始注水,水开始网上满(图像的说法就是梯度法),其中那些最低点已经被标记,不会被淹没,那些中间点是被淹没的。

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

第四步:这样基于局部最小值,和找到的局部最大值,就可以分割图像了。

分类图

模拟结果图

是不是感觉上面的方法很好,也很简单?接着看下面的图:

利用上面的步骤,第一步找到了三个点,然后第二步开始漫水,这三个点都被记录下来了,又找到两个局部最大值。

这是我们想要的吗?

回答是否定的!其中中间那个最小值我们不需要,因为只是一个很少并且很小的噪点而已,我们不需要图像分割的那么细致。

缺陷显露出来了吧?没关系,下面我们的opencv把这个问题解决了。

模拟分类图

模拟结果图

opencv改进的分水岭算法

针对上面出现的问题,我们想到的是能不能给这种小细节一个标记,让它不属于我们找的最小的点呢?

opencv对其改进就是使用了人工标记的方法,我们标记一些点,基于这些点去引导分水岭算法的进行,效果很好!

比如我们对上面的图像标记了两个三角形,第一步我们找到三个局部最小点,第二步淹没的时候三个点都被淹没了,然而中间那个没被标记,那就淹死了(没有救生圈),其余两个点保留,这样就可以达到我们的想要的结果了。

注释:这里的标记是用不同的标号进行的,我为了方便使用了同样的三角形了。因为标记用来分类,所以不同的标记打上不同的标号!这在下面opencv程序中体现了。。。

模拟分类图

模拟结果图

注释:具体的实现没有完成,感觉原理懂了会使用了这样就可以了,当你需要深入的时候再去研究实现的算法,当你浅浅的使用懂了原理应该会改一点,面试过了完全可以啊!哈哈哈~~

opencv实现:

#include

#include

using namespace cv;

using namespace std;

void waterSegment(InputArray& _src, OutputArray& _dst, int& noOfSegment);

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

Mat inputImage = imread("coins.jpg");

assert(!inputImage.data);

Mat graImage, outputImage;

int offSegment;

waterSegment(inputImage, outputImage, offSegment);

waitKey(0);

return 0;

}

void waterSegment(InputArray& _src,OutputArray& _dst,int& noOfSegment)

{

Mat src = _src.getMat();//dst = _dst.getMat();

Mat grayImage;

cvtColor(src, grayImage,CV_BGR2GRAY);

threshold(grayImage, grayImage, 0, 255, THRESH_BINARY | THRESH_OTSU);

Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));

morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);

distanceTransform(grayImage, grayImage, DIST_L2, DIST_MASK_3, 5);

normalize(grayImage, grayImage,0,1, NORM_MINMAX);

grayImage.convertTo(grayImage, CV_8UC1);

threshold(grayImage, grayImage,0,255, THRESH_BINARY | THRESH_OTSU);

morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);

vector> contours;

vector hierarchy;

Mat showImage = Mat::zeros(grayImage.size(), CV_32SC1);

findContours(grayImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));

for (size_t i = 0; i < contours.size(); i++)

{

//这里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);

watershed(src, showImage);

//随机分配颜色

vector colors;

for (size_t i = 0; i < contours.size(); i++) {

int r = theRNG().uniform(0, 255);

int g = theRNG().uniform(0, 255);

int b = theRNG().uniform(0, 255);

colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));

}

// 显示

Mat dst = Mat::zeros(showImage.size(), CV_8UC3);

int index = 0;

for (int row = 0; row < showImage.rows; row++) {

for (int col = 0; col < showImage.cols; col++) {

index = showImage.at(row, col);

if (index > 0 && index <= contours.size()) {

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

}

else if (index == -1)

{

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

}

else {

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

}

}

}

}

分水岭合并代码:

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

{

vector samples;

int newNumSeg = numSeg;

//初始化变量长度的Vector

for (size_t i = 0; i < newNumSeg; i++)

{

Mat sample;

samples.push_back(sample);

}

for (size_t i = 0; i < segments.rows; i++)

{

for (size_t j = 0; j < segments.cols; j++)

{

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

if (index >= 0 && index <= newNumSeg)//把同一个区域的点合并到一个Mat中

{

if (!samples[index].data)//数据为空不能合并,否则报错

{

samples[index] = image(Rect(j, i, 1, 1));

}

else//按行合并

{

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

}

}

//if (index >= 0 && index <= newNumSeg)

// samples[index].push_back(image(Rect(j, i, 1, 1)));

}

}

vector hist_bases;

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 hist_base;

for (size_t i = 1; i < numSeg; i++)

{

if (samples[i].dims > 0)

{

cvtColor(samples[i], hsv_base, CV_BGR2HSV);

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

normalize(hist_base, hist_base, 0, 1, NORM_MINMAX);

hist_bases.push_back(hist_base);

}

else

{

hist_bases.push_back(Mat());

}

}

double similarity = 0;

vector merged;//是否合并的标志位

for (size_t i = 0; i < hist_bases.size(); i++)

{

for (size_t j = i+1; j < hist_bases.size(); j++)

{

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

{

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

{

similarity = compareHist(hist_bases[i], hist_bases[j], HISTCMP_BHATTACHARYYA);

if (similarity > 0.8)

{

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

if (i != j)//这里没必要,i不可能等于j

{

newNumSeg --;//分割部分减少

for (size_t p = 0; p < segments.rows; p++)

{

for (size_t k = 0; k < segments.cols; k++)

{

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

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

}

}

}

}

}

}

}

}

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

}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • OpenCV
    +关注

    关注

    31

    文章

    634

    浏览量

    41338

原文标题:分水岭算法(理论+opencv实现)

文章出处:【微信号:AI_shequ,微信公众号:人工智能爱好者社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于分水岭的图像分割求指点

    `我想对这幅图像中的水稻进行图像分割,采取了基于控制标记的距离变换分水岭分割程序如下rgb = imread('C:UserschenxuanDesktop稻子原图.jpg&
    发表于 08-27 13:46

    【HiSpark IPC DIY Camera试用连载 】第三篇 分水岭算法测试

    自己唯一的编号,轮廓的定位可以通过Opencv中findContours方法实现,这个是执行 分水岭之前的要求。接下来执行分水岭会发生什么呢?算法
    发表于 01-21 23:38

    分水岭算法在重叠细胞图象分割中的应用

    分水岭算法是一种广泛使用的分割方法,将其用于细胞图象分割可以克服由于细胞交叠造成的图象分析困难,但缺陷在于它的过分割结果。本文给出一种针对分水岭过分割问题的解
    发表于 06-26 08:31 24次下载

    多晶硅“门槛”定调:2010或成行业分水岭

    多晶硅“门槛”定调:2010或成行业分水岭   山雨欲来,一场多晶硅行业的政策风暴正在酝酿。   近日,记者独家获
    发表于 02-01 10:04 526次阅读

    分水岭算法_《OpenCV3编程入门》书本配套源代码

    OpenCV3编程入门》书本配套源代码:分水岭算法
    发表于 06-06 15:39 8次下载

    OpenCV3编程入门-源码例程全集-分水岭算法

    OpenCV3编程入门-源码例程全集-分水岭算法,感兴趣的小伙伴们可以瞧一瞧。
    发表于 09-18 16:55 0次下载

    基于分水岭算法的尿沉渣图像处理方法研究_逄涵涵

    基于分水岭算法的尿沉渣图像处理方法研究_逄涵涵
    发表于 03-17 09:41 2次下载

    一种新的彩色图像分割算法

    本文提出一种新的结合分水岭与种子区域生成、区域合并的彩色图像分割算法。首先将RGB颜色空间转换成HSI间,应用分水岭算法对图像进行初始化分割,形成过分割效果。接着基于
    发表于 12-14 14:41 1次下载
    一种新的彩色图像分割<b class='flag-5'>算法</b>

    2018年将为全球供应链数码化分水岭

    据报导,随著企业积极响应政府和政府间组织的新倡议,2018年将成为全球供应链数码化的分水岭。而能促成全球供应链数码化的关键,可从下面几格趋势来观察:
    发表于 01-22 08:43 1072次阅读

    中国互联网未来5年趋势是如何的?分水岭大时代到来。

    报告指出,分水岭大时代即将到来:“分水岭”将成为未来五年中国互联网的关键词;从浅水区向深水区过度,引发竞争格局的强弱势转化;分水岭区不存在直道竞争,冷静和变化成为主旋律。
    的头像 发表于 09-09 09:18 6656次阅读

    国产手机市场的争夺还在继续 华为小米手机业务走到了分水岭

    2018年对小米和华为来说是一个转折点。国产手机市场的争夺还在继续,但是两家的业务布局在悄然变化,手机业务对集团的战略支撑,走到了分水岭
    发表于 12-19 14:10 1205次阅读

    “史上最严”能效令发布 空调市场即将迎来分水岭

    近日,随着“史上最严”空调能效标准发布这一权威消息不胫而走,深陷价格战泥潭的空调市场即将迎来分水岭。记者从相关渠道获悉,长虹空调将继主推的超一级能效产品Q5Ks之后,即可发布两款新品——Q5A好睡眠空调和Q5D AI舒适空调,抢占能效调整带来的最大一波变频红利。
    发表于 01-06 10:05 541次阅读

    站在从4G向5G跨越的分水岭上,四大厂商2019年的业绩表现如何

    对于通信行业而言,2019年是真正意义上的5G元年,虽然全球范围内的5G网络建设仍未大规模启动,但随着韩国、美国和中国等主要市场相继宣布5G商用,2019年已成为通信行业从4G向5G跨越的分水岭
    的头像 发表于 04-10 15:19 2355次阅读
    站在从4G向5G跨越的<b class='flag-5'>分水岭</b>上,四大厂商2019年的业绩表现如何

    超全分水岭算法汇总

    超全分水岭算法汇总
    发表于 10-08 10:27 0次下载

    opencv实战——机器视觉检测和计数

    由于之前网购的维生素片,有时候忘了今天有没有吃过,就想对瓶子里的药片计数...在学习opencv以后,希望实现对于维生素片分割计数算法。本次实战在基于形态学的基础上又衍生出基于距离变换的分水岭
    的头像 发表于 03-03 11:54 1974次阅读