Java 比ColorConvertOp更快的替代方案

Java 比ColorConvertOp更快的替代方案,java,javax.imageio,jai,Java,Javax.imageio,Jai,我有一个方法将类型为自定义的BuffereImage转换为类型为INT的RGB。我正在使用下面的代码,但是我真的很想找到一种更快的方法来实现这一点 BufferedImage newImg = new BufferedImage( src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB); ColorConvertOp op = new ColorConvertOp(null); op.filter(s

我有一个方法将类型为自定义的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
转换后的颜色模型:

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;
}
publicstaticbufferedimage makeCompatible(BufferedImage img)引发IOException{
//分配新映像
BuffereImage dstImage=新的BuffereImage(img.getWidth(),img.getHeight(),BuffereImage.TYPE_INT_RGB);
//检查颜色空间是否为RGB,传输类型是否为BYTE。
//否则,此快速方法将无法按预期工作
ColorModel cm=img.getColorModel();
if(cm.getColorSpace().getType()==ColorSpace.TYPE\u RGB&&img.getRaster().getTransferType()==DataBuffer.TYPE\u字节){
//分配数组
int len=img.getWidth()*img.getHeight();
字节[]src=新字节[len*3];
int[]dst=新的int[len];
//将src映像数据读入数组
getgraster().getDataElements(0,0,img.getWidth(),img.getHeight(),src);
//转换为INT_RGB
int j=0;

对于(int i=0;i您是否尝试过提供任何?不保证,但使用

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

而不是代码片段中的
null
,可能会在某种程度上加快速度。

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

问:您是否可以使用

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


问:如果其他方法都失败了,你愿意写一个JNI接口吗?要么写你自己的自定义C代码,要么写一个外部库,比如?

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

我记得最基本的问题是Java2D在一般情况下根本没有针对TYPE_自定义图像进行优化。当您安装JAI时,它附带了codecLib,它有一个解码器,返回TYPE_自定义并使用,而不是默认值。JAI列表可能能够提供更多帮助,已经有好几年了。

也许可以尝试以下方法:

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

如果您能够管理,请始终重复使用位图,以便获得更好的性能。此外,您还可以使用其他画布功能绘制位图。缓冲图像的速度非常慢。我找到了一个解决方案,但我不确定您是否会喜欢它。处理和转换缓冲图像的最快方法是从内部提取原始数据数组通过调用buffImg.getRaster()并将其转换为特定的光栅,然后调用raster.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];
ByteInterlevedRaster srcRaster=(ByteInterlevedRaster)src.getRaster();
字节srcData[]=srcRaster.getDataStorage();
integerinerLeavedRaster=(integerinerLeavedRaster)dst.getRaster();
int dstData[]=dstRaster.getDataStorage();

dstData[0]=srcData[0]我发现使用Graphics.drawImage()而不是ColorConvertOp进行渲染要快50倍。我只能假设drawImage()是GPU加速的

i、 这真的很慢,比如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;
}
i、 然而,对于相同的输入,该寄存器小于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;
}

另外-您看过Java 6++中的任何新ImageIO调用吗?gc.createCompatibleImage()将无法工作(headless machine),位图是真彩色的,我不反对使用JNI或ImageMagick挂起,我可以得到与使用ColorConvertOp相同的结果。我使用带有本机加速的ImageIO打开JPG。Q:您的原始位图是什么格式?Q:我想您肯定已经将问题缩小到ColorConvertOp.filter()上了,对吗?Q:转换一张图像需要多长时间?是因为图像太大(大小是多少?),还是因为图像太多(一次转换多少张?),还是因为这种方法本身就很慢?如果有机会,请回答我的问题。我很好奇:)但同时,这里有一个指向“JavaMagick”的链接:很漂亮!处理原始数据将处理时间缩短了95%!!请参阅编辑的帖子,了解我最终是如何做到这一点的。我没有使用ByteInterleavedRaster和IntegerInterleavedRaster类,因为出于某种原因,我没有sun软件包。天哪,我刚刚从处理100MB+psd文件开始,处理了10分钟到8秒。谢谢