Need Faster way to get RGB value for each Pixel of a Buffered Image
Asked Answered
H

5

9

What is the fastest way to get the RGB value of each pixel of a BufferedImage?

Right now I am getting the RGB values using two for loops as shown in the code below, but it took too long to get those values as the nested loop runs a total of 479999 times for my image. If I use a 16-bit image this number would be even higher!

I need a faster way to get the pixel values.

Here is the code I am currently trying to work with:

BufferedImage bi=ImageIO.read(new File("C:\\images\\Sunset.jpg"));

int countloop=0;  

for (int x = 0; x <bi.getWidth(); x++) {
    for (int y = 0; y < bi.getHeight(); y++) {
        Color c = new Color(bi.getRGB(x, y));
        System.out.println("red=="+c.getRed()+" green=="+c.getGreen()+"    blue=="+c.getBlue()+"  countloop="+countloop++);                                                                                                                                                  
    }
}
Houseleek answered 10/4, 2012 at 12:6 Comment(8)
it can even rise when i will use 16 bit image - Why would the number of iterations depend on the bits per pixel? And what's the use case for that? Note that creating Color objects as well as printing to the console takes a while. If you want to access all 479999 pixels you can't get rid of a loop (you could merge them to one but that shouldn't make that big a difference).Unsnarl
The output slows the whole looping down. Try it without.Thimblerig
It might go a lot faster without the printlnFatso
Look at here #4349113Hemi
Taking out the System.out.println() calls will make it substantially faster. You could possibly define c outside of the loop, and even avoid instantiating a Color if you needed to, but it's probably not necessary.Sweet
@Sweet Well i am using System.out.println() just to check and letter on i will remove it but the thing is i have to apply some equation on this pixel values which may take even more timeHouseleek
@Unsnarl well it rises because height and width of 16 bit image is more as it contains 2^16 pixels......Houseleek
@AshishDonvir the height and width of an image normally doesn't depend on the bits per pixels. A 800x600 pixel image has 480000 pixels whether it's 8-, 16-, 24- or 32-bit (or even more). Only the number of bytes rises but not the number of pixels which you are looping over. If the width depends on the bits per pixel in your case then please explain why.Unsnarl
R
15

I don't know if this might help and I haven't tested it yet but you can get the rgb values this way:

BufferedImage bi=ImageIO.read(new File("C:\\images\\Sunset.jpg"));
int[] pixel;

for (int y = 0; y < bi.getHeight(); y++) {
    for (int x = 0; x < bi.getWidth(); x++) {
        pixel = bi.getRaster().getPixel(x, y, new int[3]);
        System.out.println(pixel[0] + " - " + pixel[1] + " - " + pixel[2] + " - " + (bi.getWidth() * y + x));
    }
}

As you can see you don't have to initialize a new Color inside the loop. I also inverted the width/height loops as suggested by onemasse to retrieve the counter from data I already have.

Reform answered 10/4, 2012 at 12:42 Comment(0)
T
7

By changing from a bunch of in individual getRGB's to one big getRGB to copy the entire image into an array, the execution time dropped by an order of magnitude from 33,000 milliseconds to 3,200 milliseconds, while the time create the array was only 31 milliseconds.

No doubt about it, one big read into an array and direct indexing of the array is much faster than many individual reads.

Performance difference appears related to the use of a breakpoint statement at the end of the class. While the breakpoint was outside the loop, every line of code within the class appears to be tested for the breakpoint. Changing to individual gets does NOT improve speed.

Since the code is still correct, the remainder of the answer may still be of use.

Old read statement

colorRed=new Color(bi.getRGB(x,y)).getRed();

Read statement to copy an bit image into an array

int[] rgbData = bi.getRGB(0,0, bi.getWidth(), bi.getHeight(), 
                null, 0,bi.getWidth());        

The getRGB into an array puts all 3 color values into a single array element, so individual colors must be extracted by rotating and an "and". The y coordinate must be multiplied by the width of the image.

Code to read individual colors out of the array

colorRed=(rgbData[(y*bi.getWidth())+x] >> 16) & 0xFF; 

colorGreen=(rgbData[(y*bi.getWidth())+x] >> 8) & 0xFF; 

colorBlue=(rgbData[(y*bi.getWidth())+x]) & 0xFF; 
Tgroup answered 28/11, 2012 at 4:23 Comment(0)
D
2

Did you try BufferedImage.getRGB(int, int ,int ,int, int[] , int , int)?

Something like:

int[] rgb = bi.getRGB(0,0, bi.getWidth(), bi.getHeight(), new int[bi.getWidth() * bi.getHeight(), bi.getWidth()])

Didn't try, so not sure if it's faster.

edit Having looked @ the code, it probably isn't, but worth a shot.

Danit answered 10/4, 2012 at 12:20 Comment(0)
P
2

You should loop the rows in the outer loop and the columns in the inner. That way you'll avoid cache misses.

Peninsula answered 10/4, 2012 at 12:25 Comment(0)
W
0

I found a solution here https://alvinalexander.com/blog/post/java/getting-rgb-values-for-each-pixel-in-image-using-java-bufferedi

BufferedImage bi = ImageIO.read(new File("C:\\images\\Sunset.jpg"));

for (int x = 0; x < bi.getWidth(); x++) {
    for (int y = 0; y < bi.getHeight(); y++) {
        int pixel = bi.getRGB(x, y);
        int red = (pixel >> 16) & 0xff;
        int green = (pixel >> 8) & 0xff;
        int blue = (pixel) & 0xff;
        System.out.println("red: " + red + ", green: " + green + ", blue: " + blue);                                                                                                                                                  
    }
}
Wotton answered 8/1, 2018 at 14:3 Comment(1)
is it a faster algorithm ?Myrilla

© 2022 - 2024 — McMap. All rights reserved.