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