图像处理第二步:二值化

来源:互联网 发布:java线程创建方式 编辑:程序博客网 时间:2024/05/27 09:48

图像处理第二步:二值化

第一种分类:(局部与整体)

1、全局二值化

设定一个全局的阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。将大于T的像素群的像素值设定为白色(或者黑色),小于T的像素群的像素值设定为黑色(或者白色)。

2、局部自适应二值化

局部二值化的方法就是按照一定的规则将整幅图像划分为N个窗口,对这N个窗口中的每一个窗口再按照一个统一的阈值T将该窗口内的像素划分为两部分,进行二值化处理。

第二种分类:(按照阈值选取方法不同来分类)

1、固定阈值

直接设定一个阈值,阈值的选取或者根据所处理问题的实际情况,或者毫不讲理心血来潮随便设定一个中间值,这种算法意义不大。

2、自适应阈值

1)、以图像的平均灰度值作为阈值。

使用平均值作为二值化阈值同样有个致命的缺点,可能导致部分对象像素或者背景像素丢失。二值化结果不能真实反映源图像信息。

2)、使用直方图方法来寻找二值化阈值。

直方图方法选择二值化阈值主要是发现图像的两个最高的峰,然后在阈值取值在两个峰之间的峰谷最低处。该方法相对前面两种方法而言稍微精准一点点。结果也更让人可以接受。

3)、使用近似一维Means方法寻找二值化阈值

该方法的大致步骤如下:

1.      一个初始化阈值T,可以自己设置或者根据随机方法生成。

2.      根据阈值图每个像素数据P(n,m)分为对象像素数据G1与背景像素数据G2。(n为行,m为列)

3.      G1的平均值是m1, G2的平均值是m2

4.      一个新的阈值T’ = (m1 + m2)/2

5.      回到第二步,用新的阈值继续分像素数据为对象与北京像素数据,继续2~4步,

package com.gloomyfish.filter.study;    import java.awt.image.BufferedImage;  import java.util.ArrayList;  import java.util.List;    public class ThresholdBinaryFilter extends GrayFilter {        @Override      public BufferedImage filter(BufferedImage src, BufferedImage dest) {          int width = src.getWidth();          int height = src.getHeight();            if ( dest == null )              dest = createCompatibleDestImage( src, null );            int[] inPixels = new int[width*height];          int[] outPixels = new int[width*height];          src = super.filter(src, null); // we need to create new one          getRGB( src, 0, 0, width, height, inPixels );          int index = 0;          int means = getThreshold(inPixels, height, width);          for(int row=0; row<height; row++) {              int ta = 0, tr = 0, tg = 0, tb = 0;              for(int col=0; col<width; col++) {                  index = row * width + col;                  ta = (inPixels[index] >> 24) & 0xff;                  tr = (inPixels[index] >> 16) & 0xff;                  tg = (inPixels[index] >> 8) & 0xff;                  tb = inPixels[index] & 0xff;                  if(tr > means) {                      tr = tg = tb = 255; //white                  } else {                      tr = tg = tb = 0; // black                  }                  outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;              }          }          setRGB( dest, 0, 0, width, height, outPixels );          return dest;      }        private int getThreshold(int[] inPixels, int height, int width) {          // maybe this value can reduce the calculation consume;           int inithreshold = 127;          int finalthreshold = 0;          int temp[] = new int[inPixels.length];          for(int index=0; index<inPixels.length; index++) {              temp[index] = (inPixels[index] >> 16) & 0xff;          }          List<Integer> sub1 = new ArrayList<Integer>();          List<Integer> sub2 = new ArrayList<Integer>();          int means1 = 0, means2 = 0;          while(finalthreshold != inithreshold) {              finalthreshold = inithreshold;              for(int i=0; i<temp.length; i++) {                  if(temp[i] <= inithreshold) {                      sub1.add(temp[i]);                  } else {                      sub2.add(temp[i]);                  }              }              means1 = getMeans(sub1);              means2 = getMeans(sub2);              sub1.clear();              sub2.clear();              inithreshold = (means1 + means2) / 2;          }          long start = System.currentTimeMillis();          System.out.println("Final threshold  = " + finalthreshold);          long endTime = System.currentTimeMillis() - start;          System.out.println("Time consumes : " + endTime);          return finalthreshold;      }        private static int getMeans(List<Integer> data) {          int result = 0;          int size = data.size();          for(Integer i : data) {              result += i;          }          return (result/size);      }    }  

4)、OTSU算法

OTSU的中心思想是阈值T应使目标与背景两类的类间方差最大。

int Threshold(int *hist) //compute the threshold{float u0, u1;float w0, w1;int count0;int t, maxT;float devi, maxDevi = 0; //方差及最大方差int i;int sum = 0;for (i = 0; i < 256; i++){sum = sum + hist[i];}for (t = 0; t < 255; t++){u0 = 0; count0 = 0;//阈值为t时,c0组的均值及产生的概率for (i = 0; i <= t; i++){u0 += i * hist[i]; count0 += hist[i];}u0 = u0 / count0; w0 = (float)count0/sum;//阈值为t时,c1组的均值及产生的概率u1 = 0;for (i = t + 1; i < 256; i++){u1 += i * hist[i];}u1 = u1 / (sum - count0); w1 = 1 - w0;//两类间方差devi = w0 * w1 * (u1 - u0) * (u1 - u0);//记录最大的方差及最佳位置if (devi > maxDevi){maxDevi = devi;maxT = t;}}return maxT;}//二值化处理void OTSU(IplImage *src, IplImage *dst){int i = 0, j = 0;int wide = src->widthStep;int high = src->height;int hist[256] = {0};int t;unsigned char *p, *q;for (j = 0; j < high; j ++){p = (unsigned char *)(src->imageData + j * wide);for (i = 0; i < wide; i++){hist[p[i]]++; //统计直方图}}t = Threshold(hist);for (j = 0; j < high; j ++){q = (unsigned char *)(dst->imageData + j * wide);p = (unsigned char *)(src->imageData + j * wide);for (i = 0; i < wide; i++){q[i] = p[i] >= t ? 255 : 0;}}}
5)、Kittle算法

一种快速的全局阈值法。它的效果不比OTSU差多少,但速度快好多倍,如果可以应用在图像质量不错的环境。它的中心思想是,计算整幅图像的梯度灰度的平均值,以此平均值做为阈值。
//kittler算法for (i=1;i<high-1;i++){plineadd=src->imageData+i*wide;pNextLine=src->imageData+(i+1)*wide;pPreLine=src->imageData+(i-1)*wide;for(j=1;j<wide-1;j++){//求水平或垂直方向的最大梯度Grads=MAX(abs((uchar)pPreLine[j]-(uchar)pNextLine[j]),abs((uchar)plineadd[j-1]-(uchar)plineadd[j+1])); //max(xGrads,yGrads)sumGrads += Grads;//梯度与当前点灰度的积sumGrayGrads += Grads*((uchar)plineadd[j]);}}threshold=sumGrayGrads/sumGrads;// printf("%d\n",threshold);for(i=0;i<high;i++){plineadd=src->imageData+i*wide;pTempLine=kittler->imageData+i*wide;for(j=0;j<wide;j++){pTempLine[j]=(uchar)plineadd[j]>threshold?255:0;[3]}}





0 0