LCOV - code coverage report
Current view: top level - include/math/func - gaussian.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 69.6 % 46 32
Test Date: 2026-08-30 22:23:37 Functions: 62.5 % 8 5

            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            0 : constexpr floatT twosqrt2log2()
      50              : {
      51            0 :     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            0 : floatT sigma2fwhm( floatT sig /**< [in] the Gaussian width parameter */ )
      80              : {
      81            0 :     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            0 : 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            0 :     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 doc]"
     123              :   *
     124              :   */
     125              : template <typename realT>
     126       620134 : realT gaussian2D( const realT x,    ///< [in] the x-position at which to evaluate the Gaussian
     127              :                   const realT y,    ///< [in] the y-positoin at which to evaluate the Gaussian
     128              :                   const realT G0,   ///< [in] the constant to add to the Gaussian
     129              :                   const realT G,    ///< [in] the scaling factor (peak height is  G-G0)
     130              :                   const realT x0,   ///< [in] the x-coordinate of the center
     131              :                   const realT y0,   ///< [in] the y-coordinate of the center
     132              :                   const realT sigma ///< [in] the width of the Gaussian.
     133              : )
     134              : {
     135            0 :     return G0 +
     136       620134 :            G * std::exp( -( 0.5 / ( sigma * sigma ) * ( ( ( x - x0 ) * ( x - x0 ) ) + ( ( y - y0 ) * ( y - y0 ) ) ) ) );
     137              : }
     138              : 
     139              : /// Fill in an array with the 2D arbitrarily-centered symmetric Gaussian
     140              : /**
     141              :  * At each pixel (x,y) of the array this computes:
     142              :  *
     143              :  * \f$ f(x,y) = G_0 + G\exp[-(0.5/\sigma^2)((x-x_0)^2+(y-y_0)^2)] \f$
     144              :  *
     145              :  * \tparam realT is the type to use for arithmetic
     146              :  *
     147              :  * \ingroup gen_math_gaussians
     148              :  */
     149              : template <typename realT>
     150           47 : void gaussian2D( realT *arr,       ///< [out] is the allocated array to fill in
     151              :                  size_t nx,        ///< [in] is the size of the x dimension of the array
     152              :                  size_t ny,        ///< [in] is the size of the y dimension of the array
     153              :                  const realT G0,   ///< [in] is the constant to add to the Gaussian
     154              :                  const realT G,    ///< [in] is the scaling factor (peak height = G-G0)
     155              :                  const realT x0,   ///< [in] is the x-coordinate of the center
     156              :                  const realT y0,   ///< [in] is the y-coordinate of the center
     157              :                  const realT sigma ///< [in] is the third rotation and scaling factor
     158              : )
     159              : {
     160              :     size_t idx;
     161              : 
     162         4357 :     for( size_t j = 0; j < ny; ++j )
     163              :     {
     164       624444 :         for( size_t i = 0; i < nx; ++i )
     165              :         {
     166       620134 :             idx = i + j * nx;
     167              : 
     168       620134 :             arr[idx] = gaussian2D( (realT)i, (realT)j, G0, G, x0, y0, sigma );
     169              :         }
     170              :     }
     171           47 : }
     172              : 
     173              : /// Find value at position (x,y) of the 2D general elliptical Gaussian
     174              : /**
     175              :  * Computes:
     176              :  *
     177              :  * \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$
     178              :  *
     179              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     180              :  *
     181              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     182              :  *
     183              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     184              :  *
     185              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     186              :  *
     187              :  * In this version the parameters are specified directly as (a,b,c), in particular avoiding the trig function calls.
     188              :  * This should be much more efficient, and so this version should be used inside fitting routines, etc.  However
     189              :  * note that the matrix {a b}{b c} must be <a
     190              :  * href="http://mathworld.wolfram.com/PositiveDefiniteMatrix.html">positive-definite</a> otherwise infinities can result
     191              :  * from the argument of the exponent being positive.
     192              :  *
     193              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     194              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.  The function gaussian2D_ang() is a
     195              :  * wrapper for this function, which instead accepts (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) as inputs.
     196              :  *
     197              :  * \returns the value of the 2D elliptical Gaussian at (x,y)
     198              :  *
     199              :  * \tparam realT is the type to use for arithmetic
     200              :  *
     201              :  * \ingroup gen_math_gaussians
     202              :  */
     203              : template <typename realT>
     204       298237 : realT gaussian2D( const realT x,  ///< [in] the x-position at which to evaluate the Gaussian
     205              :                   const realT y,  ///< [in] the y-positoin at which to evaluate the Gaussian
     206              :                   const realT G0, ///< [in] the constant to add to the Gaussian
     207              :                   const realT G,  ///< [in] the scaling factor (peak = G-G0)
     208              :                   const realT x0, ///< [in] the x-coordinate of the center
     209              :                   const realT y0, ///< [in] the y-coordinate of the center
     210              :                   const realT a,  ///< [in] the first rotation and scaling factor
     211              :                   const realT b,  ///< [in] the second rotation and scaling factor
     212              :                   const realT c   ///< [in] the third rotation and scaling factor
     213              : )
     214              : {
     215       298237 :     realT dx = x - x0;
     216       298237 :     realT dy = y - y0;
     217              : 
     218       298237 :     return G0 + G * std::exp( -0.5 * ( a * dx * dx + 2. * b * dx * dy + c * dy * dy ) );
     219              : }
     220              : 
     221              : /// Convert from (a,b,c) to (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) for the elliptical Gaussian.
     222              : /** The general 2D elliptical Gaussian
     223              :  *
     224              :  *  \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$
     225              :  *
     226              :  * can be expressed in terms of widths and a rotation angle using:
     227              :  *
     228              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     229              :  *
     230              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     231              :  *
     232              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     233              :  *
     234              :  * where \f$ \theta \f$ specifies a counter-clockwise rotation.
     235              :  *
     236              :  * This function calculates (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) from inputs (a,b,c). It adopts
     237              :  * the convention that the long axis of the ellipse is \f$\sigma_x\f$, and \f$\theta\f$ is chosen
     238              :  * appropriately.  Note that \f$-\frac{\pi}{2} < \theta < \frac{\pi}{2}\f$.
     239              :  *
     240              :  * \tparam realT is the type to use for arithmetic
     241              :  *
     242              :  * \ingroup gen_math_gaussians
     243              :  */
     244              : template <typename realT>
     245           16 : void gaussian2D_gen2rot( realT &sigma_x, ///< [out] the width parameter in the rotated x-direction
     246              :                          realT &sigma_y, ///< [out] the width parameter in the rotated y-direction
     247              :                          realT &theta,   ///< [out] the c.c.w rotation
     248              :                          const realT a,  ///< [in] the first rotation and scaling parameter
     249              :                          const realT b,  ///< [in] the second rotation and scaling parameter
     250              :                          const realT c   ///< [in] the the third rotation and scaling parameter
     251              : )
     252              : {
     253              :     realT x1, x2, s, s2, theta0, theta1;
     254              : 
     255           16 :     realT arg = a * a - 2 * a * c + 4 * b * b + c * c;
     256           16 :     if( arg < 0 )
     257              :     {
     258            0 :         x2 = 0.5 * ( a + c );
     259            0 :         x1 = x2;
     260              :     }
     261              :     else
     262              :     {
     263              :         // There are two roots, one is 1/sigma_x^2 and one is 1/sigma_y^2
     264           16 :         x2 = 0.5 * ( a + c ) + 0.5 * sqrt( arg );
     265           16 :         x1 = 0.5 * ( a + c ) - 0.5 * sqrt( arg );
     266              :     }
     267              : 
     268              :     // Our convention is that the larger width is sigma_x
     269           16 :     sigma_x = sqrt( 1. / x1 );
     270           16 :     sigma_y = sqrt( 1. / x2 );
     271              : 
     272              :     //----------------------------------------------------------------------------//
     273              :     // Choosing theta:
     274              :     // There is an ambiguity in theta and which direction (x,y) is the long axis
     275              :     // Here we choose theta so that it specifies the long direction, sigma_x
     276              :     //----------------------------------------------------------------------------//
     277              : 
     278              :     // s is  (sin(theta))^2
     279              :     // s2 = (a-x2)*(a-x2)/(b*b + (a-x2)*(a-x2));
     280           16 :     s = ( a - x1 ) * ( a - x1 ) / ( b * b + ( a - x1 ) * ( a - x1 ) );
     281              : 
     282              :     // First check if x1-x2 will be close to zero
     283              : 
     284           16 :     if( fabs( x1 - x2 ) < 1e-12 )
     285              :     {
     286           16 :         theta = 0;
     287           16 :         return;
     288              :     }
     289              : 
     290            0 :     theta0 = 0.5 * asin( 2 * b / ( x1 - x2 ) ); // This always gives the correct sign
     291            0 :     theta1 = asin( sqrt( s ) ); // This always gives the correct magnitude, and seems to be more accurate
     292              : 
     293              :     // Compare signs.  If they match, then we use theta1
     294            0 :     if( std::signbit( theta0 ) == std::signbit( theta1 ) )
     295              :     {
     296            0 :         theta = theta1;
     297              :     }
     298              :     else
     299              :     {
     300              :         // Otherwise, we switch quadrants
     301            0 :         theta = asin( -sqrt( s ) );
     302              :     }
     303              : }
     304              : 
     305              : /// Convert from (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) to (a,b,c) for the elliptical Gaussian.
     306              : /** The general 2D elliptical Gaussian
     307              :  *
     308              :  *  \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$
     309              :  *
     310              :  * can be expressed in terms of widths and a rotation angle using:
     311              :  *
     312              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     313              :  *
     314              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     315              :  *
     316              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     317              :  *
     318              :  * where \f$ \theta \f$ specifies a counter-clockwise rotation.
     319              :  *
     320              :  * This function calculates (a,b,c) from inputs (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$).
     321              :  *
     322              :  * \tparam realT is the type to use for arithmetic
     323              :  *
     324              :  * \ingroup gen_math_gaussians
     325              :  */
     326              : template <typename realT>
     327            8 : void gaussian2D_rot2gen( realT &a,            ///< [out] the first rotation and scaling parameter
     328              :                          realT &b,            ///< [out] the second rotation and scaling parameter
     329              :                          realT &c,            ///< [out] the the third rotation and scaling parameter
     330              :                          const realT sigma_x, ///< [in] the width parameter in the rotated x-direction
     331              :                          const realT sigma_y, ///< [in] the width parameter in the rotated y-direction
     332              :                          const realT theta    ///< [in] the c.c.w rotation
     333              : )
     334              : {
     335              :     realT sn, cs, sx2, sy2;
     336              : 
     337            8 :     sn = sin( theta );
     338            8 :     cs = cos( theta );
     339            8 :     sx2 = sigma_x * sigma_x;
     340            8 :     sy2 = sigma_y * sigma_y;
     341              : 
     342            8 :     a = cs * cs / sx2 + sn * sn / sy2;
     343            8 :     b = sn * cs * ( 1. / sx2 - 1. / sy2 );
     344            8 :     c = sn * sn / sx2 + cs * cs / sy2;
     345            8 : }
     346              : 
     347              : /// Find value at position (x,y) of the 2D rotated elliptical Gaussian
     348              : /**
     349              :  * Computes:
     350              :  * \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$
     351              :  *
     352              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     353              :  *
     354              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     355              :  *
     356              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     357              :  *
     358              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     359              :  *
     360              :  * This is a convenience wrapper for the general elliptical Gaussian function gaussian2D(), where here
     361              :  * (a,b,c) are first calculated from (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$).  This will in general be
     362              :  * slower due to the trig function calls, so the (a,b,c) version should be used most of the time.
     363              :  *
     364              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     365              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.  The function gaussian2D_rot() is a
     366              :  * wrapper for this function, which instead accepts (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) as inputs.
     367              :  *
     368              :  * \returns the value of the 2D elliptical Gaussian at (x,y)
     369              :  *
     370              :  * \tparam realT is the type to use for arithmetic
     371              :  *
     372              :  * \ingroup gen_math_gaussians
     373              :  */
     374              : template <typename realT>
     375              : realT gaussian2D_ang( const realT x,       ///< [in] the x-position at which to evaluate the Gaussian
     376              :                       const realT y,       ///< [in] the y-positoin at which to evaluate the Gaussian
     377              :                       const realT G0,      ///< [in] the constant to add to the Gaussian
     378              :                       const realT G,       ///< [in] the scaling factor (peak height = G-G0)
     379              :                       const realT x0,      ///< [in] the x-coordinate of the center
     380              :                       const realT y0,      ///< [in] the y-coordinate of the center
     381              :                       const realT sigma_x, ///< [in] the width in the rotated x direction
     382              :                       const realT sigma_y, ///< [in] the width in the rotated y direction
     383              :                       const realT theta    ///< [in] the counter-clockwise rotation angle
     384              : )
     385              : {
     386              :     realT a, b, c;
     387              : 
     388              :     gaussian2D_rot2gen( a, b, c, sigma_x, sigma_y, theta );
     389              : 
     390              :     return gaussian2D( x, y, G0, G, x0, y0, a, b, c );
     391              : }
     392              : 
     393              : /// Fill in an array with the 2D general elliptical Gaussian
     394              : /**
     395              :  * At each pixel (x,y) of the array this computes:
     396              :  *
     397              :  * \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$
     398              :  *
     399              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     400              :  *
     401              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     402              :  *
     403              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     404              :  *
     405              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     406              :  *
     407              :  * In this version the parameters are specified directly as (a,b,c), in particular avoiding the trig function calls.
     408              :  * This should be much more efficient, and so this version should be used inside fitting routines, etc.
     409              :  *
     410              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     411              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.  The function gaussian2D_ang() is a
     412              :  * wrapper for this function, which instead accepts (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) as inputs.
     413              :  *
     414              :  * \tparam realT is the type to use for arithmetic
     415              :  *
     416              :  * \ingroup gen_math_gaussians
     417              :  */
     418              : template <typename realT>
     419              : void gaussian2D( realT *arr,     ///< [out] the native array to populate with the Gaussian function
     420              :                  size_t nx,      ///< [in] the x-size of the array, in pixels
     421              :                  size_t ny,      ///< [in] the y-size of the array, in pixels
     422              :                  const realT G0, ///< [in] the constant to add to the Gaussian
     423              :                  const realT G,  ///< [in] the scaling factor (peak = G)
     424              :                  const realT x0, ///< [in] the x-coordinate of the center, in pixels
     425              :                  const realT y0, ///< [in] the y-coordinate of the center, in pixels
     426              :                  const realT a,  ///< [in] is the first rotation and scaling factor
     427              :                  const realT b,  ///< [in] is the second rotation and scaling factor
     428              :                  const realT c   ///< [in] is the third rotation and scaling factor
     429              : )
     430              : {
     431              :     size_t idx;
     432              : 
     433              :     for( size_t j = 0; j < ny; ++j )
     434              :     {
     435              :         for( size_t i = 0; i < nx; ++i )
     436              :         {
     437              :             idx = i + j * nx;
     438              : 
     439              :             arr[idx] = gaussian2D( (realT)i, (realT)j, G0, G, x0, y0, a, b, c );
     440              :         }
     441              :     }
     442              : }
     443              : 
     444              : /// Fill in an array with the 2D general elliptical Gaussian
     445              : /**
     446              :  * At each pixel (x,y) of the array this computes:
     447              :  *
     448              :  * \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$
     449              :  *
     450              :  * where, for a counter-clockwise rotation \f$ \theta \f$, we have
     451              :  *
     452              :  * \f$ a = \frac{\cos^2 \theta}{\sigma_x^2} + \frac{\sin^2\theta}{\sigma_y^2}\f$
     453              :  *
     454              :  * \f$ b = \frac{\sin 2\theta}{2} \left(\frac{1}{\sigma_x^2} - \frac{1}{\sigma_y^2} \right)\f$
     455              :  *
     456              :  * \f$ c = \frac{\sin^2 \theta}{\sigma_x^2} + \frac{\cos^2\theta}{\sigma_y^2}\f$
     457              :  *
     458              :  * This is a convenience wrapper for the general elliptical Gaussian function
     459              :  * gaussian2D( realT *, size_t, size_t, const realT, const realT, const realT, const realT, const realT, const realT,
     460              :  * const realT) , where here (a,b,c) are first calculated from (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$).
     461              :  *
     462              :  * The functions gaussian2D_gen2rot() and gaussian2D_rot2gen() provide conversions from
     463              :  * (a,b,c) to  (\f$\sigma_x\f$,\f$\sigma_y\f$,\f$\theta\f$) and back.
     464              :  *
     465              :  *
     466              :  * \tparam realT is the type to use for arithmetic
     467              :  *
     468              :  * \ingroup gen_math_gaussians
     469              :  */
     470              : template <typename realT>
     471              : void gaussian2D_ang( realT *arr,          ///< [out] the native array to populate with the Gaussian function
     472              :                      size_t nx,           ///< [in] the x-size of the array, in pixels
     473              :                      size_t ny,           ///< [in] the y-size of the array, in pixels
     474              :                      const realT G0,      ///< [in] the constant to add to the Gaussian
     475              :                      const realT G,       ///< [in] the scaling factor (peak = G)
     476              :                      const realT x0,      ///< [in] the x-coordinate of the center, in pixels
     477              :                      const realT y0,      ///< [in] the y-coordinate of the center, in pixels
     478              :                      const realT sigma_x, ///< [in] the width in the rotated x direction, in pixels
     479              :                      const realT sigma_y, ///< [in] the width in the rotated y direction, in pixels
     480              :                      const realT theta    ///< [in] the counter-clockwise rotation angle, in radians
     481              : )
     482              : {
     483              :     realT a, b, c;
     484              :     size_t idx;
     485              : 
     486              :     // Get the (a,b,c) parameters so the trig only happens once
     487              :     gaussian2D_rot2gen( a, b, c, sigma_x, sigma_y, theta );
     488              : 
     489              :     gaussian2D( arr, nx, ny, G0, G, x0, y0, a, b, c );
     490              : }
     491              : 
     492              : /// Calculate the Jacobian at position (x,y) for the 2D general elliptical Gaussian
     493              : /** \note this has not been verified and may be incorrect.
     494              :  *
     495              :  * Given:
     496              :  *
     497              :  * \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$
     498              :  *
     499              :  * we calculate
     500              :  *
     501              :  * \f$ \frac{\partial G}{\partial G_0} =  1 \f$
     502              :  *
     503              :  * \f$ \frac{\partial G}{\partial G} = (G - G_0)/A \f$
     504              :  *
     505              :  * \f$ \frac{\partial G}{\partial x_0} = 0.5(G-G_0)( 2a(x-x_0) + b(y-y_0))  \f$
     506              :  *
     507              :  * \f$ \frac{\partial G}{\partial y_0} = 0.5(G-G_0) ( b(x-x_0) + 2c(y-y_0)) \f$
     508              :  *
     509              :  * \f$ \frac{\partial G}{\partial a} = -0.5(G-G_0)  ( (x-x_0)^2 ) \f$
     510              :  *
     511              :  * \f$ \frac{\partial G}{\partial b} = -0.5(G-G_0) ( (x-x_0)(y-y_0) ) \f$
     512              :  *
     513              :  * \f$ \frac{\partial G}{\partial c} = -0.5(G-G_0) ( (y-y_0)^2 )\f$
     514              :  *
     515              :  * \param j is a 7 element vector which is populated with the derivatives
     516              :  * \param x is the x-position at which to evaluate the Gaussian
     517              :  * \param y is the y-positoin at which to evaluate the Gaussian
     518              :  * \param G0 is the constant to add to the Gaussian
     519              :  * \param G is the scaling factor (peak = A)
     520              :  * \param x0 is the x-coordinate of the center
     521              :  * \param y0 is the y-coordinate of the center
     522              :  * \param a is the first rotation and scaling factor
     523              :  * \param b is the second rotation and scaling factor
     524              :  * \param c is the third rotation and scaling factor
     525              :  *
     526              :  *
     527              :  * \tparam realT is the type to use for arithmetic
     528              :  *
     529              :  * \ingroup gen_math_gaussians
     530              :  */
     531              : template <typename realT>
     532              : void gaussian2D_jacobian( realT *j,
     533              :                           const realT x,
     534              :                           const realT y,
     535              :                           const realT G0,
     536              :                           const realT G,
     537              :                           const realT x0,
     538              :                           const realT y0,
     539              :                           const realT a,
     540              :                           const realT b,
     541              :                           const realT c )
     542              : {
     543              :     realT G_G0 = gaussian2D<realT>( x, y, 0, G, x0, y0, a, b, c );
     544              : 
     545              :     j[0] = (realT)1;
     546              : 
     547              :     j[1] = ( G_G0 ) / G;
     548              : 
     549              :     j[2] = 0.5 * G_G0 * ( 2 * a * ( x - x0 ) + b * ( y - y0 ) );
     550              : 
     551              :     j[3] = 0.5 * G_G0 * ( b * ( x - x0 ) + 2 * c * ( y - y0 ) );
     552              : 
     553              :     j[4] = -0.5 * G_G0 * ( ( x - x0 ) * ( x - x0 ) );
     554              : 
     555              :     j[5] = -0.5 * G_G0 * ( ( x - x0 ) * ( y - y0 ) );
     556              : 
     557              :     j[6] = -0.5 * G_G0 * ( ( y - y0 ) * ( y - y0 ) );
     558              : }
     559              : 
     560              : } // namespace func
     561              : } // namespace math
     562              : } // namespace mx
     563              : 
     564              : #endif // gaussian_hpp
        

Generated by: LCOV version 2.0-1