Libraryless. Click here for Pure Java version (2543L/17K/54K).
1 | !752 |
2 | |
3 | static RGBImage originalImage; |
4 | static int imageWidth = 200; |
5 | |
6 | !include #1000522 // helper functions for image reproduction |
7 | |
8 | p { |
9 | String imageID = "#1000326"; // Bryan Cranston! |
10 | if (args.length != 0) imageID = args[0]; |
11 | final String _imageID = imageID; |
12 | |
13 | JFrame frame = new JFrame("A JavaX Frame"); |
14 | final new ImageSurface imageSurface; |
15 | frame.add(imageSurface); |
16 | frame.setBounds(100, 100, 300, 300); |
17 | frame.setVisible(true); |
18 | exitOnFrameClose(frame); |
19 | |
20 | thread { |
21 | originalImage = loadImage(_imageID); |
22 | originalImage = resizeToWidth(originalImage, imageWidth); |
23 | reproduceOpenEnd(originalImage, imageSurface); |
24 | } |
25 | } |
26 | |
27 | static abstract class Params { |
28 | RGBImage originalImage; |
29 | abstract RGBImage render(); |
30 | abstract Params copy(); |
31 | |
32 | void baseClone(Params p) { |
33 | p.originalImage = originalImage; |
34 | } |
35 | |
36 | RGBImage rendered; |
37 | RGBImage getImage() { |
38 | if (rendered == null) |
39 | rendered = render(); |
40 | return rendered; |
41 | } |
42 | |
43 | double score = 2.0; |
44 | double getScore() { |
45 | if (score == 2.0) |
46 | score = calcScore(); |
47 | return score; |
48 | } |
49 | |
50 | double calcScore() { |
51 | return diff(originalImage, getImage()); |
52 | } |
53 | |
54 | boolean isBetterThan(Params p) { |
55 | return getScore() < p.getScore(); |
56 | } |
57 | } |
58 | |
59 | static class SlantedSplit extends Params { |
60 | double splitPointL, splitPointR; |
61 | RGB col1, col2; |
62 | boolean swap; |
63 | |
64 | SlantedSplit copy() { |
65 | SlantedSplit p = new SlantedSplit(); |
66 | baseClone(p); |
67 | p.splitPointL = splitPointL; |
68 | p.splitPointR = splitPointR; |
69 | p.col1 = col1; |
70 | p.col2 = col2; |
71 | p.swap = swap; |
72 | return p; |
73 | } |
74 | |
75 | public String toString() { |
76 | return (swap ? "SlantedHSplit " : "SlantedVSplit ") + splitPointL + " " + splitPointR + " " + col1 + " " + col2; |
77 | } |
78 | |
79 | RGBImage render() { |
80 | int w = originalImage.getWidth(), h = originalImage.getHeight(); |
81 | RGBImage image = new RGBImage(w, h, Color.white); |
82 | slantedSplit(image, this); |
83 | return image; |
84 | } |
85 | } |
86 | |
87 | static class Solid extends Params { |
88 | RGB col; |
89 | |
90 | Solid copy() { |
91 | Solid p = new Solid(); |
92 | baseClone(p); |
93 | p.col = col; |
94 | return p; |
95 | } |
96 | |
97 | public String toString() { |
98 | return "Solid " + col; |
99 | } |
100 | |
101 | RGBImage render() { |
102 | int w = originalImage.getWidth(), h = originalImage.getHeight(); |
103 | return new RGBImage(w, h, col); |
104 | } |
105 | } |
106 | |
107 | interface Reproducer { |
108 | public Params reproduce(RGBImage original); |
109 | } |
110 | |
111 | static class RandomSlantedSplit implements Reproducer { |
112 | int n = -1; |
113 | public Params reproduce(RGBImage original) { |
114 | ++n; |
115 | SlantedSplit p = new SlantedSplit(); |
116 | p.swap = random(2) == 0; |
117 | p.originalImage = original; |
118 | p.splitPointL = random(); |
119 | p.splitPointR = random(); |
120 | if (n % 2 == 0) { |
121 | p.col1 = randomColor(); |
122 | p.col2 = randomColor(); |
123 | } else { |
124 | p.col1 = probeRandomPixel(original); |
125 | p.col2 = probeRandomPixel(original); |
126 | } |
127 | return p; |
128 | } |
129 | } |
130 | |
131 | static class RandomSolid implements Reproducer { |
132 | int n = -1; |
133 | public Params reproduce(RGBImage original) { |
134 | ++n; |
135 | Solid p = new Solid(); |
136 | p.originalImage = original; |
137 | if (n % 2 == 0) { |
138 | p.col = randomColor(); |
139 | } else { |
140 | p.col = probeRandomPixel(original); |
141 | } |
142 | return p; |
143 | } |
144 | } |
145 | |
146 | static class VaryBest implements Reproducer { |
147 | Reproducer base; |
148 | Params best; |
149 | |
150 | VaryBest(Reproducer base) { |
151 | this.base = base; |
152 | } |
153 | |
154 | public Params reproduce(RGBImage original) { |
155 | Params p = base.reproduce(original); |
156 | if (best == null || p.isBetterThan(best)) |
157 | best = p; |
158 | Params variation = vary(best); |
159 | //System.out.println("Best: " + best.getScore() + ", variation: " + variation.getScore()); |
160 | if (variation.isBetterThan(best)) { |
161 | //System.out.println("Using variation, diff=" + (best.getScore()-variation.getScore())); |
162 | best = variation; |
163 | } |
164 | return best; |
165 | } |
166 | |
167 | Params vary(Params p) { |
168 | if (p instanceof SlantedSplit) { |
169 | SlantedSplit n = ((SlantedSplit) p).copy(); |
170 | int s = random(3); |
171 | if (s == 0) |
172 | varySplitPoint(n); |
173 | else if (s == 1) |
174 | n.col1 = varyColor(n.col1); |
175 | else |
176 | n.col2 = varyColor(n.col2); |
177 | return n; |
178 | } else if (p instanceof Solid) { |
179 | Solid n = ((Solid) p).copy(); |
180 | n.col = varyColor(n.col); |
181 | return n; |
182 | } |
183 | return null; |
184 | } |
185 | |
186 | void varySplitPoint(SlantedSplit p) { |
187 | if (random(2) == 0) |
188 | p.splitPointL = Math.max(0, Math.min(1, p.splitPointL+random(-0.1, 0.1))); |
189 | else |
190 | p.splitPointR = Math.max(0, Math.min(1, p.splitPointR+random(-0.1, 0.1))); |
191 | } |
192 | |
193 | float varyChannel(float x) { |
194 | return Math.max(0f, Math.min(1f, (float) (x+random(-0.1, 0.1)))); |
195 | } |
196 | |
197 | RGB varyColor(RGB rgb) { |
198 | int s = random(3); |
199 | if (s == 0) |
200 | return new RGB(varyChannel(rgb.r), rgb.g, rgb.b); |
201 | else if (s == 1) |
202 | return new RGB(rgb.r, varyChannel(rgb.g), rgb.b); |
203 | else |
204 | return new RGB(rgb.r, rgb.g, varyChannel(rgb.b)); |
205 | } |
206 | } |
207 | |
208 | static class Alternate implements Reproducer { |
209 | int n = -1; |
210 | Reproducer[] list; |
211 | |
212 | Alternate(Reproducer... list) { |
213 | this.list = list; |
214 | } |
215 | |
216 | public Params reproduce(RGBImage original) { |
217 | ++n; |
218 | return list[n % list.length].reproduce(original); |
219 | } |
220 | } |
221 | |
222 | interface ReproducerMaker { |
223 | public Reproducer make(); |
224 | } |
225 | |
226 | static class Gridded extends Params { |
227 | int w, h; |
228 | Params[] array; |
229 | |
230 | Gridded(int w, int h) { |
231 | this.w = w; |
232 | this.h = h; |
233 | array = new Params[w*h]; |
234 | } |
235 | |
236 | Gridded copy() { |
237 | Gridded p = new Gridded(w, h); |
238 | baseClone(p); |
239 | for (int i = 0; i < w*h; i++) |
240 | p.array[i] = array[i].copy(); |
241 | return p; |
242 | } |
243 | |
244 | public String toString() { |
245 | StringBuilder buf = new StringBuilder("grid{"); |
246 | for (int i = 0; i < w*h; i++) { |
247 | if (i != 0) |
248 | buf.append(", "); |
249 | buf.append(array[i]); |
250 | } |
251 | return buf + "}"; |
252 | } |
253 | |
254 | public RGBImage render() { |
255 | int ow = originalImage.getWidth(), oh = originalImage.getHeight(); |
256 | RGBImage img = new RGBImage(ow, oh, Color.white); |
257 | for (int y = 0; y < h; y++) |
258 | for (int x = 0; x < w; x++) { |
259 | int x1 = x*ow/w, y1 = y*oh/h; |
260 | int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h; |
261 | RGBImage part = array[y*w+x].render(); |
262 | main.copy(part, 0, 0, img, x1, y1, part.getWidth(), part.getHeight()); |
263 | } |
264 | return img; |
265 | } |
266 | } |
267 | |
268 | static class Grid implements Reproducer { |
269 | int w, h; |
270 | Reproducer[] bases; |
271 | |
272 | Grid(ReproducerMaker maker, int w, int h) { |
273 | this.w = w; |
274 | this.h = h; |
275 | bases = new Reproducer[w*h]; |
276 | for (int i = 0; i < w*h; i++) |
277 | bases[i] = maker.make(); |
278 | } |
279 | |
280 | RGBImage getGridElement(RGBImage originalImage, int i) { |
281 | int ow = originalImage.getWidth(), oh = originalImage.getHeight(); |
282 | int y = i / w; |
283 | int x = i % w; |
284 | int x1 = x*ow/w, y1 = y*oh/h; |
285 | int x2 = (x+1)*ow/w, y2 = (y+1)*oh/h; |
286 | return originalImage.clip(x1, y1, x2-x1, y2-y1); |
287 | } |
288 | |
289 | public Params reproduce(RGBImage original) { |
290 | Gridded gridded = new Gridded(w, h); |
291 | gridded.originalImage = original; |
292 | for (int i = 0; i < w*h; i++) { |
293 | RGBImage img = getGridElement(original, i); |
294 | Params p = bases[i].reproduce(img); |
295 | if (p == null) |
296 | return null; |
297 | gridded.array[i] = p; |
298 | } |
299 | return gridded; |
300 | } |
301 | } |
302 | |
303 | static ReproducerMaker baseMaker = new ReproducerMaker() { |
304 | public Reproducer make() { |
305 | return new VaryBest( |
306 | new Alternate( |
307 | new RandomSolid(), new RandomSlantedSplit() |
308 | )); |
309 | } |
310 | }; |
311 | |
312 | // main reproduce function |
313 | static Reproducer reproducer = |
314 | new Alternate( |
315 | baseMaker.make(), |
316 | new Grid(baseMaker, 4, 4), |
317 | new Grid(baseMaker, 16, 8) |
318 | ); |
319 | |
320 | static Params reproduce(RGBImage original) { |
321 | int w = original.getWidth(), h = original.getHeight(); |
322 | return reproducer.reproduce(original); |
323 | } |
324 | |
325 | static void reproduceOpenEnd(RGBImage original, ImageSurface imageSurface) { |
326 | Params best = null; |
327 | long lastPrint = 0, lastN = 0; |
328 | for (long ntry = 1; ; ntry++) { |
329 | long now = System.currentTimeMillis(); |
330 | if (now >= lastPrint+1000) { |
331 | long tps = (ntry-lastN)*1000/(now-lastPrint); |
332 | lastPrint = now; |
333 | lastN = ntry; |
334 | String s = "Try " + ntry + " (" + tps + "/s)"; |
335 | if (best == null) |
336 | System.out.println(s); |
337 | else { |
338 | System.out.println("Best: " + best); |
339 | System.out.println(s + ", score: " + formatDouble(best.getScore()*100, 2) + "%, structure size: " + structureSize(best, Params.class)); |
340 | } |
341 | } |
342 | Params p = reproduce(original); |
343 | if (best == null || p != null && p.getScore() < best.getScore()) { |
344 | //System.out.println("New best! " + p.getScore()); |
345 | best = p; |
346 | imageSurface.setImage(p.getImage()); |
347 | } |
348 | |
349 | if (p != null && p.getScore() == 0.0) |
350 | break; |
351 | } |
352 | } |
353 | |
354 | static void slantedSplit(RGBImage img, SlantedSplit p) { |
355 | int w = img.getWidth(), h = img.getHeight(); |
356 | for (int yy = 0; yy < h; yy++) |
357 | for (int xx = 0; xx < w; xx++) { |
358 | double x = ((double) xx)/(w-1); |
359 | double y = ((double) yy)/(h-1); |
360 | if (p.swap) { |
361 | double temp = x; x = y; y = x; |
362 | } |
363 | double splitPoint = mix(p.splitPointL, p.splitPointR, x); |
364 | RGB col = y <= splitPoint ? p.col1 : p.col2; |
365 | img.setPixel(xx, yy, col); |
366 | } |
367 | } |
Began life as a copy of #666
download show line numbers debug dex old transpilations
Travelled to 17 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, qbtsjoyahagl, teubizvjbppd, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #668 |
Snippet name: | Reproducing Heisenberg v8 (slanted lines) |
Eternal ID of this version: | #668/1 |
Text MD5: | 047e0a72771688706b364ff7cc410545 |
Transpilation MD5: | 7601c0de9c41269da6d58cf9be3f07b1 |
Author: | stefan |
Category: | |
Type: | JavaX source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-08-20 15:27:16 |
Source code size: | 9414 bytes / 367 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 764 / 794 |
Referenced in: | [show references] |