java图像字节数组到灰度回到图像

时间:2016-12-09 00:16:54

标签: arrays image-processing

我正在尝试对图像处理进行编码,因此我创建了一个方法,该方法接收BufferedImage并将其转换为字节数组(方法名称convertToByteArray(BufferedImage inImg))。

然后我从每个像素的字节中获取ARGB或RGB值(每个像素为8位,使用按位变换)。然后将ARGB或RGB的int值追加回字节数组(方法名convertToGrayscale(byte[] inImg))。

然后将字节数组提供给转换回图像的方法(方法名称convertToBufferedImage(byte[] inImg))。

出于某种原因,当我将BufferedImage传递给方法以将其转换为字节数组时,然后无需更改,将字节数组传递给方法以转换回BufferedImage它工作

这是我遇到问题的地方。当我将BufferedImage传递给方法转换为字节数组时,然后将方法更改为灰度,并在同一方法中将灰度int值更改为字节数组。这是问题所在,当我将改变后的字节数组传递给方法转换回BufferedImage时...结果是" img为空"请帮忙,要么我的转换错了,要么我不知道哪里或哪里出错了。

public byte[] convertToByteArray(BufferedImage inImg) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        ImageIO.write(inImg, "jpg", baos);
    } catch (IOException e) {
        e.printStackTrace();
    }
    outImgByte = baos.toByteArray();

    System.out.println("img to byte array length: " + outImgByte.length);
    System.out.println("convert to byte array complete...");
    return outImgByte;
}

public BufferedImage convertToBufferedImage(byte[] inImg) {
    try {
        outImg = ImageIO.read(new ByteArrayInputStream(inImg));
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("convert byte array to image complete...");
    return outImg;
}

public void convertToGrayscale(byte[] inImg) {
    int r, g, b;
    int grayscale;
    // for loop to change each byte value into gray scale
    for(int i = 0; i < inImg.length; i++) {
        // first must get the value of RGB out from byte 
        // array and get the average
        r = (inImg[i] >> 16) & 0xff;
        g = (inImg[i] >> 8) & 0xff;
        b = (inImg[i]) & 0xff;

        grayscale = (r + g + b) / 3;

        outImgByte[i] = (byte) (grayscale << 16 | grayscale << 8 |   grayscale);
    }
    System.out.println("byte to grayscale byte array length: " + outImgByte.length);
    System.out.println("convert to grayscale from byte array complete...");
}

控制台输出:

Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(Unknown Source)
at javax.imageio.ImageIO.getWriter(Unknown Source)
at javax.imageio.ImageIO.write(Unknown Source)
at Main.main(Main.java:50)

2 个答案:

答案 0 :(得分:0)

BufferedImage后面,有一个数组,很可能是一个字节数组(有时是短数组)。因此,如果您的BufferedImage类型为TYPE_BYTE_GRAYTYPE_3BYTE_BGRTYPE_4BYTE_ABGR,那么您可以使用此DataBuffer直接访问byte[] databuffer = ((DataBufferByte)image.getRaster().getDataBuffer()).getData() ;。它可以直接访问像素值。但是,执行此操作时,您必须自行管理图像编码,因此如果BufferedImage的类型为TYPE_USHORT_GRAY,则无法执行此操作。

如果您想要更简单的方法(但速度较慢)来访问像素值,请使用光栅:

BufferedImage image = ...
for (int y=0 ; y < image.getHeight() ; y++)
    for (int x=0 ; x < image.getWidth() ; x++)
        for (int c=0 ; c < image.getRaster().getNumBands() ; c++)
            final int value = image.getRaster().getSample(x, y, c) ; // Returns the value of the channel C of the pixel (x,y)

因此,使用getSamplesetSample,您无需管理图片编码即可访问和修改像素值,但速度比直接访问{{1}要慢}。

此外,DataBuffer几乎从未使用BufferedImage(或其他TYPE_INT_RGB编码)编码,这意味着当您使用INT访问像素值时,您会问要将像素值转换为getRGB的图像,然后您必须再次分解该值。所以你做了两次转换。通常,必须禁止方法INT。它比使用Raster慢得多。

[编辑] 对于类型为getRGB的图片,您可以使用TYPE_BYTE_GBR访问像素值。注意,它可以直接访问像素,因此如果将值修改为此数组,则会修改像素。对于byte[] databuffer = ((DataBufferByte)image.getRaster().getDataBuffer()).getData()像素的图像,编码为[b1, g1, r1, b2, g2, r2, ... bN, gN, rN]:所以(b,g,r)三元组。

您的方法N变为:

convertToByteArray

[编辑2]

public byte[] copyIntoByteArray(BufferedImage inImg)
    {
    byte[] result = null ;
    switch ( inImg.getType() )
        {
        case BufferedImage.TYPE_3BYTE_BGR:
            byte[] databuffer = ((DataBufferByte) inImg.getRaster().getDataBuffer()).getData() ;
            result = new byte[databuffer.length] ;
            System.arraycopy(databuffer, result, databuffer.length) ;
            break ;
        // Other encodings
        default: throw new IllegalArgumentException("Not supported.") ;
        }

    System.out.print("img to byte array length: " + databuffer.length) ;
    System.out.println(", convert to byte array complete...") ;
    return result ;
    }

答案 1 :(得分:0)

函数ByteArrayToBufferedImage可以正常使用。
但是,这是我对功能稍作更改的地方

    public BufferedImage ByteArrayToBufferedImage(byte[] src, final int width, final int height) {
        //create empty bufferedImage
        BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
        //remove System.arraycopy (fill empty image with input byte array)
        result.getRaster().setDataElements(0, 0, width, height, src);
        return result;
    }

我没有理由使用result.getRaster().setDataElements而不是System.arraycopy
如果有人知道不同,请比较这两种方法。谢谢