一、Ostu的原理
最大类间方差法是由日本学者大津(Nobuyuki Ostu)在1979年提出的,该方法根据计算公式自动计算分割单域值,是一种根据灰度图像自动计算阈值的方法。它按照灰度图像的灰度值等级属性,将图像256个灰度级自动划分成背景点和目标点两部分,即计算出一个合适的中间值k,将图像256个灰度级分为两部分。算法分类的原理是使背景和目标之间的类间方差最大,因为背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大,错分的可能性越小。
类间方法
g
g
g的计算公式为:
g
=
w
1
∗
w
−
2
∗
(
u
1
−
u
2
)
2
g=w_1*w-2*(u_1-u_2)^2
g=w1∗w−2∗(u1−u2)2
其中:
w
1
w_1
w1为目标像素点占整幅图像的比例,
u
1
u_1
u1为其平均灰度,
w
2
w_2
w2为背景像素点占整幅图像的比例,
u
2
u_2
u2为其平均灰度。通过公式计算得到的
g
g
g也就是类间方差最大值,即这副图像的自适应阈值。
二、基于OpenCV的C++程序
int otsu(Mat image)
{
int width = image.rows, height = image.cols, threshold = 0;
int pixelCount[256];
float pixelPro[256];
//初始化
for (int i = 0; i < 256; i++)
{
pixelCount[i] = 0;
pixelPro[i] = 0;
}
//统计灰度级中每个像素在整幅图像中的个数
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
pixelCount[image.at<uchar>(i,j)]++;
}
}
//计算每个像素在整幅图像中的比例
for (int i = 0; i < 256; i++)
{
pixelPro[i] = (float)(pixelCount[i]) / (float)(width*height);
}
//经典ostu算法,得到前景和背景的分割
//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
for (int i = 0; i < 256; i++)
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
for (int j = 0; j < 256; j++)
{
if (j <= i) //背景部分
{
//以i为阈值分类,第一类总的概率
w0 += pixelPro[j];
u0tmp += j * pixelPro[j];
}
else //前景部分
{
//以i为阈值分类,第二类总的概率
w1 += pixelPro[j];
u1tmp += j * pixelPro[j];
}
}
u0 = u0tmp / w0; //第一类的平均灰度
u1 = u1tmp / w1; //第二类的平均灰度
u = u0tmp + u1tmp; //整幅图像的平均灰度
//计算类间方差
deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
//找出最大类间方差以及对应的阈值
if (deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
threshold = i;
}
}
//返回最佳阈值;
return threshold;
}
void main()
{
cv::Mat diff_image, binary_image;
diff_image = imread("..//xx", 0); //读取灰度图
int threshold = otsu(diff_image); //得到阈值
cv::threshold(diff_image, binary_image, threshold, 255, THRESH_BINARY); //二值化
imshow("binary_image", binary_image);
}