vpgl_backproject_dem.cxx
Go to the documentation of this file.
1 // This is core/vpgl/algo/vpgl_backproject_dem.cxx
2 #include <limits>
3 #include <algorithm>
4 #include "vpgl_backproject.h"
5 #include "vpgl_backproject_dem.h"
7 #include <vgl/vgl_point_2d.h>
8 #include <vgl/vgl_point_3d.h>
9 #include <vgl/vgl_plane_3d.h>
10 #include <vgl/vgl_ray_3d.h>
11 #include <vpgl/algo/vpgl_ray.h>
12 #include <vil/vil_image_resource.h>
13 #include <vil/vil_math.h>
14 #include <vnl/vnl_cost_function.h>
17 public:
18  dem_bproj_cost_function(vil_image_view<float> const& dem_view, vpgl_geo_camera* geo_cam, vgl_ray_3d<double> const& ray, bool verbose=false) :
19  vnl_cost_function(1), ray_(ray), geo_cam_(geo_cam), dview_(&dem_view), verbose_(verbose){}
20  //: x is the parameter that runs along the ray, with x=0 at the ray origin
21  double f(vnl_vector<double> const& x) override{
22  //get the lon and lat values for a given parameter value
23  vgl_point_3d<double> org = ray_.origin(), rayp;
25  rayp = org + x[0]*dir;
26  double lon = rayp.x(), lat = rayp.y(), elev = rayp.z();
27  double ud, vd;
28  //determine the dem pixel coordinates and check bounds
29  geo_cam_->project(lon, lat, elev, ud, vd);
30  int u = static_cast<int>(ud+0.5), v = static_cast<int>(vd+0.5);
31  int ni = dview_->ni(), nj = dview_->nj();
32  if(u<0||u>=ni||v<0||v>=nj){
33  if(verbose_) std::cout << "warning: dem backprojection cost function - outside DEM bounds" << std::endl;
34  return std::numeric_limits<double>::max();
35  }
36  // within bounds so get squared distance between dem z and ray z
37  double z = (*dview_)(u,v);
38  return (elev-z)*(elev-z);
39  }
40 
41 private:
44  const vil_image_view<float>* dview_;
45  bool verbose_;
46 };
47 vpgl_backproject_dem::vpgl_backproject_dem( vil_image_resource_sptr const& dem, double zmin, double zmax):verbose_(false), min_samples_(5000.0), tail_fract_(0.025), dem_(dem)
48 {
49  //construct a geo_camera for the dem (an orthographic view looking straight down)
51  if(verbose_) std::cout << "WARNING! - units unknown in vpgl_backproject_dem - assume degrees meters" << std::endl;
52  }
53  if(!geo_cam_)
54  return;
55  //get the image of elevations
56  dem_view_ = dem_->get_view();
57  unsigned ni = dem_view_.ni(), nj = dem_view_.nj();
58 
59  // get the center of the dem
60  unsigned nhi = ni/2, nhj = nj/2;
61  double lon, lat;
62  geo_cam_->img_to_global(nhi, nhj, lon, lat);
63  double elev = dem_view_(nhi, nhj);
64  geo_center_.set(lon, lat, elev);
65 
66  // get the corners of the dem
67  geo_cam_->img_to_global(0, 0, lon, lat);
68  elev = dem_view_(0, 0);
69  dem_corners_.emplace_back(lon, lat, elev);
70 
71  geo_cam_->img_to_global(ni-1, 0, lon, lat);
72  elev = dem_view_(ni-1, 0);
73  dem_corners_.emplace_back(lon, lat, elev);
74 
75  geo_cam_->img_to_global(ni-1, nj-1, lon, lat);
76  elev = dem_view_(ni-1, nj-1);
77  dem_corners_.emplace_back(lon, lat, elev);
78 
79  geo_cam_->img_to_global(0, nj-1, lon, lat);
80  elev = dem_view_(0, nj-1);
81  dem_corners_.emplace_back(lon, lat, elev);
82 
83  // check for appropriate zmin/zmax inputs
84  if (zmax > zmin) {
85  z_min_ = zmin;
86  z_max_ = zmax;
87 
88  } else {
89  if(verbose_) std::cout << "Calculating Z-range from DEM..." << std::endl;
90  //get the bounds on elevation by sampling according to a fraction of the dem area
91  //compute the pixel interval (stride) for sampling the fraction
92  double area = ni*nj;
93  double stride_area = area/min_samples_;
94  auto stride_interval = static_cast<unsigned>(std::sqrt(stride_area));
95 
96  // sample elevations
97  std::vector<double> z_samples;
98  float zmin_calc=std::numeric_limits<float>::max(), zmax_calc=-zmin_calc;
99  for(unsigned j = 0; j<nj; j+=stride_interval)
100  for(unsigned i = 0; i<ni; i+=stride_interval){
101  float z = dem_view_(i,j);
102  if(z <= 0.0)
103  continue;
104  z_samples.push_back(z);
105  }
106  // sort the samples to remove tails due to DEM errors
107  std::sort(z_samples.begin(), z_samples.end());
108  // remove the tails and compute min max elevations
109  auto ns = static_cast<double>(z_samples.size());
110  auto band_size = static_cast<unsigned>(ns*tail_fract_);
111  for(unsigned k = band_size; k<(ns-band_size); ++k){
112  double z = z_samples[k];
113  if(z<zmin_calc) zmin_calc = static_cast<float>(z);
114  if(z>zmax_calc) zmax_calc = z;
115  }
116  //the final elevation bounds
117  z_min_ = zmin_calc;
118  z_max_ = zmax_calc;
119  }
120 
121  if(verbose_) std::cout << "[ZMIN,ZMAX]=[" << z_min_ << "," << z_max_ << "]" << std::endl;
122 }
124  if(geo_cam_)
125  delete geo_cam_;
126  geo_cam_ = nullptr;
127 }
128 // the function to backproject onto the dem using vgl objects
130  vgl_point_2d<double> const& image_point,
131  double max_z, double min_z,
132  vgl_point_3d<double> const& initial_guess,
133  vgl_point_3d<double> & world_point,
134  double error_tol){
135 if(verbose_) std::cout << "vpgl_backproj_dem " << image_point << " max_z " << max_z << " min_z " << min_z << " init_guess " << initial_guess << " error tol " << error_tol << std::endl;
136  //compute the ray corresponding to the image point
137  double dz = (max_z - min_z);
138  vgl_point_2d<double> initial_xy(initial_guess.x(), initial_guess.y());
139  vgl_ray_3d<double> ray;
140  if(!vpgl_ray::ray(cam, image_point, initial_xy, max_z, dz, ray)){
141  if(verbose_) std::cout << " compute camera ray failed - Fatal!" << std::endl;
142  return false;
143  }
144  vgl_point_3d<double> origin = ray.origin();
145  //find min parameter on ray
146  vgl_vector_3d<double> dir = ray.direction();
147  if(std::fabs(dir.z())<0.001){
148  if(verbose_) std::cout << "Ray parallel to XY plane - Fatal!" << std::endl;
149  return false;
150  }
151  //inital guess at ray parameter
152  double t = (initial_guess.z() - max_z)/dir.z();
153 
154  //check if guess is inside DEM - could be too conservative for very oblique cameras
155  vgl_point_3d<double> guess_point = origin + t*dir;
156  double lon = guess_point.x(), lat = guess_point.y(),elev = guess_point.z();
157  double ud, vd;
158  //Note that elevation has no effect in the project function - just required to meet the interface of an abstract camera
159  geo_cam_->project(lon, lat, elev, ud, vd);
160  int u = static_cast<int>(ud+0.5), v = static_cast<int>(vd+0.5);
161  int ni = dem_view_.ni(), nj = dem_view_.nj();
162  if(u<0||u>=ni||v<0||v>=nj){
163  if(verbose_) std::cout << "Initial guess for DEM intersection is outside DEM bounds - Fatal!" << std::endl;
164  return false;
165  }
166  // construct the brent minimizer
167  // note the brent minimzier is not fully integrated with the vil_nonlinear_minimizer interface
168  // thus the non standard call for error below
170  vnl_brent_minimizer brm(c);
171  double tmin = brm.minimize(t);
172  double error = brm.f_at_last_minimum();
173  if(error>error_tol)
174  return false;
175 
176  world_point = origin + tmin*dir;
177 
178  if(verbose_) std::cout << "success! ray/dem intersection " << world_point << std::endl;
179  return true;
180 }
181 
182 bool vpgl_backproject_dem::bproj_dem(const vpgl_camera<double>* cam, vnl_double_2 const& image_point,
183  double max_z, double min_z, vnl_double_3 const& initial_guess, vnl_double_3& world_point,
184  double error_tol){
185  vgl_point_2d<double> img_pt;
186  vgl_point_3d<double> init_guess;
187  vgl_point_3d<double> wrld_pt;
188  img_pt.set(image_point[0], image_point[1]);
189  init_guess.set(initial_guess[0],initial_guess[1],initial_guess[2]);
190  bool good = this->bproj_dem(cam, img_pt, max_z, min_z, init_guess, wrld_pt, error_tol);
191 
192  if(!good){
193  return false;
194  }
195  world_point[0]=wrld_pt.x(); world_point[1]=wrld_pt.y(); world_point[2]=wrld_pt.z();
196  return true;
197 }
198 
199 bool vpgl_backproject_dem::bproj_dem(vpgl_rational_camera<double> const& rcam, vnl_double_2 const& image_point, double max_z, double min_z,
200  vnl_double_3 const& initial_guess, vnl_double_3& world_point, double error_tol){
201 
202  const auto* cam = dynamic_cast<const vpgl_camera<double>* >(&rcam);
203  return this->bproj_dem(cam, image_point, max_z, min_z, initial_guess, world_point, error_tol);
204 }
205 
206 bool vpgl_backproject_dem::bproj_dem(vpgl_rational_camera<double> const& rcam, vgl_point_2d<double> const& image_point, double max_z, double min_z,
207  vgl_point_3d<double> const& initial_guess, vgl_point_3d<double>& world_point, double error_tol){
208 
209  const auto* cam = dynamic_cast<const vpgl_camera<double>* >(&rcam);
210  return this->bproj_dem(cam, image_point, max_z, min_z, initial_guess, world_point, error_tol);
211 }
static bool ray(const vpgl_camera< double > *cam, vnl_double_3 const &point_3d, vnl_double_3 &ray)
Generic camera interfaces (pointer for abstract class).
Definition: vpgl_ray.cxx:19
vil_image_view< float > dem_view_
dem_bproj_cost_function(vil_image_view< float > const &dem_view, vpgl_geo_camera *geo_cam, vgl_ray_3d< double > const &ray, bool verbose=false)
void img_to_global(const double i, const double j, double &lon, double &lat) const
returns the corresponding geographical coordinates for a given pixel position (i,j).
Type & z()
vpgl_geo_camera * geo_cam_
#define v
vgl_point_3d< double > geo_center_
double z_min_
bounds of the DEM.
vpgl_backproject_dem(vil_image_resource_sptr const &dem, double zmin=0.0, double zmax=-1.0)
default constructor not allowed.
void set(Type px, Type py)
std::vector< vgl_point_3d< double > > dem_corners_
A geotiff image deduced camera class.
double minimize(double ax)
const vil_image_view< float > * dview_
bool bproj_dem(const vpgl_camera< double > *cam, vnl_double_2 const &image_point, double max_z, double min_z, vnl_double_3 const &initial_guess, vnl_double_3 &world_point, double error_tol=1.0)
General camera - typically a RPC camera.
T x() const
static bool init_geo_camera(vil_image_resource_sptr const &geotiff_img, const vpgl_lvcs_sptr &lvcs, vpgl_geo_camera *&camera)
uses lvcs to convert local x-y to global longitude and latitude.
T z() const
vgl_point_3d< Type > origin() const
Type & x()
double f(vnl_vector< double > const &x) override
x is the parameter that runs along the ray, with x=0 at the ray origin.
double zmax() const
elevation bounds of the DEM (with tail removal).
Camera backproject functions involving geotiff DEMs.
void set(Type px, Type py, Type pz)
vil_image_resource_sptr dem_
double f_at_last_minimum() const
void project(const double x, const double y, const double z, double &u, double &v) const override
Implementing the generic camera interface of vpgl_camera.
Methods for computing the camera ray direction at a given 3-d point and other operations on camera ra...
vgl_vector_3d< Type > direction() const
Methods for back_projecting from cameras to 3-d geometric structures.
Type & y()