有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java比ColorConvertOp更快的替代方案

我有一个方法将类型为自定义的BuffereImage转换为类型为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;
}

共 (6) 个答案

  1. # 1 楼答案

    我发现使用图形进行渲染。drawImage()比ColorConvertOp快50倍。我只能假设drawImage()是GPU加速的

    也就是说,这真的很慢,比如100x200个矩形的速度是50毫秒

    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;
    }
    
  2. # 2 楼答案

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

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

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

    问:如果其他方面都失败了,您是否愿意编写一个JNI接口?或者是您自己的自定义C代码,或者是外部库,比如ImageMagick

  3. # 3 楼答案

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

    正如我所记得的,基本问题是Java2D对于TYPE_自定义图像通常根本没有进行优化。当您安装JAI时,它附带了codecLib,它有一个解码器,返回类型_CUSTOM,并使用它来代替默认值。JAI名单可能会提供更多的帮助,已经有好几年了

  4. # 4 楼答案

    你试过提供任何RenderingHints吗?不保证,但使用

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

    与代码片段中的null不同,它可能会稍微加快速度

  5. # 5 楼答案

    也许可以试试这个:

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

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

  6. # 6 楼答案

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

    例如:

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

    或者类似的。预期编译器错误会警告您不要访问这样的低级光栅。我对这种技术唯一有问题的地方是小程序内部,在那里会发生访问冲突