图片二值化: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 }