上下文 我正在尝试用java创建动画。 动画只是拍摄一张图像,并使其从最暗的像素显示到最亮的像素。
问题: 定义像素变换的内部算法不是我的问题。 我是Java和计算的新手。我做了一些研究,并且知道有很多API可以帮助进行图像过滤/转换。 我的问题是表现,理解它。
在实现中,我创建了一个执行以下操作的方法:
之后,我使用Timer调用该方法。 返回的BufferedImage在每次调用后通过setIcon附加到JButton。
对于500x500图像,我的机器需要大约3ms来处理每个呼叫。 对于标准1080p图像,它需要大约30ms,大约每秒33帧。
我的目标是以30fps的速度处理/动画全高清图像...而且我无法使用我正在追踪的路径。不在大多数计算机中。
我错了什么?我怎么能让它更快?使用getDataBuffer或getPixels而不是getSample可以改进它吗?
提前致谢!抱歉我的英语。
部分结论: 感谢这里的一些帮助。我改变了概念。我没有使用getSample和setSample,而是将BufferedImage的像素ARGB信息存储到数组中。所以我处理数组并将其全部复制到另一个BufferedImage的Raster中。
处理时间从30ms(获取/设置样本)减少到1ms。 (测得很差,但在同一台机器,环境和代码中)。
下面是我编写实现它的一个小类。该类只能在亮度级别下过滤像素,其他像素变为透明(alpha = 0)。
希望将来能够搜索相同的解决方案。要小心我在Java中的新手级别以下,因此代码可能组织不当/优化。
import java.awt.Graphics2D;
import java.awt.image.*;
/**
* @author Psyny
*/
public class ImageAppearFX {
//Essencial Data
BufferedImage imgProcessed;
int[] RAWoriginal;
int[] RAWprocessed;
WritableRaster rbgRasterProcessedW;
//Information about the image
int x,y;
int[] mapBrightness;
public ImageAppearFX(BufferedImage inputIMG) {
//Store Dimensions
x = inputIMG.getWidth();
y = inputIMG.getHeight();
//Convert the input image to INT_ARGB and store it.
this.imgProcessed = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);
Graphics2D canvas = this.imgProcessed.createGraphics();
canvas.drawImage(inputIMG, 0, 0, x, y, null);
canvas.dispose();
//Create an int Array of the pixels informations.
//p.s.: Notice that the image was converted to INT_ARGB
this.RAWoriginal = ((DataBufferInt) this.imgProcessed.getRaster().getDataBuffer()).getData();
//Dupplication of original pixel array. So we can make changes based on original image
this.RAWprocessed = this.RAWoriginal.clone();
//Get Raster. We will need the raster to write pixels on
rbgRasterProcessedW = imgProcessed.getRaster();
//Effect Information: Store brightness information
mapBrightness = new int[x*y];
int r,g,b,a,greaterColor;
// PRocess all pixels
for(int i=0 ; i < this.RAWoriginal.length ; i++) {
a = (this.RAWoriginal[i] >> 24) & 0xFF;
r = (this.RAWoriginal[i] >> 16) & 0xFF;
g = (this.RAWoriginal[i] >> 8) & 0xFF;
b = (this.RAWoriginal[i] ) & 0xFF;
//Search for Stronger Color
greaterColor = r;
if( b > r ) {
if( g > b ) greaterColor = g;
else greaterColor = b;
} else if ( g > r ) {
greaterColor = g;
}
this.mapBrightness[i] = greaterColor;
}
}
//Effect: Show only in a certain percent of brightness
public BufferedImage BrightnessLimit(float percent) {
// Adjust input values
percent = percent / 100;
// Pixel Variables
int hardCap = (int)(255 * percent);
int r,g,b,a,bright;
// Process all pixels
for(int i=0 ; i < this.RAWoriginal.length ; i++) {
//Get information of a pixel of the ORIGINAL image
a = (this.RAWoriginal[i] >> 24) & 0xFF;
r = (this.RAWoriginal[i] >> 16) & 0xFF;
g = (this.RAWoriginal[i] >> 8) & 0xFF;
b = (this.RAWoriginal[i] ) & 0xFF;
//Brightness information of that same pixel
bright = this.mapBrightness[i];
//
if( bright > hardCap ) {
a = 0;
}
this.RAWprocessed[i] = ((a << 24) + (r << 16) + (g << 8) + ( b )); //Write ARGB in byte format
}
//Copy the processed array into the raster of processed image
rbgRasterProcessedW.setDataElements(0, 0, x, y, RAWprocessed);
return imgProcessed;
}
//Return reference to the processed image
public BufferedImage getImage() {
return imgProcessed;
}
}
答案 0 :(得分:1)
虽然改变所导致的时差并不能证明重复搜索是瓶颈,但它确实暗示了它。
如果你愿意/能够交换内存的时间,我会首先按亮度排序所有像素位置的列表。接下来,我将在动画期间使用排序列表来查找要复制的下一个像素。
额外建议:使用Java内置的排序方法之一。制作自己的教育很有教育意义,但学习如何排序似乎不是你的目标。此外,如果我对瓶颈的猜测是错误的,那么你会希望尽量减少花时间来回答这个问题。