contrib/mul/mfpf/mfpf_sad_vec_cost_builder.cxx
Go to the documentation of this file.
00001 #include "mfpf_sad_vec_cost_builder.h"
00002 //:
00003 // \file
00004 // \brief Builder for mfpf_sad_vec_cost objects.
00005 // \author Tim Cootes
00006 
00007 #include <mfpf/mfpf_sad_vec_cost.h>
00008 #include <vsl/vsl_binary_loader.h>
00009 #include <vul/vul_string.h>
00010 #include <vcl_cassert.h>
00011 #include <vcl_algorithm.h>
00012 #include <vcl_sstream.h>
00013 
00014 #include <mbl/mbl_parse_block.h>
00015 #include <mbl/mbl_read_props.h>
00016 #include <mbl/mbl_stats_1d.h>
00017 
00018 #include <vnl/io/vnl_io_vector.h>
00019 #include <vsl/vsl_vector_io.h>
00020 
00021 //=======================================================================
00022 // Dflt ctor
00023 //=======================================================================
00024 
00025 mfpf_sad_vec_cost_builder::mfpf_sad_vec_cost_builder()
00026 {
00027   set_defaults();
00028 }
00029 
00030 //: Define default values
00031 void mfpf_sad_vec_cost_builder::set_defaults()
00032 {
00033   min_mad_ = 0.01;
00034   impose_robust_min_mad_=false;
00035 }
00036 
00037 //=======================================================================
00038 // Destructor
00039 //=======================================================================
00040 
00041 mfpf_sad_vec_cost_builder::~mfpf_sad_vec_cost_builder()
00042 {
00043 }
00044 
00045 //: Create new mfpf_sad_vec_cost on heap
00046 mfpf_vec_cost* mfpf_sad_vec_cost_builder::new_cost() const
00047 {
00048   return new mfpf_sad_vec_cost();
00049 }
00050 
00051 
00052 //: Initialise building
00053 // Must be called before any calls to add_example(...)
00054 void mfpf_sad_vec_cost_builder::clear(unsigned n_egs)
00055 {
00056   data_.resize(0);
00057 }
00058 
00059 //: Add one example to the model
00060 void mfpf_sad_vec_cost_builder::add_example(const vnl_vector<double>& v)
00061 {
00062   data_.push_back(v);
00063 }
00064 
00065 //: dv[i] = |v1[i]-v2[i]|
00066 inline void abs_diff(const vnl_vector<double>& v1,
00067                      const vnl_vector<double>& v2,
00068                      vnl_vector<double>& dv)
00069 {
00070   unsigned n = v1.size();
00071   dv.set_size(n);
00072   for (unsigned i=0;i<n;++i) dv[i]=vcl_fabs(v1[i]-v2[i]);
00073 }
00074 
00075 //: Build this object from the data supplied in add_example()
00076 void mfpf_sad_vec_cost_builder::build(mfpf_vec_cost& pf)
00077 {
00078   assert(pf.is_a()=="mfpf_sad_vec_cost");
00079   mfpf_sad_vec_cost& nc = static_cast<mfpf_sad_vec_cost&>(pf);
00080 
00081   unsigned n = data_.size();
00082 
00083   if (n==1)
00084   {
00085     // Create from only one example
00086     vnl_vector<double> wts(data_[0].size(),1.0/min_mad_);
00087     nc.set(data_[0],wts);
00088     return;
00089   }
00090 
00091   // First compute mean
00092   vnl_vector<double> mean=data_[0];
00093   for (unsigned i=1;i<n;++i) mean+=data_[i];
00094   mean/=n;
00095 
00096   // Now compute mean absolute difference from mean
00097   vnl_vector<double> dv, dv_sum;
00098   abs_diff(mean,data_[0],dv_sum);
00099   for (unsigned i=1;i<n;++i)
00100   {
00101     abs_diff(mean,data_[i],dv);
00102     dv_sum+=dv;
00103   }
00104 
00105   vnl_vector<double> wts(mean.size());
00106   double dn=double(n);
00107   if (impose_robust_min_mad_)
00108   {
00109       //May impose stricter min_mad as per typical robust kernel fitting (see /isbe_apm/rpca)
00110       //If we were using SD this would be the median of the MAD (taken over each pixel)
00111       //As we are using MAD not SD, downscale the median MAD by 1.4826 (MAD to SD conversion for Gaussian)
00112       //Note this prevents attaching an exaggerated importance to low variance pixels in flat sub-regions of the patch
00113 
00114       vcl_vector<double> mads;
00115       mads.reserve(mean.size());
00116 
00117       for (unsigned i=0;i<mean.size();++i)
00118       {
00119           mads.push_back(dv_sum[i]/dn);
00120       }
00121       vcl_vector<double>::iterator medIter=mads.begin()+mads.size()/2;
00122       vcl_nth_element(mads.begin(),medIter,mads.end());
00123       const double kMADtoSD=1.4826;
00124       min_mad_ = vcl_max(min_mad_,(*medIter/kMADtoSD));
00125   }
00126 
00127   for (unsigned i=0;i<mean.size();++i)
00128   {
00129     wts[i]=1.0/vcl_max(min_mad_,dv_sum[i]/dn);
00130   }
00131 
00132   nc.set(mean,wts);
00133 
00134   // Now compute the statistics of the output on the training set
00135   mbl_stats_1d stats;
00136   for (unsigned i=0;i<n;++i)
00137     stats.obs(nc.evaluate(data_[i]));
00138 
00139   // Tweak the weights so that the SD of this will be unity
00140   if (stats.sd()>1e-6)
00141     wts/=stats.sd();
00142 
00143   nc.set(mean,wts);
00144 
00145   // Discard data
00146   data_.resize(0);
00147 }
00148 
00149 //=======================================================================
00150 // Method: set_from_stream
00151 //=======================================================================
00152 //: Initialise from a string stream
00153 bool mfpf_sad_vec_cost_builder::set_from_stream(vcl_istream &is)
00154 {
00155   // Cycle through string and produce a map of properties
00156   vcl_string s = mbl_parse_block(is);
00157   vcl_istringstream ss(s);
00158   mbl_read_props_type props = mbl_read_props_ws(ss);
00159 
00160   set_defaults();
00161 
00162   // Extract the properties
00163   if (props.find("min_mad")!=props.end())
00164   {
00165     min_mad_=vul_string_atof(props["min_mad"]);
00166     props.erase("min_mad");
00167   }
00168 
00169   if (props.find("impose_robust_min_mad") !=props.end())
00170   {
00171     vcl_string strImpose=props["impose_robust_min_mad"];
00172     if (strImpose[0]=='f' || strImpose[0]=='F' || strImpose[0]=='0')
00173         impose_robust_min_mad_=false;
00174     else
00175         impose_robust_min_mad_=true;
00176 
00177     props.erase("impose_robust_min_mad");
00178   }
00179 
00180   // Check for unused props
00181   mbl_read_props_look_for_unused_props(
00182       "mfpf_sad_vec_cost_builder::set_from_stream", props, mbl_read_props_type());
00183   return true;
00184 }
00185 
00186 //=======================================================================
00187 // Method: is_a
00188 //=======================================================================
00189 
00190 vcl_string mfpf_sad_vec_cost_builder::is_a() const
00191 {
00192   return vcl_string("mfpf_sad_vec_cost_builder");
00193 }
00194 
00195 //: Create a copy on the heap and return base class pointer
00196 mfpf_vec_cost_builder* mfpf_sad_vec_cost_builder::clone() const
00197 {
00198   return new mfpf_sad_vec_cost_builder(*this);
00199 }
00200 
00201 //=======================================================================
00202 // Method: print
00203 //=======================================================================
00204 
00205 void mfpf_sad_vec_cost_builder::print_summary(vcl_ostream& os) const
00206 {
00207   os << "{ min_mad: " << min_mad_ << " }";
00208 }
00209 
00210 //: Version number for I/O
00211 short mfpf_sad_vec_cost_builder::version_no() const
00212 {
00213   return 1;
00214 }
00215 
00216 
00217 void mfpf_sad_vec_cost_builder::b_write(vsl_b_ostream& bfs) const
00218 {
00219   vsl_b_write(bfs,version_no());
00220   vsl_b_write(bfs,min_mad_);
00221   vsl_b_write(bfs,data_);
00222 }
00223 
00224 //=======================================================================
00225 // Method: load
00226 //=======================================================================
00227 
00228 void mfpf_sad_vec_cost_builder::b_read(vsl_b_istream& bfs)
00229 {
00230   if (!bfs) return;
00231   short version;
00232   vsl_b_read(bfs,version);
00233   switch (version)
00234   {
00235     case (1):
00236       vsl_b_read(bfs,min_mad_);
00237       vsl_b_read(bfs,data_);
00238       break;
00239     default:
00240       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&)\n"
00241                << "           Unknown version number "<< version << vcl_endl;
00242       bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00243       return;
00244   }
00245 }
00246