自动二值化算法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

自动二值化算法自动二值化算法

自动二值化算法
cndg
二值化算法用很多,比如中值算法,迭代法等,本文主要介绍几种效果不错的自动二值化算法,这些代码是基于在Cxiamge基础上编写的,关于Cxiamge的源代码可以到下载.
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; }

相关文档
最新文档