sclass IntegralImage implements MakesBufferedImage { int w, h; int[] data; // 3 ints per pixel *() {} *(BufferedImage img) { this(RGBImage(img)); } *(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; } } } // gets the integral value at x/y for given RGB channel int get(int x, int y, int channel) { ret x < 0 || y < 0 || x >= w || y >= h ? 0 : data[(y*w+x)*3+channel]; } // gets sum of the 3 channels int get(int x, int y) { if (x < 0 || y < 0 || x >= w || y >= h) ret 0; int i = (y*w+x)*3; ret data[i]+data[i+1]+data[i+2]; } // extracts a pixel int getPixel(int x, int y) { ret integralImage_sumRect(this, x, y, x+1, y+1); } double averageBrightness() { ret doubleRatio(get(w-1, h-1), w*h*3*255.0); } toString { ret "IntegralImage " + w + "*" + h + ", brightness: " + averageBrightness(); } public BufferedImage getBufferedImage() { bufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) bufferedImage.setRGB(x, y, pixels[y*width+x]); return bufferedImage; } }