Tomáš Zato Tomáš Zato - 4 months ago 30
Java Question

Get average color on bufferedimage and bufferedimage portion as fast as possible

I am trying to find image in an image. I do this for desktop automation. At this moment, I'm trying to be fast, not precise. As such, I have decided to match similar image solely based on the same average color.

If I pick several icons on my desktop, for example:

several desktop icons

And I will search for the last one (I'm still wondering what this file is):

some file icon

You can clearly see what is most likely to be the match:

image displaying average colors in regions

In different situations, this may not work. However when image size is given, it should be pretty reliable and lightning fast.

I can get a screenshot as

BufferedImage
object:

MSWindow window = MSWindow.windowFromName("Firefox", false);
BufferedImage img = window.screenshot();
//Or, if I can estimate smaller region for searching:
BufferedImage img2 = window.screenshotCrop(20,20,50,50);


Of course, the image to search image will be loaded from template saved in a file:

BufferedImage img = ImageIO.read(...whatever goes in there, I'm still confused...);


I explained what all I know so that we can focus on the only problem:


  • Q: How can I get average color on buffered image? How can I get such average color on sub-rectangle of that image?



Speed wins here. In this exceptional case, I consider it more valuable than code readability.

k_g k_g
Answer

I think that no matter what you do, you are going to have an O(wh) operation, where w is your width and h is your height.

Therefore, I'm going to post this (naive) solution to fulfil the first part of your question as I do not believe there is a faster solution.

/*
 * Where bi is your image, (x0,y0) is your upper left coordinate, and (w,h)
 * are your width and height respectively
 */
public static Color averageColor(BufferedImage bi, int x0, int y0, int w,
        int h) {
    int x1 = x0 + w;
    int y1 = y0 + h;
    long sumr = 0, sumg = 0, sumb = 0;
    for (int x = x0; x < x1; x++) {
        for (int y = y0; y < y1; y++) {
            Color pixel = new Color(bi.getRGB(x, y));
            sumr += pixel.getRed();
            sumg += pixel.getGreen();
            sumb += pixel.getBlue();
        }
    }
    int num = w * h;
    return new Color(sumr / num, sumg / num, sumb / num);
}