ColorConvertOp 的更快替代方案
我有一个方法将类型为 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;
}
I have a method converting BufferedImages who's type is TYPE_CUSTOM to TYPE_INT_RGB. I am using the following code, however I would really like to find a faster way of doing this.
BufferedImage newImg = new BufferedImage(
src.getWidth(),
src.getHeight(),
BufferedImage.TYPE_INT_RGB);
ColorConvertOp op = new ColorConvertOp(null);
op.filter(src, newImg);
It works fine, however it's quite slow and I am wondering if there is a faster way to do this conversion.
ColorModel Before Conversion:
ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@1c92586f transparency = 1 has alpha = false isAlphaPre = false
ColorModel After Conversion:
DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0
Thanks!
Update:
Turns out working with the raw pixel data was the best way. Since the TYPE_CUSTOM was actually RGB converting it manually is simple and is about 95% faster than ColorConvertOp.
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
BufferedImages 速度慢得令人痛苦。我有一个解决方案,但我不确定你会喜欢它。处理和转换缓冲图像的最快方法是从 BufferedImage 内部提取原始数据数组。您可以通过调用 buffImg.getRaster() 并将其转换为特定的栅格来完成此操作。然后调用raster.getDataStorage()。一旦您能够访问原始数据,就可以编写快速的图像处理代码,而不会因为 BufferedImages 中的所有抽象而减慢速度。这项技术还需要您对图像格式有深入的了解,并需要进行一些逆向工程。这是我能够让图像处理代码运行得足够快以适合我的应用程序的唯一方法。
例如:
或者类似的东西。预计编译器错误会警告您不要访问这样的低级栅格。我对这种技术唯一遇到问题的地方是在小程序内部,那里会发生访问冲突。
BufferedImages are painfully slow. I got a solution but I'm not sure you will like it. The fastest way to process and convert buffered images is to extract the raw data array from inside the BufferedImage. You do that by calling buffImg.getRaster() and converting it into the specific raster. Then call raster.getDataStorage(). Once you have access to the raw data it is possible to write fast image processing code without all the abstraction in BufferedImages slowing it down. This technique also requires an in depth understanding of image formats and some reverse engineering on your part. This is the only way I have been able to get image processing code to run fast enough for my applications.
Example:
or something like that. Expect compiler errors warning you not to access low level rasters like that. The only place I have had issues with this technique is inside of applets where an access violation will occur.
我发现使用 Graphics.drawImage() 而不是 ColorConvertOp 渲染速度快了 50 倍。我只能假设drawImage()是GPU加速的。
也就是说,这真的很慢,比如 100x200 矩形需要 50 毫秒
,但是这个寄存器 <相同输入为 1ms
I've found rendering using Graphics.drawImage() instead of ColorConvertOp 50 times faster. I can only assume that drawImage() is GPU accelerated.
i.e this is really slow, like 50ms a go for 100x200 rectangles
i.e however this registers < 1ms for same inputs
您是否尝试过提供任何RenderingHints?不能保证,但
在代码片段中使用而不是
null
可能会稍微加快速度。Have you tried supplying any RenderingHints? No guarantees, but using
rather than the
null
in your code snippet might speed it up somewhat.我怀疑问题可能是 ColorConvertOp() 逐像素工作(保证“慢”)。
问:您是否可以使用 gc.createCompatibleImage()?
问:您的原始位图是真彩色的,还是使用颜色图?
问:如果一切都失败了,您是否同意编写 JNI 接口?是您自己的自定义 C 代码,还是外部库,例如 ImageMagick?
I suspect the problem might be that ColorConvertOp() works pixel-by-pixel (guaranteed to be "slow").
Q: Is it possible for you to use gc.createCompatibleImage()?
Q: Is your original bitmap true color, or does it use a colormap?
Q: Failing all else, would you be agreeable to writing a JNI interface? Either to your own, custom C code, or to an external library such as ImageMagick?
如果您安装了 JAI,那么您可以尝试卸载它(如果可以的话),或者寻找某种方法在加载 JPEG 时禁用 codecLib。在过去的生活中,我也遇到过类似的问题(http://www.java.net/node/660804),而 ColorConvertOp 当时是最快的。
我记得根本问题是 Java2D 根本没有针对 TYPE_CUSTOM 图像进行优化。当您安装 JAI 时,它附带了 codecLib,它有一个返回 TYPE_CUSTOM 的解码器并被使用而不是默认值。 JAI名单也许能提供更多帮助,已经好几年了。
If you have JAI installed then you might try uninstalling it, if you can, or otherwise look for some way to disable codecLib when loading JPEG. In a past life I had similar issues (http://www.java.net/node/660804) and ColorConvertOp was the fastest at the time.
As I recall the fundamental problem is that Java2D is not at all optimized for TYPE_CUSTOM images in general. When you install JAI it comes with codecLib which has a decoder that returns TYPE_CUSTOM and gets used instead of the default. The JAI list may be able to provide more help, it's been several years.
也许试试这个:
然后源位图将被修改。
稍后您可以这样做:
如果您可以管理,请始终重用位图,以便您能够获得更好的性能。您也可以使用其他画布函数来绘制位图
maybe try this:
Then the source bitmap will be modified.
Later you can do:
if you can manage always reuse the bitmap so you be able to get better performance. As well you can use other canvas functions to draw your bitmap