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