天天看点

图像二值化算法比较

要写论文了,就整理了下图像二值方面的算法及性能比较,记在这里。

此篇介绍两种全局阈值方法,下篇介绍自适应方法。

1:经典算法OTSU

OTSU的中心思想是阈值T应使目标与背景两类的类间方差最大。

//用类间方差最大思想计算阈值

int Threshold(int *hist)  //compute the threshold

{

 float u0, u1;

 float w0, w1;

 int count0;

 int t, maxT;

 float devi, maxDevi = 0; //方差及最大方差

 int i;

 int sum = 0;

 for (i = 0; i < 256; i++)

 {

  sum = sum + hist[i];

 }

 for (t = 0; t < 255; t++)

 {

  u0 = 0; count0 = 0;

  //阈值为t时,c0组的均值及产生的概率

  for (i = 0; i <= t; i++)

  {

   u0 += i * hist[i]; count0 += hist[i];

  }

  u0 = u0 / count0; w0 = (float)count0/sum;

  //阈值为t时,c1组的均值及产生的概率

  u1 = 0;

  for (i = t + 1; i < 256; i++)

  {

   u1 += i * hist[i]; 

  }

  u1 = u1 / (sum - count0); w1 = 1 - w0;

  //两类间方差

  devi = w0 * w1 * (u1 - u0) * (u1 - u0);

  //记录最大的方差及最佳位置

  if (devi > maxDevi)

  {

   maxDevi = devi;

   maxT = t;

  }

 }

 return maxT;

}

//二值化处理

void OTSU(IplImage *src, IplImage *dst)

{

 int i = 0, j = 0;

 int wide = src->widthStep;

 int high = src->height;

 int hist[256] = {0};

 int t;

 unsigned char *p, *q;

 for (j = 0; j < high; j ++)

 {

  p = (unsigned char *)(src->imageData + j * wide);

  for (i = 0; i < wide; i++)

  {

   hist[p[i]]++;   //统计直方图

  }

 }

 t = Threshold(hist);

 for (j = 0; j < high; j ++)

 {

  q = (unsigned char *)(dst->imageData + j * wide);

  p = (unsigned char *)(src->imageData + j * wide);

  for (i = 0; i < wide; i++)

  {

   q[i] = p[i] >= t ? 255 : 0;

  }

 }

}

OTSU算法对不均匀光照的图片不能产生很好的效果。

2:另外一个Kittler算法,是一种快速的全局阈值法。它的效果不比OTSU差多少,但速度快好多倍,如果可以应用在图像质量不错的环境。

它的中心思想是,计算整幅图像的梯度灰度的平均值,以此平均值做为阈值。

//kittler算法

  for (i=1;i<high-1;i++)             

 {

  plineadd=src->imageData+i*wide;

  pNextLine=src->imageData+(i+1)*wide;

  pPreLine=src->imageData+(i-1)*wide; 

  for(j=1;j<wide-1;j++)

  {

//求水平或垂直方向的最大梯度

   Grads=MAX(abs((uchar)pPreLine[j]-(uchar)pNextLine[j]),abs((uchar)plineadd[j-1]-(uchar)plineadd[j+1])); //max(xGrads,yGrads)

   sumGrads += Grads;

//梯度与当前点灰度的积

   sumGrayGrads += Grads*((uchar)plineadd[j]);   

  }

 }

 threshold=sumGrayGrads/sumGrads;

// printf("%d\n",threshold);

 for(i=0;i<high;i++)

 { 

  plineadd=src->imageData+i*wide;

  pTempLine=kittler->imageData+i*wide;

  for(j=0;j<wide;j++)

  {

   pTempLine[j]=(uchar)plineadd[j]>threshold?255:0;

  }

 }

转载于:https://www.cnblogs.com/lingde27/archive/2011/04/29/2032570.html