00001 /*!@file Beobot/ImageSpring.H derived from the image template class */ 00002 // all the pixels are linked to theirs neighbors with springs 00003 00004 00005 // //////////////////////////////////////////////////////////////////// // 00006 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00007 // University of Southern California (USC) and the iLab at USC. // 00008 // See http://iLab.usc.edu for information about this project. // 00009 // //////////////////////////////////////////////////////////////////// // 00010 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00011 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00012 // in Visual Environments, and Applications'' by Christof Koch and // 00013 // Laurent Itti, California Institute of Technology, 2001 (patent // 00014 // pending; application number 09/912,225 filed July 23, 2001; see // 00015 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00016 // //////////////////////////////////////////////////////////////////// // 00017 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00018 // // 00019 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00020 // redistribute it and/or modify it under the terms of the GNU General // 00021 // Public License as published by the Free Software Foundation; either // 00022 // version 2 of the License, or (at your option) any later version. // 00023 // // 00024 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00025 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00026 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00027 // PURPOSE. See the GNU General Public License for more details. // 00028 // // 00029 // You should have received a copy of the GNU General Public License // 00030 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00031 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00032 // Boston, MA 02111-1307 USA. // 00033 // //////////////////////////////////////////////////////////////////// // 00034 // 00035 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00036 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Beobot/ImageSpring.H $ 00037 // $Id: ImageSpring.H 9412 2008-03-10 23:10:15Z farhan $ 00038 // 00039 00040 #ifndef IMAGE_SPRING_H_DEFINED 00041 #define IMAGE_SPRING_H_DEFINED 00042 00043 #include "Image/Image.H" 00044 #include "Util/Assert.H" 00045 00046 template <class T> class PixRGB; 00047 00048 //! This class is some sort of self organizing map used for clustering 00049 /*! All the pixels are linked by springs whose stiffness depends on the 00050 difference between them 00051 */ 00052 template<class T> 00053 class ImageSpring : public Image<T> 00054 { 00055 public: 00056 //! Constructor that only allocates memory for given size 00057 inline ImageSpring(const int width, const int height, 00058 const int nbNeighbors); 00059 00060 //! Constructor for uninitialized image (useful for arrays of Images). 00061 /*! Use init() later to initialize */ 00062 inline ImageSpring(); 00063 00064 //! Copy constructor 00065 inline ImageSpring(const ImageSpring<T>& A); 00066 00067 //! init function 00068 inline void init(const int width, const int height, 00069 const int nbNeighbors); 00070 00071 //! init function, to copy another ImageSpring 00072 inline void init(const T* a, const float* posX, const float* posY, 00073 const float** stiff, 00074 const int width, const int height, 00075 const int nbNeighbors); 00076 00077 //! Destructor 00078 inline ~ImageSpring(); 00079 00080 //! Free memory and switch to uninitialized state 00081 inline void freeMem(); 00082 00083 //! initialize 'stiff' and 'pos' 00084 void initClustering(bool initPosMasses); 00085 00086 //! compute the stiffness of the spring between the masses 00087 /*! based on the color-distance between pixels */ 00088 void computeStiff(void); 00089 00090 //! updates the positions of the masses 00091 /*! based on simple mechanics */ 00092 void computePos(const float dt); 00093 00094 //! computes mean and stdev (**heuristic**) 00095 /*! this function is a heuristic because it will only 00096 consider nbHeuristic pixels at random */ 00097 void getStats(void); 00098 00099 //! computes meanDist and stdevDist (**heuristic**) 00100 /*! weight must be defined 00101 this function is an heuristic because it will only 00102 consider nbHeuristic pairs of pixels at random */ 00103 void getStatsDist(void); 00104 00105 //! returns (X,Y) given an index=X+w*Y (see posX) 00106 inline void getXY(const int index, Point2D<int> &pt) const; 00107 00108 //! returns the index=X+w*Y (see posX) 00109 inline void getIndex(const Point2D<int> point, int &index) const; 00110 00111 //! returns the number of neighbors 00112 inline int getNbNeighbors(void) const; 00113 00114 //! distance between the 2 masses 00115 float getDistanceMasses(const int index1, const int index2) const; 00116 00117 //! computes the index of the nth neighbor of "index" 00118 /*! returns true iif the neighbor is in the image */ 00119 inline bool getNeighbor(const int index, const int n, 00120 int& indexNeighbor) const; 00121 00122 //! Get position of masses and strength of springs (for debug) 00123 void getPositions(Image< PixRGB<byte> >& img, const int zoom = 16); 00124 00125 00126 //! get clustered image and track centroid position 00127 void getClusteredImage(const Image< PixRGB<byte> > &scene, 00128 Image< PixRGB<byte> > &clusteredImage, 00129 Point2D<int> &supposedTrackCentroid, 00130 const Point2D<int>& previousTrackCentroid); 00131 00132 private: 00133 //! subfunction find n-connex graph 00134 /*! n connex sub-graph are the subgraph whose nodes are connected to 00135 one another by at least n links. The nodes already marked have non 0 00136 values in 'marked', the current node is 'currentPoint' and the current label 00137 (i.e. number of the group) is 'color'. 'begin' is used to initialize the 00138 algorithm because if we apply n-connexity from the beginng then obviously 00139 no node will qualify as the first one we see has 0 neighbors... */ 00140 void goGraph(Image<int32> &marked, const int currentIndex, 00141 const int32 color, const int begin = 3); 00142 00143 //! defines the neighborhhod topology (5, 9 or 25) 00144 /*! see "getNeighbor" for indexing */ 00145 int nbNeighbors; 00146 00147 //! mean and stdev of the image 00148 /*! not necessarily scalar, don't confuse with meanDist, stdevDist */ 00149 T mean, stdev; 00150 00151 //! mean and stdev of the distance between meighbor pixels 00152 /*! always scalar by definition of adistance... 00153 don't be confused, it's NOT the mean and stdev of the image */ 00154 double meanDist, stdevDist; 00155 00156 //! to define weightedDistance() between pixels 00157 /*! this is normally stdev.inverse(), this way the system is 00158 completly independent from the dynamic range of the low 00159 level features */ 00160 T weight; 00161 00162 //! physical position of the "masses" at time t 00163 /*! 2D array represented as 1D array: index = x+y*nX */ 00164 float *posX, *posY; 00165 00166 //! physical position of the "masses" at time t-dt. 00167 float *oldPosX, *oldPosY; 00168 00169 /*! stiff[index][n] is the stiffness of the spring between index and 00170 its nth neighbor. Note: we consider that length is 0 for all 00171 springs ! */ 00172 float **stiff; 00173 00174 //! computes weight given mean & stdev 00175 void computeWeight(void); 00176 00177 //! sets the "physical" position of mass at (x,y) 00178 inline void setPos(const Point2D<int> mass, const float x, const float y); 00179 00180 //! sets the stiffness of the spring 00181 inline void setStiff(const Point2D<int> mas, int neighboor, float stiff); 00182 00183 //! the moments will be estimated with nbHeuristic outcomes 00184 const static int nbHeuristic = 500; 00185 }; 00186 00187 // ###################################################################### 00188 // ###################################################################### 00189 // ###################################################################### 00190 // INLINE FUNCTIONS: 00191 // ###################################################################### 00192 // ###################################################################### 00193 // ###################################################################### 00194 00195 // ###################################################################### 00196 template<class T> inline 00197 ImageSpring<T>::ImageSpring(const int width, const int height, 00198 const int nbN) : 00199 Image<T>(width, height, NO_INIT) 00200 { 00201 init(width, height, nbN); 00202 } 00203 00204 // ###################################################################### 00205 template<class T> inline 00206 ImageSpring<T>::ImageSpring() : Image<T>() 00207 { posX = NULL; posY = NULL; oldPosX = NULL; oldPosY = NULL; stiff = NULL; } 00208 00209 // ###################################################################### 00210 template<class T> inline 00211 ImageSpring<T>::ImageSpring(const ImageSpring<T>& A) : Image<T>(A) 00212 { 00213 ASSERT(A.initialized()); 00214 posX = NULL; posY = NULL; oldPosX = NULL; oldPosY = NULL; stiff = NULL; 00215 00216 init(A.getArrayPtr(), posX, posY, const_cast<const float**>(A.stiff), 00217 A.getWidth(), A.getHeight(), A.nbNeighbors); 00218 } 00219 00220 // ###################################################################### 00221 template<class T> inline 00222 ImageSpring<T>::~ImageSpring() 00223 { freeMem(); } 00224 00225 // ###################################################################### 00226 template<class T> inline 00227 void ImageSpring<T>::freeMem() 00228 { 00229 if (stiff) { 00230 for (int index = 0;index < this->getSize(); index++) delete [] stiff[index]; 00231 delete [] stiff; stiff = NULL; 00232 } 00233 if (posX) { delete [] posX; posX = NULL; } 00234 if (posY) { delete [] posY; posY = NULL; } 00235 if (oldPosX) { delete [] oldPosX; oldPosX = NULL; } 00236 if (oldPosY) { delete [] oldPosY; oldPosY = NULL; } 00237 Image<T>::freeMem(); 00238 } 00239 00240 // ###################################################################### 00241 template<class T> inline 00242 void ImageSpring<T>::init(const T* inarray, 00243 const float* inPosX, const float* inPosY, 00244 const float** inStiff, 00245 const int width, const int height, 00246 const int nbN) 00247 { 00248 freeMem(); // delete any allocated memory 00249 this->resize(width, height); // allocate underlying Image<T> 00250 nbNeighbors = nbN; int size = this->getSize(); 00251 00252 // allocate memory for the mass positions: 00253 posX = new float[size]; memcpy(posX, inPosX, size * sizeof(float)); 00254 posY = new float[size]; memcpy(posY, inPosY, size * sizeof(float)); 00255 oldPosX = new float[size]; memcpy(oldPosX, inPosX, size * sizeof(float)); 00256 oldPosY = new float[size]; memcpy(oldPosY, inPosY, size * sizeof(float)); 00257 00258 // the neighbor #0 is the grid point, so there are nbN+1 neighbors 00259 typedef float* floatptr; 00260 stiff = new floatptr[size]; 00261 for (int index = 0; index < size; index++) 00262 { 00263 stiff[index] = new float[nbN + 1]; 00264 memcpy(stiff[index], inStiff[index], (nbN + 1) * sizeof(float)); 00265 } 00266 } 00267 00268 // ###################################################################### 00269 template<class T> inline 00270 void ImageSpring<T>::init(const int width, const int height, 00271 const int nbN) 00272 { 00273 freeMem(); // delete any allocated memory 00274 this->resize(width, height); // allocate underlying Image<T> 00275 nbNeighbors = nbN; int size = this->getSize(); 00276 00277 // allocate memory for the mass positions: 00278 posX = new float[size]; posY = new float[size]; 00279 oldPosX = new float[size]; oldPosY = new float[size]; 00280 00281 typedef float* floatptr; 00282 stiff = new floatptr[size]; 00283 for (int index = 0; index < size; index++) stiff[index] = new float[nbN + 1]; 00284 } 00285 00286 // ###################################################################### 00287 template<class T> inline 00288 void ImageSpring<T>::getXY( const int index, Point2D<int> &pt ) const 00289 { pt.i = index % this->getWidth(); pt.j = index / this->getWidth(); } 00290 00291 // ###################################################################### 00292 template<class T> inline 00293 void ImageSpring<T>::getIndex( const Point2D<int> point, int &index ) const 00294 { index = point.i + point.j * this->getWidth(); } 00295 00296 // ###################################################################### 00297 template<class T> inline 00298 bool ImageSpring<T>::getNeighbor( const int index, const int n, 00299 int& indexNeighbor ) const 00300 { 00301 ASSERT(n > 0 && n <= nbNeighbors); 00302 00303 Point2D<int> pt; getXY(index, pt); 00304 00305 switch(n) 00306 { 00307 case 0 : break; // to the grid 00308 00309 // 4-neighbors 00310 case 1 : pt.i--; break; 00311 case 2 : pt.j--; break; 00312 case 3 : pt.i++; break; 00313 case 4 : pt.j++; break; 00314 00315 // 8-neighbors 00316 case 5 : pt.i--; pt.j--; break; 00317 case 6 : pt.i++; pt.j--; break; 00318 case 7 : pt.i--; pt.j++; break; 00319 case 8 : pt.i++; pt.j++; break; 00320 00321 // 24-neighbors 00322 case 9 : pt.i-=2; pt.j+=2; break; 00323 case 10: pt.i-=1; pt.j+=2; break; 00324 case 11: pt.j+=2; break; 00325 case 12: pt.i+=1; pt.j+=2; break; 00326 case 13: pt.i+=2; pt.j+=2; break; 00327 case 14: pt.i+=2; pt.j+=1; break; 00328 case 15: pt.i+=2; break; 00329 case 16: pt.i+=2; pt.j-=1; break; 00330 case 17: pt.i+=2; pt.j-=2; break; 00331 case 18: pt.i+=1; pt.j-=2; break; 00332 case 19: pt.j-=2; break; 00333 case 20: pt.i-=1; pt.j-=2; break; 00334 case 21: pt.i-=2; pt.j-=2; break; 00335 case 22: pt.i-=2; pt.j-=1; break; 00336 case 23: pt.i-=2; break; 00337 case 24: pt.i-=2; pt.j+=1; break; 00338 00339 // larger than that is unsupported: 00340 default: 00341 LFATAL("Neighbor out or range"); 00342 } 00343 00344 getIndex( pt, indexNeighbor ); 00345 00346 return this->coordsOk( pt ); 00347 } 00348 00349 // ###################################################################### 00350 template<class T> inline 00351 int ImageSpring<T>::getNbNeighbors( void ) const 00352 { return nbNeighbors; } 00353 00354 // ###################################################################### 00355 template<class T> inline 00356 void ImageSpring<T>::setPos(const Point2D<int> mass, const float x, const float y) 00357 { 00358 ASSERT(this->initialized() && this->coordsOk(mass)); 00359 int index; getIndex(mass, index); 00360 posX[index] = x; posY[index] = y; 00361 } 00362 00363 // ###################################################################### 00364 template<class T> 00365 void ImageSpring<T>::setStiff(const Point2D<int> mass, int neighbor, float stif) 00366 { 00367 ASSERT(this->initialized() && this->coordsOk(mass) && neighbor <= nbNeighbors); 00368 int index; getIndex(mass, index); 00369 stiff[index][neighbor] = stif; 00370 } 00371 00372 00373 00374 // ###################################################################### 00375 /* So things look consistent in everyone's emacs... */ 00376 /* Local Variables: */ 00377 /* indent-tabs-mode: nil */ 00378 /* End: */ 00379 00380 #endif