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