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

542
LINES

< > BotCompany Repo | #669 // Reproducing Coins

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

Libraryless. Click here for Pure Java version (1387L/10K/31K).

!636

!629 // standard functions
!658 // image classes

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

public class main {
  static RGBImage originalImage;
  static int imageWidth = 200;
  
  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(),
      new RandomCoin(),
      new RandomCoin(),
      new RandomCoin(),
      new RandomCoin()
    )).varyBest;
  
  static Params reproduce(RGBImage original) {
    int w = original.getWidth(), h = original.getHeight();
    return reproducer.reproduce(original);
  }
  
  public static void main(String[] args) {
    String imageID = "#1000329"; // Picture of some coins
    if (args.length != 0) imageID = args[0];
    final String _imageID = imageID;
    
    JFrame frame = new JFrame("A JavaX Frame");
    
    final ImageSurface imageSurface = new ImageSurface();
    Component panel = imageSurface;
    
    frame.add(panel);
    frame.setBounds(100, 100, 300, 300);
    frame.setVisible(true);
    exitOnFrameClose(frame);
    
    new Thread() {
      public void run() {
        originalImage = loadImage(_imageID);
        originalImage = resizeToWidth(originalImage, imageWidth);
        
        reproduceOpenEnd(originalImage, imageSurface);
      }
    }.start();
  }
  
  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());
      }
      
      if (p != null && p.getScore() == 0.0)
        break;
    }
  }
  
  static RGB probeRandomPixel(RGBImage image) {
    int x = (int) (random()*(image.getWidth()-1));
    int y = (int) (random()*(image.getHeight()-1));
    return image.getPixel(x, y);
  }
  
  static RGB randomColor() {
    return new RGB(random(), random(), random());
  }
  
  static RGBImage resizeToWidth(RGBImage image, int w) {
    return resize(image, w, (int) ((image.getHeight()*(double) w)/image.getWidth()));
  }
  
  public static RGBImage resize(RGBImage image, int w, int h) {
    if (w == image.getWidth() && h == image.getHeight()) return image;

    int[] pixels = new int[w*h];
    for (int y = 0; y < h; y++)
      for (int x = 0; x < w; x++)
        pixels[y*w+x] = image.getInt(x*image.getWidth()/w, y*image.getHeight()/h);
    return new RGBImage(w, h, pixels);
  }

  static boolean useImageCache = true;
  static RGBImage loadImage(String snippetID) {
   try {
    File dir = new File(System.getProperty("user.home"), ".tinybrain/image-cache");
    if (useImageCache) {
      dir.mkdirs();
      File file = new File(dir, snippetID + ".png");
      if (file.exists() && file.length() != 0)
        try {
          return new RGBImage(ImageIO.read(file));
        } catch (Throwable e) {
          e.printStackTrace();
          // fall back to loading from sourceforge
        }
    }

    String imageURL = getImageURL(parseSnippetID(snippetID));
    System.err.println("Loading image: " + imageURL);
    BufferedImage image = ImageIO.read(new URL(imageURL));

    if (useImageCache) {
      File tempFile = new File(dir, snippetID + ".tmp." + System.currentTimeMillis());
      ImageIO.write(image, "png", tempFile);
      tempFile.renameTo(new File(dir, snippetID + ".png"));
      //Log.info("Cached image.");
    }

    //Log.info("Loaded image.");
    return new RGBImage(image);
   } catch (IOException e) {
    throw new RuntimeException(e);
   }
  }

  static String getImageURL(long snippetID) throws IOException {
    String url;
    if (snippetID == 1000010 || snippetID == 1000012)
      url = "http://tinybrain.de:8080/tb/show-blobimage.php?id=" + snippetID;
    else
      url = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + snippetID
        + "&contentType=image/png";
    return url;
  }

  public static long parseSnippetID(String snippetID) {
    return Long.parseLong(shortenSnippetID(snippetID));
  }

  private static String shortenSnippetID(String snippetID) {
    if (snippetID.startsWith("#"))
      snippetID = snippetID.substring(1);
    String httpBlaBla = "http://tinybrain.de/";
    if (snippetID.startsWith(httpBlaBla))
      snippetID = snippetID.substring(httpBlaBla.length());
    return snippetID;
  }
  
  static Random _random = new Random();
  static double random() {
    return _random.nextInt(100001)/100000.0;
  }
  
  static int random(int max) {
    return _random.nextInt(max);
  }
  
  static double random(double min, double max) {
    return min+random()*(max-min);
  }
  
  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);
      }
    }
  }
  
  static double mix(double a, double b, double bishness) {
    return a+(b-a)*bishness;
  }
  
  public static double pixelDiff(RGB a, RGB b) {
    return (Math.abs(a.r-b.r) + Math.abs(a.g-b.g) + Math.abs(a.b-b.b))/3;
  }

  public static double diff(RGBImage image, RGBImage image2) {
    int w = image.getWidth(), h = image.getHeight();
    double sum = 0;
    for (int y = 0; y < h; y++)
      for (int x = 0; x < w; x++)
        sum += pixelDiff(image.getRGB(x, y), image2.getRGB(x, y));
    return sum/(w*h);
  }
  
  public static void copy(RGBImage src, int srcX, int srcY, RGBImage dst, int dstX, int dstY, int w, int h) {
    for (int y = 0; y < h; y++)
      for (int x = 0; x < w; x++)
        dst.setPixel(dstX+x, dstY+y, src.getPixel(srcX+x, srcY+y));
  }
  
  public static int structureSize(Object o, Class baseClass) {
    return structureSize(o, baseClass, new IdentityHashMap());
  }
  
  static int structureSize(Object o, Class baseClass,
    IdentityHashMap seen) {
    if (o == null || seen.containsKey(o)) return 0;
    seen.put(o, Boolean.TRUE);
    int size = 1;
    Class c = o.getClass();
    if (c.isArray()) {
      int n = Array.getLength(o);
      for (int i = 0; i < n; i++)
        size += structureSize(Array.get(o, i), baseClass, seen);
    } else
      while (c != Object.class && c != baseClass) {
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
          if ((field.getModifiers() & Modifier.STATIC) != 0)
            continue;
          if (field.getType().isPrimitive())
            ++size;
          else {
            Object value = null;
            try {
              value = field.get(o);
            } catch (IllegalAccessException e) {
              throw new RuntimeException(e);
            }
            size += structureSize(value, baseClass, seen);
          }
        }
        c = c.getSuperclass();
      }
    return size;
  }
  
  public static String formatDouble(double d, int digits) {
    String format = "0.";
    for (int i = 0; i < digits; i++) format += "#";
    return new java.text.DecimalFormat(format, new java.text.DecimalFormatSymbols(Locale.ENGLISH)).format(d);
  }

  static float varyChannel(float x) {
    return Math.max(0f, Math.min(1f, (float) (x+random(-0.1, 0.1))));
  }
  
  static double vary01(double x) {
    return Math.max(0, Math.min(1, x+random(-0.1, 0.1)));
  }
  
  static 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));
  }
}

Author comment

Began life as a copy of #668

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: #669
Snippet name: Reproducing Coins
Eternal ID of this version: #669/1
Text MD5: 6318af112f75828bdcd43e2deb334681
Transpilation MD5: d925d6b17425472b289b2033e3cdb517
Author: stefan
Category:
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-07-15 14:32:59
Source code size: 15380 bytes / 542 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 813 / 758
Referenced in: [show references]