求和区域表(积分图像)返回矩形和的无意义

时间:2015-02-02 00:05:18

标签: java image-processing computer-vision

所以在维基百科上你可以看到一篇描述how summed area table (integral image) works的文章。它是计算机视觉和图像分析中非常重要的一部分。

我正在尝试实施它。这个概念非常简单:

  1. 制作array[imageheight][imagewidth]
  2. 每个数组成员应包含原始图像前后所有像素的总和
  3. 要获得任何矩形的总和,请使用A-B-C+D公式,其中ABCD是此矩形: summed area table sum - wikipedia
  4. 所以我做了这个函数来对BufferedImage上的所有像素求和:

      public static double[][] integralImageGrayscale(BufferedImage image) {
        //Cache width and height in variables
        int w = image.getWidth();
        int h = image.getHeight();
        //Create the 2D array as large as the image is
        //Notice that I use [Y, X] coordinates to comply with the formula
        double integral_image[][] = new double[h][w];
        //Sum to be assigned to the pixels
        double the_sum = 0;
        //Well... the loop
        for (int y = 0; y < h; y++) {
          for (int x = 0; x < w; x++) {
            //Get pixel. It's actually 0xAARRGGBB, so the function should be getARGB
            int pixel = image.getRGB(x, y);
            //Extrapolate color values from the integer 
            the_sum+= ((pixel&0x00FF0000)>>16)+((pixel&0x0000FF00)>>8)+(pixel&0x000000FF);
            integral_image[y][x] = the_sum;
          }
        }
        //Return the array
        return integral_image;
      }
    

    我也做了一个调试功能,它让我觉得它有效:

    normal and integral image
    注意白色区域如何影响图像的总和

    但如果我做这个测试用例:

       //Summed area table (thing is BufferedImage)
       double is[][] = ScreenWatcher.integralImageGrayscale(thing);
       //Sum generated by a normal for loop
       double ss = ScreenWatcher.grayscaleSum(thing);
       //Height of the resulting array
       int ish = is.length;
       //Width of resulting array. Also throws nasty error if something goes wrong
       int isw = is[is.length-1].length;
       //Testing whether different methods give same results
       System.out.println(
           ss +" =? " + 
         //Last "pixel" in integral image must contain the sum of the image
           is[ish-1][isw-1]+" =? "+
         //The "sum over rectangle" with a rectangle that contains whole image
         //     A            B            C              D
           (+is[0][0]  -is[0][isw-1] -is[ish-1][0] +is[ish-1][isw-1])
       );
    

    我得到了一个悲伤的结果:

    1.7471835E7 =? 1.7471835E7 =? 112455.0
    

    有趣的是,纯白图像返回0:

    7650000.0 =? 7650000.0 =? 0.0  - this was 100x100 white image and 765 is 3*255 so everything seems right
    

    我不知道如何深入了解这一点。一切似乎都太清楚了,不能包含错误。所以要么上面的代码中有拼写错误,要么逻辑错误。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

你的问题在这里:

//Extrapolate color values from the integer 
the_sum+= ((pixel&0x00FF0000)>>16)+((pixel&0x0000FF00)>>8)+(pixel&0x000000FF);
integral_image[y][x] = the_sum;

你应该做的是:

int A = (x > 0 && y > 0) ? integral_image[y-1][x-1] : 0;
int B = (x > 0) ? integral_image[y][x-1] : 0;
int C = (y > 0) ? integral_image[y-1][x] : 0;
integral_image[y][x] = - A + B + C
    + ((pixel&0x00FF0000)>>16)+((pixel&0x0000FF00)>>8)+(pixel&0x000000FF);

(没有the_sum变量)。


现在可以使用(minx, miny) -> (maxx, maxy)中的值,在恒定时间内评估图像integral_image部分的总和:

double A = (minx > 0 && miny > 0) ? integral_image[miny-1][minx-1] : 0;
double B = (minx > 0) ? integral_image[maxy][miny-1] : 0;
double C = (miny > 0) ? integral_image[miny-1][maxx] : 0;
double D = integral_image[maxy][maxx];

double sum = A - B - C + D;

请注意,由于最小坐标的包含性,因此使用了minx-1miny-1