1 // This is brl/bseg/bvxm/pro/processes/bvxm_roi_init_process.cxx
2 #include "bvxm_roi_init_process.h"
3 //:
4 // \file
5 #include <bvxm/bvxm_voxel_world.h>
6 #include <bvxm/bvxm_world_params.h>
7 #include <bvxm/bvxm_util.h>
8
9 #include "vgl/vgl_point_2d.h"
10 #include "vgl/vgl_box_2d.h"
11 #include "vgl/vgl_box_3d.h"
12 #include "vgl/vgl_vector_3d.h"
13
14 #include <vsol/vsol_box_2d_sptr.h>
15 #include <vsol/vsol_box_2d.h>
16
17 #include <brip/brip_roi.h>
18
19 #include "vil/vil_load.h"
20 #include <vil/file_formats/vil_nitf2_image.h>
21 #include "vil/vil_image_view_base.h"
22 #include "vpgl/vpgl_local_rational_camera.h"
23
24 #include <bprb/bprb_parameters.h>
25
26 //: set input and output types
bvxm_roi_init_process_cons(bprb_func_process & pro)27 bool bvxm_roi_init_process_cons(bprb_func_process& pro)
28 {
29 using namespace bvxm_roi_init_process_globals;
30 //this process takes 4 input:
31 //the filename of the image, the camera and the voxel world
32 std::vector<std::string> input_types_(n_inputs_);
33 unsigned i=0;
34 input_types_[i++] = "vcl_string"; // NITF image path
35 input_types_[i++] = "vpgl_camera_double_sptr"; // rational camera
36 input_types_[i++] = "bvxm_voxel_world_sptr"; // voxel world spec
37 input_types_[i++] = "bool"; // option to keep less significant bits as casting nitf image
38 if (!pro.set_input_types(input_types_))
39 return false;
40
41 //output
42 unsigned j = 0;
43 std::vector<std::string> output_types_(n_outputs_);
44 output_types_[j++] = "vpgl_camera_double_sptr"; // unadjusted local rational camera
45 output_types_[j++] = "vil_image_view_base_sptr"; // image ROI
46 output_types_[j++] = "float"; // uncertainty
47 return pro.set_output_types(output_types_);
48 }
49
50
bvxm_roi_init_process(bprb_func_process & pro)51 bool bvxm_roi_init_process(bprb_func_process& pro)
52 {
53 using namespace bvxm_roi_init_process_globals;
54 //static const parameters
55 static const std::string error = "error";
56
57 if ( pro.n_inputs() < n_inputs_ ) {
58 std::cout << pro.name() << " The input number should be " << n_inputs_<< std::endl;
59 return false;
60 }
61
62 // get the inputs:
63 unsigned i = 0;
64 // image
65 std::string image_path = pro.get_input<std::string>(i++);
66 // camera
67 vpgl_camera_double_sptr camera = pro.get_input<vpgl_camera_double_sptr>(i++);
68 //voxel_world
69 bvxm_voxel_world_sptr voxel_world = pro.get_input<bvxm_voxel_world_sptr>(i++);
70 // option to truncated last 3 less important bits
71 bool is_all_bits = pro.get_input<bool>(i++);
72
73 // uncertainty (meters) -- SHOULD BE A PARAM
74 float uncertainty=0;
75 if ( !pro.parameters()->get_value(error, uncertainty) ) {
76 std::cout << pro.name() << ": error in retrieving parameters\n";
77 return false;
78 }
79
80 bvxm_world_params_sptr world_params = voxel_world->get_params();
81
82
83 auto* rat_camera =
84 dynamic_cast<vpgl_rational_camera<double>*> (camera.as_pointer());
85 if (!rat_camera) {
86 std::cerr << "The camera input is not a rational camera\n";
87 return false;
88 }
89
90 vpgl_local_rational_camera<double> local_camera;
91
92 if (!is_all_bits) { // throw the less important 3 bits in the nitf image and output an byte image
93 auto* img_ptr = new vil_image_view<unsigned char>();
94 if (!roi_init(image_path, rat_camera, world_params, uncertainty, img_ptr, local_camera)) {
95 std::cerr << "The process has failed!\n";
96 return false;
97 }
98 if (img_ptr->ni() == 0 || img_ptr->nj() == 0)
99 return false;
100 //Store outputs
101 unsigned j = 0;
102 // update the camera and store
103 pro.set_output_val<vpgl_camera_double_sptr >(j++, new vpgl_local_rational_camera<double> (local_camera));
104 // store image output
105 pro.set_output_val<vil_image_view_base_sptr>(j++, img_ptr);
106 // store uncertainty
107 pro.set_output_val<float>(j++, uncertainty);
108
109 return true;
110 }
111 else { // keep all 11 bits in the nitf image and output an short image
112 auto* img_ptr = new vil_image_view<vxl_uint_16>();
113 if (!roi_init(image_path, rat_camera, world_params, uncertainty, img_ptr, local_camera)) {
114 std::cerr << pro.name() << ": The process has failed!\n"; return false;
115 }
116 if (img_ptr->ni() == 0 || img_ptr->nj() == 0) {
117 std::cerr << pro.name() << ": The process has failed!\n"; return false;
118 }
119 // store outputs
120 unsigned j = 0;
121 // update the camera and store
122 pro.set_output_val<vpgl_camera_double_sptr >(j++, new vpgl_local_rational_camera<double> (local_camera));
123 // store image output
124 pro.set_output_val<vil_image_view_base_sptr>(j++, img_ptr);
125 // store uncertainty
126 pro.set_output_val<float>(j++, uncertainty);
127 return true;
128 }
129
130 }
131
132 //: roi_init function
roi_init(std::string const & image_path,vpgl_rational_camera<double> * camera,const bvxm_world_params_sptr & world_params,float error,vil_image_view<unsigned char> * nitf_image_unsigned_char,vpgl_local_rational_camera<double> & local_camera)133 bool bvxm_roi_init_process_globals::roi_init( std::string const& image_path,
134 vpgl_rational_camera<double>* camera,
135 const bvxm_world_params_sptr& world_params,
136 float error,
137 vil_image_view<unsigned char>* nitf_image_unsigned_char,
138 vpgl_local_rational_camera<double>& local_camera)
139 {
140 // read the image and extract the camera
141 vil_image_resource_sptr img = vil_load_image_resource(image_path.c_str());
142 std::string format = img->file_format();
143 std::string prefix = format.substr(0,4);
144 if (prefix.compare("nitf") != 0) {
145 std::cerr << "bvxm_roi_init_process::execute - The image should be an NITF\n";
146 return false;
147 }
148
149 auto* nitf = static_cast<vil_nitf2_image*> (img.ptr());
150
151 vgl_vector_3d<unsigned int> dims = world_params->num_voxels();
152 int dimx = dims.x();
153 int dimy = dims.y();
154 int dimz = dims.z();
155 double min_position[3];
156 double voxel_length = world_params->voxel_length();
157 min_position[0] = world_params->corner().x();
158 min_position[1] = world_params->corner().y();
159 min_position[2] = world_params->corner().z();
160 vgl_box_3d<double> box(min_position,
161 dimx*voxel_length,
162 dimy*voxel_length,
163 dimz*voxel_length,
164 vgl_box_3d<double>::min_pos);
165
166 vpgl_lvcs_sptr lvcs = world_params->lvcs();
167 vgl_box_2d<double>* roi_box = project_box(camera, lvcs, box, error);
168 std::cout << " roi box: " << *roi_box << std::endl;
169
170 brip_roi broi(nitf->ni(), nitf->nj());
171 vsol_box_2d_sptr bb = new vsol_box_2d();
172 bb->add_point(roi_box->min_x(), roi_box->min_y());
173 bb->add_point(roi_box->max_x(), roi_box->max_y());
174 bb = broi.clip_to_image_bounds(bb);
175
176 if (bb->width() <= 0 || bb->height() <= 0) {
177 std::cerr << "bvxm_roi_init_process::roi_init()-- clipping box is out of image boundaries\n";
178 return false;
179 }
180
181 vil_image_view_base_sptr roi =
182 nitf->get_copy_view((unsigned int)bb->get_min_x(),
183 (unsigned int)bb->width(),
184 (unsigned int)bb->get_min_y(),
185 (unsigned int)bb->height());
186
187 if (!roi) {
188 std::cerr << "bvxm_roi_init_process::roi_init()-- cannot get copy view from image!\n";
189 return false;
190 }
191
192 if (!roi.as_pointer())
193 return false;
194
195 if (roi->pixel_format() == VIL_PIXEL_FORMAT_UINT_16)
196 {
197 vil_image_view<vxl_uint_16> nitf_image_vxl_uint_16(roi);
198
199 *nitf_image_unsigned_char = vil_image_view<unsigned char> (roi->ni(),roi->nj(),roi->nplanes());
200
201 int bigendian = 0;
202 { union { unsigned int i; char c[4]; } u; u.i = 1; bigendian = u.c[0] == 0; }
203 for (unsigned m=0; m<nitf_image_unsigned_char->ni(); ++m)
204 {
205 for (unsigned n=0; n<nitf_image_unsigned_char->nj(); ++n)
206 {
207 for (unsigned p=0; p<nitf_image_unsigned_char->nplanes(); ++p)
208 {
209 // we will ignore the most significant 5 bits and less significant 3 bits
210 vxl_uint_16 curr_pixel_val = nitf_image_vxl_uint_16(m,n,p);
211
212 if (bigendian) {
213 auto* arr = (unsigned char*) &curr_pixel_val;
214 // [defgh3][5abc]
215 // --> [abcdefgh]
216 unsigned char big = *arr;
217 unsigned char small = *(++arr);
218 big >>= 3;
219 small <<= 5;
220 curr_pixel_val = big | small;
221 }
222 else { // little endian
223 // [5abc][defgh3]
224 // --> [abcdefgh35]
225 curr_pixel_val <<= 5;
226 // [abcdefgh35]
227 // --> [abcdefgh]
228 curr_pixel_val >>= 8;
229 }
230
231 auto pixel_val = static_cast<unsigned char> (curr_pixel_val);
232
233 #if 0
234 //This is how Thom use to get the region
235 int temp_pix_val = int(int(curr_pixel_val)*255.0/1500.0);
236 if (temp_pix_val > 255)
237 temp_pix_val =255;
238 unsigned char pixel_val = static_cast<unsigned char>(temp_pix_val);
239 //end hack
240 #endif
241
242 (*nitf_image_unsigned_char)(m,n,p) = pixel_val;
243 }
244 }
245 }
246 }
247 else if (roi->pixel_format() == VIL_PIXEL_FORMAT_BYTE) {
248 *nitf_image_unsigned_char = vil_image_view<unsigned char>(roi);
249 }
250 else
251 std::cout << "bvxm_roi_init_process - Unsupported Pixel Format = " << roi->pixel_format() << std::endl;
252
253 double u, v;
254 camera->image_offset(u, v);
255 //double tu = u - roi_box->min_x();
256 //double tv = v - roi_box->min_y();
257 // bug fix: use image bounding box instead of roi_box to modify the local cam offsets
258 double tu = u - bb->get_min_x();
259 double tv = v - bb->get_min_y();
260
261 //camera->set_image_offset(tu, tv); // DO NOT MODIFY THE ORIGINAL CAMERA!! It may be used outside of this process in the python process pipeline
262 local_camera = vpgl_local_rational_camera<double> (*lvcs, *camera);
263 local_camera.set_image_offset(tu, tv);
264 delete roi_box;
265 return true;
266 }
267
roi_init(std::string const & image_path,vpgl_rational_camera<double> * camera,const bvxm_world_params_sptr & world_params,float error,vil_image_view<vxl_uint_16> * nitf_image_unsigned_short,vpgl_local_rational_camera<double> & local_camera)268 bool bvxm_roi_init_process_globals::roi_init( std::string const& image_path,
269 vpgl_rational_camera<double>* camera,
270 const bvxm_world_params_sptr& world_params,
271 float error,
272 vil_image_view<vxl_uint_16>* nitf_image_unsigned_short,
273 vpgl_local_rational_camera<double>& local_camera)
274 {
275 // read the image and extract the camera
276 vil_image_resource_sptr img = vil_load_image_resource(image_path.c_str());
277 std::string format = img->file_format();
278 std::string prefix = format.substr(0,4);
279 if (prefix.compare("nitf") != 0) {
280 std::cerr << "bvxm_roi_init_process::execute - The image should be an NITF\n";
281 return false;
282 }
283
284 auto* nitf = static_cast<vil_nitf2_image*> (img.ptr());
285
286 vgl_vector_3d<unsigned int> dims = world_params->num_voxels();
287 int dimx = dims.x();
288 int dimy = dims.y();
289 int dimz = dims.z();
290 double min_position[3];
291 double voxel_length = world_params->voxel_length();
292 min_position[0] = world_params->corner().x();
293 min_position[1] = world_params->corner().y();
294 min_position[2] = world_params->corner().z();
295 vgl_box_3d<double> box(min_position,
296 dimx*voxel_length,
297 dimy*voxel_length,
298 dimz*voxel_length,
299 vgl_box_3d<double>::min_pos);
300
301 vpgl_lvcs_sptr lvcs = world_params->lvcs();
302 vgl_box_2d<double>* roi_box = project_box(camera, lvcs, box, error);
303 std::cout << " roi box: " << *roi_box << std::endl;
304
305 brip_roi broi(nitf->ni(), nitf->nj());
306 vsol_box_2d_sptr bb = new vsol_box_2d();
307 bb->add_point(roi_box->min_x(), roi_box->min_y());
308 bb->add_point(roi_box->max_x(), roi_box->max_y());
309 bb = broi.clip_to_image_bounds(bb);
310
311 if (bb->width() <= 0 || bb->height() <= 0) {
312 std::cerr << "bvxm_roi_init_process::roi_init()-- clipping box is out of image boundaries\n";
313 return false;
314 }
315
316 vil_image_view_base_sptr roi =
317 nitf->get_copy_view((unsigned int)bb->get_min_x(),
318 (unsigned int)bb->width(),
319 (unsigned int)bb->get_min_y(),
320 (unsigned int)bb->height());
321
322 if (!roi) {
323 std::cerr << "bvxm_roi_init_process::roi_init()-- cannot get copy view from image!\n";
324 return false;
325 }
326
327 if (!roi.as_pointer())
328 return false;
329
330 if (roi->pixel_format() == VIL_PIXEL_FORMAT_UINT_16)
331 {
332 vil_image_view<vxl_uint_16> nitf_image_vxl_uint_16(roi);
333
334 *nitf_image_unsigned_short = vil_image_view<vxl_uint_16> (roi->ni(),roi->nj(),roi->nplanes());
335
336 int bigendian = 0;
337 { union { unsigned int i; char c[4]; } u; u.i = 1; bigendian = u.c[0] == 0; }
338 for (unsigned m=0; m<nitf_image_unsigned_short->ni(); ++m)
339 {
340 for (unsigned n=0; n<nitf_image_unsigned_short->nj(); ++n)
341 {
342 for (unsigned p=0; p<nitf_image_unsigned_short->nplanes(); ++p)
343 {
344 // we will ignore the most significant 5 bits but keep all other 11 bits for nitf image
345 vxl_uint_16 curr_pixel_val = nitf_image_vxl_uint_16(m,n,p);
346 if (bigendian) {
347 auto* arr = (unsigned char*) &curr_pixel_val;
348 // [defgh3][5abc]
349 // --> [abcdefgh3]
350 unsigned char big = *arr;
351 unsigned char small = *(++arr);
352 small <<= 5;
353 curr_pixel_val = big | small;
354 }
355 else { // little endian
356 // [5abc][defgh3]
357 // --> [abcdefgh35]
358 curr_pixel_val <<= 5;
359 // [abcdefgh35]
360 // --> [abcdefgh3]
361 curr_pixel_val >>= 5;
362 }
363 (*nitf_image_unsigned_short)(m,n,p) = curr_pixel_val;
364 }
365 }
366 }
367 }
368 else if (roi->pixel_format() == VIL_PIXEL_FORMAT_BYTE) {
369 vil_image_view<unsigned char> nitf_image_vxl_unsigned_char(roi);
370 *nitf_image_unsigned_short = vil_image_view<vxl_uint_16> (roi->ni(),roi->nj(),roi->nplanes());
371 for (unsigned m=0; m<nitf_image_unsigned_short->ni(); ++m)
372 for (unsigned n=0; n<nitf_image_unsigned_short->nj(); ++n)
373 for (unsigned p=0; p<nitf_image_unsigned_short->nplanes(); ++p)
374 (*nitf_image_unsigned_short)(m,n,p) = static_cast<vxl_uint_16>(nitf_image_vxl_unsigned_char(m,n,p));
375 }
376 else {
377 std::cout << "bvxm_roi_init_process - Unsupported Pixel Format = " << roi->pixel_format() << std::endl;
378 return false;
379 }
380
381 double u, v;
382 camera->image_offset(u, v);
383 //double tu = u - roi_box->min_x();
384 //double tv = v - roi_box->min_y();
385 // bug fix: use image bounding box instead of roi_box to modify the local cam offsets
386 double tu = u - bb->get_min_x();
387 double tv = v - bb->get_min_y();
388
389 //camera->set_image_offset(tu, tv); // DO NOT MODIFY THE ORIGINAL CAMERA!! It may be used outside of this process in the python process pipeline
390 local_camera = vpgl_local_rational_camera<double> (*lvcs, *camera);
391 local_camera.set_image_offset(tu, tv);
392 delete roi_box;
393 return true;
394 }
395
396 //: project_box function
project_box(vpgl_rational_camera<double> * cam,const vpgl_lvcs_sptr & lvcs,vgl_box_3d<double> box,float r)397 vgl_box_2d<double>* bvxm_roi_init_process_globals::project_box( vpgl_rational_camera<double>* cam,
398 const vpgl_lvcs_sptr& lvcs,
399 vgl_box_3d<double> box,
400 float r)
401 {
402 double xoff, yoff, zoff;
403 xoff = cam->offset(vpgl_rational_camera<double>::X_INDX);
404 yoff = cam->offset(vpgl_rational_camera<double>::Y_INDX);
405 zoff = cam->offset(vpgl_rational_camera<double>::Z_INDX);
406
407 // global to local
408 double lx, ly, lz;
409 lvcs->global_to_local(xoff, yoff, zoff, vpgl_lvcs::wgs84, lx, ly, lz, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
410 double center[3];
411 center[0] = lx;
412 center[1] = ly;
413 center[2] = lz;
414
415 // create a box with uncertainty
416 vgl_box_3d<double> cam_box(center, 2*r, 2*r, 2*r, vgl_box_3d<double>::centre);
417 std::vector<vgl_point_3d<double> > cam_corners = bvxm_util::corners_of_box_3d<double>(cam_box);
418 std::vector<vgl_point_3d<double> > box_corners = bvxm_util::corners_of_box_3d<double>(box);
419 auto* roi = new vgl_box_2d<double>();
420
421 double lon, lat, gz;
422 for (auto cam_corner : cam_corners) {
423 lvcs->local_to_global(cam_corner.x(), cam_corner.y(), cam_corner.z(),
424 vpgl_lvcs::wgs84, lon, lat, gz, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
425 vpgl_rational_camera<double>* new_cam = cam->clone();
426 new_cam->set_offset(vpgl_rational_camera<double>::X_INDX, lon);
427 new_cam->set_offset(vpgl_rational_camera<double>::Y_INDX, lat);
428 new_cam->set_offset(vpgl_rational_camera<double>::Z_INDX, gz);
429
430 // project the box
431 for (auto & box_corner : box_corners) {
432 // convert the box corners to world coordinates
433 lvcs->local_to_global(box_corner.x(), box_corner.y(), box_corner.z(),
434 vpgl_lvcs::wgs84, lon, lat, gz, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
435 vgl_point_2d<double> p2d = new_cam->project(vgl_point_3d<double>(lon, lat, gz));
436 roi->add(p2d);
437 }
438 }
439 return roi;
440 }
441