前面学习了直方图双峰法:图像二值化方法中的阈值法
最大类间方差法(OTSU)是找到自适应阈值的常用方法。原理参考了冈萨雷斯的《数字图像处理》。
以下是自己写的函数:
//----获取灰度图in的OTSU阈值--
int Segment::otsuMat(Mat in)
{
int i,j;
int temp;
//第一类均值,第二类均值,全局均值,mk=p1*m1, 第一类概率,第二类概率
double m1,m2,mG,mk,p1,p2;
int hist[256] = {0};
double pro_hist[256] = {0.0};
double cov;
double maxcov=0.0;
int maxthread=0;
int row = in.rows;
int col = in.cols;
//统计每个灰度的数量
for(i=0; i<row; ++i) {
for(j=0; j<col; ++j) {
temp = in.at<uchar>(i,j);
hist[temp]++;
}
}
//计算每个灰度级占图像的概率
for(i=0; i<256; ++i)
pro_hist[i] = (double)hist[i]/(double)(row*col);
//计算平均灰度值
mG = 0.0;
for(i=0; i<256; ++i)
mG += i * pro_hist[i];
//统计前景和背景的平均灰度值,并计算类间方差
for(i=0; i<256; ++i)
{
m1=0.0; m2=0.0; mk=0.0; p1=0.0; p2=0.0;
for(j=0; j<i; ++j) {
p1 += pro_hist[j];
mk += j*pro_hist[j];
}
m1 = mk/p1; //mk=p1*m1,是一个中间值
p2 = 1 - p1; //p1+p2=1;
m2 = (mG - mk)/p2; //mG=p1*m1+p2*m2;
//计算类间方差
cov = p1*p2*(m1-m2)*(m1-m2);
if(cov>maxcov) {
maxcov = cov;
maxthread = i;
}
}
//cout<<maxthread<<endl;
return maxthread;
}
每次需要的时候就直接复制粘贴,效果常常很满意,就感觉要二值化OTSU法总可以用上,但是今天发现不好用了。我需要把一组图片分离出目标和背景,选取了Lab空间中的L通道,直接使用OTSU法。本来这一组图背景很相似,但是结果发现分割后有一些图片错误太明显。查看了阈值,发现相差蛮多的。例如下面的四张图。