!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 Object androidContext; static int imageWidth = 200; static double pixelDiffThreshold = 0.1; !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 double sideshiftlimit = sqrt(2)/2; static class Magnet extends Params { double angle, sideshift; RGB col1 = new RGB(Color.black), col2 = new RGB(Color.white); double p1 = -1, p2 = -1; RGB def(double x, double y) { P p = new P(x-0.5, y-0.5); x = rotate_x(p, -angle); return x < sideshift ? col1 : col2; } Magnet copy() { new Magnet p; baseClone(p); p.sideshift = sideshift; p.angle = angle; p.col1 = col1; p.col2 = col2; return p; } public String toString() { return "M " + formatDouble(sideshift, 2) + " " + (int) angle + " " + col1 + " " + col2; } RGBImage render() { int w = w(), h = h(); RGBImage image = new RGBImage(w, h, Color.white); paint(image, this); /*getP1P2(); image.setPixel(Math.min(w-1, (int) ptox(p1)), Math.min(h-1, (int) ptoy(p1)), Color.red); image.setPixel(Math.min(w-1, (int) ptox(p2)), Math.min(h-1, (int) ptoy(p2)), Color.red);*/ return image; } RGBImage renderWithHints() { RGBImage image = new RGBImage(getImage()); image.setPixel(0, 0, Color.red); image.setPixel(w()-1, 0, Color.red); image.setPixel(0, h()-1, Color.red); image.setPixel(w()-1, h()-1, Color.red); return image; } double ptox(double i) { int w = original.getWidth(); return i < w ? i : i < 2*w ? w : i < 3*w ? w-(i-2*w) : 0; } double ptoy(double i) { int w = original.getWidth(); return i < w ? 0 : i < 2*w ? i-w : i < 3*w ? w : w-(i-3*w); } void getP1P2() { if (p2 != -1) return; int w = original.getWidth(); if (w != original.getHeight()) fail("not a square"); RGB last = null; for (int i = 0; i < 4*w; i++) { double x = ptox(i); double y = ptoy(i); RGB col = def(x/w, y/w); if (last == null) last = col; else if (!col.equals(last)) if (p1 == -1) p1 = i; else p2 = i; } if (p1 != -1 && p2 == -1) p2 = 0; if (p1 == -1) p1 = 0; } } static abstract class Params { RGBImage original; abstract RGBImage render(); abstract Params copy(); int w() { return original.getWidth(); } int h() { return original.getHeight(); } RGBImage renderWithHints() { return getImage(); } void baseClone(Params p) { p.original = original; } 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(original, getImage()); } boolean isBetterThan(Params p) { return getScore() < p.getScore(); } } static class RandomMagnet implements Reproducer { int n = -1; public Params reproduce(RGBImage original) { ++n; new Magnet p; p.original = original; p.sideshift = random(-sideshiftlimit, sideshiftlimit); 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 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 Magnet) { Magnet n = ((Magnet) p).copy(); int s = random(3); if (s == 0) { s = random(2); if (s == 0) n.sideshift = varySideshift(n.sideshift); 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; } double varySideshift(double sideshift) { return max(-sideshiftlimit, min(sideshiftlimit, sideshift+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 = original.getWidth(), oh = original.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].getImage(); main.copy(part, 0, 0, img, x1, y1, part.getWidth(), part.getHeight()); } return img; } public RGBImage renderPartsWithHints() { int ow = original.getWidth(), oh = original.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].renderWithHints(); main.copy(part, 0, 0, img, x1, y1, part.getWidth(), part.getHeight()); } return img; } public RGBImage renderWithHints() { /* int ow = original.getWidth(), oh = original.getHeight(); RGBImage img = renderPartsWithHints(); 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; // paint lr diffs if (x < w-1) { double[] bla = diffMatchLR(x, y); double diff = bla[0]; int s1 = (int) bla[1], s2 = (int) bla[2]; if (diff < 1) { RGB rgb = new RGB(1.0-diff); img.setPixel(x2-1, y1+s1, rgb); img.setPixel(x2, y1+s2, rgb); } } } return img; */ int w = w(), h = h(); RGBImage rendered = getImage(); RGBImage img = new RGBImage(w, h, Color.white); for (int y = 0; y < h-1; y++) for (int x = 0; x < w-1; x++) { RGB p = rendered.getPixel(x, y); /* if (isDifferent(p, rendered.getPixel(x+1, y)) || isDifferent(p, rendered.getPixel(x, y+1))) img.setPixel(x, y, Color.black); */ double diff = max(pixelDiff(p, rendered.getPixel(x+1, y)), pixelDiff(p, rendered.getPixel(x, y+1))); if (diff >= pixelDiffThreshold) img.setPixel(x, y, new RGB(1-diff)); } return img; } boolean isDifferent(RGB a, RGB b) { return pixelDiff(a, b) >= pixelDiffThreshold; } double[] diffMatchLR(int x, int y) { Params a = array[y*w+x], b = array[y*w+x+1]; RGBImage i1 = getRenderedRect(a, new Rectangle(a.w()-1, 0, 1, a.h())); RGBImage i2 = getRenderedRect(b, new Rectangle(b.w()-1, 0, 1, b.h())); int s1 = findSplitPointY(i1), s2 = findSplitPointY(i2); //if (allOneColor(i1) && allOneColor(i2)) if (s1 < 0 || s2 < 0) return new double[] {1, 0, 0}; else return new double[] {diff(i1, i2), s1, s2}; } } static int findSplitPointY(RGBImage img) { RGB col = img.getPixel(0, 0); for (int y = 1; y < img.getHeight(); y++) if (!img.getPixel(0, y).equals(col)) return y-1; return -1; } static boolean allOneColor(RGBImage img) { RGB col = img.getPixel(0, 0); for (int y = 0; y < img.getHeight(); y++) for (int x = 0; x < img.getWidth(); x++) if (!img.getPixel(x, y).equals(col)) return false; return true; } static RGBImage getRenderedRect(Params p, Rectangle r) { return p.getImage().clip(r); } 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 original, int i) { int ow = original.getWidth(), oh = original.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 original.clip(x1, y1, x2-x1, y2-y1); } public Params reproduce(RGBImage original) { Gridded gridded = new Gridded(w, h); gridded.original = 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 RandomMagnet()); } }; // main reproduce function static Reproducer reproducer; static String imageID = "#1000326"; // Bryan Cranston! static RGBImage original; static FrameWithImages fwi; psvm { if (args.length != 0) imageID = args[0]; fwi = new FrameWithImages(1); fwi.setZoom(2); fwi.hop(); thread { original = loadImage(imageID); original = resizeToWidth(original, imageWidth); fwi.setInnerSize(original); int gx = original.getWidth()/8, gy = original.getHeight()/8; reproducer = new Grid(baseMaker, gx, gy); reproduceOpenEnd(original); } /* new Magnet m; m.sideshift = -0.2; 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.renderWithHints()); } 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)); } } }
Began life as a copy of #1000551
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, kmhbujppghqa, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, teubizvjbppd, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1000552 |
Snippet name: | Magnets (v4, with edge diffs) |
Eternal ID of this version: | #1000552/1 |
Text MD5: | 8fd85affd034a9215bd7fb78be676d72 |
Author: | stefan |
Category: | |
Type: | JavaX source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2015-08-12 21:02:00 |
Source code size: | 14123 bytes / 496 lines |
Pitched / IR pitched: | No / Yes |
Views / Downloads: | 841 / 611 |
Referenced in: | #3000189 - Answer for stefanreich(>> t bla) #3000190 - Answer for stefanreich(>> t 20 questions) #3000382 - Answer for ferdie (>> t = 1, f = 0) #3000383 - Answer for funkoverflow (>> t=1, f=0 okay) |