【智能车】图像二值化算法--大津法OTSU
图像二值化算法–大津法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/(M∗N) ω 1 = N 1 / ( M ∗ N ) ω_1 = N_1 / (M * N) ω1=N1/(M∗N)
数量恒等式: N 0 + N 1 = M ∗ N N_0+N_1 = M * N N0+N1=M∗N ω 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的自动选取,其算法步骤为:
- 先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量
- 归一化直方图,将每个bin中像素点数量除以总的像素点
- i 表示分类的阈值,也即一个灰度级,从0开始迭代 i
- 通过归一化的直方图,统计0-i 灰度级的像素(前景像素) 所占整幅图像的比例w0,平均灰度u0;统计i-255灰度级的像素(背景像素) * 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;
- 计算前景像素和背景像素的方差 g = ω 0 ∗ ω 1 ∗ ( μ 0 − μ 1 ) ∗ ( μ 0 − μ 1 ) g = ω_0 * ω_1 * (μ_0 - μ_1) * (μ_0 - μ_1) g=ω0∗ω1∗(μ0−μ1)∗(μ0−μ1)
- i++;重复第4、5步,直到 i 为256时结束迭代
- 将最大 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
代码来自龙邱开源库,有改动
更多推荐
所有评论(0)