zsig 1.0.0
|
00001 00008 #ifndef ZSIG_ZPOLBASIST_HH 00009 #define ZSIG_ZPOLBASIST_HH 00010 00011 //== INCLUDES ================================================================= 00012 00013 #include <cmath> 00014 #include <vector> 00015 #include <complex> 00016 #include <iostream> 00017 00018 //== NAMESPACES =============================================================== 00019 00020 namespace zsig { 00021 00022 //=== IMPLEMENTATION ========================================================== 00023 00032 template< class T > 00033 T fac( const int& _n ) { 00034 T f = (T)1; 00035 for (int i = 2; i <= _n; ++i) f *= i; 00036 return f; 00037 } 00038 00060 template< class T > 00061 T compute_R( const unsigned& _p, 00062 const int& _q, 00063 const T& _r ) { 00064 00065 int a, b, c, d; 00066 T sum = (T)0; 00067 00068 for (int k = (_q<0?-_q:_q); k <= _p; k += 2) { 00069 00070 a = (_p - k) / 2; b = (_p + k) / 2; 00071 c = (k - _q) / 2; d = (k + _q) / 2; 00072 00073 sum += ( ( pow( (T)-1.0, (T)a ) * fac<T>(b) ) / 00074 ( fac<T>(a) * fac<T>(c) * fac<T>(d) ) ) * pow( _r, (T)k ); 00075 00076 } 00077 00078 return sum; 00079 00080 } 00081 00101 template< class T > 00102 std::complex< T > compute_V( const unsigned& _p, 00103 const int& _q, 00104 const T& _r, 00105 const T& _t ) { 00106 00107 return std::polar( compute_R<T>( _p, _q, _r), _q * _t ); 00108 00109 } 00110 00111 //== CLASS DEFINITION ========================================================= 00112 00162 template< unsigned Order = 8, class T = long double > 00163 class ZernikePolynomialsBasisT { 00164 00165 public: 00166 00167 typedef ZernikePolynomialsBasisT< Order, T > zpolbasis_type; 00168 typedef std::complex< T > value_type; 00169 typedef std::vector< value_type > radial_polynomial; 00170 00177 ZernikePolynomialsBasisT() : pol(Order+1) { 00178 for (unsigned p = 0; p <= Order; ++p) pol[p].resize( 1+p/2 ); 00179 } 00180 00211 void project( const T **_fxy, 00212 const zpolbasis_type **_zpb, 00213 const unsigned int& _szx, 00214 const unsigned int& _szy ) { 00215 T x, y, r; // (x, y) cartesian coordinates and radius r 00216 for (unsigned p = 0; p <= Order; ++p) { 00217 T p1pi = (p + 1) / M_PI; // frac outside summation 00218 for (int qi = 0; qi <= p/2; ++qi) { 00219 pol[p][qi] = value_type(); 00220 for (int gx = 0; gx < _szx; ++gx) { 00221 x = ( (T)2 * gx + (T)1 ) / (T)_szx - (T)1; 00222 for (int gy = 0; gy < _szy; ++gy) { 00223 y = ( (T)2 * gy + (T)1 ) / (T)_szy - (T)1; 00224 r = (T)sqrt( x*x + y*y ); 00225 if( r > (T)1 ) continue; // outside unit circle is zero 00226 pol[p][qi] += std::conj( _zpb[gx][gy][p][qi] ) * _fxy[gx][gy]; 00227 } // gy 00228 } // gx 00229 pol[p][qi] *= p1pi; 00230 } // qi 00231 } // p 00232 } 00233 00241 void project( const T **_fxy, 00242 zpolbasis_type **_zpb, 00243 const unsigned int& _szx, 00244 const unsigned int& _szy ) { 00245 project( _fxy, (const zpolbasis_type **)_zpb, _szx, _szy ); 00246 } 00247 00255 void project( T **_fxy, 00256 const zpolbasis_type **_zpb, 00257 const unsigned int& _szx, 00258 const unsigned int& _szy ) { 00259 project( (const T **)_fxy, (const zpolbasis_type **)_zpb, _szx, _szy ); 00260 } 00261 00269 void project( T **_fxy, 00270 zpolbasis_type **_zpb, 00271 const unsigned int& _szx, 00272 const unsigned int& _szy ) { 00273 project( (const T **)_fxy, (const zpolbasis_type **)_zpb, _szx, _szy ); 00274 } 00275 00287 void project( const T **_fxy, 00288 const unsigned int& _szx, 00289 const unsigned int& _szy ) { 00290 T x, y, r, t; // (x, y) cartesian and (r, t) polar coordinates 00291 for (unsigned p = 0; p <= Order; ++p) { 00292 T p1pi = (p + 1) / M_PI; // frac outside summation 00293 int qi = 0; // q index: q[0, 2, 4] -> qi[0, 1, 2] 00294 for (int q = p % 2; q <= p; q += 2, qi++) { 00295 pol[p][qi] = value_type(); 00296 for (int gx = 0; gx < _szx; ++gx) { 00297 x = ( (T)2 * gx + (T)1 ) / (T)_szx - (T)1; 00298 for (int gy = 0; gy < _szy; ++gy) { 00299 y = ( (T)2 * gy + (T)1 ) / (T)_szy - (T)1; 00300 r = (T)sqrt( x*x + y*y ); 00301 if( r > (T)1 ) continue; // outside unit circle is zero 00302 t = (T)atan2( y, x ); 00303 pol[p][qi] += std::conj( compute_V(p, q, r, t) ) * _fxy[gx][gy]; 00304 } // gy 00305 } // gx 00306 pol[p][qi] *= p1pi; 00307 } // q 00308 } // p 00309 } 00310 00317 void project( T **_fxy, 00318 const unsigned int& _szx, 00319 const unsigned int& _szy ) { 00320 project( (const T **)_fxy, _szx, _szy ); 00321 } 00322 00336 void reconstruct( T **_fxy, 00337 const zpolbasis_type **_zpb, 00338 const unsigned int& _szx, 00339 const unsigned int& _szy ) const { 00340 value_type rv; // reconstructed value 00341 for (int gx = 0; gx < _szx; ++gx) { 00342 for (int gy = 0; gy < _szy; ++gy) { 00343 rv = value_type(); 00344 for (unsigned p = 0; p <= Order; ++p) { 00345 for (int qi = 0; qi <= p/2; ++qi) { 00346 rv += pol[p][qi] * _zpb[gx][gy][p][qi]; // using +q 00347 if( p % 2 != 0 or qi != 0 ) // for p even and q zero z does not repeat itself 00348 rv += std::conj( pol[p][qi] ) * std::conj( _zpb[gx][gy][p][qi] ); // using -q 00349 } // qi 00350 } // p 00351 _fxy[gx][gy] = rv.real(); 00352 } // gy 00353 } // gx 00354 } 00355 00363 void reconstruct( T **_fxy, 00364 zpolbasis_type **_zpb, 00365 const unsigned int& _szx, 00366 const unsigned int& _szy ) const { 00367 reconstruct( _fxy, (const zpolbasis_type **)_zpb, _szx, _szy ); 00368 } 00369 00380 void reconstruct( T **_fxy, 00381 const unsigned int& _szx, 00382 const unsigned int& _szy ) const { 00383 T x, y, r, t; // (x, y) cartesian and (r, t) polar coordinates 00384 value_type rv, zpV; // reconstructed value and Zernike Polynomial V 00385 for (int gx = 0; gx < _szx; ++gx) { 00386 x = ( (T)2 * gx + (T)1 ) / (T)_szx - (T)1; 00387 for (int gy = 0; gy < _szy; ++gy) { 00388 y = ( (T)2 * gy + (T)1 ) / (T)_szy - (T)1; 00389 r = (T)sqrt( x*x + y*y ); 00390 rv = value_type(); 00391 if( r <= (T)1 ) { // reconstruct inside unit circle only 00392 for (unsigned p = 0; p <= Order; ++p) { 00393 int qi = 0; // q index: q[0, 2, 4] -> qi[0, 1, 2] 00394 for (int q = p % 2; q <= p; q += 2, qi++) { 00395 t = (T)atan2( y, x ); 00396 zpV = compute_V(p, q, r, t); 00397 rv += pol[p][qi] * zpV; // using +q 00398 if( p % 2 != 0 or qi != 0 ) // for p even and q zero z does not repeat itself 00399 rv += std::conj( pol[p][qi] ) * std::conj( zpV ); // using -q 00400 } // q 00401 } // p 00402 } // if 00403 _fxy[gx][gy] = rv.real(); 00404 } // gy 00405 } // gx 00406 } 00407 00419 T compare( const zpolbasis_type& _zp ) const { 00420 T dist = (T)0; // distance 00421 T modz[2]; // modulus of z 00422 for (unsigned p = 0; p <= Order; ++p) { 00423 for (unsigned qi = 0; qi <= p/2; ++qi) { 00424 modz[0] = std::abs( pol[p][qi] ); 00425 modz[1] = std::abs( _zp[p][qi] ); 00426 dist += (modz[0] - modz[1] ) * (modz[0] - modz[1] ); 00427 } // qi 00428 } // p 00429 return sqrt( dist ); 00430 } 00431 00437 radial_polynomial& operator[] ( const unsigned& _p ) { return this->pol[_p]; } 00438 00444 const radial_polynomial& operator[] ( const unsigned& _p ) const { return this->pol[_p]; } 00445 00452 friend std::ostream& operator << ( std::ostream& _out, 00453 const zpolbasis_type& _z ) { 00454 for (unsigned p = 0; p <= Order; ++p) { 00455 _out << _z[p][0]; 00456 for (unsigned qi = 1; qi <= p/2; ++qi) 00457 _out << " " << _z[p][qi]; 00458 if( p < Order ) _out << "\n"; 00459 } 00460 return _out; 00461 } 00462 00469 friend std::istream& operator >> ( std::istream& _in, 00470 zpolbasis_type& _z ) { 00471 for (unsigned p = 0; p <= Order; ++p) 00472 for (unsigned qi = 0; qi <= p/2; ++qi) 00473 _in >> _z[p][qi]; 00474 return _in; 00475 } 00476 00477 private: 00478 00479 std::vector< radial_polynomial > pol; 00480 00481 }; 00490 //=== IMPLEMENTATION ========================================================== 00491 00523 template< unsigned Order, class T > 00524 void compute_basis( ZernikePolynomialsBasisT< Order, T > **_zpb, 00525 const unsigned int& _szx, 00526 const unsigned int& _szy ) { 00527 00528 T x, y, r, t; // (x, y) cartesian and (r, t) polar coordinates 00529 00530 for (unsigned gx = 0; gx < _szx; ++gx) { 00531 00532 x = ( (T)2 * gx + (T)1 ) / (T)_szx - (T)1; 00533 00534 for (unsigned gy = 0; gy < _szy; ++gy) { 00535 00536 y = ( (T)2 * gy + (T)1 ) / (T)_szy - (T)1; 00537 00538 r = (T)sqrt( x*x + y*y ); 00539 if( r > (T)1 ) continue; // outside unit circle is zero 00540 00541 t = (T)atan2( y, x ); 00542 00543 for (int p = 0; p <= Order; ++p) { 00544 00545 int qi = 0; // q index: q[0, 2, 4] -> qi[0, 1, 2] 00546 00547 for (int q = p % 2; q <= p; q += 2, qi++) { 00548 00549 _zpb[gx][gy][p][qi] = compute_V(p, q, r, t); 00550 00551 } // q 00552 00553 } // p 00554 00555 } // gy 00556 00557 } // gx 00558 00559 } 00568 //============================================================================= 00569 } // namespace zsig 00570 //============================================================================= 00571 #endif // ZSIG_ZPOLBASIST_HH 00572 //=============================================================================