comparison org/sense.org @ 199:305439cec54d

added video to sense.org
author Robert McIntyre <rlm@mit.edu>
date Mon, 06 Feb 2012 01:40:22 -0700
parents fc0bf33bded2
children 7eb966144dad
comparison
equal deleted inserted replaced
198:fc0bf33bded2 199:305439cec54d
223 define its own way of turning sense-data into pictures, while the 223 define its own way of turning sense-data into pictures, while the
224 actual rendering of said pictures stays in one central place. 224 actual rendering of said pictures stays in one central place.
225 =(points->image)= helps senses generate a base image onto which they 225 =(points->image)= helps senses generate a base image onto which they
226 can overlay actual sense data. 226 can overlay actual sense data.
227 227
228 #+name view-senses 228 #+name: view-senses
229 #+begin_src clojure 229 #+begin_src clojure
230 (defn view-sense 230 (in-ns 'cortex.sense)
231 "Take a kernel that produces a BufferedImage from some sense data
232 and return a function which takes a list of sense data, uses the
233 kernel to convert to images, and displays those images, each in
234 its own JFrame."
235 [sense-display-kernel]
236 (let [windows (atom [])]
237 (fn [data]
238 (if (> (count data) (count @windows))
239 (reset!
240 windows (map (fn [_] (view-image)) (range (count data)))))
241 (dorun
242 (map
243 (fn [display datum]
244 (display (sense-display-kernel datum)))
245 @windows data)))))
246 231
247 (defn points->image 232 (defn points->image
248 "Take a collection of points and visuliaze it as a BufferedImage." 233 "Take a collection of points and visuliaze it as a BufferedImage."
249 [points] 234 [points]
250 (if (empty? points) 235 (if (empty? points)
264 (dorun 249 (dorun
265 (for [index (range (count points))] 250 (for [index (range (count points))]
266 (.setRGB image (- (xs index) x0) (- (ys index) y0) -1))) 251 (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))
267 image))) 252 image)))
268 253
254 (defn view-image
255 "Initailizes a JPanel on which you may draw a BufferedImage.
256 Returns a function that accepts a BufferedImage and draws it to the
257 JPanel. If given a directory it will save the images as png files
258 starting at 0000000.png and incrementing from there."
259 ([#^File save]
260 (let [idx (atom -1)
261 image
262 (atom
263 (BufferedImage. 1 1 BufferedImage/TYPE_4BYTE_ABGR))
264 panel
265 (proxy [JPanel] []
266 (paint
267 [graphics]
268 (proxy-super paintComponent graphics)
269 (.drawImage graphics @image 0 0 nil)))
270 frame (JFrame. "Display Image")]
271 (SwingUtilities/invokeLater
272 (fn []
273 (doto frame
274 (-> (.getContentPane) (.add panel))
275 (.pack)
276 (.setLocationRelativeTo nil)
277 (.setResizable true)
278 (.setVisible true))))
279 (fn [#^BufferedImage i]
280 (reset! image i)
281 (.setSize frame (+ 8 (.getWidth i)) (+ 28 (.getHeight i)))
282 (.repaint panel 0 0 (.getWidth i) (.getHeight i))
283 (if save
284 (ImageIO/write
285 i "png"
286 (File. save (format "%07d.png" (swap! idx inc))))))))
287 ([] (view-image nil)))
288
289 (defn view-sense
290 "Take a kernel that produces a BufferedImage from some sense data
291 and return a function which takes a list of sense data, uses the
292 kernel to convert to images, and displays those images, each in
293 its own JFrame."
294 [sense-display-kernel]
295 (let [windows (atom [])]
296 (fn [data]
297 (if (> (count data) (count @windows))
298 (reset!
299 windows (map (fn [_] (view-image)) (range (count data)))))
300 (dorun
301 (map
302 (fn [display datum]
303 (display (sense-display-kernel datum)))
304 @windows data)))))
305
269 (defn gray 306 (defn gray
270 "Create a gray RGB pixel with R, G, and B set to num. num must be 307 "Create a gray RGB pixel with R, G, and B set to num. num must be
271 between 0 and 255." 308 between 0 and 255."
272 [num] 309 [num]
273 (+ num 310 (+ num
341 (.localToWorld object local-coordinate nil)) 378 (.localToWorld object local-coordinate nil))
342 #+end_src 379 #+end_src
343 380
344 =(bind-sense)= binds either a Camera or a Listener object to any 381 =(bind-sense)= binds either a Camera or a Listener object to any
345 object so that they will follow that object no matter how it 382 object so that they will follow that object no matter how it
346 moves. Here is some example code which shows a camera bound to a blue 383 moves. It is used to create both eyes and ears.
347 box as it is buffeted by white cannonballs.
348 384
349 #+name: node-2 385 #+name: node-2
350 #+begin_src clojure 386 #+begin_src clojure
351 (defn bind-sense 387 (defn bind-sense
352 "Bind the sense to the Spatial such that it will maintain its 388 "Bind the sense to the Spatial such that it will maintain its
372 sense 408 sense
373 (.mult total-rotation initial-sense-rotation)))) 409 (.mult total-rotation initial-sense-rotation))))
374 (controlRender [_ _]))))) 410 (controlRender [_ _])))))
375 #+end_src 411 #+end_src
376 412
413 Here is some example code which shows a camera bound to a blue
414 box as it is buffeted by white cannonballs.
415
416 #+name: test
417 #+begin_src clojure
418 (ns cortex.test.sense
419 (:use (cortex world util sense vision))
420 (:import
421 java.io.File
422 (com.jme3.math Vector3f ColorRGBA)
423 (com.aurellem.capture RatchetTimer Capture)))
424
425 (defn test-bind-sense
426 "Show a camera that stays in the same relative position to a blue cube."
427 []
428 (let [camera-pos (Vector3f. 0 30 0)
429 rock (box 1 1 1 :color ColorRGBA/Blue
430 :position (Vector3f. 0 10 0)
431 :mass 30)
432 rot (.getWorldRotation rock)
433 table (box 3 1 10 :color ColorRGBA/Gray :mass 0
434 :position (Vector3f. 0 -3 0))]
435 (world
436 (nodify [rock table])
437 standard-debug-controls
438 (fn [world]
439 (let
440 [cam (doto (.clone (.getCamera world))
441 (.setLocation camera-pos)
442 (.lookAt Vector3f/ZERO
443 Vector3f/UNIT_X))]
444 (bind-sense rock cam)
445 (.setTimer world (RatchetTimer. 60))
446 (Capture/captureVideo
447 world (File. "/home/r/proj/cortex/render/bind-sense0"))
448 (add-camera!
449 world cam
450 (comp (view-image
451 (File. "/home/r/proj/cortex/render/bind-sense1"))
452 BufferedImage!))
453 (add-camera! world (.getCamera world) no-op)))
454 no-op)))
455 #+end_src
456
457 ** Demo Video
458
459 #+begin_html
460 <video controls="controls" width="755">
461 <source src="../video/bind-sense.ogg" type="video/ogg"
462 preload="none" poster="../images/aurellem-1280x480.png" />
463 </video>
464
465 #+end_html
466
467 note to self: the video was created with the following commands:
468
469
470 #+begin_src clojure :results silent
471 (in-ns 'user)
472 (import java.io.File)
473 (use 'clojure.contrib.shell-out)
474
475 (let
476 [idx (atom -1)
477 left (rest
478 (sort
479 (file-seq (File. "/home/r/proj/cortex/render/bind-sense0/"))))
480 right (rest
481 (sort
482 (file-seq (File. "/home/r/proj/cortex/render/bind-sense1/"))))]
483 (dorun
484 (map
485 (fn [im-1 im-2]
486 (println idx)
487 (sh "convert" (.getCanonicalPath im-1)
488 (.getCanonicalPath im-2) "+append"
489 (.getCanonicalPath
490 (File. "/home/r/proj/cortex/render/bind-sense/"
491 (format "%07d.png" (swap! idx inc))))))
492 left right)))
493 #+end_src
494
495 #+begin_src sh :results silent
496 cd /home/r/proj/cortex/render/
497 cp ../images/aurellem-1280x480.png bind-sense/0000000.png
498 ffmpeg -r 60 -b 9000k -i bind-sense/%07d.png bind-sense.ogg
499 #+end_src
500
377 501
378 502
379 * Bookkeeping 503 * Bookkeeping
380 Here is the header for this namespace, included for completness. 504 Here is the header for this namespace, included for completness.
381 #+name header 505 #+name: header
382 #+begin_src clojure 506 #+begin_src clojure
383 (ns cortex.sense 507 (ns cortex.sense
384 "Here are functions useful in the construction of two or more 508 "Here are functions useful in the construction of two or more
385 sensors/effectors." 509 sensors/effectors."
386 {:author "Robert McInytre"} 510 {:author "Robert McInytre"}
390 (:import java.awt.image.BufferedImage) 514 (:import java.awt.image.BufferedImage)
391 (:import com.jme3.collision.CollisionResults) 515 (:import com.jme3.collision.CollisionResults)
392 (:import com.jme3.bounding.BoundingBox) 516 (:import com.jme3.bounding.BoundingBox)
393 (:import (com.jme3.scene Node Spatial)) 517 (:import (com.jme3.scene Node Spatial))
394 (:import com.jme3.scene.control.AbstractControl) 518 (:import com.jme3.scene.control.AbstractControl)
395 (:import (com.jme3.math Quaternion Vector3f))) 519 (:import (com.jme3.math Quaternion Vector3f))
520 (:import javax.imageio.ImageIO)
521 (:import java.io.File)
522 (:import (javax.swing JPanel JFrame SwingUtilities)))
523
396 #+end_src 524 #+end_src
397 525
398 * Source Listing 526 * Source Listing
399 Full source: [[../src/cortex/sense.clj][sense.clj]] 527 Full source: [[../src/cortex/sense.clj][sense.clj]]
400 528
408 <<topology-2>> 536 <<topology-2>>
409 <<node-1>> 537 <<node-1>>
410 <<node-2>> 538 <<node-2>>
411 <<view-senses>> 539 <<view-senses>>
412 #+end_src 540 #+end_src
541
542 #+begin_src clojure :tangle ../src/cortex/test/sense.clj
543 <<test>>
544 #+end_src