/*========================================================================= Program: Tensor ToolKit - TTK Module: $URL$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itkMatrixOffsetTensorTransformBase_txx #define _itkMatrixOffsetTensorTransformBase_txx #include "itkNumericTraits.h" #include "itkMatrixOffsetTensorTransformBase.h" #include "vnl/algo/vnl_matrix_inverse.h" namespace itk { // Constructor with default arguments template MatrixOffsetTensorTransformBase ::MatrixOffsetTensorTransformBase() : Superclass(OutputSpaceDimension, ParametersDimension) { m_Matrix.SetIdentity(); m_Rigid.SetIdentity(); m_MatrixMTime.Modified(); m_Offset.Fill( 0 ); m_Center.Fill( 0 ); m_Translation.Fill( 0 ); m_Singular = false; m_InverseMatrix.SetIdentity(); m_InverseMatrixMTime = m_MatrixMTime; this->m_FixedParameters.SetSize ( NInputDimensions ); this->m_FixedParameters.Fill ( 0.0 ); } // Constructor with default arguments template MatrixOffsetTensorTransformBase ::MatrixOffsetTensorTransformBase( unsigned int outputDims, unsigned int paramDims ) : Superclass(outputDims, paramDims) { m_Matrix.SetIdentity(); m_Rigid.SetIdentity(); m_MatrixMTime.Modified(); m_Offset.Fill( 0 ); m_Center.Fill( 0 ); m_Translation.Fill( 0 ); m_Singular = false; m_InverseMatrix.SetIdentity(); m_InverseMatrixMTime = m_MatrixMTime; } // Constructor with explicit arguments template MatrixOffsetTensorTransformBase ::MatrixOffsetTensorTransformBase(const MatrixType &matrix, const OutputVectorType &offset) { m_Matrix = matrix; m_MatrixMTime.Modified(); m_Offset = offset; m_Center.Fill( 0 ); m_Translation.Fill(0); for(unsigned int i=0; iComputeMatrixParameters(); this->ComputeRigidPartOfTransform(); } // Destructor template MatrixOffsetTensorTransformBase ::~MatrixOffsetTensorTransformBase() { return; } // Print self template void MatrixOffsetTensorTransformBase ::PrintSelf(std::ostream &os, Indent indent) const { Superclass::PrintSelf(os,indent); unsigned int i, j; os << indent << "Matrix: " << std::endl; for (i = 0; i < NInputDimensions; i++) { os << indent.GetNextIndent(); for (j = 0; j < NOutputDimensions; j++) { os << m_Matrix[i][j] << " "; } os << std::endl; } os << indent << "Rigid: " << std::endl; for (i = 0; i < NInputDimensions; i++) { os << indent.GetNextIndent(); for (j = 0; j < NOutputDimensions; j++) { os << m_Rigid[i][j] << " "; } os << std::endl; } os << indent << "Offset: " << m_Offset << std::endl; os << indent << "Center: " << m_Center << std::endl; os << indent << "Translation: " << m_Translation << std::endl; os << indent << "Inverse: " << std::endl; for (i = 0; i < NInputDimensions; i++) { os << indent.GetNextIndent(); for (j = 0; j < NOutputDimensions; j++) { os << this->GetInverseMatrix()[i][j] << " "; } os << std::endl; } os << indent << "Singular: " << m_Singular << std::endl; } // Constructor with explicit arguments template void MatrixOffsetTensorTransformBase ::SetIdentity( void ) { m_Matrix.SetIdentity(); m_Rigid.SetIdentity(); m_MatrixMTime.Modified(); m_Offset.Fill( 0.0 ); m_Translation.Fill( 0.0 ); m_Center.Fill( 0.0 ); m_Singular = false; m_InverseMatrix.SetIdentity(); m_InverseMatrixMTime = m_MatrixMTime; this->Modified(); } // Compose with another affine transformation template void MatrixOffsetTensorTransformBase ::Compose(const Self * other, bool pre) { if (pre) { m_Offset = m_Matrix * other->m_Offset + m_Offset; m_Matrix = m_Matrix * other->m_Matrix; } else { m_Offset = other->m_Matrix * m_Offset + other->m_Offset; m_Matrix = other->m_Matrix * m_Matrix; } this->ComputeTranslation(); this->ComputeMatrixParameters(); this->ComputeRigidPartOfTransform(); m_MatrixMTime.Modified(); this->Modified(); return; } // Transform a point template typename MatrixOffsetTensorTransformBase::OutputPointType MatrixOffsetTensorTransformBase ::TransformPoint(const InputPointType &point) const { return m_Matrix * point + m_Offset; } // Transform a vector template typename MatrixOffsetTensorTransformBase::OutputVectorType MatrixOffsetTensorTransformBase ::TransformVector(const InputVectorType &vect) const { return m_Matrix * vect; } // Transform a vnl_vector_fixed template typename MatrixOffsetTensorTransformBase::OutputVnlVectorType MatrixOffsetTensorTransformBase ::TransformVector(const InputVnlVectorType &vect) const { return m_Matrix * vect; } // Transform a vector template typename MatrixOffsetTensorTransformBase::OutputVectorType MatrixOffsetTensorTransformBase ::InverseTransformVector(const InputVectorType &vect) const { return this->GetInverseMatrix() * vect; } // Transform a vnl_vector_fixed template typename MatrixOffsetTensorTransformBase::OutputVnlVectorType MatrixOffsetTensorTransformBase ::InverseTransformVector(const InputVnlVectorType &vect) const { return this->GetInverseMatrix() * vect; } // Transform a CovariantVector template typename MatrixOffsetTensorTransformBase::OutputCovariantVectorType MatrixOffsetTensorTransformBase ::TransformCovariantVector(const InputCovariantVectorType &vec) const { OutputCovariantVectorType result; // Converted vector for (unsigned int i = 0; i < NOutputDimensions; i++) { result[i] = NumericTraits::Zero; for (unsigned int j = 0; j < NInputDimensions; j++) { result[i] += this->GetInverseMatrix()[j][i]*vec[j]; // Inverse transposed } } return result; } // Transform a Tensor template typename MatrixOffsetTensorTransformBase::OutputTensorType MatrixOffsetTensorTransformBase ::TransformTensor(const InputTensorType &tensor) const { // rotate w.r.t the rigid part of the transform OutputTensorType TENS; auto matrix = tensor.ApplyMatrix(static_cast>(m_Rigid.GetTranspose())); TENS.SetVnlMatrix(matrix.as_ref()); return TENS; } // Transform a Tensor template typename MatrixOffsetTensorTransformBase::OutputTensorType MatrixOffsetTensorTransformBase ::TransformTensorReverse(const InputTensorType &tensor) const { // rotate w.r.t the rigid part of the transform OutputTensorType TENS; auto matrix = tensor.GetVnlMatrix() * m_Rigid.GetVnlMatrix(); TENS.SetVnlMatrix(matrix.as_ref()); return TENS; } // Transform a Tensor with Finiste Strain (FS) reorientation strategy template typename MatrixOffsetTensorTransformBase::OutputTensorType MatrixOffsetTensorTransformBase ::TransformTensorWithFS(const InputTensorType &tensor) const { // rotate w.r.t the rigid part of the transform OutputTensorType TENS; auto matrix = tensor.ApplyMatrix(static_cast>(m_Rigid.GetTranspose())); TENS.SetVnlMatrix(matrix.as_ref()); return TENS; } // Transform a Tensor with Preservation of Principal Direction (PPD) reorientation strategy template typename MatrixOffsetTensorTransformBase::OutputTensorType MatrixOffsetTensorTransformBase ::TransformTensorWithPPD(const InputTensorType &tensor) const { // rotate preserving the principal direction affine transformation // The PPD only works with 3D tensors! if ((NInputDimensions > 3) || (NOutputDimensions > 3) || (NInputDimensions != NOutputDimensions)) return tensor; InputVectorType E1 = tensor.GetEigenvector(2); InputVectorType E2 = tensor.GetEigenvector(1); InputVectorType E3 = tensor.GetEigenvector(0); TScalarType e1 = tensor.GetEigenvalue(2); TScalarType e2 = tensor.GetEigenvalue(1); TScalarType e3 = tensor.GetEigenvalue(0); E1 = this->InverseTransformVector(E1); E1 /= E1.GetNorm(); E2 = this->InverseTransformVector(E2); E2 = E2 - E1*(E1*E2); E2 /= E2.GetNorm(); E3 = CrossProduct(E1,E2); OutputTensorType TENS; TENS = e1*Tensor(E1) + e2*Tensor(E2) + e3*Tensor(E3); return TENS; } // Recompute the inverse matrix (internal) template const typename MatrixOffsetTensorTransformBase::InverseMatrixType & MatrixOffsetTensorTransformBase ::GetInverseMatrix( void ) const { // If the transform has been modified we recompute the inverse if(m_InverseMatrixMTime != m_MatrixMTime) { m_Singular = false; try { m_InverseMatrix = m_Matrix.GetInverse(); } catch(...) { m_Singular = true; } m_InverseMatrixMTime = m_MatrixMTime; } return m_InverseMatrix; } // return an inverse transformation template bool MatrixOffsetTensorTransformBase ::GetInverse( Self * inverse) const { if(!inverse) { return false; } this->GetInverseMatrix(); if(m_Singular) { return false; } inverse->m_Matrix = this->GetInverseMatrix(); inverse->m_InverseMatrix = m_Matrix; inverse->m_Offset = -(this->GetInverseMatrix() * m_Offset); inverse->ComputeTranslation(); inverse->ComputeMatrixParameters(); inverse->ComputeRigidPartOfTransform(); return true; } // Get fixed parameters template void MatrixOffsetTensorTransformBase ::SetFixedParameters( const ParametersType & fp ) { this->m_FixedParameters = fp; InputPointType c; for ( unsigned int i = 0; i < NInputDimensions; i++ ) { c[i] = this->m_FixedParameters[i]; } this->SetCenter ( c ); } /** Get the Fixed Parameters. */ template const typename MatrixOffsetTensorTransformBase::ParametersType & MatrixOffsetTensorTransformBase ::GetFixedParameters(void) const { this->m_FixedParameters.SetSize ( NInputDimensions ); for ( unsigned int i = 0; i < NInputDimensions; i++ ) { this->m_FixedParameters[i] = this->m_Center[i]; } return this->m_FixedParameters; } // Get parameters template const typename MatrixOffsetTensorTransformBase::ParametersType & MatrixOffsetTensorTransformBase ::GetParameters( void ) const { // Transfer the linear part unsigned int par = 0; for(unsigned int row=0; rowm_Parameters[par] = m_Matrix[row][col]; ++par; } } // Transfer the constant part for(unsigned int i=0; im_Parameters[par] = m_Translation[i]; ++par; } return this->m_Parameters; } // Set parameters template void MatrixOffsetTensorTransformBase ::SetParameters( const ParametersType & parameters ) { unsigned int par = 0; this->m_Parameters = parameters; for(unsigned int row=0; rowm_Parameters[par]; ++par; } } // Transfer the constant part for(unsigned int i=0; im_Parameters[par]; ++par; } m_MatrixMTime.Modified(); this->ComputeMatrix(); // Not necessary since parameters explicitly define // the matrix this->ComputeOffset(); this->ComputeRigidPartOfTransform(); // Modified is always called since we just have a pointer to the // parameters and cannot know if the parameters have changed. this->Modified(); } // Compute the Jacobian in one position template const typename MatrixOffsetTensorTransformBase::JacobianType & MatrixOffsetTensorTransformBase ::GetJacobian( const InputPointType & p ) const { // The Jacobian of the affine transform is composed of // subblocks of diagonal matrices, each one of them having // a constant value in the diagonal. this->m_Jacobian.Fill( 0.0 ); unsigned int blockOffset = 0; for(unsigned int block=0; block < NInputDimensions; block++) { for(unsigned int dim=0; dim < NOutputDimensions; dim++ ) { this->m_Jacobian( block , blockOffset + dim ) = p[dim]; } blockOffset += NInputDimensions; } for(unsigned int dim=0; dim < NOutputDimensions; dim++ ) { this->m_Jacobian( dim , blockOffset + dim ) = 1.0; } return this->m_Jacobian; } // Computes offset based on center, matrix, and translation variables template void MatrixOffsetTensorTransformBase ::ComputeOffset( void ) { const MatrixType & matrix = this->GetMatrix(); OffsetType offset; for(unsigned int i=0; i void MatrixOffsetTensorTransformBase ::ComputeTranslation( void ) { const MatrixType & matrix = this->GetMatrix(); OffsetType translation; for(unsigned int i=0; i void MatrixOffsetTensorTransformBase ::ComputeMatrix( void ) { // Since parameters explicitly define the matrix in this base class, this // function does nothing. Normally used to compute a matrix when // its parameterization (e.g., the class' versor) is modified. } // Computes parameters - base class does nothing. In derived classes is // used to convert, for example, matrix into a versor template void MatrixOffsetTensorTransformBase ::ComputeMatrixParameters( void ) { // Since parameters explicitly define the matrix in this base class, this // function does nothing. Normally used to update the parameterization // of the matrix (e.g., the class' versor) when the matrix is explicitly // set. } template void MatrixOffsetTensorTransformBase ::ComputeRigidPartOfTransform( void ) { vnl_matrix_fixed MMt = (m_Matrix.GetVnlMatrix() * m_Matrix.GetTranspose()).as_matrix(); InputTensorType T; T.SetVnlMatrix (MMt.as_matrix()); T = T.InvSqrt(); vnl_matrix res = T.GetVnlMatrix()*m_Matrix.GetVnlMatrix(); for( unsigned int i=0; i