annotate org/eyes.org @ 112:128fa71ee188

working on retina design
author Robert McIntyre <rlm@mit.edu>
date Thu, 19 Jan 2012 11:29:46 -0700
parents b7a3ba5e879b
children a980462ebe76
rev   line source
rlm@34 1 #+title: Simulated Sense of Sight
rlm@23 2 #+author: Robert McIntyre
rlm@23 3 #+email: rlm@mit.edu
rlm@38 4 #+description: Simulated sight for AI research using JMonkeyEngine3 and clojure
rlm@34 5 #+keywords: computer vision, jMonkeyEngine3, clojure
rlm@23 6 #+SETUPFILE: ../../aurellem/org/setup.org
rlm@23 7 #+INCLUDE: ../../aurellem/org/level-0.org
rlm@23 8 #+babel: :mkdirp yes :noweb yes :exports both
rlm@23 9
rlm@34 10 * Vision
rlm@23 11
rlm@34 12 I want to make creatures with eyes. Each eye can be independely moved
rlm@34 13 and should see its own version of the world depending on where it is.
rlm@66 14 #+name: eyes
rlm@23 15 #+begin_src clojure
rlm@34 16 (ns cortex.vision
rlm@34 17 "Simulate the sense of vision in jMonkeyEngine3. Enables multiple
rlm@34 18 eyes from different positions to observe the same world, and pass
rlm@34 19 the observed data to any arbitray function."
rlm@34 20 {:author "Robert McIntyre"}
rlm@34 21 (:use cortex.world)
rlm@34 22 (:import com.jme3.post.SceneProcessor)
rlm@112 23 (:import (com.jme3.util BufferUtils))
rlm@34 24 (:import java.nio.ByteBuffer)
rlm@34 25 (:import java.awt.image.BufferedImage)
rlm@34 26 (:import com.jme3.renderer.ViewPort)
rlm@34 27 (:import com.jme3.math.ColorRGBA))
rlm@23 28
rlm@23 29 (defn scene-processor
rlm@34 30 "Create a SceneProcessor object which wraps a vision processing
rlm@34 31 continuation function. The SceneProcessor will take care of
rlm@34 32 converting the rendered frame to a BufferedImage and passing that
rlm@34 33 BufferedImage to the continuation. The continuation should be a
rlm@112 34 function that takes a ByteBuffer which represents the image."
rlm@23 35 [continuation]
rlm@23 36 (let [byte-buffer (atom nil)
rlm@112 37 renderer (atom nil)]
rlm@23 38 (proxy [SceneProcessor] []
rlm@23 39 (initialize
rlm@23 40 [renderManager viewPort]
rlm@23 41 (let [cam (.getCamera viewPort)
rlm@23 42 width (.getWidth cam)
rlm@23 43 height (.getHeight cam)]
rlm@23 44 (reset! renderer (.getRenderer renderManager))
rlm@23 45 (reset! byte-buffer
rlm@23 46 (BufferUtils/createByteBuffer
rlm@112 47 (* width height 4)))))
rlm@23 48 (isInitialized [] (not (nil? @byte-buffer)))
rlm@23 49 (reshape [_ _ _])
rlm@23 50 (preFrame [_])
rlm@23 51 (postQueue [_])
rlm@23 52 (postFrame
rlm@23 53 [#^FrameBuffer fb]
rlm@23 54 (.clear @byte-buffer)
rlm@112 55 ;;(.readFrameBuffer @renderer fb @byte-buffer)
rlm@112 56 (continuation @byte-buffer))
rlm@23 57 (cleanup []))))
rlm@23 58
rlm@112 59 (defn buffer->image! [width height]
rlm@112 60 (let [image (BufferedImage. width height
rlm@112 61 BufferedImage/TYPE_4BYTE_ABGR)]
rlm@112 62 (fn [byte-buffer]
rlm@112 63 (Screenshots/convertScreenShot byte-buffer image)
rlm@112 64 image)))
rlm@112 65
rlm@23 66 (defn add-eye
rlm@34 67 "Add an eye to the world, calling continuation on every frame
rlm@34 68 produced."
rlm@23 69 [world camera continuation]
rlm@23 70 (let [width (.getWidth camera)
rlm@23 71 height (.getHeight camera)
rlm@23 72 render-manager (.getRenderManager world)
rlm@23 73 viewport (.createMainView render-manager "eye-view" camera)]
rlm@23 74 (doto viewport
rlm@23 75 (.setClearFlags true true true)
rlm@112 76 (.setBackgroundColor ColorRGBA/Black)
rlm@23 77 (.addProcessor (scene-processor continuation))
rlm@23 78 (.attachScene (.getRootNode world)))))
rlm@34 79 #+end_src
rlm@23 80
rlm@112 81 #+results: eyes
rlm@112 82 : #'cortex.vision/add-eye
rlm@112 83
rlm@34 84 Note the use of continuation passing style for connecting the eye to a
rlm@34 85 function to process the output. You can create any number of eyes, and
rlm@34 86 each of them will see the world from their own =Camera=. Once every
rlm@34 87 frame, the rendered image is copied to a =BufferedImage=, and that
rlm@34 88 data is sent off to the continuation function. Moving the =Camera=
rlm@34 89 which was used to create the eye will change what the eye sees.
rlm@23 90
rlm@34 91 * Example
rlm@23 92
rlm@66 93 #+name: test-vision
rlm@23 94 #+begin_src clojure
rlm@68 95 (ns cortex.test.vision
rlm@34 96 (:use (cortex world util vision))
rlm@34 97 (:import java.awt.image.BufferedImage)
rlm@34 98 (:import javax.swing.JPanel)
rlm@34 99 (:import javax.swing.SwingUtilities)
rlm@34 100 (:import java.awt.Dimension)
rlm@34 101 (:import javax.swing.JFrame)
rlm@34 102 (:import com.jme3.math.ColorRGBA)
rlm@45 103 (:import com.jme3.scene.Node)
rlm@112 104 (:import com.jme3.math.Vector3f)
rlm@112 105 (:import (com.jme3.util Screenshots)))
rlm@23 106
rlm@34 107 (defn view-image
rlm@99 108 "Initailizes a JPanel on which you may draw a BufferedImage.
rlm@99 109 Returns a function that accepts a BufferedImage and draws it to the
rlm@99 110 JPanel."
rlm@99 111 []
rlm@34 112 (let [image
rlm@34 113 (atom
rlm@99 114 (BufferedImage. 1 1 BufferedImage/TYPE_4BYTE_ABGR))
rlm@34 115 panel
rlm@34 116 (proxy [JPanel] []
rlm@34 117 (paint
rlm@34 118 [graphics]
rlm@34 119 (proxy-super paintComponent graphics)
rlm@99 120 (.drawImage graphics @image 0 0 nil)))
rlm@99 121 frame (JFrame. "Display Image")]
rlm@34 122 (SwingUtilities/invokeLater
rlm@34 123 (fn []
rlm@99 124 (doto frame
rlm@34 125 (-> (.getContentPane) (.add panel))
rlm@34 126 (.pack)
rlm@34 127 (.setLocationRelativeTo nil)
rlm@99 128 (.setResizable true)
rlm@34 129 (.setVisible true))))
rlm@34 130 (fn [#^BufferedImage i]
rlm@34 131 (reset! image i)
rlm@99 132 (.setSize frame (+ 8 (.getWidth i)) (+ 28 (.getHeight i)))
rlm@99 133 (.repaint panel 0 0 (.getWidth i) (.getHeight i)))))
rlm@23 134
rlm@36 135 (defn test-two-eyes
rlm@69 136 "Testing vision:
rlm@69 137 Tests the vision system by creating two views of the same rotating
rlm@69 138 object from different angles and displaying both of those views in
rlm@69 139 JFrames.
rlm@69 140
rlm@69 141 You should see a rotating cube, and two windows,
rlm@69 142 each displaying a different view of the cube."
rlm@36 143 []
rlm@58 144 (let [candy
rlm@58 145 (box 1 1 1 :physical? false :color ColorRGBA/Blue)]
rlm@112 146 (world
rlm@112 147 (doto (Node.)
rlm@112 148 (.attachChild candy))
rlm@112 149 {}
rlm@112 150 (fn [world]
rlm@112 151 (let [cam (.clone (.getCamera world))
rlm@112 152 width (.getWidth cam)
rlm@112 153 height (.getHeight cam)]
rlm@112 154 (add-eye world cam
rlm@112 155 no-op
rlm@112 156 ;;(comp (view-image) (buffer->image! width height))
rlm@112 157 )
rlm@112 158 (add-eye world
rlm@112 159 (doto (.clone cam)
rlm@112 160 (.setLocation (Vector3f. -10 0 0))
rlm@112 161 (.lookAt Vector3f/ZERO Vector3f/UNIT_Y))
rlm@112 162 no-op
rlm@112 163 ;;(comp (view-image) (buffer->image! width height))
rlm@112 164 )
rlm@112 165
rlm@112 166
rlm@112 167 ;; This is here to restore the main view
rlm@112 168 ;; after the other views have completed processing
rlm@112 169 (add-eye world (.getCamera world) no-op)))
rlm@112 170 (fn [world tpf]
rlm@112 171 (.rotate candy (* tpf 0.2) 0 0)))))
rlm@23 172 #+end_src
rlm@23 173
rlm@112 174 #+results: test-vision
rlm@112 175 : #'cortex.test.vision/test-two-eyes
rlm@112 176
rlm@34 177 The example code will create two videos of the same rotating object
rlm@34 178 from different angles. It can be used both for stereoscopic vision
rlm@34 179 simulation or for simulating multiple creatures, each with their own
rlm@34 180 sense of vision.
rlm@24 181
rlm@35 182 - As a neat bonus, this idea behind simulated vision also enables one
rlm@35 183 to [[../../cortex/html/capture-video.html][capture live video feeds from jMonkeyEngine]].
rlm@35 184
rlm@24 185
rlm@24 186 * COMMENT code generation
rlm@34 187 #+begin_src clojure :tangle ../src/cortex/vision.clj
rlm@24 188 <<eyes>>
rlm@24 189 #+end_src
rlm@24 190
rlm@68 191 #+begin_src clojure :tangle ../src/cortex/test/vision.clj
rlm@24 192 <<test-vision>>
rlm@24 193 #+end_src