图像二值化算法–大津法OTSU


大津算法是一种图像二值化算法,作用是确定将图像分成黑白两个部分的阈值。

大津法是针对灰度值进行阈值分割二值化,如果是彩色图像的话需要先转化成灰度图再进行计算。

方差越大,相关性越低,黑白越分明。

目的:找出一个灰度值阈值Threshold,对该灰度值以上或以下的像素的分别计算方差,满足Threshold以上计算出来的方差和Threshold以下计算出来的方差的和最大。

# 算法推导:

对于图像 Image[M, N] ,其大小为M x N。有以下信息:

符号含义
ω 0 ω_0 ω0前景的像素点数占整幅图像的比例
μ 0 μ_0 μ0前景像素平均灰度
ω 1 ω_1 ω1背景的像素点数占整幅图像的比例
μ 1 μ_1 μ1背景像素平均灰度
μ μ μ总像素平均灰度
T T T前景和背景的分割阈值
N 0 N_0 N0灰度值大于阈值的像素个数
N 1 N_1 N1灰度值小于阈值的像素个数
g g g类间方差

根据变量的含义,可以得出以下关系式:

前后景像素比例: ω 0 = N 0 / ( M ∗ N ) ω_0 = N_0 / (M * N) ω0=N0/(MN) ω 1 = N 1 / ( M ∗ N ) ω_1 = N_1 / (M * N) ω1=N1/(MN)

数量恒等式: N 0 + N 1 = M ∗ N N_0+N_1 = M * N N0+N1=MN ω 0 + ω 1 = 1 ω_0 + ω_1 = 1 ω0+ω1=1

平均灰度值关系: μ = ω 0 ∗ μ 0 + ω 1 ∗ μ 1 μ = ω_0 * μ_0 + ω_1 * μ_1 μ=ω0μ0+ω1μ1

方差定义式: g = ω 0 ( μ 0 − μ ) 2 + ω 1 ( μ 1 − μ ) 2 g = ω_0 (μ_0 - μ)^2 + ω_1 (μ_1 - μ)^2 g=ω0(μ0μ)2+ω1(μ1μ)2
      
将μ代入式g,得到等价公式: g = ω 0 ∗ ω 1 ( μ 0 − μ 1 ) 2 g = ω_0 * ω_1 (μ_0 - μ_1)^2 g=ω0ω1(μ0μ1)2

# 算法实现(C语言):

Ostu方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取,其算法步骤为:

  1. 先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量
  2. 归一化直方图,将每个bin中像素点数量除以总的像素点
  3. i 表示分类的阈值,也即一个灰度级,从0开始迭代 i
  4. 通过归一化的直方图,统计0-i 灰度级的像素(前景像素) 所占整幅图像的比例w0,平均灰度u0;统计i-255灰度级的像素(背景像素) * 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;
  5. 计算前景像素和背景像素的方差 g = ω 0 ∗ ω 1 ∗ ( μ 0 − μ 1 ) ∗ ( μ 0 − μ 1 ) g = ω_0 * ω_1 * (μ_0 - μ_1) * (μ_0 - μ_1) g=ω0ω1(μ0μ1)(μ0μ1)
  6. i++;重复第4、5步,直到 i 为256时结束迭代
  7. 将最大 g 相应的 i 值作为图像的全局阈值

缺陷:OTSU算法在处理光照不均匀的图像的时候,效果会明显不好,因为利用的是全局像素信息。

/*************************************************************************
 *  函数名称:short GetOTSU (unsigned char tmImage[LCDH][LCDW])
 *  功能说明:大津法求阈值大小
 *  参数说明:tmImage : 图像数据
 *  函数返回:无
*************************************************************************/
short GetOTSU (unsigned char tmImage[LCDH][LCDW])
{
    signed short i, j;
    unsigned long Amount = 0;
    unsigned long PixelBack = 0;
    unsigned long PixelshortegralBack = 0;
    unsigned long Pixelshortegral = 0;
    signed long PixelshortegralFore = 0;
    signed long PixelFore = 0;
    float OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma; // 类间方差;
    signed short MinValue, MaxValue;
    signed short Threshold = 0;
    unsigned short HistoGram[256];     //原先为unsigned char ,但是同一个灰度值的像素点可能会超过255个,因此造成溢出,扩大数据范围,感谢评论区指正。

    for (j = 0; j < 256; j++)
        HistoGram[j] = 0; //初始化灰度直方图

    for (j = 0; j < LCDH; j++)
    {
        for (i = 0; i < LCDW; i++)
        {
            HistoGram[tmImage[j][i]]++; //统计灰度级中每个像素在整幅图像中的个数
        }
    }

    for (MinValue = 0; MinValue < 256 && HistoGram[MinValue] == 0; MinValue++);        //获取最小灰度的值
    for (MaxValue = 255; MaxValue > MinValue && HistoGram[MaxValue] == 0; MaxValue--); //获取最大灰度的值

    if (MaxValue == MinValue)
        return MaxValue;         // 图像中只有一个颜色
    if (MinValue + 1 == MaxValue)
        return MinValue;        // 图像中只有二个颜色

    for (j = MinValue; j <= MaxValue; j++)
        Amount += HistoGram[j];        //  像素总数

    Pixelshortegral = 0;
    for (j = MinValue; j <= MaxValue; j++)
    {
        Pixelshortegral += HistoGram[j] * j;        //灰度值总数
    }
    SigmaB = -1;
    for (j = MinValue; j < MaxValue; j++)
    {
        PixelBack = PixelBack + HistoGram[j];     //前景像素点数
        PixelFore = Amount - PixelBack;           //背景像素点数
        OmegaBack = (float) PixelBack / Amount;   //前景像素百分比
        OmegaFore = (float) PixelFore / Amount;   //背景像素百分比
        PixelshortegralBack += HistoGram[j] * j;  //前景灰度值
        PixelshortegralFore = Pixelshortegral - PixelshortegralBack;  //背景灰度值
        MicroBack = (float) PixelshortegralBack / PixelBack;   //前景灰度百分比
        MicroFore = (float) PixelshortegralFore / PixelFore;   //背景灰度百分比
        Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore);   //计算类间方差
        if (Sigma > SigmaB)                    //遍历最大的类间方差g //找出最大类间方差以及对应的阈值
        {
            SigmaB = Sigma;
            Threshold = j;
        }
    }
    return Threshold;                        //返回最佳阈值;
}

参考:
https://blog.csdn.net/Galen_xia/article/details/107911867
代码来自龙邱开源库,有改动

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐