!752 p { BWImage img = shootScreenBW(); print(go(img)); setFrameTitle("g = " + g, showImageWithSelections(img.getBufferedImage(), clips)); g = 3; print(go(img)); setFrameTitle("g = " + g, showImageWithSelections(img.getBufferedImage(), clips)); } static L clips; static int[] grid; static int gw, gh; static int g = 4; static Rect fill(int x, int y, Rect r) { if (x < 0 || y < 0 || x >= gw || y >= gh) return r; int idx = y*gw+x; if (grid[idx] == 0) return r; grid[idx] = 0; Rect me = new Rect(x, y, 1, 1); if (r == null) r = me; else r = rectUnion(r, me); r = fill(x-1, y, r); r = fill(x+1, y, r); r = fill(x, y-1, r); r = fill(x, y+1, r); return r; } static S go(BWImage img) { int w = img.getWidth(), h = img.getHeight(); gw = w/g; gh = h/g; // width & height of grid grid = new int[gw*gh]; for (int gy = 0; gy <= h- g; gy += g) next: for (int gx = 0; gx <= w- g; gx += g) { float min = 1, max = 0; for (int y = gy; y < gy + g; y++) for (int x = gx; x < gx + g; x++) { float b = img.getPixel(x, y); min = Math.min(min, b); max = Math.max(max, b); if (min < 0.5 && max > 0.5) { grid[(gy / g) * gw + (gx / g)] = 2; continue next; } } } new L result; clips = new L; for (int y = 0; y < gh; y++) for (int x = 0; x < gw; x++) { Rect r = fill(x, y, null); if (r != null) { r = scaleRect(r, g); clips.add(r); r = autoCropOfBWImage(img, r); BWImage cropped = img.clip(r); String hash = md5OfBWImage(cropped); result.add(r + " -> " + hash); } } return "Floodfill: " + join("|", result); }