00001 /*!@file Channels/InputFrame.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/Channels/InputFrame.C $ 00035 // $Id: InputFrame.C 14600 2011-03-14 21:52:47Z dberg $ 00036 // 00037 00038 #ifndef CHANNELS_INPUTFRAME_C_DEFINED 00039 #define CHANNELS_INPUTFRAME_C_DEFINED 00040 00041 #include "Channels/InputFrame.H" 00042 00043 #include "Image/ColorOps.H" 00044 #include "Util/Assert.H" 00045 #include "Util/JobWithSemaphore.H" 00046 #include "Util/MainJobServer.H" 00047 00048 #include <pthread.h> 00049 #include <vector> 00050 00051 // ###################################################################### 00052 struct RgbByteToLuminanceJob : public JobWithSemaphore 00053 { 00054 RgbByteToLuminanceJob(const PixRGB<byte>* in_, 00055 const PixRGB<byte>* end_, 00056 float* lumout_) 00057 : 00058 in(in_), end(end_), 00059 lumout(lumout_) 00060 {} 00061 00062 virtual ~RgbByteToLuminanceJob() 00063 {} 00064 00065 virtual void run() 00066 { 00067 const PixRGB<byte>* in_ = in; 00068 const PixRGB<byte>* const end_ = end; 00069 float* lumout_ = lumout; 00070 00071 const float one_third = 1.0f / 3.0f; 00072 00073 while (in_ != end_) 00074 { 00075 *lumout_++ = one_third * (in_->p[0] + in_->p[1] + in_->p[2]); 00076 ++in_; 00077 } 00078 00079 this->markFinished(); 00080 } 00081 00082 virtual const char* jobType() const { return "RgbByteToLuminanceJob"; } 00083 00084 const PixRGB<byte>* const in; 00085 const PixRGB<byte>* const end; 00086 float* const lumout; 00087 }; 00088 00089 // ###################################################################### 00090 struct RgbByteToFloatJob : public JobWithSemaphore 00091 { 00092 RgbByteToFloatJob(const PixRGB<byte>* in_, 00093 const PixRGB<byte>* end_, 00094 PixRGB<float>* rgbout_) 00095 : 00096 in(in_), end(end_), 00097 rgbout(rgbout_) 00098 {} 00099 00100 virtual ~RgbByteToFloatJob() 00101 {} 00102 00103 virtual void run() 00104 { 00105 const PixRGB<byte>* in_ = in; 00106 const PixRGB<byte>* const end_ = end; 00107 PixRGB<float>* rgbout_ = rgbout; 00108 00109 while (in_ != end_) 00110 *rgbout_++ = PixRGB<float>(*in_++); 00111 00112 this->markFinished(); 00113 } 00114 00115 virtual const char* jobType() const { return "RgbByteToFloatJob"; } 00116 00117 const PixRGB<byte>* const in; 00118 const PixRGB<byte>* const end; 00119 PixRGB<float>* const rgbout; 00120 }; 00121 00122 // ###################################################################### 00123 InputFrame::InputFrame() 00124 {} 00125 00126 // ###################################################################### 00127 InputFrame InputFrame::fromRgb(const Image<PixRGB<byte> >* in, 00128 SimTime t, 00129 const Image<byte>* clip, 00130 const rutz::shared_ptr<PyramidCache<float> >& cache, 00131 bool disableCache) 00132 { 00133 ASSERT(in != 0); ASSERT(in->initialized()); 00134 00135 InputFrame result; 00136 00137 result.itsTime = t; 00138 result.itsDims = in->getDims(); 00139 if (clip != 0) 00140 result.itsClipMask = *clip; 00141 else 00142 result.itsClipMask = Image<byte>(); 00143 result.itsColorByte = *in; 00144 00145 result.itsColorFloat = Image<PixRGB<float> >(); // will be generated on-demand in colorFloat() 00146 result.itsGrayFloat = Image<float>(in->getDims(), NO_INIT); 00147 result.itsPyrCache = 00148 disableCache 00149 ? rutz::shared_ptr<PyramidCache<float> >(/* null */) 00150 : cache.get() != 0 00151 ? cache 00152 : rutz::shared_ptr<PyramidCache<float> >(new PyramidCache<float>); 00153 00154 result.itsPyrCacheRgb = rutz::shared_ptr<PyramidCache<PixRGB<float> > >(/* null */); 00155 00156 const int sz = in->getSize(); 00157 00158 JobServer& srv = getMainJobServer(); 00159 00160 const unsigned int ntiles = srv.getParallelismHint(); 00161 00162 LDEBUG("ntiles = %u", ntiles); 00163 00164 std::vector<rutz::shared_ptr<RgbByteToLuminanceJob > > jobs; 00165 00166 for (unsigned int i = 0; i < ntiles; ++i) 00167 { 00168 const int start = (i*sz)/ntiles; 00169 const int end = ((i+1)*sz)/ntiles; 00170 00171 jobs.push_back 00172 (rutz::make_shared(new RgbByteToLuminanceJob 00173 (in->getArrayPtr() + start, 00174 in->getArrayPtr() + end, 00175 result.itsGrayFloat.getArrayPtr() + start))); 00176 00177 srv.enqueueJob(jobs.back()); 00178 } 00179 00180 for (size_t i = 0; i < jobs.size(); ++i) 00181 jobs[i]->wait(); 00182 00183 return result; 00184 } 00185 00186 // ###################################################################### 00187 InputFrame InputFrame::fromRgbFloat(const Image<PixRGB<float> >* col, 00188 SimTime t, 00189 const Image<byte>* clip, 00190 const rutz::shared_ptr<PyramidCache<float> >& cache, 00191 bool disableCache) 00192 { 00193 ASSERT(col != 0); ASSERT(col->initialized()); 00194 00195 InputFrame result; 00196 00197 result.itsTime = t; 00198 result.itsDims = col->getDims(); 00199 if (clip != 0) 00200 result.itsClipMask = *clip; 00201 else 00202 result.itsClipMask = Image<byte>(); 00203 result.itsColorByte = Image<PixRGB<byte> >(); 00204 result.itsColorFloat = *col; 00205 result.itsGrayFloat = luminance(result.itsColorFloat); 00206 result.itsPyrCache = 00207 disableCache 00208 ? rutz::shared_ptr<PyramidCache<float> >(/* null */) 00209 : cache.get() != 0 00210 ? cache 00211 : rutz::shared_ptr<PyramidCache<float> >(new PyramidCache<float>); 00212 00213 result.itsPyrCacheRgb = rutz::shared_ptr<PyramidCache<PixRGB<float> > >(/* null */); 00214 00215 return result; 00216 } 00217 00218 // ###################################################################### 00219 InputFrame InputFrame::fromGrayFloat(const Image<float>* bw, 00220 SimTime t, 00221 const Image<byte>* clip, 00222 const rutz::shared_ptr<PyramidCache<float> >& cache, 00223 bool disableCache) 00224 { 00225 ASSERT(bw != 0); ASSERT(bw->initialized()); 00226 00227 InputFrame result; 00228 00229 result.itsTime = t; 00230 result.itsDims = bw->getDims(); 00231 if (clip != 0) 00232 result.itsClipMask = *clip; 00233 else 00234 result.itsClipMask = Image<byte>(); 00235 result.itsColorByte = Image<PixRGB<byte> >(); 00236 result.itsColorFloat = Image<PixRGB<float> >(); 00237 result.itsGrayFloat = *bw; 00238 result.itsPyrCache = 00239 disableCache 00240 ? rutz::shared_ptr<PyramidCache<float> >(/* null */) 00241 : cache.get() != 0 00242 ? cache 00243 : rutz::shared_ptr<PyramidCache<float> >(new PyramidCache<float>); 00244 00245 result.itsPyrCacheRgb = rutz::shared_ptr<PyramidCache<PixRGB<float> > >(/* null */); 00246 00247 return result; 00248 } 00249 // ###################################################################### 00250 InputFrame InputFrame::fromRgbAndGrayFloat(const Image<PixRGB<byte> >* rgbb, 00251 const Image<PixRGB<float> >* rgbf, 00252 const Image<float>* bw, 00253 SimTime t, 00254 const Image<byte>* clip, 00255 const rutz::shared_ptr<PyramidCache<float> >& cache, 00256 bool disableCache) 00257 { 00258 ASSERT(rgbb != 0); ASSERT(rgbb->initialized()); 00259 ASSERT(rgbf != 0); ASSERT(rgbf->initialized()); 00260 ASSERT(bw != 0); ASSERT(bw->initialized()); 00261 00262 if (rgbb->getDims() != rgbf->getDims()) 00263 LFATAL("Color-byte and color-float inputs must have the same dimensions " 00264 "(got %dx%d color-byte and %dx%d color-float)", 00265 rgbb->getWidth(), rgbb->getHeight(), 00266 rgbf->getWidth(), rgbf->getHeight()); 00267 00268 if (rgbf->getDims() != bw->getDims()) 00269 LFATAL("Color and grayscale inputs must have the same dimensions " 00270 "(got %dx%d color and %dx%d grayscale)", 00271 rgbf->getWidth(), rgbf->getHeight(), 00272 bw->getWidth(), bw->getHeight()); 00273 00274 InputFrame result; 00275 00276 result.itsTime = t; 00277 result.itsDims = rgbb->getDims(); 00278 if (clip != 0) 00279 result.itsClipMask = *clip; 00280 else 00281 result.itsClipMask = Image<byte>(); 00282 result.itsColorByte = *rgbb; 00283 result.itsColorFloat = *rgbf; 00284 result.itsGrayFloat = *bw; 00285 result.itsPyrCache = 00286 disableCache 00287 ? rutz::shared_ptr<PyramidCache<float> >(/* null */) 00288 : cache.get() != 0 00289 ? cache 00290 : rutz::shared_ptr<PyramidCache<float> >(new PyramidCache<float>); 00291 00292 result.itsPyrCacheRgb = rutz::shared_ptr<PyramidCache<PixRGB<float> > >(/* null */); 00293 00294 return result; 00295 } 00296 // ###################################################################### 00297 InputFrame InputFrame::fromRgbDepth(const Image<PixRGB<byte> >* in, 00298 const Image<uint16>* depth, 00299 SimTime t, 00300 const Image<byte>* clip, 00301 const rutz::shared_ptr<PyramidCache<float> >& cache, 00302 bool disableCache) 00303 { 00304 ASSERT(in != 0); ASSERT(in->initialized()); 00305 ASSERT(depth != 0); ASSERT(depth->initialized()); 00306 00307 InputFrame result; 00308 00309 result.itsTime = t; 00310 result.itsDims = in->getDims(); 00311 if (clip != 0) 00312 result.itsClipMask = *clip; 00313 else 00314 result.itsClipMask = Image<byte>(); 00315 result.itsColorByte = *in; 00316 00317 result.itsDepthImage = *depth; 00318 00319 result.itsColorFloat = Image<PixRGB<float> >(); // will be generated on-demand in colorFloat() 00320 result.itsGrayFloat = Image<float>(in->getDims(), NO_INIT); 00321 result.itsPyrCache = 00322 disableCache 00323 ? rutz::shared_ptr<PyramidCache<float> >(/* null */) 00324 : cache.get() != 0 00325 ? cache 00326 : rutz::shared_ptr<PyramidCache<float> >(new PyramidCache<float>); 00327 00328 result.itsPyrCacheRgb = rutz::shared_ptr<PyramidCache<PixRGB<float> > >(/* null */); 00329 00330 const int sz = in->getSize(); 00331 00332 JobServer& srv = getMainJobServer(); 00333 00334 const unsigned int ntiles = srv.getParallelismHint(); 00335 00336 LDEBUG("ntiles = %u", ntiles); 00337 00338 std::vector<rutz::shared_ptr<RgbByteToLuminanceJob > > jobs; 00339 00340 for (unsigned int i = 0; i < ntiles; ++i) 00341 { 00342 const int start = (i*sz)/ntiles; 00343 const int end = ((i+1)*sz)/ntiles; 00344 00345 jobs.push_back 00346 (rutz::make_shared(new RgbByteToLuminanceJob 00347 (in->getArrayPtr() + start, 00348 in->getArrayPtr() + end, 00349 result.itsGrayFloat.getArrayPtr() + start))); 00350 00351 srv.enqueueJob(jobs.back()); 00352 } 00353 00354 for (size_t i = 0; i < jobs.size(); ++i) 00355 jobs[i]->wait(); 00356 00357 return result; 00358 } 00359 00360 // ###################################################################### 00361 const Image<PixRGB<float> >& InputFrame::colorFloat() const 00362 { 00363 if (!itsColorFloat.initialized() && itsColorByte.initialized()) 00364 { 00365 itsColorFloat = Image<float>(itsColorByte.getDims(), NO_INIT); 00366 00367 const int sz = itsColorByte.getSize(); 00368 00369 JobServer& srv = getMainJobServer(); 00370 00371 const unsigned int ntiles = srv.getParallelismHint(); 00372 00373 LDEBUG("ntiles = %u", ntiles); 00374 00375 std::vector<rutz::shared_ptr<RgbByteToFloatJob > > jobs; 00376 00377 for (unsigned int i = 0; i < ntiles; ++i) 00378 { 00379 const int start = (i*sz)/ntiles; 00380 const int end = ((i+1)*sz)/ntiles; 00381 00382 jobs.push_back 00383 (rutz::make_shared(new RgbByteToFloatJob 00384 (itsColorByte.getArrayPtr() + start, 00385 itsColorByte.getArrayPtr() + end, 00386 const_cast<PixRGB<float>*> 00387 (itsColorFloat.getArrayPtr() + start)))); 00388 00389 srv.enqueueJob(jobs.back()); 00390 } 00391 00392 for (size_t i = 0; i < jobs.size(); ++i) 00393 jobs[i]->wait(); 00394 } 00395 00396 return itsColorFloat; 00397 } 00398 00399 const rutz::shared_ptr<PyramidCache<float> > InputFrame::emptyCache; 00400 00401 // ###################################################################### 00402 /* So things look consistent in everyone's emacs... */ 00403 /* Local Variables: */ 00404 /* indent-tabs-mode: nil */ 00405 /* End: */ 00406 00407 #endif // CHANNELS_INPUTFRAME_C_DEFINED