购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第6章
图像分割

第5章介绍的图像预处理主要是对图像进行全局处理,而实际检测关注的往往是图像的局部区域。为了使检测范围进一步缩小,可以将感兴趣的局部区域从背景中分离出来,使关键目标更便于辨识和分析。图像分割就是完成这一任务的方法。图像分割的标准可以是像素的灰度、边界、几何形状、颜色,甚至是纹理。

图像分割的方法很多,根据不同的检测图像特征可以使用不同的方法,分割的效果会直接影响视觉分析和识别的准确率。本章将从阈值处理、区域提取、边缘检测3个方面对图像分割的原理和方法进行讨论。

本章主要涉及的知识点如下。

●阈值处理:介绍全局阈值、自适应阈值、局部阈值等常用的阈值分割方法。

●区域生长法:介绍几种区域生长法的常用算子。

●分水岭算法:介绍常见的几种边缘检测算子。

注意

分水岭算法属于基于边缘的图像分割方法,但本章并未详细讲述边缘提取的方法,这部分内容将在第10章详细介绍。

6.1 阈值处理

在场景中选择物体或特征是图像测量或识别的重要基础,而阈值处理是最简单也最常用的区域选择方法,特别适用于目标和背景的灰度有明显区别的情况。下面就介绍几种常用的阈值处理方法。

6.1.1 全局阈值

首先来看什么是阈值。简单来说,阈值就是一个指定的像素灰度值的范围。假设阈值为0~255灰度值,阈值处理就是将图像中的像素灰度值与该阈值进行比较,落在该范围内的像素称为前景,其余的像素称为背景。一般会用黑白两色来表示前景与背景。这样图像就变成了只有黑与白两种颜色的二值图像。

当检测对象的图像灰度与背景差异比较大时,用阈值处理可以很方便地将其与背景分离开来。根据像素与相邻像素之间的灰度值差异设置一个阈值,可以将像素与其相邻像素分隔开来。如果是在图像边缘,可以利用边缘的灰度差值进行简单的阈值处理,有助于沿边界分割图像。在Halcon中,可使用threshold算子进行全局阈值处理。举例如下:

read_image (Image,'data/codes')
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, DarkArea, 0, 128)

该程序的阈值处理结果如图6.1所示,其中图6.1(a)为输入图像,图6.2(b)中的红色区域为阈值处理后提取出的较暗区域。

图6.1 使用threshold算子进行阈值处理的结果

在上面的例子中,threshold算子的第1个参数GrayImage为输入图像,这里用的是灰度图;第2个参数DarkArea为输出的区域,类型为Region;第3个和第4个参数为阈值的区间值,表示0~128灰度范围内的像素区域。

6.1.2 基于直方图的自动阈值分割方法

有时手动设定阈值并不是一个严谨的方法,因为人对图像灰度的感受并不精准,即使对同一场景,当光线有微妙变化时,灰度也会有差异。手动设定阈值在粗估计时可能是一个便捷的方法,但是随着后续计算步骤的叠加,将带来不可估量的误差。在连续采集的图像中,图像的灰度也是动态变化的,环境光照、拍摄角度等因素都会影响图像的灰度。如果阈值是一个固定的值,那么在处理连续图像时结果会不够准确。因此,可以使用自适应阈值进行调节。

自适应阈值是一种基于直方图的阈值。5.3.1小节已经提到过,直方图是图像像素落在0~255这个区间内的数量统计图。通过直方图可以看出图像灰度的大致分布,在有些情况下甚至可以估计检测对象的面积与结构。

在Halcon中使用auto_threshold算子进行自适应阈值处理。该算子可以对单通道图像进行多重阈值处理,其原理是,以灰度直方图中出现的谷底为分割点,对灰度直方图的波峰进行分割。因此,有多少个波峰,就会分割出多少个区域。auto_threshold算子的第3个参数Sigma(此例中为8.0)是一个平滑算子,可以对直方图进行平滑处理。举例如下:

read_image(Image,'data/shapes')
rgb1_to_gray (Image, GrayImage)
auto_threshold(GrayImage,Regions,8.0)

该程序的阈值处理结果如图6.2所示,其中图6.2(a)为灰度图像,包括几种不同灰度的对象,图6.2(b)用3种不同的颜色区分了自动阈值分割出的3个区域。其中圆形与矩形物体因为灰度值相近被分割为同一区域;三角形的灰度值与另外两种有差异,被分割为单独的区域;背景灰度值最大,也被分割为一个单独的区域。

图6.2 auto_threshold算子的自适应阈值处理结果

auto_threshold算子的前两个参数分别为输入的Image图像和输出的Region类型的区域。第3个参数Sigma为对灰度直方图进行高斯平滑的核的大小。5.4节提到过高斯卷积运算,其计算原理是,先确定图像的绝对灰度直方图,然后使用高斯滤波器对该直方图进行平滑处理。在本例中,设Sigma值为8.0,对灰度直方图的平滑效果如图6.3所示。

图6.3 auto_threshold算子对灰度直方图进行平滑的效果对比

图6.3(a)为原始灰度直方图,可以看出波峰比较多,如不处理将产生大量的分割区域,不利于提取出有意义的部分,因此这里将Sigma值设得大一些,使波峰变得平滑。图6.3(b)为Sigma为8.0时对灰度直方图进行高斯平滑后的效果,可见波峰明显减少到了3个,因此图像中自动分割的区域也减少到了3部分。

因此,Sigma的值越大,平滑效果越显著,直方图波峰越少,分割出的区域也越少;反之,Sigma的值越小,直方图平滑的效果越不明显,分割的次数也越多。

注意

可以使用gray_histo算子和gen_region_histo算子查看Sigma参数对灰度直方图的影响。

6.1.3 自动全局阈值分割方法

除了auto_threshold算子外,还常用binary_threshold算子对直方图波峰图像进行自动阈值分割。binary_threshold算子同样利用了直方图,但不同的是,该算子是根据直方图中的像素分布提供可选的分割方法,如使用最大类间方差法或平滑直方图法,都可以自动计算出一个灰度级别用于分割区域。

同时,该算子也可以选择提取较亮还是较暗的范围,尤其适用于在比较亮的背景图像上提取比较暗的字符。举例如下:

read_image (Image, 'data/codes')
rgb1_to_gray (Image, GrayImage)
binary_threshold (GrayImage, RegionMaxSeparabilityLight, 'max_separability',
'dark', UsedThreshold)

该程序运行效果如图6.4所示,其中图6.4(a)为灰度图像,图6.4(b)为使用binary_threshold算子进行阈值分割后的图像。

图6.4 使用binary_threshold算子进行阈值分割的效果

binary_threshold算子的前两个参数分别为输入和输出的对象。第3个参数为分割的方法,这个例子中选择max_separability,表示在直方图中对最大的可分性进行分割;也可以选择smooth_histo,表示平滑直方图,平滑的原理与6.1.2小节的auto_threshold算子类似。第4个参数表示提取前景还是背景,这里选择dark,表示提取较暗的部分;也可以选择light,表示提取较亮的部分。最后一个参数UsedThreshold为返回结果,将返回所用的阈值。

6.1.4 局部阈值分割方法

上文介绍了几种全局阈值分割方法,本小节介绍一个基于局部阈值分割的dyn_threshold算子。它适用于一些无法用单一灰度进行分割的情况,如背景灰度比较复杂,有的部分比前景目标亮,有的部分比前景目标暗;又如前景目标包含多种灰度,因而无法用全局阈值完成分割。该算子利用邻域,通过局部灰度对比,找到一个合适的阈值进行分割。

dyn_threshold算子的应用步骤一般分三步:首先,读取原始图像;然后,使用平滑滤波器对原始图像进行适当平滑;最后,使用dyn_threshold算子比较原始图像与均值处理后的图像局部像素差异,将差异大于设定值的点提取出来。

举一个例子,如图6.5(a)所示,该图中前景部分的字符颜色不均匀,无法用单一的灰度阈值进行提取,因此可以使用局部阈值分割方法进行提取。代码举例如下:

read_image (Image, 'data/text')
*将图像转换为灰度图
rgb1_to_gray (Image, GrayImage)
*由于图像对比度比较低,因此对图像进行相乘,增强对比度
mult_image (GrayImage, GrayImage, ImageResult, 0.005, 0)
*使用平滑滤波器对原始图像进行适当平滑
mean_image (ImageResult, ImageMean, 50,50)
*动态阈值分割,提取字符区域
dyn_threshold (ImageResult, ImageMean, RegionDynThresh, 4, 'not_equal')
*开运算,去除无意义的小的杂点
opening_circle (RegionDynThresh, RegionOpening, 1.5)
*显示结果
dev_clear_window()
dev_display (RegionOpening)

该段代码运行效果如图6.5所示,其中图6.5(a)为灰度图像,图像中的字符部分颜色不均;图6.5(b)为用dyn_threshold算子进行阈值分割后的图像。

图6.5 dyn_threshold算子阈值分割效果

再举一个使用动态阈值进行轮廓提取的例子。如图6.6(a)所示,该图的前景与背景部分灰度都不均匀,因而无法用全局阈值进行提取,这时可以用dyn_threshold算子提取前景的轮廓。代码如下:

read_image (Image, 'data/garlic')

read_image (Image, 'data/garlic')
*将图像转换为灰度图
rgb1_to_gray (Image, GrayImage)
*使用平滑滤波器对原始图像进行适当平滑
mean_image (GrayImage, ImageMean, 30,30)
*动态阈值分割,提取字符区域
dyn_threshold (GrayImage, ImageMean, RegionDynThresh, 30, 'not_equal')
*腐蚀操作,去除杂点
erosion_circle (RegionDynThresh, RegionClosing, 1.5)

该段代码运行效果如图6.6所示,其中图6.6(a)为灰度图像,前景目标灰度复杂,背景因为光照不均匀,局部甚至比前景目标更亮;图6.6(b)为使用dyn_threshold算子进行阈值分割后的图像。

图6.6 使用dyn_threshold算子进行阈值分割提取轮廓

dyn_threshold算子的第1个参数为输入的灰度图像。第2个参数为输入的预处理图像,这里使用Mean_Image得到了一张均值图像,用于做局部灰度对比。第3个参数为输出的阈值区域。第4个参数是offset值,是将原图与均值图像作对比后设定的值,灰度差异大于该值的将被提取出来。第5个参数决定了提取的是哪部分区域,一般有如下4个选择。

(1)light:表示原图中大于等于预处理图像像素点值加上offset值的像素被选中。

(2)dark:表示原图中小于等于预处理图像像素点值减去offset值的像素被选中。

(3)equal:表示原图中像素点大于预处理图像像素点值减去offset值,小于预处理图像像素点值加上offset值的点被选中。

(4)not_equal:表示与equal相反,它的提取范围在equal范围以外。

该算子适用于在复杂背景下提取前景目标的轮廓,或无法用单一灰度阈值提取边缘等情况。

注意

实际应用中可以根据图像的灰度值,设置均值滤波器的系数和动态阈值的参数。

6.1.5 其他阈值分割方法

除了上述介绍的方法外,在Halcon中还有其他几种方法也可以进行阈值分割,举例如下。

1. var_threshold算子

除了dyn_threshold算子可以利用局部像素灰度差进行分割外,var_threshold算子也是一种基于局部动态阈值的分割方法。该方法分割的依据是局部的均值和标准差,选择图像中邻域像素满足阈值条件的区域进行分割。该阈值不是一个固定的值,而是在点( x , y )的邻域中使用矩形mask进行扫描,分别用点( x , y )的灰度与均值图像中的点( x , y )的灰度,和矩形的中心点的标准差灰度进行比较。该矩形mask的长宽需要是奇数,这样便于找到矩形的中心点,其具体的宽和高应该略大于待分割的图像区域。举例如下:

read_image (Image,'data/holes')
rgb1_to_gray (Image, GrayImage)
*设置矩形,选择感兴趣区域
gen_rectangle1 (Rectangle, 170, 80, 370, 510)
reduce_domain (GrayImage, Rectangle, ImageReduced)
var_threshold (ImageReduced, Region, 15, 15, 0.2, 35, 'dark')

该程序的运行效果如图6.7所示,其中图6.7(a)为输入图像,图6.7(b)为使用var_threshold算子进行阈值分割后的图像,灰度变化符合阈值的区域被提取了出来。

图6.7 var_threshold算子分割效果

该算子的第1个参数为输入的灰度图像;第2个参数为输出的阈值区域;第3个和第4个参数为用于扫描邻域的矩形mask的宽和高;第5个参数为标准差因子,用于计算灰度标准差,默认为0.2;第6个参数为设定的绝对阈值,该值用于比较矩形区域内的灰度标准差与均值图像的最小灰度值;第7个参数决定了提取的是哪部分区域,一般有4个选择,即dark、light、equal、not_equal,具体解释与dyn_threshold算子相同。

2. char_threshold算子

该算子一般用来提取字符,适用于在明亮的背景上提取黑暗的字符。该算子的运算过程如下:首先计算一个灰度曲线;然后给定一个Sigma值,用于平滑这个曲线;最后将前景与背景区分开来。

分割的阈值取决于直方图中的最大值。例如,如果选择百分比为95%,灰度阈值将锁定在距离直方图峰值的5%左右的区域,因为这个算子假定的是字符的灰度都暗于背景。举例如下:

read_image (Char, 'data/char')
rgb1_to_gray (Char, GrayImage)
char_threshold (GrayImage, GrayImage, Characters, 6, 95, Threshold)

该程序的运行效果如图6.8所示,其中图6.8(a)为灰度图像,图6.8(b)为使用char_threshold算子进行阈值分割后的图。

图6.8 char_threshold算子阈值分割效果

与binary_threshold算子相比,char_threshold算子适用于直方图的波峰之间没有明确的谷底的情况,或者是直方图没有明确的峰值的情况。这种情况是可能出现的,如图像中只包含几个字符,或者是存在不规则光照。

3. dual_threshold算子

该算子表示双阈值处理,其原型如下:

dual_threshold(Image : RegionCrossings : MinSize, MinGray, Threshold :)

该定义来自Halcon官方文档。其第1个参数为输入图像,第2个参数为阈值处理的输出区域,第3个参数为分割出的区域的最小面积,第4个参数为区域的灰度下限,第5个参数为灰度阈值Threshold。该阈值处理可以看作是对两个方向进行了阈值分割,不但提取出了灰度大于等于Threshold值的范围,也提取出了小于等于-Threshold值的范围。

之所以会有负的灰度值,是因为dual_threshold算子在处理之前一般会先对原始图像进行拉普拉斯操作,输入的图像一般是拉普拉斯图像,这类图像包含正的和负的灰度值的区域。

满足灰度阈值并符合面积条件,同时还满足最小灰度条件的区域将最终被分割出来。

6.2 区域生长法

如果想要获得具有相似灰度的相连区域,可以使用区域生长法寻找相邻的符合条件的像素。区域生长法的基本思想是,在图像上选定一个“种子”像素或“种子”区域,然后从“种子”的邻域像素开始搜索,将灰度或者颜色相近的像素附加在“种子”上,最终将代表同一物体的像素全部归属于同一“种子”区域,达到将目标物体分割出来的目的。

注意

区域生长法的算法执行速度非常快,适用于对检测速度要求高的情况。

6.2.1 regiongrowing算子

Halcon中的regiongrowing算子实现了区域生长的功能,它能将灰度相近的相邻像素合并为同一区域。regiongrowing算子的原型如下:

regiongrowing(Image : Regions : Row, Column, Tolerance, MinSize : )

其中各参数的含义如下。

(1)参数1:Image为输入的单通道图像。

(2)参数2:Regions为输出的一组区域。

(3)参数3和4:Row、Column分别为矩形区域的宽和高,需要是奇数,以便计算中心点坐标。默认为1,1,也可以选择其他奇数。

(4)参数5:Tolerance为灰度差值的分割标准。如果另一个点的灰度与种子区域的灰度差值小于Tolerance,则认为它们可以合并为同一区域。这个值默认为6.0。

(5)参数6:MinSize,表示输出区域的最小像素数,默认为100。

其工作步骤如下。

(1)设定一个尺寸为Row*Column的卷积核,以及一个作为分界依据的像素灰度差值Tolerance。

(2)使用上述指定尺寸的卷积核在原图上进行扫描,并计算卷积核内矩形图像的中心点灰度与邻域矩形图像的中心点灰度差。如果差值小于Tolerance,则将这两个矩形区域合并为同一个。

卷积核默认为1*1,一般长宽都为奇数。如果大于1*1,需要先对图像进行平滑处理,平滑的卷积核大小至少为Row*Colum,这是为了使矩形中心更突出。如果图像上的噪点比较多并且卷积核比较小,也可以省略平滑这一步骤,以减少误判。

(3)对合并后的区域进行判断,如果该区域包含的像素数大于设定的MineSize,则输出结果区域。举例如下:

*导入图像
read_image(Image,'data/village')
*对原图进行均值处理,选用5*5的滤波器
mean_image(Image,Mean,5,5)
*使用regiongrowing算子寻找颜色相似的邻域
regiongrowing(Mean,Regions,1,1,3.0,100)
*对提取区域进行形态学处理,使区域更加平滑和完整
closing_circle (Regions, RegionClosing, 3.5)

使用regiongrowing算子进行区域分割的效果如图6.9所示。

图6.9 使用regiongrowing算子进行区域分割的效果

图6.8(a)为输入的原始图像(该图像来自网络新闻),图6.8(b)为使用regiongrowing算子进行区域生长后分割出的区域。由图6.9可以看出,颜色相近的邻域被合并成了同一区域,并以同一种颜色显示。分割的效果与滤波器的方法、尺寸有关,也与regiongrowing算子的参数有关,可根据实际需要进行调节。

6.2.2 regiongrowing_mean算子

regiongrowing_mean算子的作用与regiongrowing算子类似,也是使用区域生长法进行分割。不同的是,regiongrowing_mean 算子的输入需要是灰度均值图像。regiongrowing_mean算子的原型如下:

regiongrowing_mean(Image : Regions : startRow, startColumn,Tolerance,MinSize : )

其中各参数的含义如下。

(1)参数1:Image为输入的单通道图像。

(2)参数2:Regions为输出的一组区域。

(3)参数3和4:startRow、startColumn分别为起始生长点的坐标。

(4)参数5:Tolerance为灰度差值的分割标准。如果另一个点的灰度与种子区域的灰度差值小于Tolerance,则认为它们可以合并为同一区域。这个值默认为5.0。

(5)参数6:MinSize为输出区域的最小像素数,默认为100。

该算子指明了开始进行区域生长算法的点( x , y )的坐标,并以指定的点为中心,不断搜索其邻域,寻找符合设定条件的区域。这里的条件有两种,一是区域边缘的灰度值与当前均值图中对应的灰度值的差小于Tolerance参数的值;二是区域包含的像素数应大于MinSize参数的值。举例如下:

*读取图像
read_image (Image, ' data/village')
*对原图进行均值处理,选用circle类型的中值滤波器
median_image (Image, ImageMedian, 'circle', 2, 'mirrored')
*使用regiongrowing算子寻找颜色相似的邻域
regiongrowing (ImageMedian, Regions, 1, 1, 3, 500)
*对图像进行粗略的区域分割,提取满足条件的各个独立区域
shape_trans (Regions, Centers, 'inner_center')
connection (Centers, SingleCenters)
*计算出初步提取的区域的中心点坐标
area_center (SingleCenters, Area, Row, Column)
*以均值灰度图像为输入,进行区域生长计算,计算的起始坐标为上一步的各区域中心
regiongrowing_mean (ImageMedian, RegionsMean, Row, Column, 25, 100)

这样满足参数条件的相似邻域就合并成了一个区域,提取的效果如图6.10所示。

图6.10(a)为输入的原始图像(该图像原始图来自网络新闻),图6.10(b)为使用regiongrowing_mean算子进行区域生长后分割出的区域。可以看出,与图6.9相比,图6.10分割出的区域单个面积更大,更多的小面积区域被大的邻近区域合并,边界也更加清晰。可以根据实际需要调节所用的参数,以便更理想地分割出目标物体。

图6.10 使用regiongrowing_mean算子进行区域分割的效果

6.3 分水岭算法

分水岭算法是一种典型的基于边缘的图像分割算法,通过寻找区域之间的分界线,对图像进行分割。“分水岭”这个名字与一种地貌特点有关,它的思想是,把图像的灰度看作一张地形图,其中像素的灰度表示该地点的高度。灰度值低的区域是低地,灰度值越高,地势越高。

低地聚集的地方如同一块盆地,如果模拟向整片区域注水,那么每块盆地将成为一个单独的积水区,即图像上的分割区域,盆地与盆地之间的边界就是区域的边界。随着注水的量越来越多,盆地的积水面积会不断扩大,边界区域则会越来越小,最后形成的分割边界就是分水岭。

分水岭算法能较好地适用于复杂背景下的目标分割,特别是具有蜂窝状结构的画面的内容分割。Halcon中使用watersheds算子提取图像的分水岭。该算子的原型如下:

watersheds(Image : Basins, Watersheds : : )

其中各参数的含义如下。

(1)参数1:Image为输入的图像,一般为单通道图像。这里要注意,因为盆地一般指的是灰度值低的区域,所以如果前景目标比较亮而背景比较暗,可以在导入图像后使用invert_image算子将图像颜色进行反转。

(2)参数2:Basins为输出的盆地区域。

(3)参数3:Watersheds为输出的分水岭区域。一般一幅输入图像对应一个分水岭区域,而输出的Basins区域则是多个区域的集合。

注意

如果图像上包含过多的精细区域或者噪点,输出的区域数量将非常庞大,并影响算法的速度。

除了watersheds算子外,也可以使用watersheds_threshold算子进行分水岭分割。二者的区别在于,后者比前者多了一步操作,即在得到初步的分水岭分割结果之后,将灰度小于阈值的分水岭合并。具体来说,假设分水岭的最小灰度为 W min ,分水岭两侧的“洼地”区域的最小灰度分别为 B 1 B 2 ,如果max{( W min - B 1 ,),( W min - B 2 ,)}的值小于阈值,则将这两个“洼地”区域合并,分水岭消失。通过这样的阈值处理,符合灰度阈值条件的灰度“洼地”区域即被提取出来。该算子的原型如下:

watersheds_threshold(Image : Basins:Threshold: )

其中各参数的含义如下。

(1)参数1:Image为输入的图像,一般为单通道图像。如果前景目标比较亮而背景比较暗,可以在导入图像后使用invert_image算子将图像颜色进行反转。

(2)参数2:Basins为输出的盆地区域。

(3)参数3:Threshold为设置的灰度阈值。建议该值不要超过原图的最大灰度,否则将无法提取出分水岭,图像整体将作为一个区域被提取出来。

这里以一个实际场景图片为例,介绍图像分水岭算法的算子与应用。案例的图像如图6.11所示,其中:图6.11(a)为输入的原始图像,图6.11(b)为使用Watersheds算子进行分割的结果,图6.11(c)为提取出的缺陷区域,并以不同的颜色对分割出的区域进行了区分。

图6.11 使用watersheds算子对木材缺陷图像进行分水岭分割

使用分水岭算法进行分割的代码如下:

*输入待检测的木材图像
read_image (Image, 'data/woodboard')
*将原始图转化为灰度图,便于后续的平滑处理
rgb1_to_gray (Image, GrayImage)
*对单通道图像进行高斯平滑处理,以去除噪声
gauss_filter (GrayImage, ImageGauss, 11)
*对高斯平滑后的图像进行分水岭处理与阈值分割,提取出盆地区域
watersheds (ImageGauss, Basins1, Watersheds)
watersheds_threshold(ImageGauss, Basins, 50)

经过上述步骤,即可得到图像中的灰度“洼地”区域,结合图像的内容,这部分区域即为木材缺陷的局部区域。 i9KByEzAZlZoWQUqu4dTb1eFrUuzRShsWwkFqKu/oGDVQJSUIPUMX3u+11ILZS0r

点击中间区域
呼出菜单
上一章
目录
下一章
×