00001
00002 #include "mbl_thin_plate_spline_2d.h"
00003
00004
00005
00006
00007
00008 #include <vcl_cmath.h>
00009 #include <vcl_cstdlib.h>
00010 #include <vsl/vsl_indent.h>
00011 #include <vsl/vsl_vector_io.h>
00012 #include <vnl/vnl_math.h>
00013 #include <vnl/algo/vnl_svd.h>
00014 #include <vnl/io/vnl_io_vector.h>
00015 #include <vnl/io/vnl_io_matrix.h>
00016 #include <vgl/vgl_vector_2d.h>
00017 #include <vgl/io/vgl_io_point_2d.h>
00018 #include <mbl/mbl_matxvec.h>
00019
00020
00021
00022
00023
00024
00025
00026
00027 mbl_thin_plate_spline_2d::mbl_thin_plate_spline_2d()
00028 : Wx_(0),Wy_(0),
00029 Ax0_(0),AxX_(1),AxY_(0),Ay0_(0),AyX_(0),AyY_(1),
00030 energy_x_(0),energy_y_(0),return_pure_affine_(false)
00031 {
00032 }
00033
00034
00035
00036
00037
00038 mbl_thin_plate_spline_2d::~mbl_thin_plate_spline_2d()
00039 {
00040 }
00041
00042
00043 #if 0 // unused
00044 inline double r2lnr(const vgl_point_2d<double>& pt)
00045 {
00046 double r2 = pt.x() * pt.x() + pt.y() * pt.y();
00047 if (r2>1e-8) return 0.5 * r2 * vcl_log(r2);
00048 else return 0;
00049 }
00050 #endif
00051
00052 inline double r2lnr(const vgl_vector_2d<double>& pt)
00053 {
00054 double r2 = pt.x() * pt.x() + pt.y() * pt.y();
00055 if (r2>1e-8) return 0.5 * r2 * vcl_log(r2);
00056 else return 0;
00057 }
00058
00059 inline double r2lnr(double x, double y)
00060 {
00061 double r2 = x * x + y * y;
00062 if (r2>1e-8) return 0.5 * r2 * vcl_log(r2);
00063 else return 0;
00064 }
00065
00066
00067
00068
00069 static void build_K_part(vnl_matrix<double>& L,
00070 const vcl_vector<vgl_point_2d<double> >& pts)
00071 {
00072 unsigned int n = pts.size();
00073 if ( (L.rows()!=n+3) | (L.columns()!=n+3) ) L.set_size(n+3,n+3);
00074
00075 const vgl_point_2d<double> * pts_data = &pts[0];
00076 double** K_data = L.data_array();
00077
00078
00079 for (unsigned int i=0;i<n;i++)
00080 K_data[i][i] = 0;
00081
00082 for (unsigned int i=1;i<n;i++)
00083 for (unsigned int j=0;j<i;j++)
00084 {
00085 K_data[i][j] = K_data[j][i] = r2lnr(pts_data[i]-pts_data[j]);
00086 }
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096 static void build_L(vnl_matrix<double>& L, const vcl_vector<vgl_point_2d<double> >& pts)
00097 {
00098 int i,j;
00099
00100 build_K_part(L,pts);
00101
00102 int n = pts.size();
00103
00104 const vgl_point_2d<double> * pts_data = &pts[0];
00105 double** L_data = L.data_array();
00106
00107
00108
00109 for (i=0;i<n;i++)
00110 {
00111 L_data[i][n] = 1;
00112 L_data[i][n+1] = pts_data[i].x();
00113 L_data[i][n+2] = pts_data[i].y();
00114
00115 L_data[n][i] = 1;
00116 L_data[n+1][i] = pts_data[i].x();
00117 L_data[n+2][i] = pts_data[i].y();
00118 }
00119
00120
00121 for (i=n;i<n+3;i++)
00122 for (j=n;j<n+3;j++)
00123 L_data[i][j] = 0;
00124 }
00125
00126
00127 void mbl_thin_plate_spline_2d::build_pure_affine(
00128 const vcl_vector<vgl_point_2d<double> >& source_pts,
00129 const vcl_vector<vgl_point_2d<double> >& dest_pts)
00130 {
00131 int n=source_pts.size();
00132 L_inv_.set_size(0,0);
00133 if (n==0)
00134 {
00135
00136 Ax0_ = 0;
00137 Ay0_ = 0;
00138 AxX_ = 1; AxY_ = 0;
00139 AyX_ = 0; AyY_ = 1;
00140
00141 Wx_.set_size(0);
00142 Wy_.set_size(0);
00143
00144 src_pts_.resize(0);
00145
00146 return;
00147 }
00148
00149 if (n==1)
00150 {
00151
00152 Ax0_ = dest_pts[0].x() - source_pts[0].x();
00153 Ay0_ = dest_pts[0].y() - source_pts[0].y();
00154 Wx_.set_size(0);
00155 Wy_.set_size(0);
00156 AxX_ = 1; AxY_ = 0;
00157 AyX_ = 0; AyY_ = 1;
00158 src_pts_.resize(0);
00159
00160 return;
00161 }
00162
00163 if (n==2)
00164 {
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 vgl_point_2d<double> x1,x2,u1,u2;
00178 double dx,dy,du,dv;
00179 double a,b;
00180
00181 x1 = source_pts[0];
00182 x2 = source_pts[1];
00183 u1 = dest_pts[0];
00184 u2 = dest_pts[1];
00185
00186 dx = x2.x() - x1.x();
00187 dy = x2.y() - x1.y();
00188 du = u2.x() - u1.x();
00189 dv = u2.y() - u1.y();
00190
00191 double L2=(dx * dx + dy * dy);
00192 a = (dx * du + dy * dv)/L2;
00193 b = (dv * dx - du * dy)/L2;
00194
00195 AxX_ = a;
00196 AxY_ = -b;
00197 AyX_ = b;
00198 AyY_ = a;
00199 Ax0_ = u1.x() - (a * x1.x() - b * x1.y());
00200 Ay0_ = u1.y() - (b * x1.x() + a * x1.y());
00201
00202 Wx_.set_size(0);
00203 Wy_.set_size(0);
00204 src_pts_.resize(0);
00205
00206 return;
00207 }
00208
00209
00210 if (n==3)
00211 {
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 vgl_point_2d<double> x0,x1,x2,u0,u1,u2;
00222
00223 x0 = source_pts[0];
00224 x1 = source_pts[1];
00225 x2 = source_pts[2];
00226 u0 = dest_pts[0];
00227 u1 = dest_pts[1];
00228 u2 = dest_pts[2];
00229
00230 double dx1 = x1.x() - x0.x();
00231 double dy1 = x1.y() - x0.y();
00232 double dx2 = x2.x() - x0.x();
00233 double dy2 = x2.y() - x0.y();
00234
00235 double du1 = u1.x() - u0.x();
00236 double dv1 = u1.y() - u0.y();
00237 double du2 = u2.x() - u0.x();
00238 double dv2 = u2.y() - u0.y();
00239
00240 double L2=(dx1 * dy2 - dy1 * dx2);
00241 double a = (du1*dy2 - du2*dy1)/L2;
00242 double b = (du2*dx1 - du1*dx2)/L2;
00243 double c = (dv1*dy2 - dv2*dy1)/L2;
00244 double d = (dv2*dx1 - dv1*dx2)/L2;
00245
00246 AxX_ = a;
00247 AxY_ = b;
00248 AyX_ = c;
00249 AyY_ = d;
00250 Ax0_ = u0.x() - (a * x0.x() + b * x0.y());
00251 Ay0_ = u0.y() - (c * x0.x() + d * x0.y());
00252
00253 Wx_.set_size(0);
00254 Wy_.set_size(0);
00255 src_pts_.resize(0);
00256
00257 return;
00258 }
00259 }
00260
00261
00262 void mbl_thin_plate_spline_2d::set_params(const vnl_vector<double>& W1,
00263 const vnl_vector<double>& W2)
00264 {
00265 int n = W1.size()-3;
00266
00267 if (int(Wx_.size()) < n) Wx_.set_size(n);
00268 if (int(Wy_.size()) < n) Wy_.set_size(n);
00269
00270 double *Wx_data=Wx_.data_block();
00271 double *Wy_data=Wy_.data_block();
00272 const double *W1_data=W1.data_block();
00273 const double *W2_data=W2.data_block();
00274
00275 for (int i=0;i<n;i++)
00276 {
00277 Wx_data[i] = W1_data[i];
00278 Wy_data[i] = W2_data[i];
00279 }
00280
00281 Ax0_ = W1_data[n];
00282 AxX_ = W1_data[n+1];
00283 AxY_ = W1_data[n+2];
00284
00285 Ay0_ = W2_data[n];
00286 AyX_ = W2_data[n+1];
00287 AyY_ = W2_data[n+2];
00288 }
00289
00290 void mbl_thin_plate_spline_2d::compute_energy(vnl_vector<double>& W1,
00291 vnl_vector<double>& W2,
00292 const vnl_matrix<double>& L)
00293 {
00294 int n = W1.size()-3;
00295 double *W1_data=W1.data_block();
00296 double *W2_data=W2.data_block();
00297
00298
00299
00300 W1_data[n]=0.0;
00301 W1_data[n+1]=0.0;
00302 W1_data[n+2]=0.0;
00303 vnl_vector<double> LW;
00304 mbl_matxvec_prod_mv(L,W1,LW);
00305 energy_x_ = dot_product(W1,LW) / (8*vnl_math::pi);
00306
00307
00308 W2_data[n]=0.0;
00309 W2_data[n+1]=0.0;
00310 W2_data[n+2]=0.0;
00311 mbl_matxvec_prod_mv(L,W2,LW);
00312 energy_y_ = dot_product(W2,LW) / (8*vnl_math::pi);
00313 }
00314
00315 void mbl_thin_plate_spline_2d::set_up_rhs(vnl_vector<double>& Bx,
00316 vnl_vector<double>& By,
00317 const vcl_vector<vgl_point_2d<double> >& dest_pts)
00318 {
00319 int n =dest_pts.size();
00320
00321 Bx.set_size(n+3);
00322 By.set_size(n+3);
00323 double* Bx_data=Bx.data_block();
00324 double* By_data=By.data_block();
00325 const vgl_point_2d<double> *d_pts_data=&dest_pts[0];
00326
00327 for (int i=0;i<n;i++)
00328 {
00329 Bx_data[i] = d_pts_data[i].x();
00330 By_data[i] = d_pts_data[i].y();
00331 }
00332 for (int i=n;i<n+3;i++)
00333 {
00334 Bx_data[i] = 0;
00335 By_data[i] = 0;
00336 }
00337 }
00338
00339 void mbl_thin_plate_spline_2d::build(const vcl_vector<vgl_point_2d<double> >& source_pts,
00340 const vcl_vector<vgl_point_2d<double> >& dest_pts,
00341 bool compute_the_energy)
00342 {
00343
00344
00345 unsigned int n=source_pts.size();
00346 if (dest_pts.size() != n)
00347 {
00348 vcl_cerr<<"mbl_thin_plate_spline_2d::build - incompatible number of points.\n";
00349 vcl_abort();
00350 }
00351
00352 L_inv_.set_size(0,0);
00353
00354 if (n<=3)
00355 {
00356 build_pure_affine(source_pts,dest_pts);
00357 return;
00358 }
00359
00360 src_pts_ = source_pts;
00361
00362 vnl_matrix<double> L;
00363 vnl_vector<double> Bx(n+3), W1(n+3);
00364 vnl_vector<double> By(n+3), W2(n+3);
00365
00366 build_L(L,source_pts);
00367
00368 set_up_rhs(Bx,By,dest_pts);
00369
00370
00371
00372
00373 {
00374 vnl_svd<double> svd(L);
00375 svd.solve(Bx.data_block(),W1.data_block());
00376 svd.solve(By.data_block(),W2.data_block());
00377 }
00378
00379 set_params(W1,W2);
00380 if (compute_the_energy)
00381 compute_energy(W1,W2,L);
00382 }
00383
00384
00385
00386
00387 void mbl_thin_plate_spline_2d::set_source_pts(const vcl_vector<vgl_point_2d<double> >& source_pts)
00388 {
00389 unsigned int n=source_pts.size();
00390 src_pts_ = source_pts;
00391
00392 if (n<=3)
00393 {
00394 L_inv_.set_size(0,0);
00395 return;
00396 }
00397
00398 vnl_matrix<double> L;
00399 build_L(L,source_pts);
00400
00401
00402
00403
00404 {
00405 vnl_svd<double> svd(L);
00406 L_inv_ = svd.inverse();
00407 }
00408 }
00409
00410
00411 void mbl_thin_plate_spline_2d::build(const vcl_vector<vgl_point_2d<double> >& dest_pts)
00412 {
00413 unsigned int n=src_pts_.size();
00414 if (dest_pts.size() != n)
00415 {
00416 vcl_cerr<<"mbl_thin_plate_spline_2d::build - incompatible number of points.\n";
00417 vcl_abort();
00418 }
00419
00420 if (n<=3)
00421 {
00422 build_pure_affine(src_pts_,dest_pts);
00423 return;
00424 }
00425
00426 vnl_vector<double> Bx(n+3), W1(n+3);
00427 vnl_vector<double> By(n+3), W2(n+3);
00428
00429 set_up_rhs(Bx,By,dest_pts);
00430
00431 mbl_matxvec_prod_mv(L_inv_,Bx,W1);
00432 mbl_matxvec_prod_mv(L_inv_,By,W2);
00433
00434 set_params(W1,W2);
00435 energy_x_ = -1;
00436 energy_y_ = -1;
00437 }
00438
00439
00440 vgl_point_2d<double> mbl_thin_plate_spline_2d::operator()(double x, double y) const
00441 {
00442 unsigned int n = src_pts_.size();
00443
00444 double x_sum = Ax0_ + AxX_ * x + AxY_ * y;
00445 double y_sum = Ay0_ + AyX_ * x + AyY_ * y;
00446
00447 if (n<=3 || return_pure_affine_)
00448 return vgl_point_2d<double>(x_sum,y_sum);
00449
00450 const vgl_point_2d<double> * pts_data = &src_pts_[0];
00451 const double* Wx_data = Wx_.data_block();
00452 const double* Wy_data = Wy_.data_block();
00453
00454 for (unsigned int i=0;i<n;i++)
00455 {
00456 double Ui = r2lnr(x - pts_data[i].x(), y - pts_data[i].y() );
00457 x_sum += (Ui * Wx_data[i]);
00458 y_sum += (Ui * Wy_data[i]);
00459 }
00460
00461 return vgl_point_2d<double>(x_sum,y_sum);
00462 }
00463
00464
00465
00466
00467
00468 short mbl_thin_plate_spline_2d::version_no() const
00469 {
00470 return 1;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 void mbl_thin_plate_spline_2d::print_summary(vcl_ostream& os) const
00480 {
00481 os<<"\nfx: "<<Ax0_<<" + "<<AxX_<<"*x + "<<AxY_<<"*y Nonlinear terms:";
00482 for (unsigned int i=0;i<Wx_.size();++i)
00483 os<<" "<<Wx_[i];
00484 os<<"\nfy: "<<Ay0_<<" + "<<AyX_<<"*x + "<<AyY_<<"*y Nonlinear terms:";
00485 for (unsigned int i=0;i<Wy_.size();++i)
00486 os<<" "<<Wy_[i];
00487 os<<'\n';
00488 }
00489
00490
00491
00492
00493
00494
00495 void mbl_thin_plate_spline_2d::b_write(vsl_b_ostream& bfs) const
00496 {
00497 vsl_b_write(bfs,version_no());
00498 vsl_b_write(bfs,Wx_); vsl_b_write(bfs,Wy_);
00499 vsl_b_write(bfs,Ax0_); vsl_b_write(bfs,AxX_); vsl_b_write(bfs,AxY_);
00500 vsl_b_write(bfs,Ay0_); vsl_b_write(bfs,AyX_); vsl_b_write(bfs,AyY_);
00501 vsl_b_write(bfs,energy_x_); vsl_b_write(bfs,energy_y_);
00502 vsl_b_write(bfs,src_pts_);
00503 vsl_b_write(bfs,L_inv_);
00504 }
00505
00506
00507
00508
00509
00510
00511 void mbl_thin_plate_spline_2d::b_read(vsl_b_istream& bfs)
00512 {
00513 if (!bfs) return;
00514
00515 short version;
00516 vsl_b_read(bfs,version);
00517 switch (version)
00518 {
00519 case (1):
00520 vsl_b_read(bfs,Wx_);
00521 vsl_b_read(bfs,Wy_);
00522 vsl_b_read(bfs,Ax0_); vsl_b_read(bfs,AxX_); vsl_b_read(bfs,AxY_);
00523 vsl_b_read(bfs,Ay0_); vsl_b_read(bfs,AyX_); vsl_b_read(bfs,AyY_);
00524 vsl_b_read(bfs,energy_x_); vsl_b_read(bfs,energy_y_);
00525 vsl_b_read(bfs,src_pts_);
00526 vsl_b_read(bfs,L_inv_);
00527 break;
00528 default:
00529 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, mbl_thin_plate_spline_2d &)\n"
00530 << " Unknown version number "<< version << '\n';
00531 bfs.is().clear(vcl_ios::badbit);
00532 return;
00533 }
00534 }
00535
00536
00537 bool mbl_thin_plate_spline_2d::operator==(const mbl_thin_plate_spline_2d& tps) const
00538 {
00539 if (&tps==this) return true;
00540 if (vcl_fabs(Ax0_-tps.Ax0_)>1e-8) return false;
00541 if (vcl_fabs(AxX_-tps.AxX_)>1e-8) return false;
00542 if (vcl_fabs(AxY_-tps.AxY_)>1e-8) return false;
00543 if (vcl_fabs(Ay0_-tps.Ay0_)>1e-8) return false;
00544 if (vcl_fabs(AyX_-tps.AyX_)>1e-8) return false;
00545 if (vcl_fabs(AyY_-tps.AyY_)>1e-8) return false;
00546 if (vnl_vector_ssd(Wx_,tps.Wx_)>1e-6) return false;
00547 if (vnl_vector_ssd(Wy_,tps.Wy_)>1e-6) return false;
00548 return true;
00549 }
00550
00551
00552
00553
00554
00555 void vsl_b_write(vsl_b_ostream& bfs, const mbl_thin_plate_spline_2d& b)
00556 {
00557 b.b_write(bfs);
00558 }
00559
00560
00561
00562
00563
00564 void vsl_b_read(vsl_b_istream& bfs, mbl_thin_plate_spline_2d& b)
00565 {
00566 b.b_read(bfs);
00567 }
00568
00569
00570
00571
00572
00573 vcl_ostream& operator<<(vcl_ostream& os,const mbl_thin_plate_spline_2d& b)
00574 {
00575 os << "mbl_thin_plate_spline_2d: ";
00576 vsl_indent_inc(os);
00577 b.print_summary(os);
00578 vsl_indent_dec(os);
00579 return os;
00580 }