OTSU常用的二值化方法

来源:互联网 发布:淘宝京东比价插件 编辑:程序博客网 时间:2024/05/22 05:18

OTSU算法称为大律法或最大类间方差法

原理:

利用阈值将原图像分成前景,背景两个图象。
前景:用w0,u0表示在当前阈值下的前景的点数占图像的比例,前景的平均灰度值
背景:用w1, u1表示在当前阈值下的背景的点数占图像的比例,背景的平均灰度值
当取最佳阈值时,背景应该与前景差别最大,关键在于如何选择衡量差别的标准,而在otsu算法中这个衡量差别的标准就是最大类间方差(英文简称otsu,这也就是这个算法名字的来源)
设th为前景与背景的分割阈值,则图像的总平均灰度为:
 
                     u=w0*u0+w1*u1
 
前景与背景图像的方差:
 
                   g= w0*(u0-u)*(u0-u)+w1*(u1-u)*(u1-u)=w0*w1*(u0-u1)*(u0-u1)
 
当方差g最大时,可以认为此时前景和背景差异最大,此时的灰度th是最佳阈值。
 
特点:
类间方差法对噪音和目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。
当目标与背景的大小比例悬殊时,类间方差准则函数可能呈现双峰或多峰,此时效果不好,但是类间方差法是用时最少的。
 
实现:

Mat Otsu(Mat src)   
{   
 int height=src.rows  ;//rows ; 
 int width=src.cols ;       
 int threshold;     
 float maxVariance=0;   
 float variance[256];
 //histogram   
 float histogram[256] = {0};   
 for(int i=0; i < height; i++) 
 {   
  //unsigned char* p=(unsigned char*)src.data  + src.step * i; 
  unsigned char* p=src.ptr<unsigned char>(i);
  for(int j = 0; j < width; j++)  
  { 

   //histogram[int(*p++)]++;   
   histogram[p[j]]++;
   
  }

 }   
 //normalize histogram   
 int size = height * width;   
 for(int i = 0; i < 256; i++) 
 {   
  histogram[i] = histogram[i] / size;   
 }   

 for(threshold=0;threshold<256;threshold++)
 {
  float w0 = 0, u0 = 0,w1= 0,u1= 0;
  for(int i = 0; i < threshold; i++)  
  {   
   w0 += histogram[i];  //前景像素 所占整幅图像的比例 
   u0 += i * histogram[i];//  前景像素的平均灰度值 
  }
  for(int i = threshold; i < 256; i++)  
  {   
   w1 += histogram[i];  //背景像素)所占整幅图像的比例 
   u1 += i * histogram[i];// 背景像素的平均灰度值 
  }
  variance[threshold] = w0*w1*(u0-u1)*(u0-u1);  
 }
 threshold=1;
 for(int i=1;i<256;i++)
 {
  if(variance[i]>variance[threshold])
  {
   threshold=i;
  }
 }
 Mat dst=src.clone();
 for(int i=0; i < height; i++) 
 {     
  unsigned char* data=src.ptr<unsigned char>(i);
  unsigned char* dst_data=dst.ptr<unsigned char>(i);
  for(int j = 0; j < width; j++)  
  {   
   if(data[j]<threshold)
   {
    dst_data[j]=255;
   }
   else
   {
    dst_data[j]=0;
   }
  }   
 }   

 return dst;   

0 0