The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

src/mpiimage.h

Go to the documentation of this file.
00001 
00027 #ifndef _MPIIMAGE_H_
00028 #define _MPIIMAGE_H_
00029 
00030 #include <fstream>
00031 #include <vector>
00032 
00033 #include "rimage.h"
00034 #include "square.h"
00035 #include "roi.h"
00036 #include "faceboxlist.h"
00037 
00038 using namespace std;
00039 
00040 template<class T> class MPIImagePyramid; // forward declaration for convenience
00041 
00052 template<class T>
00053 class MPIScaledImage{
00054   //private:
00055   
00056  public:
00057   const MPIImagePyramid<T>& m_ref;
00058   float shift;
00059   const int m_scale_ind;
00060   const int m_scale_factor;
00061   const float m_true_scale_factor;
00062   int   subwin_size_x; // Note: this is pure evil if m_true_scale_factor * (m_ref.m_window_x) is not an integer;
00063   int   subwin_size_y; // same as above
00064   int m_min_x, m_max_x, m_min_y, m_max_y;
00065   MPIScaledImage(const MPIImagePyramid<T>& ref, const int &scale_ind)
00066     : m_ref(ref), m_scale_ind(scale_ind), m_scale_factor(static_cast<int>(m_ref.scale_factors[scale_ind]+0.5)),
00067       m_true_scale_factor(ref.scale_factors[scale_ind]) {
00068     shift = max(1.0f,m_scale_factor*(m_ref.m_stride + 0.00001f));  // Fudge to make sure floor works correctly
00069     subwin_size_x = static_cast<int>(m_true_scale_factor * (m_ref.m_window_x)+0.0001f);
00070     subwin_size_y = static_cast<int>(m_true_scale_factor * (m_ref.m_window_y)+0.0001f);
00071     m_min_x = ref.m_roi.vmin_x[scale_ind];
00072     m_max_x = ref.m_roi.vmax_x[scale_ind];
00073     m_min_y = ref.m_roi.vmin_y[scale_ind];
00074     m_max_y = ref.m_roi.vmax_y[scale_ind];
00075   }
00093   class const_iterator{
00094   private:
00095     typedef const_iterator self;
00096     const MPIScaledImage< T > & m_ref;
00097     const vector< RImage< T > * >& ref_image; //  gcc 2.95 requires this... bug in gcc?
00098     const T* pixel0, *pixel1; // a reference to the first pixel of the first two images. Bad if there aren't enough windows.
00099     int m_max_x, m_max_y, m_max_valid_x_ind, m_max_valid_y_ind;
00100     float m_pos_x, m_pos_y;
00101     int m_working_x, m_working_y;
00102     //int old_x, old_y;
00103     int m_ind, m_line_ind;
00104     int m_min_x;
00105     float m_min_x_f;
00106     float m_shift;
00107     public:
00108       const_iterator(MPIScaledImage<T>& ref, const int &pos_x, const int &pos_y) : m_ref(ref),
00109         ref_image(m_ref.m_ref.m_image), m_shift(ref.shift) {
00110             m_working_x = pos_x;
00111             m_working_y = pos_y;
00112             m_pos_x = static_cast<float>(m_working_x);
00113             m_pos_y = static_cast<float>(m_working_y);
00114             m_line_ind = m_working_y*ref_image[0]->width;
00115             m_ind = m_line_ind + m_working_x;
00116             m_max_x = m_ref.m_max_x - (m_ref.subwin_size_x); 
00117             m_max_y = m_ref.m_max_y - (m_ref.subwin_size_y);
00118             m_max_valid_x_ind = ref_image[0]->width - m_ref.subwin_size_x;
00119             m_max_valid_y_ind = ref_image[0]->height - m_ref.subwin_size_y;
00120             m_min_x = m_ref.m_min_x;
00121             m_min_x_f = static_cast<float>(m_min_x);
00122 
00123         pixel0 = ref_image[0]->array + m_ind;
00124         pixel1 = ref_image[1]->array + m_ind;
00125                 }
00126                 
00127       // Increment Logic
00128                 inline void do_increment(){
00129                   m_pos_x += m_shift;
00130                   m_working_x = static_cast<int>(m_pos_x);
00131                   if(m_working_x < m_max_x){
00132                     m_ind = m_line_ind + m_working_x;
00133                   } else {
00134             m_pos_x = m_min_x_f; 
00135                     m_working_x = m_min_x; 
00136                     m_pos_y += m_shift;
00137                     m_working_y = static_cast<int>(m_pos_y);
00138                     m_line_ind = m_working_y*ref_image[0]->width;
00139                     m_ind = m_line_ind + m_working_x;
00140                   }
00141                   pixel0 = ref_image[0]->array + m_ind;
00142                   pixel1 = ref_image[1]->array + m_ind;
00143                 }
00145                 inline self& operator++ () { 
00146                   do_increment(); 
00147                   return *this; }
00149                 inline self operator++ (int) { self tmp = *this; do_increment(); return tmp; }
00150                 inline self& operator=(const self &it){
00151                   m_max_x = it.m_max_x; m_max_y=it.m_max_y; m_max_valid_x_ind=it.m_max_valid_x_ind;
00152                   m_max_valid_y_ind=it.m_max_valid_y_ind; m_pos_x=it.m_pos_x; m_pos_y=it.m_pos_y;
00153                   m_working_x=it.m_working_x; m_working_y=it.m_working_y; m_ind=it.m_ind; m_line_ind=it.m_line_ind;
00154                   return *this;
00155                 }
00156                 //: Predecrement
00157                 //inline self& operator-- () { --m_pos; return *this; }
00158                 //: Postdecrement
00159                 //inline self operator-- (int) { self tmp = *this; --m_pos; return tmp; }
00160                 
00161                 inline T operator*() const{ return ref_image[0]->getPixel( m_ind ); }
00162                 inline bool operator!=(const self& x) const { return m_ind != x.m_ind; }
00163                 inline bool operator<=(const self& x) const { return m_pos_y <= x.m_pos_y; }
00164                 inline RImage<T>& operator[](int i) const { return *ref_image[i]; }
00165                 inline void getIndex(int &ind) const { ind = m_ind; }
00166                 inline void getCoords(int &x, int &y) const { x = m_working_x, y = m_working_y; }
00167                 inline int getSize() const {return m_ref.subwin_size_x;}
00168                 
00169                 //-------------------------------------------
00170                 // Get Pixel functions
00171                 //
00173       inline T getPixel(const int &i, const int &ind){
00174         return ref_image[i]->getPixel(m_ind+ind); }
00176       inline T getPixel0(const int &ind) const { return pixel0[ind]; }
00178       inline T getPixel1(const int &ind) const { return pixel1[ind]; }
00180       inline T getPixel(const int &i, const int &ind, const int &x, const int &y) const {
00181           if((m_working_x < 0) || (m_working_y < 0) || (m_working_x > m_max_valid_x_ind) || (m_working_y > m_max_valid_y_ind))
00182             return ref_image[i]->getPixel(m_working_x + x, m_working_y + y);
00183           else
00184             return ref_image[i]->getPixel(m_ind+ind);
00185       }
00186       inline T getScalePixel(const int &i, const int &x, const int &y) const {
00187         return ref_image[i]->getPixel(m_working_x + x * m_ref.m_scale_factor, m_working_y + y * m_ref.m_scale_factor); }
00188 
00190       inline T getShiftPixel(const int &i, const int &x, const int &y){
00191         return ref_image[i]->getPixel(static_cast<int>(m_pos_x + x * m_shift),
00192                                       static_cast<int>(m_pos_y + y * m_shift)); }
00193       //--------------------------------------------
00194 
00195 
00196       //-------------------------------------------
00197       // Set Pixel functions
00198       //
00199       inline void setPixel(const int &i, const int &ii, const T &val){
00200                         ref_image[i]->setPixel(m_ind+ii, val); }
00201       inline void setPixel(const int &i, const int &x, const int &y, const T &val){
00202             ref_image[i]->setPixel(static_cast<int>(m_pos_x + x),
00203                                    static_cast<int>(m_pos_y + y), val); }
00204       inline void setShiftPixel(const int &i, const int &x, const int &y, const T &val){
00205                         ref_image[i]->setPixel(static_cast<int>(m_pos_x + x * m_shift),
00206                                       static_cast<int>(m_pos_y + y * m_shift), val); }
00207       inline void setScalePixel(const int &i, const int &x, const int &y, const T &val){
00208                         ref_image[i]->setPixel(m_working_x + x * m_ref.m_scale_factor,
00209                                       m_working_y + y * m_ref.m_scale_factor, val); }
00210       // set pixels that correspond to shifting the window (i.e., take stride into account)
00211       //--------------------------------------------
00212       inline Square getSquare() const { return Square(m_ref.subwin_size_x, m_working_x, m_working_y, m_ref.m_scale_ind); }
00213     };
00214     friend class const_iterator;
00215 
00216     inline const_iterator begin(){ return const_iterator(*this, m_min_x, m_min_y); }
00217     inline const_iterator end(){
00218       // This is inefficient, but trying to figure it out correctly is very error-prone. Help!
00219       int working_y = m_min_y;
00220       float pos_y = static_cast<float>(working_y);
00221       while((working_y + subwin_size_y) < m_max_y){
00222         pos_y += shift;
00223         working_y = static_cast<int>(pos_y);
00224       }
00225       return const_iterator(*this, m_min_x, working_y);// - (m_scale_factor - 1));
00226     }
00227 };
00228 
00229 
00236 template<class T>
00237 class MPIImagePyramid{
00238   friend class MPIScaledImage<T>;
00239   // Issues annoying warning on gcc 3.2, but I think its a bug in gcc
00240   friend class MPIScaledImage<T>::const_iterator; 
00241 
00242   // Public Functions and data
00243  public:
00244   MPIImagePyramid(RImage<T> &image, float scale_factor, int window_x, int window_y, float stride)
00245     : m_scale_factor(scale_factor),
00246     m_window_x(window_x), m_window_y(window_y), m_stride(stride){
00247     m_image.push_back(&image);
00248     SetScaleFactors();
00249     InitROI(); }
00250          
00251   MPIImagePyramid(vector< RImage<T>* > &image, float scale_factor, int window_x, int window_y, float stride)
00252     : m_image(image),  m_scale_factor(scale_factor),
00253     m_window_x(window_x), m_window_y(window_y), m_stride(stride){
00254     SetScaleFactors();
00255     InitROI(); }
00256 
00257   ~MPIImagePyramid(){ }
00258          
00259   class const_iterator{
00260   private:
00261     typedef const_iterator self;
00262     const MPIImagePyramid<T>& m_ref; 
00263     int m_pos;
00264   public:
00265     const_iterator(const MPIImagePyramid &ref, const int &pos) : m_ref(ref), m_pos(pos) {
00266       //;//cout << "scale iterator: m_pos="<<m_pos<<endl;
00267     }
00268     // Preincrement
00269     inline self& operator++ () { ++m_pos; return *this; }
00270     // Postincrement
00271     inline self operator++ (int) { self tmp = *this; ++m_pos; return tmp; }
00272     // Preincrement
00273     inline self& operator-- () { --m_pos; return *this; }
00274     // Postincrement
00275     inline self operator-- (int) { self tmp = *this; --m_pos; return tmp; }
00276     // Dereference
00277     MPIScaledImage<T> operator*() const{ return MPIScaledImage<T>(m_ref, m_pos);}
00278     // Notequals
00279     inline bool operator!=(const self& x) const { return m_pos != x.m_pos; }
00280     inline int getScale(float &sf){sf = m_ref.scale_factors[m_pos]; return m_pos; }
00281     inline float getScale(){return m_ref.scale_factors[m_pos];}
00282   };
00283 
00284   friend class const_iterator;
00285   inline const_iterator begin(){
00286     return const_iterator(*this, m_roi.m_min_scale); }
00287   inline const_iterator end(){
00288     return const_iterator(*this, m_roi.m_max_scale); }
00289          
00290  public:
00291   vector< float > scale_factors;
00292   float m_stride;
00293   inline float getMaxScale(){return scale_factors[scale_factors.size() - 1];}
00294   inline int getMaxScale(float &sf){sf = scale_factors[scale_factors.size() - 1]; return scale_factors.size() - 1;}
00295  private:
00296   // Private data
00297   vector< RImage<T>* > m_image;
00298   ROI m_roi;
00299   float m_scale_factor;
00300   int m_window_x, m_window_y;
00301   float temp;
00302 
00303   // Private Functions
00304   inline int imax(const int &x, const int &y) const { return(x > y ? x : y);}
00305   inline int imin(const int &x, const int &y) const { return(x < y ? x : y);}
00306   inline int scale(const int &x, const int &y) const { return(x * y);}
00307   void SetScaleFactorsFloat(){
00308       // Find maximum scales
00309       float max_y_scale_factor = static_cast<int>(m_image[0]->height / (m_window_y+1));
00310       float max_x_scale_factor = static_cast<int>(m_image[0]->width / (m_window_x+1));
00311       if (max_x_scale_factor && max_y_scale_factor){
00312           float scale_factor = 1.0f;
00313           while((scale_factor < max_y_scale_factor) && (scale_factor < max_x_scale_factor)){
00314               scale_factors.push_back(scale_factor);
00315               temp = (float)(static_cast<int>(scale_factor*m_scale_factor*(float)m_window_x + .99999f))/(float)m_window_x;
00316               scale_factor = temp;
00317           }
00318           // make the last scale such that the window gets as close as possible to the full image
00319           scale_factor = min(max_x_scale_factor,max_y_scale_factor);
00320           scale_factors.push_back(scale_factor);
00321       }
00322   }
00323   void SetScaleFactors(){
00324     // Find maximum scales
00325     int max_y_scale_factor = static_cast<int>(m_image[0]->height / (m_window_y+1));
00326     int max_x_scale_factor = static_cast<int>(m_image[0]->width / (m_window_x+1));
00327     if (max_x_scale_factor && max_y_scale_factor){
00328       int scale_factor = 1;
00329       while((scale_factor < max_y_scale_factor) && (scale_factor < max_x_scale_factor)){
00330         scale_factors.push_back(scale_factor);
00331         temp = imax (scale_factor+1, static_cast<int>(scale_factor*m_scale_factor));
00332         scale_factor = (int)temp;
00333       }
00334       // make the last scale such that the window gets as close as possible to the full image
00335       scale_factor = imin(max_x_scale_factor,max_y_scale_factor);
00336       scale_factors.push_back(scale_factor);
00337     }
00338   }
00339   void SetScaleFactorsNew(int start, int scale_size, float percent){
00340     //Find maximum scales
00341     int max_y_scale_factor = static_cast<int>(m_image[0]->height / (m_window_y+1));
00342     int max_x_scale_factor = static_cast<int>(m_image[0]->width / (m_window_x+1));
00343     if (max_x_scale_factor && max_y_scale_factor){
00344       int max_scale_factor = imin(max_x_scale_factor, max_y_scale_factor);
00345       int current_scale = 0;
00346       int previous_scale = start;
00347       int previous_point, current_point;
00348       scale_factors.push_back(start);
00349       while(current_scale < max_scale_factor){
00350         current_scale = previous_scale+1;
00351         previous_point = scale(previous_scale, scale_size) + (scale(previous_scale, scale_size) * percent);
00352         while(current_scale < max_scale_factor){
00353           current_point = scale(current_scale, scale_size) - (scale(current_scale, scale_size) * percent);
00354           if(current_point < previous_point)
00355             current_scale++;
00356           else{
00357             if(current_scale - 1 == previous_scale)
00358               current_scale++;//to make sure next scale != to previous scale
00359             scale_factors.push_back(current_scale - 1);
00360             previous_scale = current_scale - 1;
00361             break;
00362           }
00363         }
00364       }
00365       // make the last scale such that the window gets as close as possible to the full image
00366       // if gap between previous_scale and max_scale then also add prior scale
00367       current_point = scale(max_scale_factor, scale_size) - (scale(max_scale_factor, scale_size) * percent);
00368       if(current_point > previous_point && (max_scale_factor - 1) > previous_scale)
00369         scale_factors.push_back(max_scale_factor -1);
00370       scale_factors.push_back(max_scale_factor);
00371     }
00372   }
00373   void InitROIvectors(){
00374     m_roi.vmin_x.clear();
00375     m_roi.vmax_x.clear();
00376     m_roi.vmin_y.clear();
00377     m_roi.vmax_y.clear();
00378     for(unsigned int i=0; i < scale_factors.size(); ++i){
00379       m_roi.vmin_x.push_back(m_roi.m_min_x);
00380       m_roi.vmax_x.push_back(m_roi.m_max_x);
00381       m_roi.vmin_y.push_back(m_roi.m_min_y);
00382       m_roi.vmax_y.push_back(m_roi.m_max_y);
00383     }
00384   }
00385 
00386  public:
00387   void InitROI(){
00388     m_roi.m_min_x = 0;
00389     m_roi.m_min_y = 0;
00390     m_roi.m_min_scale = 0;
00391     m_roi.m_max_x = m_image[0]->width;
00392     m_roi.m_max_y = m_image[0]->height;
00393     m_roi.m_max_scale = scale_factors.size();
00394     m_roi.m_limit_scale = scale_factors.size();
00395     InitROIvectors();
00396   }
00397   ROI SetROI(ROI &roi){
00398     // set ROI to boundaries of image and scales
00399     m_roi = roi;
00400     if(m_roi.m_min_x < 0) m_roi.m_min_x = 0;
00401     if(m_roi.m_max_x > m_image[0]->width) m_roi.m_max_x = m_image[0]->width;
00402     if(m_roi.m_min_y < 0) m_roi.m_min_y = 0;
00403     if(m_roi.m_max_y > m_image[0]->height) m_roi.m_max_y = m_image[0]->height;
00404     if(m_roi.m_min_scale < 0) m_roi.m_min_scale = 0;
00405     if(m_roi.m_max_scale > (int)scale_factors.size()) m_roi.m_max_scale = scale_factors.size();
00406     // if vector parts are empty, initialize them to full image pyramid
00407     if(!m_roi.vmin_x.size() && !m_roi.vmax_x.size() && !m_roi.vmin_y.size() && !m_roi.vmax_y.size()){
00408       InitROIvectors();
00409     }
00410     // if they are not empty but different from correct size, reinitialize them
00411     else {
00412       if((m_roi.vmin_x.size() != scale_factors.size()) || 
00413                                 (m_roi.vmax_x.size() != scale_factors.size()) || 
00414                                 (m_roi.vmin_y.size() != scale_factors.size()) || 
00415                                 (m_roi.vmax_y.size() != scale_factors.size()) ){
00416                                 std::cerr << "MPIImagePyramid::SetROI():  Received inconsistent vector part of ROI! Resetting ROI vectors" << endl;
00417                                 InitROIvectors();
00418       }
00419       // Ok, suppose it has a valid vector part, then
00420       // make sure no vector parts go outside of image boundary
00421       else{
00422                                 for(unsigned int i=0; i < scale_factors.size(); ++i){
00423                                         if(m_roi.vmin_x[i] < 0) m_roi.vmin_x[i] = 0;
00424                                         if(m_roi.vmax_x[i] > m_image[0]->width) m_roi.vmax_x[i] = m_image[0]->width;
00425                                         if(m_roi.vmin_y[i] < 0) m_roi.vmin_y[i] = 0;
00426                                         if(m_roi.vmax_y[i] > m_image[0]->height) m_roi.vmax_y[i] = m_image[0]->height;
00427                                 }
00428       }
00429       // Make sure the ROI holds correct values for the absolute min and max
00430       for(unsigned int i=0; i < scale_factors.size(); ++i){
00431                                 if(m_roi.m_min_x > m_roi.vmin_x[i]) m_roi.m_min_x = m_roi.vmin_x[i];
00432                                 if(m_roi.m_max_x < m_roi.vmax_x[i]) m_roi.m_max_x = m_roi.vmax_x[i];
00433                                 if(m_roi.m_min_y > m_roi.vmin_y[i]) m_roi.m_min_y = m_roi.vmin_y[i];
00434                                 if(m_roi.m_max_y < m_roi.vmax_y[i]) m_roi.m_max_y = m_roi.vmax_y[i];
00435       }
00436     }
00437     return m_roi;
00438   }
00439   ROI getROI() const { return m_roi; }
00440   int getClosestScale(float input_scale_factor){
00441     // if scale_factors were a map, could use stl algorithms, but its small so whatever
00442     for(int i = 1; i<scale_factors.size(); ++i)
00443       if(static_cast<float>(scale_factors[i])>input_scale_factor)
00444         return i-1;
00445     return scale_factors.size()-1;
00446   }
00447 };
00448 
00449 
00450 #endif
00451 
00452 
00453 /*
00454 * 
00455 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00456 *
00457 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00458 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
00459 *    3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
00460 * 
00461 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00462 * 
00463 */
00464 

Generated on Mon Nov 8 17:07:44 2004 for MPT by  doxygen 1.3.9.1