00001
00002 #ifndef vpgl_camera_compute_cxx_
00003 #define vpgl_camera_compute_cxx_
00004
00005 #include "vpgl_camera_compute.h"
00006
00007
00008 #include <vcl_iostream.h>
00009 #include <vcl_cassert.h>
00010 #include <vcl_cstdlib.h>
00011 #include <vcl_cmath.h>
00012 #include <vnl/vnl_numeric_traits.h>
00013 #include <vnl/vnl_det.h>
00014 #include <vnl/vnl_inverse.h>
00015 #include <vnl/vnl_vector_fixed.h>
00016 #include <vnl/vnl_double_3.h>
00017 #include <vnl/vnl_matrix_fixed.h>
00018 #include <vnl/algo/vnl_svd.h>
00019 #include <vnl/algo/vnl_qr.h>
00020 #include <vgl/algo/vgl_rotation_3d.h>
00021 #include <vgl/algo/vgl_h_matrix_2d_compute_linear.h>
00022 #include <vgl/vgl_homg_point_3d.h>
00023 #include <vpgl/algo/vpgl_ortho_procrustes.h>
00024 #include <vpgl/algo/vpgl_optimize_camera.h>
00025 #include <vgl/vgl_point_2d.h>
00026 #include <vgl/vgl_point_3d.h>
00027 #include <vgl/vgl_box_3d.h>
00028 #include <vgl/vgl_homg_point_2d.h>
00029
00030 #include <vpgl/bgeo/bgeo_lvcs.h>
00031
00032
00033
00034 bool
00035 vpgl_proj_camera_compute::compute(
00036 const vcl_vector< vgl_point_2d<double> >& image_pts,
00037 const vcl_vector< vgl_point_3d<double> >& world_pts,
00038 vpgl_proj_camera<double>& camera )
00039 {
00040 vcl_vector< vgl_homg_point_2d<double> > image_pts2;
00041 vcl_vector< vgl_homg_point_3d<double> > world_pts2;
00042 for (unsigned int i = 0; i < image_pts.size(); ++i)
00043 image_pts2.push_back( vgl_homg_point_2d<double>( image_pts[i] ) );
00044 for (unsigned int i = 0; i < world_pts.size(); ++i)
00045 world_pts2.push_back( vgl_homg_point_3d<double>( world_pts[i] ) );
00046 return compute( image_pts2, world_pts2, camera );
00047 }
00048
00049
00050
00051 bool
00052 vpgl_proj_camera_compute::compute(
00053 const vcl_vector< vgl_homg_point_2d<double> >& image_pts,
00054 const vcl_vector< vgl_homg_point_3d<double> >& world_pts,
00055 vpgl_proj_camera<double>& camera )
00056 {
00057 unsigned int num_correspondences = image_pts.size();
00058 if ( world_pts.size() < num_correspondences ) num_correspondences = world_pts.size();
00059 assert( num_correspondences >= 6 );
00060
00061
00062 vnl_matrix<double> S( 2*num_correspondences, 12, 0);
00063 for ( unsigned i = 0; i < num_correspondences; ++i ) {
00064 S(2*i,0) = -image_pts[i].w()*world_pts[i].x();
00065 S(2*i,1) = -image_pts[i].w()*world_pts[i].y();
00066 S(2*i,2) = -image_pts[i].w()*world_pts[i].z();
00067 S(2*i,3) = -image_pts[i].w()*world_pts[i].w();
00068 S(2*i,8) = image_pts[i].x()*world_pts[i].x();
00069 S(2*i,9) = image_pts[i].x()*world_pts[i].y();
00070 S(2*i,10) = image_pts[i].x()*world_pts[i].z();
00071 S(2*i,11) = image_pts[i].x()*world_pts[i].w();
00072 S(2*i+1,4) = -image_pts[i].w()*world_pts[i].x();
00073 S(2*i+1,5) = -image_pts[i].w()*world_pts[i].y();
00074 S(2*i+1,6) = -image_pts[i].w()*world_pts[i].z();
00075
00076 S(2*i+1,7) = -image_pts[i].w()*world_pts[i].w();
00077 S(2*i+1,8) = image_pts[i].y()*world_pts[i].x();
00078 S(2*i+1,9) = image_pts[i].y()*world_pts[i].y();
00079 S(2*i+1,10) = image_pts[i].y()*world_pts[i].z();
00080 S(2*i+1,11) = image_pts[i].y()*world_pts[i].w();
00081 }
00082 vnl_svd<double> svd( S );
00083 vnl_vector<double> c = svd.nullvector();
00084 vnl_matrix_fixed<double,3,4> cm;
00085 cm(0,0)=c(0); cm(0,1)=c(1); cm(0,2)=c(2); cm(0,3)=c(3);
00086 cm(1,0)=c(4); cm(1,1)=c(5); cm(1,2)=c(6); cm(1,3)=c(7);
00087 cm(2,0)=c(8); cm(2,1)=c(9); cm(2,2)=c(10); cm(2,3)=c(11);
00088 camera = vpgl_proj_camera<double>( cm );
00089 return true;
00090 }
00091
00092
00093
00094 bool
00095 vpgl_affine_camera_compute::compute(
00096 const vcl_vector< vgl_point_2d<double> >& image_pts,
00097 const vcl_vector< vgl_point_3d<double> >& world_pts,
00098 vpgl_affine_camera<double>& camera )
00099 {
00100 assert( image_pts.size() == world_pts.size() );
00101 assert( image_pts.size() > 3 );
00102
00103
00104 vnl_matrix<double> A( world_pts.size(), 4, 1 );
00105 for (unsigned int i = 0; i < world_pts.size(); ++i) {
00106 A(i,0) = world_pts[i].x(); A(i,1) = world_pts[i].y(); A(i,2) = world_pts[i].z();
00107 }
00108 vnl_vector<double> b1( image_pts.size() );
00109 vnl_vector<double> b2( image_pts.size() );
00110 for (unsigned int i = 0; i < image_pts.size(); ++i) {
00111 b1(i) = image_pts[i].x(); b2(i) = image_pts[i].y();
00112 }
00113 vnl_matrix<double> AtA = A.transpose()*A;
00114 vnl_svd<double> svd(AtA);
00115 if ( svd.rank() < 4 ) {
00116 vcl_cerr << "vpgl_affine_camera_compute:compute() cannot compute,\n"
00117 << " input data has insufficient rank.\n";
00118 return false;
00119 }
00120 vnl_matrix<double> S = svd.inverse()*A.transpose();
00121 vnl_vector_fixed<double,4> x1, x2;
00122 x1 = S*b1;
00123 x2 = S*b2;
00124
00125
00126 camera.set_rows( x1, x2 );
00127 return true;
00128 }
00129
00130 static vcl_vector<double>
00131 pvector(const double x, const double y, const double z)
00132 { vcl_vector<double> pv(20);
00133 pv[0]= x*x*x;
00134 pv[1]= x*x*y;
00135 pv[2]= x*x*z;
00136 pv[3]= x*x;
00137 pv[4]= x*y*y;
00138 pv[5]= x*y*z;
00139 pv[6]= x*y;
00140 pv[7]= x*z*z;
00141 pv[8]= x*z;
00142 pv[9]= x;
00143 pv[10]= y*y*y;
00144 pv[11]= y*y*z;
00145 pv[12]= y*y;
00146 pv[13]= y*z*z;
00147 pv[14]= y*z;
00148 pv[15]= y;
00149 pv[16]= z*z*z;
00150 pv[17]= z*z;
00151 pv[18]= z;
00152 pv[19]= 1;
00153 return pv;
00154 }
00155
00156 static vcl_vector<double>
00157 power_vector_dx(const double x, const double y, const double z)
00158 {
00159
00160 vcl_vector<double> pv(20, 0.0);
00161 pv[0]= 3*x*x;
00162 pv[1]= 2*x*y;
00163 pv[2]= 2*x*z;
00164 pv[3]= 2*x;
00165 pv[4]= y*y;
00166 pv[5]= y*z;
00167 pv[6]= y;
00168 pv[7]= z*z;
00169 pv[8]= z;
00170 pv[9]= 1;
00171 return pv;
00172 }
00173
00174 static vcl_vector<double>
00175 power_vector_dy(const double x, const double y, const double z)
00176 {
00177
00178 vcl_vector<double> pv(20, 0.0);
00179 pv[1]= x*x;
00180 pv[4]= 2*x*y;
00181 pv[5]= x*z;
00182 pv[6]= x;
00183 pv[10]= 3*y*y;
00184 pv[11]= 2*y*z;
00185 pv[12]= 2*y;
00186 pv[13]= z*z;
00187 pv[14]= z;
00188 pv[15]= 1;
00189 return pv;
00190 }
00191
00192 static vcl_vector<double>
00193 power_vector_dz(const double x, const double y, const double z)
00194 {
00195
00196 vcl_vector<double> pv(20, 0.0);
00197 pv[2]= x*x;
00198 pv[5]= x*y;
00199 pv[7]= 2*x*z;
00200 pv[8]= x;
00201 pv[11]= y*y;
00202 pv[13]= 2*y*z;
00203 pv[14]= y;
00204 pv[16]= 3*z*z;
00205 pv[17]= 2*z;
00206 pv[18]= 1;
00207 return pv;
00208 }
00209
00210
00211 static double pval(vcl_vector<double> const& pv, vcl_vector<double>const& coef)
00212 {
00213 double sum = 0;
00214 for (unsigned i = 0; i<20; ++i)
00215 sum += pv[i]*coef[i];
00216 return sum;
00217 }
00218
00219
00220
00221 bool vpgl_proj_camera_compute::
00222 compute( vpgl_rational_camera<double> const& rat_cam,
00223 vgl_point_3d<double> const& world_center,
00224 vpgl_proj_camera<double>& camera)
00225 {
00226 double x0 = world_center.x(), y0 = world_center.y(), z0 = world_center.z();
00227
00228 double nx0 =
00229 rat_cam.scl_off(vpgl_rational_camera<double>::X_INDX).normalize(x0);
00230 double ny0 =
00231 rat_cam.scl_off(vpgl_rational_camera<double>::Y_INDX).normalize(y0);
00232 double nz0 =
00233 rat_cam.scl_off(vpgl_rational_camera<double>::Z_INDX).normalize(z0);
00234
00235
00236 vcl_vector<vcl_vector<double> > coeffs = rat_cam.coefficients();
00237 vcl_vector<double> neu_u = coeffs[0];
00238 vcl_vector<double> den_u = coeffs[1];
00239 vcl_vector<double> neu_v = coeffs[2];
00240 vcl_vector<double> den_v = coeffs[3];
00241
00242
00243 double nmax_u = -vnl_numeric_traits<double>::maxval;
00244 double dmax_u = nmax_u, nmax_v = nmax_u,dmax_v = nmax_u;
00245 for (unsigned i = 0; i<20; ++i)
00246 {
00247 if (vcl_fabs(neu_u[i])>nmax_u)
00248 nmax_u=vcl_fabs(neu_u[i]);
00249 if (vcl_fabs(den_u[i])>dmax_u)
00250 dmax_u=vcl_fabs(den_u[i]);
00251 if (vcl_fabs(neu_v[i])>nmax_v)
00252 nmax_v=vcl_fabs(neu_v[i]);
00253 if (vcl_fabs(den_v[i])>dmax_v)
00254 dmax_v=vcl_fabs(den_v[i]);
00255 }
00256
00257 double norm_u = nmax_u, norm_v = nmax_v;
00258 if (norm_u<dmax_u) norm_u = dmax_u;
00259 if (norm_v<dmax_v) norm_v = dmax_v;
00260 for (unsigned i = 0; i<20; ++i)
00261 {
00262 neu_u[i] /= norm_u; den_u[i] /= norm_u;
00263 neu_v[i] /= norm_v; den_v[i] /= norm_v;
00264 }
00265
00266
00267
00268 vcl_vector<double> pv0 = pvector(nx0,ny0,nz0);
00269 double neu_u_0 = pval(pv0,neu_u), den_u_0 = pval(pv0,den_u);
00270 double neu_v_0 = pval(pv0,neu_v), den_v_0 = pval(pv0,den_v);
00271 vcl_vector<double> pv_dx0 = power_vector_dx(nx0,ny0,nz0);
00272 double neu_u_dx0 = pval(pv_dx0,neu_u), den_u_dx0 = pval(pv_dx0,den_u);
00273 double neu_v_dx0 = pval(pv_dx0,neu_v), den_v_dx0 = pval(pv_dx0,den_v);
00274 vcl_vector<double> pv_dy0 = power_vector_dy(nx0,ny0,nz0);
00275 double neu_u_dy0 = pval(pv_dy0,neu_u), den_u_dy0 = pval(pv_dy0,den_u);
00276 double neu_v_dy0 = pval(pv_dy0,neu_v), den_v_dy0 = pval(pv_dy0,den_v);
00277 vcl_vector<double> pv_dz0 = power_vector_dz(nx0,ny0,nz0);
00278 double neu_u_dz0 = pval(pv_dz0,neu_u), den_u_dz0 = pval(pv_dz0,den_u);
00279 double neu_v_dz0 = pval(pv_dz0,neu_v), den_v_dz0 = pval(pv_dz0,den_v);
00280
00281
00282 vnl_matrix<double> C(4,4);
00283 C[0][0]=neu_u_dx0; C[0][1]=neu_u_dy0; C[0][2]=neu_u_dz0; C[0][3]=neu_u_0;
00284 C[1][0]=den_u_dx0; C[1][1]=den_u_dy0; C[1][2]=den_u_dz0; C[1][3]=den_u_0;
00285 C[2][0]=neu_v_dx0; C[2][1]=neu_v_dy0; C[2][2]=neu_v_dz0; C[2][3]=neu_v_0;
00286 C[3][0]=den_v_dx0; C[3][1]=den_v_dy0; C[3][2]=den_v_dz0; C[3][3]=den_v_0;
00287
00288 vnl_svd<double> svd(C);
00289 vnl_vector<double> nv = svd.nullvector();
00290
00291 nv/=nv[3];
00292 #if 1
00293 vcl_cout << "Center of projection\n" << nv << '\n'
00294 << "Residual\n" << C*nv << '\n';
00295 #endif
00296
00297 double ndu = vcl_sqrt(den_u_dx0*den_u_dx0 + den_u_dy0*den_u_dy0 +
00298 den_u_dz0*den_u_dz0);
00299 double ndv = vcl_sqrt(den_v_dx0*den_v_dx0 + den_v_dy0*den_v_dy0 +
00300 den_v_dz0*den_v_dz0);
00301
00302
00303 if (ndu/vcl_fabs(den_u_0)<1.0e-10||ndv/vcl_fabs(den_v_0)<1.0e-10)
00304 {
00305 vcl_cout << "Camera is nearly affine - approximation not implemented!\n";
00306 return false;
00307 }
00308
00309 vnl_matrix_fixed<double, 3, 3> M;
00310 for (unsigned i = 0; i<3; ++i)
00311 {
00312 M[0][i]=C[0][i]/ndu;
00313 M[1][i]=C[2][i]/ndv;
00314 M[2][i]=(C[1][i]/ndu + C[3][i]/ndv)/2;
00315 }
00316 #if 1
00317 vcl_cout << "M matrix\n" << M << '\n';
00318
00319 vnl_matrix_fixed<double,3,3> Mf;
00320 for ( int i = 0; i < 3; i++ )
00321 for ( int j = 0; j < 3; j++ )
00322 Mf(i,j) = M(2-j,2-i);
00323 vnl_qr<double> QR( Mf );
00324 vnl_matrix_fixed<double,3,3> q,r,Qf,Rf, uq,ur;
00325 q = QR.Q();
00326 r = QR.R();
00327 for ( int i = 0; i < 3; i++ ){
00328 for ( int j = 0; j < 3; j++ ){
00329 Qf(i,j) = q(2-j,2-i);
00330 Rf(i,j) = r(2-j,2-i);
00331 }
00332 }
00333 vcl_cout << "Flipped Rotation\n" << Qf << '\n'
00334 << "Flipped Upper Triangular\n" << Rf << '\n';
00335 vnl_qr<double> uqr(M);
00336 uq = uqr.Q();
00337 ur = uqr.R();
00338 vcl_cout << "UnFlipped Rotation\n" << uq << '\n'
00339 << "UnFlipped Upper Triangular\n" << ur << '\n'
00340 << "Det uq " << vnl_det<double>(uq) << '\n';
00341
00342 vnl_vector<double> c1(3), c3(3);
00343 for (unsigned i = 0; i<3; ++i){
00344 c1[i]=C[1][i]/ndu;
00345 c3[i]=C[3][i]/ndv;
00346 }
00347
00348
00349 vcl_cout << "Denominators\n"
00350 << "C1 " << c1
00351 << "C3 " << c3;
00352 #endif
00353
00354 vnl_vector_fixed<double, 3> c;
00355 for (unsigned i = 0; i<3; ++i)
00356 c[i]=nv[i];
00357 vnl_vector_fixed<double, 3> p3 = -M*c;
00358
00359 vnl_matrix_fixed<double, 3, 4> pmatrix;
00360 for (unsigned r = 0; r<3; ++r)
00361 for (unsigned c = 0; c<3; ++c)
00362 pmatrix[r][c] = M[r][c];
00363 for (unsigned r = 0; r<3; ++r)
00364 pmatrix[r][3] = p3[r];
00365
00366 double uscale = rat_cam.scale(vpgl_rational_camera<double>::U_INDX);
00367 double uoff = rat_cam.offset(vpgl_rational_camera<double>::U_INDX);
00368 double vscale = rat_cam.scale(vpgl_rational_camera<double>::V_INDX);
00369 double voff = rat_cam.offset(vpgl_rational_camera<double>::V_INDX);
00370 vnl_matrix_fixed<double, 3, 3> Kr;
00371 Kr.fill(0.0);
00372 Kr[0][0]=uscale; Kr[0][2]=uoff;
00373 Kr[1][1]=vscale; Kr[1][2]=voff;
00374 Kr[2][2]=1.0;
00375 #if 1
00376 vcl_cout << "Kr\n" << Kr << '\n';
00377 vnl_matrix_fixed<double,3,3> KRf, KR=Kr*uq;
00378 for ( int i = 0; i < 3; i++ )
00379 for ( int j = 0; j < 3; j++ )
00380 KRf(i,j) = KR(2-j,2-i);
00381 vnl_qr<double> krQR( KRf );
00382 vnl_matrix_fixed<double,3,3> krq,krr,krQf,krRf;
00383 krq = krQR.Q();
00384 krr = krQR.R();
00385 for ( int i = 0; i < 3; i++ ){
00386 for ( int j = 0; j < 3; j++ ){
00387 krQf(i,j) = krq(2-j,2-i);
00388 krRf(i,j) = krr(2-j,2-i);
00389 }
00390 }
00391 vcl_cout << "Flipped Rotation (KR)\n" << krQf << '\n'
00392 << "Flipped Upper Triangular (KR)\n" << krRf << '\n';
00393
00394 int r0pos = krRf(0,0) > 0 ? 1 : -1;
00395 int r1pos = krRf(1,1) > 0 ? 1 : -1;
00396 int r2pos = krRf(2,2) > 0 ? 1 : -1;
00397 int diag[3] = { r0pos, r1pos, r2pos };
00398 vnl_matrix_fixed<double,3,3> K1,R1;
00399 for ( int i = 0; i < 3; i++ ){
00400 for ( int j = 0; j < 3; j++ ){
00401 K1(i,j) = diag[j]*krRf(i,j);
00402 R1(i,j) = diag[i]*krQf(i,j);
00403 }
00404 }
00405 K1 = K1/K1(2,2);
00406 vcl_cout << "K1\n" << K1 <<'\n'
00407 << "R1\n" << R1 << '\n'
00408 << "Det R1 " << vnl_det<double>(R1) << '\n';
00409 #endif
00410
00411
00412
00413 vnl_matrix_fixed<double, 4, 4> T;
00414 T.fill(0.0);
00415 T[0][0]=1.0; T[1][1]=1.0; T[2][2]=1.0; T[3][3]=1.0;
00416 T[0][3] = -nx0; T[1][3]= -ny0; T[2][3]=-nz0;
00417 pmatrix = Kr*pmatrix*T;
00418 #if 0
00419 vcl_cout << "P Matrix\n" << pmatrix << '\n';
00420 #endif
00421 camera.set_matrix(pmatrix);
00422 return true;
00423 }
00424
00425
00426
00427
00428 vgl_h_matrix_3d<double>
00429 vpgl_proj_camera_compute::norm_trans(vpgl_rational_camera<double> const& rat_cam)
00430 {
00431 double xscale = rat_cam.scale(vpgl_rational_camera<double>::X_INDX);
00432 double xoff = rat_cam.offset(vpgl_rational_camera<double>::X_INDX);
00433 double yscale = rat_cam.scale(vpgl_rational_camera<double>::Y_INDX);
00434 double yoff = rat_cam.offset(vpgl_rational_camera<double>::Y_INDX);
00435 double zscale = rat_cam.scale(vpgl_rational_camera<double>::Z_INDX);
00436 double zoff = rat_cam.offset(vpgl_rational_camera<double>::Z_INDX);
00437 vgl_h_matrix_3d<double> T;
00438 T.set_identity();
00439 T.set(0,0,1/xscale); T.set(1,1,1/yscale); T.set(2,2,1/zscale);
00440 T.set(0,3, -xoff/xscale); T.set(1,3, -yoff/yscale);
00441 T.set(2,3, -zoff/zscale);
00442 return T;
00443 }
00444
00445
00446
00447
00448 bool vpgl_perspective_camera_compute::
00449 compute( const vcl_vector< vgl_point_2d<double> >& image_pts,
00450 const vcl_vector< vgl_point_3d<double> >& world_pts,
00451 const vpgl_calibration_matrix<double>& K,
00452 vpgl_perspective_camera<double>& camera )
00453 {
00454 unsigned N = world_pts.size();
00455 if (image_pts.size()!=N)
00456 {
00457 vcl_cout << "Unequal points sets in"
00458 << " vpgl_perspective_camera_compute::compute()\n";
00459 return false;
00460 }
00461 if (N<6)
00462 {
00463 vcl_cout << "Need at least 6 points for"
00464 << " vpgl_perspective_camera_compute::compute()\n";
00465 return false;
00466 }
00467
00468
00469 vnl_matrix_fixed<double, 3, 3> km = K.get_matrix();
00470 vnl_matrix_fixed<double, 3, 3> k_inv = vnl_inverse<double>(km);
00471
00472
00473
00474
00475 vnl_matrix<double> wp(4, N);
00476 for (unsigned c = 0; c<N; ++c)
00477 {
00478 vgl_point_3d<double> p = world_pts[c];
00479 wp[0][c] = p.x(); wp[1][c] = p.y(); wp[2][c] = p.z();
00480 wp[3][c] = 1.0;
00481 }
00482 #ifdef CAMERA_DEBUG
00483 vcl_cout << "World Points\n" << wp << '\n';
00484 #endif
00485 vnl_svd<double> svd(wp);
00486 unsigned rank = svd.rank();
00487 if (rank != 4)
00488 {
00489 vcl_cout << "Insufficient rank for world point"
00490 << " matrix in vpgl_perspective_camera_compute::compute()\n";
00491 return false;
00492 }
00493
00494 vnl_matrix<double> V = svd.V();
00495 unsigned nr = V.rows(), nc = V.columns();
00496 vnl_matrix<double> null_space(nr, nc-4);
00497 for (unsigned c = 4; c<nc; ++c)
00498 for (unsigned r = 0; r<nr; ++r)
00499 null_space[r][c-4] = V[r][c];
00500 #ifdef CAMERA_DEBUG
00501 vcl_cout << "Null Space\n" << null_space << '\n';
00502 #endif
00503
00504 unsigned nrk = 3*(nc-4), nck = 3*nr;
00505 vnl_matrix<double> v2k(nrk, nck);
00506 for (unsigned r = 0; r<(nc-4); ++r)
00507 for (unsigned c = 0; c<nr; ++c)
00508 for (unsigned rk = 0; rk<3; ++rk)
00509 for (unsigned ck = 0; ck<3; ++ck)
00510 v2k[rk+3*r][ck+3*c] = k_inv[rk][ck]*null_space[c][r];
00511 #ifdef CAMERA_DEBUG
00512 vcl_cout << "V2K\n" << v2k << '\n';
00513 #endif
00514
00515 vnl_matrix<double> D(3*N, N);
00516 D.fill(0);
00517 for (unsigned c = 0; c<N; ++c)
00518 {
00519 vgl_point_2d<double> p = image_pts[c];
00520 D[3*c][c] = p.x(); D[3*c+1][c] = p.y(); D[3*c+2][c] = 1.0;
00521 }
00522 #ifdef CAMERA_DEBUG
00523 vcl_cout << "D\n" << D << '\n';
00524 #endif
00525
00526 vnl_matrix<double> M = v2k*D;
00527 vnl_svd<double> svdm(M);
00528
00529
00530 vnl_vector<double> depth = svdm.nullvector();
00531
00532 #ifdef CAMERA_DEBUG
00533 vcl_cout << "depths\n" << depth << '\n';
00534 #endif
00535
00536
00537 double average_depth = 0;
00538 unsigned nd = depth.size();
00539 for (unsigned i = 0; i<nd; ++i)
00540 average_depth += depth[i];
00541 average_depth /= nd;
00542 double max_dev = 0;
00543 for (unsigned i = 0; i<nd; ++i)
00544 {
00545 double dev = vcl_fabs(depth[i]-average_depth);
00546 if (dev>max_dev)
00547 max_dev = dev;
00548 }
00549 double norm_max_dev = max_dev/average_depth;
00550
00551
00552 if (norm_max_dev < 0.01)
00553 for (unsigned i = 0; i<nd; ++i)
00554 depth[i]=vcl_fabs(average_depth);
00555
00556
00557 vnl_matrix<double> X(3,N), Y(3,N);
00558 for (unsigned c = 0; c<N; ++c)
00559 {
00560 vgl_point_2d<double> pi = image_pts[c];
00561 vgl_point_3d<double> pw = world_pts[c];
00562
00563 X[0][c] = pi.x()*depth[c]; X[1][c] = pi.y()*depth[c]; X[2][c] = depth[c];
00564
00565 Y[0][c] = pw.x(); Y[1][c] = pw.y(); Y[2][c] = pw.z();
00566 }
00567
00568 vpgl_ortho_procrustes op(X, Y);
00569 if (!op.compute_ok())
00570 return false;
00571
00572 vgl_rotation_3d<double> R = op.R();
00573 vnl_matrix_fixed<double, 3, 3> rr = R.as_matrix();
00574
00575 vnl_vector_fixed<double, 3> t = op.t();
00576 #ifdef CAMERA_DEBUG
00577 vcl_cout << "translation\n" << t << '\n'
00578 << "scale = " << op.s() << '\n'
00579 << "residual = " << op.residual_mean_sq_error() << '\n';
00580 #endif
00581
00582 vnl_vector_fixed<double, 3> center = -(rr.transpose())*t;
00583 vgl_point_3d<double> vgl_center(center[0],center[1],center[2]);
00584 vpgl_perspective_camera<double> tcam;
00585 tcam.set_calibration(K);
00586 tcam.set_camera_center(vgl_center);
00587 tcam.set_rotation(R);
00588
00589
00590 vcl_vector<vgl_homg_point_3d<double> > h_world_pts;
00591 for (unsigned i = 0; i<N; ++i)
00592 h_world_pts.push_back(vgl_homg_point_3d<double>(world_pts[i]));
00593 camera = vpgl_optimize_camera::opt_orient_pos_cal(tcam, h_world_pts, image_pts, 0.00005, 20000);
00594 return true;
00595 }
00596
00597
00598
00599
00600
00601
00602
00603 bool vpgl_perspective_camera_compute::
00604 compute( const vcl_vector< vgl_point_2d<double> >& image_pts,
00605 const vcl_vector< vgl_point_2d<double> >& ground_pts,
00606 vpgl_perspective_camera<double>& camera )
00607 {
00608 unsigned num_pts = ground_pts.size();
00609 if (image_pts.size()!=num_pts)
00610 {
00611 vcl_cout << "Unequal points sets in"
00612 << " vpgl_perspective_camera_compute::compute()\n";
00613 return false;
00614 }
00615 if (num_pts<4)
00616 {
00617 vcl_cout << "Need at least 4 points for"
00618 << " vpgl_perspective_camera_compute::compute()\n";
00619 return false;
00620 }
00621
00622 vcl_vector<vgl_homg_point_2d<double> > pi, pg;
00623 for(unsigned i=0; i<num_pts; ++i){
00624 #ifdef CAMERA_DEBUG
00625 vcl_cout << "("<<image_pts[i].x()<<", "<<image_pts[i].y()<<") -> "
00626 << "("<<ground_pts[i].x()<<", "<<ground_pts[i].y()<<")"<<vcl_endl;
00627 #endif
00628 pi.push_back(vgl_homg_point_2d<double>(image_pts[i].x(),image_pts[i].y()));
00629 pg.push_back(vgl_homg_point_2d<double>(ground_pts[i].x(),ground_pts[i].y()));
00630 }
00631
00632
00633 vgl_h_matrix_2d_compute_linear est_H;
00634 vnl_double_3x3 H = est_H.compute(pg,pi).get_matrix();
00635 if(vnl_det(H) > 0)
00636 H *= -1.0;
00637
00638
00639 vnl_double_3x3 Kinv = vnl_inverse(camera.get_calibration().get_matrix());
00640 vnl_double_3x3 A(Kinv*H);
00641
00642 vnl_vector_fixed<double,3> t = A.get_column(2);
00643 t.normalize();
00644
00645
00646 A.set_column(2, vnl_cross_3d(A.get_column(0), A.get_column(1)));
00647 vnl_svd<double> svdA(A);
00648 vnl_double_3x3 R = svdA.U()*svdA.V().conjugate_transpose();
00649
00650
00651 int max_idx = 0;
00652 double max_dist = 0.0;
00653 for(unsigned int i=0; i < ground_pts.size(); ++i){
00654 double d = (ground_pts[i]-vgl_point_2d<double>(0,0)).length();
00655 if(d >= max_dist){
00656 max_dist = d;
00657 max_idx = i;
00658 }
00659 }
00660
00661
00662 vnl_vector_fixed<double,3> i1 = Kinv*vnl_double_3(image_pts[max_idx].x(),image_pts[max_idx].y(),1.0);
00663 vnl_vector_fixed<double,3> t1 = vnl_cross_3d(i1, t);
00664 vnl_vector_fixed<double,3> p1 = vnl_cross_3d(i1, R*vnl_double_3(ground_pts[max_idx].x(),ground_pts[max_idx].y(),1.0));
00665 double s = p1.magnitude()/t1.magnitude();
00666
00667
00668 t *= s;
00669 t = -R.transpose()*t;
00670
00671 camera.set_rotation(vgl_rotation_3d<double>(R));
00672 camera.set_camera_center(vgl_point_3d<double>(t[0],t[1],t[2]));
00673
00674
00675
00676
00677 vcl_vector<vgl_homg_point_3d<double> > h_world_pts;
00678 for (unsigned i = 0; i<num_pts; ++i){
00679 h_world_pts.push_back(vgl_homg_point_3d<double>(ground_pts[i].x(),ground_pts[i].y(),0,1));
00680 if(camera.is_behind_camera(h_world_pts.back())){
00681 vcl_cout << "behind camera" << vcl_endl;
00682 return false;
00683 }
00684 }
00685 camera = vpgl_optimize_camera::opt_orient_pos(camera, h_world_pts, image_pts);
00686
00687 return true;
00688 }
00689
00690
00691 bool vpgl_perspective_camera_compute::
00692 compute( vpgl_rational_camera<double> const& rat_cam,
00693 vgl_box_3d<double> const& approximation_volume,
00694 vpgl_perspective_camera<double>& camera,
00695 vgl_h_matrix_3d<double>& norm_trans)
00696 {
00697 vpgl_scale_offset<double> sou =
00698 rat_cam.scl_off(vpgl_rational_camera<double>::U_INDX);
00699 vpgl_scale_offset<double> sov =
00700 rat_cam.scl_off(vpgl_rational_camera<double>::V_INDX);
00701 vpgl_scale_offset<double> sox =
00702 rat_cam.scl_off(vpgl_rational_camera<double>::X_INDX);
00703 vpgl_scale_offset<double> soy =
00704 rat_cam.scl_off(vpgl_rational_camera<double>::Y_INDX);
00705 vpgl_scale_offset<double> soz =
00706 rat_cam.scl_off(vpgl_rational_camera<double>::Z_INDX);
00707 unsigned ni = static_cast<unsigned>(2*sou.scale());
00708 unsigned nj = static_cast<unsigned>(2*sov.scale());
00709 norm_trans.set_identity();
00710 norm_trans.set(0,0,1/sox.scale()); norm_trans.set(1,1,1/soy.scale());
00711 norm_trans.set(2,2,1/soz.scale());
00712 norm_trans.set(0,3, -sox.offset()/sox.scale());
00713 norm_trans.set(1,3, -soy.offset()/soy.scale());
00714 norm_trans.set(2,3, -soz.offset()/soz.scale());
00715
00716 vgl_point_3d<double> minp = approximation_volume.min_point();
00717 vgl_point_3d<double> maxp = approximation_volume.max_point();
00718 double xmin = minp.x(), ymin = minp.y(), zmin = minp.z();
00719 double xrange = maxp.x()-xmin, yrange = maxp.y()-ymin,
00720 zrange = maxp.z()-zmin;
00721 if (xrange<0||yrange<0||zrange<0)
00722 return false;
00723
00724 unsigned n = 100;
00725 vcl_vector<vgl_point_3d<double> > world_pts;
00726 unsigned count = 0, ntrials = 0;
00727 while (count<n)
00728 {
00729 ntrials++;
00730 double rx = xrange*(vcl_rand()/(RAND_MAX+1.0));
00731 double ry = yrange*(vcl_rand()/(RAND_MAX+1.0));
00732 double rz = zrange*(vcl_rand()/(RAND_MAX+1.0));
00733 vgl_point_3d<double> wp(xmin+rx, ymin+ry, zmin+rz);
00734 vgl_point_2d<double> ip = rat_cam.project(wp);
00735 if (ip.x()<0||ip.x()>ni||ip.y()<0||ip.y()>nj)
00736 continue;
00737 world_pts.push_back(wp);
00738 count++;
00739 }
00740 vcl_cout << "Ntrials " << ntrials << '\n';
00741
00742
00743 vcl_vector<vgl_point_3d<double> > norm_world_pts;
00744 vcl_vector<vgl_point_2d<double> > image_pts, norm_image_pts;
00745 unsigned N = world_pts.size();
00746 for (unsigned i = 0; i<N; ++i)
00747 {
00748 vgl_point_3d<double> wp = world_pts[i];
00749 vgl_point_2d<double> ip = rat_cam.project(wp);
00750 image_pts.push_back(ip);
00751 vgl_point_2d<double> nip(sou.normalize(ip.x()), sov.normalize(ip.y()));
00752 norm_image_pts.push_back(nip);
00753 vgl_point_3d<double> nwp(sox.normalize(wp.x()),
00754 soy.normalize(wp.y()),
00755 soz.normalize(wp.z()));
00756 norm_world_pts.push_back(nwp);
00757 }
00758
00759
00760 vnl_matrix_fixed<double, 3, 3> kk;
00761 kk.fill(0);
00762 kk[0][0]= 1.0;
00763 kk[1][1]= 1.0;
00764 kk[2][2]=1.0;
00765
00766
00767 vpgl_calibration_matrix<double> K(kk);
00768 bool good = vpgl_perspective_camera_compute::compute(norm_image_pts,
00769 norm_world_pts,
00770 K, camera);
00771 if (!good)
00772 return false;
00773 vcl_cout << camera << '\n';
00774
00775 vpgl_calibration_matrix<double> Kmin = camera.get_calibration();
00776 vnl_matrix_fixed<double, 3, 3> kk_min;
00777 kk_min = Kmin.get_matrix();
00778 kk[0][0]= sou.scale(); kk[0][2]= sou.offset();
00779 kk[1][1]= sov.scale(); kk[1][2]= sov.offset();
00780 kk *= kk_min;
00781 camera.set_calibration(kk);
00782
00783
00784 double err_max = 0, err_min = 1e10;
00785 vgl_point_3d<double> min_pt, max_pt;
00786 for (unsigned i = 0; i<N; ++i)
00787 {
00788 vgl_point_3d<double> nwp = norm_world_pts[i];
00789 double U ,V;
00790 camera.project(nwp.x(), nwp.y(), nwp.z(), U, V);
00791 vgl_point_2d<double> ip = image_pts[i];
00792 double error = vcl_sqrt((ip.x()-U)*(ip.x()-U) + (ip.y()-V)*(ip.y()-V));
00793 if ( error > err_max )
00794 {
00795 err_max = error;
00796 max_pt = world_pts[i];
00797 }
00798 if (error < err_min)
00799 {
00800 err_min = error;
00801 min_pt = world_pts[i];
00802 }
00803 }
00804 vcl_cout << "Max Error = " << err_max << " at " << max_pt << '\n'
00805 << "Min Error = " << err_min << " at " << min_pt << '\n'
00806
00807 << "final cam\n" << camera << '\n';
00808 return true;
00809 }
00810
00811
00812 bool vpgl_perspective_camera_compute::
00813 compute_local( vpgl_rational_camera<double> const& rat_cam,
00814 vgl_box_3d<double> const& approximation_volume,
00815 vpgl_perspective_camera<double>& camera,
00816 vgl_h_matrix_3d<double>& norm_trans)
00817 {
00818
00819 double lon_low = approximation_volume.min_x();
00820 double lon_high = approximation_volume.max_x();
00821 double lat_low = approximation_volume.min_y();
00822 double lat_high = approximation_volume.max_y();
00823 assert( lat_low < lat_high && lon_low < lon_high );
00824 bgeo_lvcs lvcs_converter( lat_low, lon_low,
00825 .5*(approximation_volume.min_z()+approximation_volume.max_z()),
00826 bgeo_lvcs::wgs84, bgeo_lvcs::DEG );
00827
00828
00829 double min_lx=1e99, min_ly=1e99, min_lz=1e99, max_lx=0, max_ly=0, max_lz=0;
00830 for ( int cx = 0; cx < 2; cx++ ) {
00831 for ( int cy = 0; cy < 2; cy++ ) {
00832 for ( int cz = 0; cz < 2; cz++ ) {
00833 vgl_point_3d<double> wc(
00834 approximation_volume.min_x()*cx + approximation_volume.max_x()*(1-cx),
00835 approximation_volume.min_y()*cy + approximation_volume.max_y()*(1-cy),
00836 approximation_volume.min_z()*cz + approximation_volume.max_z()*(1-cz) );
00837 double lcx, lcy, lcz;
00838 lvcs_converter.global_to_local(
00839 wc.x(), wc.y(), wc.z(), bgeo_lvcs::wgs84, lcx, lcy, lcz );
00840 vgl_point_3d<double> wc_loc( lcx, lcy, lcz );
00841 if ( cx == 0 && cy == 0 && cz == 0 ){
00842 min_lx = wc_loc.x(); max_lx = wc_loc.x();
00843 min_ly = wc_loc.y(); max_ly = wc_loc.y();
00844 min_lz = wc_loc.z(); max_lz = wc_loc.z();
00845 continue;
00846 }
00847 if ( wc_loc.x() < min_lx ) min_lx = wc_loc.x();
00848 if ( wc_loc.y() < min_ly ) min_ly = wc_loc.y();
00849 if ( wc_loc.z() < min_lz ) min_lz = wc_loc.z();
00850 if ( wc_loc.x() > max_lx ) max_lx = wc_loc.x();
00851 if ( wc_loc.y() > max_ly ) max_ly = wc_loc.y();
00852 if ( wc_loc.z() > max_lz ) max_lz = wc_loc.z();
00853 }
00854 }
00855 }
00856 double dlx = max_lx-min_lx, dly = max_ly-min_ly, dlz = max_lz-min_lz;
00857
00858 norm_trans.set_identity();
00859 norm_trans.set(0,0,2/dlx); norm_trans.set(1,1,2/dly); norm_trans.set(2,2,2/dlz);
00860 norm_trans.set(0,3, -1-2*min_lx/dlx );
00861 norm_trans.set(1,3, -1-2*min_ly/dly);
00862 norm_trans.set(2,3, -1-2*min_lz/dlz);
00863
00864 vpgl_scale_offset<double> sou =
00865 rat_cam.scl_off(vpgl_rational_camera<double>::U_INDX);
00866 vpgl_scale_offset<double> sov =
00867 rat_cam.scl_off(vpgl_rational_camera<double>::V_INDX);
00868 vpgl_scale_offset<double> sox =
00869 rat_cam.scl_off(vpgl_rational_camera<double>::X_INDX);
00870 vpgl_scale_offset<double> soy =
00871 rat_cam.scl_off(vpgl_rational_camera<double>::Y_INDX);
00872 vpgl_scale_offset<double> soz =
00873 rat_cam.scl_off(vpgl_rational_camera<double>::Z_INDX);
00874 unsigned ni = static_cast<unsigned>(2*sou.scale());
00875 unsigned nj = static_cast<unsigned>(2*sov.scale());
00876
00877
00878 vgl_point_3d<double> minp = approximation_volume.min_point();
00879 vgl_point_3d<double> maxp = approximation_volume.max_point();
00880 double xmin = minp.x(), ymin = minp.y(), zmin = minp.z();
00881 double xrange = maxp.x()-xmin, yrange = maxp.y()-ymin,
00882 zrange = maxp.z()-zmin;
00883 if (xrange<0||yrange<0||zrange<0)
00884 return false;
00885
00886 unsigned n = 100;
00887 vcl_vector<vgl_point_3d<double> > world_pts;
00888 unsigned count = 0, ntrials = 0;
00889 while (count<n)
00890 {
00891 ntrials++;
00892 double rx = xrange*(vcl_rand()/(RAND_MAX+1.0));
00893 double ry = yrange*(vcl_rand()/(RAND_MAX+1.0));
00894 double rz = zrange*(vcl_rand()/(RAND_MAX+1.0));
00895 vgl_point_3d<double> wp(xmin+rx, ymin+ry, zmin+rz);
00896
00897 vgl_point_2d<double> ip = rat_cam.project(wp);
00898 if (ip.x()<0||ip.x()>ni||ip.y()<0||ip.y()>nj)
00899 continue;
00900 world_pts.push_back(wp);
00901 count++;
00902 }
00903 vcl_cout << "Ntrials " << ntrials << '\n';
00904
00905
00906 vcl_vector<vgl_point_3d<double> > norm_world_pts;
00907 vcl_vector<vgl_point_2d<double> > image_pts, norm_image_pts;
00908 unsigned N = world_pts.size();
00909 for (unsigned i = 0; i<N; ++i)
00910 {
00911 vgl_point_3d<double> wp = world_pts[i];
00912 vgl_point_2d<double> ip = rat_cam.project(wp);
00913 image_pts.push_back(ip);
00914 vgl_point_2d<double> nip(sou.normalize(ip.x()), sov.normalize(ip.y()));
00915 norm_image_pts.push_back(nip);
00916
00917
00918 double lcx, lcy, lcz;
00919 lvcs_converter.global_to_local(
00920 wp.x(), wp.y(), wp.z(), bgeo_lvcs::wgs84, lcx, lcy, lcz );
00921 vgl_homg_point_3d<double> wp_loc( lcx, lcy, lcz );
00922
00923 vgl_homg_point_3d<double> nwp = norm_trans*wp_loc;
00924 assert( vcl_fabs(nwp.x()) <= 1
00925 && vcl_fabs(nwp.y()) <= 1
00926 && vcl_fabs(nwp.z()) <= 1 );
00927 norm_world_pts.push_back(vgl_point_3d<double>(nwp) );
00928 }
00929
00930
00931 vnl_matrix_fixed<double, 3, 3> kk;
00932 kk.fill(0);
00933 kk[0][0]= 1.0;
00934 kk[1][1]= 1.0;
00935 kk[2][2]=1.0;
00936
00937
00938 vpgl_calibration_matrix<double> K(kk);
00939 bool good = vpgl_perspective_camera_compute::compute(norm_image_pts,
00940 norm_world_pts,
00941 K, camera);
00942 if (!good)
00943 return false;
00944 vcl_cout << camera << '\n';
00945
00946 vpgl_calibration_matrix<double> Kmin = camera.get_calibration();
00947 vnl_matrix_fixed<double, 3, 3> kk_min;
00948 kk_min = Kmin.get_matrix();
00949 kk[0][0]= sou.scale(); kk[0][2]= sou.offset();
00950 kk[1][1]= sov.scale(); kk[1][2]= sov.offset();
00951 kk *= kk_min;
00952 camera.set_calibration(kk);
00953
00954
00955 double err_max = 0, err_min = 1e10;
00956 vgl_point_3d<double> min_pt, max_pt;
00957 for (unsigned i = 0; i<N; ++i)
00958 {
00959 vgl_point_3d<double> nwp = norm_world_pts[i];
00960 double U ,V;
00961 camera.project(nwp.x(), nwp.y(), nwp.z(), U, V);
00962 vgl_point_2d<double> ip = image_pts[i];
00963 double error = vcl_sqrt((ip.x()-U)*(ip.x()-U) + (ip.y()-V)*(ip.y()-V));
00964 if ( error > err_max )
00965 {
00966 err_max = error;
00967 max_pt = world_pts[i];
00968 }
00969 if (error < err_min)
00970 {
00971 err_min = error;
00972 min_pt = world_pts[i];
00973 }
00974 }
00975 vcl_cout << "Max Error = " << err_max << " at " << max_pt << '\n'
00976 << "Min Error = " << err_min << " at " << min_pt << '\n'
00977
00978 << "final cam\n" << camera << '\n';
00979 return true;
00980 }
00981
00982 #endif // vpgl_camera_compute_cxx_