Context: I'm trying to create an animation in java. The animation just takes the image and makes it visible from the darkest pixels the easiest.
Problem: The internal algorithm for determining pixel transformations is not my problem. I am new to Java and Computing in general. I have done some research and know that there are many APIs that help with image filters / transforms. My problem is performance, understanding this.
For implementation, I created a method that does the following:
- Gets a BufferedImage.
- Get WritableRaster from BufferedImage.
- Using setSample and getSample, process and change pixel by pixel.
- Return BufferedImage.
After that, I use a timer to call the method. The returned BufferedImage is attached to JButton via setIcon after each call.
With a 500x500 image, my machine takes about 3 ms to process each call. For standard 1080p images, it takes about 30 ms, which is about 33 frames per second.
My goal is to process / animate FullHD images at a speed of 30 frames per second ... And I cannot follow this. Not on most computers.
How am I wrong? How can I do it faster? Using getDataBuffer or getPixels instead of getSample can improve it?
Thanks in advance! And sorry my english.
Partial Findings: Thanks to some help here. I changed the concept. Instead of using getSample and setSample, I saved the ARGB information in ARGB pixels in BufferedImage to an array. So I process the array and copy it immediately to the Raster of another BufferedImage.
The process time is reduced from 30 ms (receive / install sample) to 1 ms. (measured poorly, but in the same machine, environment and code).
Below is a small class that is encoded to implement it. A class can filter pixels only below the brightness level, other pixels become transparent (alpha = 0).
Hope this helps those looking for the same solution in the future. Be careful that I'm below the beginner level in Java, so the code may be poorly organized / optimized.
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. //ps: 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; } }