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)); } *(BufferedImage img) { this(BWImage(img)); } *(MakesBufferedImage img) { this(toBufferedImage(img)); } *(BWImage img) { w = img.w(); h = 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++; } } } // 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)]; } int get(Pt p) { ret get(p.x, p.y); } 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); } public int getWidth() { ret w; } public int getHeight() { ret h; } // unoptimized public BufferedImage getBufferedImage() { ret scaleDownUsingIntegralImageBW(this, w).getBufferedImage(); } }