00001 /*!@file Neuro/EnvVisualCortex.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/Neuro/EnvVisualCortex.C $ 00035 // $Id: EnvVisualCortex.C 12651 2010-01-25 21:54:07Z itti $ 00036 // 00037 00038 #ifndef NEURO_ENVVISUALCORTEX_C_DEFINED 00039 #define NEURO_ENVVISUALCORTEX_C_DEFINED 00040 00041 #include "Neuro/EnvVisualCortex.H" 00042 00043 #include "Component/ModelOptionDef.H" 00044 #include "Envision/env_c_math_ops.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_visual_cortex.h" 00049 #include "Envision/env_pthread_interface.h" 00050 #include "Envision/env_stdio_interface.h" 00051 #include "Neuro/EnvOpts.H" 00052 #include "Util/AllocAux.H" 00053 #include "Util/JobWithSemaphore.H" 00054 #include "Util/StringConversions.H" 00055 #include "Util/WorkThreadServer.H" 00056 00057 #include <cstdio> 00058 #include <sstream> 00059 #include <vector> 00060 00061 // Used by: EnvVisualCortex 00062 const ModelOptionDef OPT_EvcMaxnormType = 00063 { MODOPT_ARG(std::string), "EvcMaxnormType", &MOC_ENVISION, OPTEXP_CORE, 00064 "Type of normalization to use", 00065 "evc-maxnorm-type", '\0', "<None|Maxnorm>", "Maxnorm" }; 00066 00067 // Used by: EnvVisualCortex 00068 const ModelOptionDef OPT_EvcScaleBits = 00069 { MODOPT_ARG(byte), "EvcScaleBits", &MOC_ENVISION, OPTEXP_CORE, 00070 "Number of bits of dynamic range to use", 00071 "evc-scale-bits", '\0', "<byte>", "16" }; 00072 00073 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00074 00075 // Used by: EnvVisualCortex 00076 const ModelOptionDef OPT_EvcNumDirections = 00077 { MODOPT_ARG(byte), "EvcNumDirections", &MOC_ENVISION, OPTEXP_CORE, 00078 "Number of motion directions to use", 00079 "evc-num-directions", '\0', "<byte>", "4" }; 00080 00081 // Used by: EnvVisualCortex 00082 const ModelOptionDef OPT_EvcMotionThresh = 00083 { MODOPT_ARG(byte), "EvcMotionThresh", &MOC_ENVISION, OPTEXP_CORE, 00084 "Low threshold cutoff for motion channel", 00085 "evc-motion-thresh", '\0', "<byte>", "12" }; 00086 00087 // Used by: EnvVisualCortex 00088 const ModelOptionDef OPT_EvcFlickerThresh = 00089 { MODOPT_ARG(byte), "EvcFlickerThresh", &MOC_ENVISION, OPTEXP_CORE, 00090 "Low threshold cutoff for flicker channel", 00091 "evc-flicker-thresh", '\0', "<byte>", "20" }; 00092 00093 // Used by: EnvVisualCortex 00094 const ModelOptionDef OPT_EvcRangeThresh = 00095 { MODOPT_ARG(int), "EvcRangeThresh", &MOC_ENVISION, OPTEXP_CORE, 00096 "Low threshold cutoff for normalizing maps. " 00097 "If the range of the map is bellow this threshold " 00098 "then the value would be set to 0.", 00099 "evc-range-thresh", '\0', "<int>", "0" }; 00100 00101 // Used by: EnvVisualCortex 00102 const ModelOptionDef OPT_EvcMultiScaleFlicker = 00103 { MODOPT_FLAG, "EvcMultiScaleFlicker", &MOC_ENVISION, OPTEXP_CORE, 00104 "Whether to use a true multi-scale flicker channel", 00105 "evc-multiscale-flicker", '\0', "", "true" }; 00106 00107 // Used by: EnvVisualCortex 00108 const ModelOptionDef OPT_EvcShowMemStats = 00109 { MODOPT_FLAG, "EvcShowMemStats", &MOC_ENVISION, OPTEXP_CORE, 00110 "Whether to show memory usage", 00111 "evc-show-memstats", '\0', "", "false" }; 00112 00113 #endif 00114 00115 // Used by: EnvVisualCortex 00116 const ModelOptionDef OPT_EvcNumOrientations = 00117 { MODOPT_ARG(byte), "EvcNumOrientations", &MOC_ENVISION, OPTEXP_CORE, 00118 "Number of orientation channels to use", 00119 "evc-num-orientations", '\0', "<byte>", "4" }; 00120 00121 // Used by: EnvVisualCortex 00122 const ModelOptionDef OPT_EvcType = 00123 { MODOPT_ARG(std::string), "EvcType", &MOC_ENVISION, OPTEXP_CORE, 00124 "A string containing one or more of the characters " 00125 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00126 "'I', 'C', 'O', 'F', and 'M', " 00127 #else 00128 "'I', 'C', and 'O', " 00129 #endif 00130 "indicating which of the intensity, color, orientation, flicker, " 00131 "and motion channels should be included, respectively. Additionally, " 00132 "each character can optionally be followed by a ':' and a " 00133 "floating-point number between 0.0 and 1.0 indicating the weight for " 00134 "that channel. By default, each channel receives a weight of 1.0.", 00135 "evc-type", '\0', 00136 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00137 "<I:wC:wO:wF:wM:w>", "ICOFM" 00138 #else 00139 "<I:wC:wO:w>", "ICO" 00140 #endif 00141 }; 00142 00143 // Used by: EnvVisualCortex 00144 const ModelOptionDef OPT_EvcColorSmoothing = 00145 { MODOPT_FLAG, "EvcColorSmoothing", &MOC_ENVISION, OPTEXP_CORE, 00146 "Whether to do two-frame smoothing of the color channel", 00147 "evc-color-smoothing", '\0', "", "false" }; 00148 00149 const ModelOptionDef OPT_EvcOutputFactor = 00150 { MODOPT_ARG(float), "EvcOutputFactor", &MOC_ENVISION, OPTEXP_CORE, 00151 "Factor applied to outputs of EnvVisualCortexFloat to scale them to Amps of " 00152 "synaptic input currents to saliency map", 00153 "evc-outfac", '\0', "<float>", "5.0e-18" }; 00154 00155 // ###################################################################### 00156 // Thunk to convert from env_size_t to size_t 00157 static void* malloc_thunk(env_size_t n) 00158 { 00159 return malloc(n); 00160 } 00161 00162 // ###################################################################### 00163 static Image<byte> convert_gray(const struct env_image* iimage, const struct env_dims dims) 00164 { 00165 if (!env_img_initialized(iimage)) return Image<byte>(dims.w, dims.h, ZEROS); 00166 00167 Image<byte> result(iimage->dims.w, iimage->dims.h, NO_INIT); 00168 00169 const intg32* const src = env_img_pixels(iimage); 00170 const env_size_t sz = env_img_size(iimage); 00171 byte* bimage = result.getArrayPtr(); 00172 00173 for (env_size_t i = 0; i < sz; ++i) 00174 { 00175 // the caller is supposed to have already ensured that the intg32 image has been downsampled to a [0,255] range, 00176 // so let's verify that: 00177 ENV_ASSERT(src[i] >= 0 && src[i] <= 255); 00178 bimage[i] = byte(src[i]); 00179 } 00180 00181 return result; 00182 } 00183 00184 // ###################################################################### 00185 static Image<float> convert_gray_float(const struct env_image* iimage, 00186 const struct env_dims dims, const float factor) 00187 { 00188 if (!env_img_initialized(iimage)) return Image<float>(dims.w, dims.h, ZEROS); 00189 00190 Image<float> result(iimage->dims.w, iimage->dims.h, NO_INIT); 00191 00192 const intg32* src = env_img_pixels(iimage); 00193 const env_size_t sz = env_img_size(iimage); 00194 float* fimage = result.getArrayPtr(); 00195 if (factor == 1.0F) for (env_size_t i = 0; i < sz; ++i) { *fimage = *src; ++fimage; ++src; } 00196 else for (env_size_t i = 0; i < sz; ++i) { *fimage = (*src) * factor; ++fimage; ++src; } 00197 00198 return result; 00199 } 00200 00201 // ###################################################################### 00202 namespace 00203 { 00204 class EnvisionJob : public JobWithSemaphore 00205 { 00206 public: 00207 EnvisionJob(const struct env_job* j) : envJob(*j) {} 00208 00209 virtual ~EnvisionJob() {} 00210 00211 virtual void run() 00212 { 00213 (*envJob.callback)(envJob.userdata); 00214 this->markFinished(); 00215 } 00216 00217 virtual const char* jobType() const { return "EnvisionJob"; } 00218 00219 const struct env_job envJob; 00220 }; 00221 } 00222 00223 // ###################################################################### 00224 static void workthread_job_server(void* job_server_data, 00225 const struct env_job* jobs, 00226 const env_size_t njobs) 00227 { 00228 if (njobs == 0) return; 00229 00230 WorkThreadServer* srv = static_cast<WorkThreadServer*>(job_server_data); 00231 00232 std::vector<rutz::shared_ptr<EnvisionJob> > ejobs; 00233 for (env_size_t i = 0; i < njobs; ++i) 00234 { 00235 ejobs.push_back(rutz::make_shared(new EnvisionJob(jobs + i))); 00236 srv->enqueueJob(ejobs.back()); 00237 } 00238 00239 for (size_t i = 0; i < ejobs.size(); ++i) ejobs[i]->wait(); 00240 } 00241 00242 // ###################################################################### 00243 EnvVisualCortexBase::EnvVisualCortexBase(OptionManager& mgr, const std::string& descrName, 00244 const std::string& tagName) : 00245 ModelComponent(mgr, descrName, tagName), 00246 itsIweight("EvcIntensityWeight", this, 255, ALLOW_ONLINE_CHANGES), 00247 itsCweight("EvcColorWeight", this, 255, ALLOW_ONLINE_CHANGES), 00248 itsOweight("EvcOrientationWeight", this, 255, ALLOW_ONLINE_CHANGES), 00249 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00250 itsFweight("EvcFlickerWeight", this, 255, ALLOW_ONLINE_CHANGES), 00251 itsMweight("EvcMotionWeight", this, 255, ALLOW_ONLINE_CHANGES), 00252 #endif 00253 itsMultithreaded(&OPT_EvcMultithreaded, this, ALLOW_ONLINE_CHANGES), 00254 itsMaxnormType(&OPT_EvcMaxnormType, this), 00255 itsScaleBits(&OPT_EvcScaleBits, this), 00256 itsNumOrientations(&OPT_EvcNumOrientations, this, ALLOW_ONLINE_CHANGES), 00257 itsColorSmoothing(&OPT_EvcColorSmoothing, this, ALLOW_ONLINE_CHANGES), 00258 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00259 itsNumDirections(&OPT_EvcNumDirections, this, ALLOW_ONLINE_CHANGES), 00260 itsMotionThresh(&OPT_EvcMotionThresh, this, ALLOW_ONLINE_CHANGES), 00261 itsFlickerThresh(&OPT_EvcFlickerThresh, this, ALLOW_ONLINE_CHANGES), 00262 itsRangeThresh(&OPT_EvcRangeThresh, this, ALLOW_ONLINE_CHANGES), 00263 itsMultiScaleFlicker(&OPT_EvcMultiScaleFlicker, this, ALLOW_ONLINE_CHANGES), 00264 itsShowMemStats(&OPT_EvcShowMemStats, this, ALLOW_ONLINE_CHANGES), 00265 #endif 00266 itsLevelSpec(&OPT_EnvLevelSpec, this), 00267 itsType(&OPT_EvcType, this) 00268 { 00269 env_params_set_defaults(&this->envp); 00270 } 00271 00272 // ###################################################################### 00273 EnvVisualCortexBase::~EnvVisualCortexBase() 00274 { 00275 itsThreadServer.reset(0); 00276 env_set_job_server(0, 0); 00277 env_allocation_cleanup(); 00278 } 00279 00280 // ###################################################################### 00281 void EnvVisualCortexBase::start1() 00282 { 00283 env_assert_set_handler(&env_stdio_assert_handler); 00284 env_allocation_init(&malloc_thunk, &free); 00285 00286 LINFO(".scale_bits = %u", (unsigned int) itsScaleBits.getVal()); 00287 00288 this->envp.scale_bits = itsScaleBits.getVal(); 00289 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00290 this->envp.num_motion_directions = itsNumDirections.getVal(); 00291 this->envp.motion_thresh = itsMotionThresh.getVal(); 00292 this->envp.flicker_thresh = itsFlickerThresh.getVal(); 00293 this->envp.range_thresh = itsRangeThresh.getVal(); 00294 this->envp.multiscale_flicker = itsMultiScaleFlicker.getVal() ? 1 : 0; 00295 #endif 00296 this->envp.num_orientations = itsNumOrientations.getVal(); 00297 this->envp.cs_lev_min = itsLevelSpec.getVal().levMin(); 00298 this->envp.cs_lev_max = itsLevelSpec.getVal().levMax(); 00299 this->envp.cs_del_min = itsLevelSpec.getVal().delMin(); 00300 this->envp.cs_del_max = itsLevelSpec.getVal().delMax();; 00301 this->envp.output_map_level = itsLevelSpec.getVal().mapLevel(); 00302 00303 env_visual_cortex_init(&this->ivc, &this->envp); 00304 00305 this->npixels = 0; 00306 00307 this->framenum = 0; 00308 00309 itsIweight.setVal(this->envp.chan_i_weight); 00310 itsCweight.setVal(this->envp.chan_c_weight); 00311 itsOweight.setVal(this->envp.chan_o_weight); 00312 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00313 itsFweight.setVal(this->envp.chan_f_weight); 00314 itsMweight.setVal(this->envp.chan_m_weight); 00315 #endif 00316 } 00317 00318 // ###################################################################### 00319 void EnvVisualCortexBase::stop2() 00320 { 00321 if (itsShowMemStats.getVal()) 00322 { 00323 struct env_alloc_stats stats; 00324 env_allocation_get_stats(&stats); 00325 env_stdio_print_alloc_stats(&stats, this->npixels ? this->npixels : 1); 00326 invt_allocation_show_stats(1, "final", this->npixels); 00327 } 00328 00329 env_visual_cortex_destroy(&this->ivc); 00330 } 00331 00332 // ###################################################################### 00333 void EnvVisualCortexBase::paramChanged(ModelParamBase* const param, 00334 const bool valueChanged, 00335 ParamClient::ChangeStatus* status) 00336 { 00337 ModelComponent::paramChanged(param, valueChanged, status); 00338 00339 if (this->started() && valueChanged) 00340 LDEBUG("online change of %s", param->getName().c_str()); 00341 00342 if (param == &itsIweight) { this->envp.chan_i_weight = itsIweight.getVal(); } 00343 else if (param == &itsCweight) { this->envp.chan_c_weight = itsCweight.getVal(); } 00344 else if (param == &itsOweight) { this->envp.chan_o_weight = itsOweight.getVal(); } 00345 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00346 else if (param == &itsFweight) { this->envp.chan_f_weight = itsFweight.getVal(); } 00347 else if (param == &itsMweight) { this->envp.chan_m_weight = itsMweight.getVal(); } 00348 #endif 00349 else if (param == &itsMultithreaded) 00350 { 00351 env_set_job_server(0, 0); 00352 00353 if (itsMultithreaded.getVal()) 00354 { 00355 // once this is turned on, don't ever turn it off again 00356 env_init_pthread_alloc(); 00357 00358 itsThreadServer.reset(new WorkThreadServer("EnvVisualCortex", 12)); 00359 env_set_job_server(&workthread_job_server, static_cast<void*>(itsThreadServer.get())); 00360 } 00361 else itsThreadServer.reset(0); 00362 } 00363 else if (param == &itsMaxnormType) 00364 { 00365 if (itsMaxnormType.getVal().compare("None") == 0) this->envp.maxnorm_type = ENV_VCXNORM_NONE; 00366 else if (itsMaxnormType.getVal().compare("Maxnorm") == 0) this->envp.maxnorm_type = ENV_VCXNORM_MAXNORM; 00367 else LFATAL("Invalid maxnorm type '%s' -- must be either 'Maxnorm' or 'None'", itsMaxnormType.getVal().c_str()); 00368 } 00369 else if (param == &itsType) 00370 { 00371 // first, set all weights to zero: 00372 this->envp.chan_i_weight = 0; 00373 this->envp.chan_c_weight = 0; 00374 this->envp.chan_o_weight = 0; 00375 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00376 this->envp.chan_f_weight = 0; 00377 this->envp.chan_m_weight = 0; 00378 #endif 00379 00380 const std::string type = itsType.getVal(); 00381 const size_t len = itsType.getVal().length(); 00382 00383 for (size_t i = 0; i < len; /* incr in loop */) 00384 { 00385 const char chantype = type[i]; 00386 byte* bweightptr = 0; 00387 00388 switch (chantype) 00389 { 00390 case 'I': bweightptr = &this->envp.chan_i_weight; break; 00391 case 'C': bweightptr = &this->envp.chan_c_weight; break; 00392 case 'O': bweightptr = &this->envp.chan_o_weight; break; 00393 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00394 case 'F': bweightptr = &this->envp.chan_f_weight; break; 00395 case 'M': bweightptr = &this->envp.chan_m_weight; break; 00396 #endif 00397 default: LFATAL("Invalid channel specifier '%c'", chantype); 00398 } 00399 00400 ++i; 00401 00402 if (type[i] != ':') *bweightptr = 255; 00403 else { 00404 ++i; 00405 const size_t end = type.find_first_not_of(".0123456789", i); 00406 const std::string weightstr = type.substr(i, end - i); 00407 double weight = 1.0; 00408 00409 std::stringstream s; s << weightstr; s >> weight; 00410 if (s.fail()) LFATAL("couldn't parse '%c' channel weight from '%s'", chantype, weightstr.c_str()); 00411 i = end; 00412 00413 if (weight < 0.0 || weight > 1.0) 00414 LFATAL("invalid weight for channel '%c': got %s but expected a value between 0.0 and 1.0", 00415 chantype, weightstr.c_str()); 00416 00417 *bweightptr = byte(weight * 255.0 + 0.5); 00418 } 00419 } 00420 } 00421 else if (param == &itsNumOrientations) 00422 { 00423 if (itsNumOrientations.getVal() > 99) *status = ParamClient::CHANGE_REJECTED; 00424 else this->envp.num_orientations = itsNumOrientations.getVal(); 00425 } 00426 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00427 else if (param == &itsNumDirections) 00428 { 00429 if (itsNumDirections.getVal() > 99) *status = ParamClient::CHANGE_REJECTED; 00430 else this->envp.num_motion_directions = itsNumDirections.getVal(); 00431 } 00432 else if (param == &itsMotionThresh) 00433 { 00434 this->envp.motion_thresh = itsMotionThresh.getVal(); 00435 } 00436 else if (param == &itsFlickerThresh) 00437 { 00438 this->envp.flicker_thresh = itsFlickerThresh.getVal(); 00439 } 00440 else if (param == &itsMultiScaleFlicker) 00441 { 00442 this->envp.multiscale_flicker = itsMultiScaleFlicker.getVal() ? 1 : 0; 00443 } 00444 #endif 00445 } 00446 00447 // ###################################################################### 00448 // ###################################################################### 00449 // ###################################################################### 00450 EnvVisualCortex::EnvVisualCortex(OptionManager& mgr, const std::string& descrName, 00451 const std::string& tagName) : 00452 EnvVisualCortexBase(mgr, descrName, tagName) 00453 { 00454 this->chanmi = INTG32_MAX; this->chanma = INTG32_MIN; 00455 this->vcxmi = INTG32_MAX; this->vcxma = INTG32_MIN; 00456 } 00457 00458 // ###################################################################### 00459 EnvVisualCortex::~EnvVisualCortex() 00460 { } 00461 00462 // ###################################################################### 00463 void EnvVisualCortex::input(const Image<PixRGB<byte> >& rgbin) 00464 { 00465 struct env_image ivcout = env_img_initializer; 00466 struct env_image intens = env_img_initializer; 00467 struct env_image color = env_img_initializer; 00468 struct env_image ori = env_img_initializer; 00469 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00470 struct env_image flicker = env_img_initializer; 00471 struct env_image motion = env_img_initializer; 00472 #endif 00473 00474 ++this->framenum; 00475 00476 struct env_dims indims = { rgbin.getWidth(), rgbin.getHeight() }; 00477 00478 npixels = indims.w * indims.h; 00479 00480 const struct env_rgb_pixel* src = (const struct env_rgb_pixel*) rgbin.getArrayPtr(); 00481 00482 const struct env_rgb_pixel* src2 = (const struct env_rgb_pixel*) 00483 (itsColorSmoothing.getVal() == true && itsPrevRgb.initialized() ? itsPrevRgb.getArrayPtr() : 0); 00484 00485 env_mt_visual_cortex_input(itsMultithreaded.getVal() ? 1 : 0, 00486 &this->ivc, &this->envp, 00487 "visualcortex", 00488 src, src2, 00489 indims, 00490 0, //&print_chan_status, 00491 0, //&userdata, 00492 &ivcout, 00493 &intens, &color, &ori 00494 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00495 , &flicker, &motion 00496 #endif 00497 ); 00498 00499 env_merge_range(&ivcout, &vcxmi, &vcxma); 00500 env_rescale_range_inplace(&ivcout, vcxmi, vcxma); 00501 00502 env_visual_cortex_merge_ranges(&intens, &color, &ori, 00503 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00504 &flicker, &motion, 00505 #endif 00506 &chanmi, &chanma); 00507 00508 env_rescale_range_inplace(&intens, chanmi, chanma); 00509 env_rescale_range_inplace(&color, chanmi, chanma); 00510 env_rescale_range_inplace(&ori, chanmi, chanma); 00511 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00512 env_rescale_range_inplace(&flicker, chanmi, chanma); 00513 env_rescale_range_inplace(&motion, chanmi, chanma); 00514 #endif 00515 00516 this->itsVCXmap = convert_gray(&ivcout, ivcout.dims); 00517 00518 this->itsImap = convert_gray(&intens, ivcout.dims); 00519 this->itsCmap = convert_gray(&color, ivcout.dims); 00520 this->itsOmap = convert_gray(&ori, ivcout.dims); 00521 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00522 this->itsFmap = convert_gray(&flicker, ivcout.dims); 00523 this->itsMmap = convert_gray(&motion, ivcout.dims); 00524 #endif 00525 00526 env_img_make_empty(&ivcout); 00527 env_img_make_empty(&intens); 00528 env_img_make_empty(&color); 00529 env_img_make_empty(&ori); 00530 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00531 env_img_make_empty(&flicker); 00532 env_img_make_empty(&motion); 00533 #endif 00534 00535 itsPrevRgb = rgbin; 00536 } 00537 00538 // ###################################################################### 00539 // ###################################################################### 00540 // ###################################################################### 00541 EnvVisualCortexFloat::EnvVisualCortexFloat(OptionManager& mgr, const std::string& descrName, 00542 const std::string& tagName) : 00543 EnvVisualCortexBase(mgr, descrName, tagName), 00544 itsOutputFactor(&OPT_EvcOutputFactor, this) 00545 { } 00546 00547 // ###################################################################### 00548 EnvVisualCortexFloat::~EnvVisualCortexFloat() 00549 { } 00550 00551 // ###################################################################### 00552 // ###################################################################### 00553 void EnvVisualCortexFloat::input(const Image<PixRGB<byte> >& rgbin) 00554 { 00555 struct env_image ivcout = env_img_initializer; 00556 struct env_image intens = env_img_initializer; 00557 struct env_image color = env_img_initializer; 00558 struct env_image ori = env_img_initializer; 00559 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00560 struct env_image flicker = env_img_initializer; 00561 struct env_image motion = env_img_initializer; 00562 #endif 00563 00564 ++this->framenum; 00565 00566 struct env_dims indims = { rgbin.getWidth(), rgbin.getHeight() }; 00567 00568 npixels = indims.w * indims.h; 00569 00570 const struct env_rgb_pixel* src = (const struct env_rgb_pixel*) rgbin.getArrayPtr(); 00571 00572 const struct env_rgb_pixel* src2 = (const struct env_rgb_pixel*) 00573 (itsColorSmoothing.getVal() == true && itsPrevRgb.initialized() ? itsPrevRgb.getArrayPtr() : 0); 00574 00575 env_mt_visual_cortex_input(itsMultithreaded.getVal() ? 1 : 0, 00576 &this->ivc, &this->envp, 00577 "visualcortex", 00578 src, src2, 00579 indims, 00580 0, //&print_chan_status, 00581 0, //&userdata, 00582 &ivcout, 00583 &intens, &color, &ori 00584 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00585 , &flicker, &motion 00586 #endif 00587 ); 00588 00589 this->itsVCXmap = convert_gray_float(&ivcout, ivcout.dims, itsOutputFactor.getVal()); 00590 00591 this->itsImap = convert_gray_float(&intens, ivcout.dims, 1.0F); 00592 this->itsCmap = convert_gray_float(&color, ivcout.dims, 1.0F); 00593 this->itsOmap = convert_gray_float(&ori, ivcout.dims, 1.0F); 00594 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00595 this->itsFmap = convert_gray_float(&flicker, ivcout.dims, 1.0F); 00596 this->itsMmap = convert_gray_float(&motion, ivcout.dims, 1.0F); 00597 #endif 00598 00599 env_img_make_empty(&ivcout); 00600 env_img_make_empty(&intens); 00601 env_img_make_empty(&color); 00602 env_img_make_empty(&ori); 00603 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00604 env_img_make_empty(&flicker); 00605 env_img_make_empty(&motion); 00606 #endif 00607 00608 itsPrevRgb = rgbin; 00609 } 00610 00611 00612 00613 // ###################################################################### 00614 /* So things look consistent in everyone's emacs... */ 00615 /* Local Variables: */ 00616 /* mode: c++ */ 00617 /* indent-tabs-mode: nil */ 00618 /* End: */ 00619 00620 #endif // NEURO_ENVVISUALCORTEX_C_DEFINED