// integral image split in 2 vertical stripes so creation is 2-parallel final sclass BWIntegralImage_twoParts implements MakesBufferedImage, IBWIntegralImage { int w, h, th; IBWIntegralImage top, bottom; *() {} *(File f) { this(loadImage2(f)); } *(MakesBufferedImage img) { this(toBufferedImage(img)); } *(BufferedImage image) { this(image, (img, idx) -> BWIntegralImage(img)); } *(BufferedImage image, IF2 makeSubImage) { this(null, image, makeSubImage); } *(ThreadPoolExecutor executor, BufferedImage image, IF2 makeSubImage) ctex { w = image.getWidth(); h = image.getHeight(); th = (h+1)/2; L l = parallelEval(executor, () -> makeSubImage.get(virtualClipBufferedImage(image, 0, 0, w, th), 0), () -> h <= th ? null : makeSubImage.get(virtualClipBufferedImage(image, 0, th, w, h-th), 1) ); top = first(l); bottom = second(l); } public int getIIValue(int x, int y) { ret y < th ? top.getIIValue(x, y) : top.getIIValue(x, th-1) + bottom.getIIValue(x, y-th); } // optimization over default method public int getPixelSum(int x1, int y1, int x2, int y2) { if (y2 <= th) ret top.getPixelSum(x1, y1, x2, y2); if (y1 >= th) ret bottom.getPixelSum(x1, y1-th, x2, y2-th); // rectangle straddles top and bottom stripe //ret bwIntegralImage_sumRect(this, x1, y1, x2, y2); int topLeft = top.getIIValue(x1-1, y1-1); int topRight = top.getIIValue(x2-1, y1-1); int mediumLeft = top.getIIValue(x1-1, th-1); int mediumRight = top.getIIValue(x2-1, th-1); int bottomLeft = bottom.getIIValue(x1-1, y2-th-1); int bottomRight = bottom.getIIValue(x2-1, y2-th-1); ret bottomRight-bottomLeft+mediumRight-mediumLeft+topLeft-topRight; } public int getWidth() { ret w; } public int getHeight() { ret h; } }