contrib/mul/vimt/vimt_dog_pyramid_builder_2d.txx
Go to the documentation of this file.
00001 // This is mul/vimt/vimt_dog_pyramid_builder_2d.txx
00002 #ifndef vimt_dog_pyramid_builder_2d_txx_
00003 #define vimt_dog_pyramid_builder_2d_txx_
00004 //:
00005 // \file
00006 // \brief Build difference of gaussian pyramids of vimt_image_2d_of<T>
00007 // \author Tim Cootes
00008 
00009 #include "vimt_dog_pyramid_builder_2d.h"
00010 #include "vimt_image_pyramid.h"
00011 
00012 #include <vcl_cstdlib.h>
00013 #include <vcl_string.h>
00014 
00015 #include <vcl_cassert.h>
00016 #include <vnl/vnl_math.h> // for sqrt2
00017 #include <vgl/vgl_point_2d.h>
00018 #include <vgl/vgl_vector_2d.h>
00019 #include <vil/algo/vil_gauss_filter.h>
00020 #include <vil/vil_resample_bilin.h>
00021 #include <vil/vil_math.h>
00022 
00023 //=======================================================================
00024 
00025 template<class T>
00026 vimt_dog_pyramid_builder_2d<T>::vimt_dog_pyramid_builder_2d()
00027 : max_levels_(99)
00028 {
00029   set_min_size(5, 5);
00030 }
00031 
00032 //=======================================================================
00033 
00034 template<class T>
00035 vimt_dog_pyramid_builder_2d<T>::~vimt_dog_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_dog_pyramid_builder_2d<T>::set_max_levels(int max_l)
00044 {
00045   if (max_l<1)
00046   {
00047     vcl_cerr<<"vimt_dog_pyramid_builder_2d<T>::set_max_levels() argument must be >=1\n";
00048     vcl_abort();
00049   }
00050   max_levels_ = max_l;
00051 }
00052 
00053 //: Get the current maximum number levels allowed
00054 template<class T>
00055 int vimt_dog_pyramid_builder_2d<T>::max_levels() const
00056 {
00057   return max_levels_;
00058 }
00059 
00060 //=======================================================================
00061 //: Create new (empty) pyramid on heap
00062 //  Caller responsible for its deletion
00063 template<class T>
00064 vimt_image_pyramid* vimt_dog_pyramid_builder_2d<T>::new_image_pyramid() const
00065 {
00066   return new vimt_image_pyramid;
00067 }
00068 
00069 //=======================================================================
00070 //: Scale step between levels
00071 template<class T>
00072 double vimt_dog_pyramid_builder_2d<T>::scale_step() const
00073 {
00074   return 1.5;
00075 }
00076 
00077 
00078 //=======================================================================
00079 //: Deletes all data in im_pyr
00080 template<class T>
00081 void vimt_dog_pyramid_builder_2d<T>::empty_pyr(vimt_image_pyramid& im_pyr) const
00082 {
00083   for (int i=0; i<im_pyr.n_levels();++i)
00084     delete im_pyr.data()[i];
00085 }
00086 
00087 //=======================================================================
00088 //: Checks pyramid has at least n levels
00089 template<class T>
00090 void vimt_dog_pyramid_builder_2d<T>::check_pyr(vimt_image_pyramid& im_pyr,  int n_levels) const
00091 {
00092   const int got_levels = im_pyr.n_levels();
00093   if (got_levels >= n_levels && im_pyr(0).is_class(work_im_.is_a()))
00094   {
00095     if (im_pyr.n_levels()==n_levels) return;
00096     else
00097     {
00098       for (int i=n_levels;i<got_levels;++i)
00099         delete im_pyr.data()[i];
00100     }
00101     im_pyr.data().resize(n_levels);
00102     return;
00103   }
00104 
00105   im_pyr.data().resize(n_levels);
00106   empty_pyr(im_pyr);
00107 
00108   for (int i=0;i<n_levels;++i)
00109     im_pyr.data()[i] = new vimt_image_2d_of<T>;
00110 }
00111 
00112 //: Build pyramid
00113 template<class T>
00114 void vimt_dog_pyramid_builder_2d<T>::build(vimt_image_pyramid& dog_pyr,
00115                                            const vimt_image& im) const
00116 {
00117   vimt_image_pyramid smooth_pyr;
00118   build_dog(dog_pyr,smooth_pyr,im);
00119 }
00120 
00121 //=======================================================================
00122 //: Build pyramid
00123 template<class T>
00124 void vimt_dog_pyramid_builder_2d<T>::build_dog(vimt_image_pyramid& dog_pyr,
00125                                                vimt_image_pyramid& smooth_pyr,
00126                                                const vimt_image& im, bool abs_diff) const
00127 {
00128   //  Require image vimt_image_2d_of<T>
00129   assert(im.is_class(work_im_.is_a()));
00130 
00131   const vimt_image_2d_of<T>& base_image = static_cast<const vimt_image_2d_of<T>&>(im);
00132 
00133   unsigned ni = base_image.image().ni();
00134   unsigned nj = base_image.image().nj();
00135 
00136   // Compute number of levels to pyramid so that top is no less
00137   // than min_x_size_ x min_y_size_
00138   int max_levels = 1;
00139   while (ni>min_x_size_ && nj>min_y_size_)
00140   {
00141     max_levels++;
00142     ni = 2*ni/3;
00143     nj = 2*nj/3;
00144   }
00145 
00146   if (max_levels>max_levels_)
00147     max_levels=max_levels_;
00148 
00149   // Set up image pyramid
00150   check_pyr(dog_pyr,max_levels);
00151   check_pyr(smooth_pyr,max_levels);
00152 
00153   vimt_image_2d_of<T>& smooth0 = static_cast<vimt_image_2d_of<T>&>( smooth_pyr(0));
00154   vimt_image_2d_of<T>& dog0 = static_cast<vimt_image_2d_of<T>&>( dog_pyr(0));
00155 
00156   vil_gauss_filter_5tap_params smooth_params(0.75);
00157 
00158   vil_gauss_filter_5tap(base_image.image(),smooth0.image(),smooth_params,
00159                         dog0.image());  // Workspace
00160 
00161   if (abs_diff)
00162     vil_math_image_abs_difference(base_image.image(),smooth0.image(),dog0.image());
00163   else
00164     vil_math_image_difference(base_image.image(),smooth0.image(),dog0.image());
00165 
00166   smooth0.set_world2im(base_image.world2im());
00167   dog0.set_world2im(base_image.world2im());
00168 
00169   unsigned n_planes = base_image.image().nplanes();
00170 
00171   // Sort out world to image transformation for destination image
00172   vimt_transform_2d scaling_trans;
00173   scaling_trans.set_zoom_only(2.0/3.0,0,0);
00174 
00175   // Workspace
00176   vil_image_view<T> sub_sampled_image;
00177 
00178 
00179   // Subsequent levels
00180   for (int i=1;i<max_levels;++i)
00181   {
00182     vimt_image_2d_of<T>& smooth0 = static_cast<vimt_image_2d_of<T>&>( smooth_pyr(i-1));
00183     vimt_image_2d_of<T>& smooth1 = static_cast<vimt_image_2d_of<T>&>( smooth_pyr(i));
00184     vimt_image_2d_of<T>& dog1 = static_cast<vimt_image_2d_of<T>&>( dog_pyr(i));
00185 
00186     // Subsample by a factor of 2/3
00187     // Note - this could be implemented more efficiently
00188     //        since bilinear is sampling at pixel positions
00189     //        and on edges.
00190     unsigned ni = smooth0.image().ni();
00191     unsigned nj = smooth0.image().nj();
00192     ni = 2*ni/3;
00193     nj = 2*nj/3;
00194     sub_sampled_image.set_size(ni,nj,n_planes);
00195 
00196     vil_resample_bilin(smooth0.image(),sub_sampled_image,
00197                        0.0,0.0, 1.5,0.0,  0.0,1.5, ni,nj);
00198 
00199     vil_gauss_filter_5tap(sub_sampled_image,smooth1.image(),
00200                           smooth_params,
00201                           dog1.image());  // Workspace
00202     if (abs_diff)
00203       vil_math_image_abs_difference(sub_sampled_image,smooth1.image(),
00204                                     dog1.image());
00205     else
00206       vil_math_image_difference(sub_sampled_image,smooth1.image(),
00207                                 dog1.image());
00208 
00209     smooth1.set_world2im(scaling_trans*smooth0.world2im());
00210     dog1.set_world2im(smooth1.world2im());
00211   }
00212 
00213   // Estimate width of pixels in base image
00214   vgl_point_2d<double>  c0(0.5*(ni-1),0.5*(nj-1));
00215   vgl_point_2d<double>  c1 = c0 + vgl_vector_2d<double> (1,1);
00216   vimt_transform_2d im2world = base_image.world2im().inverse();
00217   vgl_vector_2d<double>  dw = im2world(c1) - im2world(c0);
00218 
00219   double base_pixel_width = dw.length()/vnl_math::sqrt2;
00220   double scale_step = 1.5;
00221 
00222   dog_pyr.set_widths(base_pixel_width,scale_step);
00223   smooth_pyr.set_widths(base_pixel_width,scale_step);
00224 }
00225 
00226 //=======================================================================
00227 //: Extend pyramid (not implemented)
00228 template<class T>
00229 void vimt_dog_pyramid_builder_2d<T>::extend(vimt_image_pyramid& ) const
00230 {
00231   vcl_cerr << "vimt_dog_pyramid_builder_2d<T>::extend(vimt_image_pyramid&) NYI\n";
00232 }
00233 
00234 
00235 //=======================================================================
00236 
00237 template<class T>
00238 bool vimt_dog_pyramid_builder_2d<T>::is_class(vcl_string const& s) const
00239 {
00240   return s==vimt_dog_pyramid_builder_2d<T>::is_a() || vimt_image_pyramid_builder::is_class(s);
00241 }
00242 
00243 //=======================================================================
00244 
00245 template<class T>
00246 short vimt_dog_pyramid_builder_2d<T>::version_no() const
00247 {
00248   return 1;
00249 }
00250 
00251 //=======================================================================
00252 
00253 template<class T>
00254 vimt_image_pyramid_builder* vimt_dog_pyramid_builder_2d<T>::clone() const
00255 {
00256   return new vimt_dog_pyramid_builder_2d<T>(*this);
00257 }
00258 
00259 //=======================================================================
00260 
00261 template<class T>
00262 void vimt_dog_pyramid_builder_2d<T>::print_summary(vcl_ostream&) const
00263 {
00264 }
00265 
00266 //=======================================================================
00267 
00268 template<class T>
00269 void vimt_dog_pyramid_builder_2d<T>::b_write(vsl_b_ostream& bfs) const
00270 {
00271   vsl_b_write(bfs,version_no());
00272   vsl_b_write(bfs,max_levels_);
00273   vsl_b_write(bfs,min_x_size_);
00274   vsl_b_write(bfs,min_y_size_);
00275 }
00276 
00277 //=======================================================================
00278 
00279 template<class T>
00280 void vimt_dog_pyramid_builder_2d<T>::b_read(vsl_b_istream& bfs)
00281 {
00282   if (!bfs) return;
00283 
00284   short version;
00285   vsl_b_read(bfs,version);
00286   switch (version)
00287   {
00288    // version number starts at 2 to follow on from the old mil stuff
00289    case (1):
00290     vsl_b_read(bfs,max_levels_);
00291     vsl_b_read(bfs,min_x_size_);
00292     vsl_b_read(bfs,min_y_size_);
00293     break;
00294    default:
00295     vcl_cerr << "I/O ERROR: vimt_dog_pyramid_builder_2d<T>::b_read(vsl_b_istream&)\n"
00296              << "           Unknown version number "<< version << '\n';
00297     bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00298     return;
00299   }
00300 }
00301 
00302 template<class T>
00303 void vimt_dog_pyramid_builder_2d<T>::gauss_reduce(const vimt_image_2d_of<T>& /*src_im*/,
00304                                                   vimt_image_2d_of<T>& /*dest_im*/) const
00305 {
00306   vcl_cerr << "ERROR: vimt_dog_pyramid_builder_2d<T>::gauss_reduce() not yet implemented\n";
00307 }
00308 
00309 #define VIMT_DOG_PYRAMID_BUILDER_2D_INSTANTIATE(T) \
00310 VCL_DEFINE_SPECIALIZATION vcl_string vimt_dog_pyramid_builder_2d<T >::is_a() const \
00311 {  return vcl_string("vimt_dog_pyramid_builder_2d<" #T ">"); }\
00312 template class vimt_dog_pyramid_builder_2d<T >
00313 
00314 #endif // vimt_dog_pyramid_builder_2d_txx_