25 #ifndef WSYMMETRICSPHERICALHARMONIC_H
26 #define WSYMMETRICSPHERICALHARMONIC_H
33 #include <boost/math/special_functions/spherical_harmonic.hpp>
35 #include "core/common/WLogger.h"
36 #include "core/common/math/WGeometryFunctions.h"
37 #include "../exceptions/WPreconditionNotMet.h"
38 #include "linearAlgebra/WVectorFixed.h"
39 #include "WLinearAlgebraFunctions.h"
42 #include "WTensorSym.h"
43 #include "WUnitSphereCoordinates.h"
286 template<
typename T >
289 m_SHCoefficients( 0 )
293 template<
typename T >
295 m_SHCoefficients( SHCoefficients )
299 T q = std::sqrt( 0.25 + 2.0 *
static_cast< T
>(
m_SHCoefficients.size() ) ) - 1.5;
300 m_order =
static_cast<size_t>( q );
303 template<
typename T >
308 template<
typename T >
313 const T rootOf2 = std::sqrt( 2.0 );
314 for(
int k = 0; k <= static_cast<int>( m_order ); k+=2 )
317 for(
int m = 1; m <= k; m++ )
319 j = ( k*k+k+2 ) / 2 + m;
320 result += m_SHCoefficients[ j-1 ] * rootOf2 *
321 static_cast< T
>( std::pow( -1.0, m+1 ) ) * boost::math::spherical_harmonic_i( k, m, theta, phi );
324 result += m_SHCoefficients[ ( k*k+k+2 ) / 2 - 1 ] * boost::math::spherical_harmonic_r( k, 0, theta, phi );
326 for(
int m = -k; m < 0; m++ )
328 j = ( k*k+k+2 ) / 2 + m;
329 result += m_SHCoefficients[ j-1 ] * rootOf2 * boost::math::spherical_harmonic_r( k, -m, theta, phi );
335 template<
typename T >
341 template<
typename T >
344 return m_SHCoefficients;
347 template<
typename T >
352 for(
int l = 0; l <= static_cast< int >( m_order ); l += 2 )
354 for(
int m = -l; m <= l; ++m )
356 res[ k ] = m_SHCoefficients[ k ];
357 if( m < 0 && ( ( -m ) % 2 == 1 ) )
361 else if( m > 0 && ( m % 2 == 0 ) )
371 template<
typename T >
376 T r = 1.0 / sqrt( 2.0 );
377 std::complex< T > i( 0.0, -1.0 );
378 for(
int l = 0; l <= static_cast< int >( m_order ); l += 2 )
380 for(
int m = -l; m <= l; ++m )
384 res[ k ] = m_SHCoefficients[ k ];
388 res[ k ] += i * r * m_SHCoefficients[ k - 2 * m ];
389 res[ k ] += ( -m % 2 == 1 ? -r : r ) * m_SHCoefficients[ k ];
393 res[ k ] += i * ( -m % 2 == 0 ? -r : r ) * m_SHCoefficients[ k ];
394 res[ k ] += r * m_SHCoefficients[ k - 2 * m ];
402 template<
typename T >
405 if( order < 0 || order % 2 == 1 )
411 int elements = ( m_order + 1 ) * ( m_order + 2 ) / 2;
412 m_SHCoefficients.resize( elements );
413 for(
int k = 0; k < elements; ++k )
415 m_SHCoefficients[ k ] = 0.0;
419 T r = 1.0 / sqrt( 2.0 );
420 std::complex< T > i( 0.0, -1.0 );
421 for(
int l = 0; l <= static_cast< int >( m_order ); l += 2 )
423 if( ( l + 1 ) * ( l + 2 ) > 2 *
static_cast< int >( coeffs.size() ) )
428 for(
int m = -l; m <= l; ++m )
432 m_SHCoefficients[ k ] = coeffs[ k ].real();
436 m_SHCoefficients[ k ] = std::complex< T >( r * coeffs[ k - 2 * m ] ).real();
437 m_SHCoefficients[ k ] += std::complex< T >( ( -m % 2 == 0 ? r : -r ) * coeffs[ k ] ).real();
441 m_SHCoefficients[ k ] = std::complex< T >( i * ( m % 2 == 1 ? -r : r ) * coeffs[ k ] ).real();
442 m_SHCoefficients[ k ] += std::complex< T >( -r * i * coeffs[ k - 2 * m ] ).real();
449 template<
typename T >
452 T n =
static_cast< T
>( orientations.size() );
456 std::vector< T > v( orientations.size() );
458 for( std::size_t i = 0; i < orientations.size(); ++i )
460 v[ i ] = getValue( orientations[ i ] );
465 for( std::size_t i = 0; i < orientations.size(); ++i )
474 if( gfa == 0.0 || n <= 1.0 )
479 gfa = sqrt( ( n * d ) / ( ( n - 1.0 ) * gfa ) );
481 WAssert( gfa >= -0.01 && gfa <= 1.01,
"" );
493 template<
typename T >
498 WAssert( B.
getNbCols() == m_SHCoefficients.size(),
"" );
499 for( std::size_t k = 0; k < B.
getNbCols(); ++k )
501 s( k, 0 ) = m_SHCoefficients[ k ];
511 for( std::size_t i = 0; i < s.
getNbRows(); ++i )
517 for( std::size_t i = 0; i < s.
getNbRows(); ++i )
526 if( gfa == 0.0 || n <= 1.0 )
531 gfa = sqrt( ( n * d ) / ( ( n - 1.0 ) * gfa ) );
533 WAssert( gfa >= -0.01 && gfa <= 1.01,
"" );
545 template<
typename T >
548 WAssert( frtMat.
getNbCols() == m_SHCoefficients.size(),
"" );
549 WAssert( frtMat.
getNbRows() == m_SHCoefficients.size(),
"" );
551 for(
size_t j = 0; j < m_SHCoefficients.size(); j++ )
553 m_SHCoefficients[ j ] *= frtMat( j, j );
557 template<
typename T >
563 template<
typename T >
570 std::vector< WUnitSphereCoordinates< T > > sphereCoordinates;
571 for(
typename std::vector<
WMatrixFixed< T, 3, 1 > >::const_iterator it = orientations.begin(); it != orientations.end(); it++ )
578 template<
typename T >
593 result = pseudoInverse( result )*Bt;
597 return ( P * result );
602 template<
typename T >
608 std::vector< WUnitSphereCoordinates< T > > sphereCoordinates;
609 for(
typename std::vector<
WMatrixFixed< T, 3, 1 > >::const_iterator it = orientations.begin(); it != orientations.end(); it++ )
616 template<
typename T >
633 result = pseudoInverse( result )*Bt;
648 T correctionFactor = 1.0 / ( 16.0 * std::pow(
static_cast< T
>( pi() ), 2 ) );
649 result *= correctionFactor;
655 template<
typename T >
659 WMatrix< T > B( orientations.size(), ( ( order + 1 ) * ( order + 2 ) ) / 2 );
663 const T rootOf2 = std::sqrt( 2.0 );
664 for( uint32_t row = 0; row < orientations.size(); row++ )
666 const T theta = orientations[row].getTheta();
667 const T phi = orientations[row].getPhi();
668 for(
int k = 0; k <= order; k+=2 )
671 for(
int m = 1; m <= k; m++ )
673 j = ( k * k + k + 2 ) / 2 + m;
674 B( row, j-1 ) = rootOf2 *
static_cast< T
>( std::pow(
static_cast< T
>( -1 ), m + 1 ) )
675 * boost::math::spherical_harmonic_i( k, m, theta, phi );
678 B( row, ( k * k + k + 2 ) / 2 - 1 ) = boost::math::spherical_harmonic_r( k, 0, theta, phi );
680 for(
int m = -k; m < 0; m++ )
682 j = ( k * k + k + 2 ) / 2 + m;
683 B( row, j-1 ) = rootOf2*boost::math::spherical_harmonic_r( k, -m, theta, phi );
690 template<
typename T >
696 for( std::size_t row = 0; row < orientations.size(); row++ )
698 const T theta = orientations[ row ].getTheta();
699 const T phi = orientations[ row ].getPhi();
702 for(
int k = 0; k <= order; k += 2 )
704 for(
int m = -k; m < 0; m++ )
706 B( row, j ) = boost::math::spherical_harmonic( k, m, theta, phi );
709 B( row, j ) = boost::math::spherical_harmonic( k, 0, theta, phi );
711 for(
int m = 1; m <= k; m++ )
713 B( row, j ) = boost::math::spherical_harmonic( k, m, theta, phi );
721 template<
typename T >
724 size_t R = ( ( order + 1 ) * ( order + 2 ) ) / 2;
727 for(
size_t k = 0; k <= order; k += 2 )
729 for(
int m = -
static_cast< int >( k ); m <= static_cast< int >( k ); ++m )
731 result[ i ] = -
static_cast< T
> ( k * ( k + 1 ) );
738 template<
typename T >
743 for( std::size_t i = 0; i < eigenvalues.
size(); ++i )
745 L( i, i ) = eigenvalues[ i ];
750 template<
typename T >
755 for( std::size_t i = 0; i < eigenvalues.
size(); ++i )
757 L( i, i ) = std::pow( eigenvalues[ i ], 2 );
762 template<
typename T >
765 size_t R = ( ( order + 1 ) * ( order + 2 ) ) / 2;
768 for(
size_t k = 0; k <= order; k += 2 )
770 T h = 2.0 *
static_cast< T
>( pi() ) *
static_cast< T
>( std::pow(
static_cast< T
>( -1 ),
static_cast< T
>( k / 2 ) ) ) *
771 static_cast< T
>( oddFactorial( ( k <= 1 ) ? 1 : k - 1 ) ) /
static_cast< T
>( evenFactorial( k ) );
772 for(
int m = -
static_cast< int >( k ); m <= static_cast< int >( k ); ++m )
781 template<
typename T >
784 std::vector< WVector3d > vertices;
785 std::vector< unsigned int > triangles;
787 int level =
static_cast< int >( log(
static_cast< float >( ( order + 1 ) * ( order + 2 ) ) ) / 2.0f + 1.0f );
788 tesselateIcosahedron( &vertices, &triangles, level );
789 std::vector< WUnitSphereCoordinates< T > > orientations;
790 for(
typename std::vector< WVector3d >::const_iterator cit = vertices.begin(); cit != vertices.end(); cit++ )
793 if( ( *cit )[ 0 ] >= 0.0001 )
801 template<
typename T >
805 std::size_t numElements = ( order + 1 ) * ( order + 2 ) / 2;
806 WPrecondEquals( order % 2, 0u );
807 WPrecondLess( numElements, orientations.size() + 1 );
810 std::vector< WMatrixFixed< T, 3, 1 > > directions( numElements );
811 for( std::size_t i = 0; i < numElements; ++i )
813 directions[ i ] = orientations[ i ].getEuclidean();
817 std::vector< std::size_t > indices( order, 0 );
821 for( std::size_t j = 0; j < numElements; ++j )
824 std::size_t amount[ 3 ] = { 0, 0, 0 };
825 for( std::size_t k = 0; k < order; ++k )
827 ++amount[ indices[ k ] ];
831 std::size_t multiplicity = calcSupersymmetricTensorMultiplicity( order, amount[ 0 ], amount[ 1 ], amount[ 2 ] );
832 for( std::size_t i = 0; i < numElements; ++i )
834 TEMat( i, j ) = multiplicity;
835 for( std::size_t k = 0; k < order; ++k )
837 TEMat( i, j ) *= directions[ i ][ indices[ k ] ];
842 positionIterateSortedOneStep( order, 3, indices );
847 std::vector< WUnitSphereCoordinates< T > > ori2( orientations.begin(), orientations.begin() + numElements );
851 WAssert( ( TEMat*p ).isIdentity( 1e-3 ),
"Test of inverse matrix failed. Are the given orientations linear independent?" );
853 return p * calcBaseMatrix( ori2, order );
856 template<
typename T >
860 if( m_SHCoefficients.size() > 0 )
862 scale = std::sqrt( 4.0 *
static_cast< T
>( pi() ) ) * m_SHCoefficients[0];
864 for(
size_t i = 0; i < m_SHCoefficients.size(); i++ )
866 m_SHCoefficients[ i ] /= scale;
Matrix template class with variable number of rows and columns.
size_t getNbRows() const
Get number of rows.
WMatrix transposed() const
Returns the transposed matrix.
size_t getNbCols() const
Get number of columns.
Class for symmetric spherical harmonics The index scheme of the coefficients/basis values is like in ...
const WValue< T > & getCoefficients() const
Returns the used coefficients (stored like in the mentioned 2007 Descoteaux paper).
static WMatrix< T > calcSHToTensorSymMatrix(std::size_t order)
Calculates a matrix that converts spherical harmonics to symmetric tensors of equal or lower order.
WSymmetricSphericalHarmonic()
Default constructor.
static WMatrix< T > getSHFittingMatrixForConstantSolidAngle(const std::vector< WMatrixFixed< T, 3, 1 > > &orientations, int order, T lambda)
This calculates the transformation/fitting matrix T like in the 2010 Aganj paper.
static WMatrix< T > calcSmoothingMatrix(size_t order)
This calcs the smoothing matrix L from the 2007 Descoteaux Paper "Regularized, Fast,...
void setFromComplex(WValue< std::complex< T > > const &coeffs, int order)
Set the coeffs from complex base coeffs.
static WValue< T > calcEigenvalues(size_t order)
Calc eigenvalues for SH elements.
static WMatrix< T > calcBaseMatrix(const std::vector< WUnitSphereCoordinates< T > > &orientations, int order)
Calculates the base matrix B like in the dissertation of Descoteaux.
size_t m_order
order of the spherical harmonic
T calcGFA(std::vector< WUnitSphereCoordinates< T > > const &orientations) const
Calculate the generalized fractional anisotropy for this ODF.
static WMatrix< T > calcFRTMatrix(size_t order)
Calculates the Funk-Radon-Transformation-Matrix P from the 2007 Descoteaux Paper "Regularized,...
size_t getOrder() const
Return the order of the spherical harmonic.
virtual ~WSymmetricSphericalHarmonic()
Destructor.
void applyFunkRadonTransformation(WMatrix< T > const &frtMat)
Applies the Funk-Radon-Transformation.
WValue< T > getCoefficientsSchultz() const
Returns the coefficients for Schultz' SH base.
static WMatrix< T > calcMatrixWithEigenvalues(size_t order)
Calc matrix with the eigenvalues of the SH elements on its diagonal.
void normalize()
Normalize this SH in place.
static WMatrix< T > getSHFittingMatrix(const std::vector< WMatrixFixed< T, 3, 1 > > &orientations, int order, T lambda, bool withFRT)
This calculates the transformation/fitting matrix T like in the 2007 Descoteaux paper.
WValue< T > m_SHCoefficients
coefficients of the spherical harmonic
WValue< std::complex< T > > getCoefficientsComplex() const
Returns the coefficients for the complex base.
static WMatrix< std::complex< T > > calcComplexBaseMatrix(std::vector< WUnitSphereCoordinates< T > > const &orientations, int order)
Calculates the base matrix B for the complex spherical harmonics.
T getValue(T theta, T phi) const
Return the value on the sphere.
This class stores coordinates on the unit sphere.
T getTheta() const
Return the theta angle.
T getPhi() const
Return the phi angle.
Base class for all higher level values like tensors, vectors, matrices and so on.
size_t size() const
Get number of components the value consists of.
WStreamedLogger debug(const std::string &source)
Logging a debug message.