00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "vpdfl_gaussian_builder.h"
00017
00018 #include <vcl_cstdlib.h>
00019 #include <vcl_string.h>
00020 #include <vcl_cassert.h>
00021 #include <mbl/mbl_data_wrapper.h>
00022 #include <vpdfl/vpdfl_gaussian.h>
00023 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00024
00025 #include <mbl/mbl_parse_block.h>
00026 #include <mbl/mbl_read_props.h>
00027 #include <vul/vul_string.h>
00028 #include <mbl/mbl_exception.h>
00029
00030
00031 const double min_wt = 1e-8;
00032
00033
00034
00035
00036
00037 vpdfl_gaussian_builder::vpdfl_gaussian_builder()
00038 : min_var_(1.0e-6)
00039 {
00040 }
00041
00042
00043
00044
00045
00046 vpdfl_gaussian_builder::~vpdfl_gaussian_builder()
00047 {
00048 }
00049
00050
00051
00052 vpdfl_gaussian& vpdfl_gaussian_builder::gaussian(vpdfl_pdf_base& model) const
00053 {
00054
00055 assert(model.is_class("vpdfl_gaussian"));
00056 return static_cast<vpdfl_gaussian&>(model);
00057 }
00058
00059
00060 vpdfl_pdf_base* vpdfl_gaussian_builder::new_model() const
00061 {
00062 return new vpdfl_gaussian;
00063 }
00064
00065
00066
00067
00068 void vpdfl_gaussian_builder::set_min_var(double min_var)
00069 {
00070 min_var_ = min_var;
00071 }
00072
00073
00074
00075
00076 double vpdfl_gaussian_builder::min_var() const
00077 {
00078 return min_var_;
00079 }
00080
00081
00082
00083 void vpdfl_gaussian_builder::build(vpdfl_pdf_base& model,
00084 const vnl_vector<double>& mean) const
00085 {
00086 vpdfl_gaussian& g = gaussian(model);
00087 int n = mean.size();
00088
00089 vnl_vector<double> var(n);
00090 for (int i=0;i<n;i++) var(i)=min_var_;
00091
00092
00093 vnl_matrix<double> P(n,n);
00094 for (int i=0;i<n;++i)
00095 for (int j=0;j<n;++j) P(i,j) = 0.0;
00096
00097 for (int i=0;i<n;++i) P(i,i) = 1.0;
00098
00099 g.set(mean,var,P,var);
00100 }
00101
00102
00103 void vpdfl_gaussian_builder::updateCovar(vnl_matrix<double>& S,
00104 const vnl_vector<double>& vec,
00105 double w) const
00106 {
00107 unsigned int n = vec.size();
00108 const double *v = vec.data_block();
00109 if (S.rows()!=n)
00110 {
00111 S.set_size(n,n);
00112 double **S_data = S.data_array();
00113 for (unsigned int i=0; i<n; ++i)
00114 for (unsigned int j=0; j<n; ++j)
00115 S_data[j][i] = w*v[i]*v[j];
00116 }
00117 else
00118 {
00119 double **S_data = S.data_array();
00120 double * S_row;
00121 for (unsigned int i=0; i<n; ++i)
00122 {
00123 S_row = S_data[i];
00124 double vw = w*v[i];
00125 for (unsigned int j=0; j<n; ++j)
00126 S_row[j] += vw*v[j];
00127 }
00128 }
00129 }
00130
00131
00132
00133 void vpdfl_gaussian_builder::buildFromCovar(vpdfl_gaussian& g,
00134 const vnl_vector<double>& mean,
00135 const vnl_matrix<double>& S) const
00136 {
00137 unsigned int n = mean.size();
00138 vnl_matrix<double> evecs(S.rows(), S.rows());
00139 vnl_vector<double> evals(S.rows());
00140
00141
00142 vnl_symmetric_eigensystem_compute(S, evecs, evals);
00143
00144 evals.flip();
00145 evecs.fliplr();
00146
00147
00148
00149 double *ev = evals.data_block();
00150 for (unsigned int i=0;i<n;++i)
00151 if (ev[i]<min_var_) ev[i]=min_var_;
00152
00153 g.set(mean,evecs,evals);
00154 }
00155
00156
00157
00158 void vpdfl_gaussian_builder::build(vpdfl_pdf_base& model,
00159 mbl_data_wrapper<vnl_vector<double> >& data) const
00160 {
00161 vpdfl_gaussian& g = gaussian(model);
00162
00163 assert(data.size() >= 2L);
00164
00165 vnl_vector<double> mean;
00166 vnl_matrix<double> S;
00167
00168 meanCovar(mean,S,data);
00169 buildFromCovar(g,mean,S);
00170 }
00171
00172
00173
00174 void vpdfl_gaussian_builder::meanCovar(vnl_vector<double>& mean, vnl_matrix<double>& S,
00175 mbl_data_wrapper<vnl_vector<double> >& data) const
00176 {
00177 unsigned long n_samples = data.size();
00178
00179 assert(n_samples!=0L);
00180
00181 data.reset();
00182 int n_dims = data.current().size();
00183 vnl_vector<double> sum(n_dims);
00184 sum.fill(0);
00185
00186 S.set_size(0,0);
00187
00188 data.reset();
00189 for (unsigned long i=0;i<n_samples;i++)
00190 {
00191 sum += data.current();
00192 updateCovar(S,data.current(),1.0);
00193
00194 data.next();
00195 }
00196
00197 mean = sum / (double) n_samples;
00198 updateCovar(S, mean, - (double)n_samples);
00199 S/=(n_samples-1);
00200 }
00201
00202
00203
00204 void vpdfl_gaussian_builder::weighted_build(vpdfl_pdf_base& model,
00205 mbl_data_wrapper<vnl_vector<double> >& data,
00206 const vcl_vector<double>& wts) const
00207 {
00208 vpdfl_gaussian& g = gaussian(model);
00209
00210 unsigned long n_samples = data.size();
00211
00212 assert(n_samples>=2L);
00213
00214 data.reset();
00215 int n_dims = data.current().size();
00216 vnl_vector<double> sum(n_dims);
00217 sum.fill(0);
00218 vnl_matrix<double> S;
00219 double w_sum = 0.0;
00220 unsigned actual_samples = 0;
00221
00222 data.reset();
00223 for (unsigned long i=0;i<n_samples;i++)
00224 {
00225 double w = wts[i];
00226 if (w >= min_wt) actual_samples ++;
00227 w_sum += w;
00228 sum += w*data.current();
00229 updateCovar(S,data.current(),w);
00230
00231 data.next();
00232 }
00233
00234 if (w_sum/n_samples<min_wt)
00235 {
00236 vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() :\n"
00237 <<"Weights too close to zero. Sum = "<<w_sum<<vcl_endl;
00238 vcl_abort();
00239 }
00240
00241 if (actual_samples==0)
00242 {
00243 vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() :\nAll weights zero.\n";
00244 vcl_abort();
00245 }
00246
00247 if (actual_samples==1)
00248 {
00249 #if 0
00250 vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() :\n"
00251 <<" Warning: Only one sample has non-zero weight.\n";
00252 #endif
00253
00254 sum/=w_sum;
00255 build(g,sum);
00256 return;
00257 }
00258
00259 S*=actual_samples/((actual_samples - 1) *w_sum);
00260 sum/=w_sum;
00261 updateCovar(S, sum, -1.0);
00262
00263
00264
00265 buildFromCovar(g,sum,S);
00266 }
00267
00268
00269
00270
00271 vcl_string vpdfl_gaussian_builder::is_a() const
00272 {
00273 static vcl_string class_name_ = "vpdfl_gaussian_builder";
00274 return class_name_;
00275 }
00276
00277
00278
00279
00280
00281 bool vpdfl_gaussian_builder::is_class(vcl_string const& s) const
00282 {
00283 return vpdfl_builder_base::is_class(s) || s==vpdfl_gaussian_builder::is_a();
00284 }
00285
00286
00287
00288
00289
00290 short vpdfl_gaussian_builder::version_no() const
00291 {
00292 return 1;
00293 }
00294
00295
00296
00297
00298
00299 vpdfl_builder_base* vpdfl_gaussian_builder::clone() const
00300 {
00301 return new vpdfl_gaussian_builder(*this);
00302 }
00303
00304
00305
00306
00307
00308 void vpdfl_gaussian_builder::print_summary(vcl_ostream& os) const
00309 {
00310 os << "Min. var. : "<< min_var_;
00311 }
00312
00313
00314
00315
00316
00317 void vpdfl_gaussian_builder::b_write(vsl_b_ostream& bfs) const
00318 {
00319 vsl_b_write(bfs,is_a());
00320 vsl_b_write(bfs,version_no());
00321 vsl_b_write(bfs,min_var_);
00322 }
00323
00324
00325
00326
00327
00328 void vpdfl_gaussian_builder::b_read(vsl_b_istream& bfs)
00329 {
00330 if (!bfs) return;
00331
00332 vcl_string name;
00333 vsl_b_read(bfs,name);
00334 if (name != is_a())
00335 {
00336 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_gaussian_builder &)\n"
00337 << " Attempted to load object of type "
00338 << name <<" into object of type " << is_a() << vcl_endl;
00339 bfs.is().clear(vcl_ios::badbit);
00340 return;
00341 }
00342
00343 short version;
00344 vsl_b_read(bfs,version);
00345 switch (version)
00346 {
00347 case (1):
00348 vsl_b_read(bfs,min_var_);
00349 break;
00350 default:
00351 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_gaussian_builder &)\n"
00352 << " Unknown version number "<< version << vcl_endl;
00353 bfs.is().clear(vcl_ios::badbit);
00354 return;
00355 }
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 void vpdfl_gaussian_builder::config_from_stream(vcl_istream & is)
00367 {
00368 vcl_string s = mbl_parse_block(is);
00369
00370 vcl_istringstream ss(s);
00371 mbl_read_props_type props = mbl_read_props_ws(ss);
00372
00373 double mv=1.0e-6;
00374
00375 if (props.find("min_var")!=props.end())
00376 {
00377 mv=vul_string_atof(props["min_var"]);
00378 props.erase("min_var");
00379 }
00380 set_min_var(mv);
00381 try
00382 {
00383 mbl_read_props_look_for_unused_props(
00384 "vpdfl_gaussian_builder::config_from_stream", props);
00385 }
00386 catch(mbl_exception_unused_props &e)
00387 {
00388 throw mbl_exception_parse_error(e.what());
00389 }
00390 }
00391
00392
00393