宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 2721|回复: 0

[推荐] 类别差分门限法(OTSU法)图像二值化阀值选取

[复制链接]
  • TA的每日心情
    开心
    2024-12-9 18:45
  • 签到天数: 124 天

    [LV.7]常住居民III

    admin 发表于 2010-9-28 22:07:41 | 显示全部楼层 |阅读模式

    欢迎您注册加入!这里有您将更精采!

    您需要 登录 才可以下载或查看,没有账号?注册

    x
    OTSU法由大津于1979年提出,对图像Image,记t为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。图像的总平均灰度为:u=w0*u0+w1*u1。从最小灰度值到最大灰度值遍历t,当t使得值g=w0*(u0-u)2+w1*(u1-u)2 最大时t即为分割的最佳阈值。对大津法可作如下理解:该式实际上就是类间方差值,阈值t分割出的前景和背景两部分构成了整幅图像,而前景取值u0,概率为 w0,背景取值u1,概率为w1,总均值为u,根据方差的定义即得该式。因方差是灰度分布均匀性的一种度量,方差值越大,说明构成图像的两部分差别越大, 当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。

    直接应用OTSU法计算量较大,因此我们在实现时采用了等价的公式g=w0*w1*(u0-u1)2。部分计算过程如下:



    //遍历所有灰度值求Max g。

    for intCurrentLevel:=0 to intArrLen do

      begin

        if intSclGrayLevel[intCurrentLevel]=0 then

          continue

        else

          begin

                  //计算当阈值为intCurrentLevel时的g

            intCount:=0;

            intSumPels:=0;

            for intLoop:=0 to intCurrentLevel do

              begin

                intCount:=intCount+intSclGrayLevel[intLoop];

                intSumPels:=intSumPels+intSumPelsArr[intLoop];

              end;

            w0:=intCount/intSize;

            u0:=intSumPels/intCount;

            w1:=1-w0;

            if intSize-intCount<>0 then

              u1:=(intTotalPels-intSumPels)/(intSize-intCount)

            else

              u1:=0;



            RlTempO:=w0*w1*(u0-u1)*(u0-u1);

            if RlTempO>RlMaxO then

            begin

              RlMaxO:=RlTempO;

              Result:=intCurrentLevel;

            end;

          end;

    我们在测试中发现:大津法选取出来的阈值非常理想,对各种情况的表现都较为良好。虽然它在很多情况下都不是最佳的分割,但分割质量通常都有一定的保障,可以说是最稳定的分割。由上可知,大津算法是一种较为通用的分割算法。在它的思想的启迪下,人们进一步提出了多种类似的评估阈值的算法,具体可参加【5】、【6】等。

    OTSU的算法,很好用,好不容易才找到的。
    /*
    OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。

    算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。划分点就是求得的阈值。

    parameter: *image --- buffer for image
    rows, cols --- size of image
    vvv --- debug option, is 0, no debug information outputed
    */
    /*======================================================================*/
    /* OTSU global thresholding routine */
    /* takes a 2D unsigned char array pointer, number of rows, and */
    /* number of cols in the array. returns the value of the threshold */
    /*======================================================================*/
    int FunMain::OTSU(unsigned char *image, int rows, int cols,  int vvv)
    {
    //unsigned char *nps; // 图像指针
    int nps=0;
    int thresholdValue=1; // 阈值
    int ihist[256]; // 图像直方图,256个点

    int i, j, k; // various counters
    int n, n1, n2, gmin, gmax;
    double m1, m2, sum, csum, fmax, sb;

    // 对直方图置零...
    //memset(ihist, 0, sizeof(ihist));
    for (i = 0; i <256; i++)
      ihist[i]=0;

    gmin=255; gmax=0;
    // 生成直方图
    for (i =0; i < rows; i++)
    {
      for (j = 0; j < cols; j++)
      {  
       nps =(int) image[i*cols+j];
       ihist[nps]++;
       if(nps > gmax) gmax=nps;
       if(nps < gmin) gmin=nps;
       // *nps++; /* next pixel */
      }
    }

    // set up everything
    sum = csum = 0.0;
    n = 0;

    for (k = 0; k <= 255; k++) {
      sum += (double) k * (double) ihist[k]; /* x*f(x) 质量矩*/
      n += ihist[k]; /* f(x) 质量 */
    }

    if (!n) {
      // if n has no value, there is problems...
      fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
      return (160);
    }

    // do the otsu global thresholding method
    fmax = -1.0;
    n1 = 0;
    for (k = 0; k < 255; k++) {
      n1 += ihist[k];
      if (!n1) { continue; }
      n2 = n - n1;
      if (n2 == 0) { break; }
      csum += (double) k *ihist[k];
      m1 = csum / n1;
      m2 = (sum - csum) / n2;
      sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
      /* bbg: note: can be optimized. */
      if (sb > fmax) {
       fmax = sb;
       thresholdValue = k;
      }
    }

    // at this point we have our thresholding value

    // debug code to display thresholding values
    if ( vvv & 1 )
      fprintf(stderr,"# OTSU: thresholdValue = %d gmin=%d gmax=%d\n",
      thresholdValue, gmin, gmax);

    return(thresholdValue);
    }
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    免责声明

    本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

    QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

    Copyright © 2001-2023 Discuz! Team. GMT+8, 2024-12-22 22:56 , File On Powered by Discuz! X3.49

    快速回复 返回顶部 返回列表