contrib/mul/vimt/vimt_gaussian_pyramid_builder_2d.txx
Go to the documentation of this file.
00001 // This is mul/vimt/vimt_gaussian_pyramid_builder_2d.txx
00002 #ifndef vimt_gaussian_pyramid_builder_2d_txx_
00003 #define vimt_gaussian_pyramid_builder_2d_txx_
00004 //:
00005 // \file
00006 // \brief Class to build gaussian pyramids of vimt_image_2d_of<T>
00007 // \author Tim Cootes
00008 
00009 #include "vimt_gaussian_pyramid_builder_2d.h"
00010 
00011 #include <vcl_cstdlib.h>
00012 #include <vcl_string.h>
00013 
00014 #include <vcl_cassert.h>
00015 #include <vnl/vnl_math.h> // for sqrt2
00016 #include <vgl/vgl_point_2d.h>
00017 #include <vgl/vgl_vector_2d.h>
00018 #include <vil/algo/vil_gauss_reduce.h>
00019 #include <mbl/mbl_exception.h>
00020 #include <vimt/vimt_image_pyramid.h>
00021 #include <vimt/vimt_crop.h>
00022 
00023 //=======================================================================
00024 
00025 template<class T>
00026 vimt_gaussian_pyramid_builder_2d<T>::vimt_gaussian_pyramid_builder_2d()
00027 : max_levels_(99),filter_width_(5)
00028 {
00029   set_min_size(5, 5);
00030 }
00031 
00032 //=======================================================================
00033 
00034 template<class T>
00035 vimt_gaussian_pyramid_builder_2d<T>::~vimt_gaussian_pyramid_builder_2d()
00036 {
00037 }
00038 
00039 //=======================================================================
00040 //: Define maximum number of levels to build
00041 //  Limits levels built in subsequent calls to build()
00042 template<class T>
00043 void vimt_gaussian_pyramid_builder_2d<T>::set_max_levels(int max_l)
00044 {
00045   if (max_l<1)
00046   {
00047     vcl_cerr << "vimt_gaussian_pyramid_builder_2d<T>::setMaxLevels() "
00048              << "Must be >=1\n";
00049     vcl_abort();
00050   }
00051   max_levels_ = max_l;
00052 }
00053 
00054 //: Get the current maximum number levels allowed
00055 template<class T>
00056 int vimt_gaussian_pyramid_builder_2d<T>::max_levels() const
00057 {
00058   return max_levels_;
00059 }
00060 
00061 //=======================================================================
00062 //: Create new (empty) pyramid on heap
00063 //  Caller responsible for its deletion
00064 template<class T>
00065 vimt_image_pyramid* vimt_gaussian_pyramid_builder_2d<T>::new_image_pyramid() const
00066 {
00067   return new vimt_image_pyramid;
00068 }
00069 
00070 //=======================================================================
00071 //: Scale step between levels
00072 template<class T>
00073 double vimt_gaussian_pyramid_builder_2d<T>::scale_step() const
00074 {
00075   return 2.0;
00076 }
00077 
00078 //: Set current filter width (must be 3 or 5 at present)
00079 template<class T>
00080 void vimt_gaussian_pyramid_builder_2d<T>::set_filter_width(unsigned w)
00081 {
00082   assert(w==3 || w==5);
00083   filter_width_ = w;
00084 }
00085 
00086 //: Smooth and subsample src_im to produce dest_im
00087 //  Applies filter in x and y, then samples every other pixel.
00088 template<class T>
00089 void vimt_gaussian_pyramid_builder_2d<T>::gauss_reduce(const vimt_image_2d_of<T>& src_im,
00090                                                        vimt_image_2d_of<T>& dest_im) const
00091 {
00092   switch (filter_width_)
00093   {
00094     case (3):
00095       vil_gauss_reduce_121(src_im.image(),dest_im.image());
00096       break;
00097     case (5):
00098       vil_gauss_reduce(src_im.image(),dest_im.image(),work_im_.image());
00099       break;
00100     default:
00101       vcl_cerr << "vimt_gaussian_pyramid_builder_2d<T>::gauss_reduce() "
00102                << "cannot cope with filter width of "<<filter_width_<<'\n';
00103       vcl_abort();
00104   }
00105 
00106   // Sort out world to image transformation for destination image
00107   vimt_transform_2d scaling;
00108   scaling.set_zoom_only(0.5,0,0);
00109   dest_im.set_world2im(scaling * src_im.world2im());
00110 }
00111 
00112 //=======================================================================
00113 //: Deletes all data in im_pyr
00114 template<class T>
00115 void vimt_gaussian_pyramid_builder_2d<T>::empty_pyr(vimt_image_pyramid& im_pyr) const
00116 {
00117   for (int i=0; i<im_pyr.n_levels();++i)
00118     delete im_pyr.data()[i];
00119 }
00120 
00121 //=======================================================================
00122 //: Checks pyramid has at least n levels
00123 template<class T>
00124 void vimt_gaussian_pyramid_builder_2d<T>::check_pyr(vimt_image_pyramid& im_pyr,  int n_levels) const
00125 {
00126   const int got_levels = im_pyr.n_levels();
00127   if (got_levels >= n_levels && im_pyr(0).is_class(work_im_.is_a()))
00128   {
00129     if (im_pyr.n_levels()==n_levels) return;
00130     else
00131     {
00132       for (int i=n_levels;i<got_levels;++i)
00133         delete im_pyr.data()[i];
00134     }
00135     im_pyr.data().resize(n_levels);
00136     return;
00137   }
00138 
00139   im_pyr.resize(n_levels,vimt_image_2d_of<T>());
00140 }
00141 
00142 //=======================================================================
00143 //: Build pyramid
00144 template<class T>
00145 void vimt_gaussian_pyramid_builder_2d<T>::build(vimt_image_pyramid& image_pyr,
00146                                                 const vimt_image& im) const
00147 {
00148   //  Require image vimt_image_2d_of<T>
00149   if (!im.is_class(work_im_.is_a()))
00150     throw mbl_exception_abort("vimt_gaussian_pyramid_builder_2d<T>::build(): Expected a "
00151                               + work_im_.is_a() + ", but got a " + im.is_a() );
00152 
00153   const vimt_image_2d_of<T>& base_image = static_cast<const vimt_image_2d_of<T>&>(im);
00154 
00155   int ni = base_image.image().ni();
00156   int nj = base_image.image().nj();
00157 
00158   // Compute number of levels to pyramid so that top is no less
00159   // than minXSize_ x minYSize_
00160   int s = 1;
00161   int max_levels = 1;
00162   while ((ni/(2*s)>=int(minXSize_)) && (nj/(2*s)>=int(minYSize_)))
00163   {
00164     max_levels++;
00165     s*=2;
00166   }
00167 
00168   if (max_levels>max_levels_)
00169     max_levels=max_levels_;
00170 
00171   // Set up image pyramid
00172   check_pyr(image_pyr,max_levels);
00173 
00174   vimt_image_2d_of<T>& im0 = static_cast<vimt_image_2d_of<T>&>( image_pyr(0));
00175 
00176   // Shallow copy of part of base_image
00177   im0 = vimt_crop(base_image,0,ni,0,nj);
00178 
00179   int i;
00180   for (i=1;i<max_levels;i++)
00181   {
00182     vimt_image_2d_of<T>& im_i0 = static_cast<vimt_image_2d_of<T>&>( image_pyr(i));
00183     vimt_image_2d_of<T>& im_i1 = static_cast<vimt_image_2d_of<T>&>(image_pyr(i-1));
00184 
00185     gauss_reduce(im_i1,im_i0);
00186   }
00187 
00188   // Estimate width of pixels in base image
00189   vgl_point_2d<double>  c0(0.5*(ni-1),0.5*(nj-1));
00190   vgl_point_2d<double>  c1 = c0 + vgl_vector_2d<double> (1,1);
00191   vimt_transform_2d im2world = base_image.world2im().inverse();
00192   vgl_vector_2d<double>  dw = im2world(c1) - im2world(c0);
00193 
00194   double base_pixel_width = dw.length()/vnl_math::sqrt2;
00195   double scale_step = 2.0;
00196 
00197   image_pyr.set_widths(base_pixel_width,scale_step);
00198 }
00199 
00200 //=======================================================================
00201 //: Extend pyramid
00202 // The first layer of the pyramid must already be set.
00203 template<class T>
00204 void vimt_gaussian_pyramid_builder_2d<T>::extend(vimt_image_pyramid& image_pyr) const
00205 {
00206   //  Require image vimt_image_2d_of<T>
00207   assert(image_pyr(0).is_class(work_im_.is_a()));
00208 
00209   assert(image_pyr.scale_step() == scale_step());
00210 
00211   vimt_image_2d_of<T>& im_base = static_cast<vimt_image_2d_of<T>&>( image_pyr(0));
00212   int ni = im_base.image().ni();
00213   int nj = im_base.image().nj();
00214 
00215   // Compute number of levels to pyramid so that top is no less
00216   // than 5 x 5
00217   double s = 1;
00218   int max_levels = 1;
00219   while ((ni/(scale_step()*s)>=minXSize_) && (nj/(scale_step()*s)>=minYSize_))
00220   {
00221     max_levels++;
00222     s*=scale_step();
00223   }
00224 
00225   if (max_levels>max_levels_)
00226     max_levels=max_levels_;
00227 
00228   // Set up image pyramid
00229   int oldsize = image_pyr.n_levels();
00230   if (oldsize<max_levels) // only extend, if it isn't already tall enough
00231   {
00232     image_pyr.data().resize(max_levels);
00233 
00234     int i;
00235     for (i=oldsize;i<max_levels;++i)
00236       image_pyr.data()[i] = new vimt_image_2d_of<T>;
00237 
00238     for (i=oldsize;i<max_levels;i++)
00239     {
00240       vimt_image_2d_of<T>& im_i0 = static_cast<vimt_image_2d_of<T>&>( image_pyr(i));
00241       vimt_image_2d_of<T>& im_i1 = static_cast<vimt_image_2d_of<T>&>(image_pyr(i-1));
00242 
00243       gauss_reduce(im_i1,im_i0);
00244     }
00245   }
00246 }
00247 
00248 
00249 //=======================================================================
00250 
00251 #if 0
00252 template<class T>
00253 vcl_string vimt_gaussian_pyramid_builder_2d<T>::is_a() const
00254 {
00255   return vcl_string("vimt_gaussian_pyramid_builder_2d<T>");
00256 }
00257 #endif
00258 
00259 //=======================================================================
00260 
00261 template<class T>
00262 bool vimt_gaussian_pyramid_builder_2d<T>::is_class(vcl_string const& s) const
00263 {
00264   return s==vimt_gaussian_pyramid_builder_2d<T>::is_a() || vimt_image_pyramid_builder::is_class(s);
00265 }
00266 
00267 //=======================================================================
00268 
00269 template<class T>
00270 short vimt_gaussian_pyramid_builder_2d<T>::version_no() const
00271 {
00272   return 2;
00273 }
00274 
00275 //=======================================================================
00276 
00277 template<class T>
00278 vimt_image_pyramid_builder* vimt_gaussian_pyramid_builder_2d<T>::clone() const
00279 {
00280   return new vimt_gaussian_pyramid_builder_2d<T>(*this);
00281 }
00282 
00283 //=======================================================================
00284 
00285 template<class T>
00286 void vimt_gaussian_pyramid_builder_2d<T>::print_summary(vcl_ostream&) const
00287 {
00288 }
00289 
00290 //=======================================================================
00291 
00292 template<class T>
00293 void vimt_gaussian_pyramid_builder_2d<T>::b_write(vsl_b_ostream& bfs) const
00294 {
00295   vsl_b_write(bfs,version_no());
00296   vsl_b_write(bfs,max_levels_);
00297   vsl_b_write(bfs,filter_width_);
00298 }
00299 
00300 //=======================================================================
00301 
00302 template<class T>
00303 void vimt_gaussian_pyramid_builder_2d<T>::b_read(vsl_b_istream& bfs)
00304 {
00305   if (!bfs) return;
00306 
00307   short version;
00308   vsl_b_read(bfs,version);
00309   switch (version)
00310   {
00311   // version number starts at 2 to follow on from the old mil stuff
00312   case (2):
00313     vsl_b_read(bfs,max_levels_);
00314     vsl_b_read(bfs,filter_width_);
00315     break;
00316   default:
00317     vcl_cerr << "I/O ERROR: vimt_gaussian_pyramid_builder_2d<T>::b_read(vsl_b_istream&)\n"
00318              << "           Unknown version number "<< version << '\n';
00319     bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00320     return;
00321   }
00322 }
00323 
00324 #define VIMT_GAUSSIAN_PYRAMID_BUILDER_2D_INSTANTIATE(T) \
00325 VCL_DEFINE_SPECIALIZATION vcl_string vimt_gaussian_pyramid_builder_2d<T >::is_a() const \
00326 {  return vcl_string("vimt_gaussian_pyramid_builder_2d<" #T ">"); }\
00327 template class vimt_gaussian_pyramid_builder_2d<T >
00328 
00329 #endif // vimt_gaussian_pyramid_builder_2d_txx_