[Medical Image Process] 3.4 Morphology Application—Watershed Algorithm 分水岭算法
2015-12-20 20:59
309 查看
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 算法综述
如果图像中的目标物体是连接在一起的,则分割起来会更困难,分水岭算法通常用于处理这一类问题,通常也会取得非常不错的结果。分水岭分割算法把图像看成一幅“地形图”,其中亮度比较强的区域像素值比较大,而比较暗的区域像素值比较小,通过寻找“汇水盆地”和“分水岭”界限,对图像进行分割。(Separatingtouching 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) == 3 I = rgb2gray(ImgRgb); else I = 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('标记和对象边缘叠加到原图像');
相关文章推荐
- Android进阶——声波振幅显示
- android studio ndk开发遇到的问题
- Ubuntu15.10 编译 Android4.1.1 源码
- 为什么下载APP,扫描二维码,关注微信公众号,就会送牛奶送小礼品?下载使用量高,会怎样?
- iOS 开发中的 Self-Manager 模式
- swift-基础05-类型别名和Bool型
- Android Activity生命周期 举例说明
- Opencv开发android应用
- html5离线储存,application cache,manifest使用体验
- swift-基础04-数字类型转换
- Unity 5.3 模块安装
- Android中shareSDK使用时注意事项
- Appium__用户登录&退出
- 编写高质量iOS 与OSX 代码的52个有效方法之系统框架
- Dalvik switch语句
- 修改unity GI cache位置
- Android中折线图实现方法(各类图表实现)
- Android QQ,WeChat,Weibo三方登陆
- Appium__客户端签到
- 游戏引擎cocos2d-android使用大全