1 | !636 |
2 | !629 // standard functions |
3 | !658 // image classes |
4 | |
5 | import java.awt.*; |
6 | import java.awt.image.*; |
7 | import java.util.List; |
8 | import javax.imageio.*; |
9 | |
10 | public class main { |
11 | static RGBImage originalImage; |
12 | |
13 | static abstract class Params { |
14 | abstract RGBImage render(); |
15 | abstract Params copy(); |
16 | |
17 | RGBImage rendered; |
18 | RGBImage getImage() { |
19 | if (rendered == null) |
20 | rendered = render(); |
21 | return rendered; |
22 | } |
23 | |
24 | double score = 2.0; |
25 | double getScore() { |
26 | if (score == 2.0) |
27 | score = calcScore(); |
28 | return score; |
29 | } |
30 | |
31 | double calcScore() { |
32 | return diff(originalImage, getImage()); |
33 | } |
34 | |
35 | boolean isBetterThan(Params p) { |
36 | return getScore() < p.getScore(); |
37 | } |
38 | } |
39 | |
40 | static class VSplit extends Params { |
41 | double splitPoint; |
42 | RGB col1, col2; |
43 | |
44 | VSplit copy() { |
45 | VSplit p = new VSplit(); |
46 | p.splitPoint = splitPoint; |
47 | p.col1 = col1; |
48 | p.col2 = col2; |
49 | return p; |
50 | } |
51 | |
52 | public String toString() { |
53 | return "VSplit " + splitPoint + " " + col1 + " " + col2; |
54 | } |
55 | |
56 | RGBImage render() { |
57 | int w = originalImage.getWidth(), h = originalImage.getHeight(); |
58 | RGBImage image = new RGBImage(w, h, Color.white); |
59 | vsplit(image, this); |
60 | return image; |
61 | } |
62 | } |
63 | |
64 | static class Solid extends Params { |
65 | RGB col; |
66 | |
67 | Solid copy() { |
68 | Solid p = new Solid(); |
69 | p.col = col; |
70 | return p; |
71 | } |
72 | |
73 | public String toString() { |
74 | return "Solid " + col; |
75 | } |
76 | |
77 | RGBImage render() { |
78 | int w = originalImage.getWidth(), h = originalImage.getHeight(); |
79 | return new RGBImage(w, h, col); |
80 | } |
81 | } |
82 | |
83 | interface Reproducer { |
84 | public Params reproduce(RGBImage original); |
85 | } |
86 | |
87 | static class RandomVSplit implements Reproducer { |
88 | int n = -1; |
89 | public Params reproduce(RGBImage original) { |
90 | ++n; |
91 | VSplit p = new VSplit(); |
92 | p.splitPoint = random(); |
93 | if (n % 2 == 0) { |
94 | p.col1 = randomColor(); |
95 | p.col2 = randomColor(); |
96 | } else { |
97 | p.col1 = probeRandomPixel(original); |
98 | p.col2 = probeRandomPixel(original); |
99 | } |
100 | return p; |
101 | } |
102 | } |
103 | |
104 | static class RandomSolid implements Reproducer { |
105 | int n = -1; |
106 | public Params reproduce(RGBImage original) { |
107 | ++n; |
108 | Solid p = new Solid(); |
109 | if (n % 2 == 0) { |
110 | p.col = randomColor(); |
111 | } else { |
112 | p.col = probeRandomPixel(original); |
113 | } |
114 | return p; |
115 | } |
116 | } |
117 | |
118 | static class VaryBest implements Reproducer { |
119 | Reproducer base; |
120 | Params best; |
121 | |
122 | VaryBest(Reproducer base) { |
123 | this.base = base; |
124 | } |
125 | |
126 | public Params reproduce(RGBImage original) { |
127 | Params p = base.reproduce(original); |
128 | if (best == null || p.isBetterThan(best)) |
129 | best = p; |
130 | Params variation = vary(best); |
131 | System.out.println("Best: " + best.getScore() + ", variation: " + variation.getScore()); |
132 | if (variation.isBetterThan(best)) { |
133 | System.out.println("Using variation, diff=" + (best.getScore()-variation.getScore())); |
134 | best = variation; |
135 | } |
136 | return best; |
137 | } |
138 | |
139 | Params vary(Params p) { |
140 | if (p instanceof VSplit) { |
141 | VSplit n = ((VSplit) p).copy(); |
142 | int s = random(3); |
143 | if (s == 0) |
144 | varySplitPoint(n); |
145 | else if (s == 1) |
146 | n.col1 = varyColor(n.col1); |
147 | else |
148 | n.col2 = varyColor(n.col2); |
149 | return n; |
150 | } else if (p instanceof Solid) { |
151 | Solid n = ((Solid) p).copy(); |
152 | n.col = varyColor(n.col); |
153 | return n; |
154 | } |
155 | return null; |
156 | } |
157 | |
158 | void varySplitPoint(VSplit p) { |
159 | p.splitPoint = Math.max(0, Math.min(1, p.splitPoint+random(-0.1, 0.1))); |
160 | } |
161 | |
162 | float varyChannel(float x) { |
163 | return Math.max(0f, Math.min(1f, (float) (x+random(-0.1, 0.1)))); |
164 | } |
165 | |
166 | RGB varyColor(RGB rgb) { |
167 | int s = random(3); |
168 | if (s == 0) |
169 | return new RGB(varyChannel(rgb.r), rgb.g, rgb.b); |
170 | else if (s == 1) |
171 | return new RGB(rgb.r, varyChannel(rgb.g), rgb.b); |
172 | else |
173 | return new RGB(rgb.r, rgb.g, varyChannel(rgb.b)); |
174 | } |
175 | } |
176 | |
177 | static class Alternate implements Reproducer { |
178 | int n = -1; |
179 | Reproducer[] list; |
180 | |
181 | Alternate(Reproducer... list) { |
182 | this.list = list; |
183 | } |
184 | |
185 | public Params reproduce(RGBImage original) { |
186 | ++n; |
187 | return list[n % list.length].reproduce(original); |
188 | } |
189 | } |
190 | |
191 | // main reproduce function |
192 | static Reproducer reproducer = new VaryBest( |
193 | new Alternate( |
194 | new RandomSolid(), new RandomVSplit() |
195 | )); |
196 | |
197 | static Params reproduce(RGBImage original, int ntry) { |
198 | int w = original.getWidth(), h = original.getHeight(); |
199 | return reproducer.reproduce(original); |
200 | } |
201 | |
202 | public static void main(String[] args) { |
203 | String imageID = "#1000326"; // Bryan Cranston! |
204 | if (args.length != 0) imageID = args[0]; |
205 | final String _imageID = imageID; |
206 | |
207 | JFrame frame = new JFrame("A JavaX Frame"); |
208 | |
209 | final ImageSurface imageSurface = new ImageSurface(); |
210 | Component panel = imageSurface; |
211 | |
212 | frame.add(panel); |
213 | frame.setBounds(100, 100, 500, 400); |
214 | frame.setVisible(true); |
215 | exitOnFrameClose(frame); |
216 | |
217 | new Thread() { |
218 | public void run() { |
219 | originalImage = loadImage(_imageID); |
220 | originalImage = resizeToWidth(originalImage, 100); |
221 | |
222 | reproduceOpenEnd(originalImage, imageSurface); |
223 | } |
224 | }.start(); |
225 | } |
226 | |
227 | static void reproduceOpenEnd(RGBImage original, ImageSurface imageSurface) { |
228 | Params best = null; |
229 | for (int ntry = 1; ; ntry++) { |
230 | if (best == null) |
231 | System.out.println("Try " + ntry); |
232 | else |
233 | System.out.println("Try " + ntry + ", best: " + best.getScore() + ", " + best); |
234 | Params p = reproduce(original, ntry); |
235 | if (best == null || p != null && p.getScore() < best.getScore()) { |
236 | System.out.println("New best! " + p.getScore()); |
237 | best = p; |
238 | imageSurface.setImage(p.getImage()); |
239 | } |
240 | |
241 | if (p != null && p.getScore() == 0.0) |
242 | break; |
243 | } |
244 | } |
245 | |
246 | static RGB probeRandomPixel(RGBImage image) { |
247 | int x = (int) (random()*(image.getWidth()-1)); |
248 | int y = (int) (random()*(image.getHeight()-1)); |
249 | return image.getPixel(x, y); |
250 | } |
251 | |
252 | static RGB randomColor() { |
253 | return new RGB(random(), random(), random()); |
254 | } |
255 | |
256 | static RGBImage resizeToWidth(RGBImage image, int w) { |
257 | return resize(image, w, (int) ((image.getHeight()*(double) w)/image.getWidth())); |
258 | } |
259 | |
260 | public static RGBImage resize(RGBImage image, int w, int h) { |
261 | if (w == image.getWidth() && h == image.getHeight()) return image; |
262 | |
263 | int[] pixels = new int[w*h]; |
264 | for (int y = 0; y < h; y++) |
265 | for (int x = 0; x < w; x++) |
266 | pixels[y*w+x] = image.getInt(x*image.getWidth()/w, y*image.getHeight()/h); |
267 | return new RGBImage(w, h, pixels); |
268 | } |
269 | |
270 | static boolean useImageCache = true; |
271 | static RGBImage loadImage(String snippetID) { |
272 | try { |
273 | File dir = new File(System.getProperty("user.home"), ".tinybrain/image-cache"); |
274 | if (useImageCache) { |
275 | dir.mkdirs(); |
276 | File file = new File(dir, snippetID + ".png"); |
277 | if (file.exists() && file.length() != 0) |
278 | try { |
279 | return new RGBImage(ImageIO.read(file)); |
280 | } catch (Throwable e) { |
281 | e.printStackTrace(); |
282 | // fall back to loading from sourceforge |
283 | } |
284 | } |
285 | |
286 | String imageURL = getImageURL(parseSnippetID(snippetID)); |
287 | System.err.println("Loading image: " + imageURL); |
288 | BufferedImage image = ImageIO.read(new URL(imageURL)); |
289 | |
290 | if (useImageCache) { |
291 | File tempFile = new File(dir, snippetID + ".tmp." + System.currentTimeMillis()); |
292 | ImageIO.write(image, "png", tempFile); |
293 | tempFile.renameTo(new File(dir, snippetID + ".png")); |
294 | //Log.info("Cached image."); |
295 | } |
296 | |
297 | //Log.info("Loaded image."); |
298 | return new RGBImage(image); |
299 | } catch (IOException e) { |
300 | throw new RuntimeException(e); |
301 | } |
302 | } |
303 | |
304 | static String getImageURL(long snippetID) throws IOException { |
305 | String url; |
306 | if (snippetID == 1000010 || snippetID == 1000012) |
307 | url = "http://tinybrain.de:8080/tb/show-blobimage.php?id=" + snippetID; |
308 | else |
309 | url = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + snippetID |
310 | + "&contentType=image/png"; |
311 | return url; |
312 | } |
313 | |
314 | public static long parseSnippetID(String snippetID) { |
315 | return Long.parseLong(shortenSnippetID(snippetID)); |
316 | } |
317 | |
318 | private static String shortenSnippetID(String snippetID) { |
319 | if (snippetID.startsWith("#")) |
320 | snippetID = snippetID.substring(1); |
321 | String httpBlaBla = "http://tinybrain.de/"; |
322 | if (snippetID.startsWith(httpBlaBla)) |
323 | snippetID = snippetID.substring(httpBlaBla.length()); |
324 | return snippetID; |
325 | } |
326 | |
327 | static Random _random = new Random(); |
328 | static double random() { |
329 | return _random.nextInt(100001)/100000.0; |
330 | } |
331 | |
332 | static int random(int max) { |
333 | return _random.nextInt(max); |
334 | } |
335 | |
336 | static double random(double min, double max) { |
337 | return min+random()*(max-min); |
338 | } |
339 | |
340 | static void vsplit(RGBImage img, VSplit p) { |
341 | int w = img.getWidth(), h = img.getHeight(); |
342 | for (int yy = 0; yy < h; yy++) |
343 | for (int xx = 0; xx < w; xx++) { |
344 | double x = ((double) xx)/(w-1); |
345 | double y = ((double) yy)/(h-1); |
346 | RGB col = y <= p.splitPoint ? p.col1 : p.col2; |
347 | img.setPixel(xx, yy, col); |
348 | } |
349 | } |
350 | |
351 | public static double pixelDiff(RGB a, RGB b) { |
352 | return (Math.abs(a.r-b.r) + Math.abs(a.g-b.g) + Math.abs(a.b-b.b))/3; |
353 | } |
354 | |
355 | public static double diff(RGBImage image, RGBImage image2) { |
356 | int w = image.getWidth(), h = image.getHeight(); |
357 | double sum = 0; |
358 | for (int y = 0; y < h; y++) |
359 | for (int x = 0; x < w; x++) |
360 | sum += pixelDiff(image.getRGB(x, y), image2.getRGB(x, y)); |
361 | return sum/(w*h); |
362 | } |
363 | } |
Began life as a copy of #663
download show line numbers debug dex old transpilations
Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, qbtsjoyahagl, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #664 |
Snippet name: | vsplit v4 (with solid col) |
Eternal ID of this version: | #664/1 |
Text MD5: | bb57571ad9926328794ddb3a191f6566 |
Author: | stefan |
Category: | |
Type: | JavaX source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2015-07-13 06:34:35 |
Source code size: | 10188 bytes / 363 lines |
Pitched / IR pitched: | No / Yes |
Views / Downloads: | 758 / 591 |
Referenced in: | [show references] |