view org/eyes.org @ 113:a980462ebe76

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