contrib/mul/mfpf/mfpf_mr_point_finder_builder.cxx
Go to the documentation of this file.
00001 #include "mfpf_mr_point_finder_builder.h"
00002 //:
00003 // \file
00004 // \author Tim Cootes
00005 // \brief Builder for mfpf_mr_point_finder objects.
00006 
00007 #include <mfpf/mfpf_mr_point_finder.h>
00008 
00009 #include <vimt/vimt_image_pyramid.h>
00010 #include <vnl/vnl_math.h>
00011 #include <vgl/vgl_point_2d.h>
00012 #include <vgl/vgl_vector_2d.h>
00013 #include <vcl_cmath.h>
00014 #include <vcl_algorithm.h>
00015 #include <vcl_cassert.h>
00016 #include <vcl_cstdlib.h>
00017 
00018 #include <vsl/vsl_indent.h>
00019 #include <vsl/vsl_binary_loader.h>
00020 #include <vsl/vsl_vector_io.h>
00021 
00022 //=======================================================================
00023 // Constructors
00024 //=======================================================================
00025 
00026 mfpf_mr_point_finder_builder::mfpf_mr_point_finder_builder()
00027 {
00028 }
00029 
00030 //: Copy ctor
00031 mfpf_mr_point_finder_builder::mfpf_mr_point_finder_builder(const mfpf_mr_point_finder_builder& b)
00032 {
00033  *this=b;
00034 }
00035 
00036 //: Copy operator
00037 mfpf_mr_point_finder_builder& mfpf_mr_point_finder_builder::operator=(const mfpf_mr_point_finder_builder& b)
00038 {
00039   if (&b==this) return *this;
00040 
00041   delete_all();
00042 
00043   // Take clones of all builders.
00044   unsigned n=b.size();
00045   builders_.resize(n);
00046   for (unsigned i=0;i<n;++i) builders_[i]=b.builders_[i]->clone();
00047 
00048   return *this;
00049 }
00050 
00051 //=======================================================================
00052 // Destructor
00053 //=======================================================================
00054 
00055 
00056 mfpf_mr_point_finder_builder::~mfpf_mr_point_finder_builder()
00057 {
00058   delete_all();
00059 }
00060 
00061 //: Delete all the builders
00062 void mfpf_mr_point_finder_builder::delete_all()
00063 {
00064   for (unsigned i=0;i<builders_.size();++i)
00065     delete builders_[i];
00066   builders_.resize(0);
00067 }
00068 
00069 
00070 //: Define point builders.  Clone of each taken
00071 void mfpf_mr_point_finder_builder::set(
00072              const vcl_vector<mfpf_point_finder_builder*>& builders)
00073 {
00074   delete_all();
00075   builders_.resize(builders.size());
00076   for (unsigned i=0;i<builders.size();++i)
00077     builders_[i]=builders[i]->clone();
00078 }
00079 
00080 //: Set number of builders. Any existing builders are retained
00081 void mfpf_mr_point_finder_builder::set_n_levels(unsigned n)
00082 {
00083   unsigned imax=builders_.size();
00084   builders_.resize(n);
00085   for (unsigned i=imax;i<n;i++)
00086     builders_[i]=builders_[imax]->clone();
00087 }
00088 
00089 //: Set up n builders, with step size step0*scale_step^L
00090 //  Takes clones of builder and sets up step sizes.
00091 //  Top level search parameters retained.
00092 //  Finer res models have search area and scale/angle
00093 //  ranges set to allow efficient refinement.
00094 void mfpf_mr_point_finder_builder::set(
00095           const mfpf_point_finder_builder& builder0,
00096           unsigned n, double step0, double scale_step)
00097 {
00098   delete_all();
00099   builders_.resize(n);
00100   for (unsigned i=0;i<n;++i)
00101   {
00102     builders_[i]=builder0.clone();
00103     builder(i).set_step_size(step0*vcl_pow(scale_step,int(i)));
00104   }
00105 
00106   int dx = vcl_max(1,int(0.99+1.0/scale_step));
00107   double dA = builder0.search_dA();
00108   double ds = builder0.search_ds();
00109 
00110   for (int i=n-2;i>=0;--i)  // int because unsigned always >=0
00111   {
00112     // Shrink scale/angle step at each stage
00113     dA*=0.7;
00114     ds = 1.0+0.7*(ds-1.0);
00115     builder(i).set_search_area(dx,dx);
00116     if (builder0.search_ns()>0)
00117       builder(i).set_search_scale_range(1,ds);
00118     if (builder0.search_nA()>0)
00119       builder(i).set_search_angle_range(1,dA);
00120   }
00121 }
00122 
00123 //: Define region size in world co-ordinates
00124 //  Sets up ROI in each model to cover given box (in world coords),
00125 //  with ref point at centre.
00126 void mfpf_mr_point_finder_builder::set_region_size(double wi, double wj)
00127 {
00128   for (unsigned i=0;i<size();++i)
00129   {
00130     builder(i).set_region_size(wi,wj);
00131   }
00132 }
00133 
00134 void mfpf_mr_point_finder_builder::set_size_and_levels(
00135                 const mfpf_point_finder_builder& builder0,
00136                 double wi, double wj,
00137                 double scale_step,
00138                 int min_n_samples,
00139                 int max_n_samples,
00140                 double base_pixel_width)
00141 {
00142   // Max width in pixel units
00143   double max_w = vcl_max(wi/base_pixel_width,wj/base_pixel_width);
00144 
00145   double log_s = vcl_log(scale_step);
00146 
00147   // Estimate level above which size falls below min_pixel_width pixels
00148   int max_L = int(vcl_log(max_w/min_n_samples)/log_s);
00149   // Estimate level below which size is above max_pixel_width pixels
00150   int min_L = vnl_math_rnd(0.5+vcl_log(max_w/max_n_samples)/log_s);
00151   if (min_L>max_L) max_L=min_L;
00152 
00153   double step0 = base_pixel_width*vcl_pow(scale_step,min_L);
00154   int n_levels = 1+max_L-min_L;
00155 
00156   set(builder0,n_levels,step0,scale_step);
00157   set_region_size(wi,wj);
00158 }
00159 
00160 
00161 //: Select best level for building model using u as basis
00162 //  Selects pyramid level with pixel sizes best matching
00163 //  the model pixel size at given basis vector u.
00164 unsigned mfpf_mr_point_finder_builder::image_level(
00165                       unsigned i,
00166                       const vgl_vector_2d<double>& u,
00167                       const vimt_image_pyramid& im_pyr) const
00168 {
00169   double model_pixel_size = builder(i).step_size()*u.length();
00170   double rel_size0 = model_pixel_size/im_pyr.base_pixel_width();
00171 
00172   double log_step = vcl_log(im_pyr.scale_step());
00173   int level = vnl_math_rnd(vcl_log(rel_size0)/log_step);
00174   if (level<im_pyr.lo()) return im_pyr.lo();
00175   if (level>im_pyr.hi()) return im_pyr.hi();
00176   return level;
00177 }
00178 
00179 // Find non-empty image in pyramid closest to given level
00180 static unsigned nearest_valid_level(const vimt_image_pyramid& im_pyr,
00181                              unsigned level)
00182 {
00183   int L0=int(level);
00184   int bestL=0;
00185   int min_d2=999;
00186   for (int L=0;L<=im_pyr.hi();++L)
00187   {
00188     if (im_pyr(L).image_size()[0]>0)  // This level is not empty
00189     {
00190       int d2 = (L-L0)*(L-L0);
00191       if (d2<min_d2) { min_d2=d2; bestL=L; }
00192     }
00193   }
00194   return unsigned(bestL);
00195 }
00196 
00197 //: Initialise building
00198 // Must be called before any calls to add_example(...)
00199 void mfpf_mr_point_finder_builder::clear(unsigned n_egs)
00200 {
00201   for (unsigned i=0;i<size();++i) builder(i).clear(n_egs);
00202 }
00203 
00204 //: Get sample image at specified point for level L of the point_finder hierarchy
00205 void mfpf_mr_point_finder_builder::get_sample_vector(
00206                         const vimt_image_pyramid& image_pyr,
00207                         const vgl_point_2d<double>& p,
00208                         const vgl_vector_2d<double>& u,
00209                         unsigned L,
00210                         vcl_vector<double>& v)
00211 {
00212   assert( L<size() );
00213 
00214   unsigned im_L = image_level(L,u,image_pyr);
00215 
00216   if (image_pyr(im_L).image_size()[0]==0)
00217   {
00218     vcl_cerr<<"Image at level "<<im_L<<" in pyramid has not been set up.\n"
00219             <<"This is required for level "<<L<<" of the mfpf model.\n"
00220             <<"Check range for which pyramid is defined.\n";
00221 
00222     im_L=nearest_valid_level(image_pyr,im_L);
00223     if (image_pyr(im_L).image_size()[0]==0)
00224     {
00225        vcl_cerr << "No image pyramid levels set up.\n";
00226        vcl_abort();
00227     }
00228   }
00229 
00230   assert(image_pyr(im_L).is_a()=="vimt_image_2d_of<float>");
00231   const vimt_image_2d_of<float>& image
00232     = static_cast<const vimt_image_2d_of<float>&>(image_pyr(im_L));
00233 
00234   builder(L).get_sample_vector(image,p,u,v);
00235 }
00236 
00237 //: Add one example to the model
00238 void mfpf_mr_point_finder_builder::add_example(
00239                   const vimt_image_pyramid& image_pyr,
00240                   const vgl_point_2d<double>& p,
00241                   const vgl_vector_2d<double>& u)
00242 {
00243   for (unsigned L=0;L<size();++L)
00244   {
00245     unsigned im_L = image_level(L,u,image_pyr);
00246 
00247     if (image_pyr(im_L).image_size()[0]==0)
00248     {
00249       vcl_cerr << "Image at level "<<im_L<<" in pyramid has not been set up.\n"
00250                << "This is required for level "<<L<<" of the mfpf model.\n"
00251                << "Check range for which pyramid is defined.\n";
00252 
00253       im_L=nearest_valid_level(image_pyr,im_L);
00254       if (image_pyr(im_L).image_size()[0]==0)
00255       {
00256          vcl_cerr << "No image pyramid levels set up.\n";
00257          vcl_abort();
00258       }
00259     }
00260 
00261     assert(image_pyr(im_L).is_a()=="vimt_image_2d_of<float>");
00262     const vimt_image_2d_of<float>& image
00263       = static_cast<const vimt_image_2d_of<float>&>(image_pyr(im_L));
00264 
00265     builder(L).add_example(image,p,u);
00266   }
00267 }
00268 
00269 //: Build object from the data supplied in add_example()
00270 void mfpf_mr_point_finder_builder::build(mfpf_mr_point_finder& mr_pf)
00271 {
00272   vcl_vector<mfpf_point_finder*> finders(size());
00273   for (unsigned i=0;i<size();++i)
00274   {
00275     finders[i] = builder(i).new_finder();
00276     builder(i).build(*finders[i]);
00277   }
00278 
00279   mr_pf.set(finders);
00280 
00281   // Tidy up
00282   for (unsigned i=0;i<size();++i) delete finders[i];
00283 }
00284 
00285 //=======================================================================
00286 // Method: version_no
00287 //=======================================================================
00288 
00289 short mfpf_mr_point_finder_builder::version_no() const
00290 {
00291   return 1;
00292 }
00293 
00294 
00295 //=======================================================================
00296 // Method: is_a
00297 //=======================================================================
00298 
00299 vcl_string mfpf_mr_point_finder_builder::is_a() const
00300 {
00301   return vcl_string("mfpf_mr_point_finder_builder");
00302 }
00303 
00304 //: Print class to os
00305 void mfpf_mr_point_finder_builder::print_summary(vcl_ostream& os) const
00306 {
00307   os<<'\n';
00308   unsigned n=builders_.size();
00309   os<<vsl_indent()<<"n_builders: "<<n<<'\n';
00310   vsl_indent_inc(os);
00311   for (unsigned i=0;i<n;i++)
00312   {
00313     os<<vsl_indent()<<i<<") ";
00314     vsl_indent_inc(os);
00315     os<<builders_[i]<<'\n';
00316     vsl_indent_dec(os);
00317   }
00318   vsl_indent_dec(os);
00319 }
00320 
00321 //=======================================================================
00322 // Method: save
00323 //=======================================================================
00324 
00325 void mfpf_mr_point_finder_builder::b_write(vsl_b_ostream& bfs) const
00326 {
00327   vsl_b_write(bfs,version_no());
00328   vsl_b_write(bfs,builders_.size());
00329   for (unsigned i=0;i<builders_.size();++i)
00330     vsl_b_write(bfs,builders_[i]);
00331 }
00332 
00333 //=======================================================================
00334 // Method: load
00335 //=======================================================================
00336 
00337 void mfpf_mr_point_finder_builder::b_read(vsl_b_istream& bfs)
00338 {
00339   if (!bfs) return;
00340 
00341   delete_all();
00342 
00343   short version;
00344   vsl_b_read(bfs,version);
00345   unsigned n;
00346   switch (version)
00347   {
00348     case (1):
00349       vsl_b_read(bfs,n);
00350       builders_.resize(n);
00351       for (unsigned i=0;i<n;++i)
00352       {
00353         builders_[i]=0;
00354         vsl_b_read(bfs,builders_[i]);
00355       }
00356       break;
00357     default:
00358       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&)\n"
00359                << "           Unknown version number "<< version << vcl_endl;
00360       bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00361       return;
00362   }
00363 }
00364 
00365 //=======================================================================
00366 // Associated function: operator<<
00367 //=======================================================================
00368 
00369 vcl_ostream& operator<<(vcl_ostream& os,const mfpf_mr_point_finder_builder& b)
00370 {
00371   os << b.is_a() << ": ";
00372   vsl_indent_inc(os);
00373   b.print_summary(os);
00374   vsl_indent_dec(os);
00375   return os;
00376 }
00377 
00378 //: Binary file stream output operator for class reference
00379 void vsl_b_write(vsl_b_ostream& bfs, const mfpf_mr_point_finder_builder& b)
00380 {
00381   b.b_write(bfs);
00382 }
00383 
00384 //: Binary file stream input operator for class reference
00385 void vsl_b_read(vsl_b_istream& bfs, mfpf_mr_point_finder_builder& b)
00386 {
00387   b.b_read(bfs);
00388 }
00389 
00390