otsu(大津法)灰度图像二值化方法的原理和C实现

Posted on 2011-09-23 21:20  Herway  阅读(4092)  评论(0编辑  收藏  举报

Otsu方法是一种全局化的动态二值化方法,又叫大津法,是一种灰度图像二值化的常用算法。该算法的基本思想是:设使用某一个阈值将灰度图像根据灰度大小,分成目标部分和背景部分两类,在这两类的类内方差最小和类间方差最大的时候,得到的阈值是最优的二值化阈值。

我个人对这个算法实践后的结果是:这个算法在光照均匀的时候,可以得到很好的效果,大多数情况下,都可以的到相当不错的效果。而且其本质是很好理解的。说通俗一点的比方,用一个分数线将班上所有学生的成绩分为好学生和差学生两类,要使两类学生的区分看起来最明显,很显然要达到的效果是:好学生和差学生之间要区别最大,同时好学生和好学生之间分数不能拉太大,同时差学生和差学生之间也差距不大。

回到图像的问题上来,对一幅NxM个像素的图像来说。

1.首先计算图像的总体灰度u,计算如下:

统计得到全部图像中灰度为i对应的像素个数n(i),于是

    u=1*n(1)/N*M+2*n(2)/N*M+......+i*n(i)/N*M;

 

2.记t为目标与背景的分割阈值,在该阈值下,得到目标像素(灰度大于t)占图像的比例w1,目标像素的平均灰度为u1,这两个参数计算如下:

遍历所有像素,得到灰度大于t的像素总数W1,于是

    w1=W1/N*M;

统计得到目标像素中灰度为i(i>t)对应的像素个数n(i),于是

    u1=1*n(1)/W1+2*n(2)/W1+......+i*n(i)/W1;(i>t)

 

同理,得到背景像素占图像的比例w2,背景像素的平均灰度u2。

 

3.遍历步骤2中的t,当t使得

    G=w1*(u1-u)*(u1-u)+w2*(u2-u)*(u2-u);

    G最大时,即得到了最佳阈值,与上式子等价的还有

    G=(u1-u)*(u1-u)*(u2-u)*(u2-u);最大

两者的等价关系很容易证明。

以下是我在一个工程中使用该算法的程序片段,实验性代码,不是很规范,仅供参考。

//这是一个车牌的图像,图像范围为PlateTop,PlateBottom,PlateLeft,PlateRight范围内的小片区域。

 //获取灰度直方图,八级灰度,存在数组GreyHisto[256]中
 memset(GreyHisto,0,256*sizeof(unsigned int));
 for (i=PlateTop;i<PlateBottom+1;i++){
  for (j=PlateLeft;j<PlateRight+1;j++){
  GreyHisto[PreProcessedImage[i*720+j]]++;
  }
 }
 //找出灰度范围,最小灰度为GreyA,最大灰度为GreyB.
 for (i=0;i<256;i++){
  if (GreyHisto[i]>0){
  GreyA=i;break;}
 }

 for (i=255;i>0;i--){
  if (GreyHisto[i]>0){
  GreyB=i;break;}
 }

 //求平均灰度
 temp0=0;
 for (i=GreyA;i<GreyB+1;i++){
  temp0=temp0+i*GreyHisto[i];
 }
 PlatePixSum=(PlateRight-PlateLeft+1)*(PlateBottom-PlateTop+1);
 
 Ave_u=temp0/PlatePixSum;//总平均灰度u

 for (t=GreyA;t<GreyB+1;t++){
  temp_u0=0;
  temp_uu0=0;
  for (i=GreyA;i<t+1;i++)
  temp_u0=temp_u0+GreyHisto[i];//目标比例w0 (如果要使用严格意义上的比例,还需要除以总像素,下同)
  temp_u1=PlatePixSum-temp_u0;//背景比例w1 (这里为避免除法运算,不做比例,只做整数比)
  
  for (i=GreyA;i<t+1;i++)
  temp_uu0=temp_uu0+i*GreyHisto[i];
  temp_uu1=temp0-temp_uu0;
  
  Ave_u0=temp_uu0/temp_u0;//目标平均灰度u0
  Ave_u1=temp_uu1/temp_u1;//背景平均灰度u1
  
  otsu_G[t]=(Ave_u0-Ave_u)*(Ave_u0-Ave_u)*(Ave_u1-Ave_u)*(Ave_u1-Ave_u);
//  otsu_G[t]=temp_u0*(Ave_u0-Ave_u)*(Ave_u0-Ave_u)+temp_u1*(Ave_u1-Ave_u)*(Ave_u1-Ave_u);

  }

 maxG=0;
 for (i=GreyA;i<GreyB+1;i++){
  if (otsu_G[i]>maxG){
   maxG=otsu_G[i]; Threshold=i;}
 }

 

最后的到的Threshold即为最佳阈值。

 

Copyright © 2024 Herway
Powered by .NET 8.0 on Kubernetes