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