一、介绍
今天学习了otus最大类间方差法,在图像分割中最重要的,最困难的就是寻找出前景和背景的阈值,而otus可以自动寻找出最大类间方差。设t为前景与背景的分割阈值,前景点数占图像比例为w0(w0:前景像素点的个数除以总像素点的个数),平均灰度为u0(u0前景灰度值的总和除以前景总像素值的个数);背景点数占图像比例为w1,平均灰度为u1。
则图像的总平均灰度为:u=w0u0+w1u1。
前景和背景图象的方差:g=w0*(u0-u)(u0-u)+w1(u1-u)(u1-u)=w0w1*(u1-u2)^2,此公式为方差公式。当方差g最大时,可以认为此时前景和背景差异最大,此时的灰度t是最佳阈值t = w0w1(u1-u2)*(u1-u2)。otus最大类间方差法的关键就是求解最佳阈值t。参考了下大佬求解阈值的过程,感觉很棒,与大家分享一下!
int myOtsu(Mat & src)
{
int th;
const int GrayScale = 256; //单通道图像总灰度256级
int pixCount[GrayScale] = {0};//每个灰度值所占像素个数
int pixSum = src.cols * src.rows;//图像总像素点
float pixPro[GrayScale] = {0};//每个灰度值所占总像素比例
float w0, w1, u0tmp, u1tmp, u0, u1,t, tmax= 0;
``
for(int i = 0; i < src.cols; i++)
{
for(int j = 0; j < src.rows; j++)
{
pixCount[src.at<uchar>(j,i)]++;//统计每个灰度级中像素的个数(关键步骤)
}
}
for(int i = 0; i < GrayScale; i++)
{
pixPro[i] = pixCount[i] * 1.0 / pixSum;//计算每个灰度级的像素数目占整幅图像的比例
}
for(int i = 0; i < GrayScale; i++)//遍历所有从0到255灰度级的阈值分割条件,测试哪一个的类间方差最大
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = t = 0;
for(int j = 0; j < GrayScale; j++)
{
if(j <= i)//背景
{
w0 += pixPro[j]; //这里确定是前景还是背景是通过逐个灰度级扫描的方式,当t去的最大值时,前景和背景的阈值就是所对应的i
u0tmp += j * pixPro[j];
}
else//前景
{
w1 += pixPro[j];
u1tmp += j * pixPro[j];
}
}
u0 = u0tmp / w0;
u1 = u1tmp / w1;
t = (float)(w0 *w1* pow((u0 - u1), 2)); //类间方差公式 g = w1 * w2 * (u1 - u2) ^ 2
if(t > tmax)
{
tmax = t;
th = i;
}
}
return th;
}
分割图片如下:
参考的大佬:
https://blog.csdn.net/u012198575/article/details/81128799?ops_request_misc
https://baike.baidu.com/item/otsu/16252828?fr=aladdin