Mercurial > lasercutter
diff src/clojureDemo/GenesisPlay.clj @ 1:6d9bdaf919f7
added clojureDemo source
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 20 Aug 2010 00:32:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojureDemo/GenesisPlay.clj Fri Aug 20 00:32:44 2010 -0400 1.3 @@ -0,0 +1,501 @@ 1.4 +(ns clojureDemo.GenesisPlay) 1.5 + 1.6 + 1.7 +(use 'clojure.contrib.import-static) 1.8 +(import '(java.io File)) 1.9 +(import '(org.apache.commons.io FileUtils)) 1.10 +(import '(javax.imageio ImageIO) ) 1.11 +(import '(javax.swing JFrame)) 1.12 +(import '(java.awt Color BorderLayout)) 1.13 +(import '(ij.plugin PlugIn)) 1.14 +(import '(ij ImagePlus IJ)) 1.15 +(import '(java.lang Math)) 1.16 + 1.17 +(use 'clojureDemo.appeture) 1.18 + 1.19 +(import-static java.lang.Math pow abs) 1.20 + 1.21 +(import '(ij Macro)) 1.22 + 1.23 +(import '(java.io BufferedReader InputStreamReader)) 1.24 +(import '(java.awt.image BufferedImage)) 1.25 +(import '(genesis Genesis)) 1.26 +(import '(utils Mark)) 1.27 +(import '(capenLow StoryProcessor)) 1.28 +(import '(connections Connections WiredBox)) 1.29 +(import '(specialBoxes BasicBox MultiFunctionBox)) 1.30 +(import '(http Start)) 1.31 +(import '(engineering NewHardWiredTranslator)) 1.32 + 1.33 +(import '(java.awt Polygon)) 1.34 +(import '(java.awt.geom Line2D$Double)) 1.35 +(use 'clojure.contrib.str-utils) 1.36 + 1.37 + 1.38 +(use '[clojureDemo.Xuggle :only (video-seq trans-save flash display video-data)]) 1.39 +(use 'clojureDemo.MegaDeath) 1.40 + 1.41 + 1.42 +(use 'clojure.contrib.combinatorics) 1.43 + 1.44 +(use 'clojure.contrib.repl-utils) 1.45 +(use ['clojureDemo.Defines 1.46 + :only '( 1.47 + lian look getto human0 blow base app0 app1 app2 app3 app4 app5 1.48 + bounce0 bounce1 bounce2 bounce3 bounce4 bounce5 bounce6 1.49 + collide0 collide1 collide2 collide3 collide4 1.50 + give0 give1 give2 give3 give4 target default)]) 1.51 + 1.52 + 1.53 +;(proxy 1.54 + 1.55 + 1.56 + 1.57 + 1.58 + 1.59 +(defn startInFrame-rm 1.60 + [genesis] 1.61 + (.start genesis) 1.62 + (let [frame (JFrame.)] 1.63 + (doto frame 1.64 + (.setTitle "Genesis") 1.65 + (.setBounds 0 0 1024 768) 1.66 + (doto (.getContentPane) 1.67 + (.setBackground Color/WHITE) 1.68 + (.setLayout (BorderLayout.)) 1.69 + (.add genesis)) 1.70 + (.setJMenuBar (.getMenuBar genesis)) 1.71 + (.setVisible true)) 1.72 + frame)) 1.73 + 1.74 + 1.75 +(defn run-genesis 1.76 + ([] (startInFrame-rm (Genesis.))) 1.77 + ([genesis] (startInFrame-rm genesis))) 1.78 + 1.79 +(defn lazy->hashMap 1.80 + [lazy] 1.81 + (zipmap (map first lazy) (map last lazy))) 1.82 + 1.83 +(defn make-box 1.84 + "constructs a wired box sutiable for interfacing to Genesis" 1.85 + [name process-fn] 1.86 + (let [box (proxy [BasicBox] [] (getName [] name) 1.87 + (process [obj] (.transmit (Connections/getPorts this) (process-fn obj))))] 1.88 + (.addSignalProcessor (Connections/getPorts box) "process") 1.89 + box)) 1.90 + 1.91 + 1.92 +(defn make-generator-box 1.93 + "makes a box which only outputs a constant" 1.94 + [name constant] 1.95 + (let [box (proxy [BasicBox] [] (getName [] name) (process [obj] (.transmit (Connections/getPorts this) constant)))] 1.96 + (.addSignalProcessor (Connections/getPorts box) "process") 1.97 + box)) 1.98 + 1.99 +(defn naturals [] (iterate inc 0)) 1.100 + 1.101 +;; ;(defn make-multifn-box [& args] 1.102 +;; ; (apply hash-map args) 1.103 + 1.104 +;; ; (map mega-macro naturals ) 1.105 + 1.106 +;; ; ) 1.107 + 1.108 + 1.109 + 1.110 + 1.111 +(defmacro function-name 1.112 + [function] 1.113 + (list str (list 'quote function))) 1.114 + 1.115 +(defn make-vision-box 1.116 + "eventually I'll generalize this to arbitary functions and port names, but for now this is good enough" 1.117 + [function1 function2] 1.118 + (let [box (proxy [MultiFunctionBox] [] (getName [] "vision-box") 1.119 + (process1 [obj] (.transmit (Connections/getPorts this) (function1 obj))) 1.120 + (process2 [obj] (.transmit (Connections/getPorts this) (function2 obj))))] 1.121 + (.addSignalProcessor (Connections/getPorts box) "PORT1" "process1") 1.122 + (.addSignalProcessor (Connections/getPorts box) "PORT2" "process2") 1.123 + box)) 1.124 + 1.125 +;; (defn make-box 1.126 +;; [name & functions] 1.127 +;; (let [box (proxy [MultiFunctionBox] [] (getName [] name) 1.128 +;; (for [indexed-fun (clojure.contrib.seq-utils/indexed functions)] 1.129 +;; ((symbol (str "process" (first indexed-fun))) 1.130 +;; [obj] (.transmit (Connections/getPorts this) ((last indexed-fun) obj)))))] 1.131 + 1.132 +;; (for [indexed-fun (clojure.contrib.seq-utils/indexed functions)] 1.133 +;; (.addSignalProcessor (Connections/getPorts box) (str "PORT" (first indexed-fun)) (str "process" (first indexed-fun)))) 1.134 +;; box)) 1.135 + 1.136 +;; (defmacro proxy-functions 1.137 +;; [ name & functions] 1.138 +;; (into 1.139 +;; (for [indexed-fun (clojure.contrib.seq-utils/indexed functions)] 1.140 +;; (list (symbol (str "process" (first indexed-fun))) (vector 'obj) 1.141 +;; (list '.transmit '(Connections/getPorts this) (list (last indexed-fun) 'obj)))) 1.142 +;; (list (list 'getName (vector) name) (vector) (vector MultiFunctionBox) 'proxy))) 1.143 + 1.144 + 1.145 + 1.146 +;; ((symbol (str "process" (first indexed-fun))) 1.147 +;; [obj] (.transmit (Connections/getPorts this) ((last indexed-fun) obj))))) 1.148 + 1.149 +;; (defmacro make-fun2-box 1.150 +;; [name & functions] 1.151 + 1.152 + 1.153 + 1.154 +;; (defmacro make-fun-box 1.155 +;; [name & functions] 1.156 +;; (let [proxy-functions 1.157 +;; (for [indexed-fun (clojure.contrib.seq-utils/indexed functions)] 1.158 +;; ((symbol (str "process" (first indexed-fun))) 1.159 +;; [`obj#] (.transmit (Connections/getPorts 'this) ((last indexed-fun) `obj#))))] 1.160 + 1.161 + 1.162 + 1.163 +;; `(let [box# (proxy [MultiFunctionBox] [] (getName [] ~name))] 1.164 +;; ~proxy-functions 1.165 +;; box#)) 1.166 + 1.167 +;; (defmacro return 1.168 +;; [name & functions] 1.169 +;; (let [out (for [x functions] 1.170 +;; x)] 1.171 +;; out)) 1.172 + 1.173 + 1.174 + 1.175 + 1.176 + 1.177 +(defn local-genesis 1.178 + "connects the custom vision interperter to genesis" 1.179 + [function1 function2] 1.180 + (let [vision-box (make-vision-box function1 function2) genesis (Genesis.) ] 1.181 + (Connections/wire Start/TRIPLES (.getStartParser genesis) "PORT1" vision-box) 1.182 + (Connections/wire NewHardWiredTranslator/RESULT (.getNewSemanticTranslator genesis) "PORT2" vision-box) 1.183 + genesis)) 1.184 + 1.185 + 1.186 + 1.187 + 1.188 + 1.189 + 1.190 +(defn frame-hash 1.191 + "yields a convienent representation for the pixles in an image. 1.192 + Because of the size of the structvre generated, this must only be used 1.193 + in a transient way so that java can do it's garbage collection." 1.194 + [imagePlus] 1.195 + (with-meta 1.196 + (let [buf (.. imagePlus getBufferedImage) 1.197 + color (.getColorModel buf)] 1.198 + (doall (apply hash-map 1.199 + (interleave 1.200 + (doall (for [x (range (.getWidth imagePlus)) y (range (.getHeight imagePlus))] 1.201 + (vector x y))) 1.202 + (doall (for [x (range (.getWidth imagePlus)) y (range (.getHeight imagePlus))] 1.203 + (let [data (.getRGB buf x y)] 1.204 + (hash-map :r (bit-shift-right (bit-and 0xff0000 data) 16) 1.205 + :g (bit-shift-right (bit-and 0x00ff00 data) 8) 1.206 + :b (bit-and 0x0000ff data))))))))) 1.207 + {:width (.getWidth imagePlus) :height (.getHeight imagePlus)})) 1.208 + 1.209 + 1.210 + 1.211 +(defn vid-seq 1.212 + [video] 1.213 + (with-meta (doall (map frame-hash (video-seq video))) (video-data video))) 1.214 + 1.215 + 1.216 + 1.217 + 1.218 + 1.219 +(defn video-hash 1.220 + "turns an entire video into a nice hash-map 1.221 + .... or at least it would, if java didn't suck and only give me 1.222 + 2 GB to work with with no way to increase it. 1.223 + linear processing... grumble grumble ....." 1.224 + [video-seq] 1.225 + (apply hash-map 1.226 + (interleave 1.227 + (naturals) 1.228 + (doall (map #(frame-hash %) video-seq))))) 1.229 + 1.230 + 1.231 + 1.232 + 1.233 +(defn frame-hash->bufferedImage 1.234 + [frame-hash] 1.235 + (let [data (meta frame-hash) 1.236 + image (BufferedImage. (:width data) (:height data) BufferedImage/TYPE_INT_BGR)] 1.237 + 1.238 + (doall (for [element frame-hash] 1.239 + (let [coord (key element) 1.240 + rgb (val element) 1.241 + packed-RGB 1.242 + (+ (bit-shift-left (:r rgb) 16) 1.243 + (bit-shift-left (:g rgb) 8) 1.244 + (:b rgb))] 1.245 + (.setRGB image (first coord) (last coord) packed-RGB)))) 1.246 + image)) 1.247 + 1.248 +(defmethod display 1.249 + clojure.lang.PersistentHashMap [frame-hash] 1.250 + (display (frame-hash->bufferedImage frame-hash))) 1.251 + 1.252 + (defmethod display 1.253 + clojure.lang.PersistentArrayMap [frame-hash] 1.254 + (display (frame-hash->bufferedImage frame-hash))) 1.255 + 1.256 +;; (defmethod display 1.257 +;; clojure.lang.LazySeq [frame-hash] 1.258 +;; (display (frame-hash->bufferedImage frame-hash))) 1.259 + 1.260 + 1.261 + 1.262 + 1.263 + 1.264 +(defn rectangle-window 1.265 + "efficiently grabs a rectangle from the frame-hash. 1.266 + Values that don't exisist in the picture are colored negative green!" 1.267 + [x y l w frame-hash] 1.268 + (let [coords (for [m (range (- x l) (+ 1 x l)) n (range (- y w) ( + 1 y w))] (vector m n))] 1.269 + 1.270 + (with-meta 1.271 + (zipmap 1.272 + coords 1.273 + (map #(frame-hash % {:r 0 :g -500 :b 0}) coords)) 1.274 + (meta frame-hash)))) 1.275 + 1.276 + 1.277 +(defn sum 1.278 + "squashes all the dinensions of the picture together into a single dimension 1.279 + sutiable for analysis." 1.280 + [window] 1.281 + (zipmap 1.282 + (keys window) 1.283 + (map (fn [rgb] (+ (:r rgb) (:b rgb) (:g rgb))) (vals window)))) 1.284 + 1.285 +(defn b&w 1.286 + "turn everything grey" 1.287 + [window] 1.288 + (with-meta 1.289 + (zipmap 1.290 + (keys window) 1.291 + (map (fn [rgb] 1.292 + (let [sum (int (/ (+ (:r rgb) (:b rgb) (:g rgb)) 3))] 1.293 + {:r sum :g sum :b sum })) (vals window))) (meta window))) 1.294 + 1.295 +(defn green-select-x-form 1.296 + "find green things" 1.297 + [window] 1.298 + (with-meta 1.299 + (zipmap 1.300 + (keys window) 1.301 + (map (fn [rgb] 1.302 + (if (and (> (:g rgb) (:b rgb)) (> (:g rgb) (:r rgb))) 1.303 + rgb 1.304 + {:r 0 :g 0 :b 0})) (vals window))) (meta window))) 1.305 + 1.306 + 1.307 +(defn manual-line-detect 1.308 + "Ty as I might, this can never be truly effective until higher level 1.309 + processes contribute to dynamicaly adjusting these paramaters. For 1.310 + now I'll settle with simple manual calibration." 1.311 + [var1 mean1 var2 mean2] 1.312 + (> 1.313 + (if (or (< var1 250) (< var2 250)) 1.314 + (abs (int (- mean1 mean2))) 1.315 + 0) 55)) 1.316 +;30 looks good 1.317 + 1.318 + 1.319 + 1.320 + 1.321 +(defn frame-windows 1.322 + "analyzes a frame in terms of lots of tiny windows which 1.323 + each try to find some sort of edge." 1.324 + ([ x-form frame] 1.325 + (with-meta 1.326 + (let [width (:width (meta frame) 500) 1.327 + height(:height (meta frame) 500 )] 1.328 + (filter (comp not nil?) 1.329 + (for [x (range 0 width 2) y (range 0 height 2)] 1.330 + (:line (window-line (rectangle-window x y 1 1 frame) (comp sum x-form) manual-line-detect))))) (meta frame))) 1.331 + ([frame] (frame-windows identity frame))) 1.332 + 1.333 + 1.334 +(defn static-segmentation 1.335 + "divides a single picture frame into appropiate objects using a 1.336 + simple watershed method based on sharp color variation. 1.337 + radius: the general size of the window in pixels 1.338 + gradient: threshold for a color gradient to be recognized as a edge" 1.339 + [radius gradient frame] 1.340 + (let [ah (frame-hash frame)] 1.341 + ah)) 1.342 + 1.343 + 1.344 +(defn video-parse 1.345 + "this is the equilivalent to the S.T.A.R.T Parser for videos 1.346 + right now it's just a simple blob detector" 1.347 + [video-seq] 1.348 + 1.349 + ) 1.350 + 1.351 + 1.352 + 1.353 +(defn overlay-draw 1.354 + [frame-hash overlay] 1.355 + (let [image (frame-hash->bufferedImage frame-hash) 1.356 + g2 (.getGraphics image)] 1.357 + (doall (for [ x overlay] 1.358 + (let [x1 (ffirst x) y1 (second (first x)) x2 (first (last x)) y2 (last (last x))] 1.359 + (.drawLine g2 x1 y1 x2 y2)))) 1.360 + image)) 1.361 + 1.362 + 1.363 + 1.364 +(defn video-seq->b&w 1.365 + [video-seq] 1.366 + (with-meta 1.367 + (map #(ImagePlus. "B and W" (frame-hash->bufferedImage %)) 1.368 + 1.369 + (map (fn [imgPlus] 1.370 + (let [play (frame-hash imgPlus)] 1.371 + (b&w play))) 1.372 + video-seq)) 1.373 + (meta video-seq))) 1.374 + 1.375 + 1.376 + 1.377 +(defn vid-save 1.378 + [filename vid-seq] 1.379 + (trans-save filename 1.380 + (with-meta (map (comp #(ImagePlus. "reverse-x-form" %) frame-hash->bufferedImage) vid-seq) (meta vid-seq)))) 1.381 + 1.382 + 1.383 + 1.384 +;(def g0 (video-seq give0)) 1.385 +(def gen (proxy [Genesis] [] )) 1.386 +(def short-give (with-meta (take 60 (drop 30 (video-seq give0))) {:fps 30 :width 320 :height 240 })) 1.387 + 1.388 +(def sg short-give) 1.389 +(def g1 (first sg)) 1.390 +(def gs sg) 1.391 +(def play (frame-hash (first sg))) 1.392 +(def blank (with-meta (zipmap (keys play) (repeat (count play) {:r 0 :g 0 :b 0})) (meta play))) 1.393 + 1.394 +(def blank (with-meta (zipmap (keys play) (repeat (count play) {:r 0 :g 0 :b 0})) (meta play))) 1.395 +(def b+w-play (b&w play)) 1.396 +(def rgb (rectangle-window 50 50 1 1 play)) 1.397 +(def invertedPlay (with-meta (zipmap (keys play) (map #(hash-map :r (- 255 (:r %)) :g (- 255 (:g %)) :b (- 255 (:b %))) (vals b+w-play))) (meta play))) 1.398 + 1.399 +(def invertedColorPlay (with-meta (zipmap (keys play) (map #(hash-map :r (- 255 (:r %)) :g (- 255 (:g %)) :b (- 255 (:b %))) (vals play))) (meta play))) 1.400 + 1.401 +(def play1 (with-meta (frame-hash (nth sg 0)) {:width 320 :height 240})) 1.402 +(def play2 (with-meta (frame-hash (nth sg 1)) {:width 320 :height 240})) 1.403 +(def play3 (with-meta (frame-hash (nth sg 2)) {:width 320 :height 240})) 1.404 +(def play4 (with-meta (frame-hash (nth sg 3)) {:width 320 :height 240})) 1.405 +(def play5 (with-meta (frame-hash (nth sg 4)) {:width 320 :height 240})) 1.406 + 1.407 + 1.408 + 1.409 + 1.410 + 1.411 + 1.412 + 1.413 + 1.414 + 1.415 + 1.416 + 1.417 + 1.418 + 1.419 + 1.420 + 1.421 + 1.422 + 1.423 + 1.424 + 1.425 + 1.426 + 1.427 + 1.428 + 1.429 + 1.430 + 1.431 + 1.432 +(comment 1.433 + ok here's the plan-- 1.434 + 1.435 + "genesis/language" 1.436 + raw text -> START -> representations/memory -> story tree 1.437 + 1.438 + "genesis/vision" 1.439 + raw video -> blob detector -> representations/memory -> event/structure tree 1.440 + 1.441 + first, we start off with a video. 1.442 + the video get's passed through the blob detector. 1.443 + 1.444 + (blob-detector 1.445 + first-pass- divide up each frame into exasutive polygons. no temporal dependence 1.446 + second-pass- do a pairwise comparison of frames to link the polygons from each frame. 1.447 + polygons can either split apart or merge, but this step establishes their geneology. 1.448 + third-pass- link the polygons together into higher objects using hueristic rules about motion 1.449 + these rules are determined by the language system, but for now they will be hardcoded. 1.450 + the only thing for now is that things that move together are the same object. 1.451 + ) 1.452 + 1.453 + 1.454 + so now, we have a temporal history of polygons. 1.455 + the language part of the story may specify that certain characters 1.456 + with certain qualities do certain actions. 1.457 + 1.458 + "Bob is wearing a red shirt. Shirts are big. Bob is a person. 1.459 + Mary is wearing a green shirt. 1.460 + Bob is person-sized. 1.461 + Bob is moving. 1.462 + The green object is a ball. 1.463 + Bob gives the ball to Mary." 1.464 + 1.465 + Now, Genesis can select just the polygons that are important to the story, 1.466 + and it also learns important facts such as the relative size of a person to a ball. 1.467 + 1.468 + The details which are captured in the polygon-transition space are-- 1.469 + x (location of the center of each polygon), dx/dt , ((d^2)x)/(dt)^2, color (average), [left|right], polygon area 1.470 + polygon shape 1.471 + 1.472 + This information recurses on every component polygon as well. 1.473 + 1.474 + When genesis want's to learn about verbs in particular, 1.475 + it selects the aproapiate blobs from the linguistic desctiption (in bob's 1.476 + case it's "the big red blob on the left", for example.) 1.477 + 1.478 + after selecting a subset of the blobs, it calculates the angles and distances between 1.479 + those blobs' centers as erll as whether they are touching or overlaping. 1.480 + 1.481 + From this sequence it derives an example of the verb. 1.482 + 1.483 + From other examples it can do arch earning to refine the sequence to its salient features. 1.484 + ) 1.485 + 1.486 + 1.487 + 1.488 +(comment (things you can do that will actually work!) 1.489 + 1.490 +(do (use :reload-all 'clojureDemo.GenesisPlay) (in-ns 'clojureDemo.GenesisPlay)) 1.491 +;genesis integration: 1.492 +(def gen5 (make-generator-box "the 5th element" 5)) 1.493 +(Connections/wire gen5 (make-box "printer" println)) 1.494 +(Connections/viewNetwork) 1.495 +(.process gen5 :ignore) ; causes 5 to be printed 1.496 +(Connections/obliterateNetwork) 1.497 +(.process gen5 :ignore); since the network connections were dissolved, nothing prints. 1.498 + 1.499 + 1.500 + 1.501 +) 1.502 + 1.503 + 1.504 +