1. 分水岭原理

分水岭算法是一种基于拓扑理论的数学形态学分割理论,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域成为集水盆,而集水盆的边界则形成分水岭。

分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。分水岭的计算过程是一个迭代标注过程。

分水岭比较经典的计算方法是L.Vincent提出的。在该算法中,分水岭计算分两个步骤,一个是排序过程,一个是淹没过程。首先对每个像素的灰度级进行从低到高的排序,然后再从低到高实现淹没过程中,对每一个局部极小值在H阶高度的影响域采用先进先出(FIFO)结构进行判断及标注。

分水岭变换得到的是输入图像的集水盆图像,集水盆之间的分界点即为分水岭。显然分水岭表示的是输入图像极大值点。因此为了得到图像的边缘信息,通常把梯度图像作为输入图像,即g(x,y)=grad(f(x,y))=sqrt{[f(x,y)-f(x-1,y)]^2 + [f(x.y)-f(x,y-1)]^2}。

分水岭算法对微弱的边缘具有良好的响应,是得到封闭连续边缘的保证。另外,分水岭算法所得到的封闭的集水盆,为分析图像的区域特征提供了可能。

实际应用过程中,由于一幅图像存在非常多极小值,就会造成图像的过分割。通常可以采用两种方法加以解决,一是利用先验知识去除无关边缘信息。二是修改梯度函数,使得集水盆只响应想要探测的目标。为了降低分水岭算法产生的过度分割,通常要对梯度函数进行修改,一个最简单的方法就是对梯度图像进行阈值处理,用以消除灰度的微小变化产生的过度分割。即g(x,y)=max(grad(f(x,y)),gΘ),式中gΘ表示阈值。程序可采用的方法:用阈值限制梯度图像已达到消除灰度值的微小变化造成的过分割结果,获得适量分割区域,在对这些区域的边缘点的灰度级进行从高到低的排序,然后再从低到高实现淹没过程。梯度图像用Sobel算子计算获得。对梯度图像进行阈值处理时,选取合适的阈值对最终分割的图像有很大影响,因此阈值的选取是图像分割效果好坏的一个关键。缺点:实际图像中可能含有微弱的边缘,灰度变化的数值差别不是特别明显,选取阈值过大可能会消去这些微弱边缘。

2. Matlab仿真分析分水岭算法

2.1 算法综述

如果图像中的目标物体是连接在一起的,则分割起来会更困难,分水岭算法通常用于处理这一类问题,通常也会取得非常不错的结果。分水岭分割算法把图像看成一幅“地形图”,其中亮度比较强的区域像素值比较大,而比较暗的区域像素值比较小,通过寻找“汇水盆地”和“分水岭”界限,对图像进行分割。(Separating touching objects in an image is one of the most difficult image processing operations. The watershed transform is often applied to this problem. The watershed transform finds "catchment basins " and " watershed rigid lines" in an image by treating is as a surface where light pixels are high and dark pixels are low.)
就像上面所说一样,直接应用分水岭分割算法的效果往往是不好的,如果在图像中对前景对象和背景对象进行标注区别,再应用分水岭算法会取得较好的分割效果。(Segmentation using the watershed transform works better if you can identify or "mark", foreground object and background object.)

2.2 算法执行步骤

1.计算分割函数。图像中较暗的区域是要分割的对象。
2.计算前景标志。这些是每个对象内部连接的斑点像素。
3.计算背景标志。这些不属于任何对象的像素。
4.修改分割函数,使其仅在前景和背景标记位置有极小值。
5.对修改后的分割函数做分水岭变换计算。

2.3 matlab 仿真研究

2.3.1 读入一幅彩色图像,并转成灰度图。
2.3.2 将图像的梯度幅值作为分割函数
采用Sobel边缘算子对图像进行水平方向和竖直方向进行滤波,然后求取模值,作为图像的边缘梯度。这是因为Sobel算子滤波后,在图像的边界处将会出现较大值,在非边界出现较小值。
(我们直接用梯度图像做为“分水岭”分割的导向函数,观察效果)
这样,我们可以看到。如果不对原始的边缘梯度图像进行处理,由于存在无数个极小值,这就势必会导致算法发生过分割的现象。因此,实际操作过程中,应该分别对前景对象和北京对象进行标记,已获得更好的分割结果。
2.3.3 标记前景对象
有多种方法可以应用在这里来获得前景标记,这些标记必须是前景对象内部的连接斑点像素。我们可以使用形态学技术“基于开的重建”和“基于闭的重建”来清理图像。这些操作将会在每个像素内部创建单位极大值,我们使用imregionalmax来定位。
开闭运算可以讲图像中壁结构元素小的特定图像细节去除,同时保证不产生全局几何失真。开运算可以把比结构单元小的突刺滤掉(比较亮的点),切断细长搭接而起到分离作用;闭运算可以把比结构元素小的缺口或空填上,搭接短的间隔而起到连接作用。
图像开操作
接下来,通过腐蚀后的重建来做基于开的重建计算。
在图像开操作的基础之上,进行图像的闭操作,去除图像中的暗点。
执行基于闭的形态学重建操作
通过上面的对比,我们可以清晰地看出,基于重建的开闭操作要比标准的开闭重建更加有效。那么就可以直接获取局部极大值来进行前景标记。
我们可以注意到,大多数闭塞处和阴影对象没有被标记,这就意味着这些对象在结果中将不会得到合理的分割。而且,一些对象的前景标记会一直到对象的边缘。这就意味着应该清理标记斑点的边缘,然后收缩他们。下面通过闭操作来清理标记斑点通过腐蚀操作来缩小区域。
这个过程中(腐蚀操作),会留下一些偏离的孤立元素,用bwareaopen移除少于特定像素个数的斑点。BW2 = bwareaopen(BW,P)指的是从二值图像中移除所有少于P像素的连通块。
2.3.4 背景标记
现在我们需要对背景进行标记,在清理后的“基于重建的拍闭运算”图像中,暗像素属于背景,所以可以从阈值操作开始。
背景像素在黑素的区域,但是理想情况下,不必要求背景标记太接近于要分割的对象边缘。通过计算“骨架影响范围”来细化“背景”。这个可以通过计算BW的距离变换的分水岭变换来实现,然后寻找结果的分水岭脊线D=bwdist(BW)计算二值图像BW的欧几里得矩阵。对BW的每一个像素,距离变换指定像素和最近的BW非零像素之间的距离。bwdist默认使用欧几里得距离公式。
2.3.5 梯度函数有限的分水岭变换
源代码:
%Watershed
clc; clear all; close all;
ImgRgb = imread('apple.jpg');
if ndims(ImgRgb) == 3I = rgb2gray(ImgRgb);
elseI = ImgRgb;
end
%Sobel 求图像边缘
hy = fspecial('sobel');
hx = hy';
Iy = imfilter(double(I), hy, 'replicate');
Ix = imfilter(double(I), hx, 'replicate');
GradMag = sqrt(Ix.^2 + Iy.^2);
%直接利用梯度函数图像分割
L = watershed(GradMag);
%基于开运算的重建
se = strel('disk', 20);
ImgOpen = imopen(I, se);
ImgErode = imerode(I, se);
ImgErodeConstrnct = imreconstruct(ImgErode, I);
%基于闭操作的图像重建
Ioc = imclose(ImgOpen, se);
ImgErodeConstrnctDilate = imdilate(ImgErodeConstrnct, se);
ImgErodeConstrnctDilateConstruct = imreconstruct(imcomplement(ImgErodeConstrnctDilate), imcomplement(ImgErodeConstrnct));
ImgErodeConstrnctDilateConstruct = imcomplement(ImgErodeConstrnctDilateConstruct);
%标记前景的极大值
fgm = imregionalmax(ImgErodeConstrnctDilateConstruct);
%去除前景中的零散点,并进行区域收缩
se2 = strel(ones(5,5));
fgm2 = imclose(fgm, se2);
fgm3 = imerode(fgm2, se2);
%进一步去除小的连通域
fgm4 = bwareaopen(fgm3, 20);
%标记背景
bw = im2bw(ImgErodeConstrnctDilateConstruct, graythresh(ImgErodeConstrnctDilateConstruct));
%脊线分割
D = bwdist(bw);
DL = watershed(D);
bgm = DL == 0;
gradmag2 = imimposemin(GradMag, bgm | fgm4);
L = watershed(gradmag2);
It1 = ImgRgb(:, :, 1);
It2 = ImgRgb(:, :, 2);
It3 = ImgRgb(:, :, 3);
fgm5 = imdilate(L == 0, ones(3, 3)) | bgm | fgm4;
It1(fgm5) = 0; It2(fgm5) = 255; It3(fgm5) = 0;
I4 = cat(3, It1, It2, It3);
Lrgb = label2rgb(L, 'jet', 'w', 'shuffle');
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(ImgRgb, []); title('原图像');
subplot(1, 2, 2); imshow(I4, []); title('标记和对象边缘叠加到原图像');

[Medical Image Process] 3.4 Morphology Application—Watershed Algorithm 分水岭算法相关推荐

  1. 基于边缘的图像分割——分水岭算法(watershed)算法分析(附opencv源码分析)

    最近需要做一个图像分割的程序,查了opencv的源代码,发现opencv里实现的图像分割一共有两个方法,watershed和mean-shift算法.这两个算法的具体实现都在segmentation. ...

  2. 【OpenCV】 - 图像分割之分水岭算法,watershed()函数的输出,对marker和image的改变

    一.背景 最近在学分水岭算法的opencv函数watershed()时,对函数执行完后image和marker的变化一无所知.懵懵懂懂. 于是便结合网上资料和自己现身说法,给大家分享一下[waters ...

  3. Opencv每日函数 图像分割模块 watershed分水岭算法

    ​一.分水岭理论概述 任何灰度图像都可以看作是一个地形表面,其中高强度表示峰和丘陵,而低强度表示山谷.您开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值).随着水位的上升,根据附近的山峰(梯度 ...

  4. Watershed segmentation 分水岭分割

    分水岭是用于分割的经典算法,即用于分离图像中的不同对象. 从用户定义的标记开始,分水岭算法将像素值视为局部地形(高程).该算法从标记中泛洪盆地,直到归因于不同标记的盆地在分水岭线上相遇.在许多情况下, ...

  5. 《OpenCV3编程入门》学习笔记8 图像轮廓与图像分割修复(五)分水岭算法(watershed algorithm)

    8.5 分水岭算法(watershed algorithm) 1.基于拓扑理论的数学形态学的分割方法. 2.基本思想:把图像看作测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局 ...

  6. OpenCV 【四】————Watershed Algorithm(图像分割)——分水岭算法的原理及实现

    分水岭算法实现(C++.opencv) 1.作用: 通常用于分割图像,主要实现以临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性 ...

  7. OpenCV学习(二十) :分水岭算法:watershed()

    OpenCV学习(二十) :分水岭算法:watershed() 参考博客: OpenCV-分水岭算法 图像处理--分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法--wat ...

  8. OpenCV3学习(7.2)——图像分割之二(分水岭算法watershed)

    分水岭算法原理 分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭 ...

  9. Python+OpenCV:基于分水岭算法的图像分割(Image Segmentation with Watershed Algorithm)

    Python+OpenCV:基于分水岭算法的图像分割(Image Segmentation with Watershed Algorithm) ############################ ...

最新文章

  1. webstorm github怎么用_前端开发神器WebStorm发布最新版本2019.3,代码完成更加智能...
  2. Simulating Ocean Water (2) (2005-03-31 update)
  3. HDU 1058(打表)
  4. Android线程管理(一)
  5. PIE_SDK.NET功能表
  6. Debian卸载iceweasel
  7. 芭比扣了!Nacos中服务删除不了,肿么办?
  8. 服饰贴图定制小程序V1.2.4安装更新一体包+小程序前端
  9. root用户连接mysql数据库出错 1045 access denied for user 'root'@'localhost' using password yes
  10. 微服务Springcloud超详细教程+实战(二)
  11. sql语句查看MySQL数据库大小
  12. hane WIN nfs配置
  13. 微信公众号问题:{errcode:40125,errmsg:invalid appsecret, view more at http:\/\/t.cn\/LOEdzVq, hints: [ ...
  14. 信息系统项目管理师必背知识点(完整版)
  15. Java实现蓝桥杯快乐数
  16. 嵌入地图跳转高德地图_各种地图跳转导航
  17. Unity游戏动画 从入门到住院:动画状态机
  18. 13700k和13700kf的区别 i7 13700k和13700kf怎么选
  19. matlab学习——线性规划
  20. 利用unity和steamVR完成场景漫游(五) 学习VRTK中简单案例

热门文章

  1. Mac下安装及使用rz、sz远程上传下载文件
  2. 利用Inotify和Rsync将webproject文件自己主动同步到多台应用server
  3. 大型网站技术架构文摘
  4. mysql开启查看慢查询日志[转]
  5. 别跟我说测试的坏话...
  6. 我学员的一个问题及其我对之的解答,关于lr返回值问题
  7. clcikhouse Code: 1000. DB::Exception: File not found
  8. hdu 5280(最大子串和变形,dp)
  9. VUE+SpringBoot+JWT实现token验证,SSO单点登录
  10. reduction_indices的用法