licornea_tools
cg_rotation_from_fslopes.cc
Go to the documentation of this file.
1 #include <string>
2 #include <vector>
3 #include <cmath>
4 #include <iostream>
5 #include <fstream>
6 #include <cassert>
8 #include "../lib/args.h"
9 #include "../lib/misc.h"
10 #include "../lib/json.h"
11 #include "../lib/opencv.h"
12 #include "../lib/intrinsics.h"
13 #include "../lib/assert.h"
14 #include "../lib/rotation.h"
15 
16 using namespace tlz;
17 
18 constexpr bool verbose = true;
19 
20 template<typename Func>
21 void one_dim_search_minimum(Func f, real& a, real& b, real tolerance) {
22  assert(a < b);
23 
24  real c = b - (b - a)/golden_ratio;
25  real d = a + (b - a)/golden_ratio;
26 
27  while(std::abs(c - d) > tolerance) {
28  if(f(c) < f(d)) b = d;
29  else a = c;
30  c = b - (b - a) / golden_ratio;
31  d = a + (b - a) / golden_ratio;
32  }
33 }
34 
35 
36 int main(int argc, const char* argv[]) {
37  get_args(argc, argv, "measured_feature_slopes.json intrinsics.json out_rotation.json");
38  feature_slopes measured_fslopes = feature_slopes_arg();
39  intrinsics intr = intrinsics_arg();
40  std::string out_rotation_filename = out_filename_arg();
41 
42  Assert(! measured_fslopes.is_distorted);
43 
44  auto rotation_error = [&measured_fslopes, &intr](real x, real y, real z) {
45  mat33 R = to_rotation_matrix(vec3(x, y, z));
46 
47  real fx = intr.fx(), fy = intr.fy(), cx = intr.cx(), cy = intr.cy();
48  real r11 = R(0, 0), r21 = R(1, 0), r31 = R(2, 0);
49  real r12 = R(0, 1), r22 = R(1, 1), r32 = R(2, 1);
50 
51  real err_sum = 0.0;
52  for(const auto& kv : measured_fslopes.slopes) {
53  const std::string& feature_name = kv.first;
54  const feature_point& undist_fpoint = measured_fslopes.points.at(feature_name);
55  const feature_slope& measured_fslope = kv.second;
56 
57  real ix = undist_fpoint.position[0], iy = undist_fpoint.position[1];
58  real model_hslope = (fy*r21 + cy*r31 - iy*r31) / (fx*r11 + cx*r31 - ix*r31);
59  real model_vslope = (fx*r12 + cx*r32 - ix*r32) / (fy*r22 + cy*r32 - iy*r32);
60 
61  real measured_hslope = measured_fslope.horizontal;
62  real measured_vslope = measured_fslope.vertical;
63 
64  real err = sq(model_hslope - measured_hslope) + sq(model_vslope - measured_vslope);
65  err_sum += err;
66  }
67  err_sum /= measured_fslopes.slopes.size();
68  return err_sum;
69  };
70 
71  std::cout << "minimizing rotations error" << std::endl;
72  real z = 0.0, x = 0.0, y = 0.0;
73  {
74  auto f_x = [&](real x_) { return rotation_error(x_, y, z); };
75  auto f_y = [&](real y_) { return rotation_error(x, y_, z); };
76  auto f_z = [&](real z_) { return rotation_error(x, y, z_); };
77 
78  real initial_outreach = 10.0 * rad_per_deg;
79  real initial_tolerance = 1.0 * rad_per_deg;
80  real min_error = 1e-20;
81  real min_error_diff = 1e-20;
82  int max_iterations = 500;
83  real outreach_scaledown = 0.001;
84  real tolerance_scaledown = 0.005;
85 
86  int iterations = 0;
87  real outreach = initial_outreach;
88  real tolerance = initial_tolerance;
89  real err = rotation_error(x, y, z);
90  while(err > min_error && iterations != max_iterations) {
91  if(verbose) {
92  std::cout << "iterations = " << iterations << "\n";
93  std::cout << "err = " << err << "\n";
94  std::cout << "x = " << x * deg_per_rad << "°\n";
95  std::cout << "y = " << y * deg_per_rad << "°\n";
96  std::cout << "z = " << z * deg_per_rad << "°\n";
97  std::cout << "outreach = " << outreach << "\n";
98  std::cout << "tolerance = " << tolerance << "\n\n" << std::endl;
99  } else {
100  std::cout << '.' << std::flush;
101  }
102 
103  real z_min = z - outreach, z_max = z + outreach;
104  one_dim_search_minimum(f_z, z_min, z_max, tolerance);
105  z = (z_max + z_min) / 2.0;
106 
107  real x_min = x - outreach, x_max = x + outreach;
108  one_dim_search_minimum(f_x, x_min, x_max, tolerance);
109  x = (x_max + x_min) / 2.0;
110 
111  real y_min = y - outreach, y_max = y + outreach;
112  one_dim_search_minimum(f_y, y_min, y_max, tolerance);
113  y = (y_max + y_min) / 2.0;
114 
115  ++iterations;
116  outreach = initial_outreach / std::exp(iterations * outreach_scaledown);
117  tolerance = initial_tolerance / std::exp(iterations * tolerance_scaledown);
118  real prev_err = err;
119  err = rotation_error(x, y, z);
120 
121  if(std::abs(prev_err - err) < min_error_diff) break;
122  }
123 
124  std::cout << "\nfound minimum err = " << err << "\n";
125  std::cout << "x = " << x * deg_per_rad << "°\n";
126  std::cout << "y = " << y * deg_per_rad << "°\n";
127  std::cout << "z = " << z * deg_per_rad << "°" << std::endl;
128  }
129 
130  std::cout << "saving rotation matrix" << std::endl;
131  mat33 R = to_rotation_matrix(vec3(x, y, z));
132  export_json_file(encode_mat(R), out_rotation_filename);
133 }
Numeric sq(Numeric n)
Compute square of a number.
Definition: misc.h:17
int main(int argc, const char *argv[])
constexpr real deg_per_rad
Definition: common.h:78
constexpr real golden_ratio
Definition: common.h:81
real cy() const
Definition: intrinsics.h:37
void one_dim_search_minimum(Func f, real &a, real &b, real tolerance)
feature_slopes feature_slopes_arg()
std::map< std::string, feature_point > points
intrinsics intrinsics_arg()
Definition: intrinsics.cc:119
real fx() const
Definition: intrinsics.h:34
cv::Matx< real, 3, 3 > mat33
Definition: common.h:26
json encode_mat(const Mat &mat)
Definition: json.h:19
double real
Definition: common.h:16
void export_json_file(const json &j, const std::string &filename, bool compact)
Definition: json.cc:9
cv::Vec< real, 3 > vec3
Definition: common.h:23
mat33 to_rotation_matrix(const vec3 &euler)
Definition: rotation.cc:17
#define Assert
Definition: assert.h:40
std::string out_filename_arg()
Definition: args.cc:104
constexpr real rad_per_deg
Definition: common.h:79
std::map< std::string, feature_slope > slopes
real cx() const
Definition: intrinsics.h:36
real fy() const
Definition: intrinsics.h:35
constexpr bool verbose
void get_args(int argc, const char *argv[], const std::string &usage)
Definition: args.cc:49