首页 > 代码库 > 基于直方图的图像二值化算法实现

基于直方图的图像二值化算法实现

引言

图像二值化的目的是最大限度的将图象中感兴趣的部分保留下来,在很多情况下,也是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。在过去年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法,但如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果。 

在分类方法中,基于直方图的全局二值算法都从不同的科学层次提出了各自的实施方案,并且这类方法都有着一些共同的特点:简单、算法容易实现和执行速度快。      

算法代码

第一种方法Huang L.-K et al.参考代码:

// Implements Huang‘s fuzzy thresholding method 
// Uses Shannon‘s entropy function (one can also use Yager‘s entropy function) 
// Huang L.-K. and Wang M.-J.J. (1995) "Image Thresholding by Minimizing  
// the Measures of Fuzziness" Pattern Recognition, 28(1): 41-51 M. Emre Celebi  06.15.2007
// Ported to ImageJ plugin by G. Landini from E Celebi‘s fourier_0.8 routines

int HuangLKThreshold(int* data){
    int threshold=-1;
    int ih, it;
    int first_bin;
    int last_bin;
    int sum_pix;
    int num_pix;
    double term;
    double ent;  // entropy 
    double min_ent; // min entropy 
    double mu_x;

    /* Determine the first non-zero bin */
    first_bin=0;
    for (ih = 0; ih < 256; ih++ ) {
        if ( data[ih] != 0 ) {
            first_bin = ih;
            break;
        }
    }

    /* Determine the last non-zero bin */
    last_bin=255;
    for (ih = 255; ih >= first_bin; ih-- ) {
        if ( data[ih] != 0 ){
            last_bin = ih;
            break;
        }
    }
    term = 1.0 / ( double ) ( last_bin - first_bin );
    double mu_0[256]={0.0};
    sum_pix = num_pix = 0;
    for ( ih = first_bin; ih < 256; ih++ ){
        sum_pix += ih * data[ih];
        num_pix += data[ih];
        /* NUM_PIX cannot be zero ! */
        mu_0[ih] = sum_pix / ( double ) num_pix;
    }

    double mu_1[256]={0.0};
    sum_pix = num_pix = 0;
    for ( ih = last_bin; ih > 0; ih-- ){
        sum_pix += ih * data[ih];
        num_pix += data[ih];
        /* NUM_PIX cannot be zero ! */
        mu_1[ih - 1] = sum_pix / ( double ) num_pix;
    }

    /* Determine the threshold that minimizes the fuzzy entropy */
    threshold = -1;
    min_ent = 65535;
    for ( it = 0; it < 256; it++ ){
        ent = 0.0;
        for ( ih = 0; ih <= it; ih++ ) {
            /* Equation (4) in Ref. 1 */
            mu_x = 1.0 / ( 1.0 + term * abs ( ih - mu_0[it] ) );
            if ( !((mu_x  < 1e-06 ) || ( mu_x > 0.999999))) {
                /* Equation (6) & (8) in Ref. 1 */
                ent += data[ih] * ( -mu_x * log ( mu_x ) - ( 1.0 - mu_x ) * log ( 1.0 - mu_x ) );
            }
        }

        for ( ih = it + 1; ih < 256; ih++ )  {
            /* Equation (4) in Ref. 1 */
            mu_x = 1.0 / ( 1.0 + term * abs ( ih - mu_1[it] ) );
            if ( !((mu_x  < 1e-06 ) || ( mu_x > 0.999999))) {
                /* Equation (6) & (8) in Ref. 1 */
                ent += data[ih] * ( -mu_x * log ( mu_x ) - ( 1.0 - mu_x ) * log ( 1.0 - mu_x ) );
            }
        }
        /* No need to divide by NUM_ROWS * NUM_COLS * LOG(2) ! */
        if ( ent < min_ent ){
            min_ent = ent;
            threshold = it;
        }
    }
    return threshold;
}

第二种方法参考代码

// J. M. S. Prewitt and M. L. Mendelsohn, "The analysis of cell images," in
// Annals of the New York Academy of Sciences, vol. 128, pp. 1035-1053, 1966.
// ported to ImageJ plugin by G.Landini from Antti Niemisto‘s Matlab code (GPL)
// Original Matlab code Copyright (C) 2004 Antti Niemisto
// See http://www.cs.tut.fi/~ant/histthresh/ for an excellent slide presentation
// and the original Matlab code.
//
// Assumes a bimodal histogram. The histogram needs is smoothed (using a
// running average of size 3, iteratively) until there are only two local maxima.
// j and k
// Threshold t is (j+k)/2.
// Images with histograms having extremely unequal peaks or a broad and
// at valley are unsuitable for this method.

bool BinodalTest(double *y) {
    int len=256;//y.length;
    bool b = false;
    int modes = 0;

    for (int k=1;k<len-1;k++){
        if (y[k-1] < y[k] && y[k+1] < y[k]){
            modes++;
            if (modes>2)  return false;
        }
    }
    if (modes == 2) b = true;
    return b;
}

int IntermodesThreshold(int *data ) {
    double iHisto[256]={0};
    double tHisto[256]={0};
    int iter =0;
    int threshold=-1;
    for (int i=0; i<256; i++){
        iHisto[i]=(double) data[i];
        tHisto[i] = (double)data[i];
    }
  
	while (!BinodalTest(iHisto) ){
        //smooth with a 3 point running mean filter
        for (int i=1; i<255; i++)
            tHisto[i]= (iHisto[i-1] + iHisto[i] + iHisto[i+1])/3;
        tHisto[0] = (iHisto[0]+iHisto[1])/3; //0 outside
        tHisto[255] = (iHisto[254]+iHisto[255])/3; //0 outside
        //iHisto = tHisto;
        for(int i=0; i<256; i++){
            iHisto[i] = tHisto[i];
        }
        iter++;
        if (iter>10000)  {
            threshold = -1;
            //IJ.log("Intermodes: threshold not found after 10000 iterations.");
            return threshold;
        }
}
第三种方法参考代码
// C. A. Glasbey, "An analysis of histogram-based thresholding algorithms,"
// CVGIP: Graphical Models and Image Processing, vol. 55, pp. 532-537, 1993.
// The threshold is the mean of the greyscale data
int MeanThreshold(int* data ){
    int threshold = -1;
    double tot=0, sum=0;
    for (int i=0; i<256; i++){
        tot+= data[i];
        sum+=(i*data[i]);
    }
    threshold =cvFloor(sum/tot);
    return threshold;
}
测试主程序

IplImage *srcImg = cvLoadImage("test.jpg");
IplImage *grayImg = cvCreateImage(cvGetSize(srcImg), 8, 1);
cvCvtColor(srcImg, grayImg, CV_BGR2GRAY);

int hist_size = 256;
float range_0[] = {0, 256};
float* ranges[] = {range_0};

CvHistogram *hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);
cvCalcHist(&grayImg, hist, 0, NULL);    
int data[256];
for(int idx = 0; idx < 256; ++idx){
    data[idx] = cvGet1D(hist->bins, idx).val[0];
}

IplImage *binaryImg = cvCreateImage(cvGetSize(grayImg), 8, 1);
cvThreshold(grayImg, binaryImg, HuangThreshold(data), 255, CV_THRESH_BINARY);
cvNamedWindow("Huang");
cvShowImage("Huang", binaryImg);

cvThreshold(grayImg, binaryImg, IntermodesThreshold(data), 255, CV_THRESH_BINARY);
cvNamedWindow("Intermodes");
cvShowImage("Intermodes", binaryImg);

cvThreshold(grayImg, binaryImg, MeanThreshold(data), 255, CV_THRESH_BINARY);
cvNamedWindow("Mean");
cvShowImage("Mean", binaryImg);

参考文献

[1] Huang L.-K. and Wang M.-J.J. (1995) "Image Thresholding by Minimizing the Measures of Fuzziness" Pattern Recognition, 28(1): 41-51 M. Emre Celebi 06.15.2007.

[2] J. M. S. Prewitt and M. L. Mendelsohn, "The analysis of cell images," in Annals of the New York Academy of Sciences, vol. 128, pp. 1035-1053, 1966.

[3]C. A. Glasbey, "An analysis of histogram-based thresholding algorithms,"  CVGIP: Graphical Models and Image Processing, vol. 55, pp. 532-537, 1993.


《探讨OpenCV》专栏QQ群:195358461

关于Image Engineering & Computer Vision更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.