阈值分割引言
阈值分割有非常多的算法,大体上分为全局和局部算法。 全局算法包括全局固定阈值和基于图像直方图的阈值,局部算法包括局部动态阈值分割。 基于图像直方图阈值分割的方法也有很多,比如常规的高斯滤波双峰法,OTSU大津法。 但是这类所有的法都基于一个假设:图像是有前景和背景的,待分割目标处于背景中,即图像直方图是双峰的。 如果因为非均匀光照导致待分割目标不处于背景或前景中,即图像直方图无双峰, 那么基于图像直方图的所有法都是不甚理想的 只能在此基础上进行一定的变换,例如nbl算法等,这些都属于局部算法。 任何算法,都会基于假设空间的。没有假设空间,所有算法性能一致。包括经典算法和深度学习算法。 本系列的贴子勇哥通过实验来细品它们之间的差别,以求以后可以精准应用。
histo_to_thresh本身不是阈值类算子,它是助攻,是利用直方图来辅助阈值分割,我们看看原型介绍:
histo_to_thresh( : : Histogramm, Sigma : MinThresh, MaxThresh)
histo_to_thresh从直方图中确定灰度值阈值,
用于使用函数threshold进行分割图像。
返回的阈值为0,直方图中最大的灰度值,直方图中提取的全部最小灰度值。
在确定阈值之前,用高斯平滑函数对直方图进行平滑处理。
histo_to_thresh可以处理由gray_histo返回的绝对直方图和相对直方图。
但是请注意,这里只应该使用字节图像,因为否则返回的阈值无法轻松转换为实际图像的阈值。
对于uint2类型的图像,直方图的计算应该使用 gray_histo_abs,
因为这便于阈值的简单转换,只需将阈值与gray_histo_abs中选择的量化值相乘即可。
对于uint2图像,重要的是要确保量化必须以直方图仍然包含显著信息的方式进行选择。
例如,一个640 x 480的图像,每像素灰度值分辨率为16位,
平均每个直方图bin只包含307200 / 65536 = 4.7个条目,
即,直方图的填充太稀疏,无法从中获得任何有用的统计信息。
为了能够从这样的直方图中提取有用的阈值,
Sigma必须设置为一个非常大的值,这将导致非常高的运行时间和数值问题。
因此,通常应该选择gray_histo_abs中的量化,使直方图最多包含1024个条目。
因此,对于每像素大于10位的图像,必须选择大于1的量化。
此外,gray_histo_abs返回的直方图应该被限制在包含显著信息的部分。
例如,对于每像素12位的图像,量化值应该设置为4。
只应该将计算直方图的前1024个条目(在本例中包含16384个条目)传递给column_to_thresh。
最后,MinThresh必须乘以4(即,而MaxThresh必须乘以4并增加3(即,量子化- 1)。
(一) 基本用法,分割文字
(图1)
演示程序(1):
read_image(Image, 'C:/Users/Administrator.PC8-20191007LRY/Desktop/31.bmp') get_image_size(Image, Width, Height) gen_rectangle1(Rectangle, 0, 0, Height,Width ) gray_histo(Rectangle, Image, AbsoluteHisto1, RelativeHisto) histo_to_thresh(RelativeHisto,16, MinThresh, MaxThresh) threshold(Image, Region, MinThresh, MaxThresh)
执行结果:
(图2)
这个sigma值越大,你后面的MinThresh, MaxThresh的元素数量越小。
在这里我们增大到16,让MinThresh, MaxThresh数量都是两个。
histo_to_thresh(RelativeHisto,16, MinThresh, MaxThresh)
MinThresh, MaxThresh的值用于后的面threshold分割。
这个过程按网友“不二”的说法是这样的:
提取直方图,然后用一维高斯滤波器平滑,逐步增大δ, 直到平滑后的直方图出现唯一的两个最大值和之间一个最小值, 选取最小值对应的阈值作为自动分割阈值 这样的分割是基于直方图分割阈值最好的一种算法,没有取最大值阈值做分割的。 两个最大值对应前景和背景,而唯一的最小值对应最好的分割阈值,类间方差最大。
另个,请注意threshold的最小最大值两个参数是可以接受数组的,这个没想到吧?
通过直方图,我们看到了所谓的“双峰”是这样的:
(图3)
下图是photoshop显示的直方图,要看得更清楚一些。
(图4)
再举个栗子:
用法是一致的。
演示程序(2)
read_image (Image, 'letters') get_image_size (Image, Width, Height) dev_close_window () dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowID) dev_set_color ('red') gray_histo (Image, Image, AbsoluteHisto, RelativeHisto) histo_to_thresh (RelativeHisto, 8, MinThresh, MaxThresh) dev_set_colored (12) threshold (Image, Region, MinThresh, MaxThresh)
(图5)
不过例子二的背景有点轻微渐变色,例子一是纯色。
勇哥来试试把例子一的背景改成渐变色,看代码是否可以适应?
(图6)
这时候我们看到直方图不是双峰,而是多峰了。
(图7)
在代码啥参数没改的情况下,我们看到histo_to_thresh算子求出的 MinThresh, MaxThresh值如下:
从这个值来看,蓝色部分是灰度值较亮的MinThresh, MaxThresh的最大值部分,
绿色部分是MinThresh, MaxThresh的中间值部分
而红色部分是MinThresh, MaxThresh的最小值部分。
(图8)
不过这个例子只能说明histo_to_thresh的用法,体现不了好处。
因为对于这个例子,我们threshold取0, 46的部分就可以了,不用这么麻烦。
接下来看看算子:
auto threshold
原形是:auto threshold(lmage: Regions: Siąma:)
用下面的一句话可实现图8的效果:
auto_threshold(GrayImage, Regions, 8)
所以其实算子auto threshold是下面三个算子合在一起的效果。
gray_histo(Rectangle, Image, AbsoluteHisto1, RelativeHisto) histo_to_thresh(RelativeHisto,16, MinThresh, MaxThresh) threshold(Image, Region, MinThresh, MaxThresh)
只是有个问题,为啥子为取值8,但是程序(1)中sigma取值16呢?
两者能达到一样的效果。
勇哥表示: 我也不知道~~~
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

