LCOV - code coverage report
Current view: top level - include/math/fit - fitGaussian.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 29.8 % 258 77
Test Date: 2026-08-30 22:23:37 Functions: 29.7 % 37 11

            Line data    Source code
       1              : /** \file fitGaussian.hpp
       2              :  * \author Jared R. Males
       3              :  * \brief Tools for fitting Gaussians to data.
       4              :  * \ingroup fitting_files
       5              :  *
       6              :  */
       7              : 
       8              : //***********************************************************************//
       9              : // Copyright 2015, 2016, 2017 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 fitGaussian_hpp
      28              : #define fitGaussian_hpp
      29              : 
      30              : #include "array2FitGaussian1D.hpp"
      31              : #include "array2FitGaussian2D.hpp"
      32              : 
      33              : #include "../../mxlib.hpp"
      34              : #include "levmarInterface.hpp"
      35              : #include "../func/gaussian.hpp"
      36              : #include "../constants.hpp"
      37              : 
      38              : #include "../../improc/eigenImage.hpp"
      39              : 
      40              : namespace mx
      41              : {
      42              : namespace math
      43              : {
      44              : namespace fit
      45              : {
      46              : 
      47              : /** \defgroup gaussian_peak_fit Gaussians
      48              :  * \brief Fitting Gaussians to data.
      49              :  *
      50              :  * The Gaussian function is fit to data.
      51              :  *
      52              :  * \ingroup peak_fit
      53              :  */
      54              : 
      55              : // forward
      56              : template <typename _realT>
      57              : struct gaussian1D_fitter;
      58              : 
      59              : ///\ref levmarInterface fitter structure for the symmetric Gaussian.
      60              : /** \ingroup gaussian_peak_fit
      61              :  *
      62              :  */
      63              : template <typename _realT>
      64              : struct gaussian1D_fitter
      65              : {
      66              :     typedef _realT realT;
      67              : 
      68              :     static const int nparams = 4;
      69              : 
      70            0 :     static void func( realT *p, realT *hx, int m, int n, void *adata )
      71              :     {
      72            0 :         array2FitGaussian1D<realT> *arr = (array2FitGaussian1D<realT> *)adata;
      73              : 
      74            0 :         realT G0 = arr->G0( p );
      75            0 :         realT G = arr->G( p );
      76            0 :         realT x0 = arr->x0( p );
      77            0 :         realT sigma = arr->sigma( p );
      78              : 
      79            0 :         if( arr->m_mask )
      80              :         {
      81            0 :             if( arr->m_coords )
      82              :             {
      83            0 :                 for( int i = 0; i < arr->m_nx; ++i )
      84              :                 {
      85            0 :                     if( arr->m_mask[i] == 0 )
      86            0 :                         continue;
      87            0 :                     hx[i] = func::gaussian<realT>( arr->m_coords[i], G0, G, x0, sigma ) - arr->m_data[i];
      88              :                 }
      89              :             }
      90              :             else
      91              :             {
      92            0 :                 for( int i = 0; i < arr->m_nx; ++i )
      93              :                 {
      94            0 :                     if( arr->m_mask[i] == 0 )
      95            0 :                         continue;
      96            0 :                     hx[i] = func::gaussian<realT>( i, G0, G, x0, sigma ) - arr->m_data[i];
      97              :                 }
      98              :             }
      99              :         }
     100              :         else
     101              :         {
     102            0 :             if( arr->m_coords )
     103              :             {
     104            0 :                 for( int i = 0; i < arr->m_nx; ++i )
     105              :                 {
     106            0 :                     hx[i] = func::gaussian<realT>( arr->m_coords[i], G0, G, x0, sigma ) - arr->m_data[i];
     107              :                 }
     108              :             }
     109              :             else
     110              :             {
     111            0 :                 for( int i = 0; i < arr->m_nx; ++i )
     112              :                 {
     113            0 :                     hx[i] = func::gaussian<realT>( i, G0, G, x0, sigma ) - arr->m_data[i];
     114              :                 }
     115              :             }
     116              :         }
     117            0 :     }
     118              : };
     119              : 
     120              : extern template struct gaussian1D_fitter<float>;
     121              : extern template struct gaussian1D_fitter<double>;
     122              : 
     123              : /// Class to manage fitting a 1D Gaussian to data via the \ref levmarInterface
     124              : /** Fits the following function to the data:
     125              :  * \f$ G(x) = G_0 + G\exp[-(0.5/\sigma^2)((x-x_0)^2)]\f$
     126              :  *
     127              :  * Can use a vector of x-coordinates, or use the array index as the position corresponding to each y-value.
     128              :  * A mask can be provided, where any 0 entries cause that position to be ignored.
     129              :  *
     130              :  * Any of the parameters can be fixed, and not included in the fit.
     131              :  *
     132              :  * \code
     133              :  *
     134              :  * \endcode
     135              :  *
     136              :  *
     137              :  * \tparam fitterT a type meeting the above requirements.
     138              :  *
     139              :  * \ingroup gaussian_peak_fit
     140              :  *
     141              :  */
     142              : // template<typename fitterT>
     143              : template <typename _realT>
     144              : class fitGaussian1D : public levmarInterface<gaussian1D_fitter<_realT>> // fitterT>
     145              : {
     146              : 
     147              :   public:
     148              :     typedef _realT realT;
     149              :     typedef gaussian1D_fitter<realT> fitterT;
     150              : 
     151              :   protected:
     152              :     array2FitGaussian1D<realT> arr;
     153              : 
     154            0 :     void initialize()
     155              :     {
     156            0 :         this->allocate_params( arr.nparams() );
     157            0 :         this->adata = &arr;
     158            0 :     }
     159              : 
     160              :   public:
     161            0 :     fitGaussian1D()
     162            0 :     {
     163            0 :         this->initialize();
     164            0 :     }
     165              : 
     166            0 :     ~fitGaussian1D()
     167              :     {
     168            0 :     }
     169              : 
     170              :     /// Set whether each parameter is fixed.
     171              :     /** Sets the parameter indices appropriately.
     172              :      */
     173            0 :     void setFixed( bool G0,   ///< [in] if true, then G0 will be not be part of the fit
     174              :                    bool G,    ///< [in] if true, then G will be not be part of the fit
     175              :                    bool x0,   ///< [in] if true, then x0 will be not be part of the fit
     176              :                    bool sigma ///< [in] if true, then sigma will be not be part of the fit
     177              :     )
     178              :     {
     179            0 :         arr.setFixed( G0, G, x0, sigma );
     180            0 :         this->allocate_params( arr.nparams() );
     181            0 :     }
     182              : 
     183              :     /// Set the initial guess for a symmetric Gaussian.
     184              :     /** Also works for the general case, setting the same width in both directions.
     185              :      */
     186            0 :     void setGuess( realT G0,   ///< [in] the constant background level
     187              :                    realT G,    ///< [in] the peak scaling
     188              :                    realT x0,   ///< [in] the center x-coordinate
     189              :                    realT sigma ///< [in] the width parameter
     190              :     )
     191              :     {
     192            0 :         arr.G0( this->p, G0 );
     193            0 :         arr.G( this->p, G );
     194            0 :         arr.x0( this->p, x0 );
     195            0 :         arr.sigma( this->p, sigma );
     196            0 :     }
     197              : 
     198              :     /// Set the data aray.
     199            0 :     void setArray( realT *data, int nx )
     200              :     {
     201            0 :         arr.m_data = data;
     202            0 :         arr.m_nx = nx;
     203              : 
     204            0 :         this->n = nx;
     205            0 :     }
     206              : 
     207              :     /// Set the data aray.
     208            0 :     void setArray( realT *data, realT *coords, int nx )
     209              :     {
     210            0 :         arr.m_data = data;
     211            0 :         arr.m_coords = coords;
     212            0 :         arr.m_nx = nx;
     213              : 
     214            0 :         this->n = nx;
     215            0 :     }
     216              : 
     217              :     /// Do the fit.
     218            0 :     int fit()
     219              :     {
     220              :         fitterT fitter;
     221              : 
     222            0 :         return levmarInterface<fitterT>::fit();
     223              :     }
     224              : 
     225              :     /// Get the current value of G0, the constant.
     226              :     /**
     227              :      * \returns the current value of G0, which is p[0].
     228              :      */
     229            0 :     realT G0()
     230              :     {
     231            0 :         return arr.G0( this->p );
     232              :     }
     233              : 
     234              :     /// Get the peak scaling.
     235            0 :     realT G()
     236              :     {
     237            0 :         return arr.G( this->p );
     238              :     }
     239              : 
     240              :     /// Get the center x-coordinate
     241            0 :     realT x0()
     242              :     {
     243            0 :         return arr.x0( this->p );
     244              :     }
     245              : 
     246              :     /// Return sigma
     247              :     /**
     248              :      */
     249            0 :     realT sigma()
     250              :     {
     251            0 :         return arr.sigma( this->p );
     252              :     }
     253              : };
     254              : 
     255              : extern template class fitGaussian1D<float>;
     256              : extern template class fitGaussian1D<double>;
     257              : 
     258              : /// Alias for the fitGaussian1D type fitting the gaussian.
     259              : /** \ingroup gaussian_peak_fit
     260              :  */
     261              : // template<typename realT>
     262              : // using fitGaussian1D = mx::math::fit::fitGaussian1D<mx::math::fit::gaussian1D_fitter<realT>>;
     263              : 
     264              : // forward
     265              : template <typename _realT>
     266              : struct gaussian2D_sym_fitter;
     267              : 
     268              : // forward
     269              : template <typename _realT>
     270              : struct gaussian2D_gen_fitter;
     271              : 
     272              : template <typename _realT>
     273              : struct gaussian2D_gen_fitter_bgfixed;
     274              : 
     275              : /// Class to manage fitting a 2D Gaussian to data via the \ref levmarInterface
     276              : /** Can fit either the symmetric Gaussian, or the rotated asymmetric Gaussian.  Individual parameters can be fixed,
     277              :  * except in the asymmetric case \f$\sigma_x, \sigma_y, \theta\f$ must currently be fixed together.
     278              :  *
     279              :  * In addition to the requirements on fitterT specified by \ref levmarInterface
     280              :  * this class also requires the following in fitterT
     281              :  * \code
     282              :  * static const int nparams = 7; //where the number 7 is replaced by the number of parameters that fitterT expects to
     283              :  * fit.
     284              :  *
     285              :  * void paramNormalizer( array2FitGaussian2D * arr,
     286              :  *                       realT *,
     287              :  *                       int); //A function which converts from input parameters to fitting parameters.  May do nothing.
     288              :  *
     289              :  * \endcode
     290              :  *
     291              :  *
     292              :  * \tparam fitterT a type meeting the above requirements.
     293              :  *
     294              :  * \ingroup gaussian_peak_fit
     295              :  *
     296              :  * "[test doc]"
     297              :  *
     298              :  */
     299              : template <typename fitterT>
     300              : class fitGaussian2D : public levmarInterface<fitterT>
     301              : {
     302              : 
     303              :   public:
     304              :     typedef typename fitterT::realT realT;
     305              : 
     306              :     array2FitGaussian2D<realT>
     307              :         arr; /**< Data array to pass to the levmar library.
     308              :                   Contains the actual data plus the parameters if fixed.*/
     309              : 
     310           21 :     void initialize()
     311              :     {
     312              :         if( fitterT::maxNparams == 5 )
     313              :         {
     314            0 :             arr.setSymmetric();
     315              :         }
     316              :         else
     317              :         {
     318           21 :             arr.setGeneral();
     319              :         }
     320           21 :         this->allocate_params( arr.nparams() );
     321           21 :         this->adata = &arr;
     322           21 :     }
     323              : 
     324           21 :     fitGaussian2D()
     325           21 :     {
     326           21 :         initialize();
     327           21 :     }
     328              : 
     329           21 :     ~fitGaussian2D()
     330              :     {
     331           21 :     }
     332              : 
     333              :     /// Set whether each parameter is fixed.
     334              :     /** Sets the parameter indices appropriately.
     335              :      */
     336            0 :     void setFixed( bool G0,      ///< [in] if true, then G0 will be not be part of the fit
     337              :                    bool G,       ///< [in] if true, then G will be not be part of the fit
     338              :                    bool x0,      ///< [in] if true, then x0 will be not be part of the fit
     339              :                    bool y0,      ///< [in] if true, then y0 will be not be part of the fit
     340              :                    bool sigma_x, ///< [in] if true, then sigma_x will be not be part of the fit
     341              :                    bool sigma_y, ///< [in] if true, then sigma_y will be not be part of the fit
     342              :                    bool theta    ///< [in] if true, then theta will be not be part of the fit
     343              :     )
     344              :     {
     345            0 :         arr.setFixed( G0, G, x0, y0, sigma_x, sigma_y, theta );
     346            0 :         this->allocate_params( arr.nparams() );
     347            0 :     }
     348              : 
     349              :     /// Set whether each parameter is fixed.
     350              :     /** Sets the parameter indices appropriately.
     351              :      */
     352            0 :     void setFixed( bool G0,   ///< [in] if true, then G0 will be not be part of the fit
     353              :                    bool G,    ///< [in] if true, then G will be not be part of the fit
     354              :                    bool x0,   ///< [in] if true, then x0 will be not be part of the fit
     355              :                    bool y0,   ///< [in] if true, then y0 will be not be part of the fit
     356              :                    bool sigma ///< [in] if true, then sigma will be not be part of the fit
     357              :     )
     358              :     {
     359            0 :         arr.setFixed( G0, G, x0, y0, sigma, sigma, sigma );
     360            0 :         this->allocate_params( arr.nparams() );
     361            0 :     }
     362              : 
     363              :     /// Set the initial guess for a symmetric Gaussian.
     364              :     /** Also works for the general case, setting the same width in both directions.
     365              :      */
     366            0 :     void setGuess( realT G0,   ///< [in] the constant background level
     367              :                    realT G,    ///< [in] the peak scaling
     368              :                    realT x0,   ///< [in] the center x-coordinate
     369              :                    realT y0,   ///< [in] the center y-coordinate
     370              :                    realT sigma ///< [in] the width parameter
     371              :     )
     372              :     {
     373            0 :         arr.G0( this->p, G0 );
     374            0 :         arr.G( this->p, G );
     375            0 :         arr.x0( this->p, x0 );
     376            0 :         arr.y0( this->p, y0 );
     377            0 :         arr.sigma( this->p, sigma );
     378            0 :     }
     379              : 
     380              :     /// Set the initial guess for the general Gaussian.
     381            8 :     void setGuess( realT G0,      ///< [in] the constant background level
     382              :                    realT G,       ///< [in] the peak scaling
     383              :                    realT x0,      ///< [in] the center x-coordinate
     384              :                    realT y0,      ///< [in] the center y-coordinate
     385              :                    realT sigma_x, ///< [in] the width parameter in the rotated x-direction (the long axis)
     386              :                    realT sigma_y, ///< [in] the width parameter in the rotated y-direction
     387              :                    realT theta    ///< [in] the angle of the long axis (always sigma_x)
     388              :     )
     389              :     {
     390              : 
     391            8 :         arr.G0( this->p, G0 );
     392            8 :         arr.G( this->p, G );
     393            8 :         arr.x0( this->p, x0 );
     394            8 :         arr.y0( this->p, y0 );
     395            8 :         arr.sigma_x( this->p, sigma_x );
     396            8 :         arr.sigma_y( this->p, sigma_y );
     397            8 :         arr.theta( this->p, theta );
     398            8 :     }
     399              : 
     400              :     /// Set the data aray.
     401            8 :     void setArray( realT *data, ///< [in] The 2D array of data to fit.
     402              :                    int nx,      ///< [in] the x size of the data
     403              :                    int ny       ///< [in] the y size of the data
     404              :     )
     405              :     {
     406            8 :         arr.data = data;
     407            8 :         arr.nx = nx;
     408            8 :         arr.ny = ny;
     409            8 :         arr.mask = nullptr;
     410            8 :         this->n = nx * ny;
     411            8 :     }
     412              : 
     413              :     /// Set the data aray, with a mask.
     414            0 :     void setArray(
     415              :         realT *data, ///< [in] The 2D array of data to fit.
     416              :         int nx,      ///< [in] the x size of the data
     417              :         int ny,      ///< [in] the y size of the data
     418              :         realT *mask  ///< [in] Array of same size as data.  Any 0 pixels in this array will be excluded from the fit.
     419              :     )
     420              :     {
     421            0 :         arr.data = data;
     422            0 :         arr.nx = nx;
     423            0 :         arr.ny = ny;
     424            0 :         arr.mask = mask;
     425              : 
     426            0 :         this->n = 0;
     427              :         int idx_mat;
     428            0 :         for( int j = 0; j < nx; ++j )
     429              :         {
     430            0 :             for( int i = 0; i < ny; ++i )
     431              :             {
     432            0 :                 idx_mat = i + j * nx;
     433              : 
     434            0 :                 this->n += arr.mask[idx_mat];
     435              :             }
     436              :         }
     437            0 :     }
     438              : 
     439              :     /// Do the fit.
     440            8 :     int fit()
     441              :     {
     442              :         fitterT fitter;
     443            8 :         fitter.paramNormalizer( &arr, this->p, 1 );
     444              : 
     445            8 :         levmarInterface<fitterT>::fit();
     446              : 
     447            8 :         fitter.paramNormalizer( &arr, this->p, -1 );
     448            8 :         fitter.paramNormalizer(
     449            8 :             &arr, this->init_p, -1 ); // The normalized version is stored, so fix it before possible output.
     450              : 
     451            8 :         return 0;
     452              :     }
     453              : 
     454              :     /// Get the current value of G0, the constant.
     455              :     /**
     456              :      * \returns the current value of G0.
     457              :      */
     458            0 :     realT G0()
     459              :     {
     460            0 :         return arr.G0( this->p );
     461              :     }
     462              : 
     463              :     /// Get the peak scaling.
     464            8 :     realT G()
     465              :     {
     466            8 :         return arr.G( this->p );
     467              :     }
     468              : 
     469              :     /// Get the center x-coordinate
     470            8 :     realT x0()
     471              :     {
     472            8 :         return arr.x0( this->p );
     473              :     }
     474              : 
     475              :     /// Get the center y-coordinate
     476            8 :     realT y0()
     477              :     {
     478            8 :         return arr.y0( this->p );
     479              :     }
     480              : 
     481              :     /// Return the width parameter
     482              :     /** As described for the symmetric Gaussian.
     483              :      *
     484              :      * For the general Gaussian, this returns \f$ \sigma = \sqrt{ \sigma_x^2 + \sigma_y^2} \f$.
     485              :      */
     486            0 :     realT sigma()
     487              :     {
     488            0 :         return arr.sigma( this->p );
     489              :     }
     490              : 
     491              :     /// Return the full-width at half maximum
     492              :     /** This is a simple scaling of the sigma() result
     493              :      */
     494            0 :     realT fwhm()
     495              :     {
     496            0 :         return func::sigma2fwhm( arr.sigma( this->p ) );
     497              :     }
     498              : 
     499              :     /// Return the width parameter on the long axis.
     500            0 :     realT sigma_x()
     501              :     {
     502            0 :         return arr.sigma_x( this->p );
     503              :     }
     504              : 
     505              :     /// Return the width parameter on the short axis.
     506            0 :     realT sigma_y()
     507              :     {
     508            0 :         return arr.sigma_y( this->p );
     509              :     }
     510              : 
     511              :     /// Return the orientation of the long axis.
     512            0 :     realT theta()
     513              :     {
     514            0 :         return arr.theta( this->p );
     515              :     }
     516              : };
     517              : 
     518              : ///\ref levmarInterface fitter structure for the symmetric Gaussian.
     519              : /** \ingroup gaussian_peak_fit
     520              :  *
     521              :  * "[test doc]"
     522              :  */
     523              : template <typename _realT>
     524              : struct gaussian2D_sym_fitter
     525              : {
     526              :     typedef _realT realT;
     527              : 
     528              :     static const int maxNparams = 5;
     529              : 
     530            0 :     static void func( realT *p, realT *hx, int m, int n, void *adata )
     531              :     {
     532            0 :         array2Fit<realT> *arr = (array2Fit<realT> *)adata;
     533              : 
     534              :         size_t idx_mat, idx_dat;
     535              : 
     536            0 :         idx_dat = 0;
     537              : 
     538            0 :         for( int j = 0; j < arr->ny; j++ )
     539              :         {
     540            0 :             for( int i = 0; i < arr->nx; i++ )
     541              :             {
     542            0 :                 idx_mat = i + j * arr->nx;
     543              : 
     544            0 :                 hx[idx_dat] = func::gaussian2D<realT>( i, j, p[0], p[1], p[2], p[3], p[4] ) - arr->data[idx_mat];
     545              : 
     546            0 :                 idx_dat++;
     547              :             }
     548              :         }
     549            0 :     }
     550              : 
     551              :     /// Does nothing in this case.
     552            0 :     void paramNormalizer( array2FitGaussian2D<realT> *arr, realT *p, int dir )
     553              :     {
     554            0 :         return;
     555              :     }
     556              : };
     557              : 
     558              : ///\ref levmarInterface fitter structure for the general elliptical Gaussian.
     559              : /** \ingroup gaussian_peak_fit
     560              :  *
     561              :  */
     562              : template <typename _realT>
     563              : struct gaussian2D_gen_fitter
     564              : {
     565              :     typedef _realT realT;
     566              : 
     567              :     static const int maxNparams = 7;
     568              : 
     569          301 :     static void func( realT *p, realT *hx, int m, int n, void *adata )
     570              :     {
     571          301 :         array2FitGaussian2D<realT> *arr = (array2FitGaussian2D<realT> *)adata;
     572              : 
     573              :         size_t idx_mat, idx_dat;
     574              : 
     575          301 :         realT G0 = arr->G0( p ); // 0
     576          301 :         realT G = arr->G( p );   // 1
     577          301 :         realT x0 = arr->x0( p ); // 2
     578          301 :         realT y0 = arr->y0( p ); // 3
     579          301 :         realT a = arr->a( p );   // 4
     580          301 :         realT b = arr->b( p );   // 5
     581          301 :         realT c = arr->c( p );   // 6
     582              : 
     583              :         // Check for positive-definiteness of {{a b}{b c}}
     584          301 :         if( a * c - b * b <= 0 || a <= 0 || c <= 0 || a + c <= 2 * fabs( b ) )
     585              :         {
     586            0 :             idx_dat = 0;
     587              :             // If it's not positive-definite, then we just fill in with the value of the image itself.
     588            0 :             if( arr->mask == nullptr )
     589              :             {
     590            0 :                 if( arr->weights == nullptr)
     591              :                 {
     592            0 :                     for( int j = 0; j < arr->ny; ++j )
     593              :                     {
     594            0 :                         for( int i = 0; i < arr->ny; ++i )
     595              :                         {
     596            0 :                             idx_mat = i + j * arr->nx;
     597            0 :                             hx[idx_dat] = arr->data[idx_mat];
     598            0 :                             ++idx_dat;
     599              :                         }
     600              :                     }
     601              :                 }
     602              :                 else
     603              :                 {
     604            0 :                     for( int j = 0; j < arr->ny; ++j )
     605              :                     {
     606            0 :                         for( int i = 0; i < arr->ny; ++i )
     607              :                         {
     608            0 :                             idx_mat = i + j * arr->nx;
     609            0 :                             hx[idx_dat] = arr->data[idx_mat] * arr->weights[idx_mat];
     610            0 :                             ++idx_dat;
     611              :                         }
     612              :                     }
     613              :                 }
     614              :             }
     615              :             else
     616              :             {
     617            0 :                 for( int j = 0; j < arr->ny; ++j )
     618              :                 {
     619            0 :                     for( int i = 0; i < arr->ny; ++i )
     620              :                     {
     621            0 :                         idx_mat = i + j * arr->nx;
     622            0 :                         if( arr->mask[idx_mat] == 0 )
     623              :                         {
     624            0 :                             continue;
     625              :                         }
     626            0 :                         hx[idx_dat] = arr->data[idx_mat];
     627            0 :                         ++idx_dat;
     628              :                     }
     629              :                 }
     630              :             }
     631            0 :             return;
     632              :         }
     633              : 
     634              :         // If positive-definite, now actually calculate
     635          301 :         idx_dat = 0;
     636              : 
     637          301 :         if( arr->mask == nullptr )
     638              :         {
     639          301 :             if(arr->weights == nullptr)
     640              :             {
     641         9764 :                 for( int j = 0; j < arr->ny; ++j )
     642              :                 {
     643       307700 :                     for( int i = 0; i < arr->nx; ++i )
     644              :                     {
     645       298237 :                         idx_mat = i + j * arr->nx;
     646              : 
     647       298237 :                         hx[idx_dat] = func::gaussian2D<realT>( i, j, G0, G, x0, y0, a, b, c ) - arr->data[idx_mat];
     648              : 
     649       298237 :                         ++idx_dat;
     650              :                     }
     651              :                 }
     652              :             }
     653              :             else
     654              :             {
     655            0 :                 for( int j = 0; j < arr->ny; ++j )
     656              :                 {
     657            0 :                     for( int i = 0; i < arr->nx; ++i )
     658              :                     {
     659            0 :                         idx_mat = i + j * arr->nx;
     660              : 
     661            0 :                         hx[idx_dat] = (func::gaussian2D<realT>( i, j, G0, G, x0, y0, a, b, c ) - arr->data[idx_mat])*arr->weights[idx_mat];
     662              : 
     663            0 :                         ++idx_dat;
     664              :                     }
     665              :                 }
     666              :             }
     667              :         }
     668              :         else
     669              :         {
     670            0 :             for( int j = 0; j < arr->ny; ++j )
     671              :             {
     672            0 :                 for( int i = 0; i < arr->nx; ++i )
     673              :                 {
     674            0 :                     idx_mat = i + j * arr->nx;
     675              : 
     676            0 :                     if( arr->mask[idx_mat] == 0 )
     677              :                     {
     678            0 :                         continue;
     679              :                     }
     680              :                     else
     681              :                     {
     682            0 :                         hx[idx_dat] = func::gaussian2D<realT>( i, j, G0, G, x0, y0, a, b, c ) - arr->data[idx_mat];
     683              : 
     684            0 :                         ++idx_dat;
     685              :                     }
     686              :                 }
     687              :             }
     688              :         }
     689              :     }
     690              : 
     691           24 :     void paramNormalizer( array2FitGaussian2D<realT> *arr, realT *p, int dir )
     692              :     {
     693              :         // Prepare for fit
     694           24 :         if( dir == 1 )
     695              :         {
     696              :             realT na, nb, nc;
     697            8 :             realT sx = arr->sigma_x( p );
     698            8 :             realT sy = arr->sigma_y( p );
     699            8 :             realT th = arr->theta( p );
     700              : 
     701            8 :             func::gaussian2D_rot2gen( na, nb, nc, sx, sy, th );
     702            8 :             arr->a( p, na );
     703            8 :             arr->b( p, nb );
     704            8 :             arr->c( p, nc );
     705            8 :             return;
     706              :         }
     707              : 
     708              :         // Convert after fit
     709           16 :         if( dir == -1 )
     710              :         {
     711              :             realT sx, sy, th;
     712           16 :             realT na = arr->a( p );
     713           16 :             realT nb = arr->b( p );
     714           16 :             realT nc = arr->c( p );
     715           16 :             func::gaussian2D_gen2rot( sx, sy, th, na, nb, nc );
     716              : 
     717           16 :             arr->sigma_x( p, sx );
     718           16 :             arr->sigma_y( p, sy );
     719           16 :             arr->theta( p, th );
     720           16 :             return;
     721              :         }
     722              :     }
     723              : };
     724              : 
     725              : extern template class fitGaussian2D<mx::math::fit::gaussian2D_sym_fitter<float>>;
     726              : extern template class fitGaussian2D<mx::math::fit::gaussian2D_sym_fitter<double>>;
     727              : extern template class fitGaussian2D<mx::math::fit::gaussian2D_gen_fitter<float>>;
     728              : extern template class fitGaussian2D<mx::math::fit::gaussian2D_gen_fitter<double>>;
     729              : 
     730              : /// Alias for the fitGaussian2D type fitting the symmetric gaussian.
     731              : /** \ingroup gaussian_peak_fit
     732              :  */
     733              : template <typename realT>
     734              : using fitGaussian2Dsym = fitGaussian2D<mx::math::fit::gaussian2D_sym_fitter<realT>>;
     735              : 
     736              : /// Alias for the fitGaussian2D type fitting the general elliptical gaussian.
     737              : /** \ingroup gaussian_peak_fit
     738              :  */
     739              : template <typename realT>
     740              : using fitGaussian2Dgen = fitGaussian2D<mx::math::fit::gaussian2D_gen_fitter<realT>>;
     741              : 
     742              : /// Form an estimate of the parameters of an elliptical Gaussian from a 2D image.
     743              : /** Note that this assumes that there is no constant value (i.e. it is zero-ed).
     744              :  *
     745              :  *  \ingroup gaussian_peak_fit
     746              :  */
     747              : template <typename realT>
     748            0 : int guessGauss2D_ang( realT &Ag,                         ///< [out] estimate of the peak
     749              :                       realT &xg,                         ///< [out] estimate of the x-coordinate of the peak
     750              :                       realT &yg,                         ///< [out] estimate of the y-coordinate of the peak
     751              :                       realT &xFWHM,                      ///< [out] estimate of the x-FWHM
     752              :                       realT &yFWHM,                      ///< [out] estimate of the y-FWHM
     753              :                       realT &angG,                       ///< [out] estimate of the angle of the ellipse
     754              :                       mx::improc::eigenImage<realT> &im, ///< [in] the image with an elliptical gaussian
     755              :                       realT maxWidth,                    ///< [in] the width of the box to search for the maximum
     756              :                       realT widthWidth,                  ///< [in] the radius of the circle to search for the widths
     757              :                       realT nAngs, ///< [in] the number of angles at which to search for the widths
     758              :                       realT xg0,   ///< [in] an initial guess at the x-coordinate of the peak
     759              :                       realT yg0    ///< [in] an initial guess at the y-coordinate of the peak
     760              : )
     761              : {
     762            0 :     xg = xg0;
     763            0 :     yg = yg0;
     764            0 :     Ag = im( (int)xg, (int)yg );
     765            0 :     for( int i = 0; i < 2 * maxWidth + 1; ++i )
     766              :     {
     767            0 :         for( int j = 0; j < 2 * maxWidth + 1; ++j )
     768              :         {
     769            0 :             if( im( (int)( xg0 - maxWidth + i ), (int)( yg0 - maxWidth + j ) ) > Ag )
     770              :             {
     771            0 :                 Ag = im( (int)( xg0 - maxWidth + i ), (int)( yg0 - maxWidth + j ) );
     772            0 :                 xg = xg0 - maxWidth + i;
     773            0 :                 yg = yg0 - maxWidth + j;
     774              :             }
     775              :         }
     776              :     }
     777              : 
     778            0 :     realT dAng = math::two_pi<realT>() / nAngs;
     779              :     // std::vector<realT> dist(nAngs);
     780              : 
     781              :     realT c, s;
     782              : 
     783            0 :     realT maxD = 0;
     784            0 :     int maxDidx = 0;
     785            0 :     realT minD = widthWidth;
     786            0 :     int minDidx = 0;
     787              : 
     788            0 :     for( int i = 0; i < nAngs; ++i )
     789              :     {
     790            0 :         c = cos( i * dAng );
     791            0 :         s = sin( i * dAng );
     792              : 
     793            0 :         for( int j = 0; j < widthWidth; ++j )
     794              :         {
     795            0 :             if( im( (int)( xg + j * c ), (int)( yg + j * s ) ) <= 0.5 * Ag )
     796              :             {
     797              :                 // dist[i] = j;
     798              : 
     799            0 :                 if( j > maxD )
     800              :                 {
     801            0 :                     maxD = j;
     802            0 :                     maxDidx = i;
     803              :                 }
     804              : 
     805            0 :                 if( j < minD )
     806              :                 {
     807            0 :                     minD = j;
     808            0 :                     minDidx = i;
     809              :                 }
     810            0 :                 break;
     811              :             }
     812              :         }
     813              :     }
     814              : 
     815              :     // Take minang and move it by 90 degrees
     816            0 :     realT minang = fmod( minDidx * dAng - 0.5 * math::pi<realT>(), math::pi<realT>() );
     817            0 :     if( minang < 0 )
     818            0 :         minang = fmod( minang + math::two_pi<realT>(), math::pi<realT>() );
     819              : 
     820            0 :     realT maxang = fmod( maxDidx * dAng, math::pi<realT>() );
     821              : 
     822              :     // Now average
     823            0 :     angG = 0.5 * ( minang + maxang );
     824              : 
     825            0 :     xFWHM = 2 * maxD;
     826            0 :     yFWHM = 2 * minD;
     827              : 
     828            0 :     return 0; ///\returns 0 if successful
     829              : }
     830              : 
     831              : extern template int guessGauss2D_ang<float>( float &Ag,
     832              :                                              float &xg,
     833              :                                              float &yg,
     834              :                                              float &xFWHM,
     835              :                                              float &yFWHM,
     836              :                                              float &angG,
     837              :                                              mx::improc::eigenImage<float> &im,
     838              :                                              float maxWidth,
     839              :                                              float widthWidth,
     840              :                                              float nAngs,
     841              :                                              float xg0,
     842              :                                              float yg0 );
     843              : 
     844              : extern template int guessGauss2D_ang<double>( double &Ag,
     845              :                                               double &xg,
     846              :                                               double &yg,
     847              :                                               double &xFWHM,
     848              :                                               double &yFWHM,
     849              :                                               double &angG,
     850              :                                               mx::improc::eigenImage<double> &im,
     851              :                                               double maxWidth,
     852              :                                               double widthWidth,
     853              :                                               double nAngs,
     854              :                                               double xg0,
     855              :                                               double yg0 );
     856              : 
     857              : } // namespace fit
     858              : } // namespace math
     859              : 
     860              : } // namespace mx
     861              : 
     862              : #endif // fitGaussian_hpp
        

Generated by: LCOV version 2.0-1