Jony
Jony

Reputation: 1025

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

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++);                                                                                                                                                  
    }
}

Upvotes: 9

Views: 29134

Answers (5)

pipi
pipi

Reputation: 21

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);                                                                                                                                                  
    }
}

Upvotes: 0

Fred F
Fred F

Reputation: 1047

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; 

Upvotes: 7

mastaH
mastaH

Reputation: 1267

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.

Upvotes: 15

soulcheck
soulcheck

Reputation: 36777

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.

Upvotes: 2

onemasse
onemasse

Reputation: 6584

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

Upvotes: 2

Related Questions