LCOV - code coverage report
Current view: top level - include/improc - eigenCube.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 185 185
Test Date: 2026-08-30 22:23:37 Functions: 100.0 % 37 37

            Line data    Source code
       1              : /** \file eigenCube.hpp
       2              :  * \brief An image cube with an Eigen API
       3              :  *
       4              :  * \author Jared R. Males (jaredmales@gmail.com)
       5              :  *
       6              :  * \ingroup image_processing_files
       7              :  *
       8              :  */
       9              : 
      10              : #ifndef eigenCube_hpp
      11              : #define eigenCube_hpp
      12              : 
      13              : #include <vector>
      14              : 
      15              : #pragma GCC system_header
      16              : #include <Eigen/Dense>
      17              : 
      18              : #include "../error/exception.hpp"
      19              : #include "../math/vectorUtils.hpp"
      20              : #include "eigenImage.hpp"
      21              : #include "imageUtils.hpp"
      22              : 
      23              : namespace mx
      24              : {
      25              : namespace improc
      26              : {
      27              : 
      28              : /// An image cube with an Eigen-like API
      29              : /** \ingroup eigen_image_processing
      30              :  */
      31              : template <typename dataT>
      32              : class eigenCube
      33              : {
      34              :   public:
      35              :     typedef bool is_eigenCube;
      36              :     typedef dataT Scalar;
      37              : 
      38              :     typedef typename Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>::Index Index;
      39              : 
      40              :     typedef Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> imageRef;
      41              : 
      42              :     typedef Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic> imageT;
      43              : 
      44              :   protected:
      45              :     Index _rows;
      46              :     Index _cols;
      47              :     Index _planes;
      48              : 
      49              :     dataT *m_data{ nullptr };
      50              : 
      51              :     bool _owner;
      52              : 
      53              :     /// Validate a mask and good-pixel threshold for a masked combination.
      54              :     template <typename eigenCubeT>
      55              :     void
      56              :     validateMaskedCombination( const eigenCubeT &mask, /**< [in] mask cube whose dimensions must match this cube. */
      57              :                                double minGoodFract     /**< [in] inclusive minimum fraction of good pixels in [0, 1]. */
      58              :     ) const;
      59              : 
      60              :     /// Validate the number of weights for a weighted combination.
      61              :     void
      62              :     validateWeights( const std::vector<dataT> &weights /**< [in] weights whose count must match the number of planes. */
      63              :     ) const;
      64              : 
      65              :     /// Test whether a nonempty set of good pixels meets the requested fraction.
      66              :     bool hasEnoughGoodPixels( size_t goodPixels,  /**< [in] number of unmasked pixels. */
      67              :                               double minGoodFract /**< [in] inclusive minimum fraction of good pixels. */
      68              :     ) const;
      69              : 
      70              :   public:
      71              :     eigenCube();
      72              : 
      73              :     /// C'tor which will allocate space..
      74              :     /**
      75              :      */
      76              :     eigenCube( Index nrows,  ///< [in] Number of rows in the cube
      77              :                Index ncols,  ///< [in] Number of columns the cube
      78              :                Index nplanes ///< [in] Number of planes in the cube
      79              :     );
      80              : 
      81              :     /// C'tor taking an existing array as an argument.
      82              :     /** The existing array is used as is, as in a map, and ownership is not taken.  You are
      83              :      * responsible for memory management, e.g. free-ing this array.
      84              :      */
      85              :     eigenCube( dataT *ndata,  ///< [in] Allocated array with a cube of nrows x ncols x nplanes
      86              :                size_t nrows,  ///< [in] Number of rows in the cube
      87              :                size_t ncols,  ///< [in] Number of columns the cube
      88              :                size_t nplanes ///< [in] Number of planes in the cube
      89              :     );
      90              : 
      91              :     /// Copy a cube into independently owned storage.
      92              :     eigenCube( const eigenCube<dataT> &ec /**< [in] cube to copy. */ );
      93              : 
      94              :     /// Move a cube, transferring any owned storage.
      95              :     eigenCube( eigenCube<dataT> &&ec /**< [in,out] cube to move from. */ ) noexcept;
      96              : 
      97              :     ~eigenCube();
      98              : 
      99              :     void setZero();
     100              : 
     101              :     /// Copy a cube into independently owned storage.
     102              :     eigenCube<dataT> &operator=( const eigenCube<dataT> &ec /**< [in] cube to copy. */ );
     103              : 
     104              :     /// Move a cube, transferring any owned storage.
     105              :     eigenCube<dataT> &operator=( eigenCube<dataT> &&ec /**< [in,out] cube to move from. */ ) noexcept;
     106              : 
     107              :     void shallowCopy( eigenCube<dataT> &src, bool takeOwner = false );
     108              : 
     109              :     /// De-allocate and set all sizes to 0
     110              :     void clear();
     111              : 
     112              :     void resize( int r, int c, int p );
     113              : 
     114              :     void resize( int r, int c );
     115              : 
     116              :     dataT *data();
     117              : 
     118              :     const dataT *data() const;
     119              : 
     120              :     const Index rows() const;
     121              : 
     122              :     const Index cols() const;
     123              : 
     124              :     const Index planes() const;
     125              : 
     126              :     /// Returns a 2D Eigen::Eigen::Map pointed at the entire cube.
     127              :     Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> cube();
     128              : 
     129              :     /// Returns a 2D Eigen::Eigen::Map pointed at the specified image.
     130              :     Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> image( Index n /**< [in] the image number */ );
     131              : 
     132              :     /// Returns a 2D Eigen::Eigen::Map pointed at the specified image.
     133              :     const Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>>
     134              :     image( Index n /**< [in] the image number */ ) const;
     135              : 
     136              :     /// Returns an Eigen::Eigen::Map-ed vector of the pixels at the given coordinate
     137              :     Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>,
     138              :                Eigen::Unaligned,
     139              :                Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>>
     140              :     pixel( Index i, Index j );
     141              : 
     142              :     /// Return an Eigen::Eigen::Map of the cube where each image is a vector
     143              :     Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> asVectors();
     144              : 
     145              :     /// Calculate the covariance matrix of the images in the cube
     146              :     void Covar( Eigen::Matrix<dataT, Eigen::Dynamic, Eigen::Dynamic> &cv );
     147              : 
     148              :     /// Calculate the sum image of the cube
     149              :     /**
     150              :      * \tparam eigenT an Eigen-like type.
     151              :      */
     152              :     template <typename eigenT>
     153              :     void sum( eigenT &mim /**< [out] the resultant sum image.  Is resized. */ );
     154              : 
     155              :     /// Calculate the mean image of the cube
     156              :     /**
     157              :      * \tparam eigenT an Eigen-like type.
     158              :      */
     159              :     template <typename eigenT>
     160              :     void mean( eigenT &mim /**< [out] the resultant mean image.  Is resized. */ );
     161              : 
     162              :     /// Calculate the mean image of the cube with a mask.
     163              :     /**
     164              :      * A nonempty pixel sample is accepted when its good-pixel fraction is greater than or equal to
     165              :      * \p minGoodFract. Rejected pixels are set to invalidNumber<Scalar>().
     166              :      *
     167              :      * \tparam eigenT an Eigen-like type.
     168              :      * \tparam eigenCubeT an eigenCube type.
     169              :      *
     170              :      * \throws mx::exception with error_t::sizeerr if the mask dimensions do not match the cube.
     171              :      * \throws mx::exception with error_t::invalidarg if \p minGoodFract is not finite or is outside [0, 1].
     172              :      */
     173              :     template <typename eigenT, typename eigenCubeT>
     174              :     void mean( eigenT &mim,              ///< [out] the resultant mean image.  Is resized.
     175              :                eigenCubeT &mask,         /**< [in] a mask cube.  Only pixels with value 1 are included in the
     176              :                                                    mean calculation. */
     177              :                double minGoodFract = 0.0 /**< [in] inclusive minimum fraction of good pixels in [0, 1]. */
     178              :     );
     179              : 
     180              :     /// Calculate the weighted mean image of the cube
     181              :     /**
     182              :      * \tparam eigenT an Eigen-like type.
     183              :      *
     184              :      * \throws mx::exception with error_t::sizeerr if the weight count does not match the cube planes.
     185              :      */
     186              :     template <typename eigenT>
     187              :     void mean( eigenT &mim,                ///< [out] the resultant mean image. Is resized.
     188              :                std::vector<dataT> &weights ///< [in] a vector of weights to use for calculating the mean
     189              :     );
     190              : 
     191              :     /// Calculate the weighted mean image of the cube, with a mask cube.
     192              :     /**
     193              :      * A nonempty pixel sample is accepted when its good-pixel fraction is greater than or equal to
     194              :      * \p minGoodFract. Rejected pixels are set to invalidNumber<Scalar>().
     195              :      *
     196              :      * \tparam eigenT an Eigen-like type.
     197              :      * \tparam eigenCubeT an eigenCube type.
     198              :      *
     199              :      * \throws mx::exception with error_t::sizeerr if the mask dimensions or weight count do not match the cube.
     200              :      * \throws mx::exception with error_t::invalidarg if \p minGoodFract is not finite or is outside [0, 1].
     201              :      */
     202              :     template <typename eigenT, typename eigenCubeT>
     203              :     void mean( eigenT &mim,                 ///< [out] the resultant mean image. Is resized.
     204              :                std::vector<dataT> &weights, ///< [in] a vector of weights to use for calculating the mean
     205              :                eigenCubeT &mask, ///< [in] a mask cube.  Only pixels with value 1 are included in the mean calculation.
     206              :                double minGoodFract = 0.0 ///< [in] inclusive minimum fraction of good pixels in [0, 1].
     207              :     );
     208              : 
     209              :     /// Calculate the median image of the cube
     210              :     /**
     211              :      * \tparam eigenT an Eigen-like type.
     212              :      */
     213              :     template <typename eigenT>
     214              :     void median( eigenT &mim /**< [out] the resultant median image. Is resized. */ );
     215              : 
     216              :     /// Calculate the median image of the cube with a mask.
     217              :     /**
     218              :      * A nonempty pixel sample is accepted when its good-pixel fraction is greater than or equal to
     219              :      * \p minGoodFract. Rejected pixels are set to invalidNumber<Scalar>().
     220              :      *
     221              :      * \tparam eigenT an Eigen-like type.
     222              :      * \tparam eigenCubeT an eigenCube type.
     223              :      *
     224              :      * \throws mx::exception with error_t::sizeerr if the mask dimensions do not match the cube.
     225              :      * \throws mx::exception with error_t::invalidarg if \p minGoodFract is not finite or is outside [0, 1].
     226              :      */
     227              :     template <typename eigenT, typename eigenCubeT>
     228              :     void median( eigenT &mim,              ///< [out] the resultant median image. Is resized.
     229              :                  eigenCubeT &mask,         ///< [in] a mask cube. Only pixels with value 1 are included.
     230              :                  double minGoodFract = 0.0 /**< [in] the inclusive minimum fraction of good pixels. */
     231              :     );
     232              : 
     233              :     /// Calculate the sigma clipped mean image of the cube
     234              :     /**
     235              :      * \tparam eigenT an Eigen-like type.
     236              :      */
     237              :     template <typename eigenT>
     238              :     void sigmaMean( eigenT &mim, ///< [out] the resultant mean image
     239              :                     Scalar sigma ///< [in] the sigma value at which to clip.
     240              :     );
     241              : 
     242              :     /// Calculate the sigma clipped mean image of the cube, with a mask cube
     243              :     /**
     244              :      * A nonempty pixel sample is accepted when its good-pixel fraction is greater than or equal to
     245              :      * \p minGoodFract. Rejected pixels are set to invalidNumber<Scalar>().
     246              :      *
     247              :      * \tparam eigenT an Eigen-like type.
     248              :      * \tparam eigenCubeT an eigenCube type.
     249              :      *
     250              :      * \throws mx::exception with error_t::sizeerr if the mask dimensions do not match the cube.
     251              :      * \throws mx::exception with error_t::invalidarg if \p minGoodFract is not finite or is outside [0, 1].
     252              :      */
     253              :     template <typename eigenT, typename eigenCubeT>
     254              :     void
     255              :     sigmaMean( eigenT &mim,      ///< [out] the resultant mean image.  Is resized.
     256              :                eigenCubeT &mask, ///< [in] a mask cube.  Only pixels with value 1 are included in the mean calculation.
     257              :                Scalar sigma,     ///< [in] the sigma value at which to clip.
     258              :                double minGoodFract = 0.0 ///< [in] inclusive minimum fraction of good pixels in [0, 1].
     259              :     );
     260              : 
     261              :     /// Calculate the sigma clipped weighted mean image of the cube
     262              :     /**
     263              :      * \tparam eigenT an Eigen-like type.
     264              :      *
     265              :      * \throws mx::exception with error_t::sizeerr if the weight count does not match the cube planes.
     266              :      */
     267              :     template <typename eigenT>
     268              :     void sigmaMean( eigenT &mim,                 ///< [out] the resultant mean image. Is resized.
     269              :                     std::vector<dataT> &weights, ///< [in] a vector of weights to use for calculating the mean
     270              :                     Scalar sigma                 ///< [in] the sigma value at which to clip.
     271              :     );
     272              : 
     273              :     /// Calculate the sigma clipped weighted mean image of the cube, with a mask cube.
     274              :     /**
     275              :      * A nonempty pixel sample is accepted when its good-pixel fraction is greater than or equal to
     276              :      * \p minGoodFract. Rejected pixels are set to invalidNumber<Scalar>().
     277              :      *
     278              :      * \tparam eigenT an Eigen-like type.
     279              :      * \tparam eigenCubeT an eigenCube type.
     280              :      *
     281              :      * \throws mx::exception with error_t::sizeerr if the mask dimensions or weight count do not match the cube.
     282              :      * \throws mx::exception with error_t::invalidarg if \p minGoodFract is not finite or is outside [0, 1].
     283              :      */
     284              :     template <typename eigenT, typename eigenCubeT>
     285              :     void
     286              :     sigmaMean( eigenT &mim,                 ///< [out] the resultant mean image. Is resized.
     287              :                std::vector<dataT> &weights, ///< [in] a vector of weights to use for calculating the mean
     288              :                eigenCubeT &mask, ///< [in] a mask cube.  Only pixels with value 1 are included in the mean calculation.
     289              :                Scalar sigma,     ///< [in] the sigma value at which to clip.
     290              :                double minGoodFract = 0.0 ///< [in] inclusive minimum fraction of good pixels in [0, 1].
     291              :     );
     292              : };
     293              : 
     294              : template <typename dataT>
     295              : template <typename eigenCubeT>
     296           20 : void eigenCube<dataT>::validateMaskedCombination( const eigenCubeT &mask, double minGoodFract ) const
     297              : {
     298           20 :     if( mask.rows() != _rows || mask.cols() != _cols || mask.planes() != _planes )
     299              :     {
     300            3 :         throw mx::exception( error_t::sizeerr, "mask dimensions must match cube dimensions" );
     301              :     }
     302              : 
     303           19 :     if( !math::isFinite( minGoodFract ) || minGoodFract < 0.0 || minGoodFract > 1.0 )
     304              :     {
     305           12 :         throw mx::exception( error_t::invalidarg, "minGoodFract must be finite and in [0, 1]" );
     306              :     }
     307           15 : }
     308              : 
     309              : template <typename dataT>
     310            6 : void eigenCube<dataT>::validateWeights( const std::vector<dataT> &weights ) const
     311              : {
     312            6 :     if( weights.size() != static_cast<size_t>( _planes ) )
     313              :     {
     314            6 :         throw mx::exception( error_t::sizeerr, "weights size must match cube planes" );
     315              :     }
     316            4 : }
     317              : 
     318              : template <typename dataT>
     319           15 : bool eigenCube<dataT>::hasEnoughGoodPixels( size_t goodPixels, double minGoodFract ) const
     320              : {
     321           15 :     return goodPixels > 0 && static_cast<double>( goodPixels ) >= minGoodFract * static_cast<double>( _planes );
     322              : }
     323              : 
     324              : template <typename dataT>
     325           35 : eigenCube<dataT>::eigenCube()
     326              : {
     327           35 :     _rows = 0;
     328           35 :     _cols = 0;
     329           35 :     _planes = 0;
     330           35 :     _owner = false;
     331           35 : }
     332              : 
     333              : template <typename dataT>
     334           17 : eigenCube<dataT>::eigenCube( Index nrows, Index ncols, Index nplanes )
     335              : {
     336           17 :     _rows = nrows;
     337           17 :     _cols = ncols;
     338           17 :     _planes = nplanes;
     339              : 
     340           17 :     m_data = new dataT[_rows * _cols * _planes];
     341           17 :     _owner = true;
     342           17 : }
     343              : 
     344              : template <typename dataT>
     345            1 : eigenCube<dataT>::eigenCube( dataT *ndata, size_t nrows, size_t ncols, size_t nplanes )
     346              : {
     347            1 :     _rows = nrows;
     348            1 :     _cols = ncols;
     349            1 :     _planes = nplanes;
     350              : 
     351            1 :     m_data = ndata;
     352            1 :     _owner = false;
     353            1 : }
     354              : 
     355              : template <typename dataT>
     356            1 : eigenCube<dataT>::eigenCube( const eigenCube<dataT> &ec ) : eigenCube()
     357              : {
     358            1 :     *this = ec;
     359            1 : }
     360              : 
     361              : template <typename dataT>
     362            1 : eigenCube<dataT>::eigenCube( eigenCube<dataT> &&ec ) noexcept
     363            1 :     : _rows( ec._rows ), _cols( ec._cols ), _planes( ec._planes ), m_data( ec.m_data ), _owner( ec._owner )
     364              : {
     365            1 :     ec._rows = 0;
     366            1 :     ec._cols = 0;
     367            1 :     ec._planes = 0;
     368            1 :     ec.m_data = nullptr;
     369            1 :     ec._owner = false;
     370            1 : }
     371              : 
     372              : template <typename dataT>
     373           54 : eigenCube<dataT>::~eigenCube()
     374              : {
     375           54 :     if( _owner && m_data )
     376              :     {
     377           44 :         delete[] m_data;
     378              :     }
     379           54 : }
     380              : 
     381              : template <typename dataT>
     382            7 : void eigenCube<dataT>::setZero()
     383              : {
     384            7 :     int N = _rows * _cols * _planes;
     385              : 
     386           47 :     for( int i = 0; i < N; ++i )
     387           40 :         m_data[i] = ( (dataT)0 );
     388            7 : }
     389              : 
     390              : template <typename dataT>
     391            4 : eigenCube<dataT> &eigenCube<dataT>::operator=( const eigenCube<dataT> &ec )
     392              : {
     393            4 :     if( this == &ec )
     394              :     {
     395            1 :         return *this;
     396              :     }
     397              : 
     398            3 :     resize( ec.rows(), ec.cols(), ec.planes() );
     399              : 
     400            3 :     int N = _rows * _cols * _planes;
     401              : 
     402      4194315 :     for( int i = 0; i < N; ++i )
     403      4194312 :         m_data[i] = ec.m_data[i];
     404              : 
     405            3 :     return *this;
     406              : }
     407              : 
     408              : template <typename dataT>
     409            2 : eigenCube<dataT> &eigenCube<dataT>::operator=( eigenCube<dataT> &&ec ) noexcept
     410              : {
     411            2 :     if( this == &ec )
     412              :     {
     413            1 :         return *this;
     414              :     }
     415              : 
     416            1 :     clear();
     417              : 
     418            1 :     _rows = ec._rows;
     419            1 :     _cols = ec._cols;
     420            1 :     _planes = ec._planes;
     421            1 :     m_data = ec.m_data;
     422            1 :     _owner = ec._owner;
     423              : 
     424            1 :     ec._rows = 0;
     425            1 :     ec._cols = 0;
     426            1 :     ec._planes = 0;
     427            1 :     ec.m_data = nullptr;
     428            1 :     ec._owner = false;
     429              : 
     430            1 :     return *this;
     431              : }
     432              : 
     433              : template <typename dataT>
     434            3 : void eigenCube<dataT>::shallowCopy( eigenCube<dataT> &src, bool takeOwner )
     435              : {
     436            3 :     if( this == &src )
     437              :     {
     438            1 :         return;
     439              :     }
     440              : 
     441            2 :     clear();
     442              : 
     443            2 :     _rows = src._rows;
     444            2 :     _cols = src._cols;
     445            2 :     _planes = src._planes;
     446            2 :     m_data = src.m_data;
     447              : 
     448            2 :     if( takeOwner == true )
     449              :     {
     450            1 :         _owner = src._owner;
     451            1 :         src._rows = 0;
     452            1 :         src._cols = 0;
     453            1 :         src._planes = 0;
     454            1 :         src.m_data = nullptr;
     455            1 :         src._owner = false;
     456              :     }
     457              :     else
     458              :     {
     459            1 :         _owner = false;
     460              :     }
     461              : }
     462              : 
     463              : template <typename dataT>
     464           38 : void eigenCube<dataT>::clear()
     465              : {
     466           38 :     if( _owner && m_data )
     467              :     {
     468            7 :         delete[] m_data;
     469              :     }
     470              : 
     471           38 :     _rows = 0;
     472           38 :     _cols = 0;
     473           38 :     _planes = 0;
     474           38 :     m_data = nullptr;
     475           38 :     _owner = false;
     476           38 : }
     477              : 
     478              : template <typename dataT>
     479           34 : void eigenCube<dataT>::resize( int r, int c, int p )
     480              : {
     481           34 :     clear();
     482              : 
     483           34 :     _rows = r;
     484           34 :     _cols = c;
     485           34 :     _planes = p;
     486              : 
     487     12714018 :     m_data = new dataT[_rows * _cols * _planes];
     488           34 :     _owner = true;
     489           34 : }
     490              : 
     491              : template <typename dataT>
     492            1 : void eigenCube<dataT>::resize( int r, int c )
     493              : {
     494            1 :     resize( r, c, 1 );
     495            1 : }
     496              : 
     497              : template <typename dataT>
     498          814 : dataT *eigenCube<dataT>::data()
     499              : {
     500          814 :     return m_data;
     501              : }
     502              : 
     503              : template <typename dataT>
     504            3 : const dataT *eigenCube<dataT>::data() const
     505              : {
     506            3 :     return m_data;
     507              : }
     508              : 
     509              : template <typename dataT>
     510     18303650 : const typename eigenCube<dataT>::Index eigenCube<dataT>::rows() const
     511              : {
     512     18303650 :     return _rows;
     513              : }
     514              : 
     515              : template <typename dataT>
     516     13976587 : const typename eigenCube<dataT>::Index eigenCube<dataT>::cols() const
     517              : {
     518     13976587 :     return _cols;
     519              : }
     520              : 
     521              : template <typename dataT>
     522       198454 : const typename eigenCube<dataT>::Index eigenCube<dataT>::planes() const
     523              : {
     524       198454 :     return _planes;
     525              : }
     526              : 
     527              : template <typename dataT>
     528            3 : Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> eigenCube<dataT>::cube()
     529              : {
     530            3 :     return Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>>( m_data, _rows * _cols, _planes );
     531              : }
     532              : 
     533              : template <typename dataT>
     534     50493946 : Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> eigenCube<dataT>::image( Index n )
     535              : {
     536     50493946 :     return Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>>( m_data + n * _rows * _cols, _rows, _cols );
     537              : }
     538              : 
     539              : template <typename dataT>
     540      4325376 : const Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> eigenCube<dataT>::image( Index n ) const
     541              : {
     542      4325376 :     return Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>>( m_data + n * _rows * _cols, _rows, _cols );
     543              : }
     544              : 
     545              : template <typename dataT>
     546              : Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>,
     547              :            Eigen::Unaligned,
     548              :            Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>>
     549          108 : eigenCube<dataT>::pixel( Index i, Index j )
     550              : {
     551              :     return Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>,
     552              :                       Eigen::Unaligned,
     553              :                       Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>>(
     554          108 :         m_data + j * _rows + i,
     555          108 :         _planes,
     556              :         1,
     557          216 :         Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>( 0, _rows * _cols ) );
     558              : }
     559              : 
     560              : template <typename dataT>
     561            3 : Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>> eigenCube<dataT>::asVectors()
     562              : {
     563            3 :     return Eigen::Map<Eigen::Array<dataT, Eigen::Dynamic, Eigen::Dynamic>>( m_data, _rows * _cols, _planes );
     564              : }
     565              : 
     566              : template <typename dataT>
     567            1 : void eigenCube<dataT>::Covar( Eigen::Matrix<dataT, Eigen::Dynamic, Eigen::Dynamic> &cv )
     568              : {
     569            1 :     cv = asVectors().matrix().transpose() * asVectors().matrix();
     570            1 : }
     571              : 
     572              : template <typename dataT>
     573              : template <typename eigenT>
     574              : void eigenCube<dataT>::sum( eigenT &mim )
     575              : {
     576              :     mim.resize( _rows, _cols );
     577              : 
     578              : #pragma omp parallel for schedule( static, 1 ) num_threads( Eigen::nbThreads() )
     579              :     for( Index i = 0; i < _rows; ++i )
     580              :     {
     581              :         for( Index j = 0; j < _cols; ++j )
     582              :         {
     583              :             mim( i, j ) = pixel( i, j ).sum();
     584              :         }
     585              :     }
     586              : }
     587              : 
     588              : template <typename dataT>
     589              : template <typename eigenT>
     590            2 : void eigenCube<dataT>::mean( eigenT &mim )
     591              : {
     592            2 :     mim.resize( _rows, _cols );
     593              : 
     594            2 : #pragma omp parallel for schedule( static, 1 ) num_threads( Eigen::nbThreads() )
     595              :     for( Index i = 0; i < _rows; ++i )
     596              :     {
     597              :         for( Index j = 0; j < _cols; ++j )
     598              :         {
     599              :             mim( i, j ) = pixel( i, j ).mean();
     600              :         }
     601              :     }
     602            2 : }
     603              : 
     604              : template <typename dataT>
     605              : template <typename eigenT, typename eigenCubeT>
     606            8 : void eigenCube<dataT>::mean( eigenT &mim, eigenCubeT &mask, double minGoodFract )
     607              : {
     608            8 :     validateMaskedCombination( mask, minGoodFract );
     609              : 
     610            6 :     mim.resize( _rows, _cols );
     611              : 
     612            6 : #pragma omp parallel
     613              :     {
     614              :         std::vector<dataT> work;
     615              : 
     616              : #pragma omp for
     617              :         for( Index i = 0; i < _rows; ++i )
     618              :         {
     619              :             for( Index j = 0; j < _cols; ++j )
     620              :             {
     621              : 
     622              :                 work.clear();
     623              : 
     624              :                 for( Index k = 0; k < _planes; ++k )
     625              :                 {
     626              :                     if( ( mask.pixel( i, j ) )( k, 0 ) == 1 )
     627              :                     {
     628              :                         work.push_back( ( pixel( i, j ) )( k, 0 ) );
     629              :                     }
     630              :                 }
     631              : 
     632              :                 if( hasEnoughGoodPixels( work.size(), minGoodFract ) )
     633              :                 {
     634              :                     mim( i, j ) = math::vectorMean( work );
     635              :                 }
     636              :                 else
     637              :                 {
     638              :                     mim( i, j ) = invalidNumber<Scalar>();
     639              :                 }
     640              :             }
     641              :         }
     642              :     }
     643            6 : }
     644              : 
     645              : template <typename dataT>
     646              : template <typename eigenT>
     647            2 : void eigenCube<dataT>::mean( eigenT &mim, std::vector<dataT> &weights )
     648              : {
     649            2 :     validateWeights( weights );
     650              : 
     651            1 :     mim.resize( _rows, _cols );
     652              : 
     653            1 : #pragma omp parallel num_threads( Eigen::nbThreads() )
     654              :     {
     655              :         std::vector<Scalar> work;
     656              : 
     657              : #pragma omp for schedule( static, 10 )
     658              :         for( Index i = 0; i < _rows; ++i )
     659              :         {
     660              :             for( Index j = 0; j < _cols; ++j )
     661              :             {
     662              :                 work.resize( _planes ); // work could be smaller after sigmaMean
     663              :                 // int ii=0;
     664              :                 for( int k = 0; k < _planes; ++k )
     665              :                     work[k] = ( pixel( i, j ) )( k, 0 );
     666              : 
     667              :                 mim( i, j ) = math::vectorMean( work, weights );
     668              :             }
     669              :         }
     670              :     }
     671            1 : }
     672              : 
     673              : template <typename dataT>
     674              : template <typename eigenT, typename eigenCubeT>
     675            1 : void eigenCube<dataT>::mean( eigenT &mim, std::vector<dataT> &weights, eigenCubeT &mask, double minGoodFract )
     676              : {
     677            1 :     validateMaskedCombination( mask, minGoodFract );
     678            1 :     validateWeights( weights );
     679              : 
     680            1 :     mim.resize( _rows, _cols );
     681              : 
     682            1 : #pragma omp parallel num_threads( Eigen::nbThreads() )
     683              :     {
     684              :         std::vector<Scalar> work, wwork;
     685              : 
     686              : #pragma omp for schedule( static, 10 )
     687              :         for( Index i = 0; i < _rows; ++i )
     688              :         {
     689              :             for( Index j = 0; j < _cols; ++j )
     690              :             {
     691              :                 work.clear();
     692              :                 wwork.clear();
     693              : 
     694              :                 // int ii=0;
     695              : 
     696              :                 for( Index k = 0; k < _planes; ++k )
     697              :                 {
     698              :                     if( ( mask.pixel( i, j ) )( k, 0 ) == 1 )
     699              :                     {
     700              :                         work.push_back( ( pixel( i, j ) )( k, 0 ) );
     701              :                         wwork.push_back( weights[k] );
     702              :                     }
     703              :                 }
     704              :                 if( hasEnoughGoodPixels( work.size(), minGoodFract ) )
     705              :                 {
     706              :                     mim( i, j ) = math::vectorMean( work, wwork );
     707              :                 }
     708              :                 else
     709              :                     mim( i, j ) = invalidNumber<Scalar>();
     710              :             }
     711              :         }
     712              :     }
     713            1 : }
     714              : 
     715              : template <typename dataT>
     716              : template <typename eigenT>
     717            2 : void eigenCube<dataT>::median( eigenT &mim )
     718              : {
     719            2 :     mim.resize( _rows, _cols );
     720              : 
     721            2 : #pragma omp parallel for schedule( static, 10 ) num_threads( Eigen::nbThreads() )
     722              :     for( Index i = 0; i < _rows; ++i )
     723              :     {
     724              :         // Eigen::Eigen::Array<Scalar, Eigen::Eigen::Dynamic, Eigen::Eigen::Dynamic> work;
     725              :         std::vector<Scalar> work;
     726              :         for( Index j = 0; j < _cols; ++j )
     727              :         {
     728              :             mim( i, j ) = imageMedian( pixel( i, j ), &work );
     729              :         }
     730              :     }
     731            2 : }
     732              : 
     733              : template <typename dataT>
     734              : template <typename eigenT, typename eigenCubeT>
     735            6 : void eigenCube<dataT>::median( eigenT &mim, eigenCubeT &mask, double minGoodFract )
     736              : {
     737            6 :     validateMaskedCombination( mask, minGoodFract );
     738              : 
     739            5 :     mim.resize( _rows, _cols );
     740              : 
     741            5 : #pragma omp parallel
     742              :     {
     743              :         std::vector<Scalar> work;
     744              : 
     745              : #pragma omp for
     746              :         for( Index i = 0; i < _rows; ++i )
     747              :         {
     748              :             for( Index j = 0; j < _cols; ++j )
     749              :             {
     750              :                 work.clear();
     751              : 
     752              :                 for( Index k = 0; k < _planes; ++k )
     753              :                 {
     754              :                     if( ( mask.pixel( i, j ) )( k, 0 ) == 1 )
     755              :                     {
     756              :                         work.push_back( ( pixel( i, j ) )( k, 0 ) );
     757              :                     }
     758              :                 }
     759              : 
     760              :                 if( hasEnoughGoodPixels( work.size(), minGoodFract ) )
     761              :                 {
     762              :                     mim( i, j ) = math::vectorMedianInPlace( work );
     763              :                 }
     764              :                 else
     765              :                 {
     766              :                     mim( i, j ) = invalidNumber<Scalar>();
     767              :                 }
     768              :             }
     769              :         }
     770              :     }
     771            5 : }
     772              : 
     773              : template <typename dataT>
     774              : template <typename eigenT>
     775            1 : void eigenCube<dataT>::sigmaMean( eigenT &mim, dataT sigma )
     776              : {
     777            1 :     mim.resize( _rows, _cols );
     778              : 
     779              :     // clang-format off
     780            1 :     #pragma omp parallel //clang-format on
     781              :     {
     782              :         std::vector<Scalar> work;
     783              : 
     784              :         // clang-format off
     785              :         #pragma omp for // clang-format off
     786              :         for( Index i = 0; i < _rows; ++i )
     787              :         {
     788              :             for( Index j = 0; j < _cols; ++j )
     789              :             {
     790              :                 work.resize( _planes );
     791              :                 for( int k = 0; k < _planes; ++k )
     792              :                 {
     793              :                     work[k] = ( pixel( i, j ) )( k, 0 );
     794              :                 }
     795              : 
     796              :                 mim( i, j ) = math::vectorSigmaMean( work, sigma );
     797              :             }
     798              :         }
     799              :     }
     800            1 : }
     801              : 
     802              : template <typename dataT>
     803              : template <typename eigenT, typename eigenCubeT>
     804            3 : void eigenCube<dataT>::sigmaMean( eigenT &mim, eigenCubeT &mask, dataT sigma, double minGoodFract )
     805              : {
     806            3 :     validateMaskedCombination( mask, minGoodFract );
     807              : 
     808            2 :     mim.resize( _rows, _cols );
     809              : 
     810            2 : #pragma omp parallel
     811              :     {
     812              :         std::vector<Scalar> work;
     813              : 
     814              : #pragma omp for
     815              :         for( Index i = 0; i < _rows; ++i )
     816              :         {
     817              :             for( Index j = 0; j < _cols; ++j )
     818              :             {
     819              :                 work.clear();
     820              :                 for( Index k = 0; k < _planes; ++k )
     821              :                 {
     822              :                     if( ( mask.pixel( i, j ) )( k, 0 ) == 1 )
     823              :                     {
     824              :                         work.push_back( ( pixel( i, j ) )( k, 0 ) );
     825              :                     }
     826              :                 }
     827              : 
     828              :                 if( hasEnoughGoodPixels( work.size(), minGoodFract ) )
     829              :                 {
     830              :                     mim( i, j ) = math::vectorSigmaMean( work, sigma );
     831              :                 }
     832              :                 else
     833              :                 {
     834              :                     mim( i, j ) = invalidNumber<Scalar>();
     835              :                 }
     836              :             }
     837              :         }
     838              :     }
     839            2 : }
     840              : 
     841              : template <typename dataT>
     842              : template <typename eigenT>
     843            2 : void eigenCube<dataT>::sigmaMean( eigenT &mim, std::vector<dataT> &weights, dataT sigma )
     844              : {
     845            2 :     validateWeights( weights );
     846              : 
     847            1 :     mim.resize( _rows, _cols );
     848              : 
     849            1 : #pragma omp parallel num_threads( Eigen::nbThreads() )
     850              :     {
     851              :         std::vector<Scalar> work;
     852              : 
     853              : #pragma omp for schedule( static, 10 )
     854              :         for( Index i = 0; i < _rows; ++i )
     855              :         {
     856              :             for( Index j = 0; j < _cols; ++j )
     857              :             {
     858              :                 work.resize( _planes ); // work could be smaller after sigmaMean
     859              :                 for( int k = 0; k < _planes; ++k )
     860              :                     work[k] = ( pixel( i, j ) )( k, 0 );
     861              : 
     862              :                 mim( i, j ) = math::vectorSigmaMean( work, weights, sigma );
     863              :             }
     864              :         }
     865              :     }
     866            1 : }
     867              : 
     868              : template <typename dataT>
     869              : template <typename eigenT, typename eigenCubeT>
     870            2 : void eigenCube<dataT>::sigmaMean(
     871              :     eigenT &mim, std::vector<dataT> &weights, eigenCubeT &mask, dataT sigma, double minGoodFract )
     872              : {
     873            2 :     validateMaskedCombination( mask, minGoodFract );
     874            1 :     validateWeights( weights );
     875              : 
     876            1 :     mim.resize( _rows, _cols );
     877              : 
     878            1 : #pragma omp parallel num_threads( Eigen::nbThreads() )
     879              :     {
     880              :         std::vector<Scalar> work, wwork;
     881              : 
     882              : #pragma omp for schedule( static, 10 )
     883              :         for( Index i = 0; i < _rows; ++i )
     884              :         {
     885              :             for( Index j = 0; j < _cols; ++j )
     886              :             {
     887              :                 work.clear();
     888              :                 wwork.clear();
     889              : 
     890              :                 for( Index k = 0; k < _planes; ++k )
     891              :                 {
     892              :                     if( ( mask.pixel( i, j ) )( k, 0 ) == 1 )
     893              :                     {
     894              :                         work.push_back( ( pixel( i, j ) )( k, 0 ) );
     895              :                         wwork.push_back( weights[k] );
     896              :                     }
     897              :                 }
     898              :                 if( hasEnoughGoodPixels( work.size(), minGoodFract ) )
     899              :                 {
     900              :                     mim( i, j ) = math::vectorSigmaMean( work, wwork, sigma );
     901              :                 }
     902              :                 else
     903              :                     mim( i, j ) = invalidNumber<Scalar>();
     904              :             }
     905              :         }
     906              :     }
     907            1 : }
     908              : 
     909              : } // namespace improc
     910              : 
     911              : } // namespace mx
     912              : 
     913              : #endif // eigenCube_hpp
        

Generated by: LCOV version 2.0-1