Marker-controlled 漫水填充分割算法

http://cn.mathworks.com/products/demos/image/watershed/ipexwatershed.html

如果图像中的目标紧密联系,则分割操作将会非常困难。而分水岭变换则经常被应用于处理这个问题。分水岭变换通过将灰度图的亮度看做是一个山体的表面用于找到“漫水盆地”以及“分水岭屋脊”。如果能对前景和背景位置进行标注,利用分水岭变换进行分割能够有更好的效果。Marker-controlled分水岭分割的步骤如下所示:
1 计算一个分割函数。分割函数是一个图像,这个图像的较暗的区域是你希望分割的目标。
2 计算前景标注。前景标注是每一个目标中的一个连接的区域。
3 计算背景标注。背景是一个不属于任何目标的部分。
4 修改分割函数以至于分割函数仅仅在前景和背景标注位置具有较小值。
5 重新计算修改后的分割函数的分水岭变换。
Marker-Controlled分水岭分割算法步骤如下所示:
1 读取一个图像,并将这个图像转换位灰度图像
rgb = imread('pears.png');
I = rgb2gray(rgb);
imshow(I)

text(732,501,'Image courtesy of Corel',...
     'FontSize',7,'HorizontalAlignment','right')
2 利用梯度图像来作为分割函数
梯度图像在目标的边界处具有较高的数值而在目标内部具有较小的数值,当然这样的处理利用分水岭变换得到的分割函数有一个过分割的问题。
hy = fspecial('sobel');
hx = hy';
Iy = imfilter(double(I), hy, 'replicate');
Ix = imfilter(double(I), hx, 'replicate');
gradmag = sqrt(Ix.^2 + Iy.^2);
figure, imshow(gradmag,[]), title('gradmag')
下面是利用没有修改的梯度图像来进行分水岭分割,其中L是分割之后的结果:
L = watershed(gradmag);
Lrgb = label2rgb(L);
figure, imshow(Lrgb), title('Lrgb')

由于没有其他的预处理,则很容易得到一个过分割的结果。

3 标注前景目标

一系列的步骤能够用于得到前景标注,在这个例子当中主要运用形态学处理中的开操作和闭操作来得到前景标注。而开操作和闭操作的实现由两种方式,一种是直接调用imopen和imclose函数,另一种是调用重构函数来实现开操作和闭操作。

首先看开操作的实现:

se = strel('disk', 20);
Io = imopen(I, se);
figure, imshow(Io), title('Io')
另外一个开操作的实现如下所示:

Ie = imerode(I, se);
Iobr = imreconstruct(Ie, I);
figure, imshow(Iobr), title('Iobr')
在开操作之后进行闭操作:

Ioc = imclose(Io, se);
figure, imshow(Ioc), title('Ioc')
利用重构实现闭操作

Iobrd = imdilate(Iobr, se);
Iobrcbr = imreconstruct(imcomplement(Iobrd), imcomplement(Iobr));
Iobrcbr = imcomplement(Iobrcbr);
figure, imshow(Iobrcbr), title('Iobrcbr')
需要注意的是,在这膨胀之后需要对图像进行求反之后才能进行重构操作。

在开操作和闭操作之后,将区域内的最大值置为1,这样就得到了前景。

fgm = imregionalmax(Iobrcbr);
figure, imshow(fgm), title('fgm')

当然,你也可以将这些数据给加到源图像上使得结果更利于理解:

I2 = I;
I2(fgm) = 255;
figure, imshow(I2), title('fgm superimposed on original image')
注意到,许多遮挡以及处于阴影下的目标还没有被分割出来,这意味着这些目标不能很好的在结果中分割出来。同样,前景标注刚好在一些目标的边缘上,这意味着你需要清除这些边缘并将这些边缘进行收缩。这些操作能够由腐蚀和闭操作进行处理。

se2 = strel(ones(5,5));
fgm2 = imclose(fgm, se2);
fgm3 = imerode(fgm2, se2);
然而这样的处理之后会得到一些独立的像素点,为了消除这些像素点就需要进行消除操作。
fgm4 = bwareaopen(fgm3, 20);
I3 = I;
I3(fgm4) = 255;
figure, imshow(I3)
title('fgm4 superimposed on original image')
4 计算背景标注

背景的计算是除掉前景之外的部分,这一步的实现是利用最有阈值实现的。

bw = im2bw(Iobrcbr, graythresh(Iobrcbr));
figure, imshow(bw), title('bw')
经过上面的操作之后,bw的imcomplement就可以的到图像的背景标注:

由于不希望背景标注离希望分割的目标太近,我们将这个背景进行瘦身操作。这个操作可以利用分水岭变换得到。

D = bwdist(bw);
DL = watershed(D);
bgm = DL == 0;
figure, imshow(bgm), title('bgm')
5 计算修改后的分割函数的分水岭变换

imimposemin函数修改分割函数,使得这个分割函数在前景和背景为1的位置有区域内的较小值。因此这个函数可以用于修改最初得到的梯度图像。使得梯度图像在前景和背景处取值是区域内的较小值,对修改后的函数进行分水岭变换。

gradmag2 = imimposemin(gradmag, bgm | fgm4);
<pre name="code" class="cpp">L = watershed(gradmag2);

 6 将上诉分割结果展示出来第一种方式是利用分割出来的前景和背景对原来的图像进行重新赋值: 
 

I4 = I;
I4(imdilate(L == 0, ones(3, 3)) | bgm | fgm4) = 255;
figure, imshow(I4)
title('Markers and object boundaries superimposed on original image')
第二种方式是将分割得到的标记矩阵显示出来:

Lrgb = label2rgb(L, 'jet', 'w', 'shuffle');
figure, imshow(Lrgb)
title('Lrgb')
第三种方式是利用透明叠加伪彩色来显示结果图像
figure, imshow(I), hold on
himage = imshow(Lrgb);
set(himage, 'AlphaData', 0.3);
title('Lrgb superimposed transparently on original image')

你可能感兴趣的:(图像分割)