阈值分割引言
阈值分割有非常多的算法,大体上分为全局和局部算法。 全局算法包括全局固定阈值和基于图像直方图的阈值,局部算法包括局部动态阈值分割。 基于图像直方图阈值分割的方法也有很多,比如常规的高斯滤波双峰法,OTSU大津法。 但是这类所有的法都基于一个假设:图像是有前景和背景的,待分割目标处于背景中,即图像直方图是双峰的。 如果因为非均匀光照导致待分割目标不处于背景或前景中,即图像直方图无双峰, 那么基于图像直方图的所有法都是不甚理想的 只能在此基础上进行一定的变换,例如nbl算法等,这些都属于局部算法。 任何算法,都会基于假设空间的。没有假设空间,所有算法性能一致。包括经典算法和深度学习算法。 本系列的贴子勇哥通过实验来细品它们之间的差别,以求以后可以精准应用。
binary_threshold
这个是全局二值化处理做阈值分割的算子。使用Threshold找到两个波峰之间的最小值,分割出来的是非黑即白。
注意“二值化”的意义,它有许多算法:
方法一:扫描图像的每个像素值,值小于127的将像素值设为0(黑色),值大于等于127的像素值设为255(白色)。 该方法的好处是计算量少速度快。 方法二:计算像素的平均值K,扫描图像的每个像素值如像素值大于K像素值设为255(白色), 值小于等于K像素值设为0(黑色)。 方法三:使用直方图方法来寻找二值化阈值,直方图是图像的重要特质, 直方图方法选择二值化阈值主要是发现图像的两个最高的峰,然后在阈值取值在两个峰之间的峰谷最低处。
注意halcon的binary_threshold算子算法是OSTU,以上算法只是原理说明一下怎么简单实现二值化。
Halcon算子原型:
binary_threshold(Image : Region : Method, LightDark : UsedThreshold)
参数:
Image:需要进行阈值的图像
Region:处理后的区域
Method:分割方法('max_separability':最大限度的可分性, 'smooth_histo':直方图平滑)
LightDark:提取的是黑色部分还是白色部分
UsedThreshold:自动阈值使用的阈值值
描述:
binary_threshold通过一个自动确定的全局阈值并返回区域中的分段区域来分割单通道图像。
例如:在同质照明的背景下对字符的分割很有用。binary_threshold还会返回UsedThreshold中使用的阈值。
所使用的阈值是由方法中给出的方法决定的。
目前,操作符提供了以下两种方法:“max_separability”和“smooth_histo”。这两种方法都只能用于具有双峰直方图的图像。
方法“smooth _histo”提供了由操作员bin_threshold提供的相同功能。
方法“max_separability”倾向于为UsedThreshold确定较小的值。此外,它对柱状图中的稀疏孤立峰不太敏感,而且往往比“平滑”要快得多。
最大限度的可分性(max_separability):
通过选择Method= ' max_separability ',根据“灰度直方图的阈值选择方法”的灰度直方图自动阈值调用。该算法首先计算图像的直方图,然后利用统计矩找到将像素分割为前景和背景的最优阈值,并最大化这两个类之间的可分性。此方法仅适用于byte和uint2图像。
直方图平滑(smooth_histo):
通过选择Method = 'smooth_histo ' binary_threshold可以通过以下方式确定阈值:首先确定灰度值的相对直方图。然后,从直方图提取相关的最小值,作为阈值操作的参数。为了减少最小值,直方图被平滑处理为一个高斯函数,就像在auto_threshold中一样。在平滑直方图中,掩模尺寸增大,直到最小值。然后,阈值设置为这个最小值的位置。
解释2:(更容易理解一些)
该方法是使用高斯滤波器对图像的相对灰度直方图进行滤波,逐步加大滤波器的模板大小,直到滤波后的相对灰度直方图的极小值个数只有一个,该极小值所对应的灰度值就是用于分割图像的阈值。
看效果:
当LightDark=light,max_separability选的区域比smooth_histo少一点
当LightDark=dark,max_separability选的区域比smooth_histo多一点
我们还是使用第二集最后的那张图片
它的直方图只能勉强算是双峰,其中有一峰占位太多。
但是这种险些不是双峰的图像还是可以适用binary_threshold算子。
read_image(Image, '5.bmp') rgb1_to_gray(Image, GrayImage) get_image_size(Image, Width, Height) gen_rectangle1(Rectangle, 0, 0, Height,Width ) binary_threshold(GrayImage, res1, 'smooth_histo', 'dark', UsedThreshold1) binary_threshold(GrayImage, res2, 'max_separability', 'dark', UsedThreshold2) binary_threshold(GrayImage, res3, 'smooth_histo', 'light', UsedThreshold3) binary_threshold(GrayImage, res4, 'max_separability', 'light', UsedThreshold4)
(res1)
(res2)
(res3)
(res4)
程序运行后,4个自动选择的阈值分别是 45,135, 45,135
这个45正好是双峰谷底中间位置,如下图所示:
135是由算法max_separability取得的阈值,其位置如下图所示。
不过这个位置有点让人不理解。
如果我们换一张图:
则会发现无论是'smooth_histo' 或者是 'max_separability' 算法,都会选择到双峰谷底了。
'smooth_histo'取的值是146。
'max_separability'取的值是136。
所以'smooth_histo'是基于直方图计算谷底,位置很准。
而'max_separability'貌似总会比'smooth_histo'多选择一些,可能是偏向左峰或者是偏向右峰。
bin_threshold
这个算子,少了两个算法选项,也不能决定选择黑或者白。
因此被halcon建议作废。
bin_threshold(GrayImage, Region)
从效果来看,是直接选择了黑色部分。
binary_threshold原理和实现
binary_threshold应用了OSTU算法(大津算法)
对原理有兴趣可以参考:
https://www.cnblogs.com/guopengfei/p/4759569.html
类同halcon的
binary_threshold (Image, Region, 'max_separability', 'light', UsedThreshold3) 效果的算法如下:
算法使用halcon编写:
gray_histo (Region, Image, AbsoluteHisto, RelativeHisto) get_image_size (Image, Width, Height) TotalSize:=Width*Height intensity (Region, Image, avgValue, Deviation)//avgValue图像总平均灰度 MaxDiff:=0.0 Diff:=0.0 //方差 Thre:=0 delta_max:=0 for i := 0 to 255 by 1 w0:=0.0 u0:=0.0 w1:=0.0 u1:=0.0 uo_temp:=0 u1_temp:=0 delta_temp:=0 **背景部分 for j:=0 to i by 1 w0:=w0+AbsoluteHisto[j] uo_temp:=uo_temp+j*AbsoluteHisto[j] endfor **前景部分 w1:=TotalSize-w0 u1_temp:=avgValue*TotalSize-uo_temp **计算两类的平均灰度 if(w0==0 or w1==0) u0:=0 u1:=0 else u0:=uo_temp/w0 u1:=u1_temp/w1 endif **依次找到最大类间方差下的阈值 delta_temp:=w0*w1*pow((u0-u1),2) if(delta_temp>delta_max) delta_max := delta_temp Thre:=i endif endfor return ()
优化后的代码如下:
gray_histo (Region, Image, AbsoluteHisto, RelativeHisto) intensity (Region, Image, avgValue, Deviation)//avgValue图像总平均灰度 wk:=0.0 //分开后前景像素点数占图像的比例 uk:=0.0 //分开后前景像素数的平均灰度值 MaxDiff:=0.0 Diff:=0.0 //方差 Thre:=0 for Index := 0 to 255 by 1 wk:=wk+RelativeHisto[Index] uk:=uk+RelativeHisto[Index]*Index if(wk<=0.0 or wk>=1.0) Diff:=0 else Diff:=(avgValue*wk-uk)*(avgValue*wk-uk )/(wk*(1-wk)) endif if(Diff>MaxDiff) MaxDiff:=Diff Thre:=Index endif endfor return ()
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

