大津二值化算法(Otsu’s Method)
大津算法,也被称作最大类间方差法,是一种可以自动确定二值化中阈值的算法。
从类内方差和类间方差的比值计算得来:
小于阈值t的类记作0,大于阈值t的类记作1$
w0和w1是被阈值t分开的两个类中的像素数占总像素数的比率(满足w0+w1=1)
S02,S12是这两个类中像素值的方差
M0,M1是这两个类的像素值的平均值
即:
类内方差:
S_w^2=w_0·S_0^2+w_1·S_1^2类间方差:
S_b^2=w_0·(M_0-M_t)^2+w_1·(M_1-M_t)^2图像所有像素的方差:
S_t^2=S_w^2+S_b^2=常数
根据以上的式子,我们用以下的式子计算分离度X:
X=\frac {S_b^2} {S_w^2}=\frac {S_b^2} {S_t^2-S_w^2}
也就是说
\mathop{\arg\max}\limits_{t} X = \mathop{\arg\max}\limits_{t} S_b^2
换言之,如果使S_b^2=w_0·w_1·(M_0-M_1)^2最大,就可以得到最好的二值化阈值t
void solution4::otsuMethod(Mat& src, Mat& dst)
{
if (src.channels() != 1)
{
dst = src.clone();
cout << "input src's channel is not 1" << endl;
return;
}
double totalnum = src.rows * src.cols;
int otsu_th = 0;
double max_st = 0.0;
for (int i = 0; i < 256; i++)
{
int t0 = 0;//图像小于i的像素点数目
int t1 = 0;//图像大于i的像素点数目
int s0 = 0;//图像小于i的像素点灰度和
int s1 = 0;//图像大于i的像素点灰度和
double m0 = 0.0;//图像小于i的像素点的平均灰度
double m1 = 0.0;//图像大于i的像素点的平均灰度
double w0 = 0.0;//图像小于i的像素点数目/总数
double w1 = 0.0;//图像大于i的像素点数目/总数
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
int grayval = src.at<uchar>(row, col);
if (grayval < i)
{
t0++;
s0 += grayval;
}
else
{
t1++;
s1 += grayval;
}
}
}
w0 = t0 / totalnum;
w1 = t1 / totalnum;
if (w0 <= 0.0 || w1 <= 0.0)
{
continue;
}
m0 = s0 / t0;
m1 = s1 / t1;
double st = w0 * w1 * abs(m1 - m0);
if (st > max_st)
{
max_st = st;
otsu_th = i;
}
}
Mat dst_otsu;
threshold(src, dst, otsu_th, 255, THRESH_BINARY);
threshold(src, dst_otsu, 0, 255, THRESH_BINARY|THRESH_OTSU);
getchar();
}