(1)otsu :最大类间方差
记t为前景与背景的分割阈值,前景点数占图像比例为w0, 平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。
则图像的总平均灰度为:u=w0*u0+w1*u1。
前景和背景图象的方差:g=w0*(u0-u)*(u0-u)+w1*(u1-u)*(u1-u)。
当方差g最大时,可以认为此时前景和背景差异最大,此时的灰度t是最佳阈值。
int otsu(IplImage *image)
{
cvNamedWindow("kanxia",1);
cvShowImage("kanxia",image);
assert(NULL != image);
int width = image->width;
int height = image->height;
int x=0,y=0;
int pixelCount[256]={0};
float pixelPro[256]={0};
int i, j, pixelSum = width * height, threshold = 0;
uchar* data = (uchar*)image->imageData;
//统计灰度级中每个像素在整幅图像中的个数
for(i = y; i < height; i++)
{
for(j = x;j <width;j++)
{
pixelCount[data[i * image->widthStep + j]]++;
}
}
//计算每个像素在整幅图像中的比例
for(i = 0; i < 256; i++)
{
pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
}
//经典ostu算法,得到前景和背景的分割
//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
float w0, w1, u0tmp, u1tmp, u0, u1, u,deltaTmp, deltaMax = 0;
for(i = 0; i < 256; i++)
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
for(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;
}
}
cout<<"阈值为:"<<threshold<<endl;
//返回最佳阈值;
return threshold;
}
(2)迭代阈值分割
迭代阈值分割就是通过迭代方法计算阈值,求取阈值的具体步骤为:假定一个初始阈值T1,T1一般取图像中灰度值的最大值和最小值的中间值;使用T1分割图像,得到两个数组H1和H2,H1是由灰度值大于等于T1的所有像素点组成,H2由灰度值小于T1的所有像素组成;
计算H1和H_2两个数组的平均值μ1和μ2;计算新阈值
T2=(μ1+ μ2)/2 (2-5)
如果|T2-T1 |≤T0(T_0为一个很小的数),即两次阈值的值很接近时,迭代终止,否则T1=T2,重复上述步骤。最后的T2就是所求的阈值。
int height = img->height;
int width = img->width;
int step = img->widthStep;
int channels = img->nChannels;
uchar* data = (uchar*)img->imageData;
double tempg = -1;//临时类间方差
double Histogram[256]={0};// = new double[256];//灰度直方图
for(int i=0;i<height;i++)
{//计算直方图
for(int j=0;j<width;j++)
{
double temp =data[i*step + j * 3] * 0.114 + data[i*step + j * 3+1] * 0.587 + data[i*step + j * 3+2] * 0.299;
temp = temp<0? 0:temp;
temp = temp>255? 255:temp;
Histogram[(int)temp]++;
}
}
//迭代阈值分割
double k1,k2;
double t=0,u=0,u1,u2;
for (i=0;i<255;i++)
{
t+=Histogram[i];
u+=i*Histogram[i];
}
k2= (u/t);
//迭代,知道k1=K2;
do
{
k1=k2;
t=u=0.0;
for (i=0;i<k2;i++)//K2将图像分成2部分,低灰度区域的灰度平均值
{
t+=Histogram[i];
u+=i*Histogram[i];
}
u1=u/t;
t=u=0.0;
for(i=(int)k2;i<255;i++)//高灰度区域的灰度平均值
{
t+=Histogram[i];
u+=i*Histogram[i];
}
u2=u/t;
k2=(u1+u2)/2;//取平均
} while (fabs(k1-k2)<0.000000001);//知道二次的平均一致,不在改变!
cvThreshold(m_pImage, m_pImage, k2+10, 255, CV_THRESH_BINARY_INV);