天天看點

圖像二值化算法比較

要寫論文了,就整理了下圖像二值方面的算法及性能比較,記在這裡。

此篇介紹兩種全局門檻值方法,下篇介紹自适應方法。

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