自动二值化算法

来源:互联网 发布:淘宝东西刚买完就下架 编辑:程序博客网 时间:2024/05/19 08:23

自动二值化算法

                                                                                 cndg

二值化算法用很多,比如中值算法,迭代法等,本文主要介绍几种效果不错的自动二值化算法,这些代码是基于在Cxiamge基础上编写的,关于Cxiamge的源代码可以到www.codeproject.com下载.

1、采用大津法进行阈值二值化

 void AutoThreshold(CxImage *iSrc, int &nLevel,CxImage *iDst)

{

  void* pDib = NULL;

 pDib = iSrc->GetDIB();

if (!pDib) return ;

 if (iSrc->GetBpp()==1) return ;

 long iWidth = 0,iHeight =0,x = 0,y = 0,i = 0,t = 0;

unsigned char iThreshold, iNewThreshold, iMaxGrayValue = 255, iMinGrayValue = 0, iMean1GrayValue, iMean2GrayValue;

 double w0,w1,iMeanGrayValue;

double G=0, tempG=0;

 long lP1, lS1, lP2, lS2;

iWidth = iSrc->GetWidth();

iHeight = iSrc->GetHeight();

//保存原始图像

CxImage tmpSrc(iWidth,iHeight,iSrc->GetBpp());

tmpSrc.Copy(*iSrc);

///////////////////////////////////////////////

iSrc->GrayScale();

//灰度分布统计

 long *pGray = new long[256];

 memset(pGray,0,sizeof(long)*256);

for (y=0;yGetPixelIndex(x,y);

  pGray[i]++; //修改最大灰度值和最小灰度值

if(iMinGrayValue > i)

 { iMinGrayValue = i; }

if(iMaxGrayValue < i)

{ iMaxGrayValue = i; } } } // 遍历t, 选取最佳阈值

for(t = iMinGrayValue; t < iMaxGrayValue ; t++)

{

iNewThreshold = t; lP1 = 0; lS1 = 0; lP2 = 0; lS2 = 0; // 求前景,背景两个区域的平均灰度值, 点数所占比例

for(i = iMinGrayValue; i <= iNewThreshold; i++)

{ lP1 += pGray[i] * i; lS1 += pGray[i]; }

if(lS1==0) continue;

 iMean1GrayValue = (unsigned char) (lP1/lS1);

w0 = (double) (lS1) / (iWidth * iHeight);

 for(i = iNewThreshold + 1; i <= iMaxGrayValue; i++)

{ lP2 += pGray[i] * i; lS2 += pGray[i]; }

if(lS2==0) continue;

iMean2GrayValue = (unsigned char) (lP2/lS2);

w1 = 1 - w0;

 iMeanGrayValue=w0*iMean1GrayValue +w1*iMean2GrayValue ;

 G = w0 *(iMean1GrayValue-iMeanGrayValue)*(iMean1GrayValue-iMeanGrayValue)+w1* (iMean2GrayValue-iMeanGrayValue)*(iMean2GrayValue-iMeanGrayValue);

 if(G > tempG)

{ tempG = G; iThreshold = iNewThreshold; }

}

nLevel = iThreshold;

if(pGray)

 { delete []pGray; pGray = NULL; }

 ////////////////////////////////////////////////

CxImage tmp(iWidth,iHeight,1);

if (!tmp.IsValid()) { return ; }

for (y=0;yGetPixelIndex(x,y);

 if (i>nLevel)

 tmp.SetPixelIndex(x,y,0);

else

tmp.SetPixelIndex(x,y,1); }

}

tmp.SetPaletteColor(0,255,255,255);

 tmp.SetPaletteColor(1,0,0,0);

iDst->Transfer(tmp);

 // iSrc->Copy(tmpSrc);

}

 

2、自动自适应二值化

BOOL AutoAdaptiveThreshold(CxImage *iSrc,long method = 0, long nBoxSize = 64, CxImage* pContrastMask = 0, long nBias = 0, float fGlobalLocalBalance = 0.5f,CxImage *iDst=NULL);

int OptimalThreshold(CxImage *iSrc,long method = 0, RECT * pBox = 0, CxImage* pContrastMask = 0);

 

/**

* Finds the optimal (global or local) treshold for image binarization

* /param method: 0 = average all methods (default); 1 = Otsu; 2 = Kittler & Illingworth; 3 = max entropy; 4 = potential difference;

 * /param pBox: region from where the threshold is computed; 0 = full image (default).

* /param pContrastMask: limit the computation only in regions with contrasted (!=0) pixels; default = 0.

* the pContrastMask image must be grayscale with same with and height of the current image,

* can be obtained from the current image with a filter:

* CxImage iContrastMask(*image,true,false,false);

* iContrastMask.GrayScale();

* long edge[]={-1,-1,-1,-1,8,-1,-1,-1,-1};

* iContrastMask.Filter(edge,3,1,0);

* long blur[]={1,1,1,1,1,1,1,1,1};

* iContrastMask.Filter(blur,3,9,0);

* /return optimal threshold; -1 = error.

* /sa AdaptiveThreshold

*/

 

int OptimalThreshold(CxImage *iSrc,long method, RECT * pBox, CxImage* pContrastMask)

{

void *pDib = NULL;

pDib = iSrc->GetDIB();

 if (!pDib) return 0;

int nBitCount = 0,nWidth = 0,nHeight = 0;

nWidth = iSrc->GetWidth();

 nHeight = iSrc->GetHeight();

nBitCount = iSrc->GetBpp();

 if (nBitCount!=8)

{

//OptimalThreshold works only on 8 bit images

return -1;

 }

if (pContrastMask)

{

if (!pContrastMask->IsValid() || !pContrastMask->IsGrayScale() || pContrastMask->GetWidth() != nWidth || pContrastMask->GetHeight() != nHeight)

{

//OptimalThreshold invalid ContrastMask

 return -1;

}

}

long xmin,xmax,ymin,ymax;

if (pBox)

{ xmin = max(pBox->left,0); xmax = min(pBox->right,nWidth);

 ymin = max(pBox->bottom,0); ymax = min(pBox->top,nHeight);

 }

else

{ xmin = ymin = 0; xmax = nWidth; ymax = nHeight; }

 if (xmin>=xmax || ymin>=ymax)

return -1;

double p[256];

 memset(p, 0, 256*sizeof(double));

//build histogram

for (long y = ymin; yGetBits(y) + xmin; BYTE* pContr = 0;

if (pContrastMask)

 pContr = pContrastMask->GetBits(y) + xmin;

 for (long x = xmin; x0 && p[gray_max]==0)

gray_max--;

if (gray_min > gray_max)

 return -1;

if (gray_min == gray_max)

{ if (gray_min == 0) return 0; else return gray_max-1; }

//compute total moments 0th,1st,2nd order int i,k;

double w_tot = 0; double m_tot = 0; double q_tot = 0;

 for (i = gray_min; i <= gray_max; i++){ w_tot += p[i]; m_tot += i*p[i]; q_tot += i*i*p[i]; }

double L, L1max, L2max, L3max, L4max; //objective functions int th1,th2,th3,th4;

 //optimal thresholds L1max = L2max = L3max = L4max = 0; th1 = th2 = th3 = th4 = -1;

double w1, w2, m1, m2, q1, q2, s1, s2; w1 = m1 = q1 = 0;

for (i = gray_min; i < gray_max; i++)

{ w1 += p[i]; w2 = w_tot - w1; m1 += i*p[i]; m2 = m_tot - m1; q1 += i*i*p[i]; q2 = q_tot - q1; s1 = q1/w1-m1*m1/w1/w1;

//s1 = q1/w1-pow(m1/w1,2);

s2 = q2/w2-m2*m2/w2/w2;

//s2 = q2/w2-pow(m2/w2,2);

//Otsu L = -(s1*w1 + s2*w2);

//implemented as definition //

L = w1 * w2 * (m2/w2 - m1/w1)*(m2/w2 - m1/w1);

//implementation that doesn't need s1 & s2 i

f (L1max < L || th1<0){ L1max = L; th1 = i; }

//Kittler and Illingworth

if (s1>0 && s2>0){ L = w1*log(w1/sqrt(s1))+w2*log(w2/sqrt(s2));

 //

L = w1*log(w1*w1/s1)+w2*log(w2*w2/s2); if (L2max < L || th2<0){ L2max = L; th2 = i; } }

//max entropy

 L = 0; for (k=gray_min;k<=i;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w1)/w1;

for (k;k<=gray_max;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w2)/w2; if (L3max < L || th3<0){ L3max = L; th3 = i; }

//potential difference (based on Electrostatic Binarization method by J. Acharya & G. Sreechakra)

// L=-fabs(vdiff/vsum); ?molto selettivo, sembra che L=-fabs(vdiff) o L=-(vsum)

// abbiano lo stesso valore di soglia... il che semplificherebbe molto la routine

double vdiff = 0; for (k=gray_min;k<=i;k++) vdiff += p[k]*(i-k)*(i-k); double vsum = vdiff; for (k;k<=gray_max;k++){ double dv = p[k]*(k-i)*(k-i); vdiff -= dv; vsum += dv; } if (vsum>0) L = -fabs(vdiff/vsum); else L = 0; if (L4max < L || th4<0){ L4max = L; th4 = i; } } int threshold; switch (method){ case 1: //Otsu threshold = th1; break; case 2: //Kittler and Illingworth threshold = th2; break; case 3: //max entropy threshold = th3; break; case 4: //potential difference threshold = th4; break; default: //auto { int nt = 0; threshold = 0; if (th1>=0) { threshold += th1; nt++;} if (th2>=0) { threshold += th2; nt++;} if (th3>=0) { threshold += th3; nt++;} if (th4>=0) { threshold += th4; nt++;} if (nt) threshold /= nt; else threshold = (gray_min+gray_max)/2; } } if (threshold <= gray_min || threshold >= gray_max) threshold = (gray_min+gray_max)/2; return threshold; } /** * Converts the image to B&W, using a threshold mask * /param pThresholdMask: the lightness threshold mask. * the pThresholdMask image must be grayscale with same with and height of the current image * /return true if everything is ok */ bool Threshold(CxImage *iSrc,CxImage* pThresholdMask,CxImage* iDst) { void *pDib = NULL; pDib = iSrc->GetDIB(); if (!pDib) return false; iDst->Copy(*iSrc); int nBitCount = 0,nWidth = 0,nHeight = 0; nWidth = iSrc->GetWidth(); nHeight = iSrc->GetHeight(); nBitCount = iSrc->GetBpp(); if (nBitCount == 1) return true; if (!pThresholdMask) return false; if (!pThresholdMask->IsValid() || !pThresholdMask->IsGrayScale() || pThresholdMask->GetWidth() != nWidth || pThresholdMask->GetHeight() != nHeight){ return false; } iDst->GrayScale(); CxImage tmp(nWidth,nHeight,1); if (!tmp.IsValid()) { return false; } BYTE b1,b2; for (long y=0;yBlindGetPixelIndex(x,y); b2 = pThresholdMask->BlindGetPixelIndex(x,y); if (b1>b2) tmp.BlindSetPixelIndex(x,y,1); else tmp.BlindSetPixelIndex(x,y,0); } } tmp.SetPaletteColor(0,0,0,0); tmp.SetPaletteColor(1,255,255,255); iDst->Transfer(tmp); return true; } BOOL AutoAdaptiveThreshold(CxImage *iSrc,long method, long nBoxSize, CxImage* pContrastMask, long nBias, float fGlobalLocalBalance,CxImage *iDst) { void *pDib = NULL; pDib = iSrc->GetDIB(); if (!pDib) return FALSE; int nWidth = 0,nHeight = 0; nWidth = iSrc->GetWidth(); nHeight = iSrc->GetHeight(); if (pContrastMask){ if (!pContrastMask->IsValid() || !pContrastMask->IsGrayScale() || pContrastMask->GetWidth() != nWidth || pContrastMask->GetHeight() != nHeight) { return FALSE; } } if (nBoxSize<8) nBoxSize = 8; if (fGlobalLocalBalance<0.0f) fGlobalLocalBalance = 0.0f; if (fGlobalLocalBalance>1.0f) fGlobalLocalBalance = 1.0f; long mw = (nWidth + nBoxSize - 1)/nBoxSize; long mh = (nHeight + nBoxSize - 1)/nBoxSize; CxImage mask(mw,mh,8); if(!mask.GrayScale()) return FALSE; if(!iSrc->GrayScale()) return FALSE; int globalthreshold = OptimalThreshold(iSrc,method, 0, pContrastMask); if (globalthreshold <0) return FALSE; for (long y=0; yCopy(tmp); return true; }