3

我的老师给了我们一个任务,让我们制作一个 640x480 bmp 彩色图像的课程,将其转换为灰度图像,我找到了一些有想法的来源,所以我做到了。但是有一个问题,因为它似乎导致它没有给我错误,但输出没有出现。我认为这是我的代码。我的代码是

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);
}
}
4

3 回答 3

1

除了@joni 提到的问题之外,还有一些问题。这个问题比最初看起来的要深一些。

BMP 文件格式

  • BMP 格式有一个标题。在进行图像转换之前,您应该跳过(或可能更新)标题。
  • 颜色表:您假设一个“直”调色板:颜色索引与 RGB 值相同。但这可能会有所不同......(顺便说一句:如果图片使用颜色表,那么你可以只改变它以获得灰度图像......)
  • 每个像素有多少位?您假设它是 8-8-8 分布中的每像素 24 位。这不是保证...标题提供此信息。
  • 压缩:是的,图像可能被压缩——你必须对其进行解码才能对像素值本身做任何事情。

环形

您为每个像素处理 3 个字节,并以 1 为增量循环遍历文件。通过 3D 眼镜观看生成的图像可能碰巧很有趣,但意味着出现了一些奇怪的图像。

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;
}

有符号字节

Java中的字节已签名。它从 -128 到 127,所以你的算术是无效的。对于每个字节,我将其用作 int,并在将它们与权重相加之前将其添加 128。然后求和后减去 128,然后转换为字节。

像素变换值范围

您总结了 saem 范围内的 3 个数字,并希望在该范围内获得一个数字。但是,您的权重并不能反映这一点:权重应该加起来为 1。对于初学者,我会为所有值使用 0.33(这不能提供完美的颜色权重,但在技术上应该有效)。

    //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
于 2013-09-11T14:48:52.197 回答
0

有很多东西在你的代码中不起作用。

  • 可用方法不一定返回文件中的字节数。您应该为从输入文件中读取的数据使用动态容器。
  • read 方法不会读取整个文件。您必须在循环中使用此方法,直到它返回不正确的值:

    while ((byte = fis.read()) != -1) { //对字节做一些事情 }

  • 您对文件的每个字节进行转换。我不知道这会适用于任何图片格式。有标题和填充,即使是最简单的 BMP 格式。您应该阅读您想要使用的格式,因为它不会像遍历整个流并计算每个 3 字节块的平均值那样简单。

于 2013-09-11T14:50:55.577 回答
0

这段代码有几个问题:

  1. available方法只告诉您有多少字节是立即可用的,而无需实际从磁盘读取。它很可能返回 0。
  2. read方法仅读取部分数据。返回值告诉您它实际读取了多少字节。
  3. 您不会关闭输出流。如果不关闭输出,则无法保证将任何内容写入输出文件。
于 2013-09-11T14:41:05.163 回答