OTSU算法,即最大类间方差,是由日本学者大津(Nobuyuki Otsu)于1979年提出的一种自适应阈值确定方法。算法假设一组数据 D D D 能够根据阈值被分为两部分,使得两类的区分度最大。两类之间的界限即为最佳分割阈值。大家有兴趣可以参考:Otsu, N. (1979)。
在数学上,数据
D
D
D 的阈值
d
∗
d^*
d∗ 可以表示为以下优化问题:
d
∗
=
O
T
S
U
(
D
)
=
a
r
g
max
1
≤
d
≤
L
σ
B
2
(
d
)
d^*=OTSU(D)=arg\ \max \limits_{1\leq d \leq L} \sigma_B^2(d)
d∗=OTSU(D)=arg 1≤d≤LmaxσB2(d)
其中:
σ
B
2
(
d
)
=
[
μ
T
ω
(
d
)
−
μ
(
d
)
]
2
ω
(
d
)
[
1
−
ω
(
d
)
]
\sigma_B^2(d)=\dfrac{[\mu_T^{}\omega(d)-\mu(d)]^2}{\omega(d)[1-\omega(d)]}
σB2(d)=ω(d)[1−ω(d)][μTω(d)−μ(d)]2
μ
T
=
∑
i
=
1
L
i
p
i
ω
(
d
)
=
∑
i
=
1
d
p
i
μ
(
d
)
∑
i
=
1
d
i
p
i
\mu_T^{}=\sum \limits_{i=1}^L ip_i^{} \\ \omega(d)=\sum \limits_{i=1}^d p_i^{} \\ \mu(d)\sum \limits_{i=1}^d ip_i^{}
μT=i=1∑Lipiω(d)=i=1∑dpiμ(d)i=1∑dipi
其中
p
i
p_i^{}
pi 为数据中
i
i
i 的概率,
L
L
L 为数据
D
D
D 的最大值。
代码实现如下:
int otsu(float *pix, int pixsize, float pixmin, float pixmax)
{
//pix 输入的数据
//pixsize 数据的长度
//pixmin 数据最小值
//pixmax 数据最大值
int pixsi = (int)pixmax - (int)pixmin+1;
int nThresh = (int)pixmin;
float *fStdHistogram = new float [pixsi]; // 图像直方图,pixsi个点
float *fGrayAccu = new float [pixsi];
float *fGrayAve = new float [pixsi];
float HistogramSum = 0.0;
float fAverage = 0;
float fTemp, fMax = 0;
memset(fStdHistogram, 0.0, sizeof(float) * pixsi);
memset(fGrayAccu, 0.0, sizeof(float) * pixsi);
memset(fGrayAve, 0.0, sizeof(float) * pixsi);
for (int i = 0; i < pixsize; ++i)
fStdHistogram[(int)pix[i] - (int)pixmin] += 1.0;
for (int i = 0; i < pixsi; ++i)
fStdHistogram[i] /= (pixsize * 1.0);
int minnew = 0, maxnew = pixsi;
for(int i = 0;i < pixsi; ++i)
{
for(int j = 0; j <= i; ++j)
{
fGrayAccu[i] += fStdHistogram[j];
fGrayAve[i] += j * fStdHistogram[j];
}
fAverage += i * fStdHistogram[i];
}
for(int i = 0; i < pixsi; ++i)
{
if (HistogramSum < 0.02) minnew = i;
if (HistogramSum >= 0.98)
{
maxnew = i;
break;
}
HistogramSum += fStdHistogram[i];
}
for(int i = minnew; i < maxnew; ++i)
{
fTemp = (fAverage * fGrayAccu[i] - fGrayAve[i]) * (fAverage * fGrayAccu[i] - fGrayAve[i]) / (fGrayAccu[i] * (1 - fGrayAccu[i]));
if(fTemp > fMax)
{
fMax = fTemp;
nThresh = i;
}
}
delete [] fStdHistogram;
delete [] fGrayAccu;
delete [] fGrayAve;
return 1 * (nThresh + (int)pixmin);
}
欢迎大家批评指正。