00001 #include "mfpf_lin_clsfy_finder_builder.h"
00002
00003
00004
00005
00006
00007 #include <mfpf/mfpf_region_finder.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 <mfpf/mfpf_log_lin_class_cost.h>
00027
00028 #include <clsfy/clsfy_binary_hyperplane.h>
00029 #include <clsfy/clsfy_binary_hyperplane_logit_builder.h>
00030 #include <mbl/mbl_data_array_wrapper.h>
00031
00032
00033
00034
00035
00036 mfpf_lin_clsfy_finder_builder::mfpf_lin_clsfy_finder_builder()
00037 {
00038 set_defaults();
00039 }
00040
00041
00042 void mfpf_lin_clsfy_finder_builder::set_defaults()
00043 {
00044 r1_=1.8;
00045 r2_=2.9;
00046 r3_=7.1;
00047 step_size_=1.0;
00048 search_ni_=5;
00049 search_nj_=5;
00050 n_pixels_=0;
00051 roi_.resize(0);
00052 roi_ni_=0;
00053 roi_nj_=0;
00054 ref_x_=0;
00055 ref_y_=0;
00056 nA_=0;
00057 dA_=0.0;
00058 norm_method_=1;
00059 overlap_f_=1.0;
00060 var_min_ = 1.0E-6;
00061 tvar_min_=1.0E30;
00062 num_examples_=0;
00063 estimate_var_min_=true;
00064 }
00065
00066
00067
00068
00069
00070 mfpf_lin_clsfy_finder_builder::~mfpf_lin_clsfy_finder_builder()
00071 {
00072 }
00073
00074
00075 mfpf_point_finder* mfpf_lin_clsfy_finder_builder::new_finder() const
00076 {
00077 return new mfpf_region_finder();
00078 }
00079
00080
00081
00082
00083
00084 void mfpf_lin_clsfy_finder_builder::set_region(const mfpf_region_form& form)
00085 {
00086 step_size_ = form.pose().scale();
00087
00088 if (form.form()=="box")
00089 {
00090 int ni = vcl_max(1,int(0.99+form.wi()));
00091 int nj = vcl_max(1,int(0.99+form.wj()));
00092 set_as_box(unsigned(ni),unsigned(nj),0.5*ni,0.5*nj);
00093 }
00094 else
00095 if (form.form()=="ellipse")
00096 {
00097 double ri = vcl_max(1.0,form.wi());
00098 double rj = vcl_max(1.0,form.wj());
00099 set_as_ellipse(ri,rj);
00100 }
00101 else
00102 {
00103 vcl_cerr<<"mfpf_lin_clsfy_finder_builder::set_region : Unknown form: "<<form<<vcl_endl;
00104 vcl_abort();
00105 }
00106 }
00107
00108
00109
00110
00111 void mfpf_lin_clsfy_finder_builder::set_region_size(double wi, double wj)
00112 {
00113 wi/=step_size();
00114 wj/=step_size();
00115 int ni = vcl_max(1,int(0.99+wi));
00116 int nj = vcl_max(1,int(0.99+wj));
00117 set_as_box(unsigned(ni),unsigned(nj),0.5*(ni-1),0.5*(nj-1));
00118 }
00119
00120
00121
00122 void mfpf_lin_clsfy_finder_builder::set_as_box(unsigned ni, unsigned nj)
00123 {
00124 set_as_box(ni,nj,0.5*(ni-1),0.5*(nj-1));
00125 }
00126
00127
00128 void mfpf_lin_clsfy_finder_builder::set_as_box(unsigned ni, unsigned nj,
00129 double ref_x, double ref_y)
00130 {
00131 roi_ni_=ni; roi_nj_=nj;
00132 n_pixels_ = ni*nj;
00133
00134
00135 roi_.resize(nj);
00136 for (unsigned j=0;j<nj;++j) roi_[j]=mbl_chord(0,ni-1,j);
00137
00138 ref_x_=ref_x;
00139 ref_y_=ref_y;
00140 }
00141
00142
00143
00144 void mfpf_lin_clsfy_finder_builder::set_as_ellipse(double ri, double rj)
00145 {
00146 ri+=1e-6; rj+=1e-6;
00147 int ni=int(ri);
00148 int nj=int(rj);
00149 roi_.resize(0);
00150 n_pixels_=0;
00151 for (int j = -nj;j<=nj;++j)
00152 {
00153
00154 int x = int(ri*vcl_sqrt(1.0-j*j/(rj*rj)));
00155 roi_.push_back(mbl_chord(ni-x,ni+x,nj+j));
00156 n_pixels_+=2*x+1;
00157 }
00158
00159 ref_x_=ni;
00160 ref_y_=nj;
00161 roi_ni_=2*ni+1;
00162 roi_nj_=2*nj+1;
00163 }
00164
00165
00166 void mfpf_lin_clsfy_finder_builder::set_norm_method(short norm_method)
00167 {
00168 norm_method_=norm_method;
00169 }
00170
00171
00172 unsigned mfpf_lin_clsfy_finder_builder::model_dim()
00173 {
00174 return n_pixels_;
00175 }
00176
00177
00178
00179 void mfpf_lin_clsfy_finder_builder::clear(unsigned n_egs)
00180 {
00181 num_examples_=0;
00182 }
00183
00184
00185
00186
00187
00188 void mfpf_lin_clsfy_finder_builder::add_one_example(
00189 const vimt_image_2d_of<float>& image,
00190 const vgl_point_2d<double>& p,
00191 const vgl_vector_2d<double>& u)
00192 {
00193
00194 vgl_vector_2d<double> u1=step_size_*u;
00195 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00196
00197
00198 int r = int(r3_+1.0);
00199 int nsi = 2*r + roi_ni_;
00200 int nsj = 2*r + roi_nj_;
00201
00202
00203 unsigned np=image.image().nplanes();
00204
00205 vil_image_view<float> sample(nsi,nsj,1,np);
00206
00207 const vgl_point_2d<double> p0 = p-(r+ref_x_)*u1-(r+ref_y_)*v1;
00208
00209 const vimt_transform_2d& s_w2i = image.world2im();
00210 vgl_point_2d<double> im_p0 = s_w2i(p0);
00211 vgl_vector_2d<double> im_u = s_w2i.delta(p0, u1);
00212 vgl_vector_2d<double> im_v = s_w2i.delta(p0, v1);
00213
00214 vil_resample_bilin(image.image(),sample,
00215 im_p0.x(),im_p0.y(), im_u.x(),im_u.y(),
00216 im_v.x(),im_v.y(),nsi,nsj);
00217
00218 vnl_vector<double> v(n_pixels_*sample.nplanes());
00219
00220 const float* s = sample.top_left_ptr();
00221 vcl_ptrdiff_t s_istep = sample.istep();
00222 vcl_ptrdiff_t s_jstep = sample.jstep();
00223
00224 for (int j=-r;j<=r;++j,s+=s_jstep)
00225 {
00226 const float *sp = s;
00227 for (int i=-r;i<=r;++i,sp+=s_istep)
00228 {
00229 double d = vcl_sqrt(static_cast<double>(i*i+j*j));
00230 if (d<=r3_)
00231 {
00232 mfpf_sample_region(sp,sample.jstep(),np,roi_,v);
00233 if (norm_method_==1)
00234 {
00235 double var=var_min_;
00236 mfpf_norm_vec(v,var_min_,&var);
00237 if (var<tvar_min_) tvar_min_ = var;
00238 }
00239
00240 if (d<=r1_)
00241 {
00242 samples_.push_back(v); class_id_.push_back(1);
00243 }
00244 else
00245 if (d>=r2_)
00246 {
00247 samples_.push_back(v); class_id_.push_back(0);
00248 }
00249 }
00250 }
00251 }
00252
00253 ++num_examples_;
00254 }
00255
00256
00257 void mfpf_lin_clsfy_finder_builder::add_example(const vimt_image_2d_of<float>& image,
00258 const vgl_point_2d<double>& p,
00259 const vgl_vector_2d<double>& u)
00260 {
00261 if (nA_==0)
00262 {
00263 add_one_example(image,p,u);
00264 return;
00265 }
00266
00267 vgl_vector_2d<double> v(-u.y(),u.x());
00268 for (int iA=-int(nA_);iA<=(int)nA_;++iA)
00269 {
00270 double A = iA*dA_;
00271 vgl_vector_2d<double> uA = u*vcl_cos(A)+v*vcl_sin(A);
00272 add_one_example(image,p,uA);
00273 }
00274 }
00275
00276
00277 void mfpf_lin_clsfy_finder_builder::build(mfpf_point_finder& pf)
00278 {
00279 assert(pf.is_a()=="mfpf_region_finder");
00280 mfpf_region_finder& rp = static_cast<mfpf_region_finder&>(pf);
00281
00282 double min_p = 0.001;
00283 mbl_data_array_wrapper<vnl_vector<double> > sample_data(samples_);
00284 clsfy_binary_hyperplane_logit_builder builder;
00285 builder.set_alpha(1e-6);
00286 builder.set_min_p(min_p);
00287 clsfy_binary_hyperplane classifier;
00288 double mean_error = builder.build(classifier,sample_data,class_id_);
00289 vcl_cout<<"Classifier Mean Error: "<<mean_error<<vcl_endl;
00290
00291 mfpf_log_lin_class_cost log_lin_cost;
00292 log_lin_cost.set(classifier.weights(),classifier.bias(),min_p);
00293 rp.set(roi_,ref_x_,ref_y_,log_lin_cost,norm_method_);
00294 set_base_parameters(rp);
00295 rp.set_overlap_f(overlap_f_);
00296
00297 if (estimate_var_min_ && norm_method_==1 && num_examples_>0)
00298 {
00299
00300
00301 double dn=double(num_examples_);
00302 if (dn>0.0)
00303 {
00304 double r=0.925;
00305 double alpha=1.0;
00306 if (dn>50.0)
00307 alpha=0.98;
00308 else
00309 {
00310 alpha=1-vcl_pow(r,dn);
00311 alpha=vcl_min(alpha,0.98);
00312 }
00313 tvar_min_ *= alpha;
00314 var_min_ = vcl_max(var_min_,tvar_min_);
00315 }
00316 rp.set_var_min(var_min_);
00317 }
00318 }
00319
00320
00321
00322 void mfpf_lin_clsfy_finder_builder::config_as_box(vcl_istream &is)
00323 {
00324
00325 vcl_string s = mbl_parse_block(is);
00326 vcl_istringstream ss(s);
00327 mbl_read_props_type props = mbl_read_props_ws(ss);
00328
00329 unsigned ni=5,nj=5;
00330
00331 if (props.find("ni")!=props.end())
00332 {
00333 ni=vul_string_atoi(props["ni"]);
00334 props.erase("ni");
00335 }
00336 if (props.find("nj")!=props.end())
00337 {
00338 nj=vul_string_atoi(props["nj"]);
00339 props.erase("nj");
00340 }
00341
00342 if (props.find("ref_x")!=props.end())
00343 {
00344 ref_x_=vul_string_atof(props["ref_x"]);
00345 props.erase("ref_x");
00346 }
00347 else ref_x_=0.5*(ni-1.0);
00348
00349 if (props.find("ref_y")!=props.end())
00350 {
00351 ref_y_=vul_string_atof(props["ref_y"]);
00352 props.erase("ref_y");
00353 }
00354 else ref_y_=0.5*(nj-1.0);
00355
00356
00357 mbl_read_props_look_for_unused_props(
00358 "mfpf_lin_clsfy_finder_builder::config_as_box",
00359 props, mbl_read_props_type());
00360
00361 set_as_box(ni,nj,ref_x_,ref_y_);
00362 }
00363
00364
00365
00366 void mfpf_lin_clsfy_finder_builder::config_as_ellipse(vcl_istream &is)
00367 {
00368
00369 vcl_string s = mbl_parse_block(is);
00370 vcl_istringstream ss(s);
00371 mbl_read_props_type props = mbl_read_props_ws(ss);
00372
00373 double ri=3.1,rj=3.1;
00374 if (props.find("ri")!=props.end())
00375 {
00376 ri=vul_string_atof(props["ri"]);
00377 props.erase("ri");
00378 }
00379
00380 if (props.find("rj")!=props.end())
00381 {
00382 rj=vul_string_atof(props["rj"]);
00383 props.erase("rj");
00384 }
00385
00386
00387 mbl_read_props_look_for_unused_props(
00388 "mfpf_lin_clsfy_finder_builder::config_as_ellipse",
00389 props, mbl_read_props_type());
00390
00391 set_as_ellipse(ri,rj);
00392 }
00393
00394
00395
00396
00397
00398
00399 bool mfpf_lin_clsfy_finder_builder::set_from_stream(vcl_istream &is)
00400 {
00401
00402 vcl_string s = mbl_parse_block(is);
00403 vcl_istringstream ss(s);
00404 mbl_read_props_type props = mbl_read_props_ws(ss);
00405
00406 set_defaults();
00407
00408
00409 parse_base_props(props);
00410
00411 if (props.find("shape")!=props.end())
00412 {
00413 vcl_istringstream shape_s(props["shape"]);
00414 shape_s>>shape_;
00415 if (shape_=="box")
00416 {
00417
00418 config_as_box(shape_s);
00419 }
00420 else
00421 if (shape_=="ellipse")
00422 {
00423
00424 config_as_ellipse(shape_s);
00425 }
00426 else throw mbl_exception_parse_error("Unknown shape: "+shape_);
00427
00428 props.erase("shape");
00429 }
00430
00431 if (props.find("norm")!=props.end())
00432 {
00433 if (props["norm"]=="none") norm_method_=0;
00434 else
00435 if (props["norm"]=="linear") norm_method_=1;
00436 else throw mbl_exception_parse_error("Unknown norm: "+props["norm"]);
00437
00438 props.erase("norm");
00439 }
00440 if (props.find("estimate_var_min") !=props.end())
00441 {
00442 vcl_string strEstimate=props["estimate_var_min"];
00443 if (strEstimate[0]=='f' || strEstimate[0]=='F' || strEstimate[0]=='0')
00444 estimate_var_min_=false;
00445 else
00446 estimate_var_min_=true;
00447
00448 props.erase("estimate_var_min");
00449 }
00450
00451 overlap_f_=vul_string_atof(props.get_optional_property("overlap_f",
00452 "1.0"));
00453 r1_=vul_string_atof(props.get_optional_property("r1","1.7"));
00454 r2_=vul_string_atof(props.get_optional_property("r2","2.9"));
00455 r3_=vul_string_atof(props.get_optional_property("r3","7.1"));
00456
00457 if (props.find("nA")!=props.end())
00458 {
00459 nA_=vul_string_atoi(props["nA"]);
00460 props.erase("nA");
00461 }
00462
00463 if (props.find("dA")!=props.end())
00464 {
00465 dA_=vul_string_atof(props["dA"]);
00466 props.erase("dA");
00467 }
00468
00469
00470 mbl_read_props_look_for_unused_props(
00471 "mfpf_lin_clsfy_finder_builder::set_from_stream", props, mbl_read_props_type());
00472 return true;
00473 }
00474
00475
00476
00477
00478
00479 vcl_string mfpf_lin_clsfy_finder_builder::is_a() const
00480 {
00481 return vcl_string("mfpf_lin_clsfy_finder_builder");
00482 }
00483
00484
00485 mfpf_point_finder_builder* mfpf_lin_clsfy_finder_builder::clone() const
00486 {
00487 return new mfpf_lin_clsfy_finder_builder(*this);
00488 }
00489
00490
00491
00492
00493
00494 void mfpf_lin_clsfy_finder_builder::print_summary(vcl_ostream& os) const
00495 {
00496 os << "{ size: " << roi_ni_ << 'x' << roi_nj_
00497 << " n_pixels: " << n_pixels_
00498 << " ref_pt: (" << ref_x_ << ',' << ref_y_ << ')' <<'\n';
00499 vsl_indent_inc(os);
00500 if (norm_method_==0) os<<vsl_indent()<<"norm: none"<<'\n';
00501 else os<<vsl_indent()<<"norm: linear"<<'\n';
00502 os <<vsl_indent()<< "r1: "<<r1_<<" r2: "<<r2_<<" r3: "<<r3_<<'\n'
00503 <<vsl_indent()<< "nA: " << nA_ << " dA: " << dA_ << ' '<<'\n'
00504 <<vsl_indent();
00505 mfpf_point_finder_builder::print_summary(os);
00506 os <<'\n' <<vsl_indent()<<"overlap_f: "<<overlap_f_<<'\n';
00507 vsl_indent_dec(os);
00508 os <<vsl_indent()<< '}';
00509 }
00510
00511 void mfpf_lin_clsfy_finder_builder::print_shape(vcl_ostream& os) const
00512 {
00513 vil_image_view<vxl_byte> im(roi_ni_,roi_nj_);
00514 im.fill(0);
00515 for (unsigned k=0;k<roi_.size();++k)
00516 for (int i=roi_[k].start_x();i<=roi_[k].end_x();++i)
00517 im(i,roi_[k].y())=1;
00518 for (unsigned j=0;j<im.nj();++j)
00519 {
00520 for (unsigned i=0;i<im.ni();++i)
00521 if (im(i,j)==0) os<<' ';
00522 else os<<'X';
00523 os<<'\n';
00524 }
00525 }
00526
00527
00528 short mfpf_lin_clsfy_finder_builder::version_no() const
00529 {
00530 return 1;
00531 }
00532
00533 void mfpf_lin_clsfy_finder_builder::b_write(vsl_b_ostream& bfs) const
00534 {
00535 vsl_b_write(bfs,version_no());
00536 mfpf_point_finder_builder::b_write(bfs);
00537 vsl_b_write(bfs,roi_);
00538 vsl_b_write(bfs,roi_ni_);
00539 vsl_b_write(bfs,roi_nj_);
00540 vsl_b_write(bfs,n_pixels_);
00541 vsl_b_write(bfs,ref_x_);
00542 vsl_b_write(bfs,ref_y_);
00543 vsl_b_write(bfs,nA_);
00544 vsl_b_write(bfs,dA_);
00545 vsl_b_write(bfs,r1_);
00546 vsl_b_write(bfs,r2_);
00547 vsl_b_write(bfs,r3_);
00548 vsl_b_write(bfs,norm_method_);
00549 vsl_b_write(bfs,overlap_f_);
00550 vsl_b_write(bfs,var_min_);
00551 vsl_b_write(bfs,samples_);
00552 vsl_b_write(bfs,class_id_);
00553 }
00554
00555
00556
00557
00558
00559 void mfpf_lin_clsfy_finder_builder::b_read(vsl_b_istream& bfs)
00560 {
00561 if (!bfs) return;
00562 short version;
00563 vsl_b_read(bfs,version);
00564 switch (version)
00565 {
00566 case (1):
00567 mfpf_point_finder_builder::b_read(bfs);
00568 vsl_b_read(bfs,roi_);
00569 vsl_b_read(bfs,roi_ni_);
00570 vsl_b_read(bfs,roi_nj_);
00571 vsl_b_read(bfs,n_pixels_);
00572 vsl_b_read(bfs,ref_x_);
00573 vsl_b_read(bfs,ref_y_);
00574 vsl_b_read(bfs,nA_);
00575 vsl_b_read(bfs,dA_);
00576 vsl_b_read(bfs,r1_);
00577 vsl_b_read(bfs,r2_);
00578 vsl_b_read(bfs,r3_);
00579 vsl_b_read(bfs,norm_method_);
00580 vsl_b_read(bfs,overlap_f_);
00581 vsl_b_read(bfs,var_min_);
00582 vsl_b_read(bfs,samples_);
00583 vsl_b_read(bfs,class_id_);
00584 break;
00585 default:
00586 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&)\n"
00587 << " Unknown version number "<< version << vcl_endl;
00588 bfs.is().clear(vcl_ios::badbit);
00589 return;
00590 }
00591 }