十三种基于直方图的图像全局二值化算法原理、实现、代码及效果。 您所在的位置:网站首页 对图像进行二值化处理代码 十三种基于直方图的图像全局二值化算法原理、实现、代码及效果。

十三种基于直方图的图像全局二值化算法原理、实现、代码及效果。

2023-06-24 06:17| 来源: 网络整理| 查看: 265

      图像二值化的目的是最大限度的将图象中感兴趣的部分保留下来,在很多情况下,也是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。这个看似简单的问题,在过去的四十年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法,但如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果。

     在这些庞大的分类方法中,基于直方图的全局二值算法占有了绝对的市场份额,这些算法都从不同的科学层次提出了各自的实施方案,并且这类方法都有着一些共同的特点:

  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、该原理比较简单,直接以代码实现。

/// /// 百分比阈值 /// /// 灰度图像的直方图 /// 背景在图像中所占的面积百分比 /// 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] 2) return false; } } if (Count == 2) return true; else return 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、描述:

    该算法先假定一个阈值,然后计算在该阈值下的前景和背景的中心值,当前景和背景中心值得平均值和假定的阈值相同时,则迭代中止,并以此值为阈值进行二值化。

    2、实现过程:

  (1)求出图象的最大灰度值和最小灰度值,分别记为gl和gu,令初始阈值为:

                       

      (2) 根据阈值T0将图象分割为前景和背景,分别求出两者的平均灰度值Ab和Af:

              

      (3) 令

                         

    如果Tk=Tk+1,则取Tk为所求得的阈值,否则,转2继续迭代。

     3、参考代码:

public static int GetIterativeBestThreshold(int[] HistGram) { int X, Iter = 0; int MeanValueOne, MeanValueTwo, SumOne, SumTwo, SumIntegralOne, SumIntegralTwo; int MinValue, MaxValue; int Threshold, NewThreshold; for (MinValue = 0; MinValue < 256 && HistGram[MinValue] == 0; MinValue++) ; for (MaxValue = 255; MaxValue > MinValue && HistGram[MinValue] == 0; MaxValue--) ; if (MaxValue == MinValue) return MaxValue; // 图像中只有一个颜色 if (MinValue + 1 == MaxValue) return MinValue; // 图像中只有二个颜色 Threshold = MinValue; NewThreshold = (MaxValue + MinValue) >> 1; while (Threshold != NewThreshold) // 当前后两次迭代的获得阈值相同时,结束迭代 { SumOne = 0; SumIntegralOne = 0; SumTwo = 0; SumIntegralTwo = 0; Threshold = NewThreshold; for (X = MinValue; X 1; //求出新的阈值 Iter++; if (Iter >= 1000) return -1; } return Threshold; }

  4、效果:

                  

                   

       原图                                          二值图                                         直方图 

   六、OSTU大律法

  1、描述:

       该算法是1979年由日本大津提出的,主要是思想是取某个阈值,使得前景和背景两类的类间方差最大,matlab中的graythresh即是以该算法为原理执行的。

       2、原理:

       关于该算法的原理,网络上有很多,这里为了篇幅有限,不加以赘述。

       3、参考代码:

public static int GetOSTUThreshold(int[] HistGram) { int X, Y, Amount = 0; int PixelBack = 0, PixelFore = 0, PixelIntegralBack = 0, PixelIntegralFore = 0, PixelIntegral = 0; double OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma; // 类间方差; int MinValue, MaxValue; int Threshold = 0; for (MinValue = 0; MinValue < 256 && HistGram[MinValue] == 0; MinValue++) ; for (MaxValue = 255; MaxValue > MinValue && HistGram[MinValue] == 0; MaxValue--) ; if (MaxValue == MinValue) return MaxValue; // 图像中只有一个颜色 if (MinValue + 1 == MaxValue) return MinValue; // 图像中只有二个颜色 for (Y = MinValue; Y MinValue && HistGram[MinValue] == 0; MaxValue--) ; if (MaxValue == MinValue) return MaxValue; // 图像中只有一个颜色 if (MinValue + 1 == MaxValue) return MinValue; // 图像中只有二个颜色 for (Y = MinValue; Y


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有