什么是最快的Java Image Reader

时间:2011-04-20 19:11:08

标签: java javax.imageio

我有一个程序,我必须将BufferedImage序列化到磁盘然后再读回来。目前我正在使用原始图像格式

ImageIO.getImageReadersByFormatName("raw");

经过大量测试后,它的性能似乎在相同的数据上变化很大(从一秒钟到15秒不等)。
1.知道发生了什么事吗? 2.用于完成此任务的Java中最快的图像读取器/写入器是什么?

由于

2 个答案:

答案 0 :(得分:2)

  1. 很难说是什么导致了如此巨大的性能差异。有各种各样的因素可能有助于它。请参阅:How do I write a correct micro-benchmark in Java?
  2. 这也很难回答,因为它可能取决于图像中的数据,处理器的速度以及硬盘的速度。真正了解您的数据集的唯一方法是对您的不同选项进行基准测试。
  3. 那就是说,我认为png通常是一个很好的选择。

答案 1 :(得分:0)

除非您需要在特定程序之外进行互操作,否则通过ImageIO进行序列化可能是一个缓慢的解决方案。直接读取和写入BufferedImage的像素可能会更快。这是一个完整的解决方案:

public class SerializedImage
    implements Serializable {

    private BufferedImage   mImage;

    public SerializedImage( BufferedImage image ) {

        mImage = image;
    }

    public BufferedImage getImage() {

        return mImage;
    }

    private void writeObject( ObjectOutputStream streamOut )
        throws IOException {

        streamOut.writeInt( mImage.getWidth() );
        streamOut.writeInt( mImage.getHeight() );
        streamOut.writeInt( mImage.getType() );
        streamOut.writeObject( ( (DataBufferInt) mImage.getRaster().getDataBuffer() ).getData() );
    }

    private void readObject( ObjectInputStream streamIn )
        throws IOException, ClassNotFoundException {

        mImage = new BufferedImage( streamIn.readInt(), streamIn.readInt(), streamIn.readInt() );

        int[] savedBuffer = (int[]) streamIn.readObject();
        int[] buffer = ( (DataBufferInt) mImage.getRaster().getDataBuffer() ).getData();

        System.arraycopy( savedBuffer, 0, buffer, 0, savedBuffer.length );
    }
}

更新: @haraldK要求一些基准。像所有的微观基准测试一样,你应该用一粒盐。正如@haraldK指出的那样,如果您将序列化表单写入磁盘,I / O可能会成为限制因素。始终测试您自己的用例。

但是,内存序列化/反序列化(到字节数组)的简单基准测试速度提高了10倍以上。鉴于a)PNG压缩是一项非平凡的任务,这似乎不合理。 b)可能PNG压缩必须至少读取像素数据,然后对其进行大量处理,而SerializedImage只需读取像素数据即可完成。 / p>

以下是代码:

    // Create

    BufferedImage image = new BufferedImage( 100, 200, BufferedImage.TYPE_INT_ARGB );
    Graphics2D graphics = (Graphics2D) image.getGraphics();
    graphics.setColor( Color.red );
    graphics.fillRect( 1, 1, 50, 50 );
    SerializedImage serializedImage = new SerializedImage( image );

    long start = System.currentTimeMillis();

    for( int loop = 0; loop < 10_000; loop++ ) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        // Write

        try ( ObjectOutputStream objectOutputStream = new ObjectOutputStream( outputStream ) ) {
            objectOutputStream.writeObject( serializedImage );
        }

        // Read

        try ( ObjectInputStream objectInputStream = new ObjectInputStream( new ByteArrayInputStream( outputStream.toByteArray() ) ) ) {
            ( (SerializedImage) objectInputStream.readObject() ).getImage();
        }
    }

    long end = System.currentTimeMillis() - start;
    System.out.println( "SerializedImage took " + end + "ms" );

    start = System.currentTimeMillis();

    for( int loop = 0; loop < 10_000; loop++ ) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        // Write

        ImageIO.write( image, "png", outputStream );

        // Read

        ImageIO.read( new ByteArrayInputStream( outputStream.toByteArray() ));
    }

    end = System.currentTimeMillis() - start;
    System.out.println( "ImageIO took " + end + "ms" );

出于好奇,我尝试使用FileOutputStream / FileInputStream。它仍然比ImageIO快,但速度只快了4倍。 @ haraldK的一些实验(下图)仅快了约2倍。所以你的里程可能会有所不同。