ldpk
ldpk_generic_anamorphic_distortion.h
1 #ifndef ldpk_generic_anamorphic_distortion_sdv
2 #define ldpk_generic_anamorphic_distortion_sdv
3 
6 
8 
9 namespace ldpk
10  {
22  template <class VEC2,class MAT2,int N>
23  class generic_anamorphic_distortion:public ldpk::generic_distortion_base<VEC2,MAT2,(N + 2) * (N + 4) / 4 - 2>
24  {
25  public:
26  typedef generic_distortion_base<VEC2,MAT2,(N + 2) * (N + 4) / 4 - 2> base_type;
27  typedef VEC2 vec2_type;
28  private:
29 // We represent the coefficients by a two-dimensional array.
30 // The upper right triangle including diagonal is used for the model, all others are ignored.
31 // For the generic anamorphic model, we have different values in x- and y- direction.
32  double _cx[(N / 2) + 1][(N / 2) + 1];
33  double _cy[(N / 2) + 1][(N / 2) + 1];
34 // Array for linear index access.
35  double *_c[(N + 2) * (N + 4) / 4 - 2];
36 
37  public:
39  {
40 // Default is the identity.
41  int k = 0;
42  for(int i_phi = 0;i_phi <= N;i_phi += 2)
43  {
44  for(int i_r = 0;i_r <= N;i_r += 2)
45  {
46  cx(i_phi,i_r,0);
47  cy(i_phi,i_r,0);
48  }
49  }
50  _cx[0][0] = 1.0;
51  _cy[0][0] = 1.0;
52 // Linearizing coefficients. The order of loops is important.
53  for(int i_r = 0;i_r <= N;i_r += 2)
54  {
55  for(int i_phi = 0;i_phi <= i_r;i_phi += 2)
56  {
57  if((i_phi != 0) || (i_r != 0))
58  {
59  _c[k++] = &_cx[i_phi >> 1][i_r >> 1];
60  _c[k++] = &_cy[i_phi >> 1][i_r >> 1];
61  }
62  }
63  }
65  {
66  std::cerr << "generic_anamorphic_distortion: bad implementation for N = " << N;
67  std::cerr << ". This needs to be fixed." << std::endl;
68  }
69  }
71  double get_coeff(int i) const
72  {
74  return *_c[i];
75  }
77  void set_coeff(int i,double q)
78  {
80  *_c[i] = q;
81  }
82 
83 // The coefficients of the Generic Polynomial Model fulfill
84 // the following conditions:
85 // - Indices are even
86 // - i_r in [0,N]
87 // - i_r >= i_phi
89  double cx(int i_phi,int i_r) const
90  { return _cx[i_phi >> 1][i_r >> 1]; }
91  void cx(int i_phi,int i_r,double c)
92  { _cx[i_phi >> 1][i_r >> 1] = c; }
94  double cy(int i_phi,int i_r) const
95  { return _cy[i_phi >> 1][i_r >> 1]; }
96  void cy(int i_phi,int i_r,double c)
97  { _cy[i_phi >> 1][i_r >> 1] = c; }
98 
102  vec2_type operator()(const vec2_type& p_dn) const
103  {
104 // Our generic model is based on polar coordinates,
105 // so we represent the point as radius and angle.
106  double r = norm2(p_dn);
107  double phi = atan2(p_dn[1],p_dn[0]);
108  vec2_type q;
109 // We calculate powers of r in advance for better performance.
110  double r_pow[N + 1];
111  r_pow[0] = 1.0;
112  for(int i = 2;i < N + 1;i += 2)
113  {
114  r_pow[i] = (r * r) * r_pow[i - 2];
115  }
116 // Evaluating the polynomial
117  for(int i_phi = 0;i_phi <= N;i_phi += 2)
118  {
119  double cos_i_phi = cos(i_phi * phi);
120  for(int i_r = i_phi;i_r <= N;i_r += 2)
121  {
122 // That is coefficient times cosine times power of r.
123  q[0] += cx(i_phi,i_r) * cos_i_phi * r_pow[i_r];
124  q[1] += cy(i_phi,i_r) * cos_i_phi * r_pow[i_r];
125  }
126  }
127  return vec2_type(p_dn[0] * q[0],p_dn[1] * q[1]);
128  }
129 
134  void derive(double* dg,int n_parameters,const vec2_type& p_dn) const
135  {
136  int size = 2 * n_parameters;
137 // Our generic model is based on polar coordinates,
138 // so we represent the point as radius and angle.
139  double r = norm2(p_dn);
140  double phi = atan2(p_dn[1],p_dn[0]);
141 // We calculate powers of r and cosine-terms in advance for better performance.
142  double r_pow[N + 1];
143  r_pow[0] = 1.0;
144  for(int i = 2;i < N + 1;i += 2)
145  {
146  r_pow[i] = (r * r) * r_pow[i - 2];
147  }
148  double cos_phi[N + 1];
149  for(int i_phi = 0;i_phi < N + 1;i_phi += 2)
150  {
151  cos_phi[i_phi] = cos(i_phi * phi);
152  }
153 
154 // The order of coefficients is: 1. powers of r and 2. angular frequencies.
155  int k = 0;
156  for(int i_r = 0;i_r <= N;i_r += 2)
157  {
158  for(int i_phi = 0;i_phi <= i_r;i_phi += 2)
159  {
160 // Omit (0,0) which is a constant
161  if(i_r || i_phi)
162  {
163 // Since the model is linear in each coefficient, derivatives are constants.
164  double cr = cos_phi[i_phi] * r_pow[i_r];
165  dg[k++] = p_dn[0] * cr;
166  dg[k++] = 0;
167 // We calculate at most the first n derivatives, where n is the size of dg.
168  if(k == size) return;
169 
170  dg[k++] = 0;
171  dg[k++] = p_dn[1] * cr;
172 // We calculate at most the first n derivatives, where n is the size of dg.
173  if(k == size) return;
174  }
175  }
176  }
177  }
178  std::ostream& out(std::ostream& cout) const
179  {
180  int p = cout.precision();
181  cout.precision(5);
182  for(int i_r = 0;i_r <= N;i_r += 2)
183  {
184 // One row Cx
185  if(i_r) cout << " Cx(i," << i_r << "): ";
186  for(int i_phi = 0;i_phi <= i_r;i_phi += 2)
187  {
188  if(i_r || i_phi)
189  {
190  cout.width(8);
191  cout << std::right << std::fixed << cx(i_phi,i_r) << " ";
192  }
193  }
194  if(i_r) cout << "\n";
195 // One row Cy
196  if(i_r) cout << " Cy(i," << i_r << "): ";
197  for(int i_phi = 0;i_phi <= i_r;i_phi += 2)
198  {
199  if(i_r || i_phi)
200  {
201  cout.width(8);
202  cout << std::right << std::fixed << cy(i_phi,i_r) << " ";
203  }
204  }
205  if(i_r) cout << "\n";
206  }
207  cout.precision(p);
208  return cout;
209  }
210  };
211 
214  template <class VEC2,class MAT2>
215  class generic_anamorphic_distortion<VEC2,MAT2,4>:public ldpk::generic_distortion_base<VEC2,MAT2,(4 + 2) * (4 + 4) / 4 - 2>
216  {
217  public:
218  typedef generic_distortion_base<VEC2,MAT2,(4 + 2) * (4 + 4) / 4 - 2> base_type;
219  typedef VEC2 vec2_type;
220  typedef MAT2 mat2_type;
221  private:
222 // Model parameters
223  double _cx02,_cx22,_cx04,_cx24,_cx44;
224  double _cy02,_cy22,_cy04,_cy24,_cy44;
225 // Array for linear index access.
226  double *_c[10];
227 // Coefficients, as used in evaluating functions. Calculated in prepare().
228  double _cx_for_x2,_cx_for_y2,_cx_for_x4,_cx_for_x2_y2,_cx_for_y4;
229  double _cy_for_x2,_cy_for_y2,_cy_for_x4,_cy_for_x2_y2,_cy_for_y4;
230 
231  public:
233  {
235  _c[0] = &_cx02;_c[1] = &_cy02;
236  _c[2] = &_cx22;_c[3] = &_cy22;
237  _c[4] = &_cx04;_c[5] = &_cy04;
238  _c[6] = &_cx24;_c[7] = &_cy24;
239  _c[8] = &_cx44;_c[9] = &_cy44;
240  for(int i = 0;i < 10;++i)
241  { *_c[i] = 0; }
242  }
244  double get_coeff(int i) const
245  {
247  return *_c[i];
248  }
250  void set_coeff(int i,double q)
251  {
253  *_c[i] = q;
254  }
256  void prepare()
257  {
258  _cx_for_x2 = _cx02 + _cx22;
259  _cx_for_y2 = _cx02 - _cx22;
260 
261  _cx_for_x4 = _cx04 + _cx24 + _cx44;
262  _cx_for_x2_y2 = 2.0 * _cx04 - 6.0 * _cx44;
263  _cx_for_y4 = _cx04 - _cx24 + _cx44;
264 
265  _cy_for_x2 = _cy02 + _cy22;
266  _cy_for_y2 = _cy02 - _cy22;
267 
268  _cy_for_x4 = _cy04 + _cy24 + _cy44;
269  _cy_for_x2_y2 = 2.0 * _cy04 - 6.0 * _cy44;
270  _cy_for_y4 = _cy04 - _cy24 + _cy44;
271  }
275  vec2_type operator()(const vec2_type& p_dn) const
276  {
277  double x = p_dn[0],x2 = x * x,x4 = x2 * x2;
278  double y = p_dn[1],y2 = y * y,y4 = y2 * y2;
279  double xq = x * (1.0
280  + x2 * _cx_for_x2 + y2 * _cx_for_y2
281  + x4 * _cx_for_x4 + x2 * y2 * _cx_for_x2_y2 + y4 * _cx_for_y4);
282  double yq = y * (1.0
283  + x2 * _cy_for_x2 + y2 * _cy_for_y2
284  + x4 * _cy_for_x4 + x2 * y2 * _cy_for_x2_y2 + y4 * _cy_for_y4);
285  return vec2_type(xq,yq);
286  }
288  mat2_type jacobi(const vec2_type& p_dn) const
289  {
290  double x = p_dn[0],x2 = x * x,x3 = x2 * x,x4 = x2 * x2;
291  double y = p_dn[1],y2 = y * y,y3 = y2 * y,y4 = y2 * y2;
292  mat2_type m;
293  m[0][0] = 1.0 + x2 * 3.0 * _cx_for_x2 + y2 * _cx_for_y2
294  + x4 * 5.0 * _cx_for_x4 + x2 * y2 * 3.0 * _cx_for_x2_y2 + y4 * _cx_for_y4;
295  m[1][1] = 1.0 + y2 * 3.0 * _cy_for_y2 + x2 * _cy_for_x2
296  + y4 * 5.0 * _cy_for_y4 + x2 * y2 * 3.0 * _cy_for_x2_y2 + x4 * _cy_for_x4;
297  m[0][1] = x * y * 2.0 * _cx_for_y2
298  + x * y3 * 4.0 * _cx_for_y4 + x3 * y * 2.0 * _cx_for_x2_y2;
299  m[1][0] = x * y * 2.0 * _cy_for_x2
300  + x3 * y * 4.0 * _cy_for_x4 + x * y3 * 2.0 * _cy_for_x2_y2;
301  return m;
302  }
303  vec2_type twist(const vec2_type& p_dn) const
304  {
305  double x = p_dn[0],x2 = x * x,x3 = x2 * x;
306  double y = p_dn[1],y2 = y * y,y3 = y2 * y;
307  vec2_type t;
308  t[0] = y * 2.0 * _cx_for_y2
309  + x2 * y * 6.0 * _cx_for_x2_y2 + y3 * 4.0 * _cx_for_y4;
310  t[1] = x * 2.0 * _cy_for_x2
311  + x * y2 * 6.0 * _cy_for_x2_y2 + x3 * 4.0 * _cy_for_x4;
312  return t;
313  }
314  };
317  template <class VEC2,class MAT2>
318  class generic_anamorphic_distortion<VEC2,MAT2,6>:public ldpk::generic_distortion_base<VEC2,MAT2,(6 + 2) * (6 + 4) / 4 - 2>
319  {
320  public:
321  typedef generic_distortion_base<VEC2,MAT2,(6 + 2) * (6 + 4) / 4 - 2> base_type;
322  typedef VEC2 vec2_type;
323  typedef MAT2 mat2_type;
324  private:
325 // Model parameters
326  double _cx02,_cx22,_cx04,_cx24,_cx44,_cx06,_cx26,_cx46,_cx66;
327  double _cy02,_cy22,_cy04,_cy24,_cy44,_cy06,_cy26,_cy46,_cy66;
328 // Array for linear index access.
329  double *_c[18];
330 // Coefficients, as used in evaluating functions. Calculated in prepare().
331  double _cx_for_x2,_cx_for_y2,_cx_for_x4,_cx_for_x2_y2,_cx_for_y4,_cx_for_x6,_cx_for_x4_y2,_cx_for_x2_y4,_cx_for_y6;
332  double _cy_for_x2,_cy_for_y2,_cy_for_x4,_cy_for_x2_y2,_cy_for_y4,_cy_for_x6,_cy_for_x4_y2,_cy_for_x2_y4,_cy_for_y6;
333 
334  public:
336  {
338  _c[ 0] = &_cx02;_c[ 1] = &_cy02;
339  _c[ 2] = &_cx22;_c[ 3] = &_cy22;
340  _c[ 4] = &_cx04;_c[ 5] = &_cy04;
341  _c[ 6] = &_cx24;_c[ 7] = &_cy24;
342  _c[ 8] = &_cx44;_c[ 9] = &_cy44;
343  _c[10] = &_cx06;_c[11] = &_cy06;
344  _c[12] = &_cx26;_c[13] = &_cy26;
345  _c[14] = &_cx46;_c[15] = &_cy46;
346  _c[16] = &_cx66;_c[17] = &_cy66;
347  for(int i = 0;i < 18;++i)
348  { *_c[i] = 0; }
349  }
351  double get_coeff(int i) const
352  {
354  return *_c[i];
355  }
357  void set_coeff(int i,double q)
358  {
360  *_c[i] = q;
361  }
363  void prepare()
364  {
365  _cx_for_x2 = _cx02 + _cx22;
366  _cx_for_y2 = _cx02 - _cx22;
367 
368  _cx_for_x4 = _cx04 + _cx24 + _cx44;
369  _cx_for_x2_y2 = 2.0 * _cx04 - 6.0 * _cx44;
370  _cx_for_y4 = _cx04 - _cx24 + _cx44;
371 
372  _cx_for_x6 = _cx06 + _cx26 + _cx46 + _cx66;
373  _cx_for_x4_y2 = 3.0 * _cx06 + _cx26 - 5.0 * _cx46 - 15.0 * _cx66;
374  _cx_for_x2_y4 = 3.0 * _cx06 - _cx26 - 5.0 * _cx46 + 15.0 * _cx66;
375  _cx_for_y6 = _cx06 - _cx26 + _cx46 - _cx66;
376 
377  _cy_for_x2 = _cy02 + _cy22;
378  _cy_for_y2 = _cy02 - _cy22;
379 
380  _cy_for_x4 = _cy04 + _cy24 + _cy44;
381  _cy_for_x2_y2 = 2.0 * _cy04 - 6.0 * _cy44;
382  _cy_for_y4 = _cy04 - _cy24 + _cy44;
383 
384  _cy_for_x6 = _cy06 + _cy26 + _cy46 + _cy66;
385  _cy_for_x4_y2 = 3.0 * _cy06 + _cy26 - 5.0 * _cy46 - 15.0 * _cy66;
386  _cy_for_x2_y4 = 3.0 * _cy06 - _cy26 - 5.0 * _cy46 + 15.0 * _cy66;
387  _cy_for_y6 = _cy06 - _cy26 + _cy46 - _cy66;
388  }
392  vec2_type operator()(const vec2_type& p_dn) const
393  {
394  double x = p_dn[0],x2 = x * x,x4 = x2 * x2,x6 = x4 * x2;
395  double y = p_dn[1],y2 = y * y,y4 = y2 * y2,y6 = y4 * y2;
396  double xq = x * (1.0
397  + x2 * _cx_for_x2 + y2 * _cx_for_y2
398  + x4 * _cx_for_x4 + x2 * y2 * _cx_for_x2_y2 + y4 * _cx_for_y4
399  + x6 * _cx_for_x6 + x4 * y2 * _cx_for_x4_y2 + x2 * y4 * _cx_for_x2_y4 + y6 * _cx_for_y6);
400  double yq = y * (1.0
401  + x2 * _cy_for_x2 + y2 * _cy_for_y2
402  + x4 * _cy_for_x4 + x2 * y2 * _cy_for_x2_y2 + y4 * _cy_for_y4
403  + x6 * _cy_for_x6 + x4 * y2 * _cy_for_x4_y2 + x2 * y4 * _cy_for_x2_y4 + y6 * _cy_for_y6);
404  return vec2_type(xq,yq);
405  }
410  mat2_type jacobi(const vec2_type& p_dn) const
411  {
412  double x = p_dn[0],x2 = x * x,x3 = x2 * x,x4 = x2 * x2,x5 = x3 * x2,x6 = x4 * x2;
413  double y = p_dn[1],y2 = y * y,y3 = y2 * y,y4 = y2 * y2,y5 = y3 * y2,y6 = y4 * y2;
414  mat2_type m;
415  m[0][0] = 1.0 + x2 * 3.0 * _cx_for_x2 + y2 * _cx_for_y2
416  + x4 * 5.0 * _cx_for_x4 + x2 * y2 * 3.0 * _cx_for_x2_y2 + y4 * _cx_for_y4
417  + x6 * 7.0 * _cx_for_x6 + x4 * y2 * 5.0 * _cx_for_x4_y2 + x2 * y4 * 3.0 * _cx_for_x2_y4 + y6 * _cx_for_y6;
418  m[1][1] = 1.0 + y2 * 3.0 * _cy_for_y2 + x2 * _cy_for_x2
419  + y4 * 5.0 * _cy_for_y4 + x2 * y2 * 3.0 * _cy_for_x2_y2 + x4 * _cy_for_x4
420  + x6 * _cy_for_x6 + x4 * y2 * 3.0 * _cy_for_x4_y2 + x2 * y4 * 5.0 * _cy_for_x2_y4 + y6 * 7.0 * _cy_for_y6;
421  m[0][1] = x * y * 2.0 * _cx_for_y2
422  + x * y3 * 4.0 * _cx_for_y4 + x3 * y * 2.0 * _cx_for_x2_y2
423  + x5 * y * 2.0 * _cx_for_x4_y2 + x3 * y3 * 4.0 * _cx_for_x2_y4 + x * y5 * 6.0 * _cx_for_y6;
424  m[1][0] = x * y * 2.0 * _cy_for_x2
425  + x3 * y * 4.0 * _cy_for_x4 + x * y3 * 2.0 * _cy_for_x2_y2
426  + x5 * y * 6.0 * _cy_for_x6 + x3 * y3 * 4.0 * _cy_for_x4_y2 + x * y5 * 2.0 * _cy_for_x2_y4;
427  return m;
428  }
429  vec2_type twist(const vec2_type& p_dn) const
430  {
431  double x = p_dn[0],x2 = x * x,x3 = x2 * x,x4 = x2 * x2,x5 = x3 * x2;
432  double y = p_dn[1],y2 = y * y,y3 = y2 * y,y4 = y2 * y2,y5 = y3 * y2;
433  vec2_type t;
434  t[0] = y * 2.0 * _cx_for_y2
435  + x2 * y * 6.0 * _cx_for_x2_y2 + y3 * 4.0 * _cx_for_y4
436  + x4 * y * 10.0 * _cx_for_x4_y2 + x2 * y3 * 12.0 * _cx_for_x2_y4 + y5 * 6.0 * _cx_for_y6;
437  t[1] = x * 2.0 * _cy_for_x2
438  + x * y2 * 6.0 * _cy_for_x2_y2 + x3 * 4.0 * _cy_for_x4
439  + x5 * 6.0 * _cy_for_x6 + x3 * y2 * 12.0 * _cy_for_x4_y2 + x * y4 * 10.0 * _cy_for_x2_y4;
440  return t;
441  }
442  };
443  }
444 
445 #endif
generic_anamorphic_distortion()
Definition: ldpk_generic_anamorphic_distortion.h:335
int get_num_parameters() const
Number of parameters, that is N.
Definition: ldpk_generic_distortion_base.h:49
generic_anamorphic_distortion()
Definition: ldpk_generic_anamorphic_distortion.h:232
Base class for a distortion model with N parameters. You may find it useful to derive your own distor...
Definition: ldpk_generic_distortion_base.h:20
double get_coeff(int i) const
Get coefficient as demanded by base class.
Definition: ldpk_generic_anamorphic_distortion.h:351
void set_coeff(int i, double q)
Set coefficient as demanded by base class.
Definition: ldpk_generic_anamorphic_distortion.h:357
double get_coeff(int i) const
Get coefficient as demanded by base class.
Definition: ldpk_generic_anamorphic_distortion.h:244
void check_range(int i) const
A derived class may check if the index is valid.
Definition: ldpk_generic_distortion_base.h:36
The namespace of (most of the) things related to the Lens Distortion Plugin Kit.
Definition: ldpk.h:19
void set_coeff(int i, double q)
Set coefficient as demanded by base class.
Definition: ldpk_generic_anamorphic_distortion.h:77
Base class for distortion models.
std::ostream & out(std::ostream &cout) const
The derived class implements a method for printing values inside 3DE4&#39;s matrix tool dialog...
Definition: ldpk_generic_anamorphic_distortion.h:178
double cx(int i_phi, int i_r) const
x-direction
Definition: ldpk_generic_anamorphic_distortion.h:89
mat2_type jacobi(const vec2_type &p_dn) const
Jacobi-Matrix.
Definition: ldpk_generic_anamorphic_distortion.h:288
void prepare()
To be invoked by initializeParameters().
Definition: ldpk_generic_anamorphic_distortion.h:256
double cy(int i_phi, int i_r) const
y-direction
Definition: ldpk_generic_anamorphic_distortion.h:94
mat2_type jacobi(const vec2_type &p_dn) const
Jacobi-Matrix, tested against difference quotient method in base class. We calculated the Jacobian of...
Definition: ldpk_generic_anamorphic_distortion.h:410
vec2_type operator()(const vec2_type &p_dn) const
As usual, we define the distortion mapping in diagonally normalized coordinates, (hence the suffix _d...
Definition: ldpk_generic_anamorphic_distortion.h:392
void set_coeff(int i, double q)
Set coefficient as demanded by base class.
Definition: ldpk_generic_anamorphic_distortion.h:250
vec2_type operator()(const vec2_type &p_dn) const
As usual, we define the distortion mapping in diagonally normalized coordinates, (hence the suffix _d...
Definition: ldpk_generic_anamorphic_distortion.h:275
void prepare()
To be invoked by initializeParameters().
Definition: ldpk_generic_anamorphic_distortion.h:363
double get_coeff(int i) const
Get coefficient as demanded by base class.
Definition: ldpk_generic_anamorphic_distortion.h:71
void derive(double *dg, int n_parameters, const vec2_type &p_dn) const
Derivative wrt distortion coefficients. For performance reasons we calculate all derivatives simultan...
Definition: ldpk_generic_anamorphic_distortion.h:134
A polynomial distortion model for anamorphic distortion without decntering. N is the degree of the po...
Definition: ldpk_generic_anamorphic_distortion.h:23
vec2_type operator()(const vec2_type &p_dn) const
As usual, we define the distortion mapping in diagonally normalized coordinates, (hence the suffix _d...
Definition: ldpk_generic_anamorphic_distortion.h:102