contrib/mul/vimt/vimt_gaussian_pyramid_builder_2d_general.txx
Go to the documentation of this file.
00001 // This is mul/vimt/vimt_gaussian_pyramid_builder_2d_general.txx
00002 #ifndef vimt_gaussian_pyramid_builder_2d_general_txx_
00003 #define vimt_gaussian_pyramid_builder_2d_general_txx_
00004 //:
00005 // \file
00006 // \brief Build gaussian image pyramids at any scale separation
00007 // \author Ian Scott
00008 
00009 #include "vimt_gaussian_pyramid_builder_2d_general.h"
00010 #include <vcl_cmath.h>
00011 #include <vcl_cassert.h>
00012 #include <vcl_string.h>
00013 #include <vcl_iostream.h>
00014 #include <vil/algo/vil_gauss_reduce.h>
00015 #include <vgl/vgl_point_2d.h>
00016 #include <vgl/vgl_vector_2d.h>
00017 #include <vimt/vimt_image_pyramid.h>
00018 #include <vimt/vimt_crop.h>
00019 
00020 //=======================================================================
00021 
00022 template <class T>
00023 vimt_gaussian_pyramid_builder_2d_general<T>::vimt_gaussian_pyramid_builder_2d_general():
00024   scale_params_(2.0)
00025 {}
00026 
00027 //: Construct with given scale_step
00028 template <class T>
00029 vimt_gaussian_pyramid_builder_2d_general<T>::vimt_gaussian_pyramid_builder_2d_general(double scale_step):
00030   scale_params_(scale_step)
00031 {}
00032 
00033 //=======================================================================
00034 
00035 template <class T>
00036 vimt_gaussian_pyramid_builder_2d_general<T>::~vimt_gaussian_pyramid_builder_2d_general()
00037 {}
00038 
00039 //: Set the Scale step
00040 template <class T>
00041 void vimt_gaussian_pyramid_builder_2d_general<T>::set_scale_step(double scaleStep)
00042 {
00043   scale_params_ = vil_gauss_reduce_params(scaleStep);
00044 }
00045 
00046 //=======================================================================
00047 
00048 template <class T>
00049 void vimt_gaussian_pyramid_builder_2d_general<T>::build(
00050                   vimt_image_pyramid& im_pyr,
00051                   const vimt_image& im) const
00052 {
00053   assert(im.is_class(vimt_image_2d_of<T>().is_a()));
00054 
00055   const vimt_image_2d_of<T>& base_image = static_cast<const vimt_image_2d_of<T>&>(im);
00056 
00057   int ni = base_image.image().ni();
00058   int nj = base_image.image().nj();
00059 
00060   // Compute number of levels to pyramid so that top is no less
00061   // than minXSize_ x minYSize_
00062   double s = scale_step();
00063   int maxlevels = 1;
00064   while (((unsigned int)(ni/s+0.5)>=this->min_x_size()) &&
00065          ((unsigned int)(nj/s+0.5)>=this->min_y_size()))
00066   {
00067     maxlevels++;
00068     s *= scale_step();
00069   }
00070 
00071   if (maxlevels > this->max_levels())
00072     maxlevels=this->max_levels();
00073 
00074   worka_.set_size(ni,nj);
00075   workb_.set_size(ni,nj);
00076 
00077   // Set up image pyramid
00078   this->check_pyr(im_pyr,maxlevels);
00079 
00080   vimt_image_2d_of<T>& im0 = static_cast<vimt_image_2d_of<T>&>(im_pyr(0));
00081 
00082   // Shallow copy of part of base_image
00083   im0 = vimt_crop(base_image,0,ni,0,nj);
00084 
00085   s = scale_step();
00086   for (int i=1;i<maxlevels;i++)
00087   {
00088     vimt_image_2d_of<T>& dest = static_cast<vimt_image_2d_of<T>&>(im_pyr(i));
00089     const vimt_image_2d_of<T>& src = static_cast<const vimt_image_2d_of<T>&>(im_pyr(i-1));
00090 
00091     s*=scale_step();
00092     vil_gauss_reduce_general(src.image(), dest.image(), worka_, workb_, scale_params_);
00093 
00094     // Sort out world to image transformation for destination image
00095     vimt_transform_2d scaling;
00096 
00097     // use n-1 because we are trying to align inter-pixel spaces, so that the
00098     // centre pixel is most accurately registered despite buildup of rounding errors.
00099     const double init_x = 0.5 * (src.image().ni() - 1 - (dest.image().ni()-1)*scale_params_.scale_step());
00100     const double init_y = 0.5 * (src.image().nj() - 1 - (dest.image().nj()-1)*scale_params_.scale_step());
00101 
00102     scaling.set_zoom_only(1/scale_params_.scale_step(),-init_x,-init_y);
00103     dest.set_world2im(scaling * src.world2im());
00104   }
00105 
00106   // Estimate width of pixels in base image
00107   vgl_point_2d<double>  c0(0.5*(ni-1),0.5*(nj-1));
00108   vgl_point_2d<double>  c1 = c0 + vgl_vector_2d<double> (1,1);
00109   vimt_transform_2d im2world = base_image.world2im().inverse();
00110   vgl_vector_2d<double>  dw = im2world(c1) - im2world(c0);
00111 
00112   double base_pixel_width = vcl_sqrt(0.5*(dw.x()*dw.x() + dw.y()*dw.y()));
00113 
00114   im_pyr.set_widths(base_pixel_width,scale_step());
00115 }
00116 
00117 
00118 //=======================================================================
00119 //: Extend pyramid
00120 // The first layer of the pyramid must already be set.
00121 template<class T>
00122 void vimt_gaussian_pyramid_builder_2d_general<T>::extend(vimt_image_pyramid& image_pyr) const
00123 {
00124   //  Require image vil_image_view<T>
00125   assert(image_pyr(0).is_class(vimt_image_2d_of<T>().is_a()));
00126 
00127   assert(image_pyr.scale_step() == scale_step());
00128 
00129   const vimt_image_2d_of<T>& base_image = static_cast<const vimt_image_2d_of<T>&>(image_pyr(0));
00130 
00131 
00132   const int ni = base_image.image().ni();
00133   const int nj = base_image.image().nj();
00134 
00135   // Compute number of levels to pyramid so that top is no less
00136   // than 5 x 5
00137   double s = scale_step();
00138   int maxlevels = 1;
00139   while (((unsigned int)(ni/s+0.5) >= this->min_x_size()) &&
00140          ((unsigned int)(nj/s+0.5) >= this->min_y_size()))
00141   {
00142      maxlevels++;
00143      s*=scale_step();
00144   }
00145 
00146   if (maxlevels > this->max_levels())
00147     maxlevels=this->max_levels();
00148 
00149   worka_.set_size(ni,nj);
00150   workb_.set_size(ni,nj);
00151 
00152   // Set up image pyramid
00153   int oldsize = image_pyr.n_levels();
00154   if (oldsize<maxlevels) // only extend, if it isn't already tall enough
00155   {
00156     image_pyr.data().resize(maxlevels);
00157 
00158     s = vcl_pow(scale_step(), oldsize);
00159     for (int i=oldsize;i<maxlevels;i++)
00160     {
00161       image_pyr.data()[i] = new vimt_image_2d_of<T>;
00162       vimt_image_2d_of<T>& im_i0 = static_cast<vimt_image_2d_of<T>&>(image_pyr(i));
00163       vimt_image_2d_of<T>& im_i1 = static_cast<vimt_image_2d_of<T>&>(image_pyr(i-1));
00164       im_i0.image().set_size((unsigned)(ni/s+0.5),(unsigned)(nj/s+0.5),
00165         im_i1.image().nplanes());
00166 
00167       s*=scale_step();
00168       vil_gauss_reduce_general(im_i1.image(), im_i0.image(), worka_, workb_, scale_params_);
00169     }
00170   }
00171 }
00172 
00173 
00174 //=======================================================================
00175 #if 0
00176 template <class T>
00177 vcl_string vimt_gaussian_pyramid_builder_2d_general<T>::is_a() const
00178 {
00179   return vcl_string("vimt_gaussian_pyramid_builder_2d_general<T>");
00180 }
00181 #endif // 0
00182 //=======================================================================
00183 
00184 template <class T>
00185 bool vimt_gaussian_pyramid_builder_2d_general<T>::is_class(vcl_string const& s) const
00186 {
00187   return s==vimt_gaussian_pyramid_builder_2d_general<T>::is_a() ||
00188          vimt_gaussian_pyramid_builder_2d<T>::is_class(s);
00189 }
00190 
00191 //=======================================================================
00192 
00193 template <class T>
00194 short vimt_gaussian_pyramid_builder_2d_general<T>::version_no() const
00195 {
00196   return 1;
00197 }
00198 
00199 //=======================================================================
00200 
00201 template <class T>
00202 vimt_image_pyramid_builder* vimt_gaussian_pyramid_builder_2d_general<T>::clone() const
00203 {
00204   return new vimt_gaussian_pyramid_builder_2d_general(*this);
00205 }
00206 
00207 //=======================================================================
00208 
00209 template <class T>
00210 void vimt_gaussian_pyramid_builder_2d_general<T>::print_summary(vcl_ostream& os) const
00211 {
00212   vimt_gaussian_pyramid_builder_2d<T>::print_summary(os);
00213 }
00214 
00215 //=======================================================================
00216 
00217 template <class T>
00218 void vimt_gaussian_pyramid_builder_2d_general<T>::b_write(vsl_b_ostream& bfs) const
00219 {
00220   vsl_b_write(bfs,version_no());
00221   vimt_gaussian_pyramid_builder_2d<T>::b_write(bfs);
00222   vsl_b_write(bfs,scale_step());
00223 }
00224 
00225 //=======================================================================
00226 
00227 template <class T>
00228 void vimt_gaussian_pyramid_builder_2d_general<T>::b_read(vsl_b_istream& bfs)
00229 {
00230   if (!bfs) return;
00231 
00232   short version;
00233   vsl_b_read(bfs,version);
00234   double scale;
00235 
00236   switch (version)
00237   {
00238    case 1:
00239     vimt_gaussian_pyramid_builder_2d<T>::b_read(bfs);
00240 
00241     vsl_b_read(bfs,scale);
00242     set_scale_step(scale);
00243     break;
00244    default:
00245     vcl_cerr << "I/O ERROR: vimt_gaussian_pyramid_builder_2d_general<T>::b_read(vsl_b_istream&)\n"
00246              << "           Unknown version number "<< version << '\n';
00247     bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00248     return;
00249   }
00250 }
00251 
00252 #define VIMT_GAUSSIAN_PYRAMID_BUILDER_2D_GENERAL_INSTANTIATE(T) \
00253 VCL_DEFINE_SPECIALIZATION vcl_string vimt_gaussian_pyramid_builder_2d_general<T >::is_a() const \
00254 {  return vcl_string("vimt_gaussian_pyramid_builder_2d_general<" #T ">"); }\
00255 template class vimt_gaussian_pyramid_builder_2d_general<T >
00256 
00257 
00258 #endif // vimt_gaussian_pyramid_builder_2d_general_txx_