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

484
LINES

< > BotCompany Repo | #726 // Reproducing with boxes v3 (with individual diffs, developing)

JavaX source code - run with: x30.jar

!636
!standard functions
!quicknew
!ctex
!* constructor

import java.awt.*;
import java.awt.image.*;
import java.util.List;
import javax.imageio.*;

!include #2000447 // image classes

public class main {
  static RGBImage originalImage;
  static int imageWidth = 200;
  
  static ImageSurface currentSurface, bestSurface;
  
  // XXX - main reproduce function
  static Reproducer reproducer =
    /*new Layers(
      new RandomSolid())
      .add(2, RandomBox.class)
    .varyBest;*/
    new OptimizeIndividual(new RandomBox());
    
  static abstract class Img {
    RGBImage img;
    
    *(RGBImage *img) {}
    
    int getWidth() { return img.getWidth(); }
    int getHeight() { return img.getHeight(); }
    //abstract void setPixel(int x, int y, int rgb);
    
    abstract void setPixel(int x, int y, RGB rgb);/* {
      setPixel(x, y, rgb.asInt());
    }*/
  }
  
  static class Painting extends Img {
    *(RGBImage img) { super(img); }
    
    void setPixel(int x, int y, RGB rgb) {
      img.setPixel(x, y, rgb);
    }
  }
    
  static class Diffing extends Img {
    int pixelsDiffed;
    double totalDiff;
    double[] diffed;
    
    *(RGBImage img) {
      super(img);
      diffed = new double[img.getWidth()*img.getHeight()];
      for (int i = 0; i < diffed.length; i++) diffed[i] = -1;
    }

    void setPixel(int x, int y, RGB rgb) {
      int w = img.getWidth(), h = img.getHeight();
      if (x < 0 || y < 0 || x >= w || y >= h) return;
      double old = diffed[x+y*w];
      if (old >= 0)
        totalDiff -= old;
      else
        pixelsDiffed++;
      double diff = pixelDiff(img.getPixel(x, y), rgb);
      diffed[x+y*w] = diff;
      totalDiff += diff;
    }
    
    double getScore() {
      int totalPixels = img.getWidth()*img.getHeight();
      int emptyPixels = totalPixels-pixelsDiffed;
      double innerQuality = totalDiff/Math.max(pixelsDiffed, 1);
      double outerQuality = 0.8; // makes objects shrink or grow
      double result = mix(innerQuality, outerQuality, emptyPixels/(double) totalPixels);
      System.out.println("inner=" + innerQuality + ", outer=" + outerQuality + ", pixels diffed=" + pixelsDiffed + ", result=" + result);
      return result;
    }
  }

  static abstract class Base {
    abstract Base copy();
    
    abstract void vary();
    
    Base copyVary() {
      Base copy = copy();
      copy.vary();
      return copy;
    }
  }
  
  static abstract class Overlay extends Base {
    abstract Overlay copy();
    abstract void renderOn(Img image);
  }
  
  // Params must be immutable!
  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;
    }
    
    double calcScore() {
      return diff(originalImage, getImage());
    }
    
    boolean isBetterThan(Params p) {
      return getScore() < p.getScore();
    }
  }
  
  static class Box extends Overlay {
    double cx, cy, w, h;
    RGB color;

    Box copy() {
      Box p = new Box();
      p.cx = cx;
      p.cy = cy;
      p.w = w;
      p.h = h;
      p.color = color;
      return p;
    }
    
    public String toString() {
      return "Box " + cx + " " + cy + " " + w + " " + h + " " + color;
    }

    void renderOn(Img image) {
      box(image, this);
    }
    
    void vary() {
      int s = random(5);
      if (s == 0)
        cx = vary01(cx);
      else if (s == 1)
        cy = vary01(cy);
      else if (s == 2)
        w = vary01(w);
      else if (s == 3)
        h = vary01(h);
      else
        color = varyColor(color);
    }
  }
  
  static class Solid extends Overlay {
    RGB col;
    
    *() {}
    *(RGB *col) {}
    
    Solid copy() {
      new Solid p;
      p.col = col;
      return p;
    }
    
    public String toString() {
      return "Solid " + col;
    }

    void renderOn(Img 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 RandomBox implements OverlayReproducer {
    int n = -1;
    public Overlay reproduce(RGBImage original) {
      ++n;
      new Box p;
      p.cx = random();
      p.cy = random();
      p.w = random()*0.1;
      p.h = random()*0.1;
      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;
      new Solid p;
      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;
    *(Reproducer *base) {}
    
    public Params reproduce(RGBImage original) {
      Params p = base.reproduce(original);
      if (best == null || p.isBetterThan(best))
        best = p;
      Params variation = (Params) best.copyVary();
      //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] = (Overlay) 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);
      Painting img = new Painting(image);
      for (int i = 0; i < list.length; i++)
        list[i].renderOn(img);
      return image;
    }
    
    void vary() {
      int i = random(list.length);
      if (random(2) == 0 || myMaker == null) {
        //System.out.println("Varying layer " + i);
        list[i] = (Overlay) list[i].copyVary();
      } 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()));
      }
    }
  }

  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;
    }
    
    Layers add(int n, Class<? extends OverlayReproducer> xClass) ctex {
      OverlayReproducer l[] = new OverlayReproducer[list.length+n];
      System.arraycopy(list, 0, l, 0, list.length);
      for (int i = 0; i < n; i++)
        l[list.length+i] = xClass.newInstance();
      list = l;
      return this;
    }
    
    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;
    }
  }
  
  static Params reproduce(RGBImage original) {
    int w = original.getWidth(), h = original.getHeight();
    return reproducer.reproduce(original);
  }
  
  static class OptimizeIndividual implements Reproducer {
    OverlayReproducer producer;
    double bestScore;
    Overlay best;
    
    *(OverlayReproducer *producer) {}

    public Params reproduce(RGBImage original) {
      Overlay overlay = producer.reproduce(original);
      System.out.println("overlay: " + overlay);
      double score = scoreOverlay(overlay, original);
      if (best == null || score <= bestScore) {
        best = overlay;
        bestScore = score;
      }
      Layered result = new Layered(null, new Solid(new RGB(Color.black)), best);
      result.originalImage = original;
      return result;
    }
  }
  
  static double scoreOverlay(Overlay overlay, RGBImage original) {
    Diffing d = new Diffing(original);
    overlay.renderOn(d);
    return d.getScore();
  }
  
  static class HoldBest implements Reproducer {
    Reproducer base;
    Params best;
    *(Reproducer *base) {}
    
    public Params reproduce(RGBImage original) {
      Params p = base.reproduce(original);
      if (best == null || p.isBetterThan(best))
        best = p;
      return best;
    }
  }

  psvm {
    String imageID = "#1000332"; // Picture of two coins
    
    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.equals("width"))
        imageWidth = Integer.parseInt(args[++i]);
      else if (isSnippetID(arg))
        imageID = arg;
    }
    
    final String _imageID = imageID;
    
    JFrame frame = new JFrame("A JavaX Frame");
    
    JPanel grid = new JPanel(new GridLayout(3, 1));
    
    currentSurface = new ImageSurface();
    bestSurface = new ImageSurface();
    final ImageSurface original = new ImageSurface();
    grid.add(currentSurface);
    grid.add(bestSurface);
    grid.add(original);
    
    frame.add(grid);
    frame.setBounds(100, 100, 100+imageWidth+20, 100+600);
    frame.setVisible(true);
    exitOnFrameClose(frame);
    
    new Thread() {
      public void run() {
        originalImage = loadImage(_imageID);
        originalImage = resizeToWidth(originalImage, imageWidth);
        original.setImage(originalImage);
        
        reproduceOpenEnd(originalImage);
      }
    }.start();
  }
  
  static void reproduceOpenEnd(RGBImage original) {
    //Params best = null;
    long lastPrint = 0, lastN = 0;
    for (long ntry = 1; ; ntry++) {
      Params p = reproduce(original);
      currentSurface.setImage(p.getImage());
      
      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(p.getScore()*100, 2) + "%, structure size: " + structureSize(p, Params.class));
        //}
      }
      /*if (best == null || p != null && p.getScore() < best.getScore()) {
        //System.out.println("New best! " + p.getScore());
        best = p;
        bestSurface.setImage(p.getImage());
      }*/
      
      if (p != null && p.getScore() == 0.0)
        break; // perfect result, end
    }
  }
  
  static void box(Img img, Box p) {
    int w = img.getWidth(), h = img.getHeight();
    double x1 = normalize(p.cx-p.w), x2 = normalize(p.cx+p.w);
    double y1 = normalize(p.cy-p.h), y2 = normalize(p.cy+p.h);
    int xx1 = round(x1*(w-1)), xx2 = round(x2*(w-1));
    int yy1 = round(y1*(h-1)), yy2 = round(y2*(h-1));
    
    for (int yy = yy1; yy <= yy2; yy++)
      for (int xx = xx1; xx <= xx2; xx++)
        img.setPixel(xx, yy, p.color);
  }
  
  !include #1000522  
}

Author comment

Began life as a copy of #1000528

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #726
Snippet name: Reproducing with boxes v3 (with individual diffs, developing)
Eternal ID of this version: #726/1
Text MD5: 6a084a6b5cedeeb023ad88ac7385cc84
Author: stefan
Category:
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-08-10 17:53:16
Source code size: 13065 bytes / 484 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 610 / 558
Referenced in: [show references]