// The "direct" implementation of an integral image that just // stores the whole computed matrix in an array // Precision: 8 bit per channel (RGB) // Note: There is a better implementation in MinimalRecognizer (#1032199) with flexible channels including grayscale final sclass IntegralImage implements IIntegralImage { int w, h; int[] data; // 3 ints per pixel *(RGBImage img) { init(img); } void init(RGBImage img) { w = img.w(); h = img.h(); if (longMul(w, h) > 8000000) fail("Image too big: " + w + "*" + h); data = new int[w*h*3]; int i = 0; for y to h: { int sumR = 0, sumG = 0, sumB = 0; for x to w: { int rgb = img.getInt(x, y); sumR += (rgb >> 16) & 0xFF; sumG += (rgb >> 8) & 0xFF; sumB += rgb & 0xFF; data[i] = y > 0 ? sumR + data[i-w*3] : sumR; data[i+1] = y > 0 ? sumG + data[i-w*3+1] : sumG; data[i+2] = y > 0 ? sumB + data[i-w*3+2] : sumB; i += 3; } } } *(MakesBufferedImage img) { if (img cast RGBImage) init(img); else init(toBufferedImage(img)); } *(BufferedImage img) { init(img); } void init(BufferedImage img) { w = img.getWidth(); h = img.getHeight(); if (longMul(w, h) > 8000000) fail("Image too big: " + w + "*" + h); int[] pixels = pixelsOfBufferedImage(img); data = new int[w*h*3]; int i = 0, j = 0, sumR = 0, sumG = 0, sumB = 0; for x to w: { int rgb = pixels[j++]; data[i++] = (sumR += (rgb >> 16) & 0xFF); data[i++] = (sumG += (rgb >> 8) & 0xFF); data[i++] = (sumB += rgb & 0xFF); } for (int y = 1; y < h; y++) { sumR = sumG = sumB = 0; for x to w: { int rgb = pixels[j++]; sumR += (rgb >> 16) & 0xFF; sumG += (rgb >> 8) & 0xFF; sumB += rgb & 0xFF; data[i] = sumR + data[i-w*3]; data[i+1] = sumG + data[i-w*3+1]; data[i+2] = sumB + data[i-w*3+2]; i += 3; } } } // precise version [TO TEST!] public double getIntegralValue(double x, double y, int channel) { int xFloor = ifloor(x), yFloor = ifloor(y); double val = getIntegralValue(xFloor, yFloor, channel); // at integer coordinate? if (xFloor == x && yFloor == y) ret val; // at non-integer coordinate, perform subpixel calculation double val2 = getIntegralValue(xFloor+1, yFloor, channel); double val3 = getIntegralValue(xFloor , yFloor+1, channel); double val4 = getIntegralValue(xFloor+1, yFloor+1, channel); ret blend2D(val, val2, val3, val4, x-xFloor, y-yFloor); } // gets the integral value at x/y for given RGB channel public double getIntegralValue aka get(int x, int y, int channel) { ret x < 0 || y < 0 ? 0 : data[(min(y, h-1)*w+min(x, w-1))*3+channel]; } // gets sum of the 3 channels public double getIntegralValue aka get(int x, int y) { if (x < 0 || y < 0) ret 0; int i = (min(y, h-1)*w+min(x, w-1))*3; ret data[i]+data[i+1]+data[i+2]; } toString { ret "IntegralImage " + w + "*" + h + ", brightness: " + averageBrightness(); } public BufferedImage getBufferedImage() { ret integralImageToBufferedImage(this); } public int getWidth() { ret w; } public int getHeight() { ret h; } // serialization O _serialize() { ret litobjectarray(w, h, data); } static IntegralImage _deserialize(O[] l) { ret IntegralImage((int) l[0], (int) l[1], (int[]) l[2]); } *(int *w, int *h, int[] *data) {} }