Mercurial > lasercutter
comparison src/clojureDemo/ArchLearning.clj @ 1:6d9bdaf919f7
added clojureDemo source
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 20 Aug 2010 00:32:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:163bf9b2fd13 | 1:6d9bdaf919f7 |
---|---|
1 (ns clojureDemo.ArchLearning | |
2 (:gen-class | |
3 :implements [connections.WiredBox] | |
4 :methods [ [process [Object] void] [setFile [Object] void] ] | |
5 :post-init register)) | |
6 | |
7 (use 'clojure.contrib.import-static) | |
8 (import '(java.io File)) | |
9 (import '(org.apache.commons.io FileUtils)) | |
10 (import '(javax.imageio ImageIO) ) | |
11 (import '(javax.swing JFrame)) | |
12 (import '(java.awt Color BorderLayout)) | |
13 (import '(ij.plugin PlugIn)) | |
14 (import '(ij ImagePlus IJ)) | |
15 (import '(java.lang Math)) | |
16 (import '(java.awt Polygon)) | |
17 (import '(java.awt.geom Line2D$Double)) | |
18 | |
19 (use 'clojureDemo.appeture) | |
20 | |
21 (import-static java.lang.Math pow abs) | |
22 | |
23 (import '(ij Macro)) | |
24 | |
25 (import '(java.io BufferedReader InputStreamReader)) | |
26 (import '(java.awt.image BufferedImage)) | |
27 (import '(genesis Genesis)) | |
28 (import '(utils Mark)) | |
29 (import '(capenLow StoryProcessor)) | |
30 (import '(connections Connections WiredBox)) | |
31 (import '(specialBoxes BasicBox MultiFunctionBox)) | |
32 (import '(engineering NewHardWiredTranslator)) | |
33 | |
34 (import '(java.awt Polygon)) | |
35 (import '(java.awt.geom Line2D$Double)) | |
36 (use 'clojure.contrib.str-utils) | |
37 | |
38 | |
39 ;genesis imports | |
40 (import '(http Start)) | |
41 | |
42 | |
43 (use '[clojureDemo.Xuggle :only (video-seq trans-save flash display video-data)]) | |
44 (use 'clojureDemo.MegaDeath) | |
45 | |
46 | |
47 (use 'clojure.contrib.combinatorics) | |
48 | |
49 (use 'clojure.contrib.repl-utils) | |
50 | |
51 (use 'clojureDemo.GenesisPlay) | |
52 | |
53 (use ['clojureDemo.Defines | |
54 :only '( | |
55 lian look getto human0 blow base app0 app1 app2 app3 app4 app5 | |
56 bounce0 bounce1 bounce2 bounce3 bounce4 bounce5 bounce6 | |
57 collide0 collide1 collide2 collide3 collide4 | |
58 give0 give1 give2 give3 give4 target default)]) | |
59 | |
60 (defn -register | |
61 "equivalent to Connections.getPorts(this).addSignalProcessor(\"process\"); in Java" | |
62 [this] | |
63 (println "ClojureBox (register) : Register is run | |
64 only when the object is created, as if it were a constructor.") | |
65 (. (connections.Connections/getPorts this) addSignalProcessor "process")) | |
66 | |
67 (defn -process [ this obj ] | |
68 (println "ClojureBox (process) : This is a LISP function, | |
69 being called through Java, through the wiredBox metaphor.") | |
70 (.transmit (Connections/getPorts this) obj)) | |
71 | |
72 (defn -getName | |
73 "the [_] means that the function gets an explicit 'this' | |
74 argument, just like python. In this case we don't care about it." | |
75 [_] "ArchLearning") | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 (def output-base (File. "/home/r/Desktop/output-vision")) | |
82 (def rsgs (with-meta (take 10 gs) (meta gs))) | |
83 (def rrsgs (with-meta (take 3 rsgs) (meta gs))) | |
84 ; a concept is going to be derived from Genesis' own xml based representations. | |
85 ; this is an form of archlearning which figures out a function that representes | |
86 ; the concepts. | |
87 | |
88 | |
89 (def black {:r 0 :g 0 :b 0}) | |
90 (def white {:r 255 :g 255 :b 255}) | |
91 | |
92 | |
93 (defn window-frame | |
94 "analyzes a frame in terms of lots of tiny windows which | |
95 each try to find some sort of edge. keeps coordinates." | |
96 ([x-form frame] | |
97 (let [lines (frame-windows x-form frame)] | |
98 (zipmap (for [x lines] (first (rest x))) | |
99 lines))) | |
100 ([frame] | |
101 (window-frame identity frame))) | |
102 | |
103 | |
104 (defn intense-select-x-form | |
105 "discard silly gray things" | |
106 [window] | |
107 (with-meta | |
108 (zipmap | |
109 (keys window) | |
110 (map (fn [rgb] | |
111 (let [spread (- (max (:r rgb) (:g rgb) (:b rgb)) (min (:r rgb) (:g rgb) (:b rgb)))] | |
112 (if (> spread 45) | |
113 rgb | |
114 {:r 0 :g 0 :b 0}))) (vals window))) (meta window))) | |
115 | |
116 (defn edges-x-form | |
117 [window] | |
118 (frame-hash (ImagePlus. "sad :(" (overlay-draw blank (frame-windows window))))) | |
119 | |
120 | |
121 | |
122 (defn rgb-max | |
123 [rgb1 rgb2] | |
124 {:r (max (:r rgb1) (:r rgb2)) | |
125 :g (max (:g rgb1) (:g rgb2)) | |
126 :b (max (:b rgb1) (:b rgb2))}) | |
127 | |
128 (defn frame-hash-add | |
129 [frame1 frame2] | |
130 (with-meta | |
131 (let [indexes (apply hash-set (concat (keys frame1) (keys frame2)))] | |
132 (zipmap indexes (for [x indexes] (rgb-max (frame1 x black) (frame2 x black))))) (meta frame1))) | |
133 | |
134 | |
135 | |
136 (defn vid-seq-add | |
137 "for black and white video-sequences. Just adds them together into one image sequence" | |
138 [vid-seq1 vid-seq2] | |
139 (with-meta | |
140 (map #(ImagePlus. "ADD B&W" (frame-hash->bufferedImage %)) (map frame-hash-add (map frame-hash vid-seq1) (map frame-hash vid-seq2))) | |
141 (meta vid-seq1))) | |
142 | |
143 (defn edges-center-draw | |
144 ([base edges] | |
145 (frame-hash-add | |
146 base | |
147 (zipmap (keys edges) (repeat white)))) | |
148 ([edges] | |
149 (edges-center-draw blank edges))) | |
150 | |
151 (defn edge-dot-x-form | |
152 "gives a new frame-hash with only the edge points, all white." | |
153 [frame] | |
154 (edges-center-draw (window-frame frame))) | |
155 | |
156 | |
157 (defn rgb-euclidian | |
158 [{r1 :r g1 :g b1 :b} {r2 :r g2 :g b2 :b} ] | |
159 (pow (+ (pow (- r1 r2) 2) | |
160 (pow (- g1 g2) 2) | |
161 (pow (- b1 b2) 2)) 0.5)) | |
162 | |
163 (defn rgb-sub | |
164 [tolerance rgb1 rgb2] | |
165 (if (< (rgb-euclidian rgb1 rgb2) tolerance) black white)) | |
166 | |
167 | |
168 | |
169 (defn frame-subtract | |
170 [tolerance frame1 frame2] | |
171 (with-meta | |
172 (let [indexes (apply hash-set (concat (keys frame1) (keys frame2)))] | |
173 (zipmap indexes (for [x indexes] (rgb-sub tolerance (frame1 x) (frame2 x))))) (meta frame1))) | |
174 | |
175 | |
176 (defn image-subtract | |
177 [tolerance [img1 img2]] | |
178 (frame-subtract tolerance (frame-hash img1) (frame-hash img2))) | |
179 | |
180 | |
181 (defn motion-detect | |
182 ([tolerance video-seq] | |
183 (with-meta | |
184 (map (partial image-subtract tolerance) (partition 2 1 video-seq)) (meta video-seq))) | |
185 ([video-seq] | |
186 (motion-detect 40 video-seq))) | |
187 | |
188 (defn motion-x-form | |
189 ([tolerance video-seq] | |
190 (with-meta | |
191 (map #(ImagePlus. "motion-detect!" (frame-hash->bufferedImage %)) (motion-detect tolerance video-seq)) | |
192 (meta video-seq))) | |
193 ([video-seq] | |
194 (motion-x-form 40 video-seq))) | |
195 ;the edge detector is what finds objects. | |
196 ;movement disambiguates between different ways of interperting what objects are there | |
197 ;color / other qualifiers enable focus on a subset of objects, and can give objects names. | |
198 | |
199 | |
200 | |
201 | |
202 | |
203 (defn find-an-object | |
204 "tries to find a single object from the current sensory-buffer, which | |
205 is a video-seq for now. My idea here is for this to feed-back on itself, | |
206 adjusting parameters till it can find it's target, and then using those | |
207 to construct an representation of the object in terms of how to find it using | |
208 other visual routines paramaters." | |
209 [video-seq]) | |
210 | |
211 | |
212 | |
213 (defn transform | |
214 [x-form video-seq] | |
215 (with-meta | |
216 (map (fn [imgPlus] | |
217 (let [play (frame-hash imgPlus)] | |
218 (x-form play))) | |
219 video-seq) | |
220 (meta video-seq))) | |
221 | |
222 | |
223 (defn apply-x-form | |
224 [x-form video-seq] | |
225 (with-meta | |
226 (map #(ImagePlus. "transformed!" (frame-hash->bufferedImage %)) | |
227 (map (fn [imgPlus] | |
228 (let [play (frame-hash imgPlus)] | |
229 (x-form play))) | |
230 video-seq)) | |
231 (meta video-seq))) | |
232 | |
233 | |
234 | |
235 (defn only-white | |
236 "reduce the image to only its white points" | |
237 [window] | |
238 (with-meta | |
239 (let [new-keys | |
240 (filter #(= white (window %)) (keys window))] | |
241 (zipmap new-keys (map window new-keys))) (meta window))) | |
242 | |
243 | |
244 | |
245 | |
246 (defn white-sum | |
247 [& rgbs] | |
248 (let[ wht-map {white 1}] | |
249 (reduce + (map #(wht-map % 0) rgbs)))) | |
250 | |
251 (defn island? | |
252 "return false if there's nothing around it within a certain radius" | |
253 [window [x y]] | |
254 (let [radius 3] | |
255 (<= (apply white-sum (vals (rectangle-window x y radius radius window))) 1))) | |
256 | |
257 (defn white-border | |
258 "anything that relies on a hack like this to work is wrong" | |
259 [window] | |
260 (with-meta | |
261 (let [info (meta window)] | |
262 (into window | |
263 (zipmap | |
264 (for [x (range (:width info)) y (range (:height info)) | |
265 :when (or (= (-(:width info) 1) x) (= (- (:height info) 1) y) (= 0 y) (= 0 x))] [x y]) | |
266 (repeat white))))(meta window))) | |
267 | |
268 (defn polygonize | |
269 "for each edge-point, try to connect it with all the edge points around it, | |
270 or obliterate it if it doesn't have any edge points close by." | |
271 [window] | |
272 (with-meta | |
273 (let [edges (only-white window)] | |
274 (let [new-keys | |
275 (filter (comp not (partial island? window)) (keys window))] | |
276 (let [ready-points (zipmap new-keys (map window new-keys))] | |
277 (meta window)))))) | |
278 | |
279 | |
280 (defn connect-the-dots | |
281 [radius window] | |
282 (let [edge-points (white-border (only-white window)) | |
283 image (frame-hash->bufferedImage window) | |
284 g2 (.getGraphics image)] | |
285 (doall | |
286 (for [[x y] (keys edge-points)] | |
287 | |
288 (let [points (apply cartesian-product (repeat 2 (keys (only-white (rectangle-window x y radius radius edge-points)))))] | |
289 (if (not (empty? points)) | |
290 (doall | |
291 (for [[[x1 y1][x2 y2]] points] | |
292 (.drawLine g2 x1 y1 x2 y2))))))) | |
293 (frame-hash (ImagePlus. "stupid..." image)))) | |
294 | |
295 | |
296 (defn blob-x-form | |
297 [window] | |
298 (with-meta | |
299 ((comp (partial connect-the-dots 4) edge-dot-x-form) window) | |
300 (meta window))) | |
301 | |
302 | |
303 | |
304 | |
305 (defn connect-points | |
306 [frame-hash overlay] | |
307 (let [image (frame-hash->bufferedImage frame-hash) | |
308 g2 (.getGraphics image)] | |
309 (doall (for [ x overlay] | |
310 (let [x1 (ffirst x) y1 (second (first x)) x2 (first (last x)) y2 (last (last x))] | |
311 (.drawLine g2 x1 y1 x2 y2)))) | |
312 image)) | |
313 | |
314 | |
315 (defn disambiguate-edges | |
316 "Like in project Prakesh, the thing that lets you discern shapes | |
317 is watching them *move* coherently. After many months of this | |
318 motion-boosting, the edge-detector itself becomes good enogh to | |
319 analyze static pictures without motion. This function takes edges | |
320 and tries to combine them into lines, dividing the world into | |
321 polygonal regions. Motion is used to associate two regions together. | |
322 associated with those points, that information is also used." | |
323 [edges motion] | |
324 ) | |
325 | |
326 | |
327 (defn triple-seq | |
328 [triple] | |
329 (list (.getFirst triple) (.getSecond triple) (.getThird triple))) | |
330 | |
331 (defn contains-word? | |
332 [word triple] | |
333 (contains? (set (map (fn [s] (re-sub #"-\d+" "" s)) (triple-seq triple))) word)) | |
334 | |
335 | |
336 (defn write | |
337 [reference] | |
338 (fn [x] (dosync | |
339 (println "wrote " " to " "ref.") | |
340 (ref-set reference x)))) | |
341 | |
342 | |
343 ;; (defn join-point-lists | |
344 ;; [pointlist1 pointlist2] | |
345 ;; (for [x :while (not(= x 5))] x))) | |
346 | |
347 (defn extract-single-blob | |
348 "find the biggest blob in an image and return it" | |
349 [window] | |
350 ;we're assuming that there are only blobs left -- funning this on an unprocessed | |
351 ;image will just return the entire image | |
352 (map list window)) | |
353 | |
354 | |
355 | |
356 | |
357 (def gen-out (ref nil)) | |
358 (def triple (ref nil)) | |
359 | |
360 | |
361 | |
362 (def gen1 (ref ())) | |
363 (def gen2 (ref ())) | |
364 (def gen3 (ref ())) | |
365 (def gen4 (ref ())) | |
366 (def gen5 (ref ())) | |
367 (def gen6 (ref ())) | |
368 (def gen7 (ref ())) | |
369 (def gen8 (ref ())) | |
370 | |
371 | |
372 (defn make-color-generator | |
373 [] | |
374 (let [r (java.util.Random. 58) | |
375 g (java.util.Random. 125) | |
376 b (java.util.Random. 8)] | |
377 #(hash-map :r (.nextInt r 255) :g (.nextInt r 255) :b (.nextInt r 255)))) | |
378 | |
379 | |
380 ;a blob is a collection of: | |
381 ;points, colors | |
382 ;other blobs | |
383 ;so, a window is a blob too. | |
384 | |
385 | |
386 | |
387 | |
388 | |
389 | |
390 ;; (defn blob-color-absob | |
391 ;; [blob1 blob2] | |
392 ;; (if (and (< (rgb-euclidian (color-avg blob1) (color-avg blob2)) 20) (close-together blob1 blob2)) | |
393 ;; (combine blob1 blob2) | |
394 ;; '(blob1 blob2))) | |
395 | |
396 | |
397 (defn make-test-box | |
398 "stupid." | |
399 [] | |
400 (let [box (proxy [MultiFunctionBox] [] (getName [] "test-box [clojure]") | |
401 (process1 [obj] ((write gen1) obj)) | |
402 (process2 [obj] ((write gen2) obj)) | |
403 (process3 [obj] ((write gen3) obj)) | |
404 (process4 [obj] ((write gen4) obj)) | |
405 (process5 [obj] ((write gen5) obj)) | |
406 (process6 [obj] ((write gen6) obj)) | |
407 (process7 [obj] ((write gen7) obj)) | |
408 (process8 [obj] ((write gen8) obj)))] | |
409 | |
410 (.addSignalProcessor (Connections/getPorts box) "PORT1" "process1") | |
411 (.addSignalProcessor (Connections/getPorts box) "PORT2" "process2") | |
412 (.addSignalProcessor (Connections/getPorts box) "PORT3" "process3") | |
413 (.addSignalProcessor (Connections/getPorts box) "PORT4" "process4") | |
414 (.addSignalProcessor (Connections/getPorts box) "PORT5" "process5") | |
415 (.addSignalProcessor (Connections/getPorts box) "PORT6" "process6") | |
416 (.addSignalProcessor (Connections/getPorts box) "PORT7" "process7") | |
417 (.addSignalProcessor (Connections/getPorts box) "PORT8" "process8") | |
418 box)) | |
419 | |
420 | |
421 | |
422 (defn writer-box | |
423 [reference] | |
424 (let [box (proxy [MultiFunctionBox] [] | |
425 (getName [] "ref-set\n [clojure]") | |
426 (process1 [obj] ((write reference) obj)))] | |
427 (.addSignalProcessor (Connections/getPorts box) "process1") | |
428 box)) | |
429 | |
430 | |
431 | |
432 | |
433 (def triples (ref ())) | |
434 (def parse (ref ())) | |
435 (def raw (ref ())) | |
436 (def idioms (ref ())) | |
437 (def yes-no (ref ())) | |
438 (def imagine (ref ())) | |
439 (def traj (ref ())) | |
440 (def action (ref ())) | |
441 (def transfer (ref ())) | |
442 (def pix (ref ())) | |
443 (def property (ref ())) | |
444 | |
445 (use 'clojure.contrib.str-utils) | |
446 | |
447 (defn process-video-and-subtitles | |
448 [this file] | |
449 ;we're looking for a text file of the same name as the video file. | |
450 (let [subtitles (File. (.getParent file) (str (last (first (re-seq #"(^.*)\.avi$" (.getName file)))) ".txt"))] | |
451 (dorun | |
452 (for [line (re-split #"\n" (slurp (str subtitles)))] | |
453 (do (println line) | |
454 (.transmit (Connections/getPorts this) line))))) | |
455 (display (first (video-seq file)))) | |
456 | |
457 (defn process-triple | |
458 [this triple] | |
459 (println "RLM [vision-box]: " triple)) | |
460 | |
461 (defn visionBox | |
462 [] | |
463 (let [box (proxy [MultiFunctionBox] [] | |
464 (getName [] "VisionBox \n [clojure]") | |
465 (process1 [obj] (process-video-and-subtitles this obj)) | |
466 (process2 [obj] (process-triple this obj)))] | |
467 (.addSignalProcessor (Connections/getPorts box) "video-in" "process1") | |
468 (.addSignalProcessor (Connections/getPorts box) "triple-in" "process2") | |
469 | |
470 (println "the good box") | |
471 box)) | |
472 | |
473 | |
474 | |
475 | |
476 | |
477 (defn custom-genesis | |
478 "connects the writer boxes to genesis" | |
479 [] | |
480 (Connections/obliterateNetwork) | |
481 (let [stupid-box (make-test-box) genesis (Genesis.) vis-box (visionBox) ] | |
482 (Connections/wire "tripple port" (.getStartParser genesis) (writer-box triples)) | |
483 (Connections/wire "parse" (.getStartParser genesis) (writer-box parse)) | |
484 (Connections/wire "result" (.getNewSemanticTranslator genesis) (writer-box raw)) | |
485 (Connections/wire (.getIdiomExpert genesis) (writer-box idioms)) | |
486 (Connections/wire "yes-no question" (.getCommandExpert genesis) (writer-box yes-no)) | |
487 (Connections/wire "imagine" (.getCommandExpert genesis) (writer-box imagine)) | |
488 (Connections/wire "viewer" (.getTrajectoryExpert genesis) (writer-box traj)) | |
489 (Connections/wire "viewer" (.getActionExpert genesis) (writer-box action)) | |
490 (Connections/wire "next" (.getTransferExpert genesis) (writer-box transfer)) | |
491 (Connections/wire (.getRachelsPictureFinder genesis) (writer-box pix)) | |
492 (Connections/wire "viewer" (.getPropertyExpert genesis) (writer-box property)) | |
493 (Connections/wire "tripple port" (.getStartParser genesis) "triple-in" vis-box) | |
494 | |
495 | |
496 (Connections/wire (.getArchLearning genesis) "video-in" vis-box) | |
497 (Connections/wire vis-box "sentence" (.getStartParser genesis)) | |
498 | |
499 genesis)) | |
500 | |
501 | |
502 (use 'clojure.contrib.def) | |
503 | |
504 (defvar learning-hash {} | |
505 "Right now this serves as the visual memory. | |
506 It's full of verbs/objects and the programs | |
507 that find them.") | |
508 | |
509 (def green {:r 0 :g 200 :b 0}) | |
510 (def blue {:r 0 :g 0 :b 255}) | |
511 (def red {:r 255 :g 0 :b 0}) | |
512 | |
513 | |
514 (defn color-similar? | |
515 [threshold window color coord] | |
516 (< (rgb-euclidian (window coord) color) threshold)) | |
517 ;should also have the same "shape" here | |
518 | |
519 (defn color-select | |
520 [threshold color window] | |
521 (with-meta | |
522 (let [new-keys | |
523 (filter (partial color-similar? threshold window color) (keys window))] | |
524 (zipmap new-keys (map window new-keys))) | |
525 (meta window))) | |
526 | |
527 | |
528 | |
529 (defn object-sequence | |
530 "get's the largest blob of the given color from a video sequence." | |
531 [color video-seq] | |
532 (apply-x-form (comp (partial color-select 135 color) intense-select-x-form) rrsgs)) | |
533 | |
534 (defn -setFile | |
535 [this file] | |
536 (println "file is " file) | |
537 (.process this file)) | |
538 | |
539 | |
540 | |
541 | |
542 (comment (things you can do that will actually work!) | |
543 | |
544 (do (use :reload-all 'clojureDemo.ArchLearning) (in-ns 'clojureDemo.ArchLearning)) | |
545 | |
546 (display (overlay-draw (green-select-x-form play) (frame-windows green-select-x-form play ))) | |
547 | |
548 ;vision stuff | |
549 | |
550 (def edgesD (transform window-frame rrsgs)) | |
551 | |
552 (doall | |
553 (def edgesI (apply-x-form edges-x-form rrsgs)) | |
554 (display (rectangle-window 50 50 50 50 (frame-hash (nth edgesI 1)))) | |
555 ) | |
556 | |
557 (def polyjuice (white-border (only-white (edge-dot-x-form play)))) | |
558 | |
559 (count (color-select 135 red (intense-select-x-form (frame-hash (last sg))))) | |
560 (trans-save (File. output-base "only-red.avi")(apply-x-form (comp (partial color-select 135 red) intense-select-x-form) rrsgs)) | |
561 ) | |
562 |