00001 #include "mfpf_grad_corr2d.h"
00002
00003
00004
00005
00006
00007 #include <vsl/vsl_binary_loader.h>
00008 #include <vcl_cmath.h>
00009 #include <vcl_algorithm.h>
00010 #include <vcl_cassert.h>
00011
00012 #include <vil/vil_resample_bilin.h>
00013 #include <vil/io/vil_io_image_view.h>
00014 #include <vil/vil_math.h>
00015 #include <vnl/vnl_math.h>
00016 #include <vgl/vgl_point_2d.h>
00017 #include <vgl/vgl_vector_2d.h>
00018
00019 #include <vil/vil_convert.h>
00020
00021
00022
00023
00024
00025 mfpf_grad_corr2d::mfpf_grad_corr2d()
00026 {
00027 set_defaults();
00028 }
00029
00030
00031 void mfpf_grad_corr2d::set_defaults()
00032 {
00033 step_size_=1.0;
00034 search_ni_=5;
00035 search_nj_=5;
00036 nA_=0; dA_=0.0;
00037 ns_=0; ds_=1.0;
00038 ref_x_ = 0.0;
00039 ref_y_ = 0.0;
00040 overlap_f_=1.0;
00041 }
00042
00043
00044
00045
00046
00047 mfpf_grad_corr2d::~mfpf_grad_corr2d()
00048 {
00049 }
00050
00051
00052 void mfpf_grad_corr2d::set(const vil_image_view<double>& kx,
00053 const vil_image_view<double>& ky,
00054 double ref_x, double ref_y)
00055 {
00056
00057 unsigned ni,nj;
00058 ni=kx.ni(); nj=kx.nj();
00059 kernel_x_.set_size(ni,nj);
00060 double sum_x=0.0,ss_x=0.0;
00061 for (unsigned j=0;j<nj;++j)
00062 for (unsigned i=0;i<ni;++i)
00063 {
00064 kernel_x_(i,j)=kx(i,j);
00065 sum_x+=kx(i,j); ss_x+=kx(i,j)*kx(i,j);
00066 }
00067
00068 assert(!vnl_math_isnan(sum_x));
00069
00070
00071 double mean_x=sum_x/(ni*nj);
00072 ss_x-=(mean_x*mean_x*ni*nj);
00073 assert(ss_x>1e-6);
00074 double s_x=1.0;
00075 if (ss_x>0) s_x = vcl_sqrt(1.0/ss_x);
00076 vil_math_scale_and_offset_values(kernel_x_,s_x,-s_x*mean_x);
00077
00078
00079 ni=ky.ni(); nj=ky.nj();
00080 kernel_y_.set_size(ni,nj);
00081 double sum_y=0.0,ss_y=0.0;
00082 for (unsigned j=0;j<nj;++j)
00083 for (unsigned i=0;i<ni;++i)
00084 {
00085 kernel_y_(i,j)=ky(i,j);
00086 sum_y+=ky(i,j); ss_y+=ky(i,j)*ky(i,j);
00087 }
00088
00089 assert(!vnl_math_isnan(sum_y));
00090
00091
00092 double mean_y=sum_y/(ni*nj);
00093 ss_y-=(mean_y*mean_y*ni*nj);
00094 assert(ss_y>1e-6);
00095 double s_y=1.0;
00096 if (ss_y>0) s_y = vcl_sqrt(1.0/ss_y);
00097 vil_math_scale_and_offset_values(kernel_y_,s_y,-s_y*mean_y);
00098
00099 ref_x_ = ref_x;
00100 ref_y_ = ref_y;
00101 }
00102
00103
00104 void mfpf_grad_corr2d::set(const vil_image_view<double>& kx,
00105 const vil_image_view<double>& ky)
00106 {
00107 set(kx, ky, 0.5*(kx.ni()-1.0), 0.5*(kx.nj()-1.0));
00108 }
00109
00110
00111 bool mfpf_grad_corr2d::set_model(const vcl_vector<double>& v)
00112 {
00113
00114 assert( v.size() == model_dim() );
00115
00116
00117 vil_image_view<double> im_x( kernel_x_.ni(), kernel_x_.nj() );
00118 unsigned vec_ind=0;
00119 for (unsigned j=0;j<kernel_x_.nj();++j)
00120 for (unsigned i=0;i<kernel_x_.ni();++i,++vec_ind)
00121 im_x(i,j)=v[vec_ind];
00122
00123
00124 vil_image_view<double> im_y( kernel_y_.ni(), kernel_y_.nj() );
00125 for (unsigned j=0;j<kernel_y_.nj();++j)
00126 for (unsigned i=0;i<kernel_y_.nj();++i,++vec_ind)
00127 im_y(i,j)=v[vec_ind];
00128
00129
00130 set(im_x,im_y);
00131
00132 return true;
00133 }
00134
00135
00136 unsigned mfpf_grad_corr2d::model_dim()
00137 {
00138 return kernel_x_.ni()*kernel_x_.nj() + kernel_y_.ni()*kernel_y_.nj();
00139 }
00140
00141
00142 void mfpf_grad_corr2d::get_kernel_vector(vcl_vector<double>& v) const
00143 {
00144
00145 v.resize( 2*kernel_x_.ni()*kernel_x_.nj() );
00146
00147
00148 unsigned vec_ind=0;
00149 for (unsigned j=0;j<kernel_x_.nj();++j)
00150 for (unsigned i=0;i<kernel_x_.ni();++i,++vec_ind)
00151 v[vec_ind]=kernel_x_(i,j);
00152
00153 for (unsigned j=0;j<kernel_y_.nj();++j)
00154 for (unsigned i=0;i<kernel_y_.ni();++i,++vec_ind)
00155 v[vec_ind]=kernel_y_(i,j);
00156 }
00157
00158
00159
00160 void mfpf_grad_corr2d::set_overlap_f(double f)
00161 {
00162 overlap_f_=f;
00163 }
00164
00165
00166
00167 inline double norm_corr(const double* im1, const double* im2,
00168 vcl_ptrdiff_t jstep1, vcl_ptrdiff_t jstep2,
00169 unsigned ni, unsigned nj)
00170 {
00171 double sum1=0.0,sum2=0.0,sum_sq=0.0;
00172 for (unsigned j=0;j<nj;++j,im1+=jstep1,im2+=jstep2)
00173 for (unsigned i=0;i<ni;++i)
00174 {
00175 sum1+=im1[i]*im2[i];
00176 sum2+=im1[i];
00177 sum_sq+=im1[i]*im1[i];
00178 }
00179 unsigned n=ni*nj;
00180 double mean = sum2/n;
00181 double ss = vcl_max(1e-6,sum_sq-n*mean*mean);
00182 double s = vcl_sqrt(ss);
00183
00184 return sum1/s;
00185 }
00186
00187 #if 0 // static (=local) function not used in this file
00188 static void normalize(vil_image_view<double>& im)
00189 {
00190 unsigned ni=im.ni(),nj=im.nj();
00191 double sum=0.0,ss=0.0;
00192 for (unsigned j=0;j<nj;++j)
00193 for (unsigned i=0;i<ni;++i)
00194 {
00195 sum+=im(i,j); ss+=im(i,j)*im(i,j);
00196 }
00197
00198 assert(!vnl_math_isnan(sum));
00199
00200 if (ss<1e-6)
00201 {
00202 vcl_cerr<<"Warning: Almost flat region in mfpf_grad_corr2d_builder\n"
00203 <<" Size: "<<ni<<" x "<<nj<<vcl_endl;
00204 }
00205
00206
00207 double mean=sum/(ni*nj);
00208 ss-=(mean*mean*ni*nj);
00209 double s=1.0;
00210 if (ss>0) s = vcl_sqrt(1.0/ss);
00211 vil_math_scale_and_offset_values(im,s,-s*mean);
00212 }
00213 #endif // 0
00214
00215 void mfpf_grad_corr2d::diff_image(const vimt_image_2d_of<float>& image,
00216 const vgl_point_2d<double>& p,
00217 const vgl_vector_2d<double>& u,
00218 vil_image_view<double>& grad_x,
00219 vil_image_view<double>& grad_y,
00220 int search_ni, int search_nj)
00221 {
00222 assert(image.image().size()>0);
00223
00224 unsigned ni=kernel_x_.ni();
00225 unsigned nj=kernel_x_.nj();
00226 unsigned nsi = ni + 2*search_ni;
00227 unsigned nsj = nj + 2*search_nj;
00228
00229 vgl_vector_2d<double> u1=step_size_*u;
00230 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00231
00232 const vimt_transform_2d& s_w2i = image.world2im();
00233 vgl_point_2d<double> p0, im_p0;
00234 vgl_vector_2d<double> im_u, im_v;
00235
00236 vil_image_view<float> sample;
00237
00238
00239
00240 p0 = p - (ref_x_+search_ni+0.5)*u1 - (ref_y_+search_nj)*v1;
00241 im_p0 = s_w2i(p0);
00242 im_u = s_w2i.delta(p0, u1);
00243 im_v = s_w2i.delta(p0, v1);
00244 vil_resample_bilin(image.image(),sample, im_p0.x(),im_p0.y(),
00245 im_u.x(),im_u.y(), im_v.x(),im_v.y(), nsi+1,nsj);
00246
00247
00248 grad_x.set_size( nsi,nsj );
00249
00250 const float* s1 = sample.top_left_ptr();
00251 const float* s2 = sample.top_left_ptr()+sample.istep();
00252 vcl_ptrdiff_t s_jstep = sample.jstep();
00253
00254 double* kx = grad_x.top_left_ptr();
00255 vcl_ptrdiff_t kx_jstep = grad_x.jstep();
00256
00257 for (unsigned j=0;j<nsj;++j,kx+=kx_jstep,s1+=s_jstep,s2+=s_jstep)
00258 for (unsigned i=0;i<nsi;++i)
00259 *(kx+i) = *(s2+i) - *(s1+i);
00260
00261
00262
00263 p0 = p - (ref_x_+search_ni)*u1 - (ref_y_+search_nj+0.5)*v1;
00264 im_p0 = s_w2i(p0);
00265 im_u = s_w2i.delta(p0, u1);
00266 im_v = s_w2i.delta(p0, v1);
00267 vil_resample_bilin(image.image(),sample, im_p0.x(),im_p0.y(),
00268 im_u.x(),im_u.y(), im_v.x(),im_v.y(), nsi,nsj+1);
00269
00270
00271 grad_y.set_size(nsi,nsj);
00272
00273 s1 = sample.top_left_ptr();
00274 s2 = sample.top_left_ptr()+sample.jstep();
00275 s_jstep = sample.jstep();
00276
00277 double* ky = grad_y.top_left_ptr();
00278 vcl_ptrdiff_t ky_jstep = grad_y.jstep();
00279
00280 for (unsigned j=0;j<nsj;++j,ky+=ky_jstep,s1+=s_jstep,s2+=s_jstep)
00281 for (unsigned i=0;i<nsi;++i)
00282 *(ky+i) = *(s2+i) - *(s1+i);
00283 }
00284
00285
00286 void mfpf_grad_corr2d::get_sample_vector(const vimt_image_2d_of<float>& image,
00287 const vgl_point_2d<double>& p,
00288 const vgl_vector_2d<double>& u,
00289 vcl_vector<double>& v)
00290 {
00291 assert(image.image().size()>0);
00292
00293 vil_image_view<double> grad_x, grad_y;
00294 diff_image(image,p,u,grad_x,grad_y);
00295
00296 v.resize( model_dim() );
00297 unsigned v_ind=0;
00298
00299 for (unsigned j=0;j<grad_x.nj();j++)
00300 for (unsigned i=0;i<grad_x.ni();i++,v_ind++)
00301 v[v_ind] = grad_x(i,j);
00302
00303 for (unsigned j=0;j<grad_y.nj();j++)
00304 for (unsigned i=0;i<grad_y.ni();i++,v_ind++)
00305 v[v_ind] = grad_y(i,j);
00306 }
00307
00308
00309 double mfpf_grad_corr2d::radius() const
00310 {
00311
00312 double wx = kernel_x_.ni()-1;
00313 double x2 = vcl_max(ref_x_*ref_x_,(ref_x_-wx)*(ref_x_-wx));
00314 double wy = kernel_x_.nj()-1;
00315 double y2 = vcl_max(ref_y_*ref_y_,(ref_y_-wy)*(ref_y_-wy));
00316 double r2 = x2+y2;
00317 if (r2<=1) return 1.0;
00318 return vcl_sqrt(r2);
00319 }
00320
00321
00322
00323 double mfpf_grad_corr2d::evaluate(const vimt_image_2d_of<float>& image,
00324 const vgl_point_2d<double>& p,
00325 const vgl_vector_2d<double>& u)
00326 {
00327 vil_image_view<double> grad_x, grad_y;
00328 diff_image(image,p,u,grad_x,grad_y);
00329
00330 return 2.0-norm_corr(grad_x.top_left_ptr(),kernel_x_.top_left_ptr(),
00331 grad_x.jstep(),kernel_x_.jstep(),
00332 kernel_x_.ni(),kernel_x_.nj())
00333 -norm_corr(grad_y.top_left_ptr(),kernel_y_.top_left_ptr(),
00334 grad_y.jstep(),kernel_y_.jstep(),
00335 kernel_y_.ni(),kernel_y_.nj());
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345 void mfpf_grad_corr2d::evaluate_region(
00346 const vimt_image_2d_of<float>& image,
00347 const vgl_point_2d<double>& p,
00348 const vgl_vector_2d<double>& u,
00349 vimt_image_2d_of<double>& response)
00350 {
00351 assert(image.image().nplanes()==1);
00352
00353 vil_image_view<double> grad_x, grad_y;
00354 diff_image(image,p,u,grad_x,grad_y,
00355 search_ni_,search_nj_);
00356
00357 int ni=1+2*search_ni_;
00358 int nj=1+2*search_nj_;
00359 response.image().set_size(ni,nj);
00360
00361 double* r = response.image().top_left_ptr();
00362 const double* kx = kernel_x_.top_left_ptr();
00363 const double* ky = kernel_y_.top_left_ptr();
00364 const double* sx = grad_x.top_left_ptr();
00365 const double* sy = grad_y.top_left_ptr();
00366 vcl_ptrdiff_t r_jstep = response.image().jstep();
00367 vcl_ptrdiff_t sx_jstep = grad_x.jstep();
00368 vcl_ptrdiff_t sy_jstep = grad_y.jstep();
00369 vcl_ptrdiff_t kx_jstep = kernel_x_.jstep();
00370 vcl_ptrdiff_t ky_jstep = kernel_y_.jstep();
00371
00372 for (int j=0;j<nj;++j,r+=r_jstep,sx+=sx_jstep,sy+=sy_jstep)
00373 {
00374 for (int i=0;i<ni;++i)
00375 {
00376 r[i] = 2.0-norm_corr(sx+i,kx,sx_jstep,kx_jstep,
00377 kernel_x_.ni(),kernel_x_.nj())
00378 -norm_corr(sy+i,ky,sy_jstep,ky_jstep,
00379 kernel_y_.ni(),kernel_y_.nj());
00380 }
00381 }
00382
00383
00384
00385
00386
00387 vgl_vector_2d<double> u1=step_size_*u;
00388 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00389 const vgl_point_2d<double> p1 = p-search_ni_*u1-search_nj_*v1;
00390
00391 vimt_transform_2d i2w;
00392 i2w.set_similarity(vgl_point_2d<double>(u1.x(),u1.y()),p1);
00393 response.set_world2im(i2w.inverse());
00394 }
00395
00396
00397
00398
00399
00400 double mfpf_grad_corr2d::search_one_pose(
00401 const vimt_image_2d_of<float>& image,
00402 const vgl_point_2d<double>& p,
00403 const vgl_vector_2d<double>& u,
00404 vgl_point_2d<double>& new_p)
00405 {
00406 assert(image.image().nplanes()==1);
00407
00408 vil_image_view<double> grad_x, grad_y;
00409 diff_image(image,p,u,grad_x,grad_y,
00410 search_ni_,search_nj_);
00411
00412 const double* kx = kernel_x_.top_left_ptr();
00413 const double* ky = kernel_y_.top_left_ptr();
00414 const double* sx = grad_x.top_left_ptr();
00415 const double* sy = grad_y.top_left_ptr();
00416 vcl_ptrdiff_t sx_jstep = grad_x.jstep();
00417 vcl_ptrdiff_t sy_jstep = grad_y.jstep();
00418 vcl_ptrdiff_t kx_jstep = kernel_x_.jstep();
00419 vcl_ptrdiff_t ky_jstep = kernel_y_.jstep();
00420
00421 int ni=1+2*search_ni_;
00422 int nj=1+2*search_nj_;
00423
00424 double best_r=-9e99;
00425 int best_i=-1,best_j=-1;
00426 for (int j=0;j<nj;++j,sx+=sx_jstep,sy+=sy_jstep)
00427 {
00428 for (int i=0;i<ni;++i)
00429 {
00430 double r = norm_corr(sx+i,kx,sx_jstep,kx_jstep,
00431 kernel_x_.ni(),kernel_x_.nj())
00432 + norm_corr(sy+i,ky,sy_jstep,ky_jstep,
00433 kernel_y_.ni(),kernel_y_.nj());
00434 if (r>best_r) { best_r=r; best_i=i; best_j=j; }
00435 }
00436 }
00437
00438
00439 vgl_vector_2d<double> u1=step_size_*u;
00440 vgl_vector_2d<double> v1(-u1.y(),u1.x());
00441 new_p = p+(best_i-search_ni_)*u1+(best_j-search_nj_)*v1;
00442 return 2.0 - best_r;
00443 }
00444
00445
00446 bool mfpf_grad_corr2d::is_inside(const mfpf_pose& pose,
00447 const vgl_point_2d<double>& p,
00448 double f) const
00449 {
00450
00451 vimt_transform_2d t1;
00452 t1.set_similarity(step_size()*pose.u(),pose.p());
00453
00454 vgl_point_2d<double> q=t1.inverse()(p);
00455 q.x()/=f; q.y()/=f;
00456 q.x()+=ref_x_;
00457 if (q.x()<0 || q.x()>(kernel_x_.ni()-1)) return false;
00458 q.y()+=ref_y_;
00459 if (q.y()<0 || q.y()>(kernel_x_.nj()-1)) return false;
00460 return true;
00461 }
00462
00463
00464
00465 bool mfpf_grad_corr2d::overlap(const mfpf_pose& pose1,
00466 const mfpf_pose& pose2) const
00467 {
00468 if (is_inside(pose1,pose2.p(),overlap_f_)) return true;
00469 if (is_inside(pose2,pose1.p(),overlap_f_)) return true;
00470 return false;
00471 }
00472
00473
00474
00475
00476 void mfpf_grad_corr2d::get_outline(vcl_vector<vgl_point_2d<double> >& pts) const
00477 {
00478 pts.resize(7);
00479 int roi_ni=kernel_x_.ni();
00480 int roi_nj=kernel_x_.nj();
00481 vgl_vector_2d<double> r(ref_x_,ref_y_);
00482 pts[0]=vgl_point_2d<double>(0,roi_nj)-r;
00483 pts[1]=vgl_point_2d<double>(0,0);
00484 pts[2]=vgl_point_2d<double>(roi_ni,roi_nj)-r;
00485 pts[3]=vgl_point_2d<double>(0,roi_nj)-r;
00486 pts[4]=vgl_point_2d<double>(0,0)-r;
00487 pts[5]=vgl_point_2d<double>(roi_ni,0)-r;
00488 pts[6]=vgl_point_2d<double>(roi_ni,roi_nj)-r;
00489 }
00490
00491
00492 void mfpf_grad_corr2d::get_image_of_model(vimt_image_2d_of<vxl_byte>& image) const
00493 {
00494
00495 vil_image_view<double> kx_sqr,ky_sqr,kernel;
00496 vil_math_sum_sqr(kernel_x_,kx_sqr);
00497 vil_math_sum_sqr(kernel_y_,ky_sqr);
00498 vil_math_image_sum(kx_sqr,ky_sqr,kernel);
00499 vil_math_sqrt(kernel);
00500
00501 vil_convert_stretch_range(kernel,image.image());
00502 vimt_transform_2d ref2im;
00503 ref2im.set_zoom_only(1.0/step_size_,ref_x_,ref_y_);
00504 image.set_world2im(ref2im);
00505 }
00506
00507
00508
00509
00510
00511 vcl_string mfpf_grad_corr2d::is_a() const
00512 {
00513 return vcl_string("mfpf_grad_corr2d");
00514 }
00515
00516
00517 mfpf_point_finder* mfpf_grad_corr2d::clone() const
00518 {
00519 return new mfpf_grad_corr2d(*this);
00520 }
00521
00522
00523
00524
00525
00526 void mfpf_grad_corr2d::print_summary(vcl_ostream& os) const
00527 {
00528 os << "{ size: " << kernel_x_.ni() << " x " << kernel_x_.nj();
00529 mfpf_point_finder::print_summary(os);
00530 os << " overlap_f: " << overlap_f_ << " }";
00531 }
00532
00533 void mfpf_grad_corr2d::b_write(vsl_b_ostream& bfs) const
00534 {
00535 vsl_b_write(bfs,version_no());
00536 mfpf_point_finder::b_write(bfs);
00537 vsl_b_write(bfs,kernel_x_);
00538 vsl_b_write(bfs,kernel_y_);
00539 vsl_b_write(bfs,ref_x_);
00540 vsl_b_write(bfs,ref_y_);
00541 vsl_b_write(bfs,overlap_f_);
00542 }
00543
00544 short mfpf_grad_corr2d::version_no() const
00545 {
00546 return 2;
00547 }
00548
00549
00550
00551
00552
00553 void mfpf_grad_corr2d::b_read(vsl_b_istream& bfs)
00554 {
00555 if (!bfs) return;
00556 short version;
00557 vsl_b_read(bfs,version);
00558 switch (version)
00559 {
00560 case (1):
00561 case (2):
00562 mfpf_point_finder::b_read(bfs);
00563 vsl_b_read(bfs,kernel_x_);
00564 vsl_b_read(bfs,kernel_y_);
00565 vsl_b_read(bfs,ref_x_);
00566 vsl_b_read(bfs,ref_y_);
00567 if (version==1) overlap_f_=1.0;
00568 else vsl_b_read(bfs,overlap_f_);
00569 break;
00570 default:
00571 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&)\n"
00572 << " Unknown version number "<< version << vcl_endl;
00573 bfs.is().clear(vcl_ios::badbit);
00574 return;
00575 }
00576 }
00577
00578
00579 bool mfpf_grad_corr2d::operator==(const mfpf_grad_corr2d& nc) const
00580 {
00581 if (!base_equality(nc)) return false;
00582 if (kernel_x_.ni()!=nc.kernel_x_.ni()) return false;
00583 if (kernel_x_.nj()!=nc.kernel_x_.nj()) return false;
00584 if (kernel_y_.ni()!=nc.kernel_y_.ni()) return false;
00585 if (kernel_y_.nj()!=nc.kernel_y_.nj()) return false;
00586 if (vcl_fabs(ref_x_-nc.ref_x_)>1e-6) return false;
00587 if (vcl_fabs(ref_y_-nc.ref_y_)>1e-6) return false;
00588 if (kernel_x_.size()!=nc.kernel_x_.size()) return false;
00589 if (kernel_x_.size()==0) return true;
00590 if (kernel_y_.size()!=nc.kernel_y_.size()) return false;
00591 if (kernel_y_.size()==0) return true;
00592 if (vil_math_ssd(kernel_x_,nc.kernel_x_,double(0))>1e-4) return false;
00593 return (vil_math_ssd(kernel_y_,nc.kernel_y_,double(0))<1e-4);
00594 }
00595
00596