Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

496
LINES

< > BotCompany Repo | #1000552 // Magnets (v4, with edge diffs)

JavaX source code - run with: x30.jar

1  
!636
2  
3  
import java.awt.*;
4  
import java.awt.image.*;
5  
import javax.imageio.*;
6  
import static java.lang.Math.*;
7  
8  
!standard functions
9  
!image classes
10  
!FrameWithImages
11  
!quicknew
12  
!* ctr
13  
!721 // thread {
14  
15  
class P { double x, y; *(double *x, double *y) {} }
16  
17  
interface Reproducer {
18  
  public main.Params reproduce(RGBImage original);
19  
}
20  
  
21  
interface ReproducerMaker {
22  
  public Reproducer make();
23  
}
24  
25  
main {
26  
  static Object androidContext;
27  
  static int imageWidth = 200;
28  
  static double pixelDiffThreshold = 0.1;
29  
  
30  
  !include #1000522 // helper functions for image reproduction
31  
  
32  
  static double pi = PI;
33  
  
34  
  static double rotate_x(P p, double angle) {
35  
    angle = angle*pi/180;
36  
    return p.x*cos(angle)-p.y*sin(angle);
37  
  }
38  
  
39  
  static double sideshiftlimit = sqrt(2)/2;
40  
    
41  
  static class Magnet extends Params {
42  
    double angle, sideshift;
43  
    RGB col1 = new RGB(Color.black), col2 = new RGB(Color.white);
44  
    double p1 = -1, p2 = -1;
45  
    
46  
    RGB def(double x, double y) {
47  
      P p = new P(x-0.5, y-0.5);
48  
      x = rotate_x(p, -angle);
49  
      return x < sideshift ? col1 : col2;
50  
    }
51  
    
52  
    Magnet copy() {
53  
      new Magnet p;
54  
      baseClone(p);
55  
      p.sideshift = sideshift;
56  
      p.angle = angle;
57  
      p.col1 = col1;
58  
      p.col2 = col2;
59  
      return p;
60  
    }
61  
    
62  
    public String toString() {
63  
      return "M " + formatDouble(sideshift, 2) + " " + (int) angle + " " + col1 + " " + col2;
64  
    }
65  
66  
    RGBImage render() {
67  
      int w = w(), h = h();
68  
      RGBImage image = new RGBImage(w, h, Color.white);
69  
      paint(image, this);
70  
      /*getP1P2();
71  
      image.setPixel(Math.min(w-1, (int) ptox(p1)), Math.min(h-1, (int) ptoy(p1)), Color.red);
72  
      image.setPixel(Math.min(w-1, (int) ptox(p2)), Math.min(h-1, (int) ptoy(p2)), Color.red);*/
73  
      return image;
74  
    }
75  
    
76  
    RGBImage renderWithHints() {
77  
      RGBImage image = new RGBImage(getImage());
78  
      image.setPixel(0, 0, Color.red);
79  
      image.setPixel(w()-1, 0, Color.red);
80  
      image.setPixel(0, h()-1, Color.red);
81  
      image.setPixel(w()-1, h()-1, Color.red);
82  
      return image;
83  
    }
84  
    
85  
    double ptox(double i) {
86  
      int w = original.getWidth();
87  
      return i < w ? i : i < 2*w ? w : i < 3*w ? w-(i-2*w) : 0;
88  
    }
89  
    
90  
    double ptoy(double i) {
91  
      int w = original.getWidth();
92  
      return i < w ? 0 : i < 2*w ? i-w : i < 3*w ? w : w-(i-3*w);
93  
    }
94  
    
95  
    void getP1P2() {
96  
      if (p2 != -1) return;
97  
      int w = original.getWidth();
98  
      if (w != original.getHeight()) fail("not a square");
99  
      RGB last = null;
100  
      for (int i = 0; i < 4*w; i++) {
101  
        double x = ptox(i);
102  
        double y = ptoy(i);
103  
        RGB col = def(x/w, y/w);
104  
        if (last == null) last = col;
105  
        else if (!col.equals(last))
106  
          if (p1 == -1) p1 = i; else p2 = i;
107  
      }
108  
      if (p1 != -1 && p2 == -1) p2 = 0;
109  
      if (p1 == -1) p1 = 0;
110  
    }
111  
  }
112  
113  
  static abstract class Params {
114  
    RGBImage original;
115  
    abstract RGBImage render();
116  
    abstract Params copy();
117  
    
118  
    int w() { return original.getWidth(); }
119  
    int h() { return original.getHeight(); }
120  
    
121  
    RGBImage renderWithHints() {
122  
      return getImage();
123  
    }
124  
    
125  
    void baseClone(Params p) {
126  
      p.original = original;
127  
    }
128  
    
129  
    RGBImage rendered;
130  
    RGBImage getImage() {
131  
      if (rendered == null)
132  
        rendered = render();
133  
      return rendered;
134  
    }
135  
    
136  
    double score = 2.0;
137  
    double getScore() {
138  
      if (score == 2.0)
139  
        score = calcScore();
140  
      return score;
141  
    }
142  
    
143  
    double calcScore() {
144  
      return diff(original, getImage());
145  
    }
146  
    
147  
    boolean isBetterThan(Params p) {
148  
      return getScore() < p.getScore();
149  
    }
150  
  }
151  
  
152  
  static class RandomMagnet implements Reproducer {
153  
    int n = -1;
154  
    public Params reproduce(RGBImage original) {
155  
      ++n;
156  
      new Magnet p;
157  
      p.original = original;
158  
      p.sideshift = random(-sideshiftlimit, sideshiftlimit);
159  
      p.angle = random()*360;
160  
      if (n % 2 == 0) {
161  
        p.col1 = randomColor();
162  
        p.col2 = randomColor();
163  
      } else {
164  
        p.col1 = probeRandomPixel(original);
165  
        p.col2 = probeRandomPixel(original);
166  
      }
167  
      return p;
168  
    }
169  
  }
170  
  
171  
  static class VaryBest implements Reproducer {
172  
    Reproducer base;
173  
    Params best;
174  
    
175  
    VaryBest(Reproducer base) {
176  
      this.base = base;
177  
    }
178  
    
179  
    public Params reproduce(RGBImage original) {
180  
      Params p = base.reproduce(original);
181  
      if (best == null || p.isBetterThan(best))
182  
        best = p;
183  
      Params variation = vary(best);
184  
      //System.out.println("Best: " + best.getScore() + ", variation: " + variation.getScore());
185  
      if (variation.isBetterThan(best)) {
186  
        //System.out.println("Using variation, diff=" + (best.getScore()-variation.getScore()));
187  
        best = variation;
188  
      }
189  
      return best;
190  
    }
191  
    
192  
    Params vary(Params p) {
193  
      if (p instanceof Magnet) {
194  
        Magnet n = ((Magnet) p).copy();
195  
        int s = random(3);
196  
        if (s == 0) {
197  
          s = random(2);
198  
          if (s == 0)
199  
            n.sideshift = varySideshift(n.sideshift);
200  
          else {
201  
            //double old = n.angle;
202  
            n.angle = (n.angle+360+random(-5, 5)) % 360;
203  
            //System.out.println("angle: " + formatDouble(old, 1) + " -> " + formatDouble(n.angle, 1));
204  
          }
205  
        } else if (s == 1)
206  
          n.col1 = varyColor(n.col1);
207  
        else
208  
          n.col2 = varyColor(n.col2);
209  
        return n;
210  
      }
211  
      
212  
      return null;
213  
    }
214  
    
215  
    double varySideshift(double sideshift) {
216  
      return max(-sideshiftlimit, min(sideshiftlimit, sideshift+random(-0.1, 0.1)));
217  
    }
218  
    
219  
    double varyN(double x) {
220  
      return Math.max(0, Math.min(1, x+random(-0.1, 0.1)));
221  
    }
222  
    
223  
    float varyChannel(float x) {
224  
      return Math.max(0f, Math.min(1f, (float) (x+random(-0.1, 0.1))));
225  
    }
226  
    
227  
    RGB varyColor(RGB rgb) {
228  
      int s = random(3);
229  
      if (s == 0)
230  
        return new RGB(varyChannel(rgb.r), rgb.g, rgb.b);
231  
      else if (s == 1)
232  
        return new RGB(rgb.r, varyChannel(rgb.g), rgb.b);
233  
      else
234  
        return new RGB(rgb.r, rgb.g, varyChannel(rgb.b));
235  
    }
236  
  }
237  
238  
  static class Gridded extends Params {
239  
    int w, h;
240  
    Params[] array;
241  
    
242  
    Gridded(int w, int h) {
243  
      this.w = w;
244  
      this.h = h;
245  
      array = new Params[w*h];
246  
    }
247  
    
248  
    Gridded copy() {
249  
      Gridded p = new Gridded(w, h);
250  
      baseClone(p);
251  
      for (int i = 0; i < w*h; i++)
252  
        p.array[i] = array[i].copy();
253  
      return p;
254  
    }
255  
    
256  
    public String toString() {
257  
      StringBuilder buf = new StringBuilder("grid{");
258  
      for (int i = 0; i < w*h; i++) {
259  
        if (i != 0)
260  
          buf.append(", ");
261  
        buf.append(array[i]);
262  
      }
263  
      return buf + "}";
264  
    }
265  
    
266  
    public RGBImage render() {
267  
      int ow = original.getWidth(), oh = original.getHeight();
268  
      RGBImage img = new RGBImage(ow, oh, Color.white);
269  
      for (int y = 0; y < h; y++)
270  
        for (int x = 0; x < w; x++) {
271  
          int x1 = x*ow/w, y1 = y*oh/h;
272  
          int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h;
273  
          RGBImage part = array[y*w+x].getImage();
274  
          main.copy(part, 0, 0, img, x1, y1, part.getWidth(), part.getHeight());
275  
        }
276  
      return img;
277  
    }
278  
    
279  
    public RGBImage renderPartsWithHints() {
280  
      int ow = original.getWidth(), oh = original.getHeight();
281  
      RGBImage img = new RGBImage(ow, oh, Color.white);
282  
      for (int y = 0; y < h; y++)
283  
        for (int x = 0; x < w; x++) {
284  
          int x1 = x*ow/w, y1 = y*oh/h;
285  
          int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h;
286  
          RGBImage part = array[y*w+x].renderWithHints();
287  
          main.copy(part, 0, 0, img, x1, y1, part.getWidth(), part.getHeight());
288  
        }
289  
      return img;
290  
    }
291  
    
292  
    public RGBImage renderWithHints() {
293  
      /*
294  
      int ow = original.getWidth(), oh = original.getHeight();
295  
      RGBImage img = renderPartsWithHints();
296  
      for (int y = 0; y < h; y++)
297  
        for (int x = 0; x < w; x++) {
298  
          int x1 = x*ow/w, y1 = y*oh/h;
299  
          int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h;
300  
301  
          // paint lr diffs
302  
          if (x < w-1) {
303  
            double[] bla = diffMatchLR(x, y);
304  
            double diff = bla[0];
305  
            int s1 = (int) bla[1], s2 = (int) bla[2];
306  
            if (diff < 1) {
307  
              RGB rgb = new RGB(1.0-diff);
308  
              img.setPixel(x2-1, y1+s1, rgb);
309  
              img.setPixel(x2, y1+s2, rgb);
310  
            }
311  
          }
312  
        }
313  
      return img;
314  
      */
315  
      
316  
      int w = w(), h = h();
317  
      RGBImage rendered = getImage();
318  
      RGBImage img = new RGBImage(w, h, Color.white);
319  
      for (int y = 0; y < h-1; y++)
320  
        for (int x = 0; x < w-1; x++) {
321  
          RGB p = rendered.getPixel(x, y);
322  
          /*
323  
          if (isDifferent(p, rendered.getPixel(x+1, y))
324  
            || isDifferent(p, rendered.getPixel(x, y+1)))
325  
            img.setPixel(x, y, Color.black);
326  
          */
327  
          double diff = max(pixelDiff(p, rendered.getPixel(x+1, y)),
328  
            pixelDiff(p, rendered.getPixel(x, y+1)));
329  
          if (diff >= pixelDiffThreshold)
330  
            img.setPixel(x, y, new RGB(1-diff));
331  
        }
332  
      return img;
333  
    }
334  
    
335  
    boolean isDifferent(RGB a, RGB b) {
336  
      return pixelDiff(a, b) >= pixelDiffThreshold;
337  
    }
338  
    
339  
    double[] diffMatchLR(int x, int y) {
340  
      Params a = array[y*w+x], b = array[y*w+x+1];
341  
      RGBImage i1 = getRenderedRect(a, new Rectangle(a.w()-1, 0, 1, a.h()));
342  
      RGBImage i2 = getRenderedRect(b, new Rectangle(b.w()-1, 0, 1, b.h()));
343  
      int s1 = findSplitPointY(i1), s2 = findSplitPointY(i2);
344  
      
345  
      //if (allOneColor(i1) && allOneColor(i2))
346  
      
347  
      if (s1 < 0 || s2 < 0)
348  
        return new double[] {1, 0, 0};
349  
      else
350  
        return new double[] {diff(i1, i2), s1, s2};
351  
    }
352  
  }
353  
  
354  
  static int findSplitPointY(RGBImage img) {
355  
    RGB col = img.getPixel(0, 0);
356  
    for (int y = 1; y < img.getHeight(); y++)
357  
      if (!img.getPixel(0, y).equals(col))
358  
        return y-1;
359  
    return -1;
360  
  }
361  
  
362  
  static boolean allOneColor(RGBImage img) {
363  
    RGB col = img.getPixel(0, 0);
364  
    for (int y = 0; y < img.getHeight(); y++)
365  
      for (int x = 0; x < img.getWidth(); x++)
366  
        if (!img.getPixel(x, y).equals(col))
367  
          return false;
368  
    return true;
369  
  }
370  
371  
  static RGBImage getRenderedRect(Params p, Rectangle r) {
372  
    return p.getImage().clip(r);
373  
  }
374  
  
375  
  static class Grid implements Reproducer {
376  
    int w, h;
377  
    Reproducer[] bases;
378  
    
379  
    Grid(ReproducerMaker maker, int w, int h) {
380  
      this.w = w;
381  
      this.h = h;
382  
      bases = new Reproducer[w*h];
383  
      for (int i = 0; i < w*h; i++)
384  
        bases[i] = maker.make();
385  
    }
386  
    
387  
    RGBImage getGridElement(RGBImage original, int i) {
388  
      int ow = original.getWidth(), oh = original.getHeight();
389  
      int y = i / w;
390  
      int x = i % w;
391  
      int x1 = x*ow/w, y1 = y*oh/h;
392  
      int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h;
393  
      return original.clip(x1, y1, x2-x1, y2-y1);
394  
    }
395  
      
396  
    public Params reproduce(RGBImage original) {
397  
      Gridded gridded = new Gridded(w, h);
398  
      gridded.original = original;
399  
      for (int i = 0; i < w*h; i++) {
400  
        RGBImage img = getGridElement(original, i);
401  
        Params p = bases[i].reproduce(img);
402  
        if (p == null)
403  
          return null;
404  
        gridded.array[i] = p;
405  
      }
406  
      return gridded;
407  
    }
408  
  }
409  
  
410  
  static ReproducerMaker baseMaker = new ReproducerMaker() {
411  
    public Reproducer make() {
412  
      return new VaryBest(new RandomMagnet());
413  
    }
414  
  };
415  
    
416  
  // main reproduce function
417  
  static Reproducer reproducer;
418  
419  
  static String imageID = "#1000326"; // Bryan Cranston!
420  
  static RGBImage original;
421  
  static FrameWithImages fwi;
422  
    
423  
  psvm {
424  
    if (args.length != 0) imageID = args[0];
425  
    
426  
    fwi = new FrameWithImages(1);
427  
    fwi.setZoom(2);
428  
    fwi.hop();
429  
    
430  
    thread {
431  
      original = loadImage(imageID);
432  
      original = resizeToWidth(original, imageWidth);
433  
      fwi.setInnerSize(original);
434  
      
435  
      int gx = original.getWidth()/8, gy = original.getHeight()/8;
436  
      reproducer = new Grid(baseMaker, gx, gy);
437  
      
438  
      reproduceOpenEnd(original);
439  
    }
440  
    
441  
    /*
442  
    new Magnet m;
443  
    m.sideshift = -0.2;
444  
    m.angle = 30;
445  
    
446  
    while (true) {
447  
      m.angle = (m.angle+1) % 360;
448  
      //System.out.println("Angle: " + m.angle);
449  
      RGBImage img = new RGBImage(100, 100, Color.gray);
450  
      paint(img, m);
451  
      fwi.setImage(0, img);
452  
    }
453  
    */
454  
  }
455  
  
456  
  
457  
  static void reproduceOpenEnd(RGBImage original) {
458  
    Params best = null;
459  
    long lastPrint = 0, lastN = 0;
460  
    for (long ntry = 1; ; ntry++) {
461  
      long now = System.currentTimeMillis();
462  
      if (now >= lastPrint+1000) {
463  
        long tps = (ntry-lastN)*1000/(now-lastPrint);
464  
        lastPrint = now;
465  
        lastN = ntry;
466  
        String s = "Try " + ntry + "(" + tps + "/s)";
467  
        if (best == null)
468  
          System.out.println(s);
469  
        else {
470  
          System.out.println("Best: " + best);
471  
          System.out.println(s + ", score: " + formatDouble(best.getScore()*100, 3) + "%, structure size: " + structureSize(best, Params.class));
472  
        }
473  
      }
474  
      Params p = reproducer.reproduce(original);
475  
      if (best == null || p != null && p.getScore() < best.getScore()) {
476  
        //System.out.println("New best! " + p.getScore());
477  
        best = p;
478  
        fwi.setImage(0, p.renderWithHints());
479  
      }
480  
      
481  
      if (p != null && p.getScore() == 0.0)
482  
        break;
483  
    }
484  
  }
485  
  
486  
  static void paint(RGBImage img, Magnet m) {
487  
    int w = img.getWidth(), h = img.getHeight();
488  
    for (int y = 0; y < h; y++)
489  
      for (int x = 0; x < w; x++) {
490  
        double nx = x/(double)(w-1);
491  
        double ny = y/(double)(h-1);
492  
        img.setPixel(x, y, m.def(nx, ny));
493  
      }
494  
  }
495  
  
496  
}

Author comment

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: 842 / 613
Referenced in: [show references]