标记控制的分水岭分割
此示例说明如何使用分水岭分割来分离图像中相互接触的对象。分水岭变换通过将图像视为一个曲面,其中亮像素表示较高处,暗像素表示较低处,从而找出图像中的“汇水盆地”和“分水岭脊线”。
如果您能够标识或“标记”前景对象和背景位置,使用分水岭变换的分割效果会更好。标记控制的分水岭分割遵循以下基本过程:
计算分割函数。这得到是一个图像,其中暗区域是您尝试分割的对象。
计算前景标记。这些是每个对象中连通的像素斑点。
计算背景标记。这些像素不是任何对象的一部分。
修正分割函数,使其仅在前景和背景标记位置具有最小值。
计算修正分割函数的分水岭变换。
步骤 1:读入彩色图像并将其转换为灰度
rgb = imread("pears.png"); I = im2gray(rgb); imshow(I) text(732,501,"Image courtesy of Corel(R)",... "FontSize",7,"HorizontalAlignment","right")
步骤 2:使用梯度幅值作为分割函数
计算梯度幅值。对象边界处的梯度较高,对象内部的梯度较低(大多数情况下)。
gmag = imgradient(I);
imshow(gmag,[])
title("Gradient Magnitude")
您能通过直接对梯度幅值使用分水岭变换来分割图像吗?
L = watershed(gmag);
Lrgb = label2rgb(L);
imshow(Lrgb)
title("Watershed Transform of Gradient Magnitude")
不能。如果没有额外的预处理,例如以下标记计算,直接使用分水岭变换通常会导致“过度分割”。
步骤 3:标记前景对象
此处可以应用多种过程来找到前景标记,这些标记必须是每个前景对象内部的连通像素斑点。在此示例中,您使用称为“开运算重构”和“闭运算重构”的形态学方法来“清理”图像。这些运算将在每个对象内创建最大值平面,使用 imregionalmax
可以找出这些最大值。
开运算是先腐蚀后膨胀,而开运算重构是先腐蚀后进行形态学重构。让我们对两者进行比较。首先,使用 imopen
进行开运算。
se = strel("disk",20); Io = imopen(I,se); imshow(Io) title("Opening")
接下来,使用 imerode
和 imreconstruct
进行开运算重构。
Ie = imerode(I,se);
Iobr = imreconstruct(Ie,I);
imshow(Iobr)
title("Opening-by-Reconstruction")
在开运算后闭运算可以去除暗点和针状标记。对常规形态学闭运算和闭运算重构进行比较。首先尝试 imclose
:
Ioc = imclose(Io,se);
imshow(Ioc)
title("Opening-Closing")
现在使用 imdilate
,然后使用 imreconstruct
。请注意,您必须对 imreconstruct
的输入和输出进行补充。
Iobrd = imdilate(Iobr,se);
Iobrcbr = imreconstruct(imcomplement(Iobrd),imcomplement(Iobr));
Iobrcbr = imcomplement(Iobrcbr);
imshow(Iobrcbr)
title("Opening-Closing by Reconstruction")
通过比较 Iobrcbr
和 Ioc
可以看到,在去除小瑕疵而不影响对象整体形状方面,基于重构的开运算和闭运算比标准的开运算和闭运算更高效。计算 Iobrcbr
的局部最大值,以获得良好的前景标记。
fgm = imregionalmax(Iobrcbr);
imshow(fgm)
title("Regional Maxima of Opening-Closing by Reconstruction")
为了帮助解释结果,可将前景标记图像叠加在原始图像上。
I2 = labeloverlay(I,fgm);
imshow(I2)
title("Regional Maxima Superimposed on Original Image")
请注意,一些大部分被遮挡和遮蔽的对象未被标记,这意味着在最终结果中不会正确分割这些对象。此外,一些对象中的前景标记一直延伸到对象的边缘。这意味着您应清理标记斑点的边缘,然后将它们缩小一点。您可以通过先闭运算再腐蚀来实现这一点。
se2 = strel(ones(5,5)); fgm2 = imclose(fgm,se2); fgm3 = imerode(fgm2,se2);
此过程往往会留下一些必须删除的杂散孤立像素。您可以使用 bwareaopen
来实现这一点,它可以删除像素少于特定数量的所有斑点。
fgm4 = bwareaopen(fgm3,20);
I3 = labeloverlay(I,fgm4);
imshow(I3)
title("Modified Regional Maxima Superimposed on Original Image")
步骤 4:计算背景标记
现在您需要标记背景。在清理后的图像 Iobrcbr
中,暗像素属于背景,因此您可以首先进行阈值化运算。
bw = imbinarize(Iobrcbr);
imshow(bw)
title("Thresholded Opening-Closing by Reconstruction")
背景像素为黑色,但理想情况下,我们不希望背景标记太靠近我们尝试分割的对象的边缘。我们将通过计算 bw
前景的“影响区骨架”(即 SKIZ)来“精简”背景。通过计算 bw
的距离变换的分水岭变换,然后寻找结果的分水岭脊线 (DL == 0
),可以实现这一目标。
D = bwdist(bw);
DL = watershed(D);
bgm = DL == 0;
imshow(bgm)
title("Watershed Ridge Lines")
步骤 5:计算分割函数的分水岭变换
函数 imimposemin
可用于修正图像,使其仅在特定所需位置具有局部最小值。在此处,您可以使用 imimposemin
来修正梯度幅值图像,使其局部最小值只出现在前景和背景标记像素上。
gmag2 = imimposemin(gmag, bgm | fgm4);
最后,计算基于分水岭的分割。
L = watershed(gmag2);
步骤 6:可视化结果
一种可视化方法是在原始图像上叠加前景标记、背景标记和分割的对象边界。您可以根据需要使用膨胀来使某些方面(如对象边界)更明显可见。对象边界位于 L == 0
的位置。二值前景和背景标记缩放为不同整数值,以便对它们分配不同标签。
labels = imdilate(L==0,ones(3,3)) + 2*bgm + 3*fgm4;
I4 = labeloverlay(I,labels);
imshow(I4)
title("Markers and Object Boundaries Superimposed on Original Image")
此可视化图像说明前景和背景标记的位置如何影响结果。在一些位置,部分被遮挡的较暗对象与其较亮的相邻对象已合并,因为被遮挡的对象没有前景标记。
另一种有用的可视化方法是将标签矩阵显示为彩色图像。标签矩阵,如 watershed
和 bwlabel
生成的矩阵,可通过使用 label2rgb
转换为真彩色图像,以实现可视化目的。
Lrgb = label2rgb(L,"jet","w","shuffle"); imshow(Lrgb) title("Colored Watershed Label Matrix")
您可以使用透明方式将此伪颜色标签矩阵叠加到原始强度图像上。
figure imshow(I) hold on himage = imshow(Lrgb); himage.AlphaData = 0.3; title("Colored Labels Superimposed Transparently on Original Image")
另请参阅
watershed
| imopen
| imreconstruct
| imclose
| imdilate
| imregionalmax
| imerode
| bwareaopen
| bwdist
| label2rgb
| imcomplement
| labeloverlay
| imgradient