尽可能快地获得bufferedimage和bufferedimage部分的平均颜色

时间:2015-01-27 02:56:25

标签: java computer-vision bufferedimage

我正在尝试在图像中找到图像。我这样做是为了桌面自动化。在这一刻,我想要快速,而不是精确。因此,我决定仅根据相同的平均颜色匹配相似的图像。

如果我在桌面上选择了几个图标,例如:

several desktop icons

我将搜索最后一个(我还在想这个文件是什么):

some file icon

您可以清楚地看到最有可能匹配的内容:

image displaying average colors in regions

在不同的情况下,这可能无效。但是,当给出图像大小时,它应该非常可靠且闪电般快。

我可以获得BufferedImage对象的屏幕截图:

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

当然,搜索图像的图像将从保存在文件中的模板中加载:

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

我解释了我所知道的一切,以便我们可以专注于唯一的问题:

  • 问:如何在缓冲图像上获得平均颜色?如何在该图像的子矩形上获得这样的平均颜色?

速度胜利在这里。在这种特殊情况下,我认为它比代码可读性更有价值。

2 个答案:

答案 0 :(得分:5)

我认为无论你做什么,你都会进行O(wh)操作,其中w是你的宽度,h是你的身高。

因此,我会发布这个(天真的)解决方案来完成你问题的第一部分,因为我不相信有更快的解决方案。

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

答案 1 :(得分:1)

有一种恒定时间方法可以找到图像矩形截面的平均颜色,但需要进行线性预处理。在你的情况下这应该没问题。该方法还可用于在3d阵列中找到矩形棱镜的平均值或该问题的任何更高维模拟。我将使用灰度示例,但只需重复该过程即可轻松扩展到3个或更多通道。

假设我们有一个二维数组,我们称之为“img”。

第一步是生成一个相同维度的新数组,其中每个元素包含原始图像中所有值的总和,这些值位于界定该元素的矩形和图像的左上角元素之内。

您可以使用以下方法在线性时间内构建此类图像:

int width = 1920;
int height = 1080;

//source data
int[] img = GrayScaleScreenCapture();
int[] helperImg = int[width * height]

for(int y = 0; y < height; ++y)
{
    for(int x = 0; x < width; ++x)
    {
        int total = img[y * width + x];

        if(x > 0)
        {
            //Add value from the pixel to the left in helperImg
            total += helperImg[y * width + (x - 1)];
        }

        if(y > 0)
        {
            //Add value from the pixel above in helperImg
            total += helperImg[(y - 1) * width + x];
        }

        if(x > 0 && y > 0)
        {
            //Subtract value from the pixel above and to the left in helperImg
            total -= helperImg[(y - 1) * width + (x - 1)];
        }

        helperImg[y * width + x] = total;
    }
}

现在我们可以使用helperImg在常量时间内查找给定矩形img内的所有值的总和:

//Some Rectangle with corners (x0, y0), (x1, y0) , (x0, y1), (x1, y1)
int x0 = 50;
int x1 = 150;
int y0 = 25;
int y1 = 200;

int totalOfRect = helperImg[y1 * width + x1];

if(x0 > 0)
{
    totalOfRect -= helperImg[y1 * width + (x0 - 1)];
}

if(y0 > 0)
{
    totalOfRect -= helperImg[(y0 - 1) * width + x1];
}

if(x0 > 0 && y0 > 0)
{
    totalOfRect += helperImg[(y0 - 1) * width + (x0 - 1)];
}

最后,我们只需将totalOfRect除以矩形区域即可得到平均值:

int rWidth = x1 - x0 + 1;
int rheight = y1 - y0 + 1;

int meanOfRect = totalOfRect / (rWidth * rHeight);