如何将BMP图像转换为8位灰度

时间:2016-09-09 07:16:52

标签: java image bmp grayscale

我必须制作一个程序,读取24位BMP图像(没有ImageIO或任何外部库),并使其成为8位灰度BMP图像......我读到我必须更改图像的标题才能使其成为可能一个8位,Source 1Source 2。所以我读到here BitCount字节位于Header的29和30并尝试更改它们......

首先,我读取了我的文件并生成了像这样的字节向量

FileInputStream image= new FileInputStream(path);
byte[] bytesImage = new byte[image.available()];
image.read(bytesImage);
image.close();

然后我得到图像标题并将其复制到新的矢量

int width = byteToInt(bytesImage[18], bytesImage[19], bytesImage[20], bytesImage[21]);
int height = byteToInt(bytesImage[22], bytesImage[23], bytesImage[24], bytesImage[25]);
int header = byteToInt(bytesImage[14], bytesImage[15], bytesImage[16], bytesImage[17]) + 14; // Add 14 for the header
vecGrey = Arrays.copyOf(bytesImage, bytesImage.length);

然后我更改头信息字节,使其成为8位BMP,如下所示:

byte[] values = intToByte(8);
vecGrey[28] = values[0];    // This is the index for the BitCount byte 1
vecGrey[29] = values[1];    // and this one is the index for the second one.

好了,现在出现了问题,出于某些原因,如果我尝试使用不同的标题编写vecGrey,我无法在vecGrey中写一个文件:

FileOutputStream aGrey = new FileOutputStream(name+ "-gray.bmp");
aGrey.write(vecGrey);
aGrey.close();
// This is a method that displays the resulting image in a frame...
makeInterface(name + "-gray.bmp");

我知道我必须更改vecGrey中的值,但这应该显示不正确的输出(可能是非灰度图像或根本不是图像)。但是当我尝试读取我在makeInterface()方法中生成的文件时,我得到了一个

  

javax.imageio.iioexception无法读取图片标题

所以我认为该程序无法正确读取标题,但我不知道为什么!如果我将BitCount值更改为16,它仍然可以工作,但是对于1,4或8它不会处理相同的错误...我没有上传我的漏洞代码,因为它已经在西班牙语,但如果需要,我可以翻译并在这里编辑。

谢谢!

EDIT1:我只使用640x480 24位BMP图像,所以我不需要检查填充。

2 个答案:

答案 0 :(得分:4)

当将BMP从24位更改为8位时,您必须更改标题中的其他几项内容,首先图像的大小会发生变化(字节3-6),因为您正在处理8位图像时有一个每个像素的字节,因此新的大小应该变为

headerSize {通常为54} +(numberOfColors * 4) {这是用于颜色表/调色板,我建议将其设置为256} + width * height < em> {实际像素数量}

接下来,您必须指明像素数据的偏移位置,它位于颜色表/托盘之后,此值位于字节11-14中,新值应为:

headerSize + numberOfColors * 4

接下来你需要修改从字节15开始的BITMAPINFOHEADER,字节15-18应该包含第二个标题的大小,通常为40,如果你只想转换为灰度,你可以忽略并保留一些字节不加修改,直到你到达字节29和30,你修改了bitCount(就像你已经做过的那样),然后在字节35-38中,据我所知你必须输入我们已经计算过的新图像大小,字节47-50决定了你的调色板中的颜色,因为你正在做灰度我建议使用256色,我会稍微解释一下原因。字节51-54包含重要颜色的数量,将其设置为0表示每种颜色都很重要。

接下来,您需要在heeader旁边添加颜色表/调色板。我推荐256种颜色的原因是因为彩色调色板是这样写的:[B,G,R,0]其中BGR是RGB格式的蓝色,绿色和红色值,最后是常数0,有256种颜色你可以制作一个写RGB值的调色板是R = G = B,它应该产生灰色阴影。因此,在标题旁边,您必须按升序添加这一新的字节序列:

[0,0,0,0] [1,1,1,0] [2,2,2,0] [3,3,3,0] ... [255,255,255,0]

请注意,256是numberOfColors,您需要计算图像的新大小,因为它是彩色调色板中“条目”的数量。

接下来,您需要在表格/调色板后面写下新的像素数据。由于您获得了24位图像,因此您可以提取像素矩阵并获取每个像素的RGB值,只需记住您有一个字节数组,其值为-128到127,您需要确保获得int值,所以如果任何通道的强度是&lt; 0然后将256添加到它以获取int值,然后您可以应用一个给出灰度强度的等式:

Y'= 0.299R'+ 0.587G'+ 0.114B' 其中Y'是灰色的强度,R G B是红色,绿色和蓝色的强度。

您可以对等式的结果进行舍入,然后将其作为字节写入imange,并对原始图像中的每个像素执行相同的操作。

完成后,只需在文件末尾添加两个保留的0,你就应该有一个24位图像的全新8位灰度图像。

希望这会有所帮助。

来源:您提供的那个: https://en.wikipedia.org/wiki/BMP_file_format https://en.wikipedia.org/wiki/Grayscale

答案 1 :(得分:0)

你应该首先看到24位BMP和灰度BMP的十六进制格式,那么你应该逐步进行, - 读取24位bmp标头 偏移后的读取数据。 - 写入8位灰度图像的标题 - 将数据写入8位灰度图像。 注意:你必须通过添加rgb位将rgb位转换为8位灰度,并将它们除以3。