ColorConvertOp的更快替代品

时间:2012-01-05 14:50:17

标签: java javax.imageio jai

我有一种方法将类型为TYPE_CUSTOM的BufferedImages转换为TYPE_INT_RGB。我使用以下代码,但我真的希望找到一种更快的方法。

BufferedImage newImg = new BufferedImage(
    src.getWidth(), 
    src.getHeight(), 
    BufferedImage.TYPE_INT_RGB);

ColorConvertOp op = new ColorConvertOp(null);
op.filter(src, newImg);

它工作正常,但它很慢,我想知道是否有更快的方法来进行这种转换。

转化前的ColorModel:

ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@1c92586f transparency = 1 has alpha = false isAlphaPre = false

转换后的ColorModel:

DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0

谢谢!


更新

使用原始像素数据是最好的方法。由于TYPE_CUSTOM实际上是RGB转换,因此手动操作非常简单,比ColorConvertOp快95%。

public static BufferedImage makeCompatible(BufferedImage img) throws IOException {
    // Allocate the new image
    BufferedImage dstImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);

    // Check if the ColorSpace is RGB and the TransferType is BYTE. 
    // Otherwise this fast method does not work as expected
    ColorModel cm = img.getColorModel();
    if ( cm.getColorSpace().getType() == ColorSpace.TYPE_RGB && img.getRaster().getTransferType() == DataBuffer.TYPE_BYTE ) {
        //Allocate arrays
        int len = img.getWidth()*img.getHeight();
        byte[] src = new byte[len*3];
        int[] dst = new int[len];

        // Read the src image data into the array
        img.getRaster().getDataElements(0, 0, img.getWidth(), img.getHeight(), src);

        // Convert to INT_RGB
        int j = 0;
        for ( int i=0; i<len; i++ ) {
            dst[i] = (((int)src[j++] & 0xFF) << 16) | 
                     (((int)src[j++] & 0xFF) << 8) | 
                     (((int)src[j++] & 0xFF));
        }

        // Set the dst image data
        dstImage.getRaster().setDataElements(0, 0, img.getWidth(), img.getHeight(), dst);

        return dstImage;
    }

    ColorConvertOp op = new ColorConvertOp(null);
    op.filter(img, dstImage);

    return dstImage;
}

6 个答案:

答案 0 :(得分:7)

BufferedImages非常缓慢。我有一个解决方案,但我不确定你会喜欢它。处理和转换缓冲图像的最快方法是从BufferedImage内部提取原始数据数组。您可以通过调用buffImg.getRaster()并将其转换为特定栅格来实现。然后调用raster.getDataStorage()。一旦您可以访问原始数据,就可以编写快速图像处理代码,而BufferedImages中的所有抽象都不会降低速度。这项技术还需要深入了解图像格式和您的一些逆向工程。这是我能够让图像处理代码足够快地运行我的应用程序的唯一方法。

示例:

ByteInterleavedRaster srcRaster = (ByteInterleavedRaster)src.getRaster();
byte srcData[] = srcRaster.getDataStorage();

IntegerInterleavedRaster dstRaster = (IntegerInterleavedRaster)dst.getRaster();
int dstData[] = dstRaster.getDataStorage();

dstData[0] = srcData[0] << 16 | srcData[1] << 8 | srcData[2];

或类似的东西。期待编译器错误警告您不要访问类似的低级别栅格。我遇到这种技术问题的唯一地方就是会发生访问冲突的applet内部。

答案 1 :(得分:3)

我发现使用Graphics.drawImage()代替ColorConvertOp的渲染速度提高了50倍。我只能假设drawImage()是GPU加速的。

,这真的很慢,比如100x200矩形的50ms

public void BufferdImage convert(BufferedImage input) {
   BufferedImage output= new BufferedImage(input.getWidht(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CUSTOM_PALETTE);

   ColorConvertOp op = new ColorConvertOp(input.getColorModel().getColorSpace(), 
                                          output.getColorModel().getColorSpace());

   op.filter(input, output);
   return output;
}
然而,这个寄存器&lt;相同输入1ms

public void BufferdImage convert(BufferedImage input) {
   BufferedImage output= new BufferedImage(input.getWidht(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CUSTOM_PALETTE);

   Graphics graphics = output.getGraphics();
   graphics.drawImage(input, 0, 0, null);
   graphics.dispose();
   return output;
}

答案 2 :(得分:0)

您是否尝试过提供任何RenderingHints?没有保证,但使用

ColorConvertOp op = new ColorConvertOp(new RenderingHints(
    RenderingHints.KEY_COLOR_RENDERING, 
    RenderingHints.VALUE_COLOR_RENDER_SPEED));

而不是代码段中的null可能会加速它。

答案 3 :(得分:0)

我怀疑问题可能是ColorConvertOp()逐像素工作(保证“慢”)。

问:您是否可以使用gc.createCompatibleImage()

问:原始位图是真彩色还是使用色彩图?

问:没有其他问题,您是否同意编写JNI接口?要么是您自己的自定义C代码,要么是外部库,例如ImageMagick

答案 4 :(得分:0)

如果您安装了JAI,那么您可以尝试卸载它,如果可以,或者在加载JPEG时寻找某种方法来禁用codecLib。在过去的生活中,我遇到了类似的问题(http://www.java.net/node/660804),ColorConvertOp当时是最快的。

我记得基本问题是Java2D一般都没有针对TYPE_CUSTOM图像进行优化。当你安装JAI时,它附带了codecLib,它有一个解码器返回TYPE_CUSTOM并被使用而不是默认值。 JAI名单可能会提供更多帮助,已经有好几年了。

答案 5 :(得分:-1)

也许试试这个:

Bitmap source = Bitmap.create(width, height, RGB_565);//don't remember exactly...
Canvas c = new Canvas(source);
// then 
c.draw(bitmap, 0, 0);

然后将修改源位图。

稍后你可以这样做:

onDraw(Canvas canvas){
canvas.draw(source, rectSrs,rectDestination, op);
}

如果您可以管理,请始终重复使用位图,以便您能够获得更好的性能。您也可以使用其他画布函数来绘制位图