core/vpgl/algo/vpgl_camera_convert.cxx
Go to the documentation of this file.
00001 // This is core/vpgl/algo/vpgl_camera_convert.cxx
00002 #ifndef vpgl_camera_convert_cxx_
00003 #define vpgl_camera_convert_cxx_
00004 
00005 #include "vpgl_camera_convert.h"
00006 //:
00007 // \file
00008 #include <vcl_iostream.h>
00009 #include <vcl_cassert.h>
00010 #include <vcl_cstdlib.h> // for rand()
00011 #include <vcl_cmath.h> // for std::pow()
00012 #include <vnl/vnl_numeric_traits.h>
00013 #include <vnl/vnl_det.h>
00014 #include <vnl/vnl_vector_fixed.h>
00015 #include <vnl/vnl_matrix_fixed.h>
00016 #include <vnl/algo/vnl_svd.h>
00017 #include <vnl/algo/vnl_qr.h>
00018 #include <vgl/algo/vgl_rotation_3d.h>
00019 #include <vgl/algo/vgl_h_matrix_3d.h>
00020 #include <vgl/vgl_homg_point_3d.h>
00021 #include <vpgl/algo/vpgl_ortho_procrustes.h>
00022 #include <vpgl/algo/vpgl_optimize_camera.h>
00023 #include <vpgl/algo/vpgl_camera_compute.h>
00024 #include <vgl/vgl_point_2d.h>
00025 #include <vgl/vgl_point_3d.h>
00026 #include <vgl/vgl_box_3d.h>
00027 #include <vgl/vgl_homg_point_2d.h>
00028 #include <vgl/vgl_ray_3d.h>
00029 #include <vgl/vgl_plane_3d.h>
00030 #include <vbl/vbl_array_2d.h>
00031 #include <vpgl/vpgl_lvcs.h>
00032 #include <vpgl/algo/vpgl_backproject.h>
00033 
00034 
00035 static vcl_vector<double>
00036 pvector(const double x, const double y, const double z)
00037 {
00038   //fill the vector
00039   vcl_vector<double> pv(20);
00040   pv[0]= x*x*x;
00041   pv[1]= x*x*y;
00042   pv[2]= x*x*z;
00043   pv[3]= x*x;
00044   pv[4]= x*y*y;
00045   pv[5]= x*y*z;
00046   pv[6]= x*y;
00047   pv[7]= x*z*z;
00048   pv[8]= x*z;
00049   pv[9]= x;
00050   pv[10]= y*y*y;
00051   pv[11]= y*y*z;
00052   pv[12]= y*y;
00053   pv[13]= y*z*z;
00054   pv[14]= y*z;
00055   pv[15]= y;
00056   pv[16]= z*z*z;
00057   pv[17]= z*z;
00058   pv[18]= z;
00059   pv[19]= 1;
00060   return pv;
00061 }
00062 
00063 static vcl_vector<double>
00064 power_vector_dx(const double x, const double y, const double z)
00065 {
00066   //fill the vector
00067   vcl_vector<double> pv(20, 0.0);
00068   pv[0]= 3*x*x;
00069   pv[1]= 2*x*y;
00070   pv[2]= 2*x*z;
00071   pv[3]= 2*x;
00072   pv[4]= y*y;
00073   pv[5]= y*z;
00074   pv[6]= y;
00075   pv[7]= z*z;
00076   pv[8]= z;
00077   pv[9]= 1;
00078   return pv;
00079 }
00080 
00081 static vcl_vector<double>
00082 power_vector_dy(const double x, const double y, const double z)
00083 {
00084   //fill the vector
00085   vcl_vector<double> pv(20, 0.0);
00086   pv[1]= x*x;
00087   pv[4]= 2*x*y;
00088   pv[5]= x*z;
00089   pv[6]= x;
00090   pv[10]= 3*y*y;
00091   pv[11]= 2*y*z;
00092   pv[12]= 2*y;
00093   pv[13]= z*z;
00094   pv[14]= z;
00095   pv[15]= 1;
00096   return pv;
00097 }
00098 
00099 static vcl_vector<double>
00100 power_vector_dz(const double x, const double y, const double z)
00101 {
00102   //fill the vector
00103   vcl_vector<double> pv(20, 0.0);
00104   pv[2]= x*x;
00105   pv[5]= x*y;
00106   pv[7]= 2*x*z;
00107   pv[8]= x;
00108   pv[11]= y*y;
00109   pv[13]= 2*y*z;
00110   pv[14]= y;
00111   pv[16]= 3*z*z;
00112   pv[17]= 2*z;
00113   pv[18]= 1;
00114   return pv;
00115 }
00116 
00117 //convert the value of the polynomial
00118 static double pval(vcl_vector<double> const& pv, vcl_vector<double>const& coef)
00119 {
00120   double sum = 0.0;
00121   for (unsigned i = 0; i<20; ++i)
00122     sum += pv[i]*coef[i];
00123   return sum;
00124 }
00125 
00126 // Find an approximate projective camera that approximates a rational camera
00127 // at the world center.
00128 bool vpgl_proj_camera_convert::
00129 convert( vpgl_rational_camera<double> const& rat_cam,
00130          vgl_point_3d<double> const& world_center,
00131          vpgl_proj_camera<double>& camera)
00132 {
00133   double x0 = world_center.x(), y0 = world_center.y(), z0 = world_center.z();
00134   //normalized world center
00135   double nx0 =
00136     rat_cam.scl_off(vpgl_rational_camera<double>::X_INDX).normalize(x0);
00137   double ny0 =
00138     rat_cam.scl_off(vpgl_rational_camera<double>::Y_INDX).normalize(y0);
00139   double nz0 =
00140     rat_cam.scl_off(vpgl_rational_camera<double>::Z_INDX).normalize(z0);
00141 
00142   // get the rational coefficients
00143   vcl_vector<vcl_vector<double> > coeffs = rat_cam.coefficients();
00144   vcl_vector<double> neu_u = coeffs[0];
00145   vcl_vector<double> den_u = coeffs[1];
00146   vcl_vector<double> neu_v = coeffs[2];
00147   vcl_vector<double> den_v = coeffs[3];
00148 
00149   // normalize for numerical precision
00150   double nmax_u = -vnl_numeric_traits<double>::maxval;
00151   double dmax_u  = nmax_u, nmax_v = nmax_u,dmax_v = nmax_u;
00152   for (unsigned i = 0; i<20; ++i)
00153   {
00154     if (vcl_fabs(neu_u[i])>nmax_u)
00155       nmax_u=vcl_fabs(neu_u[i]);
00156     if (vcl_fabs(den_u[i])>dmax_u)
00157       dmax_u=vcl_fabs(den_u[i]);
00158     if (vcl_fabs(neu_v[i])>nmax_v)
00159       nmax_v=vcl_fabs(neu_v[i]);
00160     if (vcl_fabs(den_v[i])>dmax_v)
00161       dmax_v=vcl_fabs(den_v[i]);
00162   }
00163   // Normalize polys so that ratio of numerator and denominator is unchanged
00164   double norm_u = nmax_u, norm_v = nmax_v;
00165   if (norm_u<dmax_u) norm_u = dmax_u;
00166   if (norm_v<dmax_v) norm_v = dmax_v;
00167   for (unsigned i = 0; i<20; ++i)
00168   {
00169     neu_u[i] /= norm_u; den_u[i] /= norm_u;
00170     neu_v[i] /= norm_v; den_v[i] /= norm_v;
00171   }
00172 
00173   // Convert linear approximations to each poly
00174   //lin_p(x, y, z)=p(0,0,0) + (dp/dx)(x-nx0) + (dp/dy)(y-ny0) + (dp/dz)(z-nz0)
00175   vcl_vector<double> pv0 = pvector(nx0,ny0,nz0);
00176   double neu_u_0 = pval(pv0,neu_u), den_u_0 = pval(pv0,den_u);
00177   double neu_v_0 = pval(pv0,neu_v), den_v_0 = pval(pv0,den_v);
00178   vcl_vector<double> pv_dx0 = power_vector_dx(nx0,ny0,nz0);
00179   double neu_u_dx0 = pval(pv_dx0,neu_u), den_u_dx0 = pval(pv_dx0,den_u);
00180   double neu_v_dx0 = pval(pv_dx0,neu_v), den_v_dx0 = pval(pv_dx0,den_v);
00181   vcl_vector<double> pv_dy0 = power_vector_dy(nx0,ny0,nz0);
00182   double neu_u_dy0 = pval(pv_dy0,neu_u), den_u_dy0 = pval(pv_dy0,den_u);
00183   double neu_v_dy0 = pval(pv_dy0,neu_v), den_v_dy0 = pval(pv_dy0,den_v);
00184   vcl_vector<double> pv_dz0 = power_vector_dz(nx0,ny0,nz0);
00185   double neu_u_dz0 = pval(pv_dz0,neu_u), den_u_dz0 = pval(pv_dz0,den_u);
00186   double neu_v_dz0 = pval(pv_dz0,neu_v), den_v_dz0 = pval(pv_dz0,den_v);
00187 
00188   //Construct the matrix to convert the center of projection
00189   vnl_matrix<double> C(4,4);
00190   C[0][0]=neu_u_dx0; C[0][1]=neu_u_dy0; C[0][2]=neu_u_dz0; C[0][3]=neu_u_0;
00191   C[1][0]=den_u_dx0; C[1][1]=den_u_dy0; C[1][2]=den_u_dz0; C[1][3]=den_u_0;
00192   C[2][0]=neu_v_dx0; C[2][1]=neu_v_dy0; C[2][2]=neu_v_dz0; C[2][3]=neu_v_0;
00193   C[3][0]=den_v_dx0; C[3][1]=den_v_dy0; C[3][2]=den_v_dz0; C[3][3]=den_v_0;
00194 
00195   vnl_svd<double> svd(C);
00196   vnl_vector<double> nv = svd.nullvector();
00197   //assume not at infinity
00198   nv/=nv[3];
00199 #if 1
00200   vcl_cout << "Center of projection\n" << nv << '\n'
00201            << "Residual\n" << C*nv << '\n';
00202 #endif
00203   //Normalize with respect to the principal plane normal (principal ray)
00204   double ndu = vcl_sqrt(den_u_dx0*den_u_dx0 + den_u_dy0*den_u_dy0 +
00205                         den_u_dz0*den_u_dz0);
00206   double ndv = vcl_sqrt(den_v_dx0*den_v_dx0 + den_v_dy0*den_v_dy0 +
00207                         den_v_dz0*den_v_dz0);
00208 
00209   // determine if the projection is affine
00210   if (ndu/vcl_fabs(den_u_0)<1.0e-10||ndv/vcl_fabs(den_v_0)<1.0e-10)
00211   {
00212     vcl_cout << "Camera is nearly affine - approximation not implemented!\n";
00213     return false;
00214   }
00215   //Construct M by joined scale factor vector
00216   vnl_matrix_fixed<double, 3, 3> M;
00217   for (unsigned i = 0; i<3; ++i)
00218   {
00219     M[0][i]=C[0][i]/ndu;
00220     M[1][i]=C[2][i]/ndv;
00221     M[2][i]=(C[1][i]/ndu + C[3][i]/ndv)/2;
00222   }
00223 #if 1
00224   vcl_cout << "M matrix\n" << M << '\n';
00225 
00226   vnl_matrix_fixed<double,3,3> Mf;
00227   for ( int i = 0; i < 3; ++i )
00228     for ( int j = 0; j < 3; ++j )
00229       Mf(i,j) = M(2-j,2-i);
00230   vnl_qr<double> QR( Mf.as_ref() );
00231   vnl_matrix_fixed<double,3,3> q,r,Qf,Rf, uq,ur;
00232   q = QR.Q();
00233   r = QR.R();
00234   for ( int i = 0; i < 3; ++i ) {
00235     for ( int j = 0; j < 3; ++j ) {
00236       Qf(i,j) = q(2-j,2-i);
00237       Rf(i,j) = r(2-j,2-i);
00238     }
00239   }
00240   vcl_cout << "Flipped Rotation\n" << Qf << '\n'
00241            << "Flipped Upper Triangular\n" << Rf << '\n';
00242   vnl_qr<double> uqr(M.as_ref());
00243   uq = uqr.Q();
00244   ur = uqr.R();
00245   vcl_cout << "UnFlipped Rotation\n" << uq << '\n'
00246            << "UnFlipped Upper Triangular\n" << ur << '\n'
00247            << "Det uq " << vnl_det<double>(uq) << '\n';
00248   //Normalized denominators
00249   vnl_vector<double> c1(3), c3(3);
00250   for (unsigned i = 0; i<3; ++i) {
00251     c1[i]=C[1][i]/ndu;
00252     c3[i]=C[3][i]/ndv;
00253   }
00254 
00255   vcl_cout << "Denominators\n"
00256            << "C1 " << c1
00257            << "C3 " << c3;
00258 #endif
00259   //convert p3 the fourth column of the projection matrix
00260   vnl_vector_fixed<double, 3> c;
00261   for (unsigned i = 0; i<3; ++i)
00262     c[i]=nv[i];
00263   vnl_vector_fixed<double, 3> p3 = -M*c;
00264   //Form the full projection matrix
00265   vnl_matrix_fixed<double, 3, 4> pmatrix;
00266   for (unsigned r = 0; r<3; ++r)
00267     for (unsigned c = 0; c<3; ++c)
00268       pmatrix[r][c] = M[r][c];
00269   for (unsigned r = 0; r<3; ++r)
00270     pmatrix[r][3] = p3[r];
00271   //account for the image scale and offsets
00272   double uscale = rat_cam.scale(vpgl_rational_camera<double>::U_INDX);
00273   double uoff = rat_cam.offset(vpgl_rational_camera<double>::U_INDX);
00274   double vscale = rat_cam.scale(vpgl_rational_camera<double>::V_INDX);
00275   double voff = rat_cam.offset(vpgl_rational_camera<double>::V_INDX);
00276   vnl_matrix_fixed<double, 3, 3> Kr;
00277   Kr.fill(0.0);
00278   Kr[0][0]=uscale;   Kr[0][2]=uoff;
00279   Kr[1][1]=vscale;   Kr[1][2]=voff;
00280   Kr[2][2]=1.0;
00281 #if 1
00282   vcl_cout << "Kr\n" << Kr << '\n';
00283   vnl_matrix_fixed<double,3,3> KRf, KR=Kr*uq;
00284   for ( int i = 0; i < 3; ++i )
00285     for ( int j = 0; j < 3; ++j )
00286       KRf(i,j) = KR(2-j,2-i);
00287   vnl_qr<double> krQR( KRf.as_ref() );
00288   vnl_matrix_fixed<double,3,3> krq,krr,krQf,krRf;
00289   krq = krQR.Q();
00290   krr = krQR.R();
00291   for ( int i = 0; i < 3; ++i ) {
00292     for ( int j = 0; j < 3; ++j ) {
00293       krQf(i,j) = krq(2-j,2-i);
00294       krRf(i,j) = krr(2-j,2-i);
00295     }
00296   }
00297   vcl_cout << "Flipped Rotation (KR)\n" << krQf << '\n'
00298            << "Flipped Upper Triangular (KR)\n" << krRf << '\n';
00299 
00300   int r0pos = krRf(0,0) > 0 ? 1 : -1;
00301   int r1pos = krRf(1,1) > 0 ? 1 : -1;
00302   int r2pos = krRf(2,2) > 0 ? 1 : -1;
00303   int diag[3] = { r0pos, r1pos, r2pos };
00304   vnl_matrix_fixed<double,3,3> K1,R1;
00305   for ( int i = 0; i < 3; ++i ) {
00306     for ( int j = 0; j < 3; ++j ) {
00307       K1(i,j) = diag[j]*krRf(i,j);
00308       R1(i,j) = diag[i]*krQf(i,j);
00309     }
00310   }
00311   K1 = K1/K1(2,2);
00312   vcl_cout << "K1\n" << K1 <<'\n'
00313            << "R1\n" << R1 << '\n'
00314            << "Det R1 " << vnl_det<double>(R1) << '\n';
00315 #endif
00316 
00317   //Need to offset x0, y0 and z0 as well.
00318   vnl_matrix_fixed<double, 4, 4> T;
00319   T.fill(0.0);
00320   T[0][0]=1.0; T[1][1]=1.0; T[2][2]=1.0; T[3][3]=1.0;
00321   T[0][3] = -nx0; T[1][3]= -ny0; T[2][3]=-nz0;
00322   pmatrix = Kr*pmatrix*T;
00323 #if 0
00324   vcl_cout << "P Matrix\n" << pmatrix << '\n';
00325 #endif
00326   camera.set_matrix(pmatrix);
00327   return true;
00328 }
00329 
00330 //:obtain a scaling transformation to normalize world geographic coordinates
00331 //The resulting values will be on the range [-1, 1]
00332 //The transform is valid anywhere the rational camera is valid
00333 vgl_h_matrix_3d<double>
00334 vpgl_proj_camera_convert::norm_trans(vpgl_rational_camera<double> const& rat_cam)
00335 {
00336   double xscale = rat_cam.scale(vpgl_rational_camera<double>::X_INDX);
00337   double xoff = rat_cam.offset(vpgl_rational_camera<double>::X_INDX);
00338   double yscale = rat_cam.scale(vpgl_rational_camera<double>::Y_INDX);
00339   double yoff = rat_cam.offset(vpgl_rational_camera<double>::Y_INDX);
00340   double zscale = rat_cam.scale(vpgl_rational_camera<double>::Z_INDX);
00341   double zoff = rat_cam.offset(vpgl_rational_camera<double>::Z_INDX);
00342   vgl_h_matrix_3d<double> T;
00343   T.set_identity();
00344   T.set(0,0,1/xscale); T.set(1,1,1/yscale); T.set(2,2,1/zscale);
00345   T.set(0,3, -xoff/xscale);   T.set(1,3, -yoff/yscale);
00346   T.set(2,3, -zoff/zscale);
00347   return T;
00348 }
00349 
00350 
00351 bool vpgl_perspective_camera_convert::
00352 convert( vpgl_rational_camera<double> const& rat_cam,
00353          vgl_box_3d<double> const& approximation_volume,
00354          vpgl_perspective_camera<double>& camera,
00355          vgl_h_matrix_3d<double>& norm_trans)
00356 {
00357   vpgl_scale_offset<double> sou =
00358     rat_cam.scl_off(vpgl_rational_camera<double>::U_INDX);
00359   vpgl_scale_offset<double> sov =
00360     rat_cam.scl_off(vpgl_rational_camera<double>::V_INDX);
00361   vpgl_scale_offset<double> sox =
00362     rat_cam.scl_off(vpgl_rational_camera<double>::X_INDX);
00363   vpgl_scale_offset<double> soy =
00364     rat_cam.scl_off(vpgl_rational_camera<double>::Y_INDX);
00365   vpgl_scale_offset<double> soz =
00366     rat_cam.scl_off(vpgl_rational_camera<double>::Z_INDX);
00367   unsigned ni = static_cast<unsigned>(2*sou.scale());//# image columns
00368   unsigned nj = static_cast<unsigned>(2*sov.scale());//# image rows
00369   norm_trans.set_identity();
00370   norm_trans.set(0,0,1/sox.scale()); norm_trans.set(1,1,1/soy.scale());
00371   norm_trans.set(2,2,1/soz.scale());
00372   norm_trans.set(0,3, -sox.offset()/sox.scale());
00373   norm_trans.set(1,3, -soy.offset()/soy.scale());
00374   norm_trans.set(2,3, -soz.offset()/soz.scale());
00375 
00376   vgl_point_3d<double> minp = approximation_volume.min_point();
00377   vgl_point_3d<double> maxp = approximation_volume.max_point();
00378   double xmin = minp.x(), ymin = minp.y(), zmin = minp.z();
00379   double xrange = maxp.x()-xmin, yrange = maxp.y()-ymin,
00380     zrange = maxp.z()-zmin;
00381   if (xrange<0||yrange<0||zrange<0)
00382     return false;
00383   //Randomly generate points
00384   unsigned n = 100;
00385   vcl_vector<vgl_point_3d<double> > world_pts;
00386   unsigned count = 0, ntrials = 0;
00387   while (count<n)
00388   {
00389     ntrials++;
00390     double rx = xrange*(vcl_rand()/(RAND_MAX+1.0));
00391     double ry = yrange*(vcl_rand()/(RAND_MAX+1.0));
00392     double rz = zrange*(vcl_rand()/(RAND_MAX+1.0));
00393     vgl_point_3d<double> wp(xmin+rx, ymin+ry, zmin+rz);
00394     vgl_point_2d<double> ip = rat_cam.project(wp);
00395     if (ip.x()<0||ip.x()>ni||ip.y()<0||ip.y()>nj)
00396       continue;
00397     world_pts.push_back(wp);
00398     count++;
00399   }
00400   vcl_cout << "Ntrials " << ntrials << '\n';
00401 
00402   //Normalize world and image points to the range [-1,1]
00403   vcl_vector<vgl_point_3d<double> > norm_world_pts;
00404   vcl_vector<vgl_point_2d<double> > image_pts, norm_image_pts;
00405   unsigned N = world_pts.size();
00406   for (unsigned i = 0; i<N; ++i)
00407   {
00408     vgl_point_3d<double> wp = world_pts[i];
00409     vgl_point_2d<double> ip = rat_cam.project(wp);
00410     image_pts.push_back(ip);
00411     vgl_point_2d<double> nip(sou.normalize(ip.x()), sov.normalize(ip.y()));
00412     norm_image_pts.push_back(nip);
00413     vgl_point_3d<double> nwp(sox.normalize(wp.x()),
00414                              soy.normalize(wp.y()),
00415                              soz.normalize(wp.z()));
00416     norm_world_pts.push_back(nwp);
00417   }
00418   //Assume identity calibration matrix initially, since image point
00419   //normalization remove any scale and offset from image coordinates
00420   vnl_matrix_fixed<double, 3, 3> kk;
00421   kk.fill(0);
00422   kk[0][0]= 1.0;
00423   kk[1][1]= 1.0;
00424   kk[2][2]=1.0;
00425   //Convert solution for rotation and translation and calibration matrix of
00426   //the perspective camera
00427   vpgl_calibration_matrix<double> K(kk);
00428   if (! vpgl_perspective_camera_compute::compute(norm_image_pts,
00429                                                  norm_world_pts,
00430                                                  K, camera))
00431     return false;
00432   vcl_cout << camera << '\n';
00433   //form the full camera by premultiplying by the image normalization
00434   vpgl_calibration_matrix<double> Kmin = camera.get_calibration();
00435   vnl_matrix_fixed<double, 3, 3> kk_min;
00436   kk_min = Kmin.get_matrix();
00437   kk[0][0]= sou.scale(); kk[0][2]= sou.offset();
00438   kk[1][1]= sov.scale(); kk[1][2]= sov.offset();
00439   kk *= kk_min;
00440   camera.set_calibration(kk);
00441 
00442   //project the points approximated
00443   double err_max = 0, err_min = 1e10;
00444   vgl_point_3d<double> min_pt, max_pt;
00445   for (unsigned i = 0; i<N; ++i)
00446   {
00447     vgl_point_3d<double> nwp = norm_world_pts[i];
00448     double U ,V;
00449     camera.project(nwp.x(), nwp.y(), nwp.z(), U, V);
00450     vgl_point_2d<double> ip = image_pts[i];
00451     double error = vcl_sqrt((ip.x()-U)*(ip.x()-U) + (ip.y()-V)*(ip.y()-V));
00452     if ( error > err_max )
00453     {
00454       err_max = error;
00455       max_pt = world_pts[i];
00456     }
00457     if (error < err_min)
00458     {
00459       err_min = error;
00460       min_pt = world_pts[i];
00461     }
00462   }
00463   vcl_cout << "Max Error = " << err_max << " at " << max_pt << '\n'
00464            << "Min Error = " << err_min << " at " << min_pt << '\n'
00465            << "final cam\n" << camera << '\n';
00466   return true;
00467 }
00468 
00469 
00470 bool vpgl_perspective_camera_convert::
00471 convert_local( vpgl_rational_camera<double> const& rat_cam,
00472                vgl_box_3d<double> const& approximation_volume,
00473                vpgl_perspective_camera<double>& camera,
00474                vgl_h_matrix_3d<double>& norm_trans)
00475 {
00476   // Set up the geo converter.
00477   double lon_low = approximation_volume.min_x();
00478   double lat_low = approximation_volume.min_y();
00479 #ifdef DEBUG
00480   double lon_high = approximation_volume.max_x();
00481   double lat_high = approximation_volume.max_y();
00482   assert( lat_low < lat_high && lon_low < lon_high );
00483 #endif
00484   vpgl_lvcs lvcs_converter( lat_low, lon_low,
00485                             .5*(approximation_volume.min_z()+approximation_volume.max_z()),
00486                             vpgl_lvcs::wgs84, vpgl_lvcs::DEG );
00487 
00488   // Get a new local bounding box.
00489   double min_lx=1e99, min_ly=1e99, min_lz=1e99, max_lx=0, max_ly=0, max_lz=0;
00490   for ( int cx = 0; cx < 2; ++cx ) {
00491     for ( int cy = 0; cy < 2; ++cy ) {
00492       for ( int cz = 0; cz < 2; ++cz ) {
00493         vgl_point_3d<double> wc(approximation_volume.min_x()*cx + approximation_volume.max_x()*(1-cx),
00494                                 approximation_volume.min_y()*cy + approximation_volume.max_y()*(1-cy),
00495                                 approximation_volume.min_z()*cz + approximation_volume.max_z()*(1-cz) );
00496         double lcx, lcy, lcz;
00497         lvcs_converter.global_to_local(wc.x(), wc.y(), wc.z(), vpgl_lvcs::wgs84, lcx, lcy, lcz );
00498         vgl_point_3d<double> wc_loc( lcx, lcy, lcz );
00499         if ( cx == 0 && cy == 0 && cz == 0 ) {
00500           min_lx = wc_loc.x(); max_lx = wc_loc.x();
00501           min_ly = wc_loc.y(); max_ly = wc_loc.y();
00502           min_lz = wc_loc.z(); max_lz = wc_loc.z();
00503           continue;
00504         }
00505         if ( wc_loc.x() < min_lx ) min_lx = wc_loc.x();
00506         if ( wc_loc.y() < min_ly ) min_ly = wc_loc.y();
00507         if ( wc_loc.z() < min_lz ) min_lz = wc_loc.z();
00508         if ( wc_loc.x() > max_lx ) max_lx = wc_loc.x();
00509         if ( wc_loc.y() > max_ly ) max_ly = wc_loc.y();
00510         if ( wc_loc.z() > max_lz ) max_lz = wc_loc.z();
00511       }
00512     }
00513   }
00514   double dlx = max_lx-min_lx, dly = max_ly-min_ly, dlz = max_lz-min_lz;
00515 
00516   norm_trans.set_identity();
00517   norm_trans.set(0,0,2/dlx); norm_trans.set(1,1,2/dly); norm_trans.set(2,2,2/dlz);
00518   norm_trans.set(0,3, -1-2*min_lx/dlx );
00519   norm_trans.set(1,3, -1-2*min_ly/dly);
00520   norm_trans.set(2,3, -1-2*min_lz/dlz);
00521 
00522   vpgl_scale_offset<double> sou =
00523     rat_cam.scl_off(vpgl_rational_camera<double>::U_INDX);
00524   vpgl_scale_offset<double> sov =
00525     rat_cam.scl_off(vpgl_rational_camera<double>::V_INDX);
00526   vpgl_scale_offset<double> sox =
00527     rat_cam.scl_off(vpgl_rational_camera<double>::X_INDX);
00528   vpgl_scale_offset<double> soy =
00529     rat_cam.scl_off(vpgl_rational_camera<double>::Y_INDX);
00530   vpgl_scale_offset<double> soz =
00531     rat_cam.scl_off(vpgl_rational_camera<double>::Z_INDX);
00532   unsigned ni = static_cast<unsigned>(2*sou.scale());//# image columns
00533   unsigned nj = static_cast<unsigned>(2*sov.scale());//# image rows
00534 
00535   vgl_point_3d<double> minp = approximation_volume.min_point();
00536   vgl_point_3d<double> maxp = approximation_volume.max_point();
00537   double xmin = minp.x(), ymin = minp.y(), zmin = minp.z();
00538   double xrange = maxp.x()-xmin,
00539          yrange = maxp.y()-ymin,
00540          zrange = maxp.z()-zmin;
00541   if (xrange<0||yrange<0||zrange<0)
00542     return false;
00543   //Randomly generate points
00544   unsigned n = 100;
00545   vcl_vector<vgl_point_3d<double> > world_pts;
00546   unsigned count = 0, ntrials = 0;
00547   while (count<n)
00548   {
00549     ++ntrials;
00550     double rx = xrange*(vcl_rand()/(RAND_MAX+1.0));
00551     double ry = yrange*(vcl_rand()/(RAND_MAX+1.0));
00552     double rz = zrange*(vcl_rand()/(RAND_MAX+1.0));
00553     vgl_point_3d<double> wp(xmin+rx, ymin+ry, zmin+rz);
00554     vgl_point_2d<double> ip = rat_cam.project(wp);
00555     if (ip.x()<0||ip.x()>ni||ip.y()<0||ip.y()>nj)
00556       continue;
00557     world_pts.push_back(wp);
00558     count++;
00559   }
00560   vcl_cout << "Ntrials " << ntrials << '\n';
00561 
00562   //Normalize world and image points to the range [-1,1]
00563   vcl_vector<vgl_point_3d<double> > norm_world_pts;
00564   vcl_vector<vgl_point_2d<double> > image_pts, norm_image_pts;
00565   unsigned N = world_pts.size();
00566   for (unsigned i = 0; i<N; ++i)
00567   {
00568     vgl_point_3d<double> wp = world_pts[i];
00569     vgl_point_2d<double> ip = rat_cam.project(wp);
00570     image_pts.push_back(ip);
00571     vgl_point_2d<double> nip(sou.normalize(ip.x()), sov.normalize(ip.y()));
00572     norm_image_pts.push_back(nip);
00573 
00574     // Convert to local coords.
00575     double lcx, lcy, lcz;
00576     lvcs_converter.global_to_local(wp.x(), wp.y(), wp.z(), vpgl_lvcs::wgs84, lcx, lcy, lcz );
00577     vgl_homg_point_3d<double> wp_loc( lcx, lcy, lcz );
00578 
00579     vgl_homg_point_3d<double> nwp = norm_trans*wp_loc;
00580     assert(   vcl_fabs(nwp.x()) <= 1
00581            && vcl_fabs(nwp.y()) <= 1
00582            && vcl_fabs(nwp.z()) <= 1 );
00583     norm_world_pts.push_back(vgl_point_3d<double>(nwp) );
00584   }
00585   //Assume identity calibration matrix initially, since image point
00586   //normalization remove any scale and offset from image coordinates
00587   vnl_matrix_fixed<double, 3, 3> kk;
00588   kk.fill(0);
00589   kk[0][0]= 1.0;
00590   kk[1][1]= 1.0;
00591   kk[2][2]=1.0;
00592   //Convert solution for rotation and translation and calibration matrix of
00593   //the perspective camera
00594   vpgl_calibration_matrix<double> K(kk);
00595   if (! vpgl_perspective_camera_compute::compute(norm_image_pts,
00596                                                  norm_world_pts,
00597                                                  K, camera))
00598     return false;
00599   vcl_cout << camera << '\n';
00600   //form the full camera by premultiplying by the image normalization
00601   vpgl_calibration_matrix<double> Kmin = camera.get_calibration();
00602   vnl_matrix_fixed<double, 3, 3> kk_min;
00603   kk_min = Kmin.get_matrix();
00604   kk[0][0]= sou.scale(); kk[0][2]= sou.offset();
00605   kk[1][1]= sov.scale(); kk[1][2]= sov.offset();
00606   kk *= kk_min;
00607   camera.set_calibration(kk);
00608 
00609   //project the points approximated
00610   double err_max = 0, err_min = 1e10;
00611   vgl_point_3d<double> min_pt, max_pt;
00612   for (unsigned i = 0; i<N; ++i)
00613   {
00614     vgl_point_3d<double> nwp = norm_world_pts[i];
00615     double U ,V;
00616     camera.project(nwp.x(), nwp.y(), nwp.z(), U, V);
00617     vgl_point_2d<double> ip = image_pts[i];
00618     double error = vcl_sqrt((ip.x()-U)*(ip.x()-U) + (ip.y()-V)*(ip.y()-V));
00619     if ( error > err_max )
00620     {
00621       err_max = error;
00622       max_pt = world_pts[i];
00623     }
00624     if (error < err_min)
00625     {
00626       err_min = error;
00627       min_pt = world_pts[i];
00628     }
00629   }
00630   vcl_cout << "Max Error = " << err_max << " at " << max_pt << '\n'
00631            << "Min Error = " << err_min << " at " << min_pt << '\n'
00632            << "final cam\n" << camera << '\n';
00633   return true;
00634 }
00635 
00636 //
00637 //linear interpolation based on a set of 4 neighboring rays
00638 //          X
00639 //        X r X
00640 //          X
00641 // ray r at the center pixel is interpolated from the neighboring X's
00642 // as shown. This method is used to test if ray interpolation
00643 // is sufficiently accurate
00644 //
00645 static bool interp_ray(vcl_vector<vgl_ray_3d<double> > const& ray_nbrs,
00646                        vgl_ray_3d<double> & intrp_ray)
00647 {
00648   unsigned nrays = ray_nbrs.size();
00649   if (nrays!=4) return false;
00650   vgl_ray_3d<double> r0 = ray_nbrs[0], r1 = ray_nbrs[1];
00651   vgl_ray_3d<double> r2 = ray_nbrs[2], r3 = ray_nbrs[3];
00652   vgl_point_3d<double> org0 = r0.origin(), org1 = r1.origin();
00653   vgl_point_3d<double> org2 = r2.origin(), org3 = r3.origin();
00654   vgl_vector_3d<double> dir0 = r0.direction(), dir1 = r1.direction();
00655   vgl_vector_3d<double> dir2 = r2.direction(), dir3 = r3.direction();
00656   // first order partial derivatives
00657   vgl_vector_3d<double> dodu = 0.5*(org2-org1);
00658   vgl_vector_3d<double> dodv = 0.5*(org3-org0);
00659   vgl_vector_3d<double> dddu = 0.5*(dir2-dir1);
00660   vgl_vector_3d<double> dddv = 0.5*(dir3-dir0);
00661   vgl_point_3d<double> temp = org1 + dodu + dodv;
00662   double ox = 0.5*(org0.x()+ temp.x());
00663   double oy = 0.5*(org0.y()+ temp.y());
00664   double oz = 0.5*(org0.z()+ temp.z());
00665   vgl_point_3d<double> iorg(ox, oy, oz);
00666   vgl_vector_3d<double> idir = 0.5*(dir1 + dddu + dir0 + dddv);
00667   intrp_ray.set(iorg, idir);
00668   return true;
00669 }
00670 
00671 // convert tolerances on ray origin and ray direction to test interpolation
00672 static bool ray_tol(vpgl_local_rational_camera<double> const& rat_cam,
00673                     double mid_u, double mid_v,
00674                     vgl_plane_3d<double> const& high,
00675                     vgl_point_3d<double> const& high_guess,
00676                     vgl_plane_3d<double> const& low,
00677                     vgl_point_3d<double> const& low_guess,
00678                     double& org_tol, double& dir_tol)
00679 {
00680   vgl_point_2d<double> ip(mid_u,mid_v);
00681   vgl_point_3d<double> high_pt, low_pt, low_pt_pix;
00682   if (!vpgl_backproject::bproj_plane(&rat_cam, ip, high, high_guess, high_pt))
00683     return false;
00684   if (!vpgl_backproject::bproj_plane(&rat_cam, ip, low, low_guess, low_pt))
00685     return false;
00686   //move 1 pixel
00687   ip.set(mid_u+1.0, mid_v+1.0);
00688   if (!vpgl_backproject::bproj_plane(&rat_cam, ip, low, low_pt, low_pt_pix))
00689     return false;
00690   // Ground Sampling Distance
00691   double gsd = (low_pt-low_pt_pix).length();
00692   // tolerance
00693   double tfact = 0.001;
00694   org_tol = tfact*gsd;
00695   vgl_vector_3d<double> dir0 = low_pt-high_pt;
00696   vgl_vector_3d<double> dir1 = low_pt_pix-high_pt;
00697   double ang = angle(dir0, dir1);
00698   dir_tol = tfact*ang;
00699   return true;
00700 }
00701 
00702 // produce rays at sub pixel locations by interpolating four neighbors
00703 //
00704 //            X  <- r0
00705 //         _______
00706 //        | o   o |
00707 // r1-> X |       | X <-r2
00708 //        | o   o |
00709 //         -------
00710 //            X <- r3
00711 // the interporlated rays are indicated by the o's
00712 // the neighbor rays are shown as X's
00713 // This method is used to populate higher resolution layers of the
00714 // ray pyramid
00715 
00716 bool vpgl_generic_camera_convert::
00717 upsample_rays(vcl_vector<vgl_ray_3d<double> > const& ray_nbrs,
00718               vgl_ray_3d<double> const& ray,
00719               vcl_vector<vgl_ray_3d<double> >& interp_rays)
00720 {
00721   unsigned nrays = ray_nbrs.size();
00722   if (nrays!=4) return false;
00723   vgl_ray_3d<double> r00 = ray_nbrs[0],
00724                      r01 = ray_nbrs[1];
00725   vgl_ray_3d<double> r10 = ray_nbrs[2],
00726                      r11 = ray_nbrs[3];
00727   vgl_point_3d<double> org = ray.origin();
00728   vgl_vector_3d<double> dir = ray.direction();
00729   vgl_point_3d<double> org00 = r00.origin(),
00730                        org01 = r01.origin();
00731   vgl_point_3d<double> org10 = r10.origin(),
00732                        org11 = r11.origin();
00733   vgl_vector_3d<double> dir00 = r00.direction(), dir01 = r01.direction();
00734   vgl_vector_3d<double> dir10 = r10.direction(), dir11 = r11.direction();
00735 
00736   //first sub ray
00737   interp_rays[0] = ray;
00738 
00739   //second sub ray
00740   vgl_point_3d<double>  iorg = org00+ (org01-org00)*0.5;
00741   vgl_vector_3d<double> idir = dir00*0.5 + dir01*0.5;
00742   interp_rays[1].set(iorg, idir);
00743 
00744   //third sub ray
00745   iorg = org00+ (org10-org00)*0.5;
00746   idir = 0.5*dir00 + 0.5*dir10;
00747   interp_rays[2].set(iorg, idir);
00748 
00749   //fourth sub ray
00750   iorg = org00+0.25*(org01-org00) + 0.25*(org10-org00)+ 0.25*(org11-org00);
00751   idir = 0.25*dir00 + 0.25*dir01+ 0.25*dir10+0.25*dir11;
00752   interp_rays[3].set(iorg, idir);
00753 
00754   return true;
00755 }
00756 
00757 // r0 and r1 are rays spaced a unit grid distane apart (either row or col)
00758 // r is the interpolated ray at n_grid unit distances past r1
00759 vgl_ray_3d<double>
00760 vpgl_generic_camera_convert::interp_pair(vgl_ray_3d<double> const& r0,
00761                                          vgl_ray_3d<double> const& r1,
00762                                          double n_grid)
00763 {
00764   vgl_vector_3d<double> v01 = r1.origin()-r0.origin();
00765   vgl_point_3d<double> intp_org = r1.origin()+ n_grid*v01;
00766   vgl_vector_3d<double> d01 = r1.direction()-r0.direction();
00767   vgl_vector_3d<double> intp_dir = r1.direction()+ n_grid*d01;
00768   return vgl_ray_3d<double>(intp_org, intp_dir);
00769 }
00770 
00771 //
00772 // convert a generic camera from a local rational camera
00773 // the approach is to form a pyramid and convert rays by
00774 // back-projecting to top and bottom planes of the valid
00775 // elevations of the rational camera. Successive higher resolution
00776 // layers of the pyramid are populated until the interpolation of
00777 // a ray by the four adjacent neighbors is sufficiently accurate
00778 // The remaining layers of the pyramid are filled in by interpolation
00779 //
00780 bool vpgl_generic_camera_convert::
00781 convert( vpgl_local_rational_camera<double> const& rat_cam,
00782          int ni, int nj, vpgl_generic_camera<double> & gen_cam, unsigned level)
00783 {
00784   // get z bounds
00785   double zoff = rat_cam.offset(vpgl_rational_camera<double>::Z_INDX);
00786   double zscl = rat_cam.scale(vpgl_rational_camera<double>::Z_INDX);
00787   // construct high and low planes
00788   // NOTE: z_scale seems to usually be much larger than actual dimensions of scene, which
00789   //       sometimes causes trouble for vpgl_backproj_plane, which causes the conversion to fail.
00790   //       Using half scale value for now, but maybe we should consider taking "top" and "bottom"
00791   //       z values as user-specified inputs.  -dec 15 Nov 2011
00792   double el_low = zoff-zscl/2;
00793   double el_high = zoff+zscl/2;
00794   double lon = rat_cam.offset(vpgl_rational_camera<double>::X_INDX);
00795   double lat = rat_cam.offset(vpgl_rational_camera<double>::Y_INDX);
00796   double x,y, z_low, z_high;
00797   // convert high and low elevations to local z values
00798   rat_cam.lvcs().global_to_local(lon,lat,el_low,vpgl_lvcs::wgs84,x,y,z_low,vpgl_lvcs::DEG);
00799   rat_cam.lvcs().global_to_local(lon,lat,el_high,vpgl_lvcs::wgs84,x,y,z_high,vpgl_lvcs::DEG);
00800 
00801   return convert(rat_cam, ni, nj, gen_cam, z_low, z_high, level);
00802 }
00803 
00804 //
00805 // convert a generic camera from a local rational camera
00806 // the approach is to form a pyramid and convert rays by
00807 // back-projecting to top and bottom planes of the valid
00808 // elevations of the rational camera. Successive higher resolution
00809 // layers of the pyramid are populated until the interpolation of
00810 // a ray by the four adjacent neighbors is sufficiently accurate
00811 // The remaining layers of the pyramid are filled in by interpolation
00812 //
00813 bool vpgl_generic_camera_convert::
00814 convert( vpgl_local_rational_camera<double> const& rat_cam,
00815          int ni, int nj, vpgl_generic_camera<double> & gen_cam,
00816          double local_z_min, double local_z_max, unsigned level)
00817 {
00818   vgl_plane_3d<double> high(0.0, 0.0, 1.0, -local_z_max);
00819   vgl_plane_3d<double> low(0.0, 0.0, 1.0, -local_z_min);
00820 
00821   // initial guess for backprojection to planes
00822   vgl_point_3d<double> org(0.0, 0.0, local_z_max), endpt(0.0, 0.0, local_z_min);
00823 
00824   // initialize the ray pyramid
00825   // convert the required number of levels
00826   double dim = ni;
00827   if (nj<ni)
00828     dim = nj;
00829   double lv = vcl_log(dim)/vcl_log(2.0);
00830   int n_levels = static_cast<int>(lv+1.0);// round up
00831   if (dim*vcl_pow(0.5, static_cast<double>(n_levels-1)) < 3.0) n_levels--;
00832   // construct pyramid of ray indices
00833   // the row and column dimensions at each level
00834   vcl_vector<int> nr(n_levels,0), nc(n_levels,0);
00835   // the scale factor at each level (to transform back to level 0)
00836   vcl_vector<double> scl(n_levels,1.0);
00837   vcl_vector<vbl_array_2d<vgl_ray_3d<double> > > ray_pyr(n_levels);
00838   ray_pyr[0].resize(nj, ni);
00839   ray_pyr[0].fill(vgl_ray_3d<double>(vgl_point_3d<double>(0,0,0),vgl_vector_3d<double>(0,0,1)));
00840   nr[0]=nj;   nc[0]=ni; scl[0]=1.0;
00841   int di = (ni+1)/2+1,
00842       dj = (nj+1)/2+1;
00843 
00844   for (int i=1; i<n_levels; ++i)
00845   {
00846     ray_pyr[i].resize(dj,di);
00847     ray_pyr[i].fill(vgl_ray_3d<double>(vgl_point_3d<double>(0,0,0),
00848                                        vgl_vector_3d<double>(0,0,1)));
00849     nr[i]=dj;
00850     nc[i]=di;
00851     scl[i]=2.0*scl[i-1];
00852     di = (di+1)/2+1;
00853     dj = (dj+1)/2+1;
00854   }
00855   // convert the ray interpolation tolerances
00856   double org_tol = 0.0;
00857   double ang_tol = 0.0;
00858   double max_org_err = 0.0, max_ang_err = 0.0;
00859   if (!ray_tol(rat_cam, ni/2.0, nj/2.0, high,
00860                org, low, endpt, org_tol, ang_tol))
00861     return false;
00862   bool need_interp = true;
00863   int lev = n_levels-1;
00864   for (; lev>=0&&need_interp; --lev) {
00865     // set rays at current pyramid level
00866     for (int j =0; j<nr[lev]; ++j) {
00867       int sj = static_cast<int>(scl[lev]*j);
00868       //if (sj>=nj) sj = nj;
00869       for (int i =0;i<nc[lev]; ++i)
00870       {
00871         int si = static_cast<int>(scl[lev]*i);
00872         //if (si>=ni) si = ni;
00873         vgl_point_2d<double> ip(si,sj);
00874 #if 1  // use result from previous pyramid level to initialize guess
00875         vgl_point_3d<double> prev_org(0.0,0.0,local_z_max);
00876         vgl_point_3d<double> prev_endpt(0.0, 0.0, local_z_min);
00877         // initialize guess with
00878         if (lev < n_levels-1) {
00879           double rel_scale = scl[lev]/scl[lev+1];
00880           int i_above = static_cast<int>(rel_scale * i);
00881           int j_above = static_cast<int>(rel_scale * j);
00882 
00883           prev_org = ray_pyr[lev+1][j_above][i_above].origin();
00884           vgl_vector_3d<double> prev_dir = ray_pyr[lev+1][j_above][i_above].direction();
00885           // find endpoint
00886           double ray_len = (local_z_min - prev_org.z()) / prev_dir.z();
00887           prev_endpt = prev_org + (prev_dir * ray_len);
00888         }
00889         const double error_tol = 0.25; // allow projection error of 0.25 pixel
00890         if (!vpgl_backproject::bproj_plane(&rat_cam, ip, high, prev_org, org, error_tol))
00891           return false;
00892         if (!vpgl_backproject::bproj_plane(&rat_cam, ip, low, prev_endpt, endpt, error_tol))
00893           return false;
00894 #else // 0
00895         if (!vpgl_backproject::bproj_plane(&rat_cam, ip, high, vgl_point_3d<double>(0.0,0.0,0.0), org))
00896           return false;
00897         if (!vpgl_backproject::bproj_plane(&rat_cam, ip, low, vgl_point_3d<double>(0.0,0.0,0.0), endpt))
00898           return false;
00899 #endif
00900         vgl_vector_3d<double> dir = endpt-org;
00901         ray_pyr[lev][j][i].set(org, dir);
00902       }
00903     }
00904 
00905     // check for interpolation accuracy at the current level
00906     // scan through the array and find largest discrepancy in
00907     // ray origin and ray direction
00908     need_interp = false;
00909     max_org_err = 0.0; max_ang_err = 0.0;
00910     vcl_vector<vgl_ray_3d<double> > ray_nbrs(4);
00911     for (int j =1; j<(nr[lev]-1)&&!need_interp; ++j) {
00912       for (int i =1;(i<nc[lev]-1)&&!need_interp; ++i) {
00913         vgl_ray_3d<double> ray = ray_pyr[lev][j][i];
00914         //
00915         //collect 4-neighbors of ray
00916         //
00917         //        0
00918         //      1 x 2
00919         //        3
00920         //
00921         ray_nbrs[0]=ray_pyr[lev][j-1][i];
00922         ray_nbrs[1]=ray_pyr[lev][j][i-1];
00923         ray_nbrs[2]=ray_pyr[lev][j][i+1];
00924         ray_nbrs[3]=ray_pyr[lev][j+1][i];
00925         //interpolate using neighbors
00926         vgl_ray_3d<double> intp_ray;
00927         if (!interp_ray(ray_nbrs, intp_ray))
00928           return false;
00929         double dorg = (ray.origin()-intp_ray.origin()).length();
00930         double dang = angle(ray.direction(), intp_ray.direction());
00931         if (dorg>max_org_err) max_org_err = dorg;
00932         if (dang>max_ang_err) max_ang_err = dang;
00933         need_interp = max_org_err>org_tol || max_ang_err>ang_tol;
00934       }
00935     }
00936   }
00937   // found level where interpolation is within tolerance
00938   // fill in values at lower levels
00939   for (++lev; lev>0; --lev) {
00940     unsigned int ncr = nc[lev];
00941     unsigned int nrb = nr[lev];
00942     vbl_array_2d<vgl_ray_3d<double> >& clev = ray_pyr[lev];
00943     vbl_array_2d<vgl_ray_3d<double> >& nlev = ray_pyr[lev-1];
00944     vcl_vector<vgl_ray_3d<double> > ray_nbrs(4);
00945     vcl_vector<vgl_ray_3d<double> > interp_rays(4);
00946     for (unsigned int j = 0; j<nrb; ++j)
00947       for (unsigned int i = 0; i<ncr; ++i) {
00948         ray_nbrs[0] = clev[j][i];
00949         ray_nbrs[1] = clev[j][i];
00950         ray_nbrs[2] = clev[j][i];
00951         ray_nbrs[3] = clev[j][i];
00952         if (i+1<ncr) ray_nbrs[1] = clev[j][i+1];
00953         if (j+1<nrb) ray_nbrs[2] = clev[j+1][i];
00954         if (i+1<ncr && j+1<nrb) ray_nbrs[3] = clev[j+1][i+1];
00955         if (!upsample_rays(ray_nbrs, clev[j][i], interp_rays))
00956           return false;
00957         if (2*i<nlev.cols() && 2*j<nlev.rows())
00958         {
00959           nlev[2*j][2*i]    =interp_rays[0];
00960           if (2*i+1<nlev.cols())                      nlev[2*j][2*i+1]  =interp_rays[1];
00961           if (2*j+1<nlev.rows())                      nlev[2*j+1][2*i]  =interp_rays[2];
00962           if (2*i+1<nlev.cols() && 2*j+1<nlev.rows()) nlev[2*j+1][2*i+1]=interp_rays[3];
00963         }
00964       }
00965   }
00966   if ((int)level < n_levels) {
00967     gen_cam = vpgl_generic_camera<double>(ray_pyr[level]);
00968     return true;
00969   }
00970   else
00971     return false;
00972 }
00973 
00974 bool vpgl_generic_camera_convert::
00975 convert( vpgl_proj_camera<double> const& prj_cam, int ni, int nj,
00976          vpgl_generic_camera<double> & gen_cam, unsigned level)
00977 {
00978   vbl_array_2d<vgl_ray_3d<double> > rays(nj, ni);
00979   vgl_ray_3d<double> ray;
00980   vgl_homg_point_2d<double> ipt;
00981   double scale = (level < 32) ? double(1L<<level) : vcl_pow(2.0,static_cast<double>(level));
00982   for (int j = 0; j<nj; ++j)
00983     for (int i = 0; i<ni; ++i) {
00984       ipt.set(i*scale, j*scale, 1.0);
00985       ray = prj_cam.backproject_ray(ipt);
00986       rays[j][i]=ray;
00987     }
00988   gen_cam = vpgl_generic_camera<double>(rays);
00989   return true;
00990 }
00991 
00992 bool vpgl_generic_camera_convert::
00993 convert( vpgl_perspective_camera<double> const& per_cam, int ni, int nj,
00994          vpgl_generic_camera<double> & gen_cam, unsigned level)
00995 {
00996   vbl_array_2d<vgl_ray_3d<double> > rays(nj, ni);
00997   vgl_ray_3d<double> ray;
00998   vgl_homg_point_2d<double> ipt;
00999   double scale = (level < 32) ? double(1L<<level) : vcl_pow(2.0,static_cast<double>(level));
01000   for (int j = 0; j<nj; ++j)
01001     for (int i = 0; i<ni; ++i) {
01002       ipt.set(i*scale, j*scale, 1.0);
01003       ray = per_cam.backproject_ray(ipt);
01004       rays[j][i]=ray;
01005     }
01006   gen_cam = vpgl_generic_camera<double>(rays);
01007   return true;
01008 }
01009 
01010 bool vpgl_generic_camera_convert::
01011 convert_with_margin( vpgl_perspective_camera<double> const& per_cam, int ni, int nj,
01012                      vpgl_generic_camera<double> & gen_cam, int margin, unsigned level)
01013 {
01014   vbl_array_2d<vgl_ray_3d<double> > rays(nj+2*margin, ni+2*margin);
01015   vgl_ray_3d<double> ray;
01016   vgl_homg_point_2d<double> ipt;
01017   double scale = (level < 32) ? double(1L<<level) : vcl_pow(2.0,static_cast<double>(level));
01018   for (int j = -margin; j<nj+margin; ++j)
01019     for (int i = -margin; i<ni+margin; ++i) {
01020       ipt.set(i*scale, j*scale, 1.0);
01021       ray = per_cam.backproject_ray(ipt);
01022       rays[j+margin][i+margin]=ray;
01023     }
01024   gen_cam = vpgl_generic_camera<double>(rays);
01025   return true;
01026 }
01027 
01028 
01029 // the affine camera defines a principal plane which is
01030 // far enough from the scene origin so that all the scene
01031 // geometry is in front of the plane. The backproject function
01032 // finds constructs finite ray origins on the principal plane.
01033 bool vpgl_generic_camera_convert::
01034 convert( vpgl_affine_camera<double> const& aff_cam, int ni, int nj,
01035          vpgl_generic_camera<double> & gen_cam, unsigned level)
01036 {
01037   double scale = (level < 32) ? double(1L<<level) : vcl_pow(2.0,static_cast<double>(level));
01038   // is an ideal point defining the ray direction
01039   vgl_homg_point_3d<double> cent = aff_cam.camera_center();
01040   vgl_vector_3d<double> dir(cent.x(), cent.y(), cent.z());
01041   vbl_array_2d<vgl_ray_3d<double> > rays(nj, ni);
01042   vgl_homg_point_3d<double> horg;
01043   vgl_point_3d<double> org;
01044   vgl_homg_point_2d<double> ipt;
01045   vgl_homg_line_3d_2_points<double> hline;
01046   for (int j = 0; j<nj; ++j)
01047     for (int i = 0; i<ni; ++i) {
01048       ipt.set(i*scale, j*scale, 1.0);
01049       hline = aff_cam.backproject(ipt);
01050       horg = hline.point_finite();
01051       org.set(horg.x()/horg.w(), horg.y()/horg.w(), horg.z()/horg.w());
01052       rays[j][i].set(org, dir);
01053     }
01054   gen_cam = vpgl_generic_camera<double>(rays);
01055   return true;
01056 }
01057 
01058 bool vpgl_generic_camera_convert::
01059 convert( vpgl_camera_double_sptr const& camera, int ni, int nj,
01060          vpgl_generic_camera<double> & gen_cam, unsigned level)
01061 {
01062   if (vpgl_local_rational_camera<double>* cam =
01063       dynamic_cast<vpgl_local_rational_camera<double>*>(camera.ptr()))
01064     return vpgl_generic_camera_convert::convert(*cam, ni, nj, gen_cam, level);
01065 
01066   if (vpgl_perspective_camera<double>* cam =
01067     dynamic_cast<vpgl_perspective_camera<double>*>(camera.ptr())) {
01068       return vpgl_generic_camera_convert::convert(*cam, ni, nj, gen_cam, level);
01069   }
01070 
01071   if (vpgl_proj_camera<double>* cam =
01072     dynamic_cast<vpgl_proj_camera<double>*>(camera.ptr())) {
01073       return vpgl_generic_camera_convert::convert(*cam, ni, nj, gen_cam, level);
01074   }
01075 
01076   if (vpgl_affine_camera<double>* cam =
01077       dynamic_cast<vpgl_affine_camera<double>*>(camera.ptr()))
01078     return vpgl_generic_camera_convert::convert(*cam, ni, nj, gen_cam, level);
01079 
01080   return false;
01081 }
01082 
01083 //: Convert a geocam (transformtaion matrix read from a geotiff header + an lvcs) to a generic camera
01084 bool vpgl_generic_camera_convert::convert( vpgl_geo_camera& geocam, int ni, int nj, double height,
01085                                            vpgl_generic_camera<double> & gen_cam, unsigned level)
01086 {
01087   double scale = (level < 32) ? double(1L<<level) : vcl_pow(2.0,static_cast<double>(level));
01088 
01089   //: all rays have the same direction
01090   vgl_vector_3d<double> dir(0.0, 0.0, -1.0);
01091 
01092   vbl_array_2d<vgl_ray_3d<double> > rays(nj, ni);
01093   vgl_point_3d<double> org;
01094 
01095   for (int j = 0; j<nj; ++j)
01096     for (int i = 0; i<ni; ++i) {
01097       double x,y,z;
01098       geocam.backproject(i*scale, j*scale,x,y,z);
01099       org.set(x, y, height);
01100       rays[j][i].set(org, dir);
01101     }
01102   gen_cam = vpgl_generic_camera<double>(rays);
01103   return true;
01104 }
01105 
01106 
01107 #endif // vpgl_camera_convert_cxx_