comparison org/vision.org @ 214:01d3e9855ef9

saving progress, time to sleep.....
author Robert McIntyre <rlm@mit.edu>
date Thu, 09 Feb 2012 09:04:17 -0700
parents 319963720179
children f283c62bd212
comparison
equal deleted inserted replaced
213:319963720179 214:01d3e9855ef9
43 43
44 * The Vision Pipeline 44 * The Vision Pipeline
45 45
46 Each eye in the simulated creature needs it's own =ViewPort= so that 46 Each eye in the simulated creature needs it's own =ViewPort= so that
47 it can see the world from its own perspective. To this =ViewPort=, I 47 it can see the world from its own perspective. To this =ViewPort=, I
48 add a =SceneProcessor= that feeds the visual data to any arbitra 48 add a =SceneProcessor= that feeds the visual data to any arbitray
49 continuation function for further processing. That continuation 49 continuation function for further processing. That continuation
50 function may perform both CPU and GPU operations on the data. To make 50 function may perform both CPU and GPU operations on the data. To make
51 this easy for the continuation function, the =SceneProcessor= 51 this easy for the continuation function, the =SceneProcessor=
52 maintains appropriatly sized buffers in RAM to hold the data. It does 52 maintains appropriatly sized buffers in RAM to hold the data. It does
53 not do any copying from the GPU to the CPU itself. 53 not do any copying from the GPU to the CPU itself.
54
54 #+name: pipeline-1 55 #+name: pipeline-1
55 #+begin_src clojure 56 #+begin_src clojure
56 (defn vision-pipeline 57 (defn vision-pipeline
57 "Create a SceneProcessor object which wraps a vision processing 58 "Create a SceneProcessor object which wraps a vision processing
58 continuation function. The continuation is a function that takes 59 continuation function. The continuation is a function that takes
121 entirely in terms of =BufferedImage= inputs. Just compose that 122 entirely in terms of =BufferedImage= inputs. Just compose that
122 =BufferedImage= algorithm with =(BufferedImage!)=. However, a vision 123 =BufferedImage= algorithm with =(BufferedImage!)=. However, a vision
123 processing algorithm that is entirely hosted on the GPU does not have 124 processing algorithm that is entirely hosted on the GPU does not have
124 to pay for this convienence. 125 to pay for this convienence.
125 126
126 127 * COMMENT asdasd
127 * Physical Eyes
128
129 The vision pipeline described above only deals with
130 Each eye in the creature in blender will work the same way as
131 joints -- a zero dimensional object with no geometry whose local
132 coordinate system determines the orientation of the resulting
133 eye. All eyes will have a parent named "eyes" just as all joints
134 have a parent named "joints". The resulting camera will be a
135 ChaseCamera or a CameraNode bound to the geo that is closest to
136 the eye marker. The eye marker will contain the metadata for the
137 eye, and will be moved by it's bound geometry. The dimensions of
138 the eye's camera are equal to the dimensions of the eye's "UV"
139 map.
140 128
141 (vision creature) will take an optional :skip argument which will 129 (vision creature) will take an optional :skip argument which will
142 inform the continuations in scene processor to skip the given 130 inform the continuations in scene processor to skip the given
143 number of cycles 0 means that no cycles will be skipped. 131 number of cycles 0 means that no cycles will be skipped.
144 132
154 by the continuation function established by its init-function. 142 by the continuation function established by its init-function.
155 They can be queried every cycle, but their information may not 143 They can be queried every cycle, but their information may not
156 necessairly be different every cycle. 144 necessairly be different every cycle.
157 145
158 146
159 #+begin_src clojure 147
160 (defn add-camera! 148 * Physical Eyes
161 "Add a camera to the world, calling continuation on every frame 149
162 produced." 150 The vision pipeline described above handles the flow of rendered
163 [#^Application world camera continuation] 151 images. Now, we need simulated eyes to serve as the source of these
164 (let [width (.getWidth camera) 152 images.
165 height (.getHeight camera) 153
166 render-manager (.getRenderManager world) 154 An eye is described in blender in the same way as a joint. They are
167 viewport (.createMainView render-manager "eye-view" camera)] 155 zero dimensional empty objects with no geometry whose local coordinate
168 (doto viewport 156 system determines the orientation of the resulting eye. All eyes are
169 (.setClearFlags true true true) 157 childern of a parent node named "eyes" just as all joints have a
170 (.setBackgroundColor ColorRGBA/Black) 158 parent named "joints". An eye binds to the nearest physical object
171 (.addProcessor (vision-pipeline continuation)) 159 with =(bind-sense=).
172 (.attachScene (.getRootNode world))))) 160
173 161 #+name: add-eye
174 (defn retina-sensor-profile 162 #+begin_src clojure
175 "Return a map of pixel selection functions to BufferedImages
176 describing the distribution of light-sensitive components of this
177 eye. Each function creates an integer from the rgb values found in
178 the pixel. :red, :green, :blue, :gray are already defined as
179 extracting the red, green, blue, and average components
180 respectively."
181 [#^Spatial eye]
182 (if-let [eye-map (meta-data eye "eye")]
183 (map-vals
184 load-image
185 (eval (read-string eye-map)))))
186
187 (defn eye-dimensions
188 "Returns [width, height] specified in the metadata of the eye"
189 [#^Spatial eye]
190 (let [dimensions
191 (map #(vector (.getWidth %) (.getHeight %))
192 (vals (retina-sensor-profile eye)))]
193 [(apply max (map first dimensions))
194 (apply max (map second dimensions))]))
195
196 (defvar
197 ^{:arglists '([creature])}
198 eyes
199 (sense-nodes "eyes")
200 "Return the children of the creature's \"eyes\" node.")
201
202 (defn add-eye! 163 (defn add-eye!
203 "Create a Camera centered on the current position of 'eye which 164 "Create a Camera centered on the current position of 'eye which
204 follows the closest physical node in 'creature and sends visual 165 follows the closest physical node in 'creature and sends visual
205 data to 'continuation." 166 data to 'continuation."
206 [#^Node creature #^Spatial eye] 167 [#^Node creature #^Spatial eye]
212 (.setFrustumPerspective 173 (.setFrustumPerspective
213 cam 45 (/ (.getWidth cam) (.getHeight cam)) 174 cam 45 (/ (.getWidth cam) (.getHeight cam))
214 1 1000) 175 1 1000)
215 (bind-sense target cam) 176 (bind-sense target cam)
216 cam)) 177 cam))
217 178 #+end_src
218 (defvar color-channel-presets 179
180 Here, the camera is created based on metadata on the eye-node and
181 attached to the nearest physical object with =(bind-sense)=
182
183
184 ** The Retina
185
186 An eye is a surface (the retina) which contains many discrete sensors
187 to detect light. These sensors have can have different-light sensing
188 properties. In humans, each discrete sensor is sensitive to red,
189 blue, green, or gray. These different types of sensors can have
190 different spatial distributions along the retina. In humans, there is
191 a fovea in the center of the retina which has a very high density of
192 color sensors, and a blind spot which has no sensors at all. Sensor
193 density decreases in proportion to distance from the retina.
194
195 I want to be able to model any retinal configuration, so my eye-nodes
196 in blender contain metadata pointing to images that describe the
197 percise position of the individual sensors using white pixels. The
198 meta-data also describes the percise sensitivity to light that the
199 sensors described in the image have. An eye can contain any number of
200 these images. For example, the metadata for an eye might look like
201 this:
202
203 #+begin_src clojure
204 {0xFF0000 "Models/test-creature/retina-small.png"}
205 #+end_src
206
207 #+caption: The retinal profile image "Models/test-creature/retina-small.png". White pixels are photo-sensitive elements. The distribution of white pixels is denser in the middle and falls off at the edges and is inspired by the human retina.
208 [[../assets/Models/test-creature/retina-small.png]]
209
210 Together, the number 0xFF0000 and the image image above describe the
211 placement of red-sensitive sensory elements.
212
213 Meta-data to very crudely approximate a human eye might be something
214 like this:
215
216 #+begin_src clojure
217 (let [retinal-profile "Models/test-creature/retina-small.png"]
218 {0xFF0000 retinal-profile
219 0x00FF00 retinal-profile
220 0x0000FF retinal-profile
221 0xFFFFFF retinal-profile})
222 #+end_src
223
224 The numbers that serve as keys in the map determine a sensor's
225 relative sensitivity to the channels red, green, and blue. These
226 sensitivity values are packed into an integer in the order _RGB in
227 8-bit fields. The RGB values of a pixel in the image are added
228 together with these sensitivities as linear weights. Therfore,
229 0xFF0000 means sensitive to red only while 0xFFFFFF means sensitive to
230 all colors equally (gray).
231
232 For convienence I've defined a few symbols for the more common
233 sensitivity values.
234
235 #+name: sensitivity
236 #+begin_src clojure
237 (defvar sensitivity-presets
219 {:all 0xFFFFFF 238 {:all 0xFFFFFF
220 :red 0xFF0000 239 :red 0xFF0000
221 :blue 0x0000FF 240 :blue 0x0000FF
222 :green 0x00FF00} 241 :green 0x00FF00}
223 "Bitmasks for common RGB color channels") 242 "Retinal sensitivity presets for sensors that extract one channel
243 (:red :blue :green) or average all channels (:gray)")
244 #+end_src
245
246 ** Metadata Processing
247
248 =(retina-sensor-profile)= extracts a map from the eye-node in the same
249 format as the example maps above. =(eye-dimensions)= finds the
250 dimansions of the smallest image required to contain all the retinal
251 sensor maps.
252
253 #+begin_src clojure
254 (defn retina-sensor-profile
255 "Return a map of pixel sensitivity numbers to BufferedImages
256 describing the distribution of light-sensitive components of this
257 eye. :red, :green, :blue, :gray are already defined as extracting
258 the red, green, blue, and average components respectively."
259 [#^Spatial eye]
260 (if-let [eye-map (meta-data eye "eye")]
261 (map-vals
262 load-image
263 (eval (read-string eye-map)))))
264
265 (defn eye-dimensions
266 "Returns [width, height] specified in the metadata of the eye"
267 [#^Spatial eye]
268 (let [dimensions
269 (map #(vector (.getWidth %) (.getHeight %))
270 (vals (retina-sensor-profile eye)))]
271 [(apply max (map first dimensions))
272 (apply max (map second dimensions))]))
273 #+end_src
274
275
276 * Eye Creation
277
278 First off, get the children of the "eyes" empty node to find all the
279 eyes the creature has.
280
281 #+begin_src clojure
282 (defvar
283 ^{:arglists '([creature])}
284 eyes
285 (sense-nodes "eyes")
286 "Return the children of the creature's \"eyes\" node.")
287 #+end_src
288
289 Then,
290
291 #+begin_src clojure
292 (defn add-camera!
293 "Add a camera to the world, calling continuation on every frame
294 produced."
295 [#^Application world camera continuation]
296 (let [width (.getWidth camera)
297 height (.getHeight camera)
298 render-manager (.getRenderManager world)
299 viewport (.createMainView render-manager "eye-view" camera)]
300 (doto viewport
301 (.setClearFlags true true true)
302 (.setBackgroundColor ColorRGBA/Black)
303 (.addProcessor (vision-pipeline continuation))
304 (.attachScene (.getRootNode world)))))
305
306
307
308
224 309
225 (defn vision-fn 310 (defn vision-fn
226 "Returns a list of functions, each of which will return a color 311 "Returns a list of functions, each of which will return a color
227 channel's worth of visual information when called inside a running 312 channel's worth of visual information when called inside a running
228 simulation." 313 simulation."
247 (vec 332 (vec
248 (map 333 (map
249 (fn [[key image]] 334 (fn [[key image]]
250 (let [whites (white-coordinates image) 335 (let [whites (white-coordinates image)
251 topology (vec (collapse whites)) 336 topology (vec (collapse whites))
252 mask (color-channel-presets key)] 337 mask (color-channel-presets key key)]
253 (fn [world] 338 (fn [world]
254 (register-eye! world) 339 (register-eye! world)
255 (vector 340 (vector
256 topology 341 topology
257 (vec 342 (vec