在编写图像二值化、灰度化的时候无意间发现在方法中使用ImageIO.write输出图像时仍然执行给bufferedImage赋值时候的语句,下面贴上代码:
package test;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class test {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedImage bufferedImage = ImageIO.read(new File("D:/adt-bundle-windows-x86_64-20140321/workspace/test/img/test6.jpg"));
BufferedImage bufferedImage2=grayimage( bufferedImage);
BufferedImage bufferedImage3=erzh( bufferedImage);//这里改变了bufferedImage2值
ImageIO.write(bufferedImage, "jpg", new File("D:/adt-bundle-windows-x86_64-20140321/workspace/test/img/yuantu.jpg"));
ImageIO.write(bufferedImage2, "jpg", new File("D:/adt-bundle-windows-x86_64-20140321/workspace/test/img/huidutu.jpg"));
ImageIO.write(bufferedImage3, "jpg", new File("D:/adt-bundle-windows-x86_64-20140321/workspace/test/img/ezh.jpg"));
}
public static BufferedImage grayimage(BufferedImage bufferedImage){
int h = bufferedImage.getHeight();
int w = bufferedImage.getWidth();
//BufferedImage bufferedImage2 = new BufferedImage(w, h, BufferedImage. TYPE_3BYTE_BGR );
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
int argb = bufferedImage.getRGB(x, y);
int r = (argb >> 16) & 0xFF;
int g = (argb >> 8) & 0xFF;
int b = (argb >> 0) & 0xFF;
int grayPixel=(int)(r+g+b)/3;
//将各个颜色组合为rgb颜色值
int rgb = (grayPixel*256 + grayPixel)*256+grayPixel;
if(rgb>8388608) //rgb的最大值为8388608,因此当大于时候需要减去256*256*256
{
rgb = rgb - 16777216;
}
bufferedImage.setRGB(x, y, rgb);
//bufferedImage2.setRGB(x, y, rgb);
}
}
//return bufferedImage2;
return bufferedImage;
}
public static int[][] huidutujuzhen(BufferedImage bufferedImage)
{
//灰度化
bufferedImage=grayimage(bufferedImage);
int h = bufferedImage.getHeight();
int w = bufferedImage.getWidth();
//获取灰度矩阵
int[][]gray=new int[h][w];
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
int a = bufferedImage.getRGB(x, y);
gray[y][x]=a;
}
}
return gray;
}
public static BufferedImage erzh(BufferedImage bufferedImage){
int h = bufferedImage.getHeight();
int w = bufferedImage.getWidth();
int[][] gray = huidutujuzhen( bufferedImage);
// BufferedImage bufferedImage2 = new BufferedImage(w, h, BufferedImage. TYPE_3BYTE_BGR );
// 效果较好的二值化算法
int threshold = ostu(gray, w, h);
System.out.print(threshold);
// BufferedImage binaryBufferedImage = ImageIO.read(new File("D:/adt-bundle-windows-x86-20130219/workspace/wenzi/src/huiduhua.jpg"));
// BufferedImage binaryBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);//最后一个参数就是二值化TYPE_BYTE_GRAY、、TYPE_3BYTE_BGR
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
int gry=gray[y][x]&0xff;
if (gry > threshold)
{
gray[y][x]=0xFFFFFF;
}
else
{
gray[y][x]=0x000000;
}
bufferedImage.setRGB(x, y, gray[y][x] );
}
}
return bufferedImage;
}
//OTSU的中心思想是阈值T应使目标与背景两类的类间方差最大。取得合适二值化阀值的函数
public static int ostu(int[][] gray, int w, int h) {
int[] histData =new int[256];// new int[w * h];
// Calculate histogram
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int red = 0xFF & gray[y][x];
histData[red]++;
}
}
// Total number of pixels
int total = w * h;
float sum = 0; //总的灰度和,,,,,,可能有的灰度不存在histdata就越界了。
for (int t = 0; t < 256; t++)
sum += t * histData[t];
float sumB = 0;
int wB = 0;
int wF = 0;
float varMax = 0;
int threshold = 0;
for (int t = 0; t < 256; t++) {
wB += histData[t]; // Weight Background//histData[t]为灰度为t的像素点的 个数,wB为已循环到的像素点和
if (wB == 0)
continue;
wF = total - wB; // Weight Foreground wF剩余像素点
if (wF == 0)
break;
sumB += (float) (t * histData[t]);//灰度为t的的像素和
float mB = sumB / wB; // Mean Background 所循环到的灰度为t的和除以已经循环到的点的和
float mF = (sum - sumB) / wF; // Mean Foreground sum为所有灰度值的和
// Calculate Between Class Variance
float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);
// Check if new maximum found
if (varBetween > varMax) {
varMax = varBetween;
threshold = t;
}
}
return threshold;
}
}
会发现在输出图像的时候如果在灰度化后二值化改变bufferedImage的值,最后输出灰度图时候发现灰度图像也被二值化了,由此推断(不知是否正确,望大牛指点)在ImageIO.write输出图像时候仍然执行了一遍BufferedImage bufferedImage2=grayimage( bufferedImage);而此时的bufferedImage已经被二值化方法改变了,因此灰度图2会变成二值化图!