【问题标题】:How to convert PNG image to grayscale using java?如何使用java将PNG图像转换为灰度?
【发布时间】:2017-12-08 17:15:43
【问题描述】:

我在将我的 PNG 图像更改为灰度时遇到了问题。我想创建一个方法,它可以接受 byte[] 图像作为参数,并将新修改的灰度图像作为 byte[] 返回。

我发现了一些使用下面的 sn-p 使图像与 JPEG 图像灰度化的链接。

private byte[] makeItGray(byte[] img, String contentType) throws IOException, Exception{


    InputStream in = new ByteArrayInputStream(img);
    BufferedImage bimg = ImageIO.read(in);

    for(int y=0; y < bimg.getHeight(); y++){
        for(int x=0; x < bimg.getWidth(); x++){
            Color color = new Color(bimg.getRGB(x,y));
            int graylevel = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
            int r = graylevel;
            int g = graylevel;
            int b = graylevel;
            int rgb = ( r<<16 ) | ( g<<8 ) | b;
            bimg.setRGB(x, y, rgb);
        }
    }

    in.close();


    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    if(contentType.equals(MediaType.IMAGE_PNG_VALUE)){
        ImageIO.write(bimg, "png", baos);
        System.out.println("PNG!!!");
    }
    else if(contentType.equals(MediaType.IMAGE_JPEG_VALUE)){
        ImageIO.write(bimg, "jpg", baos);
    }
    else
        throw new Exception();



    baos.flush();
    byte[] grayImage = baos.toByteArray();
    baos.close();

    return grayImage;
}

我的参考资料如下: How can I use ImageJ as a library for a separate Java application? https://www.mkyong.com/java/how-to-convert-byte-to-bufferedimage-in-java/

它适用于 JPEG 图像,但适用于 PNG,它会向我发送透明图像。

// converting orig image to grayscale in byte[] 
imageBytes = makeItGray(imageBytes, file.getContentType());
Path path = Paths.get("some path here that would overwrite existing image");
Files.write(path, imageBytes);

当我尝试手动打开图像以检查它是否为灰度时,它会给我透明图像或没有图像显示但不为空,因为它返回 byte[] 数据。我想知道上述方法是否适用于 PNG 格式?

如有任何问题,请告诉我。谢谢!

【问题讨论】:

  • 手动打开图片是什么意思,怎么知道是透明的?
  • 只是为了检查图像是否为灰度,我手动打开它并显示透明??因为我的应用程序没有错误,并且每当我的程序对图像 (png) 发出 GET 请求时,它都会用 base64 数据填充 标记。但是,没有图像,就像透明的一样。

标签: java image-processing png grayscale


【解决方案1】:

实际上,getRGBsetRGB 方法,尽管它们的名称,实际上返回并接受 32 位压缩 ARGB 格式的像素。这意味着,如果您的BufferedImage 的颜色模型实际上包含一个 Alpha 通道,那么像您一样将像素的 Alpha 值留空(0x00),将产生一个全透明的图像......

PNG 格式支持 alpha,而 JPEG 通常不使用它,这就是为什么您会看到您所做的结果,以及为什么它似乎对不同格式的工作方式不同。

修复很简单,只需在像素值前面加上所有不透明的 alpha:

int rgb = 0xff000000 | (r << 16) | (g << 8) | b;
bimg.setRGB(x, y, rgb);

如果你想保留原版的 alpha,你也可以这样做(我简化了代码):

int oldrgb = bimg.getRGB(x,y);
Color color = new Color(oldrgb);
int gray = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
int rgb = (oldrgb & 0xff000000) | (gray << 16) | (gray << 8) | gray;
bimg.setRGB(x, y, rgb);

PS:请注意,通过平均计算灰度值的方法不是将 RGB 转换为灰度的推荐方法,因此与其他工具相比,您的图像可能看起来不太好。参见例如Converting color to grayscale

【讨论】:

  • 哇!这就像一个魅力! :) 感谢您对问题的详细回答和解释。每当我在图像中添加带有 ARGB 值的字符串时,我也可以在 imagej 中的问题上执行此操作。
【解决方案2】:
public class GrayScaleImage{
    public static void main(String[]args)throws IOException{

        BufferedImage img = null;
        File f = null;
        try{
            f = new File("D:\\Image\\image.jpg");
            img = ImageIO.read(f);
        } catch(IOExeption e){
            System.out.println(e);
        }

        int width = img.getWidth();
        int height = img.getHeight();
        for(int y = 0; y < height; y++){
            for(int x = 0; x < width; x++){
                int p = img.getRGB(x,y);
                int a = (p>>24)&0ff;
                int r = (p>>16)&0ff;
                int g = (p>>8)&0ff;
                int b = p&0ff;
                int avg = (r + g + b)/3;
                p = (a<<24) | (avg<<16) | (avg<<8) |  avg;
                img.setRGB(x, y, p);
            }
        }
        try{
            f = new File("D:\\Image\\output.jpg");
            ImageIO.write(img, "jpg", f);
        } catch(IOException e){
            System.out.println(e);
        }

【讨论】:

    猜你喜欢
    • 2011-01-25
    • 2013-10-07
    • 2020-11-26
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    相关资源
    最近更新 更多