分水岭算法
Watershed Algorithm(分水岭算法),顾名思义,就是根据分水岭的构成来考虑图像的分割。现实中我们可以或者说可以想象有山有湖的景象,那么那一定是水绕 山,山围水的情形。当然在需要的时候,要人工构筑分水岭,以防集水盆之间的互相穿透。而区分高山(plateaus)与水的界线,以及湖与湖之间的间隔或 都是连通的关系,就是我们可爱的分水岭(watershed)。
如果图像中的目标物体是连接在一起的,则分割起来会更困难,分水岭分割算法经常用于处理这类问题,
通常会取得比较好的效果。分水岭分割算法把图像看成一幅“地形图”,
其中亮度比较强的区域像素值较大,而比较暗的区域像素值较小,通过寻找“汇水盆地”和“分水岭界限”,对图像进行分割。
案例
案例参考matlab官网案例,添加了详细注释,做出一定的调整,更容易让读者理解和接受。
实现功能:
将明显的梨从一堆梨子中分离出来
最终结果:
文末将回答一下几个问题:
(1) 如果采用最大类间方差阈值分割方法进行分割,效果如何?为什么?
(2) 直接用分水岭分割把“pears.png”分割好么?为什么?
(3) 如何获得前景标记?
(4) Imregionalmax是什么作用,请举例说明。
(5) bwareaopen是什么作用,请举例说明。它是不是用数学形态学算法实现?
(6) 如何获得背景标记?
(7) 最终如何用前景标记和背景标记实现标记分水岭分割?
第一步:读入彩色图像,将其转化成灰度图像
clc; clear ; close ;
rgb = imread('pears.png');
if ndims(rgb) == 3
I = rgb2gray(rgb);
else
I = rgb;
end
figure('units', 'normalized','Name','图像读取:原图及灰度图比较');
subplot(1, 2, 1); imshow(rgb); title('原图');
subplot(1, 2, 2); imshow(I); title('灰度图');
第2步:方法1:将梯度幅值作为分割函数
使用Sobel边缘算子对图像进行水平和垂直方向的滤波,然后求取模值, sobel算子滤波后的图像在边界处会显示比较大的值,在没有边界处的值会很小。
第一种方法是直接对梯度幅值图像使用分水岭算法
hy = fspecial('sobel');
hx = hy';
Iy = imfilter(double(I), hy, 'replicate');
Ix = imfilter(double(I), hx, 'replicate');
gradmag = sqrt(Ix.^2 + Iy.^2);
figure('units', 'normalized','Name','直接计算梯度幅值作为分割函数的结果');
subplot(1, 3, 1); imshow(I,[]), title('灰度图像')
subplot(1, 3, 2); imshow(gradmag,[]), title('梯度幅值图像')
L = watershed(gradmag);
Lrgb = label2rgb(L);
subplot(1, 3, 3); imshow(Lrgb); title('梯度幅值做分水岭变换')
直接使用梯度模值图像进行分水岭算法得到的结果往往会存在过度分割的现象。因此通常需要分别对前景对象和背景对象进行标记,以获得更好的分割效果。
第3步:使用形态学技术“基于开的重建”和“基于闭的重建”来清理图像。
se = strel('disk', 20);
Io = imopen(I, se);
% 通过腐蚀后重建来做基于开的重建计算。
Ie = imerode(I, se);
Iobr = imreconstr