contrib/mul/mfpf/mfpf_region_pdf_builder.cxx
Go to the documentation of this file.
00001 #include "mfpf_region_pdf_builder.h"
00002 //:
00003 // \file
00004 // \brief Builder for mfpf_region_pdf objects.
00005 // \author Tim Cootes
00006 
00007 #include <mfpf/mfpf_region_pdf.h>
00008 #include <vsl/vsl_binary_loader.h>
00009 #include <vul/vul_string.h>
00010 #include <vcl_cmath.h>
00011 #include <vcl_sstream.h>
00012 #include <vcl_cassert.h>
00013 
00014 #include <mbl/mbl_parse_block.h>
00015 #include <mbl/mbl_read_props.h>
00016 #include <mbl/mbl_exception.h>
00017 
00018 #include <vil/vil_resample_bilin.h>
00019 #include <vsl/vsl_vector_io.h>
00020 #include <vsl/vsl_indent.h>
00021 
00022 #include <vgl/vgl_point_2d.h>
00023 #include <vgl/vgl_vector_2d.h>
00024 #include <mfpf/mfpf_sample_region.h>
00025 #include <mfpf/mfpf_norm_vec.h>
00026 #include <mbl/mbl_data_array_wrapper.h>
00027 
00028 //=======================================================================
00029 // Dflt ctor
00030 //=======================================================================
00031 
00032 mfpf_region_pdf_builder::mfpf_region_pdf_builder()
00033 {
00034   set_defaults();
00035 }
00036 
00037 //: Define default values
00038 void mfpf_region_pdf_builder::set_defaults()
00039 {
00040   step_size_=1.0;
00041   search_ni_=5;
00042   search_nj_=5;
00043   n_pixels_=0;
00044   roi_.resize(0);
00045   roi_ni_=0;
00046   roi_nj_=0;
00047   ref_x_=0;
00048   ref_y_=0;
00049   nA_=0;
00050   dA_=0.0;
00051   norm_method_=1;
00052   overlap_f_=1.0;
00053 }
00054 
00055 //=======================================================================
00056 // Destructor
00057 //=======================================================================
00058 
00059 mfpf_region_pdf_builder::~mfpf_region_pdf_builder()
00060 {
00061 }
00062 
00063 //: Create new mfpf_region_pdf on heap
00064 mfpf_point_finder* mfpf_region_pdf_builder::new_finder() const
00065 {
00066   return new mfpf_region_pdf();
00067 }
00068 
00069 //: Define model region using description in form
00070 //  Assumes form defined in world-coords.
00071 //  Assumes step_size() pixel units (ie dimensions
00072 //  are divided by step_size() to map to reference frame).
00073 void mfpf_region_pdf_builder::set_region(const mfpf_region_form& form)
00074 {
00075   step_size_ = form.pose().scale();
00076 
00077   if (form.form()=="box")
00078   {
00079     int ni = vcl_max(1,int(0.99+form.wi()));
00080     int nj = vcl_max(1,int(0.99+form.wj()));
00081     set_as_box(unsigned(ni),unsigned(nj),0.5*ni,0.5*nj);
00082   }
00083   else
00084   if (form.form()=="ellipse")
00085   {
00086     double ri = vcl_max(1.0,form.wi());
00087     double rj = vcl_max(1.0,form.wj());
00088     set_as_ellipse(ri,rj);
00089   }
00090   else
00091   {
00092     vcl_cerr<<"mfpf_region_pdf_builder::set_region : Unknown form: "<<form<<vcl_endl;
00093     vcl_abort();
00094   }
00095 }
00096 
00097 //: Define region size in world co-ordinates
00098 //  Sets up ROI to cover given box (with samples at step_size()),
00099 //  with ref point at centre.
00100 void mfpf_region_pdf_builder::set_region_size(double wi, double wj)
00101 {
00102   wi/=step_size();
00103   wj/=step_size();
00104   int ni = vcl_max(1,int(0.99+wi));
00105   int nj = vcl_max(1,int(0.99+wj));
00106   set_as_box(unsigned(ni),unsigned(nj),0.5*(ni-1),0.5*(nj-1));
00107 }
00108 
00109 
00110 //: Define model region as an ni x nj box
00111 void mfpf_region_pdf_builder::set_as_box(unsigned ni, unsigned nj,
00112                                          double ref_x, double ref_y,
00113                                          const vpdfl_builder_base& builder)
00114 {
00115   set_as_box(ni,nj,ref_x,ref_y);
00116   pdf_builder_ = builder.clone();
00117 }
00118 
00119 //: Define model region as an ni x nj box
00120 void mfpf_region_pdf_builder::set_as_box(unsigned ni, unsigned nj,
00121                                          double ref_x, double ref_y)
00122 {
00123   roi_ni_=ni; roi_nj_=nj;
00124   n_pixels_ = ni*nj;
00125 
00126   // Set ROI to be a box
00127   roi_.resize(nj);
00128   for (unsigned j=0;j<nj;++j) roi_[j]=mbl_chord(0,ni-1,j);
00129 
00130   ref_x_=ref_x;
00131   ref_y_=ref_y;
00132 }
00133 
00134 
00135 //: Define model region as an ni x nj box
00136 void mfpf_region_pdf_builder::set_as_box(unsigned ni, unsigned nj,
00137                                          const vpdfl_builder_base& builder)
00138 {
00139   set_as_box(ni,nj, 0.5*(ni-1),0.5*(nj-1), builder);
00140 }
00141 
00142 //: Define model region as an ellipse with radii ri, rj
00143 //  Ref. point in centre.
00144 void mfpf_region_pdf_builder::set_as_ellipse(double ri, double rj,
00145                                              const vpdfl_builder_base& builder)
00146 {
00147   set_as_ellipse(ri,rj);
00148   pdf_builder_ = builder.clone();
00149 }
00150 
00151 //: Define model region as an ellipse with radii ri, rj
00152 //  Ref. point in centre.
00153 void mfpf_region_pdf_builder::set_as_ellipse(double ri, double rj)
00154 {
00155   ri+=1e-6; rj+=1e-6;
00156   int ni=int(ri);
00157   int nj=int(rj);
00158   roi_.resize(0);
00159   n_pixels_=0;
00160   for (int j = -nj;j<=nj;++j)
00161   {
00162     // Find start and end of line of pixels inside disk
00163     int x = int(ri*vcl_sqrt(1.0-j*j/(rj*rj)));
00164     roi_.push_back(mbl_chord(ni-x,ni+x,nj+j));
00165     n_pixels_+=2*x+1;
00166   }
00167 
00168   ref_x_=ni;
00169   ref_y_=nj;
00170   roi_ni_=2*ni+1;
00171   roi_nj_=2*nj+1;
00172 }
00173 
00174 //: Initialise building
00175 // Must be called before any calls to add_example(...)
00176 void mfpf_region_pdf_builder::clear(unsigned n_egs)
00177 {
00178   data_.resize(0);
00179 }
00180 
00181 //: Add one example to the model
00182 void mfpf_region_pdf_builder::add_one_example(
00183                  const vimt_image_2d_of<float>& image,
00184                  const vgl_point_2d<double>& p,
00185                  const vgl_vector_2d<double>& u)
00186 {
00187   vgl_vector_2d<double> u1=step_size_*u;
00188   vgl_vector_2d<double> v1(-u1.y(),u1.x());
00189 
00190   unsigned np=image.image().nplanes();
00191   // Set up sample area with interleaved planes (ie planestep==1)
00192   vil_image_view<float> sample(roi_ni_,roi_nj_,1,np);
00193 
00194   const vgl_point_2d<double> p0 = p-ref_x_*u1-ref_y_*v1;
00195 
00196   const vimt_transform_2d& s_w2i = image.world2im();
00197   vgl_point_2d<double> im_p0 = s_w2i(p0);
00198   vgl_vector_2d<double> im_u = s_w2i.delta(p0, u1);
00199   vgl_vector_2d<double> im_v = s_w2i.delta(p0, v1);
00200 
00201   vil_resample_bilin(image.image(),sample,
00202                      im_p0.x(),im_p0.y(),  im_u.x(),im_u.y(),
00203                      im_v.x(),im_v.y(),roi_ni_,roi_nj_);
00204 
00205   vnl_vector<double> v(n_pixels_*sample.nplanes());
00206   mfpf_sample_region(sample.top_left_ptr(),sample.jstep(),
00207                      np,roi_,v);
00208 
00209   if (norm_method_==1) mfpf_norm_vec(v);
00210   data_.push_back(v);
00211 }
00212 
00213 //: Add one example to the model
00214 void mfpf_region_pdf_builder::add_example(const vimt_image_2d_of<float>& image,
00215                                           const vgl_point_2d<double>& p,
00216                                           const vgl_vector_2d<double>& u)
00217 {
00218   if (nA_==0)
00219   {
00220     add_one_example(image,p,u);
00221     return;
00222   }
00223 
00224   vgl_vector_2d<double> v(-u.y(),u.x());
00225   for (int iA=-int(nA_);iA<=(int)nA_;++iA)
00226   {
00227     double A = iA*dA_;
00228     vgl_vector_2d<double> uA = u*vcl_cos(A)+v*vcl_sin(A);
00229     add_one_example(image,p,uA);
00230   }
00231 }
00232 
00233 //: Build this object from the data supplied in add_example()
00234 void mfpf_region_pdf_builder::build(mfpf_point_finder& pf)
00235 {
00236   assert(pf.is_a()=="mfpf_region_pdf");
00237   mfpf_region_pdf& rp = static_cast<mfpf_region_pdf&>(pf);
00238 
00239   vpdfl_pdf_base *pdf = pdf_builder().new_model();
00240 
00241   if (data_.size()==1)
00242     pdf_builder().build(*pdf,data_[0]);
00243   else
00244   {
00245     mbl_data_array_wrapper<vnl_vector<double> > data(&data_[0],
00246                                                      data_.size());
00247     pdf_builder().build(*pdf,data);
00248   }
00249 
00250   rp.set(roi_,ref_x_,ref_y_,*pdf,norm_method_);
00251   set_base_parameters(rp);
00252   rp.set_overlap_f(overlap_f_);
00253 
00254   // Tidy up
00255   delete pdf;
00256   data_.resize(0);
00257 }
00258 
00259 //: Parse stream to set up as a box shape.
00260 // Expects: "{ ni: 3 nj: 5 ref_x: 1.0 ref_y: 2.0 }
00261 void mfpf_region_pdf_builder::config_as_box(vcl_istream &is)
00262 {
00263   // Cycle through string and produce a map of properties
00264   vcl_string s = mbl_parse_block(is);
00265   vcl_istringstream ss(s);
00266   mbl_read_props_type props = mbl_read_props_ws(ss);
00267 
00268   unsigned ni=5,nj=5;
00269 
00270   if (props.find("ni")!=props.end())
00271   {
00272     ni=vul_string_atoi(props["ni"]);
00273     props.erase("ni");
00274   }
00275   if (props.find("nj")!=props.end())
00276   {
00277     nj=vul_string_atoi(props["nj"]);
00278     props.erase("nj");
00279   }
00280 
00281   if (props.find("ref_x")!=props.end())
00282   {
00283     ref_x_=vul_string_atof(props["ref_x"]);
00284     props.erase("ref_x");
00285   }
00286   else ref_x_=0.5*(ni-1.0);
00287 
00288   if (props.find("ref_y")!=props.end())
00289   {
00290     ref_y_=vul_string_atof(props["ref_y"]);
00291     props.erase("ref_y");
00292   }
00293   else ref_y_=0.5*(nj-1.0);
00294 
00295   // Check for unused props
00296   mbl_read_props_look_for_unused_props(
00297       "mfpf_region_pdf_builder::config_as_box",
00298       props, mbl_read_props_type());
00299 
00300   set_as_box(ni,nj,ref_x_,ref_y_);
00301 }
00302 
00303 //: Parse stream to set up as an ellipse shape.
00304 // Expects: "{ ri: 2.1 rj: 5.2 }
00305 void mfpf_region_pdf_builder::config_as_ellipse(vcl_istream &is)
00306 {
00307   // Cycle through string and produce a map of properties
00308   vcl_string s = mbl_parse_block(is);
00309   vcl_istringstream ss(s);
00310   mbl_read_props_type props = mbl_read_props_ws(ss);
00311 
00312   double ri=3.1,rj=3.1;
00313   if (props.find("ri")!=props.end())
00314   {
00315     ri=vul_string_atof(props["ri"]);
00316     props.erase("ri");
00317   }
00318 
00319   if (props.find("rj")!=props.end())
00320   {
00321     rj=vul_string_atof(props["rj"]);
00322     props.erase("rj");
00323   }
00324 
00325   // Check for unused props
00326   mbl_read_props_look_for_unused_props(
00327       "mfpf_region_pdf_builder::config_as_ellipse",
00328       props, mbl_read_props_type());
00329 
00330   set_as_ellipse(ri,rj);
00331 }
00332 
00333 
00334 //=======================================================================
00335 // Method: set_from_stream
00336 //=======================================================================
00337 //: Initialise from a string stream
00338 bool mfpf_region_pdf_builder::set_from_stream(vcl_istream &is)
00339 {
00340   // Cycle through string and produce a map of properties
00341   vcl_string s = mbl_parse_block(is);
00342   vcl_istringstream ss(s);
00343   mbl_read_props_type props = mbl_read_props_ws(ss);
00344 
00345   set_defaults();
00346 
00347   // Extract the properties
00348   parse_base_props(props);
00349 
00350   if (props.find("shape")!=props.end())
00351   {
00352     vcl_istringstream shape_s(props["shape"]);
00353     shape_s>>shape_;
00354     if (shape_=="box")
00355     {
00356       // Parse parameters after box
00357       config_as_box(shape_s);
00358     }
00359     else
00360     if (shape_=="ellipse")
00361     {
00362       // Parse parameters after ellipse
00363       config_as_ellipse(shape_s);
00364     }
00365     else throw mbl_exception_parse_error("Unknown shape: "+shape_);
00366 
00367     props.erase("shape");
00368   }
00369 
00370   if (props.find("norm")!=props.end())
00371   {
00372     if (props["norm"]=="none") norm_method_=0;
00373     else
00374     if (props["norm"]=="linear") norm_method_=1;
00375     else throw mbl_exception_parse_error("Unknown norm: "+props["norm"]);
00376 
00377     props.erase("norm");
00378   }
00379 
00380   if (props.find("nA")!=props.end())
00381   {
00382     nA_=vul_string_atoi(props["nA"]);
00383     props.erase("nA");
00384   }
00385 
00386   if (props.find("dA")!=props.end())
00387   {
00388     dA_=vul_string_atof(props["dA"]);
00389     props.erase("dA");
00390   }
00391 
00392   overlap_f_=vul_string_atof(props.get_optional_property("overlap_f",
00393                                                          "1.0"));
00394 
00395   if (props.find("pdf_builder")!=props.end())
00396   {
00397     vcl_istringstream b_ss(props["pdf_builder"]);
00398     vcl_auto_ptr<vpdfl_builder_base> bb =
00399          vpdfl_builder_base::new_pdf_builder_from_stream(b_ss);
00400     pdf_builder_ = bb->clone();
00401     props.erase("pdf_builder");
00402   }
00403 
00404   // Check for unused props
00405   mbl_read_props_look_for_unused_props(
00406       "mfpf_region_pdf_builder::set_from_stream", props, mbl_read_props_type());
00407   return true;
00408 }
00409 
00410 //=======================================================================
00411 // Method: is_a
00412 //=======================================================================
00413 
00414 vcl_string mfpf_region_pdf_builder::is_a() const
00415 {
00416   return vcl_string("mfpf_region_pdf_builder");
00417 }
00418 
00419 //: Create a copy on the heap and return base class pointer
00420 mfpf_point_finder_builder* mfpf_region_pdf_builder::clone() const
00421 {
00422   return new mfpf_region_pdf_builder(*this);
00423 }
00424 
00425 //=======================================================================
00426 // Method: print
00427 //=======================================================================
00428 
00429 void mfpf_region_pdf_builder::print_summary(vcl_ostream& os) const
00430 {
00431   os << "{ size: " << roi_ni_ << 'x' << roi_nj_
00432      << " n_pixels: " << n_pixels_
00433      << " ref_pt: (" << ref_x_ << ',' << ref_y_ << ')' <<'\n';
00434   vsl_indent_inc(os);
00435   if (norm_method_==0) os<<vsl_indent()<<"norm: none"<<'\n';
00436   else                 os<<vsl_indent()<<"norm: linear"<<'\n';
00437   os <<vsl_indent()<< "pdf_builder: ";
00438   if (pdf_builder_.ptr()==0) os << '-'<<'\n';
00439   else                       os << pdf_builder_<<'\n';
00440   os <<vsl_indent()<< "nA: " << nA_ << " dA: " << dA_ << ' '<<'\n'
00441      <<vsl_indent();
00442   mfpf_point_finder_builder::print_summary(os);
00443   os <<'\n' <<vsl_indent()<<"overlap_f: "<<overlap_f_<<'\n';
00444   vsl_indent_dec(os);
00445   os <<vsl_indent()<< '}';
00446 }
00447 
00448 void mfpf_region_pdf_builder::print_shape(vcl_ostream& os) const
00449 {
00450   vil_image_view<vxl_byte> im(roi_ni_,roi_nj_);
00451   im.fill(0);
00452   for (unsigned k=0;k<roi_.size();++k)
00453     for (int i=roi_[k].start_x();i<=roi_[k].end_x();++i)
00454       im(i,roi_[k].y())=1;
00455   for (unsigned j=0;j<im.nj();++j)
00456   {
00457     for (unsigned i=0;i<im.ni();++i)
00458       if (im(i,j)==0) os<<' ';
00459       else            os<<'X';
00460     os<<'\n';
00461   }
00462 }
00463 
00464 //: Version number for I/O
00465 short mfpf_region_pdf_builder::version_no() const
00466 {
00467   return 1;
00468 }
00469 
00470 void mfpf_region_pdf_builder::b_write(vsl_b_ostream& bfs) const
00471 {
00472   vsl_b_write(bfs,version_no());
00473   mfpf_point_finder_builder::b_write(bfs);  // Save base class
00474   vsl_b_write(bfs,roi_);
00475   vsl_b_write(bfs,roi_ni_);
00476   vsl_b_write(bfs,roi_nj_);
00477   vsl_b_write(bfs,n_pixels_);
00478   vsl_b_write(bfs,ref_x_);
00479   vsl_b_write(bfs,ref_y_);
00480   vsl_b_write(bfs,nA_);
00481   vsl_b_write(bfs,dA_);
00482   vsl_b_write(bfs,pdf_builder_);
00483   vsl_b_write(bfs,norm_method_);
00484   vsl_b_write(bfs,data_);
00485   vsl_b_write(bfs,overlap_f_);
00486 }
00487 
00488 //=======================================================================
00489 // Method: load
00490 //=======================================================================
00491 
00492 void mfpf_region_pdf_builder::b_read(vsl_b_istream& bfs)
00493 {
00494   if (!bfs) return;
00495   short version;
00496   vsl_b_read(bfs,version);
00497   switch (version)
00498   {
00499     case (1):
00500     case (2):
00501       mfpf_point_finder_builder::b_read(bfs);  // Load base class
00502       vsl_b_read(bfs,roi_);
00503       vsl_b_read(bfs,roi_ni_);
00504       vsl_b_read(bfs,roi_nj_);
00505       vsl_b_read(bfs,n_pixels_);
00506       vsl_b_read(bfs,ref_x_);
00507       vsl_b_read(bfs,ref_y_);
00508       vsl_b_read(bfs,nA_);
00509       vsl_b_read(bfs,dA_);
00510       vsl_b_read(bfs,pdf_builder_);
00511       vsl_b_read(bfs,norm_method_);
00512       vsl_b_read(bfs,data_);
00513       if (version==1) overlap_f_=1.0;
00514       else            vsl_b_read(bfs,overlap_f_);
00515       break;
00516     default:
00517       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&)\n"
00518                << "           Unknown version number "<< version << vcl_endl;
00519       bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00520       return;
00521   }
00522 }