contrib/gel/mrc/vpgl/file_formats/vpgl_geo_camera.cxx
Go to the documentation of this file.
00001 // This is gel/mrc/vpgl/file_formats/vpgl_geo_camera.cxx
00002 #include "vpgl_geo_camera.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_vector.h>
00007 #include <vcl_cassert.h>
00008 
00009 #include <vnl/vnl_vector.h>
00010 #include <vnl/vnl_inverse.h>
00011 
00012 #include <vpgl/bgeo/bgeo_lvcs.h>
00013 #include <vpgl/bgeo/bgeo_utm.h>
00014 
00015 vpgl_geo_camera::vpgl_geo_camera()
00016 {
00017   trans_matrix_.set_size(4,4);
00018   trans_matrix_.fill(0);
00019   trans_matrix_.fill_diagonal(1);
00020   is_utm = false;
00021   scale_tag_ = false;
00022 }
00023 
00024 vpgl_geo_camera::vpgl_geo_camera(vpgl_geo_camera const& rhs)
00025 {
00026   this->trans_matrix_ = rhs.trans_matrix_;
00027   this->lvcs_ = new bgeo_lvcs(*(rhs.lvcs_));
00028   this->is_utm = rhs.is_utm;
00029   this->utm_zone_ = rhs.utm_zone_;
00030   this->scale_tag_ = rhs.scale_tag_;
00031 }
00032 
00033 bool vpgl_geo_camera::init_geo_camera(vil_tiff_image* const& gtif_img,
00034                                       bgeo_lvcs_sptr lvcs,
00035                                       vpgl_geo_camera*& camera)
00036 {
00037   // check if the tiff file is geotiff
00038   if (!gtif_img->is_GEOTIFF()) {
00039     vcl_cout << "vpgl_geo_camera::init_geo_camera -- The image should be a GEOTIFF!\n";
00040     return false;
00041   }
00042 
00043   vil_geotiff_header* gtif = gtif_img->get_geotiff_header();
00044   int utm_zone;
00045   vil_geotiff_header::GTIF_HEMISPH h;
00046 
00047   // convert given tiepoint to world coordinates (lat, long)
00048   // based on the model defined in GEOTIFF
00049 
00050   // is this a PCS_WGS84_UTM?
00051   bool is_utm = false;
00052   if (gtif->PCS_WGS84_UTM_zone(utm_zone, h))
00053   {
00054     vcl_vector<vcl_vector<double> > tiepoints;
00055     gtif->gtif_tiepoints(tiepoints);
00056     is_utm = true;
00057 #if 0  // I, J, K should not be transformed
00058     // transform each tiepoint
00059     bgeo_utm utm;
00060 
00061     bool south_flag = (h == 1);
00062     for (unsigned i=0; i< tiepoints.size(); i++) {
00063       assert (tiepoints[i].size() == 6);
00064       double I = tiepoints[i][0]; // lat
00065       double J = tiepoints[i][1]; // lon
00066       double K = tiepoints[i][2]; // elev
00067       double X = tiepoints[i][3];
00068       double Y = tiepoints[i][4];
00069       double Z = tiepoints[i][5];
00070 
00071       utm.transform(utm_zone, X, Y, Z, I, J, K, south_flag );
00072       if (!lvcs) {
00073         lvcs = new bgeo_lvcs(I,J,K);
00074         tiepoints[i][0] = I; // lat
00075         tiepoints[i][1] = J; // lon
00076         tiepoints[i][2] = K; // elev
00077       }
00078     }
00079 #endif
00080     // create a transformation matrix
00081     // if there is a transormation matrix in GEOTIFF, use that
00082     vnl_matrix<double> trans_matrix;
00083     double* trans_matrix_values;
00084     double sx1, sy1, sz1;
00085     bool scale_tag=false;
00086     if (gtif->gtif_trans_matrix(trans_matrix_values)){
00087       vcl_cout << "Transfer matrix is given, using that...." << vcl_endl;
00088       trans_matrix.copy_in(trans_matrix_values);
00089       vcl_cout << "Warning LIDAR sample spacing different than 1 meter will not be handled correctly!\n";
00090     } else if (gtif->gtif_pixelscale(sx1, sy1, sz1)) {
00091       scale_tag = true;
00092       vpgl_geo_camera::comp_trans_matrix(sx1, sy1, sz1, tiepoints,
00093                                          trans_matrix, scale_tag);
00094     } else {
00095       vcl_cout << "vpgl_geo_camera::init_geo_camera comp_trans_matrix -- Transform matrix cannot be formed..\n";
00096       return false;
00097     }
00098 
00099     // create the camera
00100 
00101     camera = new vpgl_geo_camera(trans_matrix, lvcs, tiepoints);
00102     if (is_utm)
00103       camera->set_utm(utm_zone, h);
00104     camera->set_scale_format(scale_tag);
00105     return true;
00106   } else {
00107       vcl_cout << "bmdl_lidar_roi_process::lidar_init()-- Only ProjectedCSTypeGeoKey=PCS_WGS84_UTM_zoneXX_X is defined rigth now, please define yours!!" << vcl_endl;
00108       return false;
00109   }
00110 }
00111 
00112 //: transforms a given local 3d world point to image plane
00113 void vpgl_geo_camera::project(const double x, const double y, const double z,
00114                               double& u, double& v) const
00115 {
00116   vnl_vector<double> vec(4), res(4);
00117   double lat, lon, gz;
00118 
00119   if (lvcs_)
00120     lvcs_->local_to_global(x, y, z, bgeo_lvcs::wgs84, lon, lat, gz);
00121   else {
00122     lat = y;
00123     lon = x;
00124   }
00125 
00126   double x1=lon, y1=lat, z1=gz;
00127   if (is_utm) {
00128     bgeo_utm utm;
00129     int utm_zone;
00130     utm.transform(lat, lon, x1, y1, utm_zone);
00131     z1 = 0;
00132   }
00133   vec[0] = x1;
00134   vec[1] = y1;
00135   vec[2] = z1;
00136   vec[3] = 1;
00137 
00138   // do we really need this, const does not allow this
00139   vnl_matrix<double> tm(trans_matrix_);
00140   tm[2][2] = 1;
00141 
00142   vnl_matrix<double> trans_matrix_inv = vnl_inverse(tm);
00143   res = trans_matrix_inv*vec;
00144   u = res[0];
00145   v = res[1];
00146 }
00147 
00148 //: backprojects an image point into local coordinates (based on lvcs_)
00149 void vpgl_geo_camera::backproject(const double u, const double v,
00150                                   double& x, double& y, double& z)
00151 {
00152   vnl_vector<double> vec(4), res(4);
00153   vec[0] = trans_matrix_[0][3] + u;
00154   vec[1] = trans_matrix_[1][3] - v;
00155   vec[2] = 0;
00156   vec[3] = 1;
00157 
00158   double lat, lon, elev;
00159   if (is_utm) {
00160     //find the UTM values
00161     bgeo_utm utm;
00162     utm.transform(utm_zone_, vec[0], vec[1], vec[2], lat, lon, elev);
00163   } else {
00164     lat = vec[0];
00165     lon = vec[1];
00166     elev = vec[2];
00167   }
00168 
00169   if (lvcs_)
00170     lvcs_->global_to_local(lon, lat, elev, bgeo_lvcs::wgs84, x, y, z);
00171 }
00172 
00173 void vpgl_geo_camera::translate(double tx, double ty, double z)
00174 {
00175   // use the scale values
00176   if (scale_tag_) {
00177     trans_matrix_[0][3] += tx*trans_matrix_[0][0];
00178     trans_matrix_[1][3] -= ty*(-1.0*trans_matrix_[1][1]); //multipying by -1.0 to get sy
00179   } else {
00180     vcl_cout << "Warning! Translation offset will only be computed correctly for lidar pixel spacing = 1 meter\n";
00181     trans_matrix_[0][3] += tx;
00182     trans_matrix_[1][3] -= ty;
00183   }
00184 }
00185 
00186 void vpgl_geo_camera::img_to_wgs(const unsigned i, const unsigned j, const unsigned z,
00187                                  double& lon, double& lat, double& elev)
00188 {
00189   vnl_vector<double> v(4), res(4);
00190   v[0] = trans_matrix_[0][3] + i;
00191   v[1] = trans_matrix_[1][3] - j;
00192   v[2] = z;
00193   v[3] = 1;
00194   //find the UTM values
00195   bgeo_utm utm;
00196   utm.transform(utm_zone_, v[0], v[1], v[2], lat, lon, elev);
00197 }
00198 
00199 bool vpgl_geo_camera::operator==(vpgl_geo_camera const& rhs) const
00200 {
00201   return this->trans_matrix_ == rhs.trans_matrix_ &&
00202          *(this->lvcs_) == *(rhs.lvcs_);
00203 }
00204 
00205 //: Write vpgl_perspective_camera to stream
00206 vcl_ostream&  operator<<(vcl_ostream& s,
00207                          vpgl_geo_camera const& p)
00208 {
00209   s << p.trans_matrix_ << '\n'<< *(p.lvcs_) << '\n';
00210 
00211   return s ;
00212 }
00213 
00214 //: Read vpgl_perspective_camera from stream
00215 vcl_istream&  operator>>(vcl_istream& s,
00216                          vpgl_geo_camera& p)
00217 {
00218   vnl_matrix_fixed<double,4,4> tr_matrix;
00219   s >> tr_matrix;
00220 
00221   // read a set of tiepoints
00222   vcl_vector<vcl_vector<double> > tiepoints(1);
00223   double t0, t1, t2, t3, t4, t5;
00224   s >> t0 >> t1 >> t2 >> t3 >> t4 >> t5;
00225   tiepoints[0].resize(6);
00226   tiepoints[0][0] = t0;
00227   tiepoints[0][1] = t1;
00228   tiepoints[0][2] = t2;
00229   tiepoints[0][3] = t3;
00230   tiepoints[0][4] = t4;
00231   tiepoints[0][5] = t5;
00232 
00233   bgeo_lvcs_sptr lvcs = new bgeo_lvcs();
00234   s >> (*lvcs);
00235   p = vpgl_geo_camera(tr_matrix, lvcs, tiepoints);
00236   return s ;
00237 }
00238 
00239 bool vpgl_geo_camera::comp_trans_matrix(double sx1, double sy1, double sz1,
00240                                         vcl_vector<vcl_vector<double> > tiepoints,
00241                                         vnl_matrix<double>& trans_matrix,
00242                                         bool scale_tag)
00243 {
00244   // use tiepoints and scale values to create a transformation matrix
00245   // for now use the first tiepoint if there are more than one
00246   assert (tiepoints.size() > 0);
00247   assert (tiepoints[0].size() == 6);
00248   double I = tiepoints[0][0];
00249   double J = tiepoints[0][1];
00250   double K = tiepoints[0][2];
00251   double X = tiepoints[0][3];
00252   double Y = tiepoints[0][4];
00253   double Z = tiepoints[0][5];
00254 
00255   // Define a transformation matrix as follows:
00256   //
00257   //      |-                         -|
00258   //      |   Sx    0.0   0.0   Tx    |
00259   //      |                           |      Tx = X - I*Sx
00260   //      |   0.0  -Sy    0.0   Ty    |      Ty = Y + J*Sy
00261   //      |                           |      Tz = Z - K*Sz
00262   //      |   0.0   0.0   Sz    Tz    |
00263   //      |                           |
00264   //      |   0.0   0.0   0.0   1.0   |
00265   //      |-                         -|
00266   double sx = 1.0, sy = 1.0, sz = 1.0;
00267   if (scale_tag){
00268     sx = sx1; sy = sy1; sz = sz1;
00269   }
00270   double Tx = X - I*sx;
00271   double Ty = Y + J*sy;
00272   double Tz = Z - K*sz;
00273 
00274   vnl_matrix<double> m(4,4);
00275   m.fill(0.0);
00276   m[0][0] = sx;
00277   m[1][1] = -1*sy;
00278   m[2][2] = sz;
00279   m[3][3] = 1.0;
00280   m[0][3] = Tx;
00281   m[1][3] = Ty;
00282   m[2][3] = Tz;
00283   trans_matrix = m;
00284   vcl_cout << trans_matrix << vcl_endl;
00285   return true;
00286 }
00287 
00288 // Binary I/O
00289 
00290 //: Binary read self from stream
00291 void vpgl_geo_camera::b_read(vsl_b_istream &is)
00292 {
00293   // read transformation matrix
00294   unsigned r,c;
00295   double v;
00296   vsl_b_read(is,r);
00297   vsl_b_read(is,c);
00298   trans_matrix_.set_size(r,c);
00299   for (unsigned i=0;r; i++) {
00300     for (unsigned j=0;c; i++) {
00301       vsl_b_read(is,v);
00302       trans_matrix_.put(i,j,v);
00303     }
00304   }
00305 
00306   // read lvcs
00307   lvcs_->b_read(is);
00308   vsl_b_read(is,is_utm);
00309   vsl_b_read(is,utm_zone_);
00310   vsl_b_read(is,northing_);
00311 
00312   return;
00313 }
00314 
00315 
00316 //: Binary save self to stream.
00317 void vpgl_geo_camera::b_write(vsl_b_ostream &os) const
00318 {
00319   // write transformation matrix
00320   vsl_b_write(os,trans_matrix_.rows());
00321   vsl_b_write(os,trans_matrix_.cols());
00322   for (unsigned i=0; trans_matrix_.rows(); i++)
00323     for (unsigned j=0; trans_matrix_.cols(); i++)
00324       vsl_b_write(os,trans_matrix_(i,j));
00325 
00326   vsl_b_write(os,is_utm);
00327   vsl_b_write(os,utm_zone_);
00328   vsl_b_write(os,northing_);
00329   return;
00330 }
00331