00001 /*!@file Envision/env_mt_visual_cortex.c */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Envision/env_mt_visual_cortex.c $ 00035 // $Id: env_mt_visual_cortex.c 10990 2009-03-06 02:44:38Z itti $ 00036 // 00037 00038 #ifndef ENVISION_ENV_MT_VISUAL_CORTEX_C_DEFINED 00039 #define ENVISION_ENV_MT_VISUAL_CORTEX_C_DEFINED 00040 00041 #include "Envision/env_mt_visual_cortex.h" 00042 00043 #include "Envision/env_c_math_ops.h" 00044 #include "Envision/env_channel.h" 00045 #include "Envision/env_image_ops.h" 00046 #include "Envision/env_job_server.h" 00047 #include "Envision/env_log.h" 00048 #include "Envision/env_mt_channel.h" 00049 #include "Envision/env_params.h" 00050 00051 #define WEIGHT_SCALEBITS ((env_size_t) 8) 00052 00053 static void combine_output(struct env_image* chanOut, 00054 const intg32 iweight, 00055 struct env_image* result) 00056 { 00057 if (!env_img_initialized(chanOut)) 00058 return; 00059 00060 intg32* const sptr = env_img_pixelsw(chanOut); 00061 const env_size_t sz = env_img_size(chanOut); 00062 00063 if (!env_img_initialized(result)) 00064 { 00065 env_img_resize_dims(result, chanOut->dims); 00066 intg32* const dptr = env_img_pixelsw(result); 00067 for (env_size_t i = 0; i < sz; ++i) 00068 { 00069 sptr[i] = (sptr[i] >> WEIGHT_SCALEBITS) * iweight; 00070 dptr[i] = sptr[i]; 00071 } 00072 } 00073 else 00074 { 00075 ENV_ASSERT(env_dims_equal(chanOut->dims, result->dims)); 00076 intg32* const dptr = env_img_pixelsw(result); 00077 const env_size_t sz = env_img_size(result); 00078 for (env_size_t i = 0; i < sz; ++i) 00079 { 00080 sptr[i] = (sptr[i] >> WEIGHT_SCALEBITS) * iweight; 00081 dptr[i] += sptr[i]; 00082 } 00083 } 00084 } 00085 00086 struct env_color_job_data 00087 { 00088 const struct env_params* envp; 00089 const struct env_math* imath; 00090 const struct env_rgb_pixel* const colimg; 00091 const struct env_rgb_pixel* const prev_colimg /* or null is fine here */; 00092 const struct env_dims dims; 00093 env_chan_status_func* status_func; 00094 void* status_userdata; 00095 00096 struct env_image colorOut; 00097 }; 00098 00099 static void env_color_job_run(void* p) 00100 { 00101 struct env_color_job_data* j = (struct env_color_job_data*)(p); 00102 env_chan_color 00103 ("color", j->envp, j->imath, j->colimg, j->prev_colimg, 00104 j->dims, j->status_func, j->status_userdata, 00105 &j->colorOut); 00106 } 00107 00108 struct env_intens_job_data 00109 { 00110 const struct env_params* envp; 00111 const struct env_math* imath; 00112 const struct env_dims dims; 00113 const struct env_pyr* lowpass5; 00114 const int normalizeOutput; 00115 env_chan_status_func* status_func; 00116 void* status_userdata; 00117 00118 struct env_image intensityOut; 00119 }; 00120 00121 static void env_intens_job_run(void* p) 00122 { 00123 struct env_intens_job_data* j = (struct env_intens_job_data*)(p); 00124 env_chan_intensity 00125 ("intensity", j->envp, j->imath, j->dims, 00126 j->lowpass5, j->normalizeOutput, 00127 j->status_func, j->status_userdata, 00128 &j->intensityOut); 00129 } 00130 00131 struct env_ori_job_data 00132 { 00133 const struct env_params* envp; 00134 const struct env_math* imath; 00135 const struct env_image* bwimg; 00136 env_chan_status_func* status_func; 00137 void* status_userdata; 00138 00139 struct env_image orientationOut; 00140 }; 00141 00142 static void env_ori_job_run(void* p) 00143 { 00144 struct env_ori_job_data* j = (struct env_ori_job_data*)(p); 00145 env_mt_chan_orientation 00146 ("orientation", j->envp, j->imath, j->bwimg, 00147 j->status_func, j->status_userdata, 00148 &j->orientationOut); 00149 } 00150 00151 struct env_flicker_job_data 00152 { 00153 const struct env_params* envp; 00154 const struct env_math* imath; 00155 const struct env_dims dims; 00156 const struct env_pyr* prev_lowpass5; 00157 const struct env_pyr* lowpass5; 00158 const struct env_image* prev_bwimg; 00159 const struct env_image* bwimg; 00160 env_chan_status_func* status_func; 00161 void* status_userdata; 00162 00163 struct env_image flickerOut; 00164 }; 00165 00166 static void env_flicker_job_run(void* p) 00167 { 00168 struct env_flicker_job_data* j = (struct env_flicker_job_data*)(p); 00169 if (j->envp->multiscale_flicker) 00170 env_chan_msflicker 00171 ("flicker", j->envp, j->imath, j->dims, 00172 j->prev_lowpass5, j->lowpass5, 00173 j->status_func, j->status_userdata, 00174 &j->flickerOut); 00175 else 00176 env_chan_flicker 00177 ("flicker", j->envp, j->imath, 00178 j->prev_bwimg, j->bwimg, 00179 j->status_func, j->status_userdata, 00180 &j->flickerOut); 00181 } 00182 00183 struct env_motion_job_data 00184 { 00185 struct env_motion_channel* motion_chan; 00186 const struct env_params* envp; 00187 const struct env_math* imath; 00188 const struct env_dims dims; 00189 struct env_pyr lowpass5; 00190 env_chan_status_func* status_func; 00191 void* status_userdata; 00192 00193 struct env_image motionOut; 00194 }; 00195 00196 static void env_motion_job_run(void* p) 00197 { 00198 struct env_motion_job_data* j = (struct env_motion_job_data*)(p); 00199 env_mt_motion_channel_input_and_consume_pyr 00200 (j->motion_chan, 00201 "motion", j->envp, j->imath, j->dims, &j->lowpass5, 00202 j->status_func, j->status_userdata, 00203 &j->motionOut); 00204 } 00205 00206 // ###################################################################### 00207 void env_mt_visual_cortex_input( 00208 const int do_multithreaded, 00209 struct env_visual_cortex* vcx, 00210 const struct env_params* envp, 00211 const char* tagName, 00212 const struct env_rgb_pixel* const colimg, 00213 const struct env_rgb_pixel* const prev_colimg, 00214 const struct env_dims dims, 00215 env_chan_status_func* status_func, 00216 void* status_userdata, 00217 struct env_image* result, 00218 struct env_image* intens_result, 00219 struct env_image* color_result, 00220 struct env_image* ori_result 00221 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00222 , 00223 struct env_image* flicker_result, 00224 struct env_image* motion_result 00225 #endif 00226 ) 00227 { 00228 if (!do_multithreaded) 00229 { 00230 env_visual_cortex_input( 00231 vcx, envp, tagName, colimg, prev_colimg, dims, 00232 status_func, status_userdata, 00233 result, 00234 intens_result, color_result, ori_result 00235 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00236 , flicker_result, motion_result 00237 #endif 00238 ); 00239 return; 00240 } 00241 00242 env_img_make_empty(result); 00243 00244 const intg32 total_weight = env_total_weight(envp); 00245 00246 ENV_ASSERT(total_weight > 0); 00247 00248 /* We want to compute 00249 00250 * weight 00251 * img * ------------ 00252 * total_weight 00253 * 00254 * 00255 * To do that without overflowing, we compute it as 00256 * 00257 * 00258 * weight 256 00259 * img * ------------ * --- 00260 * total_weight 256 00261 * 00262 * img weight * 256 00263 * = ( --- ) * ( ------------ ) 00264 * 256 total_weight 00265 * 00266 * where 256 is an example of (1<<WEIGHT_SCALEBITS) for 00267 * WEIGHT_SCALEBITS=8. 00268 */ 00269 00270 struct env_job jobs[5]; 00271 env_size_t njobs = 0; 00272 00273 struct env_color_job_data c_data = 00274 { 00275 envp, 00276 &vcx->imath, 00277 colimg, 00278 prev_colimg, 00279 dims, 00280 status_func, 00281 status_userdata, 00282 env_img_initializer 00283 }; 00284 00285 if (envp->chan_c_weight > 0) 00286 { 00287 jobs[njobs].callback = &env_color_job_run; 00288 jobs[njobs].userdata = &c_data; 00289 ++njobs; 00290 } 00291 00292 struct env_image bwimg; 00293 env_img_init(&bwimg, dims); 00294 env_c_luminance_from_byte(colimg, dims.w * dims.h, 00295 vcx->imath.nbits, env_img_pixelsw(&bwimg)); 00296 00297 struct env_pyr lowpass5; 00298 env_pyr_init(&lowpass5, env_max_pyr_depth(envp)); 00299 env_pyr_build_lowpass_5(&bwimg, 00300 envp->cs_lev_min, 00301 &vcx->imath, 00302 &lowpass5); 00303 00304 struct env_intens_job_data i_data = 00305 { 00306 envp, 00307 &vcx->imath, 00308 bwimg.dims, 00309 &lowpass5, 00310 1, 00311 status_func, 00312 status_userdata, 00313 env_img_initializer 00314 }; 00315 00316 if (envp->chan_i_weight > 0) 00317 { 00318 jobs[njobs].callback = &env_intens_job_run; 00319 jobs[njobs].userdata = &i_data; 00320 ++njobs; 00321 } 00322 00323 struct env_ori_job_data o_data = 00324 { 00325 envp, 00326 &vcx->imath, 00327 &bwimg, 00328 status_func, 00329 status_userdata, 00330 env_img_initializer 00331 }; 00332 00333 if (envp->chan_o_weight > 0) 00334 { 00335 jobs[njobs].callback = &env_ori_job_run; 00336 jobs[njobs].userdata = &o_data; 00337 ++njobs; 00338 } 00339 00340 struct env_flicker_job_data f_data = 00341 { 00342 envp, 00343 &vcx->imath, 00344 bwimg.dims, 00345 &vcx->prev_lowpass5, 00346 &lowpass5, 00347 &vcx->prev_input, 00348 &bwimg, 00349 status_func, 00350 status_userdata, 00351 env_img_initializer 00352 }; 00353 00354 if (envp->chan_f_weight > 0) 00355 { 00356 jobs[njobs].callback = &env_flicker_job_run; 00357 jobs[njobs].userdata = &f_data; 00358 ++njobs; 00359 } 00360 00361 struct env_motion_job_data m_data = 00362 { 00363 &vcx->motion_chan, 00364 envp, 00365 &vcx->imath, 00366 bwimg.dims, 00367 env_pyr_initializer, 00368 status_func, 00369 status_userdata, 00370 env_img_initializer 00371 }; 00372 00373 if (envp->chan_m_weight > 0) 00374 { 00375 env_pyr_copy_src_dst(&lowpass5, &m_data.lowpass5); 00376 jobs[njobs].callback = &env_motion_job_run; 00377 jobs[njobs].userdata = &m_data; 00378 ++njobs; 00379 } 00380 00381 env_run_jobs(&jobs[0], njobs); 00382 00383 if (env_img_initialized(&c_data.colorOut)) 00384 { 00385 const intg32 color_weight = 00386 envp->chan_c_weight*(1<<WEIGHT_SCALEBITS) / total_weight; 00387 00388 combine_output(&c_data.colorOut, color_weight, result); 00389 if (color_result != 0) 00390 env_img_swap(&c_data.colorOut, color_result); 00391 env_img_make_empty(&c_data.colorOut); 00392 } 00393 00394 if (env_img_initialized(&i_data.intensityOut)) 00395 { 00396 const intg32 intensity_weight = 00397 envp->chan_i_weight*(1<<WEIGHT_SCALEBITS) / total_weight; 00398 00399 combine_output(&i_data.intensityOut, 00400 intensity_weight, result); 00401 if (intens_result != 0) 00402 env_img_swap(&i_data.intensityOut, intens_result); 00403 env_img_make_empty(&i_data.intensityOut); 00404 } 00405 00406 if (env_img_initialized(&o_data.orientationOut)) 00407 { 00408 const intg32 orientation_weight = 00409 envp->chan_o_weight*(1<<WEIGHT_SCALEBITS) / total_weight; 00410 00411 combine_output(&o_data.orientationOut, 00412 orientation_weight, result); 00413 if (ori_result != 0) 00414 env_img_swap(&o_data.orientationOut, ori_result); 00415 env_img_make_empty(&o_data.orientationOut); 00416 } 00417 00418 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00419 00420 if (env_img_initialized(&f_data.flickerOut)) 00421 { 00422 const intg32 flicker_weight = 00423 envp->chan_f_weight*(1<<WEIGHT_SCALEBITS) / total_weight; 00424 00425 combine_output(&f_data.flickerOut, flicker_weight, result); 00426 if (flicker_result != 0) 00427 env_img_swap(&f_data.flickerOut, flicker_result); 00428 env_img_make_empty(&f_data.flickerOut); 00429 } 00430 00431 if (envp->chan_f_weight > 0) 00432 { 00433 if (envp->multiscale_flicker) 00434 env_pyr_copy_src_dst 00435 (&lowpass5, &vcx->prev_lowpass5); 00436 else 00437 env_pyr_make_empty(&vcx->prev_lowpass5); 00438 } 00439 00440 if (env_img_initialized(&m_data.motionOut)) 00441 { 00442 const intg32 motion_weight = 00443 envp->chan_m_weight*(1<<WEIGHT_SCALEBITS) / total_weight; 00444 00445 combine_output(&m_data.motionOut, motion_weight, result); 00446 if (motion_result != 0) 00447 env_img_swap(&m_data.motionOut, motion_result); 00448 env_img_make_empty(&m_data.motionOut); 00449 00450 env_pyr_make_empty(&m_data.lowpass5); 00451 } 00452 00453 if (!envp->multiscale_flicker) 00454 env_img_swap(&vcx->prev_input, &bwimg); 00455 else 00456 env_img_make_empty(&vcx->prev_input); 00457 00458 #endif 00459 00460 if (status_func) 00461 (*status_func)(status_userdata, tagName, result); 00462 00463 env_pyr_make_empty(&lowpass5); 00464 env_img_make_empty(&bwimg); 00465 } 00466 00467 // ###################################################################### 00468 /* So things look consistent in everyone's emacs... */ 00469 /* Local Variables: */ 00470 /* indent-tabs-mode: nil */ 00471 /* c-file-style: "linux" */ 00472 /* End: */ 00473 00474 #endif // ENVISION_ENV_MT_VISUAL_CORTEX_C_DEFINED