00001 /*!@file Channels/SingleChannel.H Channel for a single stream of processing. */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // 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@klab.caltech.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Channels/SingleChannel.H $ 00035 // $Id: SingleChannel.H 14632 2011-03-23 20:08:44Z dberg $ 00036 // 00037 00038 #ifndef SINGLECHANNEL_H_DEFINED 00039 #define SINGLECHANNEL_H_DEFINED 00040 00041 #include "Channels/ChannelBase.H" 00042 #include "Channels/ChannelFacet.H" 00043 #include "Channels/InputHandler.H" 00044 #include "Channels/SubmapAlgorithm.H" 00045 #include "Component/ModelParam.H" 00046 #include "Image/ImageSet.H" 00047 #include "Image/LevelSpec.H" 00048 #include "Image/PyrBuilder.H" 00049 #include "Image/fancynorm.H" // for MaxNormType 00050 #include "Util/SimTime.H" 00051 #include "rutz/shared_ptr.h" 00052 #include <deque> 00053 00054 // ###################################################################### 00055 //! SingleChannel represents a single stream of processing. 00056 /*! The processing is implemented by an internal PyrBuilder object of some 00057 kind. */ 00058 class SingleChannel : public ChannelBase, public ChannelFacetMap 00059 { 00060 public: 00061 //! Constructor. See ChannelBase.H 00062 /*! @param mgr our ModelManager (see ModelManager.H) 00063 @param descrName descriptive name for human usage 00064 @param tagName name for ParamMap usage 00065 @param vs The VisualFeature implemented by the channel 00066 @param pyr The type of pyramid that should be used. */ 00067 SingleChannel(OptionManager& mgr, const std::string& descrName, 00068 const std::string& tagName, const VisualFeature vs, 00069 rutz::shared_ptr<PyrBuilder<float> > pyr); 00070 00071 //! destructor 00072 virtual ~SingleChannel(); 00073 00074 //! Reset SingleChannel 00075 /*! See the base function in ModelComponent.H for info. */ 00076 virtual void reset1(); 00077 00078 /// Calls visitSingleChannel() on the ChannelVisitor. 00079 virtual void accept(ChannelVisitor& v); 00080 00081 //! Overload so that we can reconfigure when our params get changed 00082 virtual void paramChanged(ModelParamBase* const param, 00083 const bool valueChanged, 00084 ParamClient::ChangeStatus* status); 00085 00086 //! Send an already computed pyramid as input to the channel. 00087 void inputPyramid(const ImageSet<float>& pyramid, const SimTime& t, 00088 const Image<byte>& clipMask = Image<byte>()); 00089 00090 //! Computes the channel's pyramid but doesn't store it 00091 virtual ImageSet<float> computePyramid(const Image<float>& bwimg, 00092 const rutz::shared_ptr<PyramidCache<float> >& cache); 00093 00094 virtual void readFrom(const ParamMap& pmap); 00095 00096 virtual void writeTo(ParamMap& pmap) const; 00097 00098 //! Set the template that will be applied to the submap 00099 void setTempl(const uint cntr, const uint surr, Image<float> &templ); 00100 00101 //! Set the mask that will be applied to the submap 00102 void setBiasMask(Image<float> &biasMask); 00103 00104 //! Set the mask that will be applied to the submap 00105 Image<float> getBiasMask() const; 00106 00107 //! Get the template that is beeing applied to the submap 00108 Image<float> getTempl(const uint cntr, const uint surr) const; 00109 00110 virtual bool outputAvailable() const; 00111 00112 //! do we have any input pyramids in our queue? 00113 bool hasPyramid() const; 00114 00115 //! have we already computed and cached the current output? 00116 bool hasOutputCache() const; 00117 00118 virtual Dims getMapDims() const; 00119 00120 //! Get the image from the given level of the internal pyramid 00121 virtual const Image<float>& getImage(const uint lev) const; 00122 00123 //! Get the center/surround image for the given levels 00124 virtual Image<float> centerSurround(const uint cntr, const uint surr) const; 00125 00126 //! Get the center/surround, split into positive and negative parts 00127 virtual void centerSurround(const uint cntr, const uint surr, 00128 Image<float>& pos, Image<float>& neg) const; 00129 00130 virtual uint numSubmaps() const; 00131 00132 //! This is just a caching wrapper around computeSubmap() 00133 virtual Image<float> getSubmap(const uint index) const; 00134 00135 virtual std::string getSubmapName(const uint index) const; 00136 00137 virtual std::string getSubmapNameShort(const uint index) const; 00138 00139 virtual void getFeatures(const Point2D<int>& locn, 00140 std::vector<float>& mean) const; 00141 00142 virtual void getFeaturesBatch(std::vector<Point2D<int>*> *locn, 00143 std::vector<std::vector<float> > *mean, 00144 int *count) const; 00145 00146 //! save basic stats for single channel 00147 void saveStats(const Image<float> img, const short idx); 00148 00149 //! This is just a caching wrapper around combineSubMaps() 00150 virtual Image<float> getOutput(); 00151 00152 //! Combine all feature maps into a single output map 00153 virtual Image<float> combineSubMaps(); 00154 00155 //! Save our various maps using an FrameOstream 00156 /*! Depending on our ModelParam settings, we can save raw pyramid 00157 levels (with name prefix "SR<tagname>-<level>-"), center-surround 00158 feature maps ("SF<tagname>-<ctr>-<surr>-"), and output map 00159 ("SO<tagname>-") */ 00160 virtual void saveResults(const nub::ref<FrameOstream>& ofs); 00161 00162 //! Get the number of pyramids in our queue 00163 size_t numPyramids() const; 00164 00165 //! Access to the underlying pyramid is provided for completeness. 00166 /*! However, it probably shouldn't need to be used except for testing, 00167 debugging, etc. Instead, the Channel interface should be used or 00168 extended to fill the specific need. 00169 @param index The index in the queue (0 = newest, qlen-1 = oldest). */ 00170 const ImageSet<float>& pyramid(const uint index) const; 00171 00172 //! Access to the underlying pyramid times is provided for completeness. 00173 /*! However, it probably shouldn't need to be used except for testing, 00174 debugging, etc. Instead, the Channel interface should be used or 00175 extended to fill the specific need. 00176 @param index The index in the queue (0 = newest, qlen-1 = oldest). */ 00177 SimTime pyramidTime(const uint index) const; 00178 00179 //! Access to the underlying clipPyramid 00180 const ImageSet<float>& clipPyramid() const; 00181 00182 //! get our the LevelSpec 00183 virtual LevelSpec getLevelSpec() const; 00184 00185 //! get our NormType: 00186 int getNormType() const; 00187 00188 //! SingleChannel implements this to clear its cached output. 00189 virtual void killCaches(); 00190 00191 //! a time-stamped pyramid 00192 struct TPyr 00193 { 00194 TPyr(const ImageSet<float>& pyr_, const SimTime t_) 00195 : pyr(pyr_), t(t_) {} 00196 ImageSet<float> pyr; //!< the pyramid 00197 SimTime t; //!< the timestamp 00198 }; 00199 00200 //! Store m as the output map 00201 void storeOutputCache(const Image<float>& m); 00202 00203 //! Stores p as the channel's pyramid at time t 00204 virtual void storePyramid(const ImageSet<float>& p, const SimTime& t); 00205 00206 //! Store p as the channel's clip pyramid 00207 void storeClipPyramid(const ImageSet<float>& p); 00208 00209 //! make the clipping pyramid from the clip mask 00210 virtual void setClipPyramid(const Image<byte>& clipMask); 00211 00212 //! Store p as the channel's submap cache 00213 void storeSubmapCache(const ImageSet<float>& p); 00214 00215 //! Install an input handler 00216 void setInputHandler(rutz::shared_ptr<InputHandler> h); 00217 00218 //! Get a cloned copy of our input handler 00219 rutz::shared_ptr<InputHandler> cloneInputHandler() const; 00220 00221 //! get raw CS map; part of getSubmap() 00222 virtual Image<float> getRawCSmap(const uint idx) const; 00223 00224 //! rescale and post-process raw CS map; part of default getSubMap() 00225 Image<float> postProcessMap(const Image<float>& smap, 00226 const uint idx) const; 00227 00228 //! Install a new submap algorithm 00229 void setSubmapAlgorithm(nub::ref<SubmapAlgorithm> algo); 00230 00231 void setComputeFullPyramid(bool v) 00232 { itsComputeFullPyramid.setVal(v); } 00233 00234 virtual int getMinPyrLevel() const 00235 { 00236 // If we want to save our raw pyramid maps, or otherwise need a 00237 // full pyramid, then let's compute the pyramid in full starting 00238 // from level 0; otherwise, we can skip the levels below our 00239 // LevelSpec's levMin(): 00240 return (itsSaveRawMaps.getVal() || itsComputeFullPyramid.getVal() || 00241 itsComputeFullPyramidForGist.getVal() ) ? 0 : itsLevelSpec.getVal().levMin(); 00242 } 00243 00244 virtual int getMaxPyrLevel() const { return itsLevelSpec.getVal().maxDepth(); } 00245 00246 protected: 00247 //! SingleChannel requires only luminance input 00248 virtual void doInput(const InputFrame& inframe); 00249 00250 //! Change to use a different pyramid object. 00251 void setPyramid(rutz::shared_ptr<PyrBuilder<float> > pyr); 00252 00253 //! Mutable access to underlying pyramid 00254 ImageSet<float>& pyrMut(const uint index); 00255 00256 NModelParam<bool> itsTakeAbs; 00257 NModelParam<bool> itsNormalizeOutput; 00258 NModelParam<bool> itsScaleNoiseToMax; 00259 NModelParam<float> itsLowThresh; 00260 NModelParam<bool> itsRectifyPyramid; 00261 NModelParam<bool> itsComputeFullPyramid; 00262 00263 OModelParam<bool> itsUseRandom; 00264 OModelParam<bool> itsUseSplitCS; 00265 OModelParam<LevelSpec> itsLevelSpec; 00266 OModelParam<MaxNormType> itsNormType; 00267 OModelParam<int> itsQlen; 00268 OModelParam<bool> itsUseOlderVersion; 00269 00270 //! Time decay for the contribution of differences in the pyramid queue. 00271 /*! This decay will yield a factor fac = exp( (t2 - t) * decay) 00272 applied to the difference image between t (current time, in 00273 seconds) and t2 (time of previous image, in seconds): */ 00274 OModelParam<double> itsTimeDecay; 00275 00276 //! Save our raw pyramid levels? 00277 OModelParam<bool> itsSaveRawMaps; 00278 00279 //! save our raw pyramid levels for the gist computation? 00280 OModelParam<bool> itsComputeFullPyramidForGist; 00281 00282 //! Save our center-surround feature maps? 00283 OModelParam<bool> itsSaveFeatureMaps; 00284 00285 //! Save our output map? 00286 OModelParam<bool> itsSaveOutputMap; 00287 00288 //! Type name for our SubmapAlgorithm 00289 OModelParam<std::string> itsSubmapAlgoType; 00290 00291 //! Save basic single channel stats after combineSubMaps 00292 OModelParam<bool> itsGetSingleChannelStats; 00293 00294 //! If saving stats, should we put each feature in its own file? 00295 OModelParam<bool> itsSaveStatsPerChannel; 00296 00297 //! Should we save frequency information per channel? 00298 OModelParam<bool> itsSaveStatsPerChannelFreq; 00299 00300 //! File name for single channel stats after combineSubMaps 00301 OModelParam<std::string> itsGetSingleChannelStatsFile; 00302 00303 //! Tag name for single channel stats after combineSubMaps 00304 OModelParam<std::string> itsGetSingleChannelStatsTag; 00305 00306 //! Set a fixed range of values for the raw output 00307 /*! By default, the range is set to [MAXNORMMIN .. MAXNORMMAX] at 00308 construction. If non-zero values are provided here, in getOutput() 00309 we will cumulate our various submaps, apply the provided range, 00310 apply spatial competition for salience, apply our total weight, 00311 and return the result. If a range [0.0 .. 0.0] is provided here, 00312 only spatial competition and weights will be applied, but the 00313 first step of applying the range will be skipped. This must be 00314 called before start(). */ 00315 OModelParam<float> itsOutputRangeMin; 00316 OModelParam<float> itsOutputRangeMax; 00317 00318 // get us started (see ModelComponent.H) 00319 /*! If you overload this, make sure you call SingleChannel::start1() 00320 at the beginning of your overload */ 00321 virtual void start1(); 00322 00323 // get us stopped (see ModelComponent.H) 00324 /*! If you overload this, make sure you call SingleChannel::start1() 00325 at the beginning of your overload */ 00326 virtual void stop2(); 00327 00328 // shortcut to the csToIndex function of itsLevelSpec: 00329 virtual uint csToIndex(uint centerlev, uint surroundlev) const; 00330 00331 // shortcut to the indexToCS function of itsLevelSpec: 00332 virtual void indexToCS(const uint index, uint& centerlev, uint& surroundlev) const; 00333 00334 // shortcut to maxIndex function in itsLevelSpec 00335 virtual uint maxIndex() const; 00336 00337 private: 00338 SingleChannel(const SingleChannel&); // not allowed 00339 SingleChannel& operator=(const SingleChannel&); // not allowed 00340 00341 std::deque<TPyr> itsPq; // temporal queue of pyramids 00342 Image<float> itsBiasMask; // to bias the channel based on a mask 00343 00344 uint itsFrameIdx; // for logging purposes 00345 Image<float> itsOutputCache; 00346 Image<float>* itsSubmapCache; 00347 ImageSet<float> itsTempl; // the templates at each submap level 00348 rutz::shared_ptr<PyrBuilder<float> > itsPyrBuilder; 00349 ImageSet<float> itsClipPyr; 00350 rutz::shared_ptr<InputHandler> itsInputHandler; 00351 nub::ref<SubmapAlgorithm> itsSubmapAlgo; 00352 00353 friend class OrientationChannel; // this one too 00354 friend class RGBConvolveChannel; // this one messes with itsPyrBuilder 00355 }; 00356 00357 00358 /* So things look consistent in everyone's emacs... */ 00359 /* Local Variables: */ 00360 /* indent-tabs-mode: nil */ 00361 /* End: */ 00362 00363 #endif // !SINGLECHANNEL_H_DEFINED