图片二值化:OSTU大津算法的一般JAVA实现

直接上代码:

  1 /**
  2      *  获取一张二值化图片
  3      * @param bufferImg
  4      * @return
  5      */
  6     public static BufferedImage binaryImage(BufferedImage bufferImg){
  7         int height = bufferImg.getHeight();
  8         int width = bufferImg.getWidth();
  9         int rgb = bufferImg.getRGB(0, 0);
 10         int rgbArray[][] = new int[width][height];
 11 
 12         for(int i=0;i<width;i++){
 13             for(int j=0;j<height;j++){
 14                 rgbArray[i][j] = getImageRgb(bufferImg.getRGB(i,j));
 15             }
 16         }
 17 
 18         int threshold = otsuThreshold(rgbArray, height, width);
 19 
 20         BufferedImage bufferedImage=new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);//  构造一个类型为预定义图像类型之一的 BufferedImage,TYPE_BYTE_BINARY(表示一个不透明的以字节打包的 1、2 或 4 位图像。)
 21 
 22         for(int i=0;i<width;i++){
 23             for(int j=0;j<height;j++){
 24                 if(rgbArray[i][j] > threshold){
 25                     int black=new Color(255,255,255).getRGB();
 26                     bufferedImage.setRGB(i, j, black);
 27                 }else{
 28                     int white=new Color(0,0,0).getRGB();
 29                     bufferedImage.setRGB(i, j, white);
 30                 }
 31             }
 32         }
 33 
 34         try {
 35             ImageIO.write(bufferedImage, "jpg", new File("D:"+File.separator+"new123.jpg"));
 36         } catch (IOException e) {
 37             e.printStackTrace();
 38         }
 39         return bufferedImage;
 40     }
 41 
 42     /**
 43      * 获取点的灰度值
 44      * @param i
 45      * @return
 46      */
 47     public static int getImageRgb(int i){
 48         String argb = Integer.toHexString(i); // 将十进制的颜色值转为十六进制
 49         // argb分别代表透明,红,绿,蓝 分别占16进制2位
 50         int r = (int)(Integer.parseInt(argb.substring(2, 4),16) * 1.1 + 30);//后面参数为使用进制
 51         int g = (int)(Integer.parseInt(argb.substring(4, 6),16) * 1.1 + 30);
 52         int b = (int)(Integer.parseInt(argb.substring(6, 8),16) * 1.1 + 30);
 53         if(r > 255){
 54             r = 255;
 55         }
 56         if(g > 255){
 57             g = 255;
 58         }
 59         if(b > 255){
 60             b = 255;
 61         }
 62         int result=(int) Math
 63                 .pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2)
 64                         * 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2);
 65 
 66         return result;
 67     }
 68 
 69     //自己加周围8个灰度值再除以9,算出其相对灰度值
 70      public static int  getGray(int gray[][], int x, int y, int w, int h)
 71      {
 72          int rs = gray[x][y] + (x == 0 ? 255 : gray[x - 1][y])
 73                  + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1])
 74                  + (x == 0 || y == h - 1 ? 255 : gray[x - 1][y + 1])
 75                  + (y == 0 ? 255 : gray[x][y - 1])
 76                  + (y == h - 1 ? 255 : gray[x][y + 1])
 77                  + (x == w - 1 ? 255 : gray[x + 1][ y])
 78                  + (x == w - 1 || y == 0 ? 255 : gray[x + 1][y - 1])
 79                  + (x == w - 1 || y == h - 1 ? 255 : gray[x + 1][y + 1]);
 80          return rs / 9;
 81      }
 82 
 83     /**
 84      * 通过OTSU大津算法计算分割阈值
 85      * @param rgbArray
 86      * @return
 87      */
 88     public static int otsuThreshold(int rgbArray[][], int height, int width){
 89         final int GrayScale = 256;
 90         // 每个灰度像素的数量
 91         int []pixelCount = new int[GrayScale];
 92         // 每个像素点所占的比例
 93         float []pixelPro = new float[GrayScale];
 94         // 像素点的数量
 95         int pixelSum = height * width;
 96         // 分割的阈值点
 97         int threshold = 0;
 98 
 99         //=========================统计灰度级中每个像素在整幅图像中的个数===============
100         for(int i=0;i<width;i++){
101             for (int j=0;j<height;j++){
102                 pixelCount[rgbArray[i][j]] ++;
103             }
104         }
105 
106         // ========================计算每个像素在整幅图像中的比例=========================
107         float maxPro; //
108         int kk = 0;
109         for(int i=0;i<GrayScale;i++){
110             pixelPro[i] = (float)pixelCount[i] / pixelSum;
111         }
112 
113         // ===========================遍历灰度级[0,255]======================================
114         // backgroundRatio为背景像素点占整幅图像的比例
115         // prospectRatio为前景像素点占整幅图像的比例
116         // backGrayAverage为背景像素的平均灰度
117         // proGrayAverage为前景像素的平均灰度
118         // grayAverage为整幅图像的平均灰度
119         // 公式:g = backgroundRatio * pow((backGrayAverage - grayAverage), 2) + prospectRatio * pow((proGrayAverage - grayAverage), 2)
120         // deltaTmp,deltaMax记录中间值与结果最大值
121         float  backgroundRatio, prospectRatio, u0tmp, u1tmp, backGrayAverage, proGrayAverage, grayAverage;
122         double deltaTmp, deltaMax = 0;
123         for (int i = 0; i < GrayScale; i++)     // i作为阈值
124         {
125             // 初始化
126             backgroundRatio = prospectRatio = u0tmp = u1tmp = backGrayAverage = proGrayAverage = grayAverage  = 0;
127             deltaTmp = 0;
128             for (int j = 0; j < GrayScale; j++)
129             {
130                 if (j <= i)   //背景部分
131                 {
132                     backgroundRatio += pixelPro[j];
133                     u0tmp += j * pixelPro[j]; // u0tmp=像素的灰度*像素占的比例
134                 }
135                 else   //前景部分
136                 {
137                     prospectRatio += pixelPro[j];
138                     u1tmp += j * pixelPro[j];
139                 }
140             }
141             backGrayAverage = u0tmp / backgroundRatio;
142             proGrayAverage = u1tmp / prospectRatio;
143             grayAverage = u0tmp + u1tmp;
144             deltaTmp = backgroundRatio * pow((backGrayAverage - grayAverage), 2) + prospectRatio * pow((proGrayAverage - grayAverage), 2);
145             if (deltaTmp > deltaMax)
146             {
147                 deltaMax = deltaTmp;
148                 threshold = i;
149             }
150         }
151 
152         return threshold;
153     }

 

posted @ 2020-06-03 19:22  口古口古又鸟  阅读(614)  评论(0编辑  收藏  举报