licornea_tools
cg_rcpos_from_cors.cc
Go to the documentation of this file.
1 #include "../lib/common.h"
2 #include "../lib/args.h"
3 #include "../lib/json.h"
4 #include "../lib/dataset.h"
5 #include "../lib/intrinsics.h"
6 #include "../lib/misc.h"
7 #include "../lib/assert.h"
8 #include "lib/feature_points.h"
11 #include "lib/cg/straight_depths.h"
12 #include <map>
13 #include <iostream>
14 #include <vector>
15 #include <cmath>
16 #include <utility>
17 #include <set>
18 #include <algorithm>
19 #include <fstream>
20 #include <string>
21 
22 using namespace tlz;
23 
24 constexpr bool verbose = false;
25 constexpr std::size_t minimal_samples_count = 2;
26 constexpr real maximal_position_stddev = 1000.0;
27 
28 constexpr bool find_bad_features = true;
30 
31 constexpr bool print_all_sample_positions = false;
32 
34  vec2 position = vec2(0.0, 0.0);
35  real variance = NAN;
36 
39  position(pos), variance(var) { }
40 
41  explicit operator bool () const { return ! std::isnan(variance); }
42 };
43 target_camera_position_result compute_target_camera_position(const std::map<std::string, vec2>& samples) {
44  if(samples.size() < minimal_samples_count) return target_camera_position_result();
45 
46  vec2 mean(0.0, 0.0);
47  real count = samples.size();
48  for(const auto& kv : samples) mean += kv.second;
49  mean /= count;
50 
51  real variance = 0.0;
52  for(const auto& kv : samples) {
53  const vec2& pos = kv.second;
54  variance += sq(pos[0] - mean[0]) + sq(pos[1] - mean[1]);
55  }
56  variance /= count;
57  real stddev = std::sqrt(variance);
59 
60  return target_camera_position_result(mean, variance);
61 }
62 
63 
64 int main(int argc, const char* argv[]) {
65  get_args(argc, argv, "dataset_parameters.json cors.json intr.json R.json straight_depths.json out_rcpos.json [out_sample_positions.txt] [out_final_positions.txt]");
66  dataset datas = dataset_arg();
68  intrinsics intr = intrinsics_arg();
69  mat33 R = decode_mat(json_arg());
71  std::string out_rcpos_filename = out_filename_arg();
72  std::string out_sample_positions_filename = out_filename_opt_arg();
73  std::string out_final_positions_filename = out_filename_opt_arg();
74 
75  Assert(datas.is_2d(), "need 2d dataset");
76  Assert(intr.distortion.is_none(), "input cors + intrinsics must be without distortion");
77 
78  mat33 unrotate = intr.K * R.t() * intr.K_inv;
79 
80  std::cout << "collecting all view indices and all reference view indices" << std::endl;
81  auto all_vws = get_all_views(cors);
82  auto ref_vws = get_reference_views(cors);
83 
84  view_index ref2 = *(++ref_vws.begin());
85 
86  using target_camera_position_samples = std::map<std::string, vec2>;
87  auto get_target_camera_position_samples = [&](
88  const view_index& target_idx,
89  const view_index& ref_idx,
90  const image_correspondences& ref_cors,
91  const feature_points& ref_fpoints
92  ) -> target_camera_position_samples
93  {
94  feature_points target_fpoints = feature_points_for_view(ref_cors, target_idx, false);
95 
96  target_camera_position_samples samples;
97 
98  for(const auto& kv : target_fpoints.points) {
99  const std::string& feature_name = kv.first;
100  const std::string& shrt_feature_name = short_feature_name(feature_name);
101  const feature_point& target_fpoint = kv.second;
102 
103  if(! ref_fpoints.has_feature(feature_name)) continue;
104  const feature_point& reference_fpoint = ref_fpoints.points.at(feature_name);
105 
106  //if(feature_name != "feat2033" && feature_name != "feat2038" && feature_name != "feat2020") continue;
107 
108  if(depths.find(shrt_feature_name) == depths.end()) continue;
109  real straight_d = depths.at(shrt_feature_name).depth;
110 
111  const vec2& target_pos = target_fpoint.position;
112  vec2 straight_target_pos = mul_h(unrotate, target_pos);
113 
114  const vec2& reference_pos = reference_fpoint.position;
115  vec2 straight_reference_pos = mul_h(unrotate, reference_pos);
116 
117  vec2 feature_target_camera_pos;
118  feature_target_camera_pos[0] = (straight_target_pos[0] - straight_reference_pos[0]) * straight_d / intr.fx();
119  feature_target_camera_pos[1] = (straight_target_pos[1] - straight_reference_pos[1]) * straight_d / intr.fy();
120 
121  samples[shrt_feature_name] = feature_target_camera_pos;
122  }
123 
124  return samples;
125  };
126 
127 
128  std::set<std::string> bad_features;
129  if(find_bad_features) {
130  std::cout << "finding bad features" << std::endl;
131  struct feature_evalation {
132  real average_error = 0.0;
133  int samples_count = 0;
134  };
135  std::map<std::string, feature_evalation> feature_evaluations;
136 
137  #pragma omp parallel for
138  for(std::ptrdiff_t ref_ifx_i = 0; ref_ifx_i < ref_vws.size(); ++ref_ifx_i) {
139  const view_index& ref_idx = ref_vws[ref_ifx_i];
140  #pragma omp critical
141  std::cout << " reference view " << ref_idx << std::endl;
142 
144  feature_points ref_fpoints = feature_points_for_view(ref_cors, ref_idx, false);
145  for(const view_index& target_idx : all_vws) {
146  if(target_idx == ref_idx) continue;
147  target_camera_position_samples samples = get_target_camera_position_samples(target_idx, ref_idx, ref_cors, ref_fpoints);
148  vec2 mean = 0.0;
149  for(const auto& kv : samples) mean += kv.second;
150  mean /= real(samples.size());
151  for(const auto& kv : samples) {
152  const std::string& shrt_feature_name = kv.first;
153  const vec2& pos = kv.second;
154  real mean_sq_dist = sq(mean[0] - pos[0]) + sq(mean[1] - pos[1]);
155  #pragma omp critical
156  {
157  feature_evaluations[shrt_feature_name].samples_count++;
158  feature_evaluations[shrt_feature_name].average_error += mean_sq_dist;
159  }
160  }
161  }
162  }
163 
164  std::vector<std::string> worst_features;
165  for(auto& kv : feature_evaluations) {
166  const std::string& shrt_feature_name = kv.first;
167  feature_evalation& eval = kv.second;
168  eval.average_error /= eval.samples_count;
169  worst_features.push_back(shrt_feature_name);
170  }
171  std::ptrdiff_t bad_count = worst_features.size() * (1.0 - features_inlier_percentile);
172  auto worst_features_bad_end = worst_features.begin() + bad_count;
173  std::partial_sort(
174  worst_features.begin(),
175  worst_features.begin() + bad_count,
176  worst_features.end(),
177  [&feature_evaluations](const std::string& a, const std::string& b) {
178  real err_a = feature_evaluations.at(a).average_error;
179  real err_b = feature_evaluations.at(b).average_error;
180  return (err_a > err_b);
181  }
182  );
183  bad_features = std::set<std::string>(worst_features.begin(), worst_features_bad_end);
184  std::cout << " bad features:" << std::endl;
185  for(const std::string& shrt_feature_name : bad_features) {
186  real err = feature_evaluations.at(shrt_feature_name).average_error;
187  std::cout << " " << shrt_feature_name << " (avg error: " << err << ")" << std::endl;
188  }
189  }
190 
191  std::cout << "estimating target camera positions, from each reference" << std::endl;
192  relative_camera_positions out_rcpos;
193 
194  std::ofstream out_sample_positions_stream, out_final_positions_stream;
195  if(! out_sample_positions_filename.empty()) {
196  out_sample_positions_stream.open(out_sample_positions_filename);
197  out_sample_positions_stream << "x y feature_name target_idx_x target_idx_y ref_idx_x ref_idx_y\n";
198  out_sample_positions_stream << std::setprecision(10);
199  }
200  if(! out_final_positions_filename.empty()) {
201  out_final_positions_stream.open(out_final_positions_filename);
202  out_final_positions_stream << "x y target_idx_x target_idx_y ref_idx_x ref_idx_y\n";
203  out_final_positions_stream << std::setprecision(10);
204  }
205 
206  #pragma omp parallel for
207  for(std::ptrdiff_t ref_ifx_i = 0; ref_ifx_i < ref_vws.size(); ++ref_ifx_i) {
208  const view_index& ref_idx = ref_vws[ref_ifx_i];
209 
210  int final_relative_views_count = 0;
211 
212  //if(ref_idx != ref2) continue;
213 
215  feature_points ref_fpoints = feature_points_for_view(ref_cors, ref_idx, false);
216 
217  std::map<view_index, vec2> relative_camera_positions;
218 
219  for(const view_index& target_idx : all_vws) {
221  target_camera_position_samples samples;
222 
223  if(target_idx == ref_idx) {
224  final_pos.position = vec2(0.0, 0.0);
225  final_pos.variance = 0.0;
226 
227  } else {
228  samples = get_target_camera_position_samples(target_idx, ref_idx, ref_cors, ref_fpoints);
230  for(const std::string& shrt_bad_feature_name : bad_features) samples.erase(shrt_bad_feature_name);
231 
232  final_pos = compute_target_camera_position(samples);
233  }
234 
235  if(final_pos) {
236  ++final_relative_views_count;
237 
238  #pragma omp critical
239  {
240  out_rcpos.position(ref_idx, target_idx) = final_pos.position;
241 
242  if(out_final_positions_stream.is_open())
243  out_final_positions_stream <<
244  final_pos.position[0] << ' ' <<
245  final_pos.position[1] << ' ' <<
246  target_idx.x << ' ' <<
247  target_idx.y << ' ' <<
248  ref_idx.x << ' ' <<
249  ref_idx.y << '\n';
250 
251  for(const auto& kv : samples) {
252  const std::string& shrt_feature_name = kv.first;
253  const vec2& pos = kv.second;
254  bool print_sample = print_all_sample_positions || std::abs(std::abs(target_idx.x - ref_idx.x) - std::abs(target_idx.y - ref_idx.y)) < 20;
255  if(out_sample_positions_stream.is_open() && print_sample)
256  out_sample_positions_stream <<
257  pos[0] << ' ' <<
258  pos[1] << ' ' <<
259  std::stoi(shrt_feature_name.substr(4))+1000 << ' ' <<
260  target_idx.x << ' ' <<
261  target_idx.y << ' ' <<
262  ref_idx.x << ' ' <<
263  ref_idx.y << '\n';
264  }
265  }
266  }
267  }
268 
269  #pragma omp critical
270  std::cout << " reference view " << ref_idx << ": final relative positions for " << final_relative_views_count << " views" << std::endl;
271  }
272 
273  std::cout << "checking for which views there is a position" << std::endl;
274  auto tpos = out_rcpos.to_target_reference_positions();
275  auto really_all_target_views = datas.indices();
276  for(const view_index& target_idx : really_all_target_views) {
277  if(tpos.find(target_idx) == tpos.end()) {
278  std::cout << "no camera position for " << target_idx << std::endl;
279  }
280  }
281 
282 
283  std::cout << "saving relative camera positions" << std::endl;
284  export_json_file(encode_relative_camera_positions(out_rcpos), out_rcpos_filename);
285 }
286 
Numeric sq(Numeric n)
Compute square of a number.
Definition: misc.h:17
target_reference_positions_type to_target_reference_positions() const
std::string short_feature_name(const std::string &full_feature_name)
constexpr real features_inlier_percentile
constexpr std::size_t minimal_samples_count
std::vector< view_index > get_all_views(const image_correspondences &cors)
image_correspondences image_correspondences_with_reference(const image_correspondences &cors, const view_index &reference_view)
bool is_2d() const
Definition: dataset.cc:137
Set of features, each on set of views.
Points of different features, on one view.
constexpr bool verbose
cv::Vec< real, 2 > vec2
Definition: common.h:22
std::map< std::string, feature_point > points
vec3 mul_h(const mat44 &mat, const vec3 &vec)
Definition: common.h:29
feature_points feature_points_for_view(const image_correspondences &cors, view_index idx, bool is_distorted)
cv::Mat_< real > decode_mat(const json &j)
Definition: json.cc:32
std::string out_filename_opt_arg(const std::string &def)
Definition: args.cc:110
intrinsics intrinsics_arg()
Definition: intrinsics.cc:119
real fx() const
Definition: intrinsics.h:34
json json_arg()
Definition: json.h:34
distortion_parameters distortion
Definition: intrinsics.h:30
std::vector< view_index > get_reference_views(const relative_camera_positions &rcpos)
dataset dataset_arg()
Definition: dataset.cc:297
cv::Matx< real, 3, 3 > mat33
Definition: common.h:26
std::map< std::string, straight_depth > straight_depths
double real
Definition: common.h:16
void export_json_file(const json &j, const std::string &filename, bool compact)
Definition: json.cc:9
image_correspondences image_correspondences_arg()
vec2 & position(const reference_view_index &ref_idx, const target_view_index &target_idx)
#define Assert
Definition: assert.h:40
straight_depths straight_depths_arg()
std::string out_filename_arg()
Definition: args.cc:104
constexpr real maximal_position_stddev
real fy() const
Definition: intrinsics.h:35
target_camera_position_result(const vec2 &pos, real var)
constexpr bool find_bad_features
target_camera_position_result compute_target_camera_position(const std::map< std::string, vec2 > &samples)
constexpr bool print_all_sample_positions
int main(int argc, const char *argv[])
std::vector< view_index > indices() const
Definition: dataset.cc:235
json encode_relative_camera_positions(const relative_camera_positions &rcpos)
void get_args(int argc, const char *argv[], const std::string &usage)
Definition: args.cc:49