LCOV - code coverage report
Current view: top level - math/func - gaussian.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 8 8
Test Date: 2026-02-19 16:58:26 Functions: 100.0 % 2 2

            Line data    Source code
       1              : /** \file gaussian.hpp
       2              :  * \author Jared R. Males
       3              :  * \brief Declarations for utilities related to the Gaussian function.
       4              :  * \ingroup gen_math_files
       5              :  *
       6              :  */
       7              : 
       8              : //***********************************************************************//
       9              : // Copyright 2015, 2016, 2017, 2018, 2019, 2020 Jared R. Males (jaredmales@gmail.com)
      10              : //
      11              : // This file is part of mxlib.
      12              : //
      13              : // mxlib is free software: you can redistribute it and/or modify
      14              : // it under the terms of the GNU General Public License as published by
      15              : // the Free Software Foundation, either version 3 of the License, or
      16              : // (at your option) any later version.
      17              : //
      18              : // mxlib is distributed in the hope that it will be useful,
      19              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      20              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21              : // GNU General Public License for more details.
      22              : //
      23              : // You should have received a copy of the GNU General Public License
      24              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      25              : //***********************************************************************//
      26              : 
      27              : #ifndef gaussian_hpp
      28              : #define gaussian_hpp
      29              : 
      30              : #include <cmath>
      31              : 
      32              : namespace mx
      33              : {
      34              : namespace math
      35              : {
      36              : namespace func
      37              : {
      38              : 
      39              : /// Constant to convert between the Gaussian width parameter and FWHM
      40              : /** Used for
      41              :  *
      42              :  * \f$ FWHM = 2\sqrt{2\log2}\sigma \f$
      43              :  *
      44              :  * This was calculated in long double precision.
      45              :  *
      46              :  * \ingroup gen_math_gaussians
      47              :  */
      48              : template <typename floatT>
      49              : constexpr floatT twosqrt2log2()
      50              : {
      51              :     return static_cast<floatT>( 2.3548200450309493820231386529193992754947713787716 );
      52              : }
      53              : 
      54              : /// Convert from FWHM to the Gaussian width parameter
      55              : /** Performs the conversion:
      56              :  *
      57              :  * \f$ \sigma = 2\sqrt{2\log2}FWHM \f$
      58              :  *
      59              :  * \returns the converted value of the Gaussian width parameter
      60              :  *
      61              :  * \ingroup gen_math_gaussians
      62              :  */
      63              : template <typename floatT>
      64              : floatT fwhm2sigma( floatT fw /**< [in] the full-width at half maximum */ )
      65              : {
      66              :     return fw / twosqrt2log2<floatT>();
      67              : }
      68              : 
      69              : /// Convert from Gaussian width parameter to FWHM
      70              : /** Performs the conversion:
      71              :  *
      72              :  * \f$ FWHM = 2\sqrt{2\log2}\sigma \f$
      73              :  *
      74              :  * \returns the converted value of the full-width at half maximum
      75              :  *
      76              :  * \ingroup gen_math_gaussians
      77              :  */
      78              : template <typename floatT>
      79              : floatT sigma2fwhm( floatT sig /**< [in] the Gaussian width parameter */ )
      80              : {
      81              :     return sig * twosqrt2log2<floatT>();
      82              : }
      83              : 
      84              : /// Find value at position (x) of the 1D arbitrarily-centered symmetric Gaussian
      85              : /**
      86              :  * Computes:
      87              :  * \f$ G(x) = G_0 + G\exp[-(0.5/\sigma^2)((x-x_0)^2)]\f$
      88              :  *
      89              :  *
      90              :  * \returns the value of the 1D arbitrarily-centered symmetric Gaussian at (x)
      91              :  *
      92              :  * \tparam realT is the type to use for arithmetic
      93              :  *
      94              :  * \ingroup gen_math_gaussians
      95              :  *
      96              :  *
      97              :  */
      98              : template <typename realT>
      99              : realT gaussian( const realT x,    ///< [in] is the x-position at which to evaluate the Gaussian
     100              :                 const realT G0,   ///< [in] is the constant to add to the Gaussian
     101              :                 const realT G,    ///< [in] is the scaling factor (peak height = G-G0)
     102              :                 const realT x0,   ///< [in] is the x-coordinate of the center
     103              :                 const realT sigma ///< [in] is the width of the Gaussian.
     104              : )
     105              : {
     106              :     return G0 + G * exp( -( static_cast<realT>( 0.5 ) / ( sigma * sigma ) * ( ( ( x - x0 ) * ( x - x0 ) ) ) ) );
     107              : }
     108              : 
     109              : /// Find value at position (x,y) of the 2D arbitrarily-centered symmetric Gaussian
     110              : /**
     111              :   * Computes:
     112              :   * \f[
     113              :     f(x,y) = G_0 + G \exp[-(0.5/\sigma^2)((x-x_0)^2+(y-y_0)^2)]
     114              :   * \f]
     115              :   *
     116              :   * \returns the value of the 2D arbitrarily-centered symmetric Gaussian at (x,y)
     117              :   *
     118              :   * \tparam realT is the type to use for arithmetic
     119              :   *
     120              :   * \ingroup gen_math_gaussians
     121              :   *
     122              :   * \test Scenario: Verify direction and accuracy of various image shifts \ref tests_improc_imageTransforms_imageShift
     123              :   "[test doc]"
     124              :   *
     125              :   */
     126              : template <typename realT>
     127       566796 : realT gaussian2D( const realT x,    ///< [in] the x-position at which to evaluate the Gaussian
     128              :                   const realT y,    ///< [in] the y-positoin at which to evaluate the Gaussian
     129              :                   const realT G0,   ///< [in] the constant to add to the Gaussian
     130              :                   const realT G,    ///< [in] the scaling factor (peak height is  G-G0)
     131              :                   const realT x0,   ///< [in] the x-coordinate of the center
     132              :                   const realT y0,   ///< [in] the y-coordinate of the center
     133              :                   const realT sigma ///< [in] the width of the Gaussian.
     134              : )
     135              : {
     136              :     return G0 +
     137       566796 :            G * std::exp( -( 0.5 / ( sigma * sigma ) * ( ( ( x - x0 ) * ( x - x0 ) ) + ( ( y - y0 ) * ( y - y0 ) ) ) ) );
     138              : }
     139              : 
     140              : /// Fill in an array with the 2D arbitrarily-centered symmetric Gaussian
     141              : /**
     142              :  * At each pixel (x,y) of the array this computes:
     143              :  *
     144              :  * \f$ f(x,y) = G_0 + G\exp[-(0.5/\sigma^2)((x-x_0)^2+(y-y_0)^2)] \f$
     145              :  *
     146              :  * \tparam realT is the type to use for arithmetic
     147              :  *
     148              :  * \ingroup gen_math_gaussians
     149              :  */
     150              : template <typename realT>
     151           33 : void gaussian2D( realT *arr,       ///< [out] is the allocated array to fill in
     152              :                  size_t nx,        ///< [in] is the size of the x dimension of the array
     153              :                  size_t ny,        ///< [in] is the size of the y dimension of the array
     154              :                  const realT G0,   ///< [in] is the constant to add to the Gaussian
     155              :                  const realT G,    ///< [in] is the scaling factor (peak height = G-G0)
     156              :                  const realT x0,   ///< [in] is the x-coordinate of the center
     157              :                  const realT y0,   ///< [in] is the y-coordinate of the center
     158              :                  const realT sigma ///< [in] is the third rotation and scaling factor
     159              : )
     160              : {
     161              :     size_t idx;
     162              : 
     163         3501 :     for( size_t j = 0; j < ny; ++j )
     164              :     {
     165       570264 :         for( size_t i = 0; i < nx; ++i )
     166              :         {
     167       566796 :             idx = i + j * nx;
     168              : 
     169       566796 :             arr[idx] = gaussian2D( (realT)i, (realT)j, G0, G, x0, y0, sigma );
     170              :         }
     171              :     }
     172           33 : }
     173              : 
     174              : /// Find value at position (x,y) of the 2D general elliptical Gaussian
     175              : /**
     176              :  * Computes:
     177              :  *
     178              :  * \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     179              :  *
     180              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     181              :  *
     182              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     183              :  *
     184              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     185              :  *
     186              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     187              :  *
     188              :  * In this version the parameters are specified directly as (a,b,c), in particular avoiding the trig function calls.
     189              :  * This should be much more efficient, and so this version should be used inside fitting routines, etc.  However
     190              :  * note that the matrix {a b}{b c} must be <a
     191              :  * href="http://mathworld.wolfram.com/PositiveDefiniteMatrix.html">positive-definite</a> otherwise infinities can result
     192              :  * from the argument of the exponent being positive.
     193              :  *
     194              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     195              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.  The function gaussian2D_ang() is a
     196              :  * wrapper for this function, which instead accepts (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) as inputs.
     197              :  *
     198              :  * \returns the value of the 2D elliptical Gaussian at (x,y)
     199              :  *
     200              :  * \tparam realT is the type to use for arithmetic
     201              :  *
     202              :  * \ingroup gen_math_gaussians
     203              :  */
     204              : template <typename realT>
     205              : realT gaussian2D( const realT x,  ///< [in] the x-position at which to evaluate the Gaussian
     206              :                   const realT y,  ///< [in] the y-positoin at which to evaluate the Gaussian
     207              :                   const realT G0, ///< [in] the constant to add to the Gaussian
     208              :                   const realT G,  ///< [in] the scaling factor (peak = G-G0)
     209              :                   const realT x0, ///< [in] the x-coordinate of the center
     210              :                   const realT y0, ///< [in] the y-coordinate of the center
     211              :                   const realT a,  ///< [in] the first rotation and scaling factor
     212              :                   const realT b,  ///< [in] the second rotation and scaling factor
     213              :                   const realT c   ///< [in] the third rotation and scaling factor
     214              : )
     215              : {
     216              :     realT dx = x - x0;
     217              :     realT dy = y - y0;
     218              : 
     219              :     return G0 + G * std::exp( -0.5 * ( a * dx * dx + 2. * b * dx * dy + c * dy * dy ) );
     220              : }
     221              : 
     222              : /// Convert from (a,b,c) to (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) for the elliptical Gaussian.
     223              : /** The general 2D elliptical Gaussian
     224              :  *
     225              :  *  \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     226              :  *
     227              :  * can be expressed in terms of widths and a rotation angle using:
     228              :  *
     229              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     230              :  *
     231              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     232              :  *
     233              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     234              :  *
     235              :  * where \f$ \theta \f$ specifies a counter-clockwise rotation.
     236              :  *
     237              :  * This function calculates (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) from inputs (a,b,c). It adopts
     238              :  * the convention that the long axis of the ellipse is \f$\sigma_x\f$, and \f$\theta\f$ is chosen
     239              :  * appropriately.  Note that \f$-\frac{\pi}{2} < \theta < \frac{\pi}{2}\f$.
     240              :  *
     241              :  * \tparam realT is the type to use for arithmetic
     242              :  *
     243              :  * \ingroup gen_math_gaussians
     244              :  */
     245              : template <typename realT>
     246              : void gaussian2D_gen2rot( realT &sigma_x, ///< [out] the width parameter in the rotated x-direction
     247              :                          realT &sigma_y, ///< [out] the width parameter in the rotated y-direction
     248              :                          realT &theta,   ///< [out] the c.c.w rotation
     249              :                          const realT a,  ///< [in] the first rotation and scaling parameter
     250              :                          const realT b,  ///< [in] the second rotation and scaling parameter
     251              :                          const realT c   ///< [in] the the third rotation and scaling parameter
     252              : )
     253              : {
     254              :     realT x1, x2, s, s2, theta0, theta1;
     255              : 
     256              :     realT arg = a * a - 2 * a * c + 4 * b * b + c * c;
     257              :     if( arg < 0 )
     258              :     {
     259              :         x2 = 0.5 * ( a + c );
     260              :         x1 = x2;
     261              :     }
     262              :     else
     263              :     {
     264              :         // There are two roots, one is 1/sigma_x^2 and one is 1/sigma_y^2
     265              :         x2 = 0.5 * ( a + c ) + 0.5 * sqrt( arg );
     266              :         x1 = 0.5 * ( a + c ) - 0.5 * sqrt( arg );
     267              :     }
     268              : 
     269              :     // Our convention is that the larger width is sigma_x
     270              :     sigma_x = sqrt( 1. / x1 );
     271              :     sigma_y = sqrt( 1. / x2 );
     272              : 
     273              :     //----------------------------------------------------------------------------//
     274              :     // Choosing theta:
     275              :     // There is an ambiguity in theta and which direction (x,y) is the long axis
     276              :     // Here we choose theta so that it specifies the long direction, sigma_x
     277              :     //----------------------------------------------------------------------------//
     278              : 
     279              :     // s is  (sin(theta))^2
     280              :     // s2 = (a-x2)*(a-x2)/(b*b + (a-x2)*(a-x2));
     281              :     s = ( a - x1 ) * ( a - x1 ) / ( b * b + ( a - x1 ) * ( a - x1 ) );
     282              : 
     283              :     // First check if x1-x2 will be close to zero
     284              : 
     285              :     if( fabs( x1 - x2 ) < 1e-12 )
     286              :     {
     287              :         theta = 0;
     288              :         return;
     289              :     }
     290              : 
     291              :     theta0 = 0.5 * asin( 2 * b / ( x1 - x2 ) ); // This always gives the correct sign
     292              :     theta1 = asin( sqrt( s ) ); // This always gives the correct magnitude, and seems to be more accurate
     293              : 
     294              :     // Compare signs.  If they match, then we use theta1
     295              :     if( std::signbit( theta0 ) == std::signbit( theta1 ) )
     296              :     {
     297              :         theta = theta1;
     298              :     }
     299              :     else
     300              :     {
     301              :         // Otherwise, we switch quadrants
     302              :         theta = asin( -sqrt( s ) );
     303              :     }
     304              : }
     305              : 
     306              : /// Convert from (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) to (a,b,c) for the elliptical Gaussian.
     307              : /** The general 2D elliptical Gaussian
     308              :  *
     309              :  *  \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     310              :  *
     311              :  * can be expressed in terms of widths and a rotation angle using:
     312              :  *
     313              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     314              :  *
     315              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     316              :  *
     317              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     318              :  *
     319              :  * where \f$ \theta \f$ specifies a counter-clockwise rotation.
     320              :  *
     321              :  * This function calculates (a,b,c) from inputs (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$).
     322              :  *
     323              :  * \tparam realT is the type to use for arithmetic
     324              :  *
     325              :  * \ingroup gen_math_gaussians
     326              :  */
     327              : template <typename realT>
     328              : void gaussian2D_rot2gen( realT &a,            ///< [out] the first rotation and scaling parameter
     329              :                          realT &b,            ///< [out] the second rotation and scaling parameter
     330              :                          realT &c,            ///< [out] the the third rotation and scaling parameter
     331              :                          const realT sigma_x, ///< [in] the width parameter in the rotated x-direction
     332              :                          const realT sigma_y, ///< [in] the width parameter in the rotated y-direction
     333              :                          const realT theta    ///< [in] the c.c.w rotation
     334              : )
     335              : {
     336              :     realT sn, cs, sx2, sy2;
     337              : 
     338              :     sn = sin( theta );
     339              :     cs = cos( theta );
     340              :     sx2 = sigma_x * sigma_x;
     341              :     sy2 = sigma_y * sigma_y;
     342              : 
     343              :     a = cs * cs / sx2 + sn * sn / sy2;
     344              :     b = sn * cs * ( 1. / sx2 - 1. / sy2 );
     345              :     c = sn * sn / sx2 + cs * cs / sy2;
     346              : }
     347              : 
     348              : /// Find value at position (x,y) of the 2D rotated elliptical Gaussian
     349              : /**
     350              :  * Computes:
     351              :  * \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     352              :  *
     353              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     354              :  *
     355              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     356              :  *
     357              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     358              :  *
     359              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     360              :  *
     361              :  * This is a convenience wrapper for the general elliptical Gaussian function gaussian2D(), where here
     362              :  * (a,b,c) are first calculated from (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$).  This will in general be
     363              :  * slower due to the trig function calls, so the (a,b,c) version should be used most of the time.
     364              :  *
     365              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     366              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.  The function gaussian2D_rot() is a
     367              :  * wrapper for this function, which instead accepts (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) as inputs.
     368              :  *
     369              :  * \returns the value of the 2D elliptical Gaussian at (x,y)
     370              :  *
     371              :  * \tparam realT is the type to use for arithmetic
     372              :  *
     373              :  * \ingroup gen_math_gaussians
     374              :  */
     375              : template <typename realT>
     376              : realT gaussian2D_ang( const realT x,       ///< [in] the x-position at which to evaluate the Gaussian
     377              :                       const realT y,       ///< [in] the y-positoin at which to evaluate the Gaussian
     378              :                       const realT G0,      ///< [in] the constant to add to the Gaussian
     379              :                       const realT G,       ///< [in] the scaling factor (peak height = G-G0)
     380              :                       const realT x0,      ///< [in] the x-coordinate of the center
     381              :                       const realT y0,      ///< [in] the y-coordinate of the center
     382              :                       const realT sigma_x, ///< [in] the width in the rotated x direction
     383              :                       const realT sigma_y, ///< [in] the width in the rotated y direction
     384              :                       const realT theta    ///< [in] the counter-clockwise rotation angle
     385              : )
     386              : {
     387              :     realT a, b, c;
     388              : 
     389              :     gaussian2D_rot2gen( a, b, c, sigma_x, sigma_y, theta );
     390              : 
     391              :     return gaussian2D( x, y, G0, G, x0, y0, a, b, c );
     392              : }
     393              : 
     394              : /// Fill in an array with the 2D general elliptical Gaussian
     395              : /**
     396              :  * At each pixel (x,y) of the array this computes:
     397              :  *
     398              :  * \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     399              :  *
     400              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     401              :  *
     402              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     403              :  *
     404              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     405              :  *
     406              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     407              :  *
     408              :  * In this version the parameters are specified directly as (a,b,c), in particular avoiding the trig function calls.
     409              :  * This should be much more efficient, and so this version should be used inside fitting routines, etc.
     410              :  *
     411              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     412              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.  The function gaussian2D_ang() is a
     413              :  * wrapper for this function, which instead accepts (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) as inputs.
     414              :  *
     415              :  * \tparam realT is the type to use for arithmetic
     416              :  *
     417              :  * \ingroup gen_math_gaussians
     418              :  */
     419              : template <typename realT>
     420              : void gaussian2D( realT *arr,     ///< [out] the native array to populate with the Gaussian function
     421              :                  size_t nx,      ///< [in] the x-size of the array, in pixels
     422              :                  size_t ny,      ///< [in] the y-size of the array, in pixels
     423              :                  const realT G0, ///< [in] the constant to add to the Gaussian
     424              :                  const realT G,  ///< [in] the scaling factor (peak = G)
     425              :                  const realT x0, ///< [in] the x-coordinate of the center, in pixels
     426              :                  const realT y0, ///< [in] the y-coordinate of the center, in pixels
     427              :                  const realT a,  ///< [in] is the first rotation and scaling factor
     428              :                  const realT b,  ///< [in] is the second rotation and scaling factor
     429              :                  const realT c   ///< [in] is the third rotation and scaling factor
     430              : )
     431              : {
     432              :     size_t idx;
     433              : 
     434              :     for( size_t j = 0; j < ny; ++j )
     435              :     {
     436              :         for( size_t i = 0; i < nx; ++i )
     437              :         {
     438              :             idx = i + j * nx;
     439              : 
     440              :             arr[idx] = gaussian2D( (realT)i, (realT)j, G0, G, x0, y0, a, b, c );
     441              :         }
     442              :     }
     443              : }
     444              : 
     445              : /// Fill in an array with the 2D general elliptical Gaussian
     446              : /**
     447              :  * At each pixel (x,y) of the array this computes:
     448              :  *
     449              :  * \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     450              :  *
     451              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     452              :  *
     453              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     454              :  *
     455              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     456              :  *
     457              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     458              :  *
     459              :  * This is a convenience wrapper for the general elliptical Gaussian function
     460              :  * gaussian2D( realT *, size_t, size_t, const realT, const realT, const realT, const realT, const realT, const realT,
     461              :  * const realT) , where here (a,b,c) are first calculated from (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$).
     462              :  *
     463              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     464              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.
     465              :  *
     466              :  *
     467              :  * \tparam realT is the type to use for arithmetic
     468              :  *
     469              :  * \ingroup gen_math_gaussians
     470              :  */
     471              : template <typename realT>
     472              : void gaussian2D_ang( realT *arr,          ///< [out] the native array to populate with the Gaussian function
     473              :                      size_t nx,           ///< [in] the x-size of the array, in pixels
     474              :                      size_t ny,           ///< [in] the y-size of the array, in pixels
     475              :                      const realT G0,      ///< [in] the constant to add to the Gaussian
     476              :                      const realT G,       ///< [in] the scaling factor (peak = G)
     477              :                      const realT x0,      ///< [in] the x-coordinate of the center, in pixels
     478              :                      const realT y0,      ///< [in] the y-coordinate of the center, in pixels
     479              :                      const realT sigma_x, ///< [in] the width in the rotated x direction, in pixels
     480              :                      const realT sigma_y, ///< [in] the width in the rotated y direction, in pixels
     481              :                      const realT theta    ///< [in] the counter-clockwise rotation angle, in radians
     482              : )
     483              : {
     484              :     realT a, b, c;
     485              :     size_t idx;
     486              : 
     487              :     // Get the (a,b,c) parameters so the trig only happens once
     488              :     gaussian2D_rot2gen( a, b, c, sigma_x, sigma_y, theta );
     489              : 
     490              :     gaussian2D( arr, nx, ny, G0, G, x0, y0, a, b, c );
     491              : }
     492              : 
     493              : /// Calculate the Jacobian at position (x,y) for the 2D general elliptical Gaussian
     494              : /** \note this has not been verified and may be incorrect.
     495              :  *
     496              :  * Given:
     497              :  *
     498              :  * \f$ f(x,y) = G_0 + G\exp [-0.5( a(x-x_0)^2 + b(x-x_0)(y-y_0) + c(y-y_0)^2 ]\f$
     499              :  *
     500              :  * we calculate
     501              :  *
     502              :  * \f$ \frac{\partial G}{\partial G_0} =  1 \f$
     503              :  *
     504              :  * \f$ \frac{\partial G}{\partial G} = (G - G_0)/A \f$
     505              :  *
     506              :  * \f$ \frac{\partial G}{\partial x_0} = 0.5(G-G_0)( 2a(x-x_0) + b(y-y_0))  \f$
     507              :  *
     508              :  * \f$ \frac{\partial G}{\partial y_0} = 0.5(G-G_0) ( b(x-x_0) + 2c(y-y_0)) \f$
     509              :  *
     510              :  * \f$ \frac{\partial G}{\partial a} = -0.5(G-G_0)  ( (x-x_0)^2 ) \f$
     511              :  *
     512              :  * \f$ \frac{\partial G}{\partial b} = -0.5(G-G_0) ( (x-x_0)(y-y_0) ) \f$
     513              :  *
     514              :  * \f$ \frac{\partial G}{\partial c} = -0.5(G-G_0) ( (y-y_0)^2 )\f$
     515              :  *
     516              :  * \param j is a 7 element vector which is populated with the derivatives
     517              :  * \param x is the x-position at which to evaluate the Gaussian
     518              :  * \param y is the y-positoin at which to evaluate the Gaussian
     519              :  * \param G0 is the constant to add to the Gaussian
     520              :  * \param G is the scaling factor (peak = A)
     521              :  * \param x0 is the x-coordinate of the center
     522              :  * \param y0 is the y-coordinate of the center
     523              :  * \param a is the first rotation and scaling factor
     524              :  * \param b is the second rotation and scaling factor
     525              :  * \param c is the third rotation and scaling factor
     526              :  *
     527              :  *
     528              :  * \tparam realT is the type to use for arithmetic
     529              :  *
     530              :  * \ingroup gen_math_gaussians
     531              :  */
     532              : template <typename realT>
     533              : void gaussian2D_jacobian( realT *j,
     534              :                           const realT x,
     535              :                           const realT y,
     536              :                           const realT G0,
     537              :                           const realT G,
     538              :                           const realT x0,
     539              :                           const realT y0,
     540              :                           const realT a,
     541              :                           const realT b,
     542              :                           const realT c )
     543              : {
     544              :     realT G_G0 = gaussian2D<realT>( x, y, 0, G, x0, y0, a, b, c );
     545              : 
     546              :     j[0] = (realT)1;
     547              : 
     548              :     j[1] = ( G_G0 ) / G;
     549              : 
     550              :     j[2] = 0.5 * G_G0 * ( 2 * a * ( x - x0 ) + b * ( y - y0 ) );
     551              : 
     552              :     j[3] = 0.5 * G_G0 * ( b * ( x - x0 ) + 2 * c * ( y - y0 ) );
     553              : 
     554              :     j[4] = -0.5 * G_G0 * ( ( x - x0 ) * ( x - x0 ) );
     555              : 
     556              :     j[5] = -0.5 * G_G0 * ( ( x - x0 ) * ( y - y0 ) );
     557              : 
     558              :     j[6] = -0.5 * G_G0 * ( ( y - y0 ) * ( y - y0 ) );
     559              : }
     560              : 
     561              : } // namespace func
     562              : } // namespace math
     563              : } // namespace mx
     564              : 
     565              : #endif // gaussian_hpp
        

Generated by: LCOV version 2.0-1