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

vimt_scale_pyramid_builder_2d.txx

Go to the documentation of this file.
00001 // This is mul/vimt/vimt_scale_pyramid_builder_2d.txx
00002 #ifndef vimt_scale_pyramid_builder_2d_txx_
00003 #define vimt_scale_pyramid_builder_2d_txx_
00004 //:
00005 // \file
00006 // \brief Build Gaussian image pyramids at any scale separation
00007 // \author Ian Scott
00008 
00009 #include "vimt_scale_pyramid_builder_2d.h"
00010 #include <vcl_cstdlib.h>
00011 #include <vcl_cassert.h>
00012 #include <vcl_string.h>
00013 #include <vcl_iostream.h>
00014 #include <vil/vil_bilin_interp.h>
00015 #include <vimt/vimt_image_2d_of.h>
00016 #include <vimt/vimt_image_pyramid.h>
00017 #include <vsl/vsl_indent.h>
00018 #include <vcl_cmath.h>
00019 #include <vimt/vimt_crop.h>
00020 
00021 //=======================================================================
00022 
00023 template <class T>
00024 vimt_scale_pyramid_builder_2d<T>::vimt_scale_pyramid_builder_2d()
00025 : max_levels_(99)
00026 {
00027   set_scale_step(2.0);
00028   set_min_size(5, 5);
00029 }
00030 
00031 //: Construct with given scale_step
00032 template <class T>
00033 vimt_scale_pyramid_builder_2d<T>::vimt_scale_pyramid_builder_2d(double scale_step)
00034 {
00035   set_scale_step(scale_step);
00036 }
00037 
00038 //=======================================================================
00039 
00040 template <class T>
00041 vimt_scale_pyramid_builder_2d<T>::~vimt_scale_pyramid_builder_2d()
00042 {
00043 }
00044 
00045 template <class T>
00046 void vimt_scale_pyramid_builder_2d<T>::scale_reduce(
00047            vimt_image_2d_of<T>& dest_im,
00048            const vimt_image_2d_of<T>& src_im) const
00049 {
00050   int src_ni = src_im.image().ni();
00051   int src_nj = src_im.image().nj();
00052   int dest_ni = dest_im.image().ni();
00053   int dest_nj = dest_im.image().nj();
00054   vcl_ptrdiff_t istep = src_im.image().istep();
00055   vcl_ptrdiff_t jstep = src_im.image().jstep();
00056   int n_planes = src_im.image().nplanes();
00057 
00058   // Reduce plane-by-plane
00059 
00060   // use n-1 because we are trying to align inter-pixel spaces, so that the
00061   // centre pixel is most accurately registered despite buildup of rounding errors.
00062   double init_x = 0.5 * (src_ni - 1 - (dest_ni-1)*scale_step());
00063   double init_y = 0.5 * (src_nj - 1 - (dest_nj-1)*scale_step());
00064 
00065 
00066   for (int i=0;i<n_planes;++i)
00067     scale_reduce(&dest_im.image()(0,0,i),dest_im.image().jstep(),
00068                  &src_im.image()(0,0,i),src_ni,src_nj,dest_ni,dest_nj,istep,jstep);
00069 #if 0
00070   vsl_indent_inc(vcl_cout);
00071   vcl_cout << vsl_indent() << "Work image B\n";
00072   workb_.print_all(vcl_cout);
00073   vsl_indent_dec(vcl_cout);
00074 #endif
00075 
00076     // Sort out world to image transformation for destination image
00077   vimt_transform_2d scaling;
00078   scaling.set_zoom_only(1/scale_step(),-init_x,-init_y);
00079   dest_im.set_world2im(scaling * src_im.world2im());
00080 }
00081 
00082 
00083 //: An optimisable rounding function
00084 inline unsigned char l_round(double x, unsigned char )
00085 {  return (unsigned char) (x+0.5);}
00086 
00087 inline signed char l_round(double x, signed char )
00088 {  return (signed char) (x+0.5);}
00089 
00090 inline unsigned short l_round(double x, unsigned short )
00091 {  return (unsigned short) (x+0.5);}
00092 
00093 inline signed short l_round(double x, signed short )
00094 {  return (signed short) (x+0.5);}
00095 
00096 inline unsigned int l_round(double x, unsigned int )
00097 {  return (unsigned int) (x+0.5);}
00098 
00099 inline signed int l_round(double x, signed int )
00100 {  return (signed int) (x+0.5);}
00101 
00102 inline unsigned long l_round(double x, unsigned long )
00103 {  return (unsigned long) (x+0.5);}
00104 
00105 inline signed long l_round(double x, signed long )
00106 {  return (signed long) (x+0.5);}
00107 
00108 inline double l_round (double x, double )
00109 {  return x; }
00110 
00111 inline float l_round (double x, float )
00112 {  return (float) x; }
00113 
00114 //=======================================================================
00115 //: Smooth and subsample src_im to produce dest_im
00116 //  Applies 5 pin filter in x and y, then samples
00117 //  every other pixel.
00118 //  Assumes dest_im has sufficient data allocated
00119 
00120 template <class T>
00121 void vimt_scale_pyramid_builder_2d<T>::scale_reduce(
00122            T* dest_im, vcl_ptrdiff_t dest_jstep,
00123            const T* src_im,
00124            int src_ni, int src_nj, int dest_ni, int dest_nj,
00125            vcl_ptrdiff_t src_istep, vcl_ptrdiff_t src_jstep) const
00126 {
00127   T* dest_row = dest_im;
00128 
00129   const double init_x = 0.5 * (src_ni-1 - (dest_ni-1)*scale_step());
00130   double y = 0.5 * (src_nj -1 - (dest_nj-1)*scale_step());
00131   for (int yi=0; yi<dest_nj; yi++)
00132   {
00133     double x=init_x;
00134     for (int xi=0; xi<dest_ni; xi++)
00135     {
00136       dest_row[xi] = l_round (vil_bilin_interp_safe_extend(x, y,
00137                               src_im, src_ni, src_nj, src_istep, src_jstep), (T)0);
00138       x += scale_step_;
00139     }
00140     y+= scale_step_;
00141     dest_row += dest_jstep;
00142   }
00143 }
00144 
00145 
00146 //: Set the Scale step
00147 template <class T>
00148 void vimt_scale_pyramid_builder_2d<T>::set_scale_step(double scaleStep)
00149 {
00150   assert(scaleStep> 1.0  && scaleStep<=2.0);
00151   scale_step_ = scaleStep;
00152 }
00153 
00154 
00155 //=======================================================================
00156 //: Deletes all data in im_pyr
00157 template<class T>
00158 void vimt_scale_pyramid_builder_2d<T>::emptyPyr(vimt_image_pyramid& im_pyr) const
00159 {
00160   for (int i=0; i<im_pyr.n_levels();++i)
00161     delete im_pyr.data()[i];
00162 }
00163 
00164 //=======================================================================
00165 //: Checks pyramid has at least n levels
00166 template<class T>
00167 void vimt_scale_pyramid_builder_2d<T>::checkPyr(vimt_image_pyramid& im_pyr,  int n_levels) const
00168 {
00169   const int got_levels = im_pyr.n_levels();
00170   if (got_levels >= n_levels) //&& im_pyr(0).is_a()==work_im_.is_a())
00171   {
00172     if (im_pyr.n_levels()==n_levels) return;
00173     else
00174     {
00175       for (int i=n_levels;i<got_levels;++i)
00176         delete im_pyr.data()[i];
00177     }
00178     im_pyr.data().resize(n_levels);
00179     return;
00180   }
00181 
00182   im_pyr.data().resize(n_levels);
00183   emptyPyr(im_pyr);
00184 
00185   for (int i=0;i<n_levels;++i)
00186     im_pyr.data()[i] = new vimt_image_2d_of<T>;
00187 }
00188 
00189 //=======================================================================
00190 
00191 template <class T>
00192 void vimt_scale_pyramid_builder_2d<T>::build(
00193                   vimt_image_pyramid& im_pyr,
00194                   const vimt_image& im) const
00195 {
00196   const vimt_image_2d_of<T>& base_image = static_cast<const vimt_image_2d_of<T>&>( im);
00197 
00198   int ni = base_image.image().ni();
00199   int nj = base_image.image().nj();
00200 
00201   // Compute number of levels to pyramid so that top is no less
00202   // than miniSize_ x minjSize_
00203   double s = scale_step();
00204   int max_lev = 1;
00205   while ( ((unsigned int)(ni/s+0.5)>=min_x_size_)
00206           &&
00207           ((unsigned int)(nj/s+0.5)>=min_y_size_)
00208         )
00209   {
00210     max_lev++;
00211     s *= scale_step();
00212   }
00213 
00214   if (max_lev>max_levels())
00215     max_lev=max_levels();
00216 
00217 
00218   // Set up image pyramid
00219   checkPyr(im_pyr,max_lev);
00220 
00221   vimt_image_2d_of<T>& im0 = static_cast<vimt_image_2d_of<T>&>(im_pyr(0));
00222 
00223   // Shallow copy of part of base_image
00224   im0 = vimt_crop(base_image,0,ni,0,nj);
00225 
00226   s = scale_step();
00227   for (int i=1;i<max_lev;i++)
00228   {
00229     vimt_image_2d_of<T>& im_i0 = static_cast<vimt_image_2d_of<T>&>(im_pyr(i));
00230     vimt_image_2d_of<T>& im_i1 = static_cast<vimt_image_2d_of<T>&>(im_pyr(i-1));
00231     im_i0.image().set_size((int) (ni/s+0.5), (int) (nj/s+0.5),im_i1.image().nplanes());
00232 
00233     s*=scale_step();
00234     scale_reduce(im_i0,im_i1);
00235   }
00236 
00237   // Estimate width of pixels in base image
00238   vgl_point_2d<double>  c0(0.5*(ni-1),0.5*(nj-1));
00239   vgl_point_2d<double>  c1 = c0 + vgl_vector_2d<double> (1,1);
00240   vimt_transform_2d im2world = base_image.world2im().inverse();
00241   vgl_vector_2d<double>  dw = im2world(c1) - im2world(c0);
00242 
00243   double base_pixel_width = vcl_sqrt(0.5*(dw.x()*dw.x() + dw.y()*dw.y()));
00244 
00245   im_pyr.set_widths(base_pixel_width,scale_step());
00246 }
00247 
00248 
00249 //=======================================================================
00250 //: Extend pyramid
00251 // The first layer of the pyramid must already be set.
00252 template<class T>
00253 void vimt_scale_pyramid_builder_2d<T>::extend(vimt_image_pyramid& image_pyr) const
00254 {
00255   assert(image_pyr.scale_step() == scale_step());
00256 
00257   const int ni = static_cast<const vimt_image_2d&>(image_pyr(0)).image_base().ni();
00258   const int nj = static_cast<const vimt_image_2d&>(image_pyr(0)).image_base().nj();
00259 
00260   // Compute number of levels to pyramid so that top is no less
00261   // than 5 x 5
00262   double s = scale_step();
00263   int max_lev = 1;
00264   while (((unsigned int)(ni/s+0.5)>=min_x_size_) &&
00265          ((unsigned int)(nj/s+0.5)>=min_y_size_))
00266   {
00267      max_lev++;
00268      s*=scale_step();
00269   }
00270 
00271   if (max_lev>max_levels())
00272       max_lev=max_levels();
00273 
00274   // Set up image pyramid
00275   int oldsize = image_pyr.n_levels();
00276   if (oldsize<max_lev) // only extend, if it isn't already tall enough
00277   {
00278     image_pyr.data().resize(max_lev);
00279 
00280     s = vcl_pow(scale_step(), oldsize);
00281     for (int i=oldsize;i<max_lev;i++)
00282     {
00283       image_pyr.data()[i] = new vimt_image_2d_of<T>;
00284       vimt_image_2d_of<T>& im_i0 = static_cast<vimt_image_2d_of<T>&>(image_pyr(i));
00285       vimt_image_2d_of<T>& im_i1 = static_cast<vimt_image_2d_of<T>&>(image_pyr(i-1));
00286       im_i0.image().set_size((int)(ni/s+0.5),(int)(nj/s+0.5),im_i1.image().nplanes());
00287 
00288       s*=scale_step();
00289       scale_reduce(im_i0,im_i1);
00290     }
00291   }
00292 }
00293 
00294 //=======================================================================
00295 //: Define maximum number of levels to build
00296 //  Limits levels built in subsequent calls to build()
00297 template<class T>
00298 void vimt_scale_pyramid_builder_2d<T>::set_max_levels(int max_l)
00299 {
00300   if (max_l<1)
00301   {
00302     vcl_cerr << "vimt_gaussian_pyramid_builder_2d<T>::set_max_levels() "
00303              << "Must be >=1, not " << max_l << '\n';
00304     vcl_abort();
00305   }
00306   max_levels_ = max_l;
00307 }
00308 
00309 //: Get the current maximum number levels allowed
00310 template<class T>
00311 int vimt_scale_pyramid_builder_2d<T>::max_levels() const
00312 {
00313   return max_levels_;
00314 }
00315 
00316 
00317 //=======================================================================
00318 //: Create new (empty) pyramid on heap
00319 //  Caller responsible for its deletion
00320 template<class T>
00321 vimt_image_pyramid* vimt_scale_pyramid_builder_2d<T>::new_image_pyramid() const
00322 {
00323   return new vimt_image_pyramid;
00324 }
00325 
00326 
00327 //=======================================================================
00328 #if 0
00329 template <class T>
00330 vcl_string vimt_scale_pyramid_builder_2d<T>::is_a() const
00331 {
00332   return vcl_string("vimt_scale_pyramid_builder_2d<T>");
00333 }
00334 #endif
00335 
00336 //=======================================================================
00337 
00338 template <class T>
00339 bool vimt_scale_pyramid_builder_2d<T>::is_class(vcl_string const& s) const
00340 {
00341   return s==vimt_scale_pyramid_builder_2d<T>::is_a() || vimt_scale_pyramid_builder_2d<T>::is_class(s);
00342 }
00343 
00344 //=======================================================================
00345 
00346 template <class T>
00347 short vimt_scale_pyramid_builder_2d<T>::version_no() const
00348 {
00349   return 1;
00350 }
00351 
00352 //=======================================================================
00353 
00354 template <class T>
00355 vimt_image_pyramid_builder* vimt_scale_pyramid_builder_2d<T>::clone() const
00356 {
00357   return new vimt_scale_pyramid_builder_2d(*this);
00358 }
00359 
00360 //=======================================================================
00361 
00362 template <class T>
00363 void vimt_scale_pyramid_builder_2d<T>::print_summary(vcl_ostream& /*os*/) const
00364 {
00365   vcl_cerr << "vimt_scale_pyramid_builder_2d<T>::print_summary() NYI\n";
00366 }
00367 
00368 //=======================================================================
00369 
00370 template <class T>
00371 void vimt_scale_pyramid_builder_2d<T>::b_write(vsl_b_ostream& bfs) const
00372 {
00373   vsl_b_write(bfs,version_no());
00374   vsl_b_write(bfs,scale_step());
00375 }
00376 
00377 //=======================================================================
00378 
00379 template <class T>
00380 void vimt_scale_pyramid_builder_2d<T>::b_read(vsl_b_istream& bfs)
00381 {
00382   if (!bfs) return;
00383 
00384   short version;
00385   vsl_b_read(bfs,version);
00386   double scale;
00387 
00388   switch (version)
00389   {
00390   case (1):
00391     vsl_b_read(bfs,scale);
00392     set_scale_step(scale);
00393     break;
00394   default:
00395     vcl_cerr << "I/O ERROR: vimt_scale_pyramid_builder_2d<T>::b_read(vsl_b_istream&)\n"
00396              << "           Unknown version number "<< version << "\n";
00397     bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00398     return;
00399   }
00400 }
00401 
00402 #define VIMT_SCALE_PYRAMID_BUILDER_2D_INSTANTIATE(T) \
00403 VCL_DEFINE_SPECIALIZATION vcl_string vimt_scale_pyramid_builder_2d<T >::is_a() const \
00404 {  return vcl_string("vimt_scale_pyramid_builder_2d<" #T ">"); }\
00405 template class vimt_scale_pyramid_builder_2d<T >
00406 
00407 #endif // vimt_scale_pyramid_builder_2d_txx_

Generated on Thu Jan 10 14:43:58 2008 for contrib/mul/vimt by  doxygen 1.4.4