| 1 | !636 | 
| 2 | !standard functions | 
| 3 | !quicknew | 
| 4 | !ctex | 
| 5 | !* constructor | 
| 6 | |
| 7 | import java.awt.*; | 
| 8 | import java.awt.image.*; | 
| 9 | import java.util.List; | 
| 10 | import javax.imageio.*; | 
| 11 | |
| 12 | !include #2000447 // image classes | 
| 13 | |
| 14 | public class main {
 | 
| 15 | static RGBImage originalImage; | 
| 16 | static int imageWidth = 200; | 
| 17 | |
| 18 | static ImageSurface currentSurface, bestSurface; | 
| 19 | |
| 20 | // XXX - main reproduce function | 
| 21 | static Reproducer reproducer = | 
| 22 | /*new Layers( | 
| 23 | new RandomSolid()) | 
| 24 | .add(2, RandomBox.class) | 
| 25 | .varyBest;*/ | 
| 26 | new OptimizeIndividual(new RandomBox()); | 
| 27 | |
| 28 |   static abstract class Img {
 | 
| 29 | RGBImage img; | 
| 30 | |
| 31 |     *(RGBImage *img) {}
 | 
| 32 | |
| 33 |     int getWidth() { return img.getWidth(); }
 | 
| 34 |     int getHeight() { return img.getHeight(); }
 | 
| 35 | //abstract void setPixel(int x, int y, int rgb); | 
| 36 | |
| 37 |     abstract void setPixel(int x, int y, RGB rgb);/* {
 | 
| 38 | setPixel(x, y, rgb.asInt()); | 
| 39 | }*/ | 
| 40 | } | 
| 41 | |
| 42 |   static class Painting extends Img {
 | 
| 43 |     *(RGBImage img) { super(img); }
 | 
| 44 | |
| 45 |     void setPixel(int x, int y, RGB rgb) {
 | 
| 46 | img.setPixel(x, y, rgb); | 
| 47 | } | 
| 48 | } | 
| 49 | |
| 50 |   static class Diffing extends Img {
 | 
| 51 | int pixelsDiffed; | 
| 52 | double totalDiff; | 
| 53 | |
| 54 |     *(RGBImage img) { super(img); }
 | 
| 55 | |
| 56 | // assumes each pixel is written only once! | 
| 57 |     void setPixel(int x, int y, RGB rgb) {
 | 
| 58 | totalDiff += pixelDiff(img.getPixel(x, y), rgb); | 
| 59 | pixelsDiffed++; | 
| 60 | } | 
| 61 | |
| 62 |     double getScore() {
 | 
| 63 | int totalPixels = img.getWidth()*img.getHeight(); | 
| 64 | int emptyPixels = totalPixels-pixelsDiffed; | 
| 65 | double innerQuality = totalDiff/Math.max(pixelsDiffed, 1); | 
| 66 | double outerQuality = 0.8; // makes objects shrink or grow | 
| 67 | double result = mix(innerQuality, outerQuality, emptyPixels/(double) totalPixels); | 
| 68 |       System.out.println("inner=" + innerQuality + ", outer=" + outerQuality + ", pixels diffed=" + pixelsDiffed + ", result=" + result);
 | 
| 69 | return result; | 
| 70 | } | 
| 71 | } | 
| 72 | |
| 73 |   static abstract class Base {
 | 
| 74 | abstract Base copy(); | 
| 75 | |
| 76 | abstract void vary(); | 
| 77 | |
| 78 |     Base copyVary() {
 | 
| 79 | Base copy = copy(); | 
| 80 | copy.vary(); | 
| 81 | return copy; | 
| 82 | } | 
| 83 | } | 
| 84 | |
| 85 |   static abstract class Overlay extends Base {
 | 
| 86 | abstract Overlay copy(); | 
| 87 | abstract void renderOn(Img image); | 
| 88 | } | 
| 89 | |
| 90 | // Params must be immutable! | 
| 91 |   static abstract class Params extends Base {
 | 
| 92 | RGBImage originalImage; | 
| 93 | abstract Params copy(); | 
| 94 | abstract RGBImage render(); | 
| 95 | |
| 96 |     void baseClone(Params p) {
 | 
| 97 | p.originalImage = originalImage; | 
| 98 | } | 
| 99 | |
| 100 | RGBImage rendered; | 
| 101 |     RGBImage getImage() {
 | 
| 102 | if (rendered == null) | 
| 103 | rendered = render(); | 
| 104 | return rendered; | 
| 105 | } | 
| 106 | |
| 107 | double score = 2.0; | 
| 108 |     double getScore() {
 | 
| 109 | if (score == 2.0) | 
| 110 | score = calcScore(); | 
| 111 | return score; | 
| 112 | } | 
| 113 | |
| 114 |     double calcScore() {
 | 
| 115 | return diff(originalImage, getImage()); | 
| 116 | } | 
| 117 | |
| 118 |     boolean isBetterThan(Params p) {
 | 
| 119 | return getScore() < p.getScore(); | 
| 120 | } | 
| 121 | } | 
| 122 | |
| 123 |   static class Box extends Overlay {
 | 
| 124 | double cx, cy, w, h; | 
| 125 | RGB color; | 
| 126 | |
| 127 |     Box copy() {
 | 
| 128 | Box p = new Box(); | 
| 129 | p.cx = cx; | 
| 130 | p.cy = cy; | 
| 131 | p.w = w; | 
| 132 | p.h = h; | 
| 133 | p.color = color; | 
| 134 | return p; | 
| 135 | } | 
| 136 | |
| 137 |     public String toString() {
 | 
| 138 | return "Box " + cx + " " + cy + " " + w + " " + h + " " + color; | 
| 139 | } | 
| 140 | |
| 141 |     void renderOn(Img image) {
 | 
| 142 | box(image, this); | 
| 143 | } | 
| 144 | |
| 145 |     void vary() {
 | 
| 146 | int s = random(5); | 
| 147 | if (s == 0) | 
| 148 | cx = vary01(cx); | 
| 149 | else if (s == 1) | 
| 150 | cy = vary01(cy); | 
| 151 | else if (s == 2) | 
| 152 | w = vary01(w); | 
| 153 | else if (s == 3) | 
| 154 | h = vary01(h); | 
| 155 | else | 
| 156 | color = varyColor(color); | 
| 157 | } | 
| 158 | } | 
| 159 | |
| 160 |   static class Solid extends Overlay {
 | 
| 161 | RGB col; | 
| 162 | |
| 163 |     *() {}
 | 
| 164 |     *(RGB *col) {}
 | 
| 165 | |
| 166 |     Solid copy() {
 | 
| 167 | new Solid p; | 
| 168 | p.col = col; | 
| 169 | return p; | 
| 170 | } | 
| 171 | |
| 172 |     public String toString() {
 | 
| 173 | return "Solid " + col; | 
| 174 | } | 
| 175 | |
| 176 |     void renderOn(Img image) {
 | 
| 177 | int w = image.getWidth(), h = image.getHeight(); | 
| 178 | for (int y = 0; y < h; y++) | 
| 179 | for (int x = 0; x < w; x++) | 
| 180 | image.setPixel(x, y, col); | 
| 181 | } | 
| 182 | |
| 183 |     void vary() {
 | 
| 184 | col = varyColor(col); | 
| 185 | } | 
| 186 | } | 
| 187 | |
| 188 |   interface Reproducer {
 | 
| 189 | public Params reproduce(RGBImage original); | 
| 190 | } | 
| 191 | |
| 192 |   interface OverlayReproducer {
 | 
| 193 | public Overlay reproduce(RGBImage original); | 
| 194 | } | 
| 195 | |
| 196 |   static class RandomBox implements OverlayReproducer {
 | 
| 197 | int n = -1; | 
| 198 |     public Overlay reproduce(RGBImage original) {
 | 
| 199 | ++n; | 
| 200 | new Box p; | 
| 201 | p.cx = random(); | 
| 202 | p.cy = random(); | 
| 203 | p.w = random()*0.1; | 
| 204 | p.h = random()*0.1; | 
| 205 | if (n % 2 == 0) | 
| 206 | p.color = randomColor(); | 
| 207 | else | 
| 208 | p.color = probeRandomPixel(original); | 
| 209 | return p; | 
| 210 | } | 
| 211 | } | 
| 212 | |
| 213 |   static class RandomSolid implements OverlayReproducer {
 | 
| 214 | int n = -1; | 
| 215 |     public Overlay reproduce(RGBImage original) {
 | 
| 216 | ++n; | 
| 217 | new Solid p; | 
| 218 |       if (n % 2 == 0) {
 | 
| 219 | p.col = randomColor(); | 
| 220 |       } else {
 | 
| 221 | p.col = probeRandomPixel(original); | 
| 222 | } | 
| 223 | return p; | 
| 224 | } | 
| 225 | } | 
| 226 | |
| 227 |   static class WhiteSolid implements OverlayReproducer {
 | 
| 228 |     public Overlay reproduce(RGBImage original) {
 | 
| 229 | Solid p = new Solid(); | 
| 230 | p.col = new RGB(Color.white); | 
| 231 | return p; | 
| 232 | } | 
| 233 | } | 
| 234 | |
| 235 |   static class VaryBest implements Reproducer {
 | 
| 236 | Reproducer base; | 
| 237 | Params best; | 
| 238 | |
| 239 |     VaryBest(Reproducer base) {
 | 
| 240 | this.base = base; | 
| 241 | } | 
| 242 | |
| 243 |     public Params reproduce(RGBImage original) {
 | 
| 244 | Params p = base.reproduce(original); | 
| 245 | if (best == null || p.isBetterThan(best)) | 
| 246 | best = p; | 
| 247 | Params variation = (Params) best.copyVary(); | 
| 248 |       //System.out.println("Best: " + best.getScore() + ", variation: " + variation.getScore());
 | 
| 249 |       if (variation.isBetterThan(best)) {
 | 
| 250 |         //System.out.println("Using variation, diff=" + (best.getScore()-variation.getScore()));
 | 
| 251 | best = variation; | 
| 252 | } | 
| 253 | return best; | 
| 254 | } | 
| 255 | |
| 256 |     void reset() {
 | 
| 257 | best = null; | 
| 258 | } | 
| 259 | } | 
| 260 | |
| 261 |   static class Layered extends Params {
 | 
| 262 | Layers myMaker; | 
| 263 | Overlay[] list; | 
| 264 | |
| 265 |     Layered(Layers myMaker, Overlay... list) {
 | 
| 266 | this.myMaker = myMaker; | 
| 267 | this.list = list; | 
| 268 | } | 
| 269 | |
| 270 |     Layered copy() {
 | 
| 271 | Layered p = new Layered(myMaker, new Overlay[list.length]); | 
| 272 | baseClone(p); | 
| 273 | for (int i = 0; i < list.length; i++) | 
| 274 | p.list[i] = (Overlay) list[i].copy(); | 
| 275 | return p; | 
| 276 | } | 
| 277 | |
| 278 |     public String toString() {
 | 
| 279 |       StringBuilder buf = new StringBuilder("layered{");
 | 
| 280 |       for (int i = 0; i < list.length; i++) {
 | 
| 281 | if (i != 0) | 
| 282 |           buf.append(", ");
 | 
| 283 | buf.append(list[i]); | 
| 284 | } | 
| 285 | return buf + "}"; | 
| 286 | } | 
| 287 | |
| 288 |     RGBImage render() {
 | 
| 289 | RGBImage image = new RGBImage(originalImage.getWidth(), originalImage.getHeight(), Color.white); | 
| 290 | Painting img = new Painting(image); | 
| 291 | for (int i = 0; i < list.length; i++) | 
| 292 | list[i].renderOn(img); | 
| 293 | return image; | 
| 294 | } | 
| 295 | |
| 296 |     void vary() {
 | 
| 297 | int i = random(list.length); | 
| 298 |       if (random(2) == 0 || myMaker == null) {
 | 
| 299 |         //System.out.println("Varying layer " + i);
 | 
| 300 | list[i] = (Overlay) list[i].copyVary(); | 
| 301 |       } else {
 | 
| 302 | //double score = getScore(); | 
| 303 | OverlayReproducer maker = myMaker.list[i]; | 
| 304 | list[i] = maker.reproduce(originalImage); | 
| 305 |         //System.out.println("Exchanging layer " + i + " from " + maker + ", improvement: " + (score-getFreshScore()));
 | 
| 306 | } | 
| 307 | } | 
| 308 | } | 
| 309 | |
| 310 |   static class Layers implements Reproducer {
 | 
| 311 | OverlayReproducer[] list; | 
| 312 | long ntry = -1; | 
| 313 | int stepTime = 0/*500*/; | 
| 314 | VaryBest varyBest = new VaryBest(this); | 
| 315 | |
| 316 |     Layers(OverlayReproducer... list) {
 | 
| 317 | this.list = list; | 
| 318 | } | 
| 319 | |
| 320 |     Layers add(int n, Class<? extends OverlayReproducer> xClass) ctex {
 | 
| 321 | OverlayReproducer l[] = new OverlayReproducer[list.length+n]; | 
| 322 | System.arraycopy(list, 0, l, 0, list.length); | 
| 323 | for (int i = 0; i < n; i++) | 
| 324 | l[list.length+i] = xClass.newInstance(); | 
| 325 | list = l; | 
| 326 | return this; | 
| 327 | } | 
| 328 | |
| 329 |     public Params reproduce(RGBImage original) {
 | 
| 330 | ++ntry; | 
| 331 | int n = this.list.length; | 
| 332 |       if (stepTime != 0) {
 | 
| 333 | // build up image gradually to optimize lower layers first | 
| 334 | n = (int) Math.min(n, ntry/stepTime+1); | 
| 335 | varyBest.reset(); | 
| 336 | } | 
| 337 | Overlay[] list = new Overlay[n]; | 
| 338 | for (int i = 0; i < n; i++) | 
| 339 | list[i] = this.list[i].reproduce(original); | 
| 340 | Layered result = new Layered(this, list); | 
| 341 | result.originalImage = original; | 
| 342 | return result; | 
| 343 | } | 
| 344 | } | 
| 345 | |
| 346 |   static Params reproduce(RGBImage original) {
 | 
| 347 | int w = original.getWidth(), h = original.getHeight(); | 
| 348 | return reproducer.reproduce(original); | 
| 349 | } | 
| 350 | |
| 351 |   static class OptimizeIndividual implements Reproducer {
 | 
| 352 | OverlayReproducer producer; | 
| 353 | double bestScore; | 
| 354 | Overlay best; | 
| 355 | |
| 356 |     *(OverlayReproducer *producer) {}
 | 
| 357 | |
| 358 |     public Params reproduce(RGBImage original) {
 | 
| 359 | Overlay overlay = producer.reproduce(original); | 
| 360 | double score = scoreOverlay(overlay, original); | 
| 361 |       if (best == null || score <= bestScore) {
 | 
| 362 | best = overlay; | 
| 363 | bestScore = score; | 
| 364 | } | 
| 365 | Layered result = new Layered(null, new Solid(new RGB(Color.white)), best); | 
| 366 | result.originalImage = original; | 
| 367 | return result; | 
| 368 | } | 
| 369 | } | 
| 370 | |
| 371 |   static double scoreOverlay(Overlay overlay, RGBImage original) {
 | 
| 372 | Diffing d = new Diffing(original); | 
| 373 | overlay.renderOn(d); | 
| 374 | return d.getScore(); | 
| 375 | } | 
| 376 | |
| 377 |   psvm {
 | 
| 378 | String imageID = "#1000332"; // Picture of two coins | 
| 379 | |
| 380 |     for (int i = 0; i < args.length; i++) {
 | 
| 381 | String arg = args[i]; | 
| 382 |       if (arg.equals("width"))
 | 
| 383 | imageWidth = Integer.parseInt(args[++i]); | 
| 384 | else if (isSnippetID(arg)) | 
| 385 | imageID = arg; | 
| 386 | } | 
| 387 | |
| 388 | final String _imageID = imageID; | 
| 389 | |
| 390 |     JFrame frame = new JFrame("A JavaX Frame");
 | 
| 391 | |
| 392 | JPanel grid = new JPanel(new GridLayout(3, 1)); | 
| 393 | |
| 394 | currentSurface = new ImageSurface(); | 
| 395 | bestSurface = new ImageSurface(); | 
| 396 | final ImageSurface original = new ImageSurface(); | 
| 397 | grid.add(currentSurface); | 
| 398 | grid.add(bestSurface); | 
| 399 | grid.add(original); | 
| 400 | |
| 401 | frame.add(grid); | 
| 402 | frame.setBounds(100, 100, 100+imageWidth+20, 100+600); | 
| 403 | frame.setVisible(true); | 
| 404 | exitOnFrameClose(frame); | 
| 405 | |
| 406 |     new Thread() {
 | 
| 407 |       public void run() {
 | 
| 408 | originalImage = loadImage(_imageID); | 
| 409 | originalImage = resizeToWidth(originalImage, imageWidth); | 
| 410 | original.setImage(originalImage); | 
| 411 | |
| 412 | reproduceOpenEnd(originalImage); | 
| 413 | } | 
| 414 | }.start(); | 
| 415 | } | 
| 416 | |
| 417 |   static void reproduceOpenEnd(RGBImage original) {
 | 
| 418 | Params best = null; | 
| 419 | long lastPrint = 0, lastN = 0; | 
| 420 |     for (long ntry = 1; ; ntry++) {
 | 
| 421 | long now = System.currentTimeMillis(); | 
| 422 |       if (now >= lastPrint+1000) {
 | 
| 423 | long tps = (ntry-lastN)*1000/(now-lastPrint); | 
| 424 | lastPrint = now; | 
| 425 | lastN = ntry; | 
| 426 |         String s = "Try " + ntry + " (" + tps + "/s)";
 | 
| 427 | if (best == null) | 
| 428 | System.out.println(s); | 
| 429 |         else {
 | 
| 430 |           System.out.println("Best: " + best);
 | 
| 431 | System.out.println(s + ", score: " + formatDouble(best.getScore()*100, 2) + "%, structure size: " + structureSize(best, Params.class)); | 
| 432 | } | 
| 433 | } | 
| 434 | Params p = reproduce(original); | 
| 435 | currentSurface.setImage(p.getImage()); | 
| 436 |       if (best == null || p != null && p.getScore() < best.getScore()) {
 | 
| 437 |         //System.out.println("New best! " + p.getScore());
 | 
| 438 | best = p; | 
| 439 | bestSurface.setImage(p.getImage()); | 
| 440 | } | 
| 441 | |
| 442 | if (p != null && p.getScore() == 0.0) | 
| 443 | break; | 
| 444 | } | 
| 445 | } | 
| 446 | |
| 447 |   static void box(Img img, Box p) {
 | 
| 448 | int w = img.getWidth(), h = img.getHeight(); | 
| 449 | double x1 = normalize(p.cx-p.w), x2 = normalize(p.cx+p.w); | 
| 450 | double y1 = normalize(p.cy-p.h), y2 = normalize(p.cy+p.h); | 
| 451 | int xx1 = round(x1*(w-1)), xx2 = round(x2*(w-1)); | 
| 452 | int yy1 = round(y1*(h-1)), yy2 = round(y2*(h-1)); | 
| 453 | |
| 454 | for (int yy = yy1; yy <= yy2; yy++) | 
| 455 | for (int xx = xx1; xx <= xx2; xx++) | 
| 456 | img.setPixel(xx, yy, p.color); | 
| 457 | } | 
| 458 | |
| 459 | !include #1000522 | 
| 460 | } | 
Began life as a copy of #725
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: | #1000528 | 
| Snippet name: | Reproducing with boxes v3 (with individual diffs, developing) | 
| Eternal ID of this version: | #1000528/1 | 
| Text MD5: | bb3a28d1ce7e322cbefb1a7897ddd7b7 | 
| Author: | stefan | 
| Category: | |
| Type: | JavaX source code | 
| Public (visible to everyone): | Yes | 
| Archived (hidden from active list): | No | 
| Created/modified: | 2015-08-10 17:39:43 | 
| Source code size: | 12332 bytes / 460 lines | 
| Pitched / IR pitched: | No / Yes | 
| Views / Downloads: | 968 / 870 | 
| Referenced in: | [show references] |