env_mt_visual_cortex.c

Go to the documentation of this file.
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
Generated on Sun May 8 08:04:45 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3