图像二值化是图像分析与处理中最常见最重要的处理手段,二值处理方法也非常多。越精准的方法计算量也越大。参考博客:
threshold(Image : Region : MinGray, MaxGray : )
——使用全局固定阈值分割图像
阈值从输入图像中选取灰度值g满足以下条件的像素点
满足条件的图像的所有点作为一个区域返回。如果传递多个灰度值间隔(MinGray和MaxGray的元组),则每个间隔返回一个单独的区域。对于向量场图像,阈值不应用于灰度值,而是应用于向量的长度。
应用一:利用灰度直方图确定阈值进行图像分割。一般是物体与背景之间存在一个明显的灰度差,直方图会存在两个波峰一个是目标一个是背景,那么阈值就是物体与背景之间的最小值。
read_image (Image, 'clip')
*计算直方图
gray_histo (Image, Image, AbsoluteHisto, RelativeHisto)
*将直方图转换为区域(包含直方图的区域;输入的直方图;直方图中心的行/列坐标;直方图的比例因子)
gen_region_histo (Region, AbsoluteHisto, 255, 255, 1)
*利用直方图获取阈值
histo_to_thresh (AbsoluteHisto,10, MinThresh, MaxThresh)
*期望阈值
TarGetGray:=23
for Index := |MinThresh|-1 to 0 by -1
if(MinThresh[Index]<=TarGetGray)
MinThresh:= MinThresh[Index]
break
endif
endfor
for Index1 := 0 to |MaxThresh|-1 by 1
if (MaxThresh[Index1]>=TarGetGray)
MaxThresh:=MaxThresh[Index1]
break
endif
endfor
*全局阈值分割
threshold (Image, Region1, MinThresh, MaxThresh)
参考: 阈值分割算子之OSTU算法(binary_threshold)
binary_threshold(Image : Region : Method, LightDark : UsedThreshold)
——自动全局阈值分割(自动确定的全局阈值分割单通道图像,并在区域中返回分割后的区域)
输入:
输出:
read_image (Image, 'clip')
binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)
例如,分割均匀照明的背景上有用的字符。binary_threshold还返回UsedThreshold中使用的阈值。
使用的阈值由方法中给出的方法确定。目前,该操作符提供了以下两个方法:
’max_separability’:最大限度的可分性, ‘smooth_histo’:直方图平滑。
这两种方法只能用于具有双峰直方图的图像。(如下图)
smooth_histo方法提供的功能与操作符bin_threshold提供的功能相同。方法’max_separability’倾向于为UsedThreshold确定较小的值。此外,它对柱状图中的稀疏孤立峰不那么敏感,而且通常比‘smooth_histo’更快。
最大限度的可分性(max_separability):
通过选择Method= ’ max_separability ',根据“灰度直方图的阈值选择方法”的灰度直方图自动阈值调用。该算法首先计算图像的直方图,然后利用统计矩找到将像素分割为前景和背景的最优阈值,并最大化这两个类之间的可分性。此方法仅适用于byte和uint2图像。
如果LightDark = ‘light’,则选中所有灰度值大于或等于"T*"的像素。
如果LightDark = ‘dark’,则选中所有灰色值小于"T*"的像素。
直方图平滑(smooth_histo):
通过选择Method = 'smooth_histo ’ binary_threshold可以通过以下方式确定阈值:首先确定灰度值的相对直方图。然后,从直方图提取相关的最小值,作为阈值操作的参数。为了减少最小值,直方图被平滑处理为一个高斯函数,就像在auto_threshold中一样。在平滑直方图中,掩模尺寸增大,直到最小值。然后,阈值设置为这个最小值的位置。
如果LightDark = ‘light’,则选中所有灰度值大于或等于"T*"的像素。
如果LightDark = ‘dark’,则选中所有灰色值小于"T*"的像素。
dyn_threshold(OrigImage, ThresholdImage : RegionDynThresh : Offset, LightDark : )
——局部动态阈值分割 Dynamic Threshold
dyn_threshold 这个算子就是根据一套灰度值比较规则来选择原图像中那些灰度值符合这个公式的像素点。
令
g_{o} = g_{OrigImage}; 代表原图中的像素点的灰度值
g_{t} = g_{ThresholdImage};代表参考图中的像素点的灰度值
我们的做法是把参考图像的灰度值加上(减去)一个Offset,然后去和原图的像素点逐像素对应地进行比较。
当参数 LightDark = ‘light’ 时,
既然选择light,那就代表提取相对参考图来说亮一些的地方,那么自然要选择那些灰度值比 gt + Offset 要大的像素点。
当参数 LightDark = ‘dark’ 时:
如果要提取的是比参考图要暗一些的区域,那么自然要选择比g_t的灰度值要小的那些像素点,但是这样直接比较的话提取的小区域太多了,并没有很好地提取出相对参考图来说很明显有差别的那部分,所以我们才给定Offset这个参数用来修正。这样给参考图的灰度值一减掉Offset,提取出来的和参考的之间的差距就会很明显。
当参数 LightDark = ‘equal’ 时,
选择equal的意思是选择那些和参考图的差不多的,只要在这个合理的范围内的都算。
通常,阈值图像是原始图像的平滑版本(例如,通过应用mean_image、binomial_filter、gauss_filter等)。然后dyn_threshold 的效果类似于将 threshold 应用到经过高通滤波的原始图像上(参见highpass_image)。dyn_threshold可以提取出物体的轮廓,其中物体的大小(直径)由低通滤波器的掩码大小和物体边缘的振幅决定:
所选择的模板越大,找到的region就会越大。一般来说,模板的大小应该是我们要提取的物体直径大小的两倍左右。还有很重要的一点是最好不要把Offset这个变量设置为0,因为这样会导致最后找到太多很小的regions,而这基本上都是噪声。所以这个值最好是在5-40之间,值选择的越大,提取出来的regions就会越小。
经过dyn_threshold这个算子处理之后,我们就可以提取一个物体的轮廓了,具体提取的方法当然要用到什么类似select_shape之类的算子,当然,这里最重要的是gen_contour_region_xld这个算子,用你刚才提取出来的这些区域生成XLD轮廓线,这样就达到了提取物体轮廓的目的。 注意,我们这样提取出来的所有符合条件的像素点都会被返回到一个region中去,所以如果你要分开的区域的话,就用connection这个算子再计算一下就好啦。
threshold是最简单的阈值分割算子,理解最为简单;binary_threshold是自动阈值算子,它可以自动选出暗(dark)的区域,或者自动选出亮(light)的区域,理解起来也没有难度。
动态阈值算子dyn_threshold理解起来稍微复杂一点,使用dyn_threshold算子的步骤基本是这样的:
① 将原图进行滤波模糊处理。
② 用原图和模糊后的图逐个像素做比较,它可以根据参数分割出原图比模糊后的图灰度高(或者低)若干个灰度值的区域。
举例如下:
处理代码:
read_image (Image, ‘C:/Users/happy xia/Desktop/dynPic.png‘)
mean_image (Image, ImageMean, 9, 9)
dyn_threshold (Image, ImageMean, RegionDynThresh, 10, ‘dark‘)
程序分析:本例中,将图片模糊后,点阵字的黑色扩散了,随之就是字的黑色不如原图那么黑了,那么通过给定的限值“10”和“dark”,就可以将原图比模糊后的图暗10个灰阶以上的区域(即黑色文字部分)选出来了。
Halcon阈值化算子dual_threshold和var_threshold的理解
var_threshold(Image : Region : MaskWidth, MaskHeight, StdDevScale, AbsThreshold, LightDark : )
——均值和标准偏差局部阈值分割,能够较好的分开目标和背景,对不适合的参数设置不敏感。
var_threshold图像灰度值在均值与方差之和以上或在均值与方差之差以下
1)应用示例
var threshold (Image, Region, 4, 4, 0.2, 12, 'dark' )
在该程序中,先用4x4的掩膜在图像上逐像素游走,用原图中的当前像素和对应掩膜中16个像素的灰度均值对比,找出暗(dark)的区域。当原图像素灰度比对应的掩膜灰度均值低(0.2,12)个灰阶时(本程序中StdDevScale = 0.2, AbsThreshold = 12),该区域被分割出来。
问题的关键就是理解如何通过StdDevscale和AbsThreshold来确定用于分割的阈值。
实测发现,这里的比较大小是带符号比较,由于标准差是非负数,当StdDevscale <0时,(StdDevscalex标准差) <=0恒成立,所以此时的取值就是(StdDevScale x标准差) 。
帮助文档中StdDevscale的推荐值范围是-1-1,一般通过上面的例子可知,一般的明显的黑白过度处的在50左右,StdDevScale即-50 ~50 ,50的灰度差异,对于一般分割来说足够。
标准差文档还说:推荐的值是0.2,如果参数StdDevScale太大,可能分割不出任何东西;如果参数StdDevScale太小(例如-2) ,可能会把整个图像区域全部输出,也就说达不到有效分割的目的。一般推荐使用该算子时,StdDevScale取正值。
需要强调的是:在黑白过渡处,一般掩膜覆盖的像素的标准差较大,而在其他平缓的地方,标准差较小;因此最终采用的分割值随着掩膜在不断遍历像素的过程中,在(StdDevScale x 标准差)和AbsThreshold之间不断切换。
3)var_threshold和dyn_threshold的区别和联系:
dual_threshold(Image : RegionCrossings : MinSize, MinGray, Threshold : )
read_image (Image, ‘C:/Users/happy xia/Desktop/2.png‘)
dual_threshold (Image, RegionCrossings1, 174, 200, 180)
dual_threshold (Image, RegionCrossings2, 176, 200, 180)
dual_threshold (Image, RegionCrossings3, 176, 216, 180)
* MinGray = Threshold 时,即为单阈值分割:选取灰度值大于180的区域
dual_threshold (Image, RegionCrossings4, 176, 180, 180)
源图:
RegionCrossings1
RegionCrossings2
RegionCrossings3(齿轮右下角灰度值未超过216,故无法选取)
RegionCrossings4()
auto_threshold(Image : Regions : Sigma : )
——根据直方图确定阈值自动全局阈值分割
read_image (Image, 'fabrik')
median_image (Image, Median, 'circle', 3, 'mirrored')
auto_threshold (Median, Regions, 3)
fast_threshold(Image : Region : MinGray, MaxGray, MinSize : )
——快速全局阈值分割
watersheds(Image : Basins, Watersheds : : )
——分水岭图像分割。可以分割出分水岭和盆地。
watersheds_threshold(Image : Basins : Threshold : )
——通过阈值实现图像的分水岭算法分割
read_image (Br2, 'particle')
gauss_filter (Br2, ImageGauss, 9)
invert_image (ImageGauss, ImageInvert)
watersheds (ImageInvert, Basins, Watersheds)
dev_set_draw ('margin')
dev_set_colored (12)
dev_display (Br2)
dev_display (Basins)
第1步:
通过分水岭算法watersheds()获取图像的盆地。
第2步:
根据第一步分水岭算法分离结果,若盆地部分的灰度**< threshold**,则被合并到一起。设B1和B2分别为相邻盆地的最小灰度值,W为将盆地分割为两个盆地的最小灰度值。则分割结果为: