1 // This is brl/bseg/boxm2/pro/processes/boxm2_dem_to_xyz_process.cxx
2 #include <fstream>
3 #include <iostream>
4 #include <algorithm>
5 #include <bprb/bprb_func_process.h>
6 //:
7 // \file
8 // \brief A process to prepare x y z images from a geotiff dem, the resolutions are adjusted with respect to scene resolution.
9 // E.g. if DEM is a 10 m resolution and scene is of 1m resolution, then the output images are resampled versions of DEM
10 // given x,y,z images use ingest_dem process to initialize model
11 //
12 // If a camera is passed as input (e.g. given by a previous process that reads it from tfw file then use it,
13 // otherwise try reading it from geotiff header
14 //
15 // \author Ozge C. Ozcanli
16 // \date May 02, 2012
17
18 #include <boxm2/boxm2_scene.h>
19
20 #include <vpgl/file_formats/vpgl_geo_camera.h>
21 #include "vpgl/vpgl_generic_camera.h"
22 #include "vil/vil_image_view.h"
23 #include "vil/vil_image_resource.h"
24 #include "vil/vil_load.h"
25 #ifdef _MSC_VER
26 # include "vcl_msvc_warnings.h"
27 #endif
28 //#include "vil/vil_resample_bilin.h"
29 #include "vil/vil_convert.h"
30 #include "vil/vil_new.h"
31
32 #include <vsol/vsol_box_2d_sptr.h>
33 #include <vsol/vsol_box_2d.h>
34
35 #include <brip/brip_roi.h>
36
37
38 namespace boxm2_dem_to_xyz_process_globals
39 {
40 constexpr unsigned n_inputs_ = 5;
41 constexpr unsigned n_outputs_ = 3;
42 }
43
boxm2_dem_to_xyz_process_cons(bprb_func_process & pro)44 bool boxm2_dem_to_xyz_process_cons(bprb_func_process& pro)
45 {
46 using namespace boxm2_dem_to_xyz_process_globals;
47
48 //process takes 1 input
49 std::vector<std::string> input_types_(n_inputs_);
50 input_types_[0] = "boxm2_scene_sptr";
51 input_types_[1] = "vcl_string"; // geotiff image of DEM
52 input_types_[2] = "double"; // lvcs is using wgs84 so wrt ellipsoid, however some DEMs are using geoid,
53 // in that case pass the distance between ellipsoid and geoid in the region
54 // to convert DEM heights to heights wrt to ellipsoid
55 input_types_[3] = "vpgl_camera_double_sptr"; // geocam if available, otherwise pass 0, camera will be constructed using info in geotiff header
56 input_types_[4] = "float"; // some DEMs have gaps or invalid regions, pass the value in the DEM imagery that is used to fill those areas.
57
58 // process has 1 outputs:
59 std::vector<std::string> output_types_(n_outputs_);
60 output_types_[0] = "vil_image_view_base_sptr"; // x image
61 output_types_[1] = "vil_image_view_base_sptr"; // y image
62 output_types_[2] = "vil_image_view_base_sptr"; // z image
63
64 bool good = pro.set_input_types(input_types_) && pro.set_output_types(output_types_);
65
66 // set input defaults
67 brdb_value_sptr geocam = new brdb_value_t<vpgl_camera_double_sptr>;
68 pro.set_input(3, geocam);
69
70 return good;
71 }
72
upsample_dem(vil_image_resource_sptr & out_img_res,unsigned ni,unsigned nj,vil_image_view<float> * dem_view,unsigned dem_ni,unsigned dem_nj)73 bool upsample_dem(vil_image_resource_sptr& out_img_res, unsigned ni, unsigned nj, vil_image_view<float>* dem_view, unsigned dem_ni, unsigned dem_nj)
74 {
75 if (dem_ni == ni && dem_nj == nj) {
76 out_img_res->put_view(*dem_view, 0,0);
77 return true;
78 }
79 else if (dem_ni > ni || dem_nj > nj) {
80 std::cerr << "in upsample_dem() -- cannot downsample image, image sizes are incompatible!\n";
81 return false;
82 }
83 int block_ni = ni/dem_ni;
84 int block_nj = nj/dem_nj;
85 std::cout << "ni: " << ni << " dem_ni: " << dem_ni << " block_ni: " << block_ni << '\n'
86 << "nj: " << nj << " dem_nj: " << dem_nj << " block_nj: " << block_nj << std::endl;
87 for (unsigned i = 0; i < dem_ni; i++) {
88 for (unsigned j = 0; j < dem_nj; j++) {
89 vil_image_view<float> block(block_ni, block_nj, 1);
90 block.fill((*dem_view)(i,j));
91 out_img_res->put_view(block, i*block_ni, j*block_nj);
92 }
93 }
94 return true;
95 }
96
boxm2_dem_to_xyz_process(bprb_func_process & pro)97 bool boxm2_dem_to_xyz_process(bprb_func_process& pro)
98 {
99 using namespace boxm2_dem_to_xyz_process_globals;
100
101 if ( pro.n_inputs() < n_inputs_ ){
102 std::cout << pro.name() << ": The input number should be " << n_inputs_<< std::endl;
103 return false;
104 }
105 //get the inputs
106 boxm2_scene_sptr scene = pro.get_input<boxm2_scene_sptr>(0);
107 vpgl_lvcs_sptr lvcs = new vpgl_lvcs(scene->lvcs());
108 std::string geotiff_fname = pro.get_input<std::string>(1);
109 auto geoid_height = pro.get_input<double>(2);
110 vpgl_camera_double_sptr cam = pro.get_input<vpgl_camera_double_sptr>(3);
111 auto fill_in_value = pro.get_input<float>(4);
112
113 vil_image_resource_sptr dem_res = vil_load_image_resource(geotiff_fname.c_str());
114
115 vpgl_geo_camera* geocam = nullptr;
116 if (cam && (geocam = dynamic_cast<vpgl_geo_camera*> (cam.ptr())) ) {
117 std::cout << "Using the loaded camera!\n";
118 }
119 else {
120 vpgl_geo_camera::init_geo_camera(dem_res, lvcs, geocam); // FIXME leaking geocam. This pattern is everywhere...
121 }
122
123 if (!geocam) {
124 std::cerr << "In boxm2_dem_to_xyz_process() - the geocam could not be initialized!\n";
125 return false;
126 }
127
128 vgl_box_3d<double> scene_bbox = scene->bounding_box();
129 std::vector<boxm2_block_id> blks = scene->get_block_ids();
130 if (blks.size() < 1)
131 return false;
132
133 unsigned orig_dem_ni = dem_res->ni(); unsigned orig_dem_nj = dem_res->nj();
134 std::cout << "original dem resolution: " << orig_dem_ni << ' ' << orig_dem_nj << std::endl;
135 brip_roi broi(orig_dem_ni, orig_dem_nj);
136 vsol_box_2d_sptr bb = new vsol_box_2d();
137
138 double u,v;
139 geocam->project(scene_bbox.min_x(), scene_bbox.min_y(), scene_bbox.min_z(), u, v);
140 bb->add_point(u,v);
141 geocam->project(scene_bbox.max_x(), scene_bbox.max_y(), scene_bbox.max_z(), u, v);
142 bb->add_point(u,v);
143 bb = broi.clip_to_image_bounds(bb);
144 if (bb->width() <= 0 || bb->height() <= 0) {
145 std::cout << "In boxm2_dem_to_xyz_process() -- " << geotiff_fname << " does not overlap the scene!\n";
146 return false;
147 }
148
149 vil_image_view_base_sptr dem_view_float;
150 vil_image_view_base_sptr dem_view_base = dem_res->get_view(0, orig_dem_ni, 0, orig_dem_nj);
151 auto* dem_view = dynamic_cast<vil_image_view<float>*>(dem_view_base.ptr());
152 if (!dem_view) {
153 vil_image_view<float> temp(dem_view_base->ni(), dem_view_base->nj(), 1);
154
155 auto* dem_view_int = dynamic_cast<vil_image_view<vxl_int_16>*>(dem_view_base.ptr());
156 if (!dem_view_int) {
157 auto* dem_view_byte = dynamic_cast<vil_image_view<vxl_byte>*>(dem_view_base.ptr());
158 if (!dem_view_byte) {
159 std::cerr << "Error: boxm2_dem_to_xyz_process: The image pixel format: " << dem_view_base->pixel_format() << " is not supported!\n";
160 return false;
161 }
162 else {
163 vil_convert_cast(*dem_view_byte, temp);
164 }
165 }
166 else {
167 vil_convert_cast(*dem_view_int, temp);
168 }
169
170 dem_view_float = new vil_image_view<float>(temp); // shallow copy
171 dem_view = dynamic_cast<vil_image_view<float>*>(dem_view_float.ptr());
172 //assert(dev_view);
173 }
174
175 boxm2_scene_info* info = scene->get_blk_metadata(blks[0]);
176 float sb_length = info->block_len;
177 float vox_length = sb_length/8.0f;
178
179 // prepare an image for the finest resolution
180 int ni = (int)std::ceil((scene_bbox.max_x()-scene_bbox.min_x())/vox_length);
181 int nj = (int)std::ceil((scene_bbox.max_y()-scene_bbox.min_y())/vox_length);
182
183 std::cout <<"ni: " << ni << " nj: " << nj << std::endl;
184
185 // create x y z images
186 auto* out_img_x = new vil_image_view<float>(ni, nj, 1);
187 auto* out_img_y = new vil_image_view<float>(ni, nj, 1);
188 auto* out_img_z = new vil_image_view<float>(ni, nj, 1);
189 // initialize the image by scene origin
190 out_img_x->fill(-10.0f);
191 out_img_y->fill(-10.0f);
192 out_img_z->fill(-1.0f);
193 //out_img_x->fill((float)(scene_bbox.min_x())-10.0f); // local coord system min z
194 //out_img_y->fill((float)(scene_bbox.min_y())-10.0f); // local coord system min z
195 //out_img_z->fill((float)(scene_bbox.min_z())-1.0f); // local coord system min z
196 std::cout << "out img x(0,0): " << ((*out_img_x)(0,0))
197 << "\nout img y(0,0): " << ((*out_img_y)(0,0))
198 << "\nout img z(0,0): " << ((*out_img_z)(0,0)) << std::endl;
199
200 double lon,lat,gz;
201 lvcs->local_to_global(0,0,0,vpgl_lvcs::wgs84,lon, lat, gz);
202 std::cout << "lvcs origin height: " << gz << std::endl;
203 gz += geoid_height; // correct for the difference to geoid if necessary, geoid_height should have been passed 0 if that is not necessary
204 //gz += scene_bbox.min_z();
205
206 std::cout << " scene min z: " << scene_bbox.min_z() << " gz: " << gz << std::endl;
207 if (fill_in_value <= 0)
208 fill_in_value = std::numeric_limits<float>::max();
209
210 for (int i = 0; i < ni; ++i)
211 for (int j = 0; j < nj; ++j) {
212 auto local_x = (float)(i*vox_length+scene_bbox.min_x()+vox_length/2.0);
213 auto local_y = (float)(scene_bbox.max_y()-j*vox_length+vox_length/2.0);
214 (*out_img_x)(i,j) = local_x;
215 (*out_img_y)(i,j) = local_y;
216
217 double u,v;
218 geocam->project(local_x, local_y, scene_bbox.min_z(), u, v);
219 // for now just cast to the nearest pixel in DEM, might want to sample bilinearly
220 int uu = (int)std::floor(u+0.5);
221 int vv = (int)std::floor(v+0.5);
222 if (uu >= 0 && vv >= 0 && uu < (int)orig_dem_ni && vv < (int)orig_dem_nj) {
223 if ((*dem_view)(uu,vv) < fill_in_value) // otherwise it remains at local min z
224 (*out_img_z)(i,j) = (*dem_view)(uu,vv)-(float)gz; // we need local height
225 }
226 }
227
228 pro.set_output_val<vil_image_view_base_sptr>(0, out_img_x);
229 pro.set_output_val<vil_image_view_base_sptr>(1, out_img_y);
230 pro.set_output_val<vil_image_view_base_sptr>(2, out_img_z);
231
232 return true;
233 }
234
235 //: Craete x y z images from the shadow height map of an ortho aerial image
236
237 namespace boxm2_shadow_heights_to_xyz_process_globals
238 {
239 constexpr unsigned n_inputs_ = 5;
240 constexpr unsigned n_outputs_ = 3;
241 }
242
boxm2_shadow_heights_to_xyz_process_cons(bprb_func_process & pro)243 bool boxm2_shadow_heights_to_xyz_process_cons(bprb_func_process& pro)
244 {
245 using namespace boxm2_shadow_heights_to_xyz_process_globals;
246
247 //process takes 5 inputs
248 std::vector<std::string> input_types_(n_inputs_);
249 input_types_[0] = "boxm2_scene_sptr";
250 input_types_[1] = "vil_image_view_base_sptr"; // shadow height map image of the cropped ortho aerial image, height values are in pixels with respect to a horizontal surface at the base of the object
251 input_types_[2] = "vpgl_camera_double_sptr"; // generic cam of cropped ortho aerial image (to be given by roi_init_geotiff_process)
252 input_types_[3] = "vcl_string"; // dem_fname, height image values will be added to these values
253 input_types_[4] = "double"; // pixel scaling
254
255 // process has 3 outputs:
256 std::vector<std::string> output_types_(n_outputs_);
257 output_types_[0] = "vil_image_view_base_sptr"; // x image
258 output_types_[1] = "vil_image_view_base_sptr"; // y image
259 output_types_[2] = "vil_image_view_base_sptr"; // z image
260
261 return pro.set_input_types(input_types_) && pro.set_output_types(output_types_);
262 }
263
boxm2_shadow_heights_to_xyz_process(bprb_func_process & pro)264 bool boxm2_shadow_heights_to_xyz_process(bprb_func_process& pro)
265 {
266 using namespace boxm2_shadow_heights_to_xyz_process_globals;
267
268 if ( pro.n_inputs() < n_inputs_ ){
269 std::cout << pro.name() << ": The input number should be " << n_inputs_<< std::endl;
270 return false;
271 }
272 //get the inputs
273 boxm2_scene_sptr scene = pro.get_input<boxm2_scene_sptr>(0);
274 vpgl_lvcs_sptr lvcs = new vpgl_lvcs(scene->lvcs());
275 vil_image_view_base_sptr img = pro.get_input<vil_image_view_base_sptr>(1);
276 vpgl_camera_double_sptr cam = pro.get_input<vpgl_camera_double_sptr>(2);
277 std::string geotiff_fname = pro.get_input<std::string>(3);
278 auto scale = pro.get_input<double>(4);
279
280 auto* gcam=dynamic_cast<vpgl_generic_camera<double>*> (cam.ptr());
281
282 vil_image_view<float> height_img(img);
283 unsigned ni = height_img.ni();
284 unsigned nj = height_img.nj();
285
286 if (gcam->rows() != nj || gcam->cols() !=ni) {
287 std::cerr << "In boxm2_shadow_heights_to_xyz_process() - generic cam and height image sizes are not compatible!\n"
288 << "gcam rows: " << gcam->rows() << " cols: " << gcam->cols() << " ni: " << ni << " nj: " << nj << '\n';
289 return false;
290 }
291
292 vil_image_resource_sptr dem_res = vil_load_image_resource(geotiff_fname.c_str());
293 vpgl_geo_camera* geocam = nullptr;
294 vpgl_geo_camera::init_geo_camera(dem_res, lvcs, geocam);
295
296 vgl_box_3d<double> scene_bbox = scene->bounding_box();
297 std::vector<boxm2_block_id> blks = scene->get_block_ids();
298 if (blks.size() < 1)
299 return false;
300
301 // crop the image from the DEM
302 vgl_box_2d<double> proj_bbox;
303 double u,v;
304 geocam->project(scene_bbox.min_x(), scene_bbox.min_y(), scene_bbox.min_z(), u, v);
305 proj_bbox.add(vgl_point_2d<double>(u,v));
306 geocam->project(scene_bbox.max_x(), scene_bbox.max_y(), scene_bbox.max_z(), u, v);
307 proj_bbox.add(vgl_point_2d<double>(u,v));
308 int min_i = int(std::max(0.0, std::floor(proj_bbox.min_x())));
309 int min_j = int(std::max(0.0, std::floor(proj_bbox.min_y())));
310 int max_i = int(std::min(dem_res->ni()-1.0, std::ceil(proj_bbox.max_x())));
311 int max_j = int(std::min(dem_res->nj()-1.0, std::ceil(proj_bbox.max_y())));
312 std::cout << "scene projected in the image mini: " << min_i << " minj: " << min_j << " maxi: " << max_i << " maxj: " << max_j << std::endl;
313 unsigned int dem_ni = max_i - min_i + 1;
314 unsigned int dem_nj = max_j - min_j + 1;
315 vil_image_view_base_sptr dem_view_base = dem_res->get_view((unsigned int)min_i, dem_ni, (unsigned int)min_j, dem_nj);
316 auto* dem_view = dynamic_cast<vil_image_view<float>*>(dem_view_base.ptr());
317 if (!dem_view) {
318 std::cerr << "Error: boxm2_dem_to_xyz_process: could not cast first return image to a vil_image_view<float>\n";
319 return false;
320 }
321 std::cout << "dem resolution is: " << dem_ni << " by " << dem_nj << std::endl;
322
323 auto* out_img = new vil_image_view<float>(ni, nj, 1);
324 vil_image_resource_sptr out_img_res = vil_new_image_resource_of_view(*out_img);
325
326 if (!upsample_dem(out_img_res, ni, nj, dem_view, dem_ni, dem_nj))
327 return false;
328
329 // create x y z images
330 auto* out_img_x = new vil_image_view<float>(ni, nj, 1);
331 auto* out_img_y = new vil_image_view<float>(ni, nj, 1);
332 auto* out_img_z = new vil_image_view<float>(ni, nj, 1);
333
334 double lon,lat,gz;
335 lvcs->local_to_global(0,0,0,vpgl_lvcs::wgs84,lon, lat, gz);
336
337 for (unsigned i = 0; i < ni; i++)
338 for (unsigned j = 0; j < nj; j++) {
339 vgl_ray_3d<double> ray = gcam->ray(i,j);
340 vgl_point_3d<double> o = ray.origin();
341 (*out_img_x)(i,j) = (float)o.x();
342 (*out_img_y)(i,j) = (float)o.y();
343 if (height_img(i,j) >= 0) {
344 (*out_img_z)(i,j) = (float)(height_img(i,j)*scale+(*out_img)(i,j)-gz); // we need local height
345 }
346 else
347 (*out_img_z)(i,j) = (*out_img)(i,j)-(float)gz; // we need local height
348 }
349
350 pro.set_output_val<vil_image_view_base_sptr>(0, out_img_x);
351 pro.set_output_val<vil_image_view_base_sptr>(1, out_img_y);
352 pro.set_output_val<vil_image_view_base_sptr>(2, out_img_z);
353 return true;
354 }
355
356 namespace boxm2_dem_to_xyz_process2_globals
357 {
358 constexpr unsigned n_inputs_ = 5;
359 constexpr unsigned n_outputs_ = 3;
360 }
361
boxm2_dem_to_xyz_process2_cons(bprb_func_process & pro)362 bool boxm2_dem_to_xyz_process2_cons(bprb_func_process& pro)
363 {
364 using namespace boxm2_dem_to_xyz_process2_globals;
365
366 //process takes 1 input
367 std::vector<std::string> input_types_(n_inputs_);
368 input_types_[0] = "boxm2_scene_sptr";
369 input_types_[1] = "vcl_string"; // geotiff image of DEM
370 input_types_[2] = "double"; // lvcs is using wgs84 so wrt ellipsoid, however some DEMs are using geoid,
371 // in that case pass the distance between ellipsoid and geoid in the region
372 // to convert DEM heights to heights wrt to ellipsoid
373 input_types_[3] = "vpgl_camera_double_sptr"; // geocam if available, otherwise pass 0, camera will be constructed using info in geotiff header
374 input_types_[4] = "float"; // some DEMs have gaps or invalid regions, pass the value in the DEM imagery that is used to fill those areas.
375
376 // process has 1 outputs:
377 std::vector<std::string> output_types_(n_outputs_);
378 output_types_[0] = "vil_image_view_base_sptr"; // x image
379 output_types_[1] = "vil_image_view_base_sptr"; // y image
380 output_types_[2] = "vil_image_view_base_sptr"; // z image
381
382 bool good = pro.set_input_types(input_types_) && pro.set_output_types(output_types_);
383
384 // set input defaults
385 brdb_value_sptr geocam = new brdb_value_t<vpgl_camera_double_sptr>;
386 pro.set_input(3, geocam);
387
388 return good;
389 }
390
boxm2_dem_to_xyz_process2(bprb_func_process & pro)391 bool boxm2_dem_to_xyz_process2(bprb_func_process& pro)
392 {
393 using namespace boxm2_dem_to_xyz_process2_globals;
394
395 if ( pro.n_inputs() < n_inputs_ ){
396 std::cout << pro.name() << ": The input number should be " << n_inputs_<< std::endl;
397 return false;
398 }
399 //get the inputs
400 boxm2_scene_sptr scene = pro.get_input<boxm2_scene_sptr>(0);
401 vpgl_lvcs_sptr lvcs = new vpgl_lvcs(scene->lvcs());
402 std::string geotiff_fname = pro.get_input<std::string>(1);
403 //double geoid_height = pro.get_input<double>(2); // TODO: unused!
404 vpgl_camera_double_sptr cam = pro.get_input<vpgl_camera_double_sptr>(3);
405 //float fill_in_value = pro.get_input<float>(4); // TODO: unused!
406
407 vil_image_resource_sptr dem_res = vil_load_image_resource(geotiff_fname.c_str());
408
409 vpgl_geo_camera* geocam = nullptr;
410 if ( cam && (geocam = dynamic_cast<vpgl_geo_camera*> (cam.ptr())) ) {
411 std::cout << "Using the loaded camera!\n";
412 }
413 else {
414 vpgl_geo_camera::init_geo_camera(dem_res, lvcs, geocam);
415 }
416
417 if (!geocam) {
418 std::cerr << "In boxm2_dem_to_xyz_process() - the geocam could not be initialized!\n";
419 return false;
420 }
421
422 vgl_box_3d<double> scene_bbox = scene->bounding_box();
423 std::vector<boxm2_block_id> blks = scene->get_block_ids();
424 if (blks.size() < 1)
425 return false;
426
427 unsigned orig_dem_ni = dem_res->ni(),
428 orig_dem_nj = dem_res->nj();
429 std::cout << "original dem resolution: " << orig_dem_ni << ' ' << orig_dem_nj << std::endl;
430 brip_roi broi(orig_dem_ni, orig_dem_nj);
431 vsol_box_2d_sptr bb = new vsol_box_2d();
432
433 double min_uu, min_vv, max_uu, max_vv;
434 geocam->project(scene_bbox.min_x(), scene_bbox.min_y(), scene_bbox.min_z(), min_uu, min_vv);
435 bb->add_point(min_uu,min_vv);
436 geocam->project(scene_bbox.max_x(), scene_bbox.max_y(), scene_bbox.max_z(), max_uu, max_vv);
437 bb->add_point(max_uu,max_vv);
438 bb = broi.clip_to_image_bounds(bb);
439 if (bb->width() <= 0 || bb->height() <= 0) {
440 std::cout << "In boxm2_dem_to_xyz_process() -- " << geotiff_fname << " does not overlap the scene!\n";
441 return false;
442 }
443 std::cout <<"projected scene bbox: " << *bb << std::endl;
444
445 unsigned int min_i = min_uu > 0 ? (unsigned int)min_uu : 0;
446 unsigned int min_j = max_vv > 0 ? (unsigned int)max_vv : 0; // scene box min projects to lower left corner of the scene in the image
447
448 //int ni = max_uu-min_uu+1 < orig_dem_ni ? (int)(max_uu-min_uu+1) : orig_dem_ni;
449 //int nj = min_vv-max_vv+1 < orig_dem_nj ? (int)(min_vv-max_vv+1) : orig_dem_nj;
450 int ni = bb->get_max_x() - bb->get_min_x() + 1;
451 int nj = bb->get_max_y() - bb->get_min_y() + 1;
452
453 std::cout << "min_uu: " << min_uu << " min_vv: " << min_vv
454 <<"\nmax_uu: " << max_uu << " max_vv: " << max_vv
455 <<"\nmin_i: " << min_i << " min_j: " << min_j << " ni: " << ni << " nj: " << nj << std::endl;
456
457 vil_image_view_base_sptr dem_view_base = dem_res->get_view(min_i, ni, min_j, nj);
458 auto* dem_view = dynamic_cast<vil_image_view<float>*>(dem_view_base.ptr());
459 if (!dem_view) {
460 vil_image_view<float> temp(dem_view_base->ni(), dem_view_base->nj(), 1);
461
462 auto* dem_view_int = dynamic_cast<vil_image_view<vxl_int_16>*>(dem_view_base.ptr());
463 if (!dem_view_int) {
464 auto* dem_view_byte = dynamic_cast<vil_image_view<vxl_byte>*>(dem_view_base.ptr());
465 if (!dem_view_byte) {
466 std::cerr << "Error: boxm2_dem_to_xyz_process: The image pixel format: " << dem_view_base->pixel_format() << " is not supported!\n";
467 return false;
468 }
469 else
470 vil_convert_cast(*dem_view_byte, temp);
471 }
472 else
473 vil_convert_cast(*dem_view_int, temp);
474 dem_view = new vil_image_view<float>(temp);
475 }
476 std::cout <<"got dem image!" << std::endl;
477
478 boxm2_scene_info* info = scene->get_blk_metadata(blks[0]);
479 float sb_length = info->block_len;
480 std::cout <<"sb_length: " << sb_length << "!\n\n"
481 <<"ni: " << ni << " nj: " << nj << std::endl;
482
483 // create x y z images
484 auto* out_img_x = new vil_image_view<float>(ni, nj, 1);
485 auto* out_img_y = new vil_image_view<float>(ni, nj, 1);
486 auto* out_img_z = new vil_image_view<float>(ni, nj, 1);
487 out_img_x->fill((float)(scene_bbox.min_x())-10.0f); // local coord system min z
488 out_img_y->fill((float)(scene_bbox.min_y())-10.0f); // local coord system min z
489 out_img_z->fill((float)(scene_bbox.min_z())-1.0f); // local coord system min z
490 std::cout << "out img x(0,0): " << ((*out_img_x)(0,0))
491 << "\nout img y(0,0): " << ((*out_img_y)(0,0))
492 << "\nout img z(0,0): " << ((*out_img_z)(0,0)) << std::endl;
493
494 for (int i = 0; i < ni; ++i)
495 for (int j = 0; j < nj; ++j) {
496 // find the global coord of this pixel
497 double lon, lat;
498 geocam->img_to_global(i+min_i, j+min_j, lon, lat);
499 // find the local coord of this global position
500 double lx, ly, lz;
501 lvcs->global_to_local(lon, lat, (*dem_view)(i,j), vpgl_lvcs::wgs84, lx, ly, lz);
502 vgl_point_3d<double> pt(lx, ly, lz);
503 (*out_img_x)(i,j) = (float)lx;
504 (*out_img_y)(i,j) = (float)ly;
505 (*out_img_z)(i,j) = (float)lz;
506 }
507
508 pro.set_output_val<vil_image_view_base_sptr>(0, out_img_x);
509 pro.set_output_val<vil_image_view_base_sptr>(1, out_img_y);
510 pro.set_output_val<vil_image_view_base_sptr>(2, out_img_z);
511
512 return true;
513 }
514
515
516 namespace boxm2_initialize_ground_xyz_process_globals
517 {
518 constexpr unsigned n_inputs_ = 2;
519 constexpr unsigned n_outputs_ = 3;
520 }
521
boxm2_initialize_ground_xyz_process_cons(bprb_func_process & pro)522 bool boxm2_initialize_ground_xyz_process_cons(bprb_func_process& pro)
523 {
524 using namespace boxm2_initialize_ground_xyz_process_globals;
525
526 std::vector<std::string> input_types_(n_inputs_);
527 input_types_[0] = "boxm2_scene_sptr";
528 input_types_[1] = "int"; // desired height of ground plane in global coords, e.g. for ground plane to be at global z = 0, pass 0
529
530 std::vector<std::string> output_types_(n_outputs_);
531 output_types_[0] = "vil_image_view_base_sptr"; // x image
532 output_types_[1] = "vil_image_view_base_sptr"; // y image
533 output_types_[2] = "vil_image_view_base_sptr"; // z image
534
535 return pro.set_input_types(input_types_) && pro.set_output_types(output_types_);
536 }
537
boxm2_initialize_ground_xyz_process(bprb_func_process & pro)538 bool boxm2_initialize_ground_xyz_process(bprb_func_process& pro)
539 {
540 using namespace boxm2_initialize_ground_xyz_process_globals;
541
542 if ( pro.n_inputs() < n_inputs_ ){
543 std::cout << pro.name() << ": The input number should be " << n_inputs_<< std::endl;
544 return false;
545 }
546 //get the inputs
547 boxm2_scene_sptr scene = pro.get_input<boxm2_scene_sptr>(0);
548 int ground_height = pro.get_input<int>(1);
549
550 vgl_box_3d<double> scene_bbox = scene->bounding_box();
551
552 std::vector<boxm2_block_id> blks = scene->get_block_ids();
553 boxm2_scene_info* info = scene->get_blk_metadata(blks[0]);
554 float sb_length = info->block_len;
555 float vox_length = sb_length/8.0f;
556 std::cout << "voxel length: " << vox_length;
557
558 // prepare an image for the finest resolution
559 int ni = (int)std::ceil((scene_bbox.max_x()-scene_bbox.min_x()+1.0)/vox_length);
560 int nj = (int)std::ceil((scene_bbox.max_y()-scene_bbox.min_y()+1.0)/vox_length);
561 std::cout <<"image size needs ni: " << ni << " nj: " << nj << " to support voxel res: " << vox_length << std::endl;
562
563 // create x y z images
564 auto* out_img_x = new vil_image_view<float>(ni, nj, 1);
565 auto* out_img_y = new vil_image_view<float>(ni, nj, 1);
566 auto* out_img_z = new vil_image_view<float>(ni, nj, 1);
567 out_img_x->fill((float)(scene_bbox.min_x())-10.0f); // local coord system min z
568 out_img_y->fill((float)(scene_bbox.min_y())-10.0f); // local coord system min z
569 out_img_z->fill((float)(scene_bbox.min_z())-1.0f); // local coord system min z
570
571 double lat, lon, elev; scene->lvcs().get_origin(lat, lon, elev);
572 std::cout << "global scene origin is at z = " << elev << std::endl;
573 double g_h = ground_height - elev;
574 std::cout << " in global coords, ground plane is at z = " << ground_height << '\n'
575 << " in local coords, this corresponds to z = " << scene_bbox.min_z()+g_h << '\n';
576
577 for (int i = 0; i < ni; i++)
578 for (int j = 0; j < nj; j++) {
579 (*out_img_x)(i,j) = i + 0.5;
580 (*out_img_y)(i,j) = nj - j + 0.5;
581 (*out_img_z)(i,j) = scene_bbox.min_z() + g_h; // g_h meters higher than min z
582 }
583 pro.set_output_val<vil_image_view_base_sptr>(0, out_img_x);
584 pro.set_output_val<vil_image_view_base_sptr>(1, out_img_y);
585 pro.set_output_val<vil_image_view_base_sptr>(2, out_img_z);
586 return true;
587 }
588