图像二值化的目的是最大限度的将图象中感兴趣的部分保留下来,在很多情况下,也是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。
这个看似简单的问题,在过去的四十年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法,但如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果。
在这些庞大的分类方法中,基于直方图的全局二值算法占有了绝对的市场份额,这些算法都从不同的科学层次提出了各自的实施方案,并且这类方法都有着一些共同的特点:1、简单;2、算法容易实现;3、执行速度快。
本文摘取了若干种这类方法进行了介绍。
一:灰度平局值值法:1、描述:即使用整幅图像的灰度平均值作为二值化的阈值,一般该方法可作为其他方法的初始猜想值。
2、原理:3、实现代码:public static int GetMeanThreshold(int[] HistGram){int Sum = 0, Amount = 0;for (int Y = 0; Y < 256; Y++){Amount += HistGram[Y];Sum += Y * HistGram[Y];}return Sum / Amount;}二、百分比阈值(P-Tile法)1、描述Doyle于1962年提出的P-Tile (即P分位数法)可以说是最古老的一种阈值选取方法。
该方法根据先验概率来设定阈值,使得二值化后的目标或背景像素比例等于先验概率,该方法简单高效,但是对于先验概率难于估计的图像却无能为力。
2、该原理比较简单,直接以代码实现。
/// <summary>/// 百分比阈值/// </summary>/// <param name="HistGram">灰度图像的直方图</param>/// <param name="Tile">背景在图像中所占的面积百分比</param>/// <returns></returns>public static int GetPTileThreshold(int[] HistGram, int Tile = 50){int Y, Amount = 0, Sum = 0;for (Y = 0; Y < 256; Y++) Amount += HistGram[Y]; // 像素总数for (Y = 0; Y < 256; Y++){Sum = Sum + HistGram[Y];if (Sum >= Amount * Tile / 100) return Y;}return -1;}三、基于谷底最小值的阈值1、描述:此方法实用于具有明显双峰直方图的图像,其寻找双峰的谷底作为阈值,但是该方法不一定能获得阈值,对于那些具有平坦的直方图或单峰图像,该方法不合适。
2、实现过程:该函数的实现是一个迭代的过程,每次处理前对直方图数据进行判断,看其是否已经是一个双峰的直方图,如果不是,则对直方图数据进行半径为1(窗口大小为3)的平滑,如果迭代了一定的数量比如1000次后仍未获得一个双峰的直方图,则函数执行失败,如成功获得,则最终阈值取两个双峰之间的谷底值作为阈值。
注意在编码过程中,平滑的处理需要当前像素之前的信息,因此需要对平滑前的数据进行一个备份。
另外,首数据类型精度限制,不应用整形的直方图数据,必须转换为浮点类型数据来进行处理,否则得不到正确的结果。
该算法相关参考论文如下:J. M. S. Prewitt and M. L. Mendelsohn, "The analysis of cell images," innnals of the New York Academy of Sciences, vol. 128, pp. 1035-1053, 1966.C. A. Glasbey, "An analysis of histogram-based thresholding algorithms," CVGIP: Graphical Models and Image Processing, vol. 55, pp. 532-537, 1993.3、实现代码:public static int GetMinimumThreshold(int[] HistGram){int Y, Iter = 0;double[] HistGramC = new double[256]; // 基于精度问题,一定要用浮点数来处理,否则得不到正确的结果double[] HistGramCC = new double[256]; // 求均值的过程会破坏前面的数据,因此需要两份数据for (Y = 0; Y < 256; Y++){HistGramC[Y] = HistGram[Y];HistGramCC[Y] = HistGram[Y];}// 通过三点求均值来平滑直方图while (IsDimodal(HistGramCC) == false)// 判断是否已经是双峰的图像了{HistGramCC[0] = (HistGramC[0] + HistGramC[0] + HistGramC[1]) / 3; // 第一点for (Y = 1; Y < 255; Y++)HistGramCC[Y] = (HistGramC[Y - 1] + HistGramC[Y] + HistGramC[Y + 1]) / 3; // 中间的点HistGramCC[255] = (HistGramC[254] + HistGramC[255] + HistGramC[255]) / 3; // 最后一点System.Buffer.BlockCopy(HistGramCC, 0, HistGramC, 0, 256 * sizeof(double));Iter++;if (Iter >= 1000) return -1;// 直方图无法平滑为双峰的,返回错误代码}// 阈值极为两峰之间的最小值bool Peakfound = false;for (Y = 1; Y < 255; Y++){if (HistGramCC[Y - 1] < HistGramCC[Y] && HistGramCC[Y + 1] < HistGramCC[Y]) Peakfound = true;if (Peakfound == true && HistGramCC[Y - 1] >= HistGramCC[Y] && HistGramCC[Y + 1] >= HistGramCC[Y])return Y - 1;}return -1;}其中IsDimodal函数为判断直方图是否是双峰的函数,代码如下:private static bool IsDimodal(double[] HistGram) // 检测直方图是否为双峰的{// 对直方图的峰进行计数,只有峰数位2才为双峰int Count = 0;for (int Y = 1; Y < 255; Y++){if (HistGram[Y - 1] < HistGram[Y] && HistGram[Y + 1] < HistGram[Y]){Count++;if (Count > 2) return false;}}if (Count == 2)return true;elsereturn false;}4、效果:原图二值图原始直方图平滑后的直方图对于这种有较明显的双峰的图像,该算法还是能取得不错的效果的。
四、基于双峰平均值的阈值1、描述:该算法和基于谷底最小值的阈值方法类似,只是最后一步不是取得双峰之间的谷底值,而是取双峰的平均值作为阈值。
2、参考代码:public static int GetIntermodesThreshold(int[] HistGram){int Y, Iter = 0, Index;double[] HistGramC = new double[256]; // 基于精度问题,一定要用浮点数来处理,否则得不到正确的结果double[] HistGramCC = new double[256]; // 求均值的过程会破坏前面的数据,因此需要两份数据for (Y = 0; Y < 256; Y++){HistGramC[Y] = HistGram[Y];HistGramCC[Y] = HistGram[Y];}// 通过三点求均值来平滑直方图while (IsDimodal(HistGramCC) == false)// 判断是否已经是双峰的图像了{HistGramCC[0] = (HistGramC[0] + HistGramC[0] + HistGramC[1]) / 3; // 第一点for (Y = 1; Y < 255; Y++)HistGramCC[Y] = (HistGramC[Y - 1] + HistGramC[Y] + HistGramC[Y + 1]) / 3; // 中间的点HistGramCC[255] = (HistGramC[254] + HistGramC[255] + HistGramC[255]) / 3; // 最后一点System.Buffer.BlockCopy(HistGramCC, 0, HistGramC, 0, 256 * sizeof(double)); // 备份数据,为下一次迭代做准备Iter++;if (Iter >= 10000) return -1;// 似乎直方图无法平滑为双峰的,返回错误代码}// 阈值为两峰值的平均值int[] Peak = new int[2];for (Y = 1, Index = 0; Y < 255; Y++)if (HistGramCC[Y - 1] < HistGramCC[Y] && HistGramCC[Y + 1] < HistGramCC[Y]) Peak[Index++] = Y - 1;return ((Peak[0] + Peak[1]) / 2);}3、效果:原图二值图原始直方图平滑后的直方图五、迭代最佳阈值1、描述:该算法先假定一个阈值,然后计算在该阈值下的前景和背景的中心值,当前景和背景中心值得平均值和假定的阈值相同时,则迭代中止,并以此值为阈值进行二值化。