1 #include "bsgm_pair_selector.h"
2 #include "vnl/vnl_math.h"
3 #include <bjson/bjson.h>
4 #include <algorithm>
5 #include <fstream>
6 #include <bpgl/acal/acal_metadata.h>
7 
remove_crop_postfix(std::string const & iname)8 std::string bsgm_pair_selector::remove_crop_postfix(std::string const& iname)
9 {
10   size_t s = iname.find("_crop");
11   if (s == std::string::npos)
12     return iname;
13   std::string temp = iname;
14   temp.replace(s, 5, std::string(""));
15   return temp;
16 }
17 
load_uncorr_affine_cams(std::string affine_cam_path)18 bool bsgm_pair_selector::load_uncorr_affine_cams(std::string affine_cam_path)
19 {
20   return acal_f_utils::read_affine_cameras(affine_cam_path, acams_);
21 }
22 
set_inames()23 bool bsgm_pair_selector::set_inames()
24 {
25   size_t ni = meta_.img_meta_.size(), ng = meta_.geo_corr_meta_.size();
26   if (ni == 0 || ng == 0) {
27     std::cout << "null image or geo_corr metadata (n_imeta, n_gmeta) " << ni << ' ' << ng << std::endl;
28     return false;
29   }
30   for (size_t i = 0; i<ng; ++i) {
31     // remove images with too large a projection error or a duplicate, indicated by a proj error of -1
32     const geo_corr_metadata& gm = meta_.geo_corr_meta_[i];
33     if(gm.rms_proj_err_ > params_.max_proj_err_)
34       continue;
35     if(gm.rms_proj_err_ == -1.0)
36       continue;
37     //geo_corr metadata has the actual image name including the _crop postfix
38     //the base image name is required
39     inames_[gm.image_id_] = remove_crop_postfix(gm.image_name_);
40   }
41   std::cout << inames_.size() << " images with proj error at or below " << params_.max_proj_err_ << std::endl;
42   for (std::map<size_t, std::string>::iterator iit = inames_.begin();
43       iit != inames_.end(); ++iit) {
44     size_t i = iit->first;
45     std::string iname = iit->second;
46     dtime datetime;
47     if (!acal_f_utils::datetime_from_iname(iname, datetime)) {
48       std::cout << "can't resolve datetime from " << iname << std::endl;
49       return false;
50     }
51     dtimes_[i]=datetime;
52   }
53   return true;
54 }
55 
sun_direction(std::string const & iname)56 vgl_vector_3d<double>  bsgm_pair_selector::sun_direction(std::string const& iname){
57   vgl_vector_3d<double> ret(0.0, 0.0, 0.0);
58   double deg_to_rad = vnl_math::pi/180.0;
59   bool found = false;
60   vgl_vector_2d<double> sph_dir(0.0, 0.0);
61   size_t n = meta_.img_meta_.size();
62   for (size_t i = 0; i<n&&!found; ++i) {
63     if (iname == (meta_.img_meta_[i].image_name_)) {
64       found = true;
65       sph_dir =  meta_.img_meta_[i].sph_sun_dir_;
66     }
67   }
68   if (!found) {
69     std::cout << "Warning - for sun direction can't find image name " << iname << " in metadata" << std::endl;
70     return ret;
71   }
72   double s = sin(sph_dir.y()*deg_to_rad);
73   double c = cos(sph_dir.y()*deg_to_rad);
74   double x = -c*sin(sph_dir.x()*deg_to_rad);
75   double y = -c*cos(sph_dir.x()*deg_to_rad);
76   double z = -s;
77   ret.set(x, y, z);
78   return ret;
79 }
80 
gsd(std::string const & iname)81 double bsgm_pair_selector::gsd(std::string const& iname)
82 {
83   double ret = 0.0;
84   size_t n = meta_.img_meta_.size();
85   bool found = false;
86   for (size_t i = 0; i<n&&!found; ++i)
87     if (iname == (meta_.img_meta_[i].image_name_))
88     {
89       found = true;
90       ret =  meta_.img_meta_[i].gsd_;
91     }
92   if (!found) {
93     std::cout << "Warning - for gsd can't find image name " << iname << " in metadata" << std::endl;
94   }
95   return ret;
96 }
97 
cache_pair_info()98 void bsgm_pair_selector::cache_pair_info()
99 {
100   bsgm_pair_less pl(params_.best_angle_, params_.low_angle_bnd_, params_.high_angle_bnd_,params_.max_sun_ang_, params_.max_gsd_ratio_, sun_angle_diffs_, ang_diffs_, gsd_ratios_);
101   size_t n = ordered_pairs_.size();
102   for (size_t k = 0; k<n; ++k) {
103     size_t i = ordered_pairs_[k].first, j = ordered_pairs_[k].second;
104     std::string iname_i = inames_[i], iname_j = inames_[j];
105     bsgm_pair_info pinf;
106     pinf.i_ =i; pinf.j_ = j;
107     pinf.iname_i_ = iname_i; pinf.iname_j_ = iname_j;
108     pinf.view_angle_diff_ = ang_diffs_[i][j];
109     pinf.sun_angle_diff_ = sun_angle_diffs_[i][j];
110     pinf.gsd_ratio_ = gsd_ratios_[i][j];
111     pinf.cost_ = pl.cost(pinf.view_angle_diff_, pinf.sun_angle_diff_, pinf.gsd_ratio_);
112     ordered_pair_info_.push_back(pinf);
113   }
114 }
115 
prioritize_pairs()116 bool bsgm_pair_selector::prioritize_pairs()
117 {
118   f_params params;
119   double dgen_tol = 1.0/(params.ray_uncertainty_tol_);
120   // get time differences
121   std::map<size_t, std::string>::iterator before_end = inames_.end();
122   std::advance(before_end, -1);
123   size_t ii = 0;
124   for (std::map<size_t, std::string>::iterator iit = inames_.begin();
125       iit != before_end; ++iit, ++ii)
126   {
127     size_t idx = iit->first;
128     const dtime& dti = dtimes_[idx];
129     std::map<size_t, std::string>::iterator jit = inames_.begin();
130     std::advance(jit, ii + 1);
131     for (; jit != inames_.end(); ++jit) {
132       size_t jdx = jit->first;
133       const dtime& dtj = dtimes_[jdx];
134       int dt = abs(dtime::time_diff(dti, dtj));
135       time_diffs_[idx][jdx] = dt;
136     }
137   }
138 
139   // get view ray differences (angle in degrees)
140   ii = 0;
141   for (std::map<size_t, std::string>::iterator iit = inames_.begin();
142       iit != before_end; ++iit, ++ii) {
143     size_t idx = iit->first;
144     vgl_vector_3d<double> dir_i = acams_[idx].ray_dir();
145     if (dir_i.z()>0.0) dir_i = -dir_i;
146     std::string iname = inames_[idx];
147     std::string nc_iname   = remove_crop_postfix(iname);
148     vgl_vector_3d<double> sun_ang_i = sun_direction(nc_iname);
149     double gsd_i = gsd(nc_iname);
150     std::map<size_t, std::string>::iterator jit = inames_.begin();
151     std::advance(jit, ii+1);
152     for (;jit != inames_.end(); ++jit) {
153       size_t jdx = jit->first;
154       std::string jname = inames_[jdx];
155       std::string nc_jname  = remove_crop_postfix(jname);
156       vgl_vector_3d<double> sun_ang_j = sun_direction(nc_jname);
157       double sun_ang_dif = fabs(angle(sun_ang_i, sun_ang_j));
158       sun_angle_diffs_[idx][jdx]=sun_ang_dif * 180.0 / vnl_math::pi;
159       vgl_vector_3d<double> dir_j = acams_[jdx].ray_dir();
160       if (dir_j.z()>0.0) dir_j = -dir_j;
161       double gsd_j = gsd(nc_jname);
162       double ang = fabs(angle(dir_i, dir_j))*180.0/vnl_math::pi;
163       ang_diffs_[idx][jdx] = ang;
164 
165       double el = acos(fabs(dir_i.z()));
166       double az = atan2(dir_i.y(), dir_i.x());
167       if (fabs(dir_j.z()) < fabs(dir_i.z())) {
168         el = acos(fabs(dir_j.z()));
169         az = atan2(dir_j.y(), dir_j.x());
170       }
171       el *= 180.0/vnl_math::pi;
172       az *= 180.0/vnl_math::pi;
173       view_az_el_[idx][jdx] = std::pair<double,double>(az, el);
174       double gsd_ratio = gsd_i/gsd_j;
175       if (gsd_ratio<1.0)
176         gsd_ratio = 1.0/gsd_ratio;
177       gsd_ratios_[idx][jdx] = gsd_ratio;
178       double dp = dot_product(dir_i, dir_j);
179       double dgen = fabs(1.0 - (dp*dp));
180       no_ray_degen_[idx][jdx] = dgen > 0.1*dgen_tol;
181     }
182   }
183   ii = 0;
184   for (std::map<size_t, std::string>::iterator iit = inames_.begin();
185       iit != before_end; ++iit, ++ii) {
186     size_t idx = iit->first;
187     std::map<size_t, std::string>::iterator jit = inames_.begin();
188     std::advance(jit, ii + 1);
189     for (; jit != inames_.end(); ++jit) {
190       size_t jdx = jit->first;
191       if (no_ray_degen_[idx][jdx])
192         ordered_pairs_.emplace_back(idx, jdx);
193     }
194   }
195   bsgm_pair_less pl(params_.best_angle_, params_.low_angle_bnd_, params_.high_angle_bnd_,params_.max_sun_ang_, params_.max_gsd_ratio_, sun_angle_diffs_, ang_diffs_, gsd_ratios_);
196   std::sort(ordered_pairs_.begin(),ordered_pairs_.end(), pl);
197   cache_pair_info();
198   return true;
199 }
200 
pair_inames()201 std::vector<std::pair<std::string, std::string> > bsgm_pair_selector::pair_inames()
202 {
203   std::vector<std::pair<std::string, std::string> > ret;
204   for(std::vector<std::pair<size_t, size_t> >::const_iterator pit = ordered_pairs_.begin();
205       pit != ordered_pairs_.end(); ++pit) {
206     std::pair<std::string, std::string> pr(inames_[pit->first], inames_[pit->second]);
207     ret.push_back(pr);
208   }
209   return ret;
210 }
211 
read_image_metadata()212 bool bsgm_pair_selector::read_image_metadata()
213 {
214   std::string meta_path = meta_dir_ + image_meta_fname_;
215   Json::Value root;
216   Json::Reader reader;
217   std::ifstream istr(meta_path.c_str());
218   if (!istr) {
219     std::cout << "Can't open " << meta_path << " to read metadata" << std::endl;
220     return false;
221   }
222   bool good = reader.parse(istr, root);
223   if (!good) {
224     std::cout << " Json parse failed for file " << meta_path << std::endl;
225     return false;
226   }
227   meta_.deserialize_image_meta(root);
228   return true;
229 }
230 
read_geo_corr_metadata(bool seed_cameras_only)231 bool bsgm_pair_selector::read_geo_corr_metadata(bool seed_cameras_only)
232 {
233   std::string meta_path = meta_dir_ + geo_corr_meta_fname_;
234   Json::Value root, non_seed_root;
235   Json::Reader reader;
236   std::ifstream istr(meta_path.c_str());
237   if (!istr) {
238     std::cout << "Can't open " << meta_path << " to read metadata" << std::endl;
239     return false;
240   }
241   bool good = reader.parse(istr, root);
242   if (!good) {
243     std::cout << " Json parse failed for file " << meta_path << std::endl;
244     return false;
245   }
246   meta_.deserialize_geo_corr_meta(root);
247   if (!seed_cameras_only) {
248     std::string non_seed_meta_path = meta_dir_ + non_seed_geo_corr_meta_fname_;
249     std::ifstream non_seed_istr(non_seed_meta_path.c_str());
250     if (!non_seed_istr) {
251       std::cout << "Can't open " << non_seed_meta_path << " to read metadata" << std::endl;
252       return false;
253     }
254     good = reader.parse(non_seed_istr, non_seed_root);
255     if (!good) {
256       std::cout << " Json parse failed for file " << non_seed_meta_path << std::endl;
257       return false;
258     }
259     non_seed_meta_.deserialize_geo_corr_meta(non_seed_root);
260     meta_.geo_corr_meta_.insert(meta_.geo_corr_meta_.end(), non_seed_meta_.geo_corr_meta_.begin(), non_seed_meta_.geo_corr_meta_.end());
261   }
262   return true;
263 }
264 
print_ordered_pairs()265 void bsgm_pair_selector::print_ordered_pairs()
266 {
267   std::cout << ">>>>>>>>>>>>>>>Ordered pairs<<<<<<<<<<<<<<<<<<<" << std::endl;
268   std::cout << "i   j   view     sun     gsd      cost" << std::endl;
269   bsgm_pair_less pl(params_.best_angle_, params_.low_angle_bnd_, params_.high_angle_bnd_,params_.max_sun_ang_, params_.max_gsd_ratio_, sun_angle_diffs_, ang_diffs_, gsd_ratios_);
270   for (std::vector<std::pair<size_t, size_t> >::const_iterator pit = ordered_pairs_.begin();
271        pit != ordered_pairs_.end(); ++pit) {
272     size_t i = pit->first, j = pit->second;
273     double view_ang_dif = ang_diffs_[i][j];
274     double sun_angle_dif = sun_angle_diffs_[i][j];
275     double gsd_rat = gsd_ratios_[i][j];
276     double c = pl.cost(view_ang_dif, sun_angle_dif, gsd_rat);
277     std::cout << i << ' ' << j << ' ' << view_ang_dif << ' '<< sun_angle_dif << ' ' << gsd_rat << ' ' << c << std::endl;
278   }
279 }
280 
print_pair_el_az()281 void bsgm_pair_selector::print_pair_el_az()
282 {
283   std::cout << "i   j   el     az " << std::endl;
284   for (std::vector<std::pair<size_t, size_t> >::const_iterator pit = ordered_pairs_.begin();
285        pit != ordered_pairs_.end(); ++pit) {
286     size_t i = pit->first, j = pit->second;
287     double az = view_az_el_[i][j].first, el = view_az_el_[i][j].second;
288     std::cout << i << ' ' << j << ' ' << el << ' '<< az << std::endl;
289   }
290 }
291 
save_ordered_pairs()292 bool bsgm_pair_selector::save_ordered_pairs()
293 {
294   acal_metadata meta;
295   std::string path = tile_dir_ + subdir_ + pair_output_fname_;
296   std::ofstream ostr(path.c_str());
297   if (!ostr) {
298     std::cout << "Can't open " << path<< " to write image pairs" << std::endl;
299     return false;
300   }
301   size_t n = ordered_pairs_.size();
302   for (size_t i = 0; i<n; ++i) {
303     const std::pair<size_t, size_t>& pr = ordered_pairs_[i];
304     pair_selection_metadata psm;
305     psm.pair_index_ = i;
306     psm.image1_id_ = pr.first;
307     psm.image2_id_ = pr.second;
308     std::string iname_no_corr = remove_crop_postfix(inames_[pr.first]);
309     std::string jname_no_corr = remove_crop_postfix(inames_[pr.second]);
310     //psm.iname_i_ = iname_no_corr;
311     //psm.iname_j_ = jname_no_corr;
312     psm.cost_ = ordered_pair_info_[i].cost_;
313     meta.pair_meta_.push_back(psm);
314   }
315   Json::Value pair_root;
316   meta.serialize_pair_selection_meta(pair_root);
317   if (pair_root.isNull()) {
318     std::cout << "serialize pair metadata failed" << std::endl;
319     return false;
320   }
321   Json::StyledStreamWriter writer;
322   writer.write(ostr, pair_root);
323   return true;
324 }
325 
save_all_ordered_pairs()326 bool bsgm_pair_selector::save_all_ordered_pairs()
327 {
328   acal_metadata meta;
329   std::string path = meta_dir_ + pair_output_fname_;
330   std::ofstream ostr(path.c_str());
331   if (!ostr) {
332     std::cout << "Can't open " << path<< " to write image pairs" << std::endl;
333     return false;
334   }
335   size_t n = ordered_pairs_.size();
336   for (size_t i = 0; i<n; ++i) {
337     const std::pair<size_t, size_t>& pr = ordered_pairs_[i];
338     pair_selection_metadata psm;
339     psm.pair_index_ = i;
340     psm.image1_id_ = pr.first;
341     psm.image2_id_= pr.second;
342     std::string iname_no_corr = remove_crop_postfix(inames_[pr.first]);
343     std::string jname_no_corr = remove_crop_postfix(inames_[pr.second]);
344     //psm.iname_i_ = iname_no_corr;
345     //psm.iname_j_ = jname_no_corr;
346     psm.cost_ = ordered_pair_info_[i].cost_;
347     meta.pair_meta_.push_back(psm);
348   }
349   Json::Value pair_root;
350   meta.serialize_pair_selection_meta(pair_root);
351   if (pair_root.isNull()) {
352     std::cout << "serialize pair metadata failed" << std::endl;
353     return false;
354   }
355   Json::StyledStreamWriter writer;
356   writer.write(ostr, pair_root);
357   return true;
358 }
359