!752 static RGBImage originalImage; static int imageWidth = 200; !include #1000522 // helper functions for image reproduction p { String imageID = "#1000326"; // Bryan Cranston! if (args.length != 0) imageID = args[0]; final String _imageID = imageID; JFrame frame = new JFrame("A JavaX Frame"); final new ImageSurface imageSurface; frame.add(imageSurface); frame.setBounds(100, 100, 300, 300); frame.setVisible(true); exitOnFrameClose(frame); thread { originalImage = loadImage(_imageID); originalImage = resizeToWidth(originalImage, imageWidth); reproduceOpenEnd(originalImage, imageSurface); } } static abstract class Params { RGBImage originalImage; abstract RGBImage render(); abstract Params copy(); void baseClone(Params p) { p.originalImage = originalImage; } RGBImage rendered; RGBImage getImage() { if (rendered == null) rendered = render(); return rendered; } double score = 2.0; double getScore() { if (score == 2.0) score = calcScore(); return score; } double calcScore() { return diff(originalImage, getImage()); } boolean isBetterThan(Params p) { return getScore() < p.getScore(); } } static class SlantedSplit extends Params { double splitPointL, splitPointR; RGB col1, col2; boolean swap; SlantedSplit copy() { SlantedSplit p = new SlantedSplit(); baseClone(p); p.splitPointL = splitPointL; p.splitPointR = splitPointR; p.col1 = col1; p.col2 = col2; p.swap = swap; return p; } public String toString() { return (swap ? "SlantedHSplit " : "SlantedVSplit ") + splitPointL + " " + splitPointR + " " + col1 + " " + col2; } RGBImage render() { int w = originalImage.getWidth(), h = originalImage.getHeight(); RGBImage image = new RGBImage(w, h, Color.white); slantedSplit(image, this); return image; } } static class Solid extends Params { RGB col; Solid copy() { Solid p = new Solid(); baseClone(p); p.col = col; return p; } public String toString() { return "Solid " + col; } RGBImage render() { int w = originalImage.getWidth(), h = originalImage.getHeight(); return new RGBImage(w, h, col); } } interface Reproducer { public Params reproduce(RGBImage original); } static class RandomSlantedSplit implements Reproducer { int n = -1; public Params reproduce(RGBImage original) { ++n; SlantedSplit p = new SlantedSplit(); p.swap = random(2) == 0; p.originalImage = original; p.splitPointL = random(); p.splitPointR = random(); if (n % 2 == 0) { p.col1 = randomColor(); p.col2 = randomColor(); } else { p.col1 = probeRandomPixel(original); p.col2 = probeRandomPixel(original); } return p; } } static class RandomSolid implements Reproducer { int n = -1; public Params reproduce(RGBImage original) { ++n; Solid p = new Solid(); p.originalImage = original; if (n % 2 == 0) { p.col = randomColor(); } else { p.col = probeRandomPixel(original); } return p; } } static class VaryBest implements Reproducer { Reproducer base; Params best; VaryBest(Reproducer base) { this.base = base; } public Params reproduce(RGBImage original) { Params p = base.reproduce(original); if (best == null || p.isBetterThan(best)) best = p; Params variation = vary(best); //System.out.println("Best: " + best.getScore() + ", variation: " + variation.getScore()); if (variation.isBetterThan(best)) { //System.out.println("Using variation, diff=" + (best.getScore()-variation.getScore())); best = variation; } return best; } Params vary(Params p) { if (p instanceof SlantedSplit) { SlantedSplit n = ((SlantedSplit) p).copy(); int s = random(3); if (s == 0) varySplitPoint(n); else if (s == 1) n.col1 = varyColor(n.col1); else n.col2 = varyColor(n.col2); return n; } else if (p instanceof Solid) { Solid n = ((Solid) p).copy(); n.col = varyColor(n.col); return n; } return null; } void varySplitPoint(SlantedSplit p) { if (random(2) == 0) p.splitPointL = Math.max(0, Math.min(1, p.splitPointL+random(-0.1, 0.1))); else p.splitPointR = Math.max(0, Math.min(1, p.splitPointR+random(-0.1, 0.1))); } float varyChannel(float x) { return Math.max(0f, Math.min(1f, (float) (x+random(-0.1, 0.1)))); } RGB varyColor(RGB rgb) { int s = random(3); if (s == 0) return new RGB(varyChannel(rgb.r), rgb.g, rgb.b); else if (s == 1) return new RGB(rgb.r, varyChannel(rgb.g), rgb.b); else return new RGB(rgb.r, rgb.g, varyChannel(rgb.b)); } } static class Alternate implements Reproducer { int n = -1; Reproducer[] list; Alternate(Reproducer... list) { this.list = list; } public Params reproduce(RGBImage original) { ++n; return list[n % list.length].reproduce(original); } } interface ReproducerMaker { public Reproducer make(); } static class Gridded extends Params { int w, h; Params[] array; Gridded(int w, int h) { this.w = w; this.h = h; array = new Params[w*h]; } Gridded copy() { Gridded p = new Gridded(w, h); baseClone(p); for (int i = 0; i < w*h; i++) p.array[i] = array[i].copy(); return p; } public String toString() { StringBuilder buf = new StringBuilder("grid{"); for (int i = 0; i < w*h; i++) { if (i != 0) buf.append(", "); buf.append(array[i]); } return buf + "}"; } public RGBImage render() { int ow = originalImage.getWidth(), oh = originalImage.getHeight(); RGBImage img = new RGBImage(ow, oh, Color.white); for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { int x1 = x*ow/w, y1 = y*oh/h; int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h; RGBImage part = array[y*w+x].render(); main.copy(part, 0, 0, img, x1, y1, part.getWidth(), part.getHeight()); } return img; } } static class Grid implements Reproducer { int w, h; Reproducer[] bases; Grid(ReproducerMaker maker, int w, int h) { this.w = w; this.h = h; bases = new Reproducer[w*h]; for (int i = 0; i < w*h; i++) bases[i] = maker.make(); } RGBImage getGridElement(RGBImage originalImage, int i) { int ow = originalImage.getWidth(), oh = originalImage.getHeight(); int y = i / w; int x = i % w; int x1 = x*ow/w, y1 = y*oh/h; int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h; return originalImage.clip(x1, y1, x2-x1, y2-y1); } public Params reproduce(RGBImage original) { Gridded gridded = new Gridded(w, h); gridded.originalImage = original; for (int i = 0; i < w*h; i++) { RGBImage img = getGridElement(original, i); Params p = bases[i].reproduce(img); if (p == null) return null; gridded.array[i] = p; } return gridded; } } static ReproducerMaker baseMaker = new ReproducerMaker() { public Reproducer make() { return new VaryBest( new Alternate( new RandomSolid(), new RandomSlantedSplit() )); } }; // main reproduce function static Reproducer reproducer = new Alternate( baseMaker.make(), new Grid(baseMaker, 4, 4), new Grid(baseMaker, 16, 8) ); static Params reproduce(RGBImage original) { int w = original.getWidth(), h = original.getHeight(); return reproducer.reproduce(original); } static void reproduceOpenEnd(RGBImage original, ImageSurface imageSurface) { Params best = null; long lastPrint = 0, lastN = 0; for (long ntry = 1; ; ntry++) { long now = System.currentTimeMillis(); if (now >= lastPrint+1000) { long tps = (ntry-lastN)*1000/(now-lastPrint); lastPrint = now; lastN = ntry; String s = "Try " + ntry + " (" + tps + "/s)"; if (best == null) System.out.println(s); else { System.out.println("Best: " + best); System.out.println(s + ", score: " + formatDouble(best.getScore()*100, 2) + "%, structure size: " + structureSize(best, Params.class)); } } Params p = reproduce(original); if (best == null || p != null && p.getScore() < best.getScore()) { //System.out.println("New best! " + p.getScore()); best = p; imageSurface.setImage(p.getImage()); } if (p != null && p.getScore() == 0.0) break; } } static void slantedSplit(RGBImage img, SlantedSplit p) { int w = img.getWidth(), h = img.getHeight(); for (int yy = 0; yy < h; yy++) for (int xx = 0; xx < w; xx++) { double x = ((double) xx)/(w-1); double y = ((double) yy)/(h-1); if (p.swap) { double temp = x; x = y; y = x; } double splitPoint = mix(p.splitPointL, p.splitPointR, x); RGB col = y <= splitPoint ? p.col1 : p.col2; img.setPixel(xx, yy, col); } }