Mercurial > cortex
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 |