!636 import java.awt.*; import java.awt.image.*; import javax.imageio.*; import static java.lang.Math.*; !standard functions !image classes !FrameWithImages !quicknew !* ctr !721 // thread { class P { double x, y; *(double *x, double *y) {} } interface Reproducer { public main.Params reproduce(RGBImage original); } interface ReproducerMaker { public Reproducer make(); } main { static int imageWidth = 200; !include #1000522 // helper functions for image reproduction static double pi = PI; static double rotate_x(P p, double angle) { angle = angle*pi/180; return p.x*cos(angle)-p.y*sin(angle); } static class Magnet extends Params { double cx, cy, angle; RGB col1 = new RGB(Color.black), col2 = new RGB(Color.white); RGB def(double x, double y) { P p = new P(x-cx, y-cy); x = rotate_x(p, -angle); return x < 0 ? col1 : col2; } Magnet copy() { new Magnet p; baseClone(p); p.cx = cx; p.cy = cy; p.angle = angle; p.col1 = col1; p.col2 = col2; return p; } public String toString() { return "M " + formatDouble(cx, 2) + " " + formatDouble(cy, 2) + " " + (int) angle + " " + col1 + " " + col2; } RGBImage render() { int w = originalImage.getWidth(), h = originalImage.getHeight(); RGBImage image = new RGBImage(w, h, Color.white); paint(image, this); return image; } } 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 RandomMagnet implements Reproducer { int n = -1; public Params reproduce(RGBImage original) { ++n; new Magnet p; p.originalImage = original; p.cx = random(); p.cy = random(); p.angle = random()*360; if (n % 2 == 0) { p.col1 = randomColor(); p.col2 = randomColor(); } else { p.col1 = probeRandomPixel(original); p.col2 = probeRandomPixel(original); } return p; } } 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 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; } if (p instanceof Magnet) { Magnet n = ((Magnet) p).copy(); int s = random(3); if (s == 0) { s = random(3); if (s == 0) n.cx = varyN(n.cx); else if (s == 1) n.cy = varyN(n.cy); else { //double old = n.angle; n.angle = (n.angle+360+random(-5, 5)) % 360; //System.out.println("angle: " + formatDouble(old, 1) + " -> " + formatDouble(n.angle, 1)); } } else if (s == 1) n.col1 = varyColor(n.col1); else n.col2 = varyColor(n.col2); 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))); } double varyN(double x) { return Math.max(0, Math.min(1, x+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 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 RandomSlantedSplit()); return new VaryBest(new RandomMagnet()); } }; // main reproduce function static Reproducer reproducer; static String imageID = "#1000326"; // Bryan Cranston! static RGBImage originalImage; static FrameWithImages fwi; static double zoom = 1; psvm { for (int i = 0; i < args.length; i++) { String arg = args[i]; if (isSnippetID(arg)) imageID = arg; else if (arg.equals("zoom")) zoom = Double.parseDouble(args[++i]); else if (arg.equals("w") || arg.equals("width")) { String w = args[++i]; imageWidth = w.equals("original") ? -1 : Integer.parseInt(w); } else System.out.println("Unknown argument: " + arg); } fwi = new FrameWithImages(1); fwi.hop(); thread { originalImage = loadImage(imageID); if (imageWidth < 0) imageWidth = originalImage.getWidth(); else originalImage = resizeToWidth(originalImage, imageWidth); fwi.setZoom(zoom); fwi.setInnerSize(originalImage); int gx = originalImage.getWidth()/8, gy = originalImage.getHeight()/8; reproducer = new Grid(baseMaker, gx, gy); reproduceOpenEnd(originalImage); } /* new Magnet m; m.cx = m.cy = 0.5; m.angle = 30; while (true) { m.angle = (m.angle+1) % 360; //System.out.println("Angle: " + m.angle); RGBImage img = new RGBImage(100, 100, Color.gray); paint(img, m); fwi.setImage(0, img); } */ } static void reproduceOpenEnd(RGBImage original) { 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, 3) + "%, structure size: " + structureSize(best, Params.class)); } } Params p = reproducer.reproduce(original); if (best == null || p != null && p.getScore() < best.getScore()) { //System.out.println("New best! " + p.getScore()); best = p; fwi.setImage(0, p.getImage()); } if (p != null && p.getScore() == 0.0) break; } } static void paint(RGBImage img, Magnet m) { int w = img.getWidth(), h = img.getHeight(); for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { double nx = x/(double)(w-1); double ny = y/(double)(h-1); img.setPixel(x, y, m.def(nx, ny)); } } 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); } } }