1 #include <iostream>
2 #include <algorithm>
3 #include "volm_query.h"
4 //:
5 // \file
6 #include <bpgl/bpgl_camera_utils.h>
7 #include <volm/volm_spherical_container.h>
8 #include <bsol/bsol_algs.h>
9 #include "vil/vil_image_view.h"
10 #include "vil/vil_rgb.h"
11 #include "vil/vil_save.h"
12 #include "vsl/vsl_binary_io.h"
13 #include <volm/volm_io.h>
14 #include <volm/volm_tile.h>
15 #include <volm/volm_spherical_layers.h>
16 #ifdef _MSC_VER
17 #  include "vcl_msvc_warnings.h"
18 #endif
19 #include <cassert>
20 #include <volm/volm_camera_space.h>
21 #include "vsl/vsl_vector_io.h"
22 #include "vsl/vsl_set_io.h"
23 
24 #define TOL -1E-8
25 
volm_query(const volm_camera_space_sptr & cam_space,std::string const & label_xml_file,std::string const & category_file,volm_spherical_container_sptr const & sph,volm_spherical_shell_container_sptr const & sph_shell)26 volm_query::volm_query(const volm_camera_space_sptr& cam_space,
27                        std::string const& label_xml_file,
28                        std::string const& category_file,
29                        volm_spherical_container_sptr const& sph,
30                        volm_spherical_shell_container_sptr const& sph_shell)
31 : cam_space_(cam_space), invalid_((unsigned char)255), sph_depth_(sph), sph_(sph_shell)
32 {
33   //the discrete rays defined on the sphere as x, y, z
34   query_points_ = sph_->cart_points();
35   query_size_ = (unsigned)query_points_.size();
36 
37   // load the labelme xml to define depth_map_scene and associated default value of camera parameters
38   dm_ = new depth_map_scene;
39   std::string img_category;
40   volm_io::read_labelme(label_xml_file, category_file, dm_, img_category);
41   // the dimensions of the depth image
42   ni_ = dm_->ni();
43   nj_ = dm_->nj();
44   // the image may be downsampled to provide more efficient matching
45   log_downsample_ratio_ = 0;//initial scale = 1
46   // the larger dimension of the image
47   unsigned bigger = ni_ > nj_ ? ni_ : nj_;
48   // find the scale that keeps the largest image dimension > 500
49   while ((bigger>>log_downsample_ratio_) > 500)
50     ++log_downsample_ratio_;
51   std::cout << "log_downsample_ratio_: " << log_downsample_ratio_ << std::endl; // need flush
52 
53 #if NO_CAM_SPACE_CLASS
54   //
55   // set the default camera hypothesis parameters
56   // based on img_category ( "desert" and "coast")
57   //
58   if (img_category == "desert") {
59     head_ = 0.0;      head_d_ = 180.0; head_inc_ = 2.0;
60     tilt_ = 90.0;     tilt_d_ = 20.0; tilt_inc_ = 2.0;
61     roll_ = 0.0;      roll_d_ = 3.0; roll_inc_ = 2.0; // try +2 -2
62     tfov_ = 5.0;      tfov_d_ = 5.0; tfov_inc_ = 2.0;
63   }
64   else if (img_category == "coast") {
65     // temporary use desert default
66     head_ = 0.0;      head_d_ = 180.0; head_inc_ = 2.0;
67     tilt_ = 90.0;     tilt_d_ = 0.0; tilt_inc_ = 2.0;
68     roll_ = 0.0;      roll_d_ = 1.0; roll_inc_ = 1.0;
69     tfov_ = 5.0;      tfov_d_ = 30.0; tfov_inc_ = 2.0;
70   }
71   else {
72     // undefined img category, use desert default
73     head_ = 0.0;      head_d_ = 180.0; head_inc_ = 2.0;
74     tilt_ = 90.0;     tilt_d_ = 20.0; tilt_inc_ = 2.0;
75     roll_ = 0.0;      roll_d_ = 1.0; roll_inc_ = 1.0;
76     tfov_ = 5.0;      tfov_d_ = 30.0;  tfov_inc_ = 2.0;
77   }
78   // read the camera file but don't use the values
79   // use the default values instead
80   if (use_default_) {
81     double lat, lon, head, head_d, tilt, tilt_d, roll, roll_d, tfov, tfov_d, altitude;
82     // load the camera kml, fetch the camera value and deviation
83     // for now we don't trust angle params read from the camera file
84     volm_io::read_camera(cam_kml_file, ni_, nj_, head, head_d, tilt, tilt_d, roll, roll_d, tfov, tfov_d, altitude, lat, lon);
85     // overwrite roll deviation for now
86     altitude_ = 3.0;
87     roll_d_ = 3.0;
88     std::cout << "In volm_query() - default values are used:\nheading: "
89              << head_ << " dev: " << head_d_
90              << "\ntilt: " << tilt_ << " dev: " << tilt_d_
91              << "\nroll: " << roll_ << " dev: " << roll_d_
92              << " (hard-coded to 3 till .kml passes meaningful values!!)\n"
93              << "top_fov: " << tfov_ << " dev: " << tfov_d_
94              << " alt: " << altitude_ << std::endl;
95   }
96   else {//overwrite the camera parameters with those in the camera file
97     double lat, lon;
98     volm_io::read_camera(cam_kml_file, ni_, nj_, head_, head_d_, tilt_, tilt_d_, roll_, roll_d_, tfov_, tfov_d_, altitude_, lat, lon);
99     std::cout << "In volm_query() - values are read:\nheading: "
100              << head_ << " dev: " << head_d_
101              << "\ntilt: " << tilt_ << " dev: " << tilt_d_
102              << "\nroll: " << roll_ << " dev: " << roll_d_
103              << "\ntop_fov: " << tfov_ << " dev: " << tfov_d_
104              << " alt: " << altitude_ << std::endl;
105   }
106 #endif
107 
108   altitude_ = cam_space_->altitude();
109   // create camera hypotheses
110   this->create_cameras();
111   std::cout << " volm_query has " << this->get_cam_num() << " cameras" << std::endl;
112   // generate polygon vector based on defined order
113   this->generate_regions();
114   ground_orient_ = volm_orient_table::ori_id["horizontal"];
115   sky_orient_ = volm_orient_table::ori_id["infinite"];
116   std::cout << "volm_query generated " << this->depth_regions().size() << " regions! ingesting...\n"; std::cout.flush();
117   // start to ingest query, with min_dist and order implemented
118   this->query_ingest();
119   // create offset vector
120   this->offset_ingest();
121   // start to ingest order, store in order_index_
122   this->order_ingest();
123   // implement the weight parameters for all objects
124 }
125 
126 // build a query from an existing depth map scene
volm_query(const volm_camera_space_sptr & cam_space,std::string const & depth_map_scene_file,volm_spherical_shell_container_sptr const & sph_shell,volm_spherical_container_sptr const & sph)127 volm_query::volm_query(const volm_camera_space_sptr& cam_space,
128                        std::string const& depth_map_scene_file,
129                        volm_spherical_shell_container_sptr const& sph_shell,
130                        volm_spherical_container_sptr const& sph)
131 : cam_space_(cam_space), invalid_((unsigned char)255), sph_depth_(sph), sph_(sph_shell)
132 {
133   //the discrete rays defined on the sphere as x, y, z
134   query_points_ = sph_->cart_points();
135   query_size_ = (unsigned)query_points_.size();
136 
137   // load the depth_map_scene from depth_map_scene binary
138   dm_ = new depth_map_scene;
139   vsl_b_ifstream dis(depth_map_scene_file.c_str());
140   dm_->b_read(dis);
141   dis.close();
142   // the dimensions of the depth image
143   ni_ = dm_->ni();
144   nj_ = dm_->nj();
145   // the image may be downsampled to provide more efficient matching
146   log_downsample_ratio_ = 0;//initial scale = 1
147   // the larger dimension of the image
148   unsigned bigger = ni_ > nj_ ? ni_ : nj_;
149   // find the scale that keeps the largest image dimension > 500
150   while ((bigger>>log_downsample_ratio_) > 500)
151     ++log_downsample_ratio_;
152   std::cout << "log_downsample_ratio_: " << log_downsample_ratio_ << std::endl; // need flush
153 
154   altitude_ = cam_space_->altitude();
155   this->create_cameras();
156   std::cout << " volm_query has " << this->get_cam_num() << " cameras" << std::endl;
157   // generate polygon vector based on defined order
158   this->generate_regions();
159   ground_orient_ = volm_orient_table::ori_id["horizontal"];
160   sky_orient_ = volm_orient_table::ori_id["infinite"];
161   std::cout << "volm_query generated " << this->depth_regions().size() << " regions! ingesting...\n"; std::cout.flush();
162   // start to ingest query, with min_dist and order implemented
163   this->query_ingest();
164   // create offset vector
165   this->offset_ingest();
166   // start to ingest order, store in order_index_
167   this->order_ingest();
168   // implement the weight parameters for all objects
169   //this->weight_ingest();
170 }
171 
volm_query(std::string const & query_file,const volm_camera_space_sptr & cam_space,std::string const & depth_map_scene_file,volm_spherical_shell_container_sptr const & sph_shell,volm_spherical_container_sptr const & sph)172 volm_query::volm_query(std::string const& query_file, const volm_camera_space_sptr& cam_space,
173                        std::string const& depth_map_scene_file,
174                        volm_spherical_shell_container_sptr const& sph_shell,
175                        volm_spherical_container_sptr const& sph)
176 : cam_space_(cam_space), invalid_((unsigned char)255), sph_depth_(sph), sph_(sph_shell)
177 {
178 
179   //the discrete rays defined on the sphere as x, y, z
180   std::cout << "depth_map_scene_file = " << depth_map_scene_file << std::endl;
181 
182   query_points_ = sph_->cart_points();
183   query_size_ = (unsigned)query_points_.size();
184 
185   // load the depth_map_scene from depth_map_scene binary
186   dm_ = new depth_map_scene;
187   vsl_b_ifstream dis(depth_map_scene_file.c_str());
188 
189   dm_->b_read(dis);
190   dis.close();
191   // the dimensions of the depth image
192   ni_ = dm_->ni();
193   nj_ = dm_->nj();
194   // the image may be downsampled to provide more efficient matching
195   log_downsample_ratio_ = 0;//initial scale = 1
196   // the larger dimension of the image
197   unsigned bigger = ni_ > nj_ ? ni_ : nj_;
198   // find the scale that keeps the largest image dimension > 500
199   while ((bigger>>log_downsample_ratio_) > 500)
200     ++log_downsample_ratio_;
201   //std::cout << "log_downsample_ratio_: " << log_downsample_ratio_ << std::endl; // need flush
202 
203   depth_regions_ = dm_->scene_regions();
204   // sort the regions on depth order
205   std::sort(depth_regions_.begin(), depth_regions_.end(), compare_order());
206 
207   altitude_ = cam_space_->altitude();
208 
209   // read the rest from the binary file
210   vsl_b_ifstream dis_self(query_file.c_str());
211   this->read_data(dis_self);
212   dis_self.close();
213   std::cout << " volm_query has " << this->get_cam_num() << " cameras" << std::endl;
214 }
215 
216 
217 #if NO_CAM_SPACE_CLASS
218 // generate the set of camera hypotheses
219 // the camera space includes multiple
220 // choices for focal length, heading, tilt and roll
create_cameras()221 void volm_query::create_cameras()
222 {
223   // set up the camera parameter arrays and construct vector of cameras
224   if (use_default_)//define focal length search space
225   {
226     if (img_category == "desert") {
227       //field of view angle choices (degrees)
228       double stock[] = {18.0, 19.0,
229                         20.0, 24.0, 26.0,
230                         28.0, 30.0, 32.0};
231       //store in vector
232       if (ni_ >= nj_) {  // landscape
233         top_fov_.insert(top_fov_.end(), stock, stock + 8);
234       }
235       else { // protrait, so take into account aspect ratio
236         double dtor = vnl_math::pi_over_180;
237         for (unsigned i = 0; i < 8; ++i) {
238           double tr = std::tan(stock[i]*dtor);
239           double top = std::atan(nj_*tr/ni_)/dtor;
240           top_fov_.push_back(top);
241         }
242       }
243       std::cout << " NOTE: default top field of view is used:\n\t[ ";
244       for (unsigned i = 0; i < 8; ++i)
245         std::cout << top_fov_[i] << ' ';
246       std::cout << ']' << std::endl;
247     }
248     else if (img_category == "coast") {
249       double stock[] = {3.0, 4.0, 5.0, 9.0,
250                         15.0, 16.0,
251                         20.0, 21.0, 22.0, 23.0, 24.0};
252       if (ni_ >= nj_) {   // landscape
253         top_fov_.insert(top_fov_.end(), stock, stock + 11);
254       }
255       else {             // protrait
256         double dtor = vnl_math::pi_over_180;
257         for (unsigned i = 0; i < 11; ++i) {
258           double tr = std::tan(stock[i]*dtor);
259           double top = std::atan(nj_*tr/ni_)/dtor;
260           top_fov_.push_back(top);
261         }
262       }
263       std::cout << " NOTE: default top field of view is used:\n\t[ ";
264       for (unsigned i = 0; i < 11; ++i)
265         std::cout << top_fov_[i] << ' ';
266       std::cout << ']' << std::endl;
267     }
268     else {
269       double stock[] = {3.0,  4.0, 5.0,
270                         12.0, 17.0, 18.0,19.0,
271                        20.0, 24.0};
272       top_fov_.insert(top_fov_.end(), stock, stock + 9);
273       std::cout << " NOTE: default top field of view is used:\n\t[ ";
274       for (unsigned i = 0; i < 9; ++i)
275         std::cout << top_fov_[i] << ' ';
276       std::cout << ']' << std::endl;
277     }
278   }// end use_default == true
279   else {
280     tfov_inc_ = 2.0;
281 #if 0
282     if (tfov_ < 10)      tfov_inc_ = 1.0;
283     else if (tfov_ > 20) tfov_inc_ = 4.0;
284     else                 tfov_inc_ = 2.0;
285 #endif
286     top_fov_.push_back(tfov_);    // top viewing ranges from 1 to 89
287     std::cout << "\t top_fov:\n\t " << tfov_ << ' ';
288     for (double i = tfov_inc_; i <= tfov_d_; i+=tfov_inc_) {
289       double right_fov = tfov_ + i, left_fov = tfov_ - i;
290       if (right_fov > 89)  right_fov = 89;
291       if (left_fov  < 1)   left_fov = 1;
292       top_fov_.push_back(right_fov);
293       if (left_fov != right_fov) {
294         top_fov_.push_back(left_fov);
295         std::cout << right_fov << ' ' << left_fov << ' ';
296       }
297       else
298         std::cout << right_fov << ' ';
299     }
300   }
301   // store heading hypotheses
302   headings_.push_back(head_);
303   std::cout << "\n\t headings:\n\t " << head_ << ' ';
304   for (double i = head_inc_; i <= head_d_; i+= head_inc_) {   // heading ranges from 0 to 360
305     double right_hd = head_ + i, left_hd = head_ - i;
306     if (right_hd > 360) right_hd = right_hd - 360;
307     if (left_hd < 0)    left_hd = left_hd + 360;
308     headings_.push_back(right_hd);
309     if (left_hd != right_hd) {
310       headings_.push_back(left_hd); std::cout << right_hd << ' ' << left_hd << ' ';
311     }
312     else
313       std::cout << right_hd << ' ';
314   }
315   // store tilt hypotheses
316   std::cout << "\n\t tilts:\n\t " << tilt_ << ' ';
317   tilts_.push_back(tilt_);   // tilt ranges from 0 to 180
318   for (double i =  tilt_inc_; i <= tilt_d_; i+= tilt_inc_) {
319     double right_tlt = tilt_ + i, left_tlt = tilt_ - i;
320     if (right_tlt > 180) right_tlt = 180;
321     if (left_tlt < 0)    left_tlt = 0;
322     tilts_.push_back(right_tlt);  tilts_.push_back(left_tlt);
323     std::cout << right_tlt << ' ' << left_tlt << ' ';
324   }
325   // store roll hypotheses
326   std::cout << "\n\t rolls:\n\t " << roll_ << ' ';
327   rolls_.push_back(roll_);    // roll ranges from -180 to 180 in kml, how about in camera_from_kml ?? (need to check...)
328   for (double i = roll_inc_; i <= roll_d_; i+=roll_inc_) {
329     double right_rol = roll_ + i , left_rol = roll_ - i;
330     if (right_rol > 180) right_rol = right_rol - 360;
331     if (left_rol < -180) left_rol = left_rol + 360;
332     rolls_.push_back(roll_ + i);  rolls_.push_back(roll_ - i);
333     std::cout << right_rol << ' ' << left_rol << ' ';
334   }
335   std::cout << '\n';
336   std::cout.flush();
337 
338   // construct the camera hypotheses
339   for (unsigned i = 0; i < tilts_.size(); ++i)
340     for (unsigned j = 0; j < rolls_.size(); ++j)
341       for (unsigned k = 0; k < top_fov_.size(); ++k)
342         for (unsigned h = 0; h < headings_.size(); ++h)
343         {
344           double tilt = tilts_[i], roll = rolls_[j], top_f = top_fov_[k], head = headings_[h];
345           double dtor = vnl_math::pi_over_180;
346           double ttr = std::tan(top_f*dtor);
347           double right_f = std::atan(ni_*ttr/nj_)/dtor;
348           vpgl_perspective_camera<double> cam = bpgl_camera_utils::camera_from_kml((double)ni_, (double)nj_, right_f, top_f, altitude_, head, tilt, roll);
349           // check whether current camera is consistent with defined ground plane
350           // that is, if the 2-d ground plane region actually projects onto the 3-d ground plane
351           bool success = true;
352           if (dm_->ground_plane().size()) {
353             for (unsigned i = 0; (success && i < dm_->ground_plane().size()); ++i) {
354               success = dm_->ground_plane()[i]->region_ground_2d_to_3d(cam);
355 #if 0
356               std::cout << "checking ground plane consistency for: " << dm_->ground_plane()[i]->name() << " min depth is: " << dm_->ground_plane()[i]->min_depth()
357                        << ' ' << (success ? "" : "not_") << "consistent!\n"
358 #endif
359             }
360             if (success) {
361               cameras_.push_back(cam);
362               camera_strings_.push_back(bpgl_camera_utils::get_string((double)ni_, (double)nj_, right_f, top_f, altitude_, head, tilt, roll));
363             }
364             else
365             {
366 #if 0
367               std::cout << "WARNING: following camera hypothesis is NOT consistent with defined ground plane in the query image and ignored\n"
368                        << " \t heading = " << head << ", tilt = " << tilt << ", roll = " << roll << ", top_fov = " << top_f << ", right_fov = " << right_f << std::endl;
369 #endif
370             }
371           }
372           else
373           {
374             cameras_.push_back(cam);
375             camera_strings_.push_back(bpgl_camera_utils::get_string((double)ni_, (double)nj_, right_f, top_f, altitude_, head, tilt, roll));
376           }
377         }
378 }
379 #endif
380 
create_cameras()381 void volm_query::create_cameras()
382 {
383   // iterate over valid cameras in the camera space
384   std::vector<unsigned int> const& valid_cams = cam_space_->valid_indices();
385   for (unsigned int valid_cam : valid_cams) {
386     vpgl_perspective_camera<double> cam = cam_space_->camera(valid_cam);
387     cameras_.push_back(cam);
388     std::string cam_str = cam_space_->get_string(valid_cam);
389     camera_strings_.push_back(cam_str);
390   }
391 }
392 
393 // convert min and max distances from scene depth regions to voxel indices
394 // insure consistent order indices
395 // obtain the maximum distance bound (meters)
generate_regions()396 void volm_query::generate_regions()
397 {
398   // generate the map of the depth_map_region based on their order
399   // a vector of regions not including sky or ground plane
400   depth_regions_ = dm_->scene_regions();
401   auto size = (unsigned)depth_regions_.size();
402   // sort the regions on depth order
403   std::sort(depth_regions_.begin(), depth_regions_.end(), compare_order());
404   // obtain the min and max dist for different non-ground, non-sky objects
405   // distances are in terms of voxel indices
406   for (unsigned i = 0; i < size; ++i) {
407     min_obj_dist_.push_back(sph_depth_->get_depth_interval(depth_regions_[i]->min_depth()));
408     max_obj_dist_.push_back(sph_depth_->get_depth_interval(depth_regions_[i]->max_depth()));
409     order_obj_.push_back((unsigned char)depth_regions_[i]->order());
410     obj_orient_.push_back((unsigned char)depth_regions_[i]->orient_type());
411 
412     auto land_id = (unsigned char)depth_regions_[i]->land_id();
413     std::vector<unsigned char> land_fallback_id = volm_fallback_label::fallback_id[land_id];
414     obj_land_id_.push_back(land_fallback_id);
415     std::vector<float> land_fallback_wgt = volm_fallback_label::fallback_weight[land_id];
416     obj_land_wgt_.push_back(land_fallback_wgt);
417   }
418   d_threshold_ = 20000.0; //upper depth bound
419   for (unsigned i = 0; i < size; ++i) {
420   //depth_regions_[(dm_->scene_regions())[i]->order()] = (dm_->scene_regions())[i];
421     if (d_threshold_ < (dm_->scene_regions())[i]->max_depth())
422       d_threshold_ = (dm_->scene_regions())[i]->max_depth();
423   }
424   if (dm_->ground_plane().size()) {
425     for (unsigned i = 0; i < dm_->ground_plane().size(); ++i) {
426       if (d_threshold_ < dm_->ground_plane()[i]->max_depth())
427         d_threshold_ = dm_->ground_plane()[i]->max_depth();
428     }
429   }
430   // set a constant value for sky objects, which is equal to minimum order for all sky objects
431   // actually, order for sky shouldn't matter - JLM
432   if (dm_->sky().size()) {
433     order_sky_ = dm_->sky()[0]->order();
434     for (unsigned i = 1; i < dm_->sky().size(); ++i) {
435       if ( order_sky_ > dm_->sky()[i]->order() )
436         order_sky_ = dm_->sky()[i]->order();
437     }
438   }
439   // create the order_set for all non-ground region
440   // std::set<unsigned>
441  if (depth_regions_.size())
442     for (auto & depth_region : depth_regions_)
443       order_set_.insert(depth_region->order());
444   if (dm_->sky().size())
445     order_set_.insert(order_sky_);
446 }
447 
order_ingest()448 bool volm_query::order_ingest()
449 {
450   // loop over camera hypotheses
451   auto cam_num = (unsigned)cameras_.size();
452   for (unsigned cam_id = 0; cam_id < cam_num; ++cam_id) {
453     // create a vector to store all objects and fetch the order for current layer
454     std::vector<std::vector<unsigned> > order_cam(order_set_.size());
455     std::vector<unsigned char> order_layer = order_[cam_id];
456 #if 0
457     std::cout << " --------------------- camera " << cam_id << " --------------------" << std::endl;
458 #endif
459     // loop over rays on query sphere
460     for (unsigned idx = 0; idx < query_size_; ++idx) {
461       unsigned count = 0;
462       //std::cout << " cam " << cam_id << ", order_layer[" << idx << "] = " << (int)order_layer[idx] << std::endl;
463       auto iter = this->order_set_.begin();
464       for ( ; iter != order_set_.end(); ++iter) {
465         if ( (int)order_layer[idx] == *iter) {
466           order_cam[count].push_back(idx);
467           break;
468         }
469         else {
470           ++count;
471         }
472       }
473     }
474     order_index_.push_back(order_cam);
475   } // loop over camera
476   return true;
477 }
478 
479 // computes a set of spherical shell layers for each camera hypothesis
480 // the layer contents are indexed by the camera ray, p_idx
query_ingest()481 bool volm_query::query_ingest()
482 {
483   // loop over the set of camera hypotheses
484   for (const auto& cam : cameras_)
485   {
486     // the layers for camera hypothesis i
487     // the minimum distance for each ray
488     std::vector<unsigned char> min_dist_layer;
489     // the maximum distance for each ray
490     std::vector<unsigned char> max_dist_layer;
491     // the region order for each ray
492     std::vector<unsigned char> order_layer;
493     // the set of rays intersecting the ground plane
494     std::vector<unsigned> ground_id_layer;
495     // the ground plane distance for the ray
496     std::vector<unsigned char> ground_dist_layer;
497     // the ground plane land fallback class for the ray
498     std::vector<std::vector<unsigned char> > ground_land_layer;
499     // the ground pland land fallback class weight
500     std::vector<std::vector<float> > ground_land_wgt_layer;
501     // the set of rays intersecting sky
502     std::vector<unsigned> sky_id_layer;
503     // the set of rays for each non-gp, non-sky region
504     std::vector<std::vector<unsigned> > dist_id_layer(depth_regions_.size());
505     // put current camera into depth_map_scene
506     dm_->set_camera(cam);
507     // create an depth image for current camera if there is ground plane
508     vil_image_view<float> depth_img;
509     if (dm_->ground_plane().size()) {
510       depth_img = dm_->depth_map("ground_plane", log_downsample_ratio_, d_threshold_);
511     }
512 
513     // loop over rays on sphere
514     unsigned count = 0;
515     for (unsigned p_idx = 0; p_idx < query_size_; ++p_idx)
516     {
517       vgl_point_3d<double> qp(query_points_[p_idx].x(), query_points_[p_idx].y(), query_points_[p_idx].z()+altitude_);
518       unsigned char min_dist, order, max_dist;
519       // check whether the point is behind the camera
520       if (cam.is_behind_camera(vgl_homg_point_3d<double>(qp))) {
521         min_dist_layer.push_back((unsigned char)255);
522         max_dist_layer.push_back((unsigned char)255);
523         order_layer.push_back((unsigned char)255);
524       }
525       else {
526         double u, v;
527         cam.project(qp.x(), qp.y(), qp.z(), u, v);
528         // compare (u, v) with depth_map_scene, return min_dist
529         if ( u > (double)ni_ || v > (double)nj_ || u < TOL || v < TOL) {   // container point qp is outside camera viewing volume
530           min_dist_layer.push_back((unsigned char)255);
531           max_dist_layer.push_back((unsigned char)255);
532           order_layer.push_back((unsigned char)255);
533         }
534         else {
535           bool is_ground = false, is_sky = false, is_object = false;
536           unsigned obj_id;
537           std::vector<unsigned char> grd_fallback_id;
538           std::vector<float> grd_fallback_wgt;
539           min_dist = this->fetch_depth(u, v, order, max_dist, obj_id, grd_fallback_id, grd_fallback_wgt, is_ground, is_sky, is_object, depth_img);
540           min_dist_layer.push_back(min_dist);
541           max_dist_layer.push_back(max_dist);
542           order_layer.push_back(order);
543           if (is_ground) {
544             ground_id_layer.push_back(p_idx);
545             ground_dist_layer.push_back(min_dist);
546             ground_land_layer.push_back(grd_fallback_id);
547             ground_land_wgt_layer.push_back(grd_fallback_wgt);
548           }
549           else if (is_sky) {
550             sky_id_layer.push_back(p_idx);
551           }
552           else if (is_object) {
553             if (obj_id < depth_regions_.size()) {
554               dist_id_layer[obj_id].push_back(p_idx);
555             }
556             else {
557               std::cerr << "ERROR in query creation: object id exceeds the size of non-ground, non-sky objects\n";
558               return false;
559             }
560           }
561           if ((unsigned)min_dist != 255)
562             ++count;
563         }
564       }
565     } // loop over rays for current camera
566     min_dist_.push_back(min_dist_layer);
567     max_dist_.push_back(max_dist_layer);
568     order_.push_back(order_layer);
569     ground_id_.push_back(ground_id_layer);
570     ground_dist_.push_back(ground_dist_layer);
571     ground_land_id_.push_back(ground_land_layer);
572     ground_land_wgt_.push_back(ground_land_wgt_layer);
573     sky_id_.push_back(sky_id_layer);
574     dist_id_.push_back(dist_id_layer);
575   } // loop over cameras
576   return true;
577 }
578 
579 // u, v defines the pixel location in a depth image
580 // depth image is the ground plane depth map
581 // returns min distance to depth region that contains
582 // u, v
offset_ingest()583 bool volm_query::offset_ingest()
584 {
585   auto n_cam = (unsigned)cameras_.size();
586   // create ground offset
587   unsigned count = 0;
588   ground_offset_.push_back(count);
589   for (unsigned cam_id = 0; cam_id < n_cam; ++cam_id) {
590     count += (unsigned)ground_id_[cam_id].size();
591     ground_offset_.push_back(count);
592   }
593 
594   // create sky offset
595   count = 0;
596   sky_offset_.push_back(count);
597   for (unsigned cam_id = 0; cam_id < n_cam; ++cam_id) {
598     count += (unsigned)sky_id_[cam_id].size();
599     sky_offset_.push_back(count);
600   }
601 
602   // create object offset
603   count = 0;
604   auto n_obj = (unsigned)depth_regions_.size();
605   dist_offset_.push_back(count);
606   for (unsigned cam_id = 0; cam_id < n_cam; ++cam_id)
607     for (unsigned obj_id = 0; obj_id < n_obj; ++obj_id) {
608       count += (unsigned)dist_id_[cam_id][obj_id].size();
609       dist_offset_.push_back(count);
610     }
611 
612   return true;
613 }
614 
fetch_depth(double const & u,double const & v,unsigned char & order,unsigned char & max_dist,unsigned & object_id,std::vector<unsigned char> & grd_fallback_id,std::vector<float> & grd_fallback_wgt,bool & is_ground,bool & is_sky,bool & is_object,vil_image_view<float> const & depth_img)615 unsigned char volm_query::fetch_depth(double const& u,
616                                       double const& v,
617                                       unsigned char& order,
618                                       unsigned char& max_dist,
619                                       unsigned& object_id,
620                                       std::vector<unsigned char>& grd_fallback_id,
621                                       std::vector<float>& grd_fallback_wgt,
622                                       bool& is_ground,
623                                       bool& is_sky,
624                                       bool& is_object,
625                                       vil_image_view<float> const& depth_img)
626 {
627   unsigned char min_dist;
628   // check other objects before ground,
629   // e.g.,  for overlap region of a building and ground, building is on the ground and it is must closer than the ground
630   // find if (u, v) is contained in non-ground, non-sky region
631   if (depth_regions_.size()) {
632     for (unsigned i = 0; i < depth_regions_.size(); ++i) {
633       vgl_polygon<double> poly = bsol_algs::vgl_from_poly(depth_regions_[i]->region_2d());
634       if (poly.contains(u,v)) {
635         is_object = true;
636         object_id = i;
637         double min_depth = depth_regions_[i]->min_depth();
638         if (min_depth < 0)
639           min_dist = (unsigned char)255;
640         else
641           min_dist = sph_depth_->get_depth_interval(min_depth);
642         double max_depth = depth_regions_[i]->max_depth();
643         if (max_depth < sph_depth_->min_voxel_res())
644           max_dist = (unsigned char)255;
645         else
646           max_dist = sph_depth_->get_depth_interval(max_depth);
647         order = (unsigned char)depth_regions_[i]->order();
648         return min_dist;
649       }
650     }
651   }
652   // not contained in a non-ground non_sky region, check ground_plane
653   if (dm_->ground_plane().size()) {
654     for (unsigned i = 0; i < dm_->ground_plane().size(); ++i) {
655       vgl_polygon<double> vgl_ground = bsol_algs::vgl_from_poly((dm_->ground_plane()[i])->region_2d());
656       if (vgl_ground.contains(u,v)) {
657         is_ground = true;
658         // get the depth of the pixel
659         // maybe better to do bilinear interpolation instead of casting to nearest pixel
660         int uu = (int)std::floor(u/(1<<log_downsample_ratio_)+0.5);
661         uu = uu < 0 ? 0 : uu;
662         uu = uu >= (int)depth_img.ni() ? depth_img.ni()-1 : uu;
663         int vv = (int)std::floor(v/(1<<log_downsample_ratio_)+0.5);
664         vv = vv < 0 ? 0 : vv;
665         vv = vv >= (int)depth_img.nj() ? depth_img.nj()-1 : vv;
666         float depth_uv = depth_img(uu,vv);
667         // handle the case where the voxel/ray is too close to ground_plane boundary
668         if (depth_uv < 0) {
669 #ifdef DEBUG
670           std::cout << " WARNING: point (" << (int)u << ',' << (int)v
671                    << ") is too close to the ground boundary, disregarded." << std::endl;
672 #endif
673           is_ground = false;
674           max_dist = (unsigned char)255;
675           order = (unsigned char)255;
676           return (unsigned char)253; // invalid depth value
677         }
678         min_dist = sph_depth_->get_depth_interval(depth_uv);
679         max_dist = (unsigned char)255;
680         order = (unsigned char)(dm_->ground_plane()[i])->order();
681         unsigned char grd_land = dm_->ground_plane()[i]->land_id();
682         grd_fallback_id = volm_fallback_label::fallback_id[grd_land];
683         grd_fallback_wgt = volm_fallback_label::fallback_weight[grd_land];
684         return min_dist;
685       }
686     }
687   }
688   // check if (u, v) is contained in sky
689   // considered last since all objects should be closer than sky
690   if (dm_->sky().size()) {
691     for (unsigned i = 0; i < dm_->sky().size(); ++i) {
692       vgl_polygon<double> vgl_sky = bsol_algs::vgl_from_poly((dm_->sky()[i])->region_2d());
693       if (vgl_sky.contains(u,v)) {
694         is_sky = true;
695         max_dist = (unsigned char)254;
696         order = order_sky_;
697         return (unsigned char)254;
698       }
699     }
700   }
701   // the image points (u,v) is not inside any defined objectes
702   max_dist = (unsigned char)255;
703   order = (unsigned char)255;
704   return (unsigned char)255;
705 }
706 
draw_template(std::string const & vrml_fname)707 void volm_query::draw_template(std::string const& vrml_fname)
708 {
709   // write the header and shell container first
710   sph_->draw_template(vrml_fname);
711   // write rays
712   //this->draw_rays(vrml_fname);
713   // write the camera
714   unsigned cam_num = this->get_cam_num();
715   for (unsigned i = 0; i < cam_num; ++i) {
716     float r = 0.0f;
717     float g = 0.0f;
718     float b = 0.0f;
719     if (i%2 == 0)
720       g = 1.0f;
721     else if (i%2 == 1) {
722       b = 1.0f; g = 0.0f;
723     }
724     else {
725       r = 0.0f; g = 1.0f;
726     }
727     this->draw_viewing_volume(vrml_fname, cameras_[i], r, g, b);
728   }
729 }
730 
draw_rays(std::string const & fname)731 void volm_query::draw_rays(std::string const& fname)
732 {
733   std::ofstream ofs(fname.c_str(), std::ios::app);
734   double len = 800.0;
735   vgl_point_3d<double> ori(0.0,0.0,0.0);
736   for (unsigned i=0; i<query_size_; ++i) {
737     vgl_ray_3d<double> ray(ori, query_points_[i]);
738     bvrml_write::write_vrml_cylinder(ofs, ori, ray.direction(), (float)3.0, (float)len, 0.0f, 0.0f, 0.0f, 1);
739   }
740 }
741 
draw_viewing_volume(std::string const & fname,vpgl_perspective_camera<double> cam,float r,float g,float b)742 void volm_query::draw_viewing_volume(std::string const& fname, vpgl_perspective_camera<double> cam, float r, float g, float b)
743 {
744   std::ofstream ofs(fname.c_str(), std::ios::app);
745   // reset the center back to zero
746   cam.set_camera_center(vgl_point_3d<double>(0.0,0.0,0.0) );
747   //bvrml_write::write_vrml_cylinder(ofs, cam.get_camera_center(), cam.principal_axis(),0.2f, (double)(conf_focal_ + init_focal_),r,g,b);
748 
749   // create the viewing volume by rays
750   vgl_ray_3d<double> rtl = cam.backproject_ray(vgl_point_2d<double>(0.0, 0.0));
751   vgl_ray_3d<double> rtr = cam.backproject_ray(vgl_point_2d<double>((double)ni_, 0.0));
752   vgl_ray_3d<double> rll = cam.backproject_ray(vgl_point_2d<double>(0.0, (double)nj_));
753   vgl_ray_3d<double> rlr = cam.backproject_ray(vgl_point_2d<double>((double)ni_, (double)nj_));
754   // calculate a scaling factor
755   double scale = 0.5;
756   double focal = (cam.get_calibration()).focal_length();
757   double depth = focal * scale;
758   double dist = depth / focal * 0.5 * std::sqrt(4*focal*focal + ni_*ni_ + nj_*nj_);
759   // get image corner point
760   vgl_point_3d<double> ptl = cam.get_camera_center() + dist*rtl.direction();
761   vgl_point_3d<double> ptr = cam.get_camera_center() + dist*rtr.direction();
762   vgl_point_3d<double> pll = cam.get_camera_center() + dist*rll.direction();
763   vgl_point_3d<double> plr = cam.get_camera_center() + dist*rlr.direction();
764   // draw the boundary face
765   ofs << "Shape {\n"
766       << " appearance Appearance {\n"
767       << "   material Material\n"
768       << "    {\n"
769       << "      diffuseColor " << r << ' ' << g << ' ' << b << '\n'
770       << "      transparency " << 0 << '\n'
771       << "    }\n"
772       << "  }\n"
773       << " geometry IndexedFaceSet {\n"
774       << "   coord Coordinate {\n"
775       << "      point [\n"
776       << "        " << cam.get_camera_center().x() << ' '
777       << "        " << cam.get_camera_center().y() << ' '
778       << "        " << cam.get_camera_center().z() << ",\n"
779       << "        " << ptl.x() << ' ' << ptl.y() << ' ' << ptl.z() << ",\n"
780       << "        " << ptr.x() << ' ' << ptr.y() << ' ' << ptr.z() << ",\n"
781       << "        " << pll.x() << ' ' << pll.y() << ' ' << pll.z() << ",\n"
782       << "        " << plr.x() << ' ' << plr.y() << ' ' << plr.z() << '\n'
783       << "      ]\n"
784       << "    }\n"
785       << "    coordIndex [\n"
786       << "  0, 1, 2, -1,\n"
787       << "  0, 2, 4, -1,\n"
788       << "  0, 3, 4, -1,\n"
789       << "  0, 1, 3, -1,\n"
790       << "    ]\n"
791       << "  }\n"
792       << "}\n";
793   ofs.close();
794 }
795 
draw_polygon(vil_image_view<vil_rgb<vxl_byte>> & img,vgl_polygon<double> const & poly,unsigned char const & depth)796 void volm_query::draw_polygon(vil_image_view<vil_rgb<vxl_byte> >& img, vgl_polygon<double> const& poly, unsigned char const& depth)
797 {
798   for (unsigned pi = 0; pi < poly.num_sheets(); ++pi)
799   {
800     for (unsigned vi = 0; vi < poly[pi].size(); ++vi)
801     {
802       vgl_point_2d<double> s = poly[pi][vi];
803       vgl_point_2d<double> e;
804       if (vi < poly[pi].size()-1)  e = poly[pi][vi+1];
805       else  e = poly[pi][0];
806       double k;
807       if (e.x() == s.x()) k = 10000;
808       else k = (e.y()-s.y())/(e.x()-s.x());
809       double b = s.y() - k * s.x();
810       if (std::sqrt(k*k) < 1) {// loop x
811         if (s.x() <= e.x()) {
812           for (auto xi = (unsigned)s.x(); xi <= (unsigned)e.x(); ++xi) {
813             auto xj = (unsigned)(k*xi+b);
814             if (xi < img.ni() && xj < img.nj()) {
815               img(xi,xj).r = bvrml_color::heatmap_classic[(int)depth][0];
816               img(xi,xj).g = bvrml_color::heatmap_classic[(int)depth][1];
817               img(xi,xj).b = bvrml_color::heatmap_classic[(int)depth][2];
818             }
819           }
820         }
821         else {
822           for (auto xi = (unsigned)e.x(); xi <= (unsigned)s.x(); ++xi) {
823             auto xj = (unsigned)(k*xi+b);
824             if (xi < img.ni() && xj < img.nj()) {
825               img(xi,xj).r = bvrml_color::heatmap_classic[(int)depth][0];
826               img(xi,xj).g = bvrml_color::heatmap_classic[(int)depth][1];
827               img(xi,xj).b = bvrml_color::heatmap_classic[(int)depth][2];
828             }
829           }
830         }
831       }
832       else {
833         if (s.y() <= e.y()) {
834           for (auto xj = (unsigned)s.y(); xj <= (unsigned)e.y(); ++xj) {
835             auto xi = (unsigned)((xj-b)/k);
836             if (xi < img.ni() && xj < img.nj()) {
837               img(xi,xj).r = bvrml_color::heatmap_classic[(int)depth][0];
838               img(xi,xj).g = bvrml_color::heatmap_classic[(int)depth][1];
839               img(xi,xj).b = bvrml_color::heatmap_classic[(int)depth][2];
840             }
841           }
842         }
843         else {
844           for (auto xj = (unsigned)e.y(); xj <= (unsigned)s.y(); ++xj) {
845             auto xi = (unsigned)((xj-b)/k);
846             if (xi < img.ni() && xj < img.nj()) {
847               img(xi,xj).r = bvrml_color::heatmap_classic[(int)depth][0];
848               img(xi,xj).g = bvrml_color::heatmap_classic[(int)depth][1];
849               img(xi,xj).b = bvrml_color::heatmap_classic[(int)depth][2];
850             }
851           }
852         }
853       }
854     }
855   }
856 }
857 
draw_dot(vil_image_view<vil_rgb<vxl_byte>> & img,vgl_point_3d<double> const & world_point,vil_rgb<vxl_byte> color,vpgl_perspective_camera<double> const & cam)858 void volm_query::draw_dot(vil_image_view<vil_rgb<vxl_byte> >& img,
859                           vgl_point_3d<double> const& world_point,
860                           vil_rgb<vxl_byte> color,
861                           vpgl_perspective_camera<double> const& cam)
862 {
863   int dot_size = ( img.ni() < img.nj() ) ? (int)(0.01*ni_) : (int)(0.01*nj_);
864   double u, v;
865   vgl_homg_point_3d<double> current_p(world_point.x(), world_point.y(), world_point.z()+altitude_);
866   if (!(cam.is_behind_camera(current_p))) {
867     cam.project(world_point.x(), world_point.y(), world_point.z()+altitude_, u, v);
868     int cx = (int)u;
869     int cy = (int)v;
870     for (int i = -dot_size; i < dot_size; ++i)
871       for (int j = -dot_size; j < dot_size; ++j) {
872         int x = cx + i ; int y = cy + j;
873         if ( !(x < 0 || y < 0 || x >= (int)img.ni() || y >= (int)img.nj()) ) {
874           img((unsigned)x, (unsigned)y) = color;
875         }
876       }
877   }
878 }
879 
draw_depth_map_regions(vil_image_view<vil_rgb<vxl_byte>> & out_img)880 void volm_query::draw_depth_map_regions(vil_image_view<vil_rgb<vxl_byte> >& out_img)
881 {
882   // draw depth_map polygons on the depth images
883   if (dm_->sky().size()) {
884     for (unsigned i = 0; i < dm_->sky().size(); ++i) {
885       vgl_polygon<double> poly = bsol_algs::vgl_from_poly((dm_->sky()[i])->region_2d());
886       this->draw_polygon(out_img, poly, (unsigned char)254);
887     }
888   }
889   if (dm_->ground_plane().size()) {
890     unsigned ground_size = (unsigned)dm_->ground_plane().size();
891     for (unsigned i = 0; i < ground_size; ++i) {
892       vgl_polygon<double> poly = bsol_algs::vgl_from_poly((dm_->ground_plane()[i])->region_2d());
893       this->draw_polygon(out_img, poly, (unsigned char)1);
894     }
895   }
896   if (dm_->scene_regions().size()) {
897     unsigned region_size = (unsigned)dm_->scene_regions().size();
898     for ( unsigned i = 0; i < region_size; ++i) {
899       vgl_polygon<double> poly = bsol_algs::vgl_from_poly((dm_->scene_regions())[i]->region_2d());
900       double value = (dm_->scene_regions())[i]->min_depth();
901       unsigned char depth = sph_depth_->get_depth_interval(value);
902       this->draw_polygon(out_img, poly, depth);
903     }
904   }
905 }
906 
depth_rgb_image(std::vector<unsigned char> const & values,unsigned const & cam_id,vil_image_view<vil_rgb<vxl_byte>> & out_img,const std::string & value_type)907 void volm_query::depth_rgb_image(std::vector<unsigned char> const& values,
908                                  unsigned const& cam_id,
909                                  vil_image_view<vil_rgb<vxl_byte> >& out_img,
910                                  const std::string& value_type)
911 {
912   this->draw_depth_map_regions(out_img);
913 
914   vpgl_perspective_camera<double> cam = cam_space_->camera(cam_id);
915 
916   if (value_type == "orientation") {
917     for (unsigned pidx = 0; pidx < query_size_; ++pidx) {
918       vil_rgb<vxl_byte> color_id;
919       if (values[pidx] == 0 || values[pidx] == 100)       //    invalid --> black
920         color_id = vil_rgb<vxl_byte>(0,0,0);
921       else if (values[pidx] == 1)                         // horizontal --> red
922         color_id = vil_rgb<vxl_byte>(255,0,0);
923       else if (values[pidx] > 1 && values[pidx] < 10)     //   vertical --> green
924         color_id = vil_rgb<vxl_byte>(0,180,60);
925       else if (values[pidx] == 254)                       //        sky --> blue
926         color_id = vil_rgb<vxl_byte>(51,102,255);
927       else
928         color_id = vil_rgb<vxl_byte>(49,50,62);
929       this->draw_dot(out_img, query_points_[pidx], color_id, cam);
930     }
931   }
932   else if (value_type == "land") {
933     for (unsigned pidx = 0; pidx < query_size_; ++pidx) {
934       vil_rgb<vxl_byte> color_id;
935       if (values[pidx] == 0)                   // invalid --> black
936         color_id = vil_rgb<vxl_byte>(255,0,0);
937       else if (values[pidx] == 254)            // sky --> blue
938         color_id = vil_rgb<vxl_byte>(51,102,255);
939       else
940         color_id = volm_osm_category_io::volm_land_table[values[pidx]].color_;
941         //color_id = volm_label_table::get_color(values[pidx]);
942       this->draw_dot(out_img, query_points_[pidx], color_id, cam);
943     }
944   }
945   else if (value_type == "depth") {
946     for (unsigned pidx = 0; pidx < query_size_; ++pidx) {
947       vil_rgb<vxl_byte> color_id;
948       if (values[pidx] == 254)
949         color_id = vil_rgb<vxl_byte>(51,102,255);
950       else if (values[pidx] == 253)
951         color_id = vil_rgb<vxl_byte>(0,0,0);
952       else
953         color_id = vil_rgb<vxl_byte>(bvrml_color::heatmap_classic[(int)values[pidx]][0],
954                                      bvrml_color::heatmap_classic[(int)values[pidx]][1],
955                                      bvrml_color::heatmap_classic[(int)values[pidx]][2]);
956       this->draw_dot(out_img, query_points_[pidx], color_id, cam);
957     }
958   }
959   else {
960     std::cerr << "WARNING: given image type " << value_type << " is not found in volm_query::depth_rgb_image, generate depth image instead\n";
961     for (unsigned pidx = 0; pidx < query_size_; ++pidx)
962       if (values[pidx] < 255)
963         this->draw_dot(out_img, query_points_[pidx], values[pidx], cam);
964   }
965 }
966 
draw_query_image(unsigned cam_i,std::string const & out_name)967 void volm_query::draw_query_image(unsigned cam_i, std::string const& out_name)
968 {
969   // create an rgb image instance
970   vil_image_view<vil_rgb<vxl_byte> > img(ni_, nj_);
971   // initialize the image
972   for (unsigned i = 0; i < ni_; ++i)
973     for (unsigned j = 0; j < nj_; ++j) {
974       img(i,j).r = (unsigned char)120;
975       img(i,j).g = (unsigned char)120;
976       img(i,j).b = (unsigned char)120;
977     }
978   std::vector<unsigned char> current_query = min_dist_[cam_i];
979   this->depth_rgb_image(current_query, cam_i, img);
980   // save the images
981   vil_save(img,out_name.c_str());
982 }
983 
draw_query_regions(std::string const & out_name)984 void volm_query::draw_query_regions(std::string const& out_name)
985 {
986   // create an rgb image instance
987   vil_image_view<vil_rgb<vxl_byte> > img(ni_, nj_);
988   // initialize the image
989   for (unsigned i = 0; i < ni_; ++i)
990     for (unsigned j = 0; j < nj_; ++j) {
991       img(i,j).r = (unsigned char)120;
992       img(i,j).g = (unsigned char)120;
993       img(i,j).b = (unsigned char)120;
994     }
995   this->draw_depth_map_regions(img);
996   // save the images
997   vil_save(img,out_name.c_str());
998 }
999 
draw_query_images(std::string const & out_dir)1000 void volm_query::draw_query_images(std::string const& out_dir)
1001 {
1002   // create a png img associated with each camera hypothesis, containing the geometry defined
1003   //  in depth_map_scene and the img points corresponding to points inside the container
1004   // loop over fist 100 camera
1005   unsigned img_num = (this->get_cam_num() > 20) ? 20 : (unsigned)cameras_.size();
1006   for (unsigned i = 0; i < img_num; ++i) {
1007     std::stringstream s_idx;
1008     s_idx << i;
1009     std::string fs = out_dir + "query_img_" + this->get_cam_string(i) + ".png";
1010     this->draw_query_image(i, fs);
1011   }
1012 }
1013 
visualize_query(std::string const & prefix)1014 void volm_query::visualize_query(std::string const& prefix)
1015 {
1016   // visualize the spherical shell by the query depth value -- used to compare with the generated index spherical shell
1017   // loop over all camera
1018   for (unsigned i = 0; i < this->get_cam_num(); ++i) {
1019     std::vector<unsigned char> single_layer = min_dist_[i];
1020     std::stringstream str;
1021     str << prefix << "_query_" << i << ".vrml";
1022     sph_->draw_template(str.str(), single_layer, 254);
1023   }
1024 }
1025 
get_num_top_fov(double const & top_fov) const1026 unsigned volm_query::get_num_top_fov(double const& top_fov) const
1027 {
1028   unsigned count = 0;
1029   for (unsigned i = 0; i < this->get_cam_num(); ++i) {
1030     std::string cam_string = this->get_cam_string(i);
1031     auto sindx = (unsigned)cam_string.find("top_fov");
1032     sindx += 8;
1033     std::stringstream ss( cam_string.substr(sindx, cam_string.size()-1) );
1034     double top;
1035     ss >> top;
1036     if ((unsigned)top == (unsigned)top_fov) {
1037       ++count;
1038     }
1039   }
1040   return count;
1041 }
1042 
get_top_fov(unsigned const & id) const1043 double volm_query::get_top_fov(unsigned const& id) const
1044 {
1045   std::string cam_string = this->get_cam_string(id);
1046   auto sindx = (unsigned)cam_string.find("top_fov");
1047   sindx += 8;
1048   std::stringstream ss( cam_string.substr(sindx, cam_string.size()-1) );
1049   double top;
1050   ss >> top;
1051   return top;
1052 }
1053 
get_valid_top_fov() const1054 std::vector<double> volm_query::get_valid_top_fov() const
1055 {
1056   std::set<double> top_fov_set;
1057   for (unsigned i = 0; i < this->get_cam_num(); ++i) {
1058     top_fov_set.insert(this->get_top_fov(i));
1059   }
1060   std::vector<double> valid_top_fov;
1061   valid_top_fov.reserve(top_fov_set.size());
1062 for (const auto & it : top_fov_set)
1063     valid_top_fov.push_back(it);
1064   return valid_top_fov;
1065 }
1066 
get_order_size() const1067 unsigned volm_query::get_order_size() const
1068 {
1069   unsigned count = 0;
1070   unsigned cam_num = this->get_cam_num();
1071   unsigned obj_num = this->get_obj_order_num();
1072   for (unsigned i = 0; i < cam_num; ++i)
1073     for (unsigned j = 0; j < obj_num; ++j)
1074       count += (unsigned)order_index_[i][j].size();
1075   return count;
1076 }
1077 
obj_based_query_size_byte() const1078 unsigned volm_query::obj_based_query_size_byte() const
1079 {
1080   unsigned size_byte = 0;
1081   // ground voxel size
1082   size_byte += this->get_ground_id_size()*4;     // unsigned id
1083   size_byte += this->get_ground_dist_size();       // unsigned char distance
1084   size_byte += this->get_ground_id_size()*4;     // unsigned char land classfication
1085   size_byte += this->get_ground_id_size()*4*4; // float land fallback category weight
1086   size_byte += 1;                                  // unsigned char orientation
1087   size_byte += (unsigned)ground_offset_.size()*4;  // unsinged ground offset
1088 
1089   // sky voxel size
1090   size_byte += this->get_sky_id_size()*4;        // unsigned id
1091   size_byte += (unsigned)sky_offset_.size()*4;     // unsigned sky offset
1092   //size_byte += 4;                                // float weight
1093 
1094   // non-sky, non-ground object
1095   size_byte += this->get_dist_id_size()*4;         // unsigned id
1096   size_byte += (unsigned)dist_offset_.size()*4;    // unsigned offset
1097   size_byte += (unsigned)min_obj_dist_.size();     // unsigned char distance
1098   size_byte += (unsigned)max_obj_dist_.size();     // unsigned char distance
1099   size_byte += (unsigned)obj_orient_.size();       // unsigned char orientation
1100   size_byte += (unsigned)obj_land_id_.size()*4;    // unsigned char land clarification
1101   size_byte += (unsigned)obj_land_wgt_.size()*4*4; // float land fallback category weight
1102   size_byte += (unsigned)order_obj_.size();    // unsigned char order
1103   //size_byte += (unsigned)weight_obj_.size()*4; // float weight
1104   return size_byte;
1105 }
1106 
1107 //: binary IO write
write_data(vsl_b_ostream & os)1108 void volm_query::write_data(vsl_b_ostream& os)
1109 {
1110   unsigned ver = this->version();
1111   vsl_b_write(os, ver);
1112   vsl_b_write(os, invalid_);
1113   vsl_b_write(os, d_threshold_);
1114   vsl_b_write(os, camera_strings_);
1115   vsl_b_write(os, order_set_);  // store the non-ground order, using set to ensure objects having same order are put together
1116 
1117   vsl_b_write(os, (unsigned)(order_index_.size()));
1118   for (const auto & i : order_index_)
1119     vsl_b_write(os, i);
1120 
1121   vsl_b_write(os, ground_id_);
1122   vsl_b_write(os, ground_dist_);
1123 
1124   //vsl_b_write(os, ground_land_id_);
1125   vsl_b_write(os, (unsigned)(ground_land_id_.size()));
1126   for (const auto & i : ground_land_id_)
1127     vsl_b_write(os, i);
1128 
1129   vsl_b_write(os, (unsigned)(ground_land_wgt_.size()));
1130   for (const auto & i : ground_land_wgt_)
1131     vsl_b_write(os, i);
1132 
1133   vsl_b_write(os, ground_offset_);
1134   vsl_b_write(os, ground_orient_);
1135   vsl_b_write(os, sky_id_);
1136   vsl_b_write(os, sky_offset_);
1137   vsl_b_write(os, sky_orient_);
1138 
1139   vsl_b_write(os, (unsigned)(dist_id_.size()));
1140   for (const auto & i : dist_id_)
1141     vsl_b_write(os, i);
1142 
1143   vsl_b_write(os, dist_offset_);
1144   vsl_b_write(os, min_obj_dist_);
1145   vsl_b_write(os, max_obj_dist_);
1146   vsl_b_write(os, order_obj_);
1147   vsl_b_write(os, obj_orient_);
1148   vsl_b_write(os, obj_land_id_);
1149   vsl_b_write(os, obj_land_wgt_);
1150 }
1151 
1152 //: binary IO read
read_data(vsl_b_istream & is)1153 void volm_query::read_data(vsl_b_istream& is)
1154 {
1155   unsigned ver;
1156   vsl_b_read(is, ver);
1157   if (ver ==1) {
1158     vsl_b_read(is, invalid_);
1159     vsl_b_read(is, d_threshold_);
1160     vsl_b_read(is, camera_strings_);
1161     vsl_b_read(is, order_set_);  // store the non-ground order, using set to ensure objects having same order are put together
1162     unsigned size;
1163     vsl_b_read(is, size);
1164     for (unsigned i = 0; i < size; i++) {
1165       std::vector<std::vector<unsigned> > o;
1166       vsl_b_read(is, o);
1167       order_index_.push_back(o);
1168     }
1169 
1170     vsl_b_read(is, ground_id_);
1171     vsl_b_read(is, ground_dist_);
1172 
1173     // vsl_b_read(is, ground_land_id_);
1174     vsl_b_read(is, size);
1175     for (unsigned i = 0; i < size; i++) {
1176       std::vector<std::vector<unsigned char> > temp;
1177       vsl_b_read(is, temp);
1178       ground_land_id_.push_back(temp);
1179     }
1180 
1181     vsl_b_read(is, size);
1182     for (unsigned i = 0; i < size; i++) {
1183       std::vector<std::vector<float> > temp;
1184       vsl_b_read(is, temp);
1185       ground_land_wgt_.push_back(temp);
1186     }
1187 
1188     vsl_b_read(is, ground_offset_);
1189     vsl_b_read(is, ground_orient_);
1190     vsl_b_read(is, sky_id_);
1191     vsl_b_read(is, sky_offset_);
1192     vsl_b_read(is, sky_orient_);
1193 
1194     vsl_b_read(is, size);
1195     for (unsigned i = 0; i < size; i++) {
1196       std::vector<std::vector<unsigned> > o;
1197       vsl_b_read(is, o);
1198       dist_id_.push_back(o);
1199     }
1200 
1201     vsl_b_read(is, dist_offset_);
1202     vsl_b_read(is, min_obj_dist_);
1203     vsl_b_read(is, max_obj_dist_);
1204     vsl_b_read(is, order_obj_);
1205     vsl_b_read(is, obj_orient_);
1206     vsl_b_read(is, obj_land_id_);
1207     vsl_b_read(is, obj_land_wgt_);
1208   }
1209   else {
1210     std::cerr << "volm_spherical_shell_container - unknown binary io version " << ver <<'\n';
1211     return;
1212   }
1213 }
1214 
operator ==(const volm_query & other) const1215 bool volm_query::operator== (const volm_query &other) const
1216 {
1217   return this->get_cam_num() == other.get_cam_num() &&
1218   ni_ == other.ni_ && nj_ == other.nj_ &&
1219   log_downsample_ratio_ == other.log_downsample_ratio_ &&
1220   d_threshold_ == other.d_threshold_ &&
1221   depth_regions_.size() == other.depth_regions_.size() &&
1222   camera_strings_ == other.camera_strings_ &&
1223   order_set_ == other.order_set_ &&
1224   order_index_ == other.order_index_ &&
1225   ground_id_ == other.ground_id_ &&
1226   ground_dist_ == other.ground_dist_ &&
1227   ground_land_id_ == other.ground_land_id_ &&
1228   ground_offset_ == other.ground_offset_ &&
1229   ground_orient_ == other.ground_orient_ &&
1230   sky_id_ == other.sky_id_ &&
1231   sky_offset_ == other.sky_offset_ &&
1232   sky_orient_ == other.sky_orient_ &&
1233   dist_id_ == other.dist_id_ &&
1234   dist_offset_ == other.dist_offset_ &&
1235   min_obj_dist_ == other.min_obj_dist_ &&
1236   max_obj_dist_ == other.max_obj_dist_ &&
1237   order_obj_ == other.order_obj_ &&
1238   obj_orient_ == other.obj_orient_ &&
1239   obj_land_id_ == other.obj_land_id_;
1240 }
1241