10

我有一种方法将类型为 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: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@1c92586f transparency = 1 has alpha = false isAlphaPre = false

转换后的颜色模型:

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;
}
4

6 回答 6

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];

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

于 2012-01-15T04:13:40.300 回答
3

我发现使用 Graphics.drawImage() 而不是 ColorConvertOp 的渲染速度快了 50 倍。我只能假设 drawImage() 是 GPU 加速的。

即这真的很慢,比如 50 毫秒 100x200 矩形

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;
}

即,但是对于相同的输入,此寄存器 < 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;
}
于 2014-08-27T08:38:09.420 回答
0

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

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

而不是null在您的代码片段中可能会加快速度。

于 2012-01-05T14:58:55.357 回答
0

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

问:您可以使用gc.createCompatibleImage()吗?

问:您的原始位图是真彩色,还是使用颜色图?

问:如果其他都失败了,你会同意写一个 JNI 接口吗?是您自己的自定义 C 代码,还是ImageMagick等外部库?

于 2012-01-09T19:16:09.960 回答
0

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

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

于 2012-01-12T17:14:36.913 回答
-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);
}

如果您可以管理始终重用位图,那么您可以获得更好的性能。您也可以使用其他画布功能来绘制位图

于 2012-01-14T20:19:51.417 回答