【智能车】图像二值化算法--大津法OTSU

本文详细介绍了大津法(OTSU)的原理,涉及灰度值、像素比例、方差计算,以及C语言中的算法步骤。重点讨论了如何通过类间方差最大化来确定图像阈值,以及该算法在处理光照不均匀图像的局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图像二值化算法–大津法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.youkuaiyun.com/Galen_xia/article/details/107911867
代码来自龙邱开源库,有改动

### 智能车大津的应用 #### 大津的核心原理及其优势 大津是一种基于类间方差最大化的全局阈值分割算法,能够自动计算最佳阈值用于图像二值化处理[^1]。这种方智能车图像处理中尤为重要,因为其可以根据环境光线的变化动态调整阈值,从而提高赛道循迹的准确性[^4]。 #### 应用场景分析 在智能车比赛中,摄像头获取的灰度图像是进行赛道识别的基础数据。为了有效区分赛道边界与背景区域,通常需要对这些灰度图像进行二值化处理。然而,固定的阈值难以应对光照条件的变化,而大津则可以通过实时计算最优阈值解决这一问题[^5]。具体而言: - **自适应阈值计算**:大津通过对图像像素分布的统计特性进行分析,找到使前景(赛道)和背景(其他区域)之间差异最大的阈值。 - **鲁棒性强**:即使在复杂的光照条件下,该方也能保持较高的稳定性,减少因光线变化引起的误判风险[^3]。 #### 实现过程概述 以下是利用大津完成图像二值化的主要流程及其实现方式: 1. **读取并预处理图像** 首先从摄像头捕获原始图像,并将其转换为适合后续操作的形式,例如灰度图像[^2]。 2. **计算最佳阈值** 使用大津遍历所有可能的阈值候选值,寻找使得类间方差达到最大的那个特定数值作为最终选定的阈值。 3. **执行二值化操作** 基于上述获得的最佳阈值,将原图像划分为两个类别——白色代表目标对象(如赛道),黑色表示其余部分。 ```c // C语言实现的大津核心逻辑 int otsu_threshold(unsigned char *image, int width, int height){ double sum = 0; long hist[256]; memset(hist, 0, sizeof(long)*256); for(int i=0;i<width*height;i++) { hist[image[i]]++; sum += image[i]; } double wB=0,wF=0,muB=0,muF=0,max_sigmaB=-1,sigmaB,var_between,treshold=0; for (treshold=0;treshold<=255;treshold++){ wB+=hist[treshold];wF=sum-wB; if(wB==0 || wF==0) continue; muB+=(double)(sum*wB)/((double)treshold+1);muF=(sum-muB)/(wF); var_between=wB*(muB)*(muB)+wF*(muF)*(muF); if(var_between>max_sigmaB){ max_sigmaB=var_between;} } return treshold; } ``` 此代码片段展示了如何通过迭代求解出能使两分类间的方差最大化所对应的阈值位置。 #### 局限性探讨 尽管大津具有诸多优点,但在某些特殊情况下仍可能存在不足之处。例如面对多模态直方图结构时,单一应用标准形式下的大津可能导致不理想的结果;此时需引入改进措施或多阶段处理机制来弥补缺陷。 ---
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值