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

引言

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

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

算法代码

第一种方法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.

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

时间: 2024-10-12 08:03:39

基于直方图的图像二值化算法实现的相关文章

图像处理之积分图应用四(基于局部均值的图像二值化算法)

图像处理之积分图应用四(基于局部均值的图像二值化算法) 基本原理 均值法,选择的阈值是局部范围内像素的灰度均值(gray mean),该方法的一个变种是用常量C减去均值Mean,然后根据均值实现如下操作: pixel = (pixel > (mean - c)) ? object : background 其中默认情况下参数C取值为0.object表示前景像素,background表示背景像素. 实现步骤 1. 彩色图像转灰度图像 2. 获取灰度图像的像素数据,预计算积分图 3. 根据输入的参数

十三种基于直方图的图像全局二值化算法原理、实现、代码及效果(转)

十三种基于直方图的图像全局二值化算法原理.实现.代码及效果(转) http://www.cnblogs.com/carekee/articles/3643394.html 图像二值化的目的是最大限度的将图象中感兴趣的部分保留下来,在很多情况下,也是进行图像分析.特征提取与模式识别之前的必要的图像预处理过程.这个看似简单的问题,在过去的四十年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法,但如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果. 在这些庞大的分

图像基本变换---图像二值化(包含OSTU/迭代法/统计法/双峰法/P分位法/最大熵法)

OSTU法图像二值化 [算法说明] Ostu法又叫做最大类间方差法,是一种常用的图像分割算法.基本算法思想是根据初始阈值把图像分为两类,然后计算两类之间的方差,更新阈值,重新计算类间方差,当满足类间方差最大时的阈值,即为所求最佳阈值,具体过程如下: 1,初始化一阈值Th,将图像f(x,y)分为A,B两类: 2,分别计算A,B两类像素集合的均值ua和ub,公式如下: 其中,Na和Nb分别表示集合A,B中的像素个数. 3,计算A,B两类的类间方差,公式如下: 4,将Th从0到255循环,分别计算A,

图像二值化处理Java

二值化基本概念:通俗的讲就是把一副彩色图像处理成一副黑白图像,一般是作为后续复杂图像处理操作的预处理. 二值化算法思路:遍历图像的所有像素点,计算每个像素点的灰度值.通过迭代法收敛得到一个最佳阈值,灰度值大于最佳阈值的像素点设为白色,灰度值小于最佳阈值的像素点设为黑色.(我这里的二值化处理结果是,背景是白色,前景是黑色) 迭代法获取最佳阈值思路: 1.设最小灰度值为Gmin,最大灰度值为Gmax,阈值初始化为T(0)=(Gmin+Gmax)/2. 2.以阈值T(k)将图像分割为前景和背景,求出整

记录一个优秀的图像二值化代码

#region 二值化02 public Bitmap binaryzation(Bitmap srcBitmap, Bitmap dstBitmap) { int threshold = 0; Byte[,] BinaryArray = ToBinaryArray(srcBitmap, out threshold); dstBitmap = BinaryArrayToBinaryBitmap(BinaryArray); return dstBitmap; } /// <summary> //

一种超级快速的图像二值化技术

在计算机视觉中,对图像进行二值化恐怕是最常见的操作了.为了检测目标,可能需要对每一帧图像的每一个像素点进行运算.如果能提升二值化的速度,那么,你的算法的效率就会大大的提高.本文,将介绍一种超级快速的图像二值化技术. 要解决的问题: 如上图所示,需要把彩色图像中, (1) R通道介于(smoevalue1, somevalue2)(2) G通道介于(somevalue3, somevalue4)(3) B通道介于(somevalue5, somevalue6)当图像中某个像素点同时满足上面3个条件

C# 指针操作图像 二值化处理

/// <summary> /// 二值化图像 /// </summary> /// <param name="bmp"></param> /// <returns></returns> private static unsafe Bitmap Binaryzation(Bitmap bmp) { BitmapData dstData = bmp.LockBits(new Rectangle(0, 0, bmp.W

数学之路-python计算实战(8)-机器视觉-图像二值化

二值化 hreshold Applies a fixed-level threshold to each array element. C++: double threshold(InputArray src, OutputArray dst, double thresh, doublemaxval, int type) Python: cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dst C: double cvThresh

opencv2对读书笔记——图像二值化——thresholded函数

opencv中的图像二值化函数threshold函数 其结构 double cv::threshold( //二值化函数 const CvArr* src, //原始图像 CvArr* dst, //输出图像 double threshold, //阈值 double max_value, //最大值 int threshold_type//阈值类型 ); 实例代码 #include "cv.h" #include "highgui.h" int main() {