Java 灰度缓冲图像

Posted

技术标签:

【中文标题】Java 灰度缓冲图像【英文标题】:Java Greyscale buffered image 【发布时间】:2015-11-13 13:48:11 【问题描述】:

所以我有一个表示像素数据(8 位灰度)的字节数组。没有标题。没什么。只是数据。我想从这些数据中创建一个缓冲图像。我做了

image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, data);
this.x = w;
this.y = h;
scalemode=false;
exactmode=true;

其中 w 是像素宽度,h 像素高度,data 是字节数组,图像是 BufferedImage

这是我的绘画方法

 protected void paintComponent(Graphics g)
    
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        int rx = (this.getWidth() - x) / 2;
        int ry = (this.getHeight() - y) / 2;

        g2d.drawImage(image, rx, ry,x,y, null);
    

然而,我得到了这张图片(真实的图片是指纹,大部分是白色像素)

出了什么问题?我尝试按原样保存数据,然后在 Photoshop 中查看。数据很好。

[编辑] 别管这个问题。我搞砸了代码的其他部分并且不知道。感谢您的所有投入

【问题讨论】:

data是什么类型? 数据为 byte[] 1byte = 1pixel 在每个像素上绘制每个字节... 那是图像的 1 像素边框部分吗? 没有边框不是图片的一部分 【参考方案1】:

很难确切知道哪里出了问题,因为您没有发布足够的信息。我们不知道wh 或您的data 中有什么信息。我们不知道图像应该是什么样子。

但是,这里有一些代码几乎可以完成您正在做的事情,并且对我有用:

// Set up h/w and backing data
int w = 300;
int h = 200;
byte[] data = new byte[w * h];

// Create a smooth gradient
for (int y = 0; y < h; y++) 
    int off = y * w;

    for (int x = 0; x < w; x++) 
        data[off + x] = (byte) (Math.round((x / (double) w) * 127) 
                              + Math.round((y / (double) h) * 127));
    


// Create BufferedImage from data
final BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, data);

// Show it all in a window
SwingUtilities.invokeLater(new Runnable() 
    @Override
    public void run() 
        JFrame frame = new JFrame(getClass().getSimpleName());
        frame.add(new JLabel(new ImageIcon(image)));

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    
);

结果如下:

【讨论】:

Green Melon 提供的图片看起来确实有不正确的宽度和高度值.. 我刚刚尝试测试了整个东西,我发现如果图像是在一个不错的单个主线程中创建的,那么图像就很好。但是,当我在鼠标事件侦听器线程中创建图像时,图像变得乱码!我刚刚意识到数据(字节数组)已经搞砸了,所以我无法把它弄好。您知道从侦听器线程读取 BufferedinputStream 可能有什么问题吗?我使用了来自here 的代码。特别是 upImg 方法 @GreenMellon 好的。没问题。 :-) 从流中读取应该像从侦听器线程一样正常工作,但是为了响应式 UI,强烈建议不要这样做。通常,所有 I/O 都应该在后台线程上完成。无论如何,很高兴你想通了! 原来我正在使用的指纹识别模块在将图像转换为签名文件时实际上修改了它的图像缓冲区。我完全不知道为什么(记忆力小?)。所以它与Java无关。感谢您的提示【参考方案2】:

在每个像素上绘制每个字节...

BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
for (int dy = 0; dy < h; dy ++)
    for(int dx = 0; dx < w; dx ++)
        int index = dy*w + dx;
        int rgb = data[index];
        rgb = rgb << 24 & 0xFFFF; //BufferedImage.TYPE_BYTE_GRAY consideres only the red-channel;
        //rgb = 00 data[index] FF FF
        image.setRGB(dx,dy,rgb);
        
    

【讨论】:

【参考方案3】:

您没有正确设置缓冲区...

byte[] data = ... 
DataBufferByte db = new DataBufferByte(data, w*h);
image.getRaster().setDataElements(0, 0, w, h, db );

见http://docs.oracle.com/javase/7/docs/api/java/awt/image/WritableRaster.html#setDataElements%28int,%20int,%20java.lang.Object%29

【讨论】:

您要查找的方法是setDataElements(x, y, w, h, data)。并引用文档:“为 TransferType 类型的 原始数组 中的像素矩形设置数据”(强调我的)。这个答案显然是错误的。 OP的代码在这方面很好。 @haraldK 是的,继续阅读,您会发现“对于 Java 2D API 支持的图像数据,这将是 DataBuffer.TYPE_BYTE、DataBuffer.TYPE_USHORT、DataBuffer.TYPE_INT、DataBuffer.TYPE_SHORT 之一、DataBuffer.TYPE_FLOAT 或 DataBuffer.TYPE_DOUBLE"... 那么错误在哪里? 你似乎认为DataBuffer.TYPE_BYTE == DataBufferByte。它不是。 “DataBuffer.TYPE_BYTE”类型的“原始数组”仅表示byte[] 好吧,不,这就是我现在想的 ^ ^(DataBufferByte.getType() 会返回 DataBuffer.TYPE_BYTE - 但这会导致无处可去)......我会理解你的例子并接受您的代码正在运行。正如在您的示例中的评论中提到的,我猜 OP 只是不知道宽度/高度的问题......@haraldK 感谢您提供了一个很好的例子...... 我也这么认为。这就是为什么我要问边界。作为记录,您上面的代码将在运行时崩溃,但以下异常:java.lang.ClassCastException: java.awt.image.DataBufferByte cannot be cast to [B。 ;-)

以上是关于Java 灰度缓冲图像的主要内容,如果未能解决你的问题,请参考以下文章

可视化深度缓冲区

在 Java 中旋转缓冲图像

为啥加入小缓冲图像的 Java 代码不起作用?

java缓冲图像:检测黑色像素

java应用程序中的缓冲图像问题

Java - 将缓冲图像保存到文件旋转 90 度时出现问题