图像分割(Image Segmentation)
作者:王先荣
前言
图像分割指的是将数字图像细分为多个图像子区域的过程,在OpenCv中实现了三种跟图像分割相关的算法,它们分别是:分水岭分割算法、金字塔分割算法以及均值漂移分割算法。它们的使用过程都很简单,下面的文章权且用于记录,并使该系列保持完整吧。
分水岭分割算法
分水岭分割算法需要您或者先前算法提供标记,该标记用于指定哪些大致区域是目标,哪些大致区域是背景等等;分水岭分割算法的分割效果严重依赖于提供的标记。OpenCv中的函数cvWatershed实现了该算法,函数定义如下:
void
cvWatershed(
const
CvArr
*
image, CvArr
*
markers)
其中:image为8为三通道的彩色图像;
markers是单通道整型图像,它用不同的正整数来标记不同的区域,下面的代码演示了如果响应鼠标事件,并生成标记图像。
//
当鼠标按下并在源图像上移动时,在源图像上绘制分割线条
private
void
pbSource_MouseMove(
object
sender, MouseEventArgs e)
{
//
如果按下了左键
if
(e.Button
==
MouseButtons.Left)
{
if
(previousMouseLocation.X
>=
0
&&
previousMouseLocation.Y
>=
0
)
{
Point p1
=
new
Point((
int
)(previousMouseLocation.X
*
xScale), (
int
)(previousMouseLocation.Y
*
yScale));
Point p2
=
new
Point((
int
)(e.Location.X
*
xScale), (
int
)(e.Location.Y
*
yScale));
LineSegment2D ls
=
new
LineSegment2D(p1, p2);
int
thickness
=
(
int
)(LineWidth
*
xScale);
imageSourceClone.Draw(ls,
new
Bgr(255d, 255d, 255d), thickness);
pbSource.Image
=
imageSourceClone.Bitmap;
imageMarkers.Draw(ls,
new
Gray(drawCount), thickness);
}
previousMouseLocation
=
e.Location;
}
}
//
当松开鼠标左键时,将绘图的前一位置设置为(-1,-1)
private
void
pbSource_MouseUp(
object
sender, MouseEventArgs e)
{
previousMouseLocation
=
new
Point(
-
1
,
-
1
);
drawCount
++
;
}
您可以用类似下面的方式来使用分水岭算法:
使用分水岭分割算法
金字塔分割算法
金字塔分割算法由cvPrySegmentation所实现,该函数的使用很简单;需要注意的是图像的尺寸以及金字塔的层数,图像的宽度和高度必须能被2整除,能够被2整除的次数决定了金字塔的最大层数。下面的代码演示了如果校验金字塔层数:
校验金字塔分割的金字塔层数
使用金字塔分割的示例代码如下:
使用金字塔分割算法
均值漂移分割算法
均值漂移分割算法由cvPryMeanShiftFiltering所实现,均值漂移分割的金字塔层数只能介于[1,7]之间,您可以用类似下面的代码来使用它:
使用均值漂移分割算法
函数cvPryMeanShiftFiltering在EmguCv中没有实现,我们可以用下面的方式来使用:
调用均值漂移分割
分割效果及性能对比
上述三种分割算法的效果如何呢?下面我们以它们的默认参数,对一幅2272x1704大小的图像进行分割。得到的结果如下所示:

图1 分水岭分割算法(左图白色的线条用于标记区域)

图2 金字塔分割算法

图3 均值漂移分割算法
从上面我们可以看出:
(1)分水岭分割算法的分割效果效果最好,均值漂移分割算法次之,而金字塔分割算法的效果最差;
(2)均值漂移分割算法效率最高,分水岭分割算法接近于均值漂移算法,金字塔分割算法需要很长的时间。
值得注意的是分水岭算法对标记很敏感,需要仔细而认真的绘制。
本文的完整代码如下:
本文完整代码
感谢您耐心看完本文,希望对您有所帮助。
本文介绍了图像分割中的三种算法:分水岭分割、金字塔分割及均值漂移分割。重点讲解了每种算法的工作原理及使用方法,并通过实验比较了它们的分割效果与性能。

726

被折叠的 条评论
为什么被折叠?



