- 算法步骤:
1.生成灰度直方图,即统计各灰度级的像素个数,。
2.归一化直方图,即计算各灰度级像素占总像素的比例。
3.从灰度0迭代到灰度255,每次迭代计算前景像素(灰度0至当前迭代灰度的像素)的比例w0,计算前景像素的平均灰度值u0;
计算背景像素(当前迭代灰度至灰度255的像素)的比例w1和平均灰度u1;
4.每次迭代计算前景像素和背景像素的方差 g = w0*w1*(u0-u1) ^2;
5.比较每次迭代的方差,取最大方差的那次迭代灰度为二值化的阈值。
- 算法原理:
记前景像素个数为n0,比例为w0,灰度和为s0,平均灰度为u0;背景像素个数为n1,比例为w1,灰度和为s1,平均灰度为u1;
图像的总像素个数为n,灰度和为s,平均灰度u。类间方差为g。
有公式如下:
w0=n0/n; w1=n1/n; n0+n1=n; w0+w1=1;
u0=s0/n0; u1=s1/n1; u=s/n u=u0*w0+u1*w1;
g=w0*(u0-u)^2+w1(u1-u)^2;
最终可得g = w0*w1*(u0-u1) ^2;
对于直方图有两个峰值的图像,大律法所求的阈值近似于两个峰值之间的低谷,因此可以用来二值划分。
- 算法实现:
为了减少迭代深度, 用公式u=u0*w0+u1*w1化去g = w0*w1*(u0-u1) ^2中的u1,得到公式:
g=w0/(1-w0)*(u0-u)^2
代码实现如下:
unsigned char Ostu(int size,unsigned char *image) { int i; unsigned char threshold=0; //阈值 float variance=0; //类间方差 float maxvariance=0; //最大方差 float gray=0; //前景灰度比例 float w0=0; //前景像素比例 float u0=0; //前景平均灰度 float u=0; //总平均灰度,可看做i=255时的前景灰度比例 float histogram[256]={0}; //直方图 for (i=0;i){ histogram[*(image+i)]++; //像素直方图 } for (i=0;i<256;i++){ histogram[i]/=size; //比例直方图 u+=histogram[i]*i; //获取i=255时的前景灰度比例,即总平均灰度 } for (i=0;i<256;i++){ w0+=histogram[i]; //前景像素比例 gray+=i*histogram[i]; //前景灰度比例 u0=gray/w0; //前景平均灰度=前景灰度比例/像素比例=灰度和/像素和 variance=w0/(1-w0)*(u0-u)*(u0-u); //求方差 if (variance>maxvariance){ maxvariance=variance; threshold=i; //将最大g相应的i值作为图像的全局阈值 } } return threshold; }