ldpk
tde4_ldp_radial_deg_8.h
Go to the documentation of this file.
1 #ifndef tde4_ldp_radial_deg_8_sdv
2 #define tde4_ldp_radial_deg_8_sdv
3 
4 #include <ldpk/ldpk_ldp_builtin.h>
6 
9 
13 template <class VEC2,class MAT2>
15  {
16 private:
17  typedef VEC2 vec2_type;
18  typedef MAT2 mat2_type;
20 
22 
23  static const char* _para[4];
24  double _r_clip_factor;
25 
26  bool decypher(const char* name,int& i)
27  {
28  typedef base_type bt;
29  int n;
30  getNumParameters(n);
31  for(i = 0;i < n;++i)
32  {
33  if(0 == strcmp(name,_para[i]))
34  {
35  return true;
36  }
37  }
38  return false;
39  }
40  bool initializeParameters()
41  {
42  typedef base_type bt;
43  bt::check_builtin_parameters();
44  return true;
45  }
46  bool getNumParameters(int& n)
47  {
48  n = 4;
49  return true;
50  }
51  bool getParameterName(int i,char* identifier)
52  {
53  strcpy(identifier,_para[i]);
54  return true;
55  }
56  bool setParameterValue(const char *identifier,double v)
57  {
58  typedef base_type bt;
59  int i;
60 // Does the base class know the parameter?
61  if(bt::set_builtin_parameter_value(identifier,v))
62  {
63  return true;
64  }
65  if(!decypher(identifier,i))
66  {
67  return false;
68  }
69  if(_distortion.get_coeff(i) != v)
70  {
71  bt::no_longer_uptodate_lut();
72  }
73  _distortion.set_coeff(i,v);
74  return true;
75  }
79  bool esa2plain(const vec2_type& p_esa_dn,vec2_type& p_plain_dn)
80  {
81  bool rc = true;
82  double f_dn = this->fl_cm() / this->r_fb_cm();
83 // Remove fisheye projection
84  double r_esa_dn = norm2(p_esa_dn);
85  if(r_esa_dn == 0.0)
86  {
87  p_plain_dn = p_esa_dn;
88  return rc;
89  }
90  double arg = r_esa_dn / (2.0 * f_dn),arg_clip = arg;
91 // Black areas, undefined.
92  if(arg_clip >= 1.0)
93  {
94  arg_clip = 0.9999;
95  }
96  double phi = 2.0 * asin(arg_clip);
97  if(phi >= M_PI / 2.0)
98  {
99 // This can and will happen in re-distorting footage...
100  phi = M_PI / 2.0 - 1e-5;
101  rc = false;
102  }
103  double r_plain_dn = f_dn * tan(phi);
104  if(r_plain_dn > _r_clip_factor)
105  {
106 // ... as well as this.
107  r_plain_dn = _r_clip_factor;
108  }
109  p_plain_dn = r_plain_dn * unit(p_esa_dn);
110  return rc;
111  }
112  bool plain2esa(const vec2_type& p_plain_dn,vec2_type& p_esa_dn)
113  {
114  typedef base_type bt;
115  double f_dn = bt::fl_cm() / bt::r_fb_cm();
116 // Apply fisheye projection
117  double r_plain_dn = norm2(p_plain_dn);
118  if(r_plain_dn == 0.0)
119  {
120  p_esa_dn = p_plain_dn;
121  return true;
122  }
123  double phi = atan2(r_plain_dn,f_dn);
124  double r_esa_dn = 2.0 * f_dn * std::sin(phi / 2.0);
125  p_esa_dn = r_esa_dn * unit(p_plain_dn);
126  return true;
127  }
128 
129 // Overwriting tde4_ldp_common
130  bool undistort(double x0,double y0,double &x1,double &y1)
131  {
132  typedef base_type bt;
133  vec2_type p_esa_dn = bt::map_unit_to_dn(vec2_type(x0,y0));
134  vec2_type p_plain_dn;
135  if(!esa2plain(p_esa_dn,p_plain_dn)) return false;
136 
137 // Clipping to a reasonable area, still n times as large as the image.
138  vec2_type q_dn = _distortion.eval(p_plain_dn);
139  if(norm2(q_dn) > 100.0) q_dn = 100.0 * unit(q_dn);
140 
141  vec2_type q = bt::map_dn_to_unit(q_dn);
142  x1 = q[0];
143  y1 = q[1];
144  return true;
145  }
146  bool distort(double x0,double y0,double &x1,double &y1)
147  {
148  typedef base_type bt;
149 // The distort-method without initial values is not constant by semantics,
150 // since it may cause an update of the lookup-tables. Implementing a Nuke node
151 // it turned out that we need to prevent threads from trying so simultaneously.
152 // By the following double check of is_uptodate_lut() we keep the mutex lock
153 // out of our frequently called distort stuff (for performance reasons) and
154 // prevent threads from updating without need.
155  if(!bt::is_uptodate_lut())
156  {
157  bt::lock();
158  if(!bt::is_uptodate_lut())
159  {
160  bt::update_lut();
161  }
162  bt::unlock();
163  }
164 
165 // Get initial value from lookup-table
166  vec2_type qs = bt::get_lut().get_initial_value(vec2_type(x0,y0));
167 // Call version of distort with initial value.
168  vec2_type p_plain_dn = _distortion.map_inverse(bt::map_unit_to_dn(vec2_type(x0,y0)),bt::map_unit_to_dn(qs));
169  vec2_type p_esa_dn;
170  if(!plain2esa(p_plain_dn,p_esa_dn)) return false;
171 
172  vec2_type q = bt::map_dn_to_unit(p_esa_dn);
173  x1 = q[0];
174  y1 = q[1];
175  return true;
176  }
177  bool distort(double x0,double y0,double x1_start,double y1_start,double &x1,double &y1)
178  {
179  typedef base_type bt;
180  vec2_type p_plain_dn = _distortion.map_inverse(bt::map_unit_to_dn(vec2_type(x0,y0)),bt::map_unit_to_dn(vec2_type(x1_start,y1_start)));
181  vec2_type p_esa_dn;
182  if(!plain2esa(p_plain_dn,p_esa_dn)) return false;
183 
184  vec2_type q = bt::map_dn_to_unit(p_esa_dn);
185  x1 = q[0];
186  y1 = q[1];
187  return true;
188  }
189 public:
190 // Mutex initialized and destroyed in baseclass.
191  tde4_ldp_radial_deg_8():_r_clip_factor(5.0)
192  { }
194  { }
195  double r_clip_factor() const
196  { return _r_clip_factor; }
197  void r_clip_factor(double f)
198  { _r_clip_factor = f; }
199  bool getModelName(char *name)
200  {
201 #ifdef LDPK_COMPILE_AS_PLUGIN_SDV
202  strcpy(name,"3DE4 Radial - Fisheye, Degree 8 [Plugin]");
203 #else
204  strcpy(name,"3DE4 Radial - Fisheye, Degree 8");
205 #endif
206  return true;
207  }
208  bool getParameterType(const char* identifier,tde4_ldp_ptype& ptype)
209  {
210  typedef base_type bt;
211  int i;
212  if(bt::get_builtin_parameter_type(identifier,ptype)) return true;
213  if(!decypher(identifier,i)) return false;
214  ptype = TDE4_LDP_ADJUSTABLE_DOUBLE;
215  return true;
216  }
217  bool getParameterDefaultValue(const char* identifier,double& v)
218  {
219  typedef base_type bt;
220  int i;
221  if(!decypher(identifier,i)) return false;
222  v = 0.0;
223  return true;
224  }
225  bool getParameterRange(const char* identifier,double& a,double& b)
226  {
227  typedef base_type bt;
228  int i;
229  if(!decypher(identifier,i)) return false;
230  a = -0.5;
231  b = 0.5;
232  return true;
233  }
234  bool getJacobianMatrix(double x0,double y0,double& m00,double& m01,double& m10,double& m11)
235  {
236  typedef base_type bt;
237 // The function we need to derive is a concatenation of a simple radially symmetric
238 // undistort funtion and the equisolid-angle transform. We compute this by Leipnitz's rule.
239 // Exterior derivative:
240  vec2_type p_esa_dn = bt::map_unit_to_dn(vec2_type(x0,y0));
241  vec2_type p_plain_dn;
242  if(!esa2plain(p_esa_dn,p_plain_dn))
243  {
244  m00 = 1;m01 = 0;m10 = 0;m11 = 1;
245  return false;
246  }
247  mat2_type m = _distortion.jacobi(p_plain_dn);
248 // Interior derivative
249  mat2_type e;
250  double f_dn = this->fl_cm() / this->r_fb_cm();
251  double r_esa_dn = norm2(p_esa_dn);
252  double r_esa_div_2f = r_esa_dn / (2.0 * f_dn);
253 // Test (a): make sure argument of arcsine is valid.
254  if(fabs(r_esa_div_2f) > 0.99)
255  {
256  m00 = 1;m01 = 0;m10 = 0;m11 = 1;
257  return false;
258  }
259  double asn = asin(r_esa_div_2f);
260 // Test (b): make sure cos(..) is greater than 0.
261  if(fabs(2.0 * asn) > 0.99 * M_PI / 2.0)
262  {
263  m00 = 1;m01 = 0;m10 = 0;m11 = 1;
264  return false;
265  }
266  double csn = cos(2.0 * asn);
267 // Argument of square root is positive because of test (a).
268  double sqr = sqrt(1.0 - r_esa_div_2f * r_esa_div_2f);
269  if(r_esa_dn > 1e-12)
270  {
271 // The analytic expression is undefined at 0...
272  e = (mat2_type(1) - tensq(p_esa_dn / r_esa_dn)) * (f_dn / r_esa_dn) * tan(2.0 * asn)
273  + (tensq(p_esa_dn / r_esa_dn)) / (csn * csn * sqr);
274  }
275  else
276  {
277 // ...but has well-defined limit
278  e = mat2_type(1);
279  }
280 
281 // Maps between unit and diagnorm coordinates.
282  mat2_type u2d((bt::w_fb_cm() / 2) / bt::r_fb_cm(),0.0,0.0,(bt::h_fb_cm() / 2) / bt::r_fb_cm());
283  mat2_type d2u(bt::r_fb_cm() / (bt::w_fb_cm() / 2),0.0,0.0,bt::r_fb_cm() / (bt::h_fb_cm() / 2));
284  m = d2u * m * e * u2d;
285 // We have to make sure, that the matrix doesn't run berserk in the outer regions
286  if(tr(trans(m) * m) > 100.0)
287  {
288 // Chill.
289  m = mat2_type(0);
290  }
291  m00 = m[0][0];m01 = m[0][1];m10 = m[1][0];m11 = m[1][1];
292  return true;
293  }
294  };
295 
296 template <class VEC2,class MAT2>
298  "Distortion - Degree 2",
299  "Quartic Distortion - Degree 4",
300  "Degree 6",
301  "Degree 8"
302  };
303 
304 #endif
A polynomial radially symmetric model of degree N (even)
mat2d tensq(const vec2d &a)
Tensor (dyadic) product square.
Definition: ldpk_vec2d.h:186
Plugin class for radial distortion. Does not compensate for decentering. Parameters can be calculated...
Definition: tde4_ldp_radial_deg_8.h:14
vec2_type eval(const vec2_type &p) const
Same as method instead of operator.
Definition: ldpk_generic_distortion_base.h:104
bool getJacobianMatrix(double x0, double y0, double &m00, double &m01, double &m10, double &m11)
calculate the Jacobian matrix of the undistort()-Method. Overwrite this, if you know the Jacobian for...
Definition: tde4_ldp_radial_deg_8.h:234
bool getParameterRange(const char *identifier, double &a, double &b)
returns range for adjustable double parameters...
Definition: tde4_ldp_radial_deg_8.h:225
bool getParameterDefaultValue(const char *identifier, double &v)
returns default value for given parameter (maximum length of "char *v": 1000 bytes)......
Definition: tde4_ldp_radial_deg_8.h:217
mat2_type jacobi(const vec2_type &p_dn) const
Analytic version of the Jacobi-matrix, about 2.5 times faster than the base class version which uses ...
Definition: ldpk_generic_radial_distortion.h:59
This class handles the built-in parameter and the lookup table. You may find it useful for your own d...
Definition: ldpk_ldp_builtin.h:31
bool getParameterType(const char *identifier, tde4_ldp_ptype &ptype)
returns type of given parameter... The method should return false, if the parameter addressed by iden...
Definition: tde4_ldp_radial_deg_8.h:208
virtual vec2_type map_inverse(const vec2_type &q) const
Inverse mapping by solving the fixed point equation without providing initial values. Virtual, because the derived class might use some smart data structure for calculating an initial value.
Definition: ldpk_generic_distortion_base.h:122
void set_coeff(int i, double q)
Set coefficient c[i], 0 <= i < N.
Definition: ldpk_generic_radial_distortion.h:38
double get_coeff(int i) const
Get coefficient c[i], 0 <= i < N (i.e. coefficient power r^(2i))
Definition: ldpk_generic_radial_distortion.h:32
bool getModelName(char *name)
returns a name for the model as to show up in the GUI (maximum length of "name": 100 bytes)...
Definition: tde4_ldp_radial_deg_8.h:199