The fastest image filtering

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; } } 
+6
source share
1 answer

As long as the time difference resulting from the change does not prove that a repeated search is a bottleneck, it strongly implicates it.

If you want / can trade memory for a while, I first sort the list of all pixel locations by brightness. Then I would use a sorted list during the animation to find the next pixel to copy.

Extra tip: Use one of Java's built-in sorting methods. It is educational to make your own, but learning how to sort does not seem to be your goal here. In addition, if my assumption of a bottleneck is incorrect, you will want to minimize the time spent on this answer.

+1
source

All Articles