final sclass BWIntegralImage implements MakesBufferedImage, IBWIntegralImage { int w, h; int[] data; // 1 entry per pixel ifdef BWIntegralImage_CountAccesses long accesses; endifdef *() {} *(File f) { this(loadImage2(f)); } *(MakesBufferedImage img) { this(toBufferedImage(img)); } //*(BufferedImage img) { this(BWImage(img)); } *(BufferedImage image) ctex { alloc(image.getWidth(), image.getHeight()); // Just grab directly into data array PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, w, h, data, 0, w); if (!pixelGrabber.grabPixels()) fail("Could not grab pixels"); int sum = 0; for x to w: { int packed = data[i]; int r = ((packed >> 16) & 0xFF); int g = ((packed >> 8) & 0xFF); int b = (packed & 0xFF); int brightness = (r+g+b+1)/3; data[x] = (sum += brightness); } int i = w; for (int y = 1; y < h; y++) { int sum = 0; for x to w: { int packed = data[i]; int r = ((packed >> 16) & 0xFF); int g = ((packed >> 8) & 0xFF); int b = (packed & 0xFF); int brightness = (r+g+b+1)/3; sum += brightness; data[i] = sum + data[i-w]; i++; } } } *(BWImage img) { alloc(img.w(), img.h()); data = new int[w*h]; int i = 0; for y to h: { int sum = 0; for x to w: { sum += img.getByte(x, y) & 0xFF; data[i] = y > 0 ? sum + data[i-w] : sum; i++; } } } private void alloc(int w, int h) { this.w = w; this.h = h; if (w*h > 8*1024*1024) fail("Image too large (more than 8 MP): " + w + "*" + h); data = new int[w*h]; } // pixels outside of image are considered black int get(int x, int y) { ifdef BWIntegralImage_CountAccesses ++accesses; endifdef ret x < 0 || y < 0 || x >= w || y >= h ? 0 : data[min(y, h-1)*w+min(x, w-1)]; } public double getPixelAverage(int x1, int y1, int x2, int y2) { int area = (x2-x1)*(y2-y1); ret doubleRatio(bwIntegralImage_sumRect(this, x1, y1, x2, y2), area); } int getPixel(int x, int y) { ret bwIntegralImage_sumRect(this, x, y, x+1, y+1); } int getPixel(Pt p) { ret getPixel(p.x, p.y); } public int getWidth() { ret w; } public int getHeight() { ret h; } // unoptimized public BufferedImage getBufferedImage() { ret scaleDownUsingIntegralImageBW(this, w).getBufferedImage(); } }