00001 #include "mfpf_hog_box_finder.h"
00002
00003
00004
00005
00006
00007 #include <vsl/vsl_binary_loader.h>
00008 #include <vcl_cmath.h>
00009 #include <vcl_cassert.h>
00010
00011 #include <vil/vil_resample_bilin.h>
00012 #include <vil/io/vil_io_image_view.h>
00013 #include <vsl/vsl_vector_io.h>
00014 #include <vsl/vsl_indent.h>
00015 #include <vcl_algorithm.h>
00016 #include <vnl/vnl_math.h>
00017
00018 #include <mipa/mipa_orientation_histogram.h>
00019 #include <mipa/mipa_sample_histo_boxes.h>
00020 #include <mipa/mipa_identity_normaliser.h>
00021 #include <mipa/mipa_block_normaliser.h>
00022
00023
00024
00025 inline void mfpf_norm_histo_vec(vnl_vector<double>& v, unsigned nA)
00026 {
00027 unsigned n=v.size();
00028 double sum = 0.0;
00029 for (unsigned i=1;i<=nA;++i) sum+=v[n-i];
00030 v/=sum;
00031 }
00032
00033
00034
00035
00036
00037 mfpf_hog_box_finder::mfpf_hog_box_finder():normaliser_(mipa_identity_normaliser())
00038 {
00039 set_defaults();
00040 }
00041
00042
00043 void mfpf_hog_box_finder::set_defaults()
00044 {
00045 step_size_=1.0;
00046 search_ni_=5;
00047 search_nj_=5;
00048 nA_=0; dA_=0.0;
00049 ns_=0; ds_=1.0;
00050
00051 nA_bins_=8;
00052 full360_=true;
00053 nc_=2;
00054 ni_=0;
00055 nj_=0;
00056 ref_x_=0;
00057 ref_y_=0;
00058
00059 overlap_f_=1.0;
00060 }
00061
00062
00063
00064
00065
00066 mfpf_hog_box_finder::~mfpf_hog_box_finder()
00067 {
00068 }
00069
00070
00071 void mfpf_hog_box_finder::set(unsigned nA_bins, bool full360,
00072 unsigned ni, unsigned nj, unsigned nc,
00073 double ref_x, double ref_y,
00074 const mfpf_vec_cost& cost,
00075 const mbl_cloneable_nzptr<mipa_vector_normaliser>& normaliser)
00076 {
00077 cost_ = cost.clone();
00078 ref_x_ = ref_x;
00079 ref_y_ = ref_y;
00080
00081 nA_bins_ = nA_bins;
00082 full360_ = full360;
00083 ni_ = ni;
00084 nj_ = nj;
00085 nc_ = nc;
00086
00087 normaliser_ = normaliser;
00088
00089
00090 mipa_vector_normaliser* pNormaliser=normaliser_.ptr();
00091 mipa_block_normaliser* pBlockNormaliser= dynamic_cast<mipa_block_normaliser*>(pNormaliser);
00092 if (pBlockNormaliser)
00093 {
00094 pBlockNormaliser->set_region(2*ni_,2*nj_);
00095 pBlockNormaliser->set_nbins(nA_bins_);
00096 }
00097
00098
00099 }
00100
00101
00102
00103 void mfpf_hog_box_finder::set_overlap_f(double f)
00104 {
00105 overlap_f_=f;
00106 }
00107
00108
00109
00110 double mfpf_hog_box_finder::radius() const
00111 {
00112
00113 double wx = ni_-1;
00114 double x2 = vcl_max(ref_x_*ref_x_,(ref_x_-wx)*(ref_x_-wx));
00115 double wy = nj_-1;
00116 double y2 = vcl_max(ref_y_*ref_y_,(ref_y_-wy)*(ref_y_-wy));
00117 double r2 = x2+y2;
00118 if (r2<=1) return 1.0;
00119 return nc_*vcl_sqrt(r2);
00120 }
00121
00122
00123
00124 double mfpf_hog_box_finder::evaluate(const vimt_image_2d_of<float>& image,
00125 const vgl_point_2d<double>& p,
00126 const vgl_vector_2d<double>& u)
00127 {
00128 vgl_vector_2d<double> u1=step_size_*u;
00129 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00130
00131 assert(image.image().nplanes()==1);
00132
00133
00134 unsigned sni = 2+2*nc_*ni_;
00135 unsigned snj = 2+2*nc_*nj_;
00136 vil_image_view<float> sample(sni,snj);
00137
00138 const vgl_point_2d<double> p0 = p-(1+nc_*ref_x_)*u1-(1+nc_*ref_y_)*v1;
00139
00140 const vimt_transform_2d& s_w2i = image.world2im();
00141 vgl_point_2d<double> im_p0 = s_w2i(p0);
00142 vgl_vector_2d<double> im_u = s_w2i.delta(p0, u1);
00143 vgl_vector_2d<double> im_v = s_w2i.delta(p0, v1);
00144
00145 vil_resample_bilin(image.image(),sample,
00146 im_p0.x(),im_p0.y(), im_u.x(),im_u.y(),
00147 im_v.x(),im_v.y(),
00148 sni,snj);
00149
00150 vil_image_view<float> histo_im;
00151 mipa_orientation_histogram(sample,histo_im,nA_bins_,nc_,full360_);
00152
00153 vnl_vector<double> v;
00154 mipa_sample_histo_boxes_3L(histo_im,0,0,v,ni_,nj_);
00155
00156 normaliser_->normalise(v);
00157
00158
00159
00160 return cost().evaluate(v);
00161 }
00162
00163
00164
00165
00166
00167
00168
00169
00170 void mfpf_hog_box_finder::evaluate_region(
00171 const vimt_image_2d_of<float>& image,
00172 const vgl_point_2d<double>& p,
00173 const vgl_vector_2d<double>& u,
00174 vimt_image_2d_of<double>& response)
00175 {
00176
00177
00178
00179 unsigned sni = (nc_+search_ni_-1)/nc_;
00180 unsigned snj = (nc_+search_nj_-1)/nc_;
00181
00182
00183 int nsi = 2*nc_*(sni + ni_)+2;
00184 int nsj = 2*nc_*(snj + nj_)+2;
00185
00186 assert(image.image().nplanes()==1);
00187
00188 vil_image_view<float> sample(2+nsi,2+nsj);
00189 vgl_vector_2d<double> u1=step_size_*u;
00190 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00191 const vgl_point_2d<double> p0 = p-(1+nc_*(sni+ref_x_))*u1
00192 -(1+nc_*(snj+ref_y_))*v1;
00193
00194 const vimt_transform_2d& s_w2i = image.world2im();
00195 vgl_point_2d<double> im_p0 = s_w2i(p0);
00196 vgl_vector_2d<double> im_u = s_w2i.delta(p0, u1);
00197 vgl_vector_2d<double> im_v = s_w2i.delta(p0, v1);
00198
00199
00200 vil_resample_bilin(image.image(),sample,
00201 im_p0.x(),im_p0.y(), im_u.x(),im_u.y(),
00202 im_v.x(),im_v.y(),
00203 nsi,nsj);
00204
00205
00206 vil_image_view<float> histo_im;
00207 mipa_orientation_histogram(sample,histo_im,nA_bins_,nc_,full360_);
00208
00209 vnl_vector<double> v;
00210
00211 int ni=1+2*sni;
00212 int nj=1+2*snj;
00213 response.image().set_size(ni,nj);
00214 double* r = response.image().top_left_ptr();
00215 vcl_ptrdiff_t r_jstep = response.image().jstep();
00216
00217 for (unsigned j=0;j<(unsigned)nj;++j,r+=r_jstep)
00218 {
00219 for (int i=0;i<ni;++i)
00220 {
00221 mipa_sample_histo_boxes_3L(histo_im,i,j,v,ni_,nj_);
00222
00223 normaliser_->normalise(v);
00224 r[i] = cost().evaluate(v);
00225 if (vnl_math_isnan(r[i]))
00226 {
00227 vcl_cerr<<is_a()<<"::evaluate_region: Response is NaN.\n"
00228 <<*this<<'\n'
00229 <<"i,j="<<i<<','<<j<<'\n'
00230 <<"v.sum()="<<v.sum()<<'\n';
00231 vcl_abort();
00232 }
00233 }
00234 }
00235
00236
00237
00238
00239
00240 const vgl_point_2d<double> p1 = p-nc_*sni*u1-nc_*snj*v1;
00241
00242 vimt_transform_2d i2w;
00243 i2w.set_similarity(vgl_point_2d<double>(nc_*u1.x(),nc_*u1.y()),p1);
00244 response.set_world2im(i2w.inverse());
00245 }
00246
00247
00248
00249
00250
00251 double mfpf_hog_box_finder::search_one_pose(const vimt_image_2d_of<float>& image,
00252 const vgl_point_2d<double>& p,
00253 const vgl_vector_2d<double>& u,
00254 vgl_point_2d<double>& new_p)
00255 {
00256
00257
00258
00259 unsigned sni = (nc_+search_ni_-1)/nc_;
00260 unsigned snj = (nc_+search_nj_-1)/nc_;
00261
00262
00263 int nsi = 2*nc_*(sni + ni_)+2;
00264 int nsj = 2*nc_*(snj + nj_)+2;
00265
00266 assert(image.image().nplanes()==1);
00267
00268 vil_image_view<float> sample(2+nsi,2+nsj);
00269 vgl_vector_2d<double> u1=step_size_*u;
00270 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00271 const vgl_point_2d<double> p0 = p-(1+nc_*(sni+ref_x_))*u1
00272 -(1+nc_*(snj+ref_y_))*v1;
00273
00274 const vimt_transform_2d& s_w2i = image.world2im();
00275 vgl_point_2d<double> im_p0 = s_w2i(p0);
00276 vgl_vector_2d<double> im_u = s_w2i.delta(p0, u1);
00277 vgl_vector_2d<double> im_v = s_w2i.delta(p0, v1);
00278
00279
00280 vil_resample_bilin(image.image(), sample,
00281 im_p0.x(),im_p0.y(), im_u.x(),im_u.y(), im_v.x(),im_v.y(),
00282 nsi, nsj);
00283
00284
00285 vil_image_view<float> histo_im;
00286 mipa_orientation_histogram(sample,histo_im,nA_bins_,nc_,full360_);
00287
00288 vnl_vector<double> v;
00289
00290 unsigned ni=1+2*sni;
00291 unsigned nj=1+2*snj;
00292
00293 double best_r=9.99e9;
00294 int best_i=0,best_j=0;
00295 for (unsigned j=0;j<nj;++j)
00296 {
00297 for (unsigned int i=0;i<ni;++i)
00298 {
00299 mipa_sample_histo_boxes_3L(histo_im,i,j,v,ni_,nj_);
00300
00301 normaliser_->normalise(v);
00302 double r = cost().evaluate(v);
00303 if (r<best_r) { best_r=r; best_i=i; best_j=j; }
00304 }
00305 }
00306
00307
00308 new_p = p+nc_*(best_i-sni)*u1+nc_*(best_j-snj)*v1;
00309 return best_r;
00310 }
00311
00312
00313 bool mfpf_hog_box_finder::is_inside(const mfpf_pose& pose,
00314 const vgl_point_2d<double>& p,
00315 double f) const
00316 {
00317
00318 vimt_transform_2d t1;
00319 t1.set_similarity(2*nc_*step_size()*pose.u(),pose.p());
00320
00321 vgl_point_2d<double> q=t1.inverse()(p);
00322 q.x()/=f; q.y()/=f;
00323 q.x()+=ref_x_;
00324 if (q.x()<0 || q.x()>(ni_-1)) return false;
00325 q.y()+=ref_y_;
00326 if (q.y()<0 || q.y()>(nj_-1)) return false;
00327 return true;
00328 }
00329
00330
00331
00332 bool mfpf_hog_box_finder::overlap(const mfpf_pose& pose1,
00333 const mfpf_pose& pose2) const
00334 {
00335 if (is_inside(pose1,pose2.p(),overlap_f_)) return true;
00336 if (is_inside(pose2,pose1.p(),overlap_f_)) return true;
00337 return false;
00338 }
00339
00340
00341
00342
00343 void mfpf_hog_box_finder::get_outline(vcl_vector<vgl_point_2d<double> >& pts) const
00344 {
00345 double s=2*nc_;
00346 pts.resize(7);
00347 vgl_vector_2d<double> r(s*ref_x_,s*ref_y_);
00348 pts[0]=vgl_point_2d<double>(0,s*nj_)-r;
00349 pts[1]=vgl_point_2d<double>(0,0);
00350 pts[2]=vgl_point_2d<double>(s*ni_,s*nj_)-r;
00351 pts[3]=vgl_point_2d<double>(0,s*nj_)-r;
00352 pts[4]=vgl_point_2d<double>(0,0)-r;
00353 pts[5]=vgl_point_2d<double>(s*ni_,0)-r;
00354 pts[6]=vgl_point_2d<double>(s*ni_,s*nj_)-r;
00355 }
00356
00357
00358
00359
00360
00361
00362 vcl_string mfpf_hog_box_finder::is_a() const
00363 {
00364 return vcl_string("mfpf_hog_box_finder");
00365 }
00366
00367
00368 mfpf_point_finder* mfpf_hog_box_finder::clone() const
00369 {
00370 return new mfpf_hog_box_finder(*this);
00371 }
00372
00373
00374
00375
00376
00377 void mfpf_hog_box_finder::print_summary(vcl_ostream& os) const
00378 {
00379 os << "{ "<<'\n';
00380 vsl_indent_inc(os);
00381 os << vsl_indent()<<"size: " << ni_ << 'x' << nj_
00382 << " nc: " << nc_ <<" nA_bins: "<<nA_bins_
00383 << " ref_pt: (" << ref_x_ << ',' << ref_y_ << ')' <<'\n';
00384 if (full360_) os << vsl_indent()<<"Angle range: 0-360"<<'\n';
00385 else os << vsl_indent()<<"Angle range: 0-180"<<'\n';
00386 #if 0
00387 if (norm_method_==0) os << vsl_indent()<<"norm: none"<<'\n';
00388 else os << vsl_indent()<<"norm: linear"<<'\n';
00389 #endif
00390
00391 vcl_cout<<"The HOG's normaliser is:"<<vcl_endl;
00392 normaliser_->print_summary(os);
00393
00394 os << vsl_indent()<< "cost: ";
00395 if (cost_.ptr()==0) os << "--"<<vcl_endl; else os << cost_<<'\n';
00396 os << vsl_indent();
00397 mfpf_point_finder::print_summary(os);
00398 os << '\n'
00399 << vsl_indent()<<"overlap_f: "<<overlap_f_<<'\n';
00400 vsl_indent_dec(os);
00401 os << vsl_indent()<<'}';
00402 }
00403
00404 short mfpf_hog_box_finder::version_no() const
00405 {
00406 return 2;
00407 }
00408
00409
00410 void mfpf_hog_box_finder::b_write(vsl_b_ostream& bfs) const
00411 {
00412 vsl_b_write(bfs,version_no());
00413 mfpf_point_finder::b_write(bfs);
00414 vsl_b_write(bfs,nc_);
00415 vsl_b_write(bfs,ni_);
00416 vsl_b_write(bfs,nj_);
00417 vsl_b_write(bfs,nA_bins_);
00418 vsl_b_write(bfs,full360_);
00419 vsl_b_write(bfs,cost_);
00420 vsl_b_write(bfs,ref_x_);
00421 vsl_b_write(bfs,ref_y_);
00422 vsl_b_write(bfs,normaliser_);
00423 vsl_b_write(bfs,overlap_f_);
00424 }
00425
00426
00427
00428
00429
00430 void mfpf_hog_box_finder::b_read(vsl_b_istream& bfs)
00431 {
00432 if (!bfs) return;
00433 short version;
00434 vsl_b_read(bfs,version);
00435 switch (version)
00436 {
00437 case (1):
00438 case (2):
00439 mfpf_point_finder::b_read(bfs);
00440 vsl_b_read(bfs,nc_);
00441 vsl_b_read(bfs,ni_);
00442 vsl_b_read(bfs,nj_);
00443 vsl_b_read(bfs,nA_bins_);
00444 vsl_b_read(bfs,full360_);
00445 vsl_b_read(bfs,cost_);
00446 vsl_b_read(bfs,ref_x_);
00447 vsl_b_read(bfs,ref_y_);
00448 vsl_b_read(bfs,normaliser_);
00449 if (version==1) overlap_f_=1.0;
00450 else vsl_b_read(bfs,overlap_f_);
00451 break;
00452 default:
00453 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&)\n"
00454 << " Unknown version number "<< version << '\n';
00455 bfs.is().clear(vcl_ios::badbit);
00456 return;
00457 }
00458 }
00459
00460
00461 bool mfpf_hog_box_finder::operator==(const mfpf_hog_box_finder& nc) const
00462 {
00463 if (!base_equality(nc)) return false;
00464 if (nc_!=nc.nc_) return false;
00465 if (ni_!=nc.ni_) return false;
00466 if (nj_!=nc.nj_) return false;
00467 if (normaliser_->is_a()!=nc.normaliser_->is_a()) return false;
00468 if (nA_bins_!=nc.nA_bins_) return false;
00469 if (full360_!=nc.full360_) return false;
00470 if (vcl_fabs(ref_x_-nc.ref_x_)>1e-6) return false;
00471 if (vcl_fabs(ref_y_-nc.ref_y_)>1e-6) return false;
00472 if (vcl_fabs(overlap_f_-nc.overlap_f_)>1e-6) return false;
00473
00474 return true;
00475 }
00476
00477