将BufferedImage像素数据转换为可读输出?

时间:2014-04-30 20:06:28

标签: java image awt

我正在尝试制作一个程序,将旧GBA游戏的地图划分为16x16图块,保存每个图块,然后将每个抓取图块的原始图像数据与另一个已保存图块列表进行比较,并自动确定是否为相同的形象。到目前为止,我已设法将地图划分为16x16图块,自动将每个16x16图块保存到新图像文件中,然后将所有这些图像文件作为BufferedImages加载到数组中。

 public TileSorter()
 {
   for (int a = 0; a < 1269; a++)
   {
     try {
       img[a] = ImageIO.read(new File("img" + a + ".jpg"));
     } catch (IOException e) {}
     System.out.println("img" + a + ".jpg loaded into Array.");
   }
 }

我现在要做的是分析一个数组中每个图块(一个BufferedImage)的原始数据,并确定它是否与来自另一个数组的任何已保存的BufferedImage图块相同。 我环顾四周寻找答案,并尝试了getRGB()方法和getData()栅格方法:

    img[a].getRGB(0,0,16,16,rawImgData[a],0,0);

    rawImgData[a] = ((DataBufferByte) img[a].getRaster().getDataBuffer()).getData();

问题是:从我所看到的,从这些方法返回的byte []和int []数据对于任何两个完全相同的图片是不一样的。我需要一种方法将图像数据转换为原始int []或byte []数据,可用于比较两个完全相同的图片。 (IE;如果两张图片都只是一个16x16的黑色像素阵列,它们应该输出相同的getRGB()或getData()值。) 是否有一种方法可以将这些BufferedImages转换为可以轻松比较的原始图像数据?

非常感谢任何建议,谢谢。

2 个答案:

答案 0 :(得分:2)

首先:JPG格式是 NOT 无损压缩。这意味着对于像

这样的序列
BufferedImage imageA = loadImage("image.jpg");
saveAs("saved.jpg");
BufferedImage imageB = loadImage("saved.jpg");

somehowCompare(imageA, imageB);

somehowCompare方法很可能会发现图像相等,因为JPG压缩引入了工件。

有疑问,您应该将图像存储为PNG,因为它是无损的,对于如上所述的序列,图像将被视为&#34;相等&#34; - 意味着它们具有完全相同的RGB像素值。

但这是你的实际问题:如何比较这些图像?

获得数据缓冲区的方法将是最有效的方法。但仍有一些警告:图片是否包含DataBufferIntDataBufferByte取决于细微的细节。它可能取决于文件类型(JPG,GIF或PNG),或图像是否包含透明度(如果它是PNG或GIF),或取决于压缩方法。

解决此问题的一个选择是将每个新加载的图像绘制成一个知道它包含DataBufferInt的图像。这意味着你可以使用像

这样的方法
public static BufferedImage convertToARGB(BufferedImage image)
{
    BufferedImage newImage = new BufferedImage(
        image.getWidth(), image.getHeight(),
        BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = newImage.createGraphics();
    g.drawImage(image, 0, 0, null);
    g.dispose();
    return newImage;
}

然后使用

加载图像
img[a] = convertToARGB(ImageIO.read(new File("img" + a + ".png")));

生成的图像将具有DataBufferInt。在此缓冲区中,您可以将数据作为int[]数组获取。在最好的情况下,您可以使用

简单地比较两个这样的图像的数组
DataBufferInt bufferA = (DataBufferInt)imageA.getRaster().getDataBuffer();
DataBufferInt bufferB = (DataBufferInt)imageB.getRaster().getDataBuffer();
int arrayA[] = bufferA.getData();
int arrayB[] = bufferB.getData();
if (Arrays.equal(arrayA, arrayB))
{
    // Images are equal!
}

另一种方法是简单地从图像中获取单个像素:

// Assuming equal-sized images:
for (int y=0; y<imageA.getHeight(); y++)
{
    for (int x=0; x<imageA.getWidth(); x++)
    {
        int rgbA = imageA.getRGB(x,y);
        int rgbB = imageB.getRGB(x,y);
        if (rgbA != rgbB) 
        { 
            // Images are NOT equal!
        }
    }
}

后一种方法的优点可能是您可以将图像视为&#34;等于&#34;当他们有非常相似的时候#34; (但不完全相等)像素值,通过适当调整if - 语句。

答案 1 :(得分:0)

首先想到的是JPG是一种有损格式,不应该用于精确像素图形,特别是在16x16分辨率下。当您阅读它时,您不应期望得到最初写入JPG的完全相同的RGB值。

我在单元测试中成功使用PNG作为参考图像,与生成的BufferedImage进行比较。