00001
00002 #include "vpgl_geo_camera.h"
00003
00004
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/vpgl_lvcs.h>
00013 #include <vpgl/vpgl_utm.h>
00014
00015 #include <vil/file_formats/vil_geotiff_header.h>
00016 #include <vil/file_formats/vil_tiff.h>
00017 #include <vil/file_formats/vil_nitf2_image.h>
00018
00019 vpgl_geo_camera::vpgl_geo_camera()
00020 {
00021 trans_matrix_.set_size(4,4);
00022 trans_matrix_.fill(0);
00023 trans_matrix_.fill_diagonal(1);
00024 is_utm = false;
00025 scale_tag_ = false;
00026 }
00027
00028 vpgl_geo_camera::vpgl_geo_camera(vpgl_geo_camera const& rhs)
00029 {
00030 this->trans_matrix_ = rhs.trans_matrix_;
00031 this->lvcs_ = new vpgl_lvcs(*(rhs.lvcs_));
00032 this->is_utm = rhs.is_utm;
00033 this->utm_zone_ = rhs.utm_zone_;
00034 this->scale_tag_ = rhs.scale_tag_;
00035 }
00036
00037 bool vpgl_geo_camera::init_geo_camera(vil_image_resource_sptr const geotiff_img,
00038 vpgl_lvcs_sptr lvcs,
00039 vpgl_geo_camera*& camera)
00040 {
00041
00042 vil_tiff_image* geotiff_tiff = dynamic_cast<vil_tiff_image*> (geotiff_img.ptr());
00043 if (!geotiff_tiff) {
00044 vcl_cerr << "vpgl_geo_camera::init_geo_camera : Error casting vil_image_resource to a tiff image.\n";
00045 return false;
00046 }
00047 if (!geotiff_tiff->get_geotiff_header()) {
00048 vcl_cerr << "no geotiff header!\n";
00049 return false;
00050 }
00051
00052
00053 if (!geotiff_tiff->is_GEOTIFF()) {
00054 vcl_cerr << "vpgl_geo_camera::init_geo_camera -- The image should be a GEOTIFF!\n";
00055 return false;
00056 }
00057
00058 vil_geotiff_header* gtif = geotiff_tiff->get_geotiff_header();
00059 int utm_zone;
00060 vil_geotiff_header::GTIF_HEMISPH h;
00061
00062 vcl_vector<vcl_vector<double> > tiepoints;
00063 gtif->gtif_tiepoints(tiepoints);
00064
00065
00066
00067 vnl_matrix<double> trans_matrix;
00068 double* trans_matrix_values;
00069 double sx1, sy1, sz1;
00070 bool scale_tag=false;
00071 if (gtif->gtif_trans_matrix(trans_matrix_values)) {
00072 vcl_cout << "Transfer matrix is given, using that...." << vcl_endl;
00073 trans_matrix.copy_in(trans_matrix_values);
00074 vcl_cout << "Warning LIDAR sample spacing different than 1 meter will not be handled correctly!\n";
00075 }
00076 else if (gtif->gtif_pixelscale(sx1, sy1, sz1)) {
00077 scale_tag = true;
00078 vpgl_geo_camera::comp_trans_matrix(sx1, sy1, sz1, tiepoints,
00079 trans_matrix, scale_tag);
00080 }
00081 else {
00082 vcl_cout << "vpgl_geo_camera::init_geo_camera comp_trans_matrix -- Transform matrix cannot be formed..\n";
00083 return false;
00084 }
00085
00086
00087 camera = new vpgl_geo_camera(trans_matrix, lvcs);
00088 camera->set_scale_format(scale_tag);
00089
00090
00091 if (gtif->GCS_WGS84_MET_DEG())
00092 return true;
00093
00094
00095 if (gtif->PCS_WGS84_UTM_zone(utm_zone, h) || gtif->PCS_NAD83_UTM_zone(utm_zone, h))
00096 {
00097 camera->set_utm(utm_zone, h);
00098 return true;
00099 }
00100 else {
00101 vcl_cout << "vpgl_geo_camera::init_geo_camera()-- if UTM only PCS_WGS84_UTM and PCS_NAD83_UTM, if geographic (GCS_WGS_84) only linear units in meters, angular units in degrees are supported, please define otherwise!" << vcl_endl;
00102 return false;
00103 }
00104 }
00105
00106
00107 void vpgl_geo_camera::project(const double x, const double y, const double z,
00108 double& u, double& v) const
00109 {
00110 vnl_vector<double> vec(4), res(4);
00111 double lat, lon, gz;
00112
00113 if (lvcs_) {
00114 if (lvcs_->get_cs_name() == vpgl_lvcs::utm) {
00115 if (is_utm) {
00116 double gx, gy;
00117 lvcs_->local_to_global(x, y, z, vpgl_lvcs::utm, gx, gy, gz);
00118 this->global_utm_to_img(gx, gy, utm_zone_, gz, u, v);
00119 }
00120 else {
00121 lvcs_->local_to_global(x, y, z, vpgl_lvcs::wgs84, lon, lat, gz);
00122 this->global_to_img(lon, lat, gz, u, v);
00123 }
00124 }
00125 else {
00126 lvcs_->local_to_global(x, y, z, vpgl_lvcs::wgs84, lon, lat, gz);
00127 this->global_to_img(lon, lat, gz, u, v);
00128 }
00129 }
00130 else
00131 this->global_to_img(x, y, z, u, v);
00132 }
00133
00134
00135 void vpgl_geo_camera::backproject(const double u, const double v,
00136 double& x, double& y, double& z)
00137 {
00138 vnl_vector<double> vec(4), res(4);
00139 if (scale_tag_) {
00140 vec[0] = trans_matrix_[0][3] + trans_matrix_[0][0]*u;
00141 vec[1] = trans_matrix_[1][3] + trans_matrix_[1][1]*v;
00142 }
00143 else {
00144 vec[0] = trans_matrix_[0][3] + u;
00145 vec[1] = trans_matrix_[1][3] - v;
00146 }
00147 vec[2] = 0;
00148 vec[3] = 1;
00149
00150
00151 double lat, lon, elev;
00152 if (is_utm) {
00153 if (lvcs_) {
00154 if (lvcs_->get_cs_name() == vpgl_lvcs::utm) {
00155 lvcs_->global_to_local(vec[0], vec[1], vec[2], vpgl_lvcs::utm, x, y, z);
00156 return;
00157 }
00158 }
00159
00160 vpgl_utm utm;
00161 utm.transform(utm_zone_, vec[0], vec[1], vec[2], lat, lon, elev);
00162 }
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, vpgl_lvcs::wgs84, x, y, z);
00171 }
00172
00173 void vpgl_geo_camera::translate(double tx, double ty, double z)
00174 {
00175
00176 if (scale_tag_) {
00177 trans_matrix_[0][3] += tx*trans_matrix_[0][0];
00178 trans_matrix_[1][3] += ty*trans_matrix_[1][1];
00179 }
00180 else {
00181 vcl_cout << "Warning! Translation offset will only be computed correctly for lidar pixel spacing = 1 meter\n";
00182 trans_matrix_[0][3] += tx;
00183 trans_matrix_[1][3] -= ty;
00184 }
00185 }
00186
00187
00188
00189 void vpgl_geo_camera::img_to_global(const double i, const double j,
00190 double& lon, double& lat) const
00191 {
00192 vnl_vector<double> v(4), res(4);
00193 if (scale_tag_) {
00194 v[0] = trans_matrix_[0][3] + i*trans_matrix_[0][0];
00195 v[1] = trans_matrix_[1][3] + j*trans_matrix_[1][1];
00196 }
00197 else {
00198 v[0] = trans_matrix_[0][3] + i;
00199 v[1] = trans_matrix_[1][3] - j;
00200 }
00201 v[2] = 0;
00202 v[3] = 1;
00203 if (is_utm) {
00204 vpgl_utm utm; double dummy;
00205 utm.transform(utm_zone_, v[0], v[1], v[2], lat, lon, dummy);
00206 }
00207 else {
00208
00209 lon = v[0]; lat = v[1];
00210 }
00211 }
00212
00213
00214
00215 void vpgl_geo_camera::global_to_img(const double lon, const double lat, const double gz,
00216 double& u, double& v) const
00217 {
00218 vnl_vector<double> vec(4), res(4);
00219 double x1=lon, y1=lat, z1=gz;
00220 if (is_utm) {
00221 vpgl_utm utm;
00222 int utm_zone;
00223 utm.transform(lat, lon, x1, y1, utm_zone);
00224
00225
00226 }
00227 vec[0] = x1;
00228 vec[1] = y1;
00229 vec[2] = z1;
00230 vec[3] = 1;
00231
00232
00233 vnl_matrix<double> tm(trans_matrix_);
00234 tm[2][2] = 1;
00235
00236 if (scale_tag_) {
00237 u = (vec[0] - trans_matrix_[0][3])/trans_matrix_[0][0];
00238 v = (vec[1] - trans_matrix_[1][3])/trans_matrix_[1][1];
00239 }
00240 else {
00241 vnl_matrix<double> trans_matrix_inv = vnl_inverse(tm);
00242 res = trans_matrix_inv*vec;
00243 u = res[0];
00244 v = res[1];
00245 }
00246 }
00247
00248
00249
00250 void vpgl_geo_camera::img_to_global_utm(const double i, const double j, double& x, double& y) const
00251 {
00252 vnl_vector<double> v(4), res(4);
00253 if (scale_tag_) {
00254 v[0] = trans_matrix_[0][3] + i*trans_matrix_[0][0];
00255 v[1] = trans_matrix_[1][3] + j*trans_matrix_[1][1];
00256 }
00257 else {
00258 v[0] = trans_matrix_[0][3] + i;
00259 v[1] = trans_matrix_[1][3] - j;
00260 }
00261 v[2] = 0;
00262 v[3] = 1;
00263 if (is_utm) {
00264 x = v[0];
00265 y = v[1];
00266 }
00267 else {
00268 vpgl_utm utm; int dummy_zone;
00269 utm.transform(v[0], v[1], x, y, dummy_zone);
00270 }
00271 }
00272
00273
00274
00275 void vpgl_geo_camera::global_utm_to_img(const double x, const double y, int zone, double elev, double& u, double& v) const
00276 {
00277 vnl_vector<double> vec(4), res(4);
00278 if (is_utm) {
00279 vec[0] = x;
00280 vec[1] = y;
00281 vec[2] = elev;
00282 }
00283 else {
00284 vpgl_utm utm;
00285 double lat, lon, z;
00286 utm.transform(zone, x, y, elev, lat, lon, z);
00287 vec[0] = lat;
00288 vec[1] = lon;
00289 vec[2] = z;
00290 }
00291 vec[3] = 1;
00292
00293
00294 vnl_matrix<double> tm(trans_matrix_);
00295 tm[2][2] = 1;
00296
00297 if (scale_tag_) {
00298 u = (vec[0] - trans_matrix_[0][3])/trans_matrix_[0][0];
00299 v = (vec[1] - trans_matrix_[1][3])/trans_matrix_[1][1];
00300 }
00301 else {
00302 vnl_matrix<double> trans_matrix_inv = vnl_inverse(tm);
00303 res = trans_matrix_inv*vec;
00304 u = res[0];
00305 v = res[1];
00306 }
00307 }
00308
00309
00310 void vpgl_geo_camera::local_to_utm(const double x, const double y, const double z, double& e, double& n, int& utm_zone)
00311 {
00312 double lat, lon, gz;
00313 lvcs_->local_to_global(x,y,z,vpgl_lvcs::wgs84,lon, lat, gz);
00314
00315 vpgl_utm utm;
00316 utm.transform(lat, lon, e, n, utm_zone);
00317 }
00318
00319 bool vpgl_geo_camera::img_four_corners_in_utm(const unsigned ni, const unsigned nj, double elev, double& e1, double& n1, double& e2, double& n2)
00320 {
00321 if (!is_utm) {
00322 vcl_cerr << "In vpgl_geo_camera::img_four_corners_in_utm() -- UTM hasn't been set!\n";
00323 return false;
00324 }
00325 double lon,lat;
00326 this->img_to_global(0, 0, lon, lat);
00327 vpgl_utm utm;int utm_zone;
00328 utm.transform(lat, lon, e1, n1, utm_zone);
00329 this->img_to_global(ni, nj, lon, lat);
00330 utm.transform(lat, lon, e2, n2, utm_zone);
00331 return true;
00332 }
00333
00334
00335 bool vpgl_geo_camera::operator==(vpgl_geo_camera const& rhs) const
00336 {
00337 return this->trans_matrix_ == rhs.trans_matrix_ &&
00338 *(this->lvcs_) == *(rhs.lvcs_);
00339 }
00340
00341
00342 vcl_ostream& operator<<(vcl_ostream& s,
00343 vpgl_geo_camera const& p)
00344 {
00345 s << p.trans_matrix_ << '\n'<< *(p.lvcs_) << '\n';
00346 if (p.is_utm) {
00347 s << "geocam is using UTM with zone: " << p.utm_zone_ << '\n';
00348 }
00349
00350 return s ;
00351 }
00352
00353
00354 vcl_istream& operator>>(vcl_istream& s,
00355 vpgl_geo_camera& p)
00356 {
00357 vnl_matrix_fixed<double,4,4> tr_matrix;
00358 s >> tr_matrix;
00359 vpgl_lvcs_sptr lvcs = new vpgl_lvcs();
00360 s >> (*lvcs);
00361 p = vpgl_geo_camera(tr_matrix.as_ref(), lvcs);
00362 return s ;
00363 }
00364
00365 bool vpgl_geo_camera::comp_trans_matrix(double sx1, double sy1, double sz1,
00366 vcl_vector<vcl_vector<double> > tiepoints,
00367 vnl_matrix<double>& trans_matrix,
00368 bool scale_tag)
00369 {
00370
00371
00372 assert (tiepoints.size() > 0);
00373 assert (tiepoints[0].size() == 6);
00374 double I = tiepoints[0][0];
00375 double J = tiepoints[0][1];
00376 double K = tiepoints[0][2];
00377 double X = tiepoints[0][3];
00378 double Y = tiepoints[0][4];
00379 double Z = tiepoints[0][5];
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 double sx = 1.0, sy = 1.0, sz = 1.0;
00393 if (scale_tag) {
00394 sx = sx1; sy = sy1; sz = sz1;
00395 }
00396 double Tx = X - I*sx;
00397 double Ty = Y + J*sy;
00398 double Tz = Z - K*sz;
00399
00400 vnl_matrix<double> m(4,4);
00401 m.fill(0.0);
00402 m[0][0] = sx;
00403 m[1][1] = -1*sy;
00404 m[2][2] = sz;
00405 m[3][3] = 1.0;
00406 m[0][3] = Tx;
00407 m[1][3] = Ty;
00408 m[2][3] = Tz;
00409 trans_matrix = m;
00410 vcl_cout << trans_matrix << vcl_endl;
00411 return true;
00412 }
00413
00414 void vpgl_geo_camera::img_to_wgs(unsigned i, unsigned j, unsigned k, double& lon, double& lat, double& elev)
00415 {
00416 assert(!"Not yet implemented");
00417 }