00001 #include "m23d_ortho_rigid_builder.h"
00002
00003
00004
00005
00006
00007 #include <m23d/m23d_rotation_from_ortho_projection.h>
00008 #include <m23d/m23d_scaled_ortho_projection.h>
00009 #include <m23d/m23d_set_q_constraint.h>
00010
00011 #include <vnl/vnl_inverse.h>
00012 #include <vnl/algo/vnl_svd.h>
00013 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00014 #include <vgl/vgl_vector_3d.h>
00015
00016 #include <vcl_iostream.h>
00017 #include <vcl_cassert.h>
00018 #include <vcl_cstdlib.h>
00019
00020
00021
00022 void m23d_ortho_rigid_builder::reconstruct(const vcl_vector< vcl_vector< vgl_point_2d<double> > >& pt_vec_list )
00023 {
00024
00025 int nf= pt_vec_list.size();
00026 int n0= pt_vec_list[0].size();
00027 vnl_matrix<double> D(2*nf,n0);
00028 for (int i=0; i<nf; ++i)
00029 {
00030 if ( (unsigned)n0!= pt_vec_list[i].size() )
00031 {
00032 vcl_cerr<<"ERROR m23d_ortho_rigid_builder::reconstruct()\n"
00033 <<"problem with different numbers of pts\n"
00034 <<"pt_vec_list[0].size()= "<<pt_vec_list[0].size()<<'\n'
00035 <<"pt_vec_list["<<i<<"].size()= "<<pt_vec_list[i].size()<<'\n';
00036 vcl_abort();
00037 }
00038
00039 for (int p=0; p<n0; ++p)
00040 {
00041 D(2*i,p)= pt_vec_list[i][p].x();
00042 D(2*i+1,p)= pt_vec_list[i][p].y();
00043 }
00044 }
00045
00046 reconstruct(D);
00047 }
00048
00049
00050
00051
00052
00053
00054
00055 void m23d_ortho_rigid_builder::reconstruct(const vnl_matrix<double>& P2D)
00056 {
00057 assert(P2D.rows()%2==0);
00058 unsigned nf = P2D.rows()/2;
00059 unsigned np = P2D.cols();
00060
00061
00062 P2Dc_=P2D;
00063 cog_.resize(nf);
00064 for (unsigned i=0;i<nf;++i)
00065 {
00066 vnl_vector<double> row_x=P2D.get_row(2*i);
00067 vnl_vector<double> row_y=P2D.get_row(2*i+1);
00068 double cog_x = row_x.mean();
00069 double cog_y = row_y.mean();
00070 row_x-=cog_x;
00071 row_y-=cog_y;
00072 P2Dc_.set_row(2*i,row_x);
00073 P2Dc_.set_row(2*i+1,row_y);
00074 cog_[i]=vgl_point_2d<double>(cog_x,cog_y);
00075 }
00076
00077
00078
00079 vnl_svd<double> svd(P2Dc_);
00080 P_.set_size(2*nf,3);
00081 P3D_.set_size(3,np);
00082 vnl_matrix<double> W(3,3);
00083 W.fill(0);
00084
00085 for (unsigned i=0;i<3;++i)
00086 {
00087 P_.set_column(i, svd.U().get_column(i) );
00088 P3D_.set_row(i, svd.V().get_column(i) );
00089 W(i,i)= vcl_sqrt( svd.W(i) );
00090 }
00091
00092 #if 0
00093 vcl_cout<<"W= "<<W<<'\n'
00094 <<"P_.rows()= "<<P_.rows()<<'\n'
00095 <<"P_.cols()= "<<P_.cols()<<'\n'
00096 <<"P3D_.rows()= "<<P3D_.rows()<<'\n'
00097 <<"P3D_.cols()= "<<P3D_.cols()<<vcl_endl;
00098 #endif
00099 P_= P_*W;
00100 P3D_= W*P3D_;
00101 #if 0
00102 vcl_cout<<"P_.extract(2,3)= "<<P_.extract(2,3)<<'\n'
00103 <<"P3D_.extract(3,5)= "<<P3D_.extract(3,5)<<vcl_endl;
00104 #endif
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 vnl_matrix<double> Q;
00116 find_correction_matrix( Q, P_);
00117
00118
00119 P_= P_*Q;
00120 P3D_=vnl_inverse(Q) * P3D_;
00121
00122
00123
00124
00125 vnl_matrix<double> P0=P_.extract(2,3);
00126
00127 vcl_cout<<"P0= "<<P0<<vcl_endl;
00128
00129
00130 vnl_matrix<double> R0=m23d_rotation_from_ortho_projection(P0);
00131
00132
00133 P_= P_*R0.transpose();
00134
00135
00136 P3D_=R0* P3D_;
00137
00138
00139 #if 0 // commented out
00140
00141
00142
00143 vnl_matrix<double> Q;
00144 find_correction_matrix_alt( Q, P_);
00145
00146
00147
00148
00149
00150
00151 vnl_matrix<double> P0=P_.extract(2,3)*Q;
00152
00153 #if 0
00154 vcl_cout<<"P_.extract(2,3)= "<<P_.extract(2,3)<<'\n'
00155 <<"Q= "<<Q<<'\n'
00156 <<"P0= "<<P0<<vcl_endl;
00157 #endif // 0
00158
00159
00160 vnl_matrix<double> R=m23d_rotation_from_ortho_projection(P0);
00161
00162 vcl_cout<<"P0*Rt\n"<<P0*R.transpose()<<vcl_endl;
00163
00164
00165
00166 Q=Q*R.transpose();
00167
00168
00169 P_=P_*Q;
00170 P3D_=vnl_inverse(Q) * P3D_;
00171 #endif // 0
00172
00173
00174
00175
00176
00177 for (unsigned i=0;i<np;++i)
00178 {
00179 if (P3D_(2,i)<0) break;
00180 if (P3D_(2,i)>0)
00181 {
00182
00183 flip_z_coords();
00184 break;
00185 }
00186 }
00187 }
00188
00189
00190
00191 void m23d_ortho_rigid_builder::flip_z_coords()
00192 {
00193 vcl_cerr<<"flipping z coords!\n";
00194
00195 unsigned np = P3D_.cols();
00196 for (unsigned j=0;j<np;++j)
00197 {
00198 P3D_(2,j)*=-1;
00199 }
00200
00201 unsigned nf = P_.rows();
00202 for (unsigned j=0;j<nf;++j)
00203 {
00204 P_(j,2)*=-1;
00205 }
00206 }
00207
00208
00209 void m23d_ortho_rigid_builder::find_correction_matrix_alt( vnl_matrix<double>& Q,
00210 const vnl_matrix<double>& P)
00211 {
00212
00213 unsigned nq = 6;
00214 int nf= P.rows()/2;
00215 unsigned n_con = 2*nf+1;
00216
00217
00218
00219
00220 vnl_matrix<double> A(n_con,nq);
00221 vnl_vector<double> rhs(n_con);
00222
00223 unsigned c=0;
00224
00225 vnl_vector<double> px0 = P.get_row(0);
00226 vnl_vector<double> py0 = P.get_row(1);
00227 m23d_set_q_constraint1(A,rhs,c,px0,px0,1); ++c;
00228 m23d_set_q_constraint1(A,rhs,c,py0,py0,1); ++c;
00229 m23d_set_q_constraint1(A,rhs,c,px0,py0,0); ++c;
00230
00231
00232
00233 for (unsigned i=1;i<(unsigned)nf;++i)
00234 {
00235 vnl_vector<double> pxi = P.get_row(2*i);
00236 vnl_vector<double> pyi = P.get_row(2*i+1);
00237 m23d_set_q_constraint2(A,rhs,c,pxi,pyi); ++c;
00238 m23d_set_q_constraint1(A,rhs,c,pxi,pyi,0); ++c;
00239 }
00240
00241 assert(c==n_con);
00242
00243 vnl_svd<double> svd_A(A);
00244 vcl_cout<<"Singular values of constraints: "<<svd_A.W().diagonal()<<vcl_endl;
00245
00246 vnl_vector<double> q = svd_A.solve(rhs);
00247 vcl_cout<<"RMS Error in q = "<<(A*q-rhs).rms()<<vcl_endl;
00248
00249 vnl_matrix<double> L(3,3);
00250 c=0;
00251 for (unsigned i=0;i<3;++i)
00252 for (unsigned j=0;j<=i;++j,++c)
00253 L(i,j)=L(j,i)=q[c];
00254 #if 0
00255 vcl_cout<<"L= "<<L<<vcl_endl;
00256 #endif
00257
00258
00259 vnl_symmetric_eigensystem<double> eig(L);
00260 #if 0
00261 vnl_matrix<double> Q(3,3);
00262 #endif
00263 Q.set_size(3,3);
00264 vcl_cout<<"Eigenvalues: "<<eig.D.diagonal()<<vcl_endl;
00265 for (unsigned i=0;i<3;++i)
00266 {
00267
00268
00269
00270
00271
00272
00273 double s= vcl_sqrt( vcl_fabs(eig.get_eigenvalue(2-i)) );
00274 Q.set_column(i,s*eig.get_eigenvector(2-i));
00275 }
00276
00277 #if 0
00278 vcl_cout<<"Q= "<<Q<<vcl_endl;
00279 #endif
00280 }
00281
00282
00283
00284 void m23d_ortho_rigid_builder::find_correction_matrix( vnl_matrix<double>& Q,
00285 const vnl_matrix<double>& P)
00286 {
00287 int nf= P.rows()/2;
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 vnl_matrix<double> G(nf*3,6);
00306 vnl_vector<double> con_vec(nf*3);
00307 for (int f=0; f<nf; ++f)
00308 {
00309
00310 vnl_vector<double> i_vec= P.get_row(f*2);
00311 vnl_vector<double> j_vec= P.get_row(f*2+1);
00312 #if 0
00313 vcl_cout<<"f="<<f<<vcl_endl
00314 <<"i_vec= "<<i_vec<<vcl_endl
00315 <<"j_vec= "<<j_vec<<vcl_endl;
00316 #endif
00317
00318 int r0= f*3;
00319 vnl_vector<double> c0_vec;
00320 compute_one_row_of_constraints( c0_vec, i_vec, i_vec );
00321 G.set_row(r0,c0_vec);
00322 con_vec(r0)=1;
00323
00324
00325 int r1= f*3+1;
00326 vnl_vector<double> c1_vec;
00327 compute_one_row_of_constraints( c1_vec, j_vec, j_vec );
00328 G.set_row(r1,c1_vec);
00329 con_vec(r1)=1;
00330
00331
00332 int r2= f*3+2;
00333 vnl_vector<double> c2_vec;
00334 compute_one_row_of_constraints( c2_vec, i_vec, j_vec );
00335 G.set_row(r2,c2_vec);
00336 con_vec(r2)=0;
00337 }
00338
00339
00340
00341 vnl_svd<double> svd_G(G);
00342 vnl_vector<double> I= svd_G.pinverse()*con_vec;
00343
00344
00345 vnl_matrix<double> L(3,3);
00346 L(0,0)= I(0);
00347 L(0,1)= I(1);
00348 L(0,2)= I(2);
00349 L(1,0)= I(1);
00350 L(1,1)= I(3);
00351 L(1,2)= I(4);
00352 L(2,0)= I(2);
00353 L(2,1)= I(4);
00354 L(2,2)= I(5);
00355
00356
00357
00358 #if 0
00359 vcl_cout<<"L= "<<L<<vcl_endl;
00360 #endif
00361
00362 vnl_symmetric_eigensystem<double> eig(L);
00363 #if 0
00364 vcl_cout<<"eig.V= "<<eig.V<<vcl_endl
00365 <<"eig.D= "<<eig.D<<vcl_endl;
00366 vnl_matrix<double> Q(3,3);
00367 #endif
00368 Q.set_size(3,3);
00369 vcl_cout<<"Eigenvalues: "<<eig.D.diagonal()<<vcl_endl;
00370 for (unsigned i=0;i<3;++i)
00371 {
00372
00373 #if 0
00374 double s=0.00001;
00375 if (eig.get_eigenvalue(2-i)>0.0)
00376 {
00377 s = vcl_sqrt(eig.get_eigenvalue(2-i));
00378 }
00379 #endif
00380
00381
00382 double s= vcl_sqrt( vcl_fabs(eig.get_eigenvalue(2-i)) );
00383 Q.set_column(i,s*eig.get_eigenvector(2-i) );
00384 }
00385 #if 0
00386 vcl_cout<<"Q= "<<Q<<vcl_endl;
00387 #endif
00388 }
00389
00390
00391 void m23d_ortho_rigid_builder::compute_one_row_of_constraints( vnl_vector<double>& c,
00392 const vnl_vector<double>& a,
00393 const vnl_vector<double>& b)
00394 {
00395 c.set_size(6);
00396 c(0)=a(0)*b(0);
00397 c(1)=a(1)*b(0)+a(0)*b(1);
00398 c(2)=a(2)*b(0)+a(0)*b(2);
00399 c(3)=a(1)*b(1);
00400 c(4)=a(2)*b(1)+a(1)*b(2);
00401 c(5)=a(2)*b(2);
00402 }
00403
00404
00405
00406
00407 void m23d_ortho_rigid_builder::make_pure_projections()
00408 {
00409 unsigned nf = P_.rows()/2;
00410
00411
00412 P_(0,0)=1; P_(0,1)=0; P_(0,2)=0;
00413 P_(1,0)=0; P_(1,1)=1; P_(1,2)=0;
00414
00415
00416
00417 for (unsigned i=1;i<nf;++i)
00418 {
00419 vnl_matrix<double> newPi = m23d_scaled_ortho_projection(P_.extract(2,3,2*i,0));
00420 P_.update(newPi,2*i,0);
00421 }
00422 }
00423
00424
00425 void m23d_ortho_rigid_builder::refine()
00426 {
00427 make_pure_projections();
00428
00429 vnl_svd<double> svd(P_);
00430 P3D_ = svd.pinverse() * P2Dc_;
00431
00432
00433 }
00434
00435
00436
00437
00438 void m23d_ortho_rigid_builder::mat_to_3d_pts(vcl_vector< vgl_point_3d<double> >& pt_vec,
00439 const vnl_matrix<double>& M) const
00440 {
00441
00442 if ( M.rows() != 3 )
00443 {
00444 vcl_cerr<<"ERROR m23d_ortho_rigid_builder::mat_to_3d_pts()\n"
00445 <<"problem with size of matrix\n"
00446 <<"M.rows()= "<<M.rows()<<'\n'
00447 <<"M.cols()= "<<M.cols()<<'\n';
00448 vcl_abort();
00449 }
00450
00451 int np= M.cols();
00452 pt_vec.resize(np);
00453 for (int i=0; i<np; ++i)
00454 {
00455 pt_vec[i].set( M(0,i), M(1,i), M(2,i) );
00456 }
00457 }
00458
00459
00460 void m23d_ortho_rigid_builder::recon_shapes(vcl_vector< vcl_vector< vgl_point_3d<double> > >& pt_vec_list ) const
00461 {
00462 if (P_.rows() < 2 || P_.cols() != 3 )
00463 {
00464 vcl_cerr<<"ERROR m23d_ortho_rigid_builder::recon_shapes()\n"
00465 <<"problem with size of P_\n"
00466 <<"P_.rows()= "<<P_.rows()<<'\n'
00467 <<"P_.cols()= "<<P_.cols()<<'\n';
00468 vcl_abort();
00469 }
00470
00471 unsigned nf= P_.rows()/2;
00472 pt_vec_list.resize(nf);
00473 for (unsigned i=0;i<nf;++i)
00474 {
00475
00476
00477 vnl_matrix<double> P0= P_.extract(2,3,2*i,0);
00478
00479
00480
00481 vnl_matrix<double> R0=m23d_rotation_from_ortho_projection(P0);
00482
00483
00484 vnl_matrix<double> rot_pts_mat=R0* P3D_;
00485 mat_to_3d_pts( pt_vec_list[i], rot_pts_mat );
00486
00487
00488 int np= pt_vec_list[i].size();
00489 vgl_vector_3d<double> tran_vec( cog_[i].x(), cog_[i].y(), 0 );
00490 for (int p=0; p<np; ++p)
00491 {
00492 pt_vec_list[i][p]= pt_vec_list[i][p] + tran_vec;
00493 }
00494 }
00495 }
00496
00497
00498
00499 void m23d_ortho_rigid_builder::get_shape_3d_pts( vcl_vector< vgl_point_3d<double> >& pts ) const
00500 {
00501 if (P_.rows() < 2 || P_.cols() != 3 )
00502 {
00503 vcl_cerr<<"ERROR m23d_ortho_rigid_builder::get_shape_3d_pts()\n"
00504 <<"problem with size of P_\n"
00505 <<"P_.rows()= "<<P_.rows()<<'\n'
00506 <<"P_.cols()= "<<P_.cols()<<'\n';
00507 vcl_abort();
00508 }
00509
00510
00511
00512
00513 vnl_matrix<double> P0= P_.extract(2,3);
00514
00515
00516
00517 vnl_matrix<double> R0=m23d_rotation_from_ortho_projection(P0);
00518
00519
00520 vnl_matrix<double> rot_pts_mat=R0* P3D_;
00521 mat_to_3d_pts( pts, rot_pts_mat );
00522
00523
00524 int np= pts.size();
00525 vgl_vector_3d<double> tran_vec( cog_[0].x(), cog_[0].y(), 0 );
00526 for (int p=0; p<np; ++p)
00527 {
00528 pts[p]= pts[p] + tran_vec;
00529 }
00530 }
00531