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

350
LINES

< > BotCompany Repo | #671 // Reproducing 2 Coins

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Uses 3874K of libraries. Click here for Pure Java version (6166L/42K/151K).

!7

static int imageWidth = 200;

static RGBImage originalImage;
static ImageSurface imageSurface;
static JLabel isTitle;

!include #1000522 // helper functions for image reproduction

static abstract class Base {
  abstract Base copy();
  abstract void vary();
}

static abstract class Overlay extends Base {
  abstract Overlay copy();
  abstract void renderOn(RGBImage image);
}

static abstract class Params extends Base {
  RGBImage originalImage;
  abstract Params copy();
  abstract RGBImage render();

  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;
  }
  
  // when object has changed
  double getFreshScore() {
    resetScore();
    return getScore();
  }
  
  void resetScore() {
    score = 2.0;
    rendered = null;
  }
  
  double calcScore() {
    return diff(originalImage, getImage());
  }
  
  boolean isBetterThan(Params p) {
    return getScore() < p.getScore();
  }
}

static class Coin extends Overlay {
  double cx, cy, radius;
  RGB color;

  Coin copy() {
    Coin p = new Coin();
    p.cx = cx;
    p.cy = cy;
    p.radius = radius;
    p.color = color;
    return p;
  }
  
  public String toString() {
    return "Coin " + cx + " " + cy + " " + radius + " " + color;
  }

  void renderOn(RGBImage image) {
    coin(image, this);
  }
  
  void vary() {
    int s = random(4);
    if (s == 0)
      cx = vary01(cx);
    else if (s == 1)
      cy = vary01(cy);
    else if (s == 2)
      radius = vary01(radius);
    else
      color = varyColor(color);
  }
}

static class Solid extends Overlay {
  RGB col;
  
  Solid copy() {
    Solid p = new Solid();
    p.col = col;
    return p;
  }
  
  public String toString() {
    return "Solid " + col;
  }

  void renderOn(RGBImage image) {
    int w = image.getWidth(), h = image.getHeight();
    for (int y = 0; y < h; y++)
      for (int x = 0; x < w; x++)
        image.setPixel(x, y, col);
  }
  
  void vary() {
    col = varyColor(col);
  }
}

interface Reproducer {
  public Params reproduce(RGBImage original);
}

interface OverlayReproducer {
  public Overlay reproduce(RGBImage original);
}

static class RandomCoin implements OverlayReproducer {
  int n = -1;
  public Overlay reproduce(RGBImage original) {
    ++n;
    Coin p = new Coin();
    p.cx = random();
    p.cy = random();
    p.radius = random()*0.2;
    if (n % 2 == 0)
      p.color = randomColor();
    else
      p.color = probeRandomPixel(original);
    return p;
  }
}

static class RandomSolid implements OverlayReproducer {
  int n = -1;
  public Overlay reproduce(RGBImage original) {
    ++n;
    Solid p = new Solid();
    if (n % 2 == 0) {
      p.col = randomColor();
    } else {
      p.col = probeRandomPixel(original);
    }
    return p;
  }
}

static class WhiteSolid implements OverlayReproducer {
  public Overlay reproduce(RGBImage original) {
    Solid p = new Solid();
    p.col = new RGB(Color.white);
    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 = best.copy();
    variation.vary();
    //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;
  }
  
  void reset() {
    best = null;
  }
}

static class Layered extends Params {
  Layers myMaker;
  Overlay[] list;
  
  Layered(Layers myMaker, Overlay[] list) {
    this.myMaker = myMaker;
    this.list = list;
  }
  
  Layered copy() {
    Layered p = new Layered(myMaker, new Overlay[list.length]);
    baseClone(p);
    for (int i = 0; i < list.length; i++)
      p.list[i] = list[i].copy();
    return p;
  }
  
  public String toString() {
    StringBuilder buf = new StringBuilder("layered{");
    for (int i = 0; i < list.length; i++) {
      if (i != 0)
        buf.append(", ");
      buf.append(list[i]);
    }
    return buf + "}";
  }

  RGBImage render() {
    RGBImage image = new RGBImage(originalImage.getWidth(), originalImage.getHeight(), Color.white);
    for (int i = 0; i < list.length; i++)
      list[i].renderOn(image);
    return image;
  }
  
  void vary() {
    int i = random(list.length);
    if (random(2) == 0) {
      //System.out.println("Varying layer " + i);
      list[i].vary();
    } else {
      //double score = getScore();
      OverlayReproducer maker = myMaker.list[i];
      list[i] = maker.reproduce(originalImage);
      //System.out.println("Exchanging layer " + i + " from " + maker + ", improvement: " + (score-getFreshScore()));
    }
    resetScore();
  }
}

static class Layers implements Reproducer {
  OverlayReproducer[] list;
  long ntry = -1;
  int stepTime = 0/*500*/;
  VaryBest varyBest = new VaryBest(this);
  
  Layers(OverlayReproducer... list) {
    this.list = list;
  }
  
  public Params reproduce(RGBImage original) {
    ++ntry;
    int n = this.list.length;
    if (stepTime != 0) {
      // build up image gradually to optimize lower layers first
      n = (int) Math.min(n, ntry/stepTime+1);
      varyBest.reset();
    }
    Overlay[] list = new Overlay[n];
    for (int i = 0; i < n; i++)
      list[i] = this.list[i].reproduce(original);
    Layered result = new Layered(this, list);
    result.originalImage = original;
    return result;
  }
}

// main reproduce function
static Reproducer reproducer =
  /*new VaryBest*/(new Layers(
    /*new RandomSolid()*/new WhiteSolid(),
    new RandomCoin(),
    new RandomCoin()
  )).varyBest;

static Params reproduce(RGBImage original) {
  int w = original.getWidth(), h = original.getHeight();
  return reproducer.reproduce(original);
}

p-substance-thread {
  String imageID = "#1000332"; // Picture of two coins
  if (args.length != 0) imageID = args[0];
  final String _imageID = imageID;
  originalImage = loadImage(_imageID);
  originalImage = resizeToWidth(originalImage, imageWidth);
  
  swing {
    imageSurface = new ImageSurface;
    isTitle = jCenteredLabel("Reproduction");
      
    showPackedFrame(vgrid(
      withCenteredTitle("Original Image", new ImageSurface(originalImage)),
      withTitle(isTitle, imageSurface)));
  }
  
  reproduceOpenEnd(originalImage, imageSurface);
}

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());
      setText(isTitle, print("Reproduction (" + formatDouble(100*(1-p.getScore()), 1) + "%)"));
    }
    
    if (p != null && p.getScore() == 0.0)
      break;
  }
}

static void coin(RGBImage img, Coin p) {
  int w = img.getWidth(), h = img.getHeight();
  double ratio = ((double) w)/h;
  for (int yy = 0; yy < h; yy++) {
    double y = ((double) yy)/(h-1);
    double ybla = Math.abs(y-p.cy)/p.radius;
    if (ybla <= 1) {
      double xbla = Math.sqrt(1-ybla*ybla)/ratio;
      double l = p.cx-xbla*p.radius, r = p.cx+xbla*p.radius;
      int ll = (int) (l*w), rr = (int) (r*w);
      ll = Math.max(0, ll);
      rr = Math.min(w-1, rr);
      for (int xx = ll; xx <= rr; xx++)
        img.setPixel(xx, yy, p.color);
    }
  }
}

Author comment

Began life as a copy of #669

download  show line numbers  debug dex  old transpilations   

Travelled to 16 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, qbtsjoyahagl, teubizvjbppd, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #671
Snippet name: Reproducing 2 Coins
Eternal ID of this version: #671/17
Text MD5: 7875379eb79815532f7e6b97b5b0c9c2
Transpilation MD5: c4cea5ac04af475a769dca57de6422c2
Author: stefan
Category:
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-02-19 13:40:24
Source code size: 8677 bytes / 350 lines
Pitched / IR pitched: No / No
Views / Downloads: 779 / 803
Version history: 16 change(s)
Referenced in: [show references]