问题
My teacher gave us a task to make a class that takes an 640x480 bmp colored image, to convert it in grayscale image, I found some sources with ideas so i did it. But there's a problem because it seems that it makes it cause it doesn't give me error, but the output doesn't appear. I think it's my code. My code is
import java.io.*;
public class Grayscale{
FileInputStream image;
FileOutputStream img;
byte[] datos;
int gray;
public Grayscale(String nombre)throws Exception{
this.image = new FileInputStream(nombre);
this.img = img;
this.datos = new byte[image.available()];
this.gray = gray;
}
public void gray()throws Exception{
image.read(datos);
img = new FileOutputStream("grayscaleprueba.bmp");
for (int i = 0; i<datos.length; i++){
gray = (byte)(datos[i]*0.3 + datos[i+1]*0.59 + datos[i+2]);
datos[i] = (byte)gray;
datos[i+1] = (byte)gray;
datos[i+2] = (byte)gray;
}
img.write(datos);
}
}
回答1:
There are some problems apart from those that @joni mentioned. This problem is a bit deeper than what it first seems to be.
BMP file format
- The BMP format has a header. You should skip (or probably update) the header before doing the image transformation.
- color table: you assume a "straight" palette: the color index the same as the RGB value. But this might be different... (BTW: If the picture uses a color table, then you could alter only that to get a grayscale image however...)
- how many bits per pixel are there? You assumed that it is 24 bits per pixel, in a 8-8-8 distribution. This is not guarranteed... The header provides this info.
- compression: yep, the image might be compressed - you'd have to decode it to do anything with the pixel values themselves.
Loop
You deal with 3 bytes for each pixel, and you loop through the file in the increments of 1. The resulting image might happen to be quite interesting to watch through 3D glasses, but will mean some strange image appearing.
for (int i = 0; i<datos.length; i+=3){ // increment by 3 instead of 1
gray = (byte)(datos[i]*0.3 + datos[i+1]*0.59 + datos[i+2]);
datos[i] = (byte)gray;
datos[i+1] = (byte)gray;
datos[i+2] = (byte)gray;
}
Signed byte
Byte in Java is signed. It goes from -128 to 127, so your arithmetic is not valid. For each byte, I'd use it as an int, and add 128 to it before summing them with weights. Then after summing, subtract the 128, and then cast to byte.
Pixel transformation values range
You sum up 3 numbers in the saem range, and would want to get a number in the range itself. However, your weights don't reflect this: the weights should add up to 1. For starters, I'd use 0.33 for all values (that does not give perfect color weights,but should technically works).
//using double to have some precision
double temp = datos[i]/3.0d + datos[i+1]/3.0d + datos[i]/3.0d;
gray = (byte)(Math.round(temp)-128); //rounding to Long, and converting to byt value range
回答2:
There are a few problems with this code:
- The
available
method only tells you how many bytes are immediately available, without actually having to read from disk. It may well return 0. - The
read
method reads only a part of the data. The return value tells you how many bytes it actually read. - You don't close the output stream. Without closing the output there is no guarantee that anything at all is written to the output file.
回答3:
There are a lot of things that won't work in your code.
- The available method does not necessarily returns the number of bytes in a file. You should use a dynamic container for the data you read from the input file.
The read method doesn't read the entire file. You have to use this method in a loop until it returns an incorrect value:
while ((byte = fis.read()) != -1) { //do something with byte }
You make your conversion over every byte of the file. I don't know of any picture format where this would work. There are headers and padding, even in the most simple BMP format. You should read about the format you want to use because it won't be as simple as iterating over the whole stream and make the average of every block of 3 bytes.
来源:https://stackoverflow.com/questions/18744123/rgb-to-grayscale-bmp-image-in-java