/*========================================================================= Program: vv http://www.creatis.insa-lyon.fr/rio/vv Authors belong to: - University of LYON http://www.universite-lyon.fr/ - Léon Bérard cancer center http://www.centreleonberard.fr - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copyright notices for more information. It is distributed under dual licence - BSD See included LICENSE.txt file - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html ===========================================================================**/ #ifndef __clitkMultipleBSplineDeformableTransform_txx #define __clitkMultipleBSplineDeformableTransform_txx // clitk #include "clitkMultipleBSplineDeformableTransformInitializer.h" // itk #include namespace clitk { // Constructor with default arguments template MultipleBSplineDeformableTransform::MultipleBSplineDeformableTransform() : Superclass(0) { m_nLabels = 1; m_labels = 0; m_labelInterpolator = 0; m_trans.resize(1); m_trans[0] = TransformType::New(); m_parameters.resize(1); this->m_FixedParameters.SetSize(NInputDimensions * (NInputDimensions + 5) + 4); this->m_FixedParameters.Fill(0.0); m_InternalParametersBuffer = ParametersType(0); // Make sure the parameters pointer is not NULL after construction. m_InputParametersPointer = &m_InternalParametersBuffer; m_BulkTransform = 0; m_LastJacobian = -1; } template MultipleBSplineDeformableTransform ::~MultipleBSplineDeformableTransform() { } template void MultipleBSplineDeformableTransform ::SetLabels(ImageLabelPointer labels) { GetFixedParameters(); // Update m_FixedParameters if (labels) { typedef itk::RelabelComponentImageFilter RelabelImageFilterType; typename RelabelImageFilterType::Pointer relabelImageFilter = RelabelImageFilterType::New(); relabelImageFilter->SetInput(labels); relabelImageFilter->Update(); m_labels = relabelImageFilter->GetOutput(); m_nLabels = relabelImageFilter->GetNumberOfObjects(); m_trans.resize(m_nLabels); m_parameters.resize(m_nLabels); for (unsigned i = 0; i < m_nLabels; ++i) m_trans[i] = TransformType::New(); m_labelInterpolator = ImageLabelInterpolator::New(); m_labelInterpolator->SetInputImage(m_labels); } else { m_nLabels = 1; m_trans.resize(1); m_parameters.resize(1); m_trans[0] = TransformType::New(); } this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions + 2] = (double)((size_t) m_labels); this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions + 3] = m_nLabels; SetFixedParameters(this->m_FixedParameters); } #define LOOP_ON_LABELS(FUNC, ARGS) \ for (unsigned i = 0; i < m_nLabels; ++i) \ m_trans[i]->FUNC(ARGS); template inline void MultipleBSplineDeformableTransform ::SetSplineOrder(const unsigned int & splineOrder) { LOOP_ON_LABELS(SetSplineOrder, splineOrder); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetSplineOrders(const SizeType & splineOrders) { LOOP_ON_LABELS(SetSplineOrders, splineOrders); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetLUTSamplingFactor( const int & samplingFactor) { LOOP_ON_LABELS(SetLUTSamplingFactor, samplingFactor); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetLUTSamplingFactors( const SizeType & samplingFactors) { LOOP_ON_LABELS(SetLUTSamplingFactors, samplingFactors); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetGridRegion( const RegionType & region ) { LOOP_ON_LABELS(SetGridRegion, region); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetGridSpacing( const SpacingType & spacing ) { LOOP_ON_LABELS(SetGridSpacing, spacing); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetGridDirection( const DirectionType & direction ) { LOOP_ON_LABELS(SetGridDirection, direction); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetGridOrigin( const OriginType& origin ) { LOOP_ON_LABELS(SetGridOrigin, origin); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetIdentity() { LOOP_ON_LABELS(SetIdentity, ); if ( m_InputParametersPointer ) { ParametersType * parameters = const_cast( m_InputParametersPointer ); parameters->Fill( 0.0 ); } this->Modified(); } template inline const std::vector::CoefficientImagePointer>& MultipleBSplineDeformableTransform ::GetCoefficientImages() const { m_CoefficientImages.resize(m_nLabels); for (unsigned i = 0; i < m_nLabels; ++i) m_CoefficientImages[i] = m_trans[i]->GetCoefficientImage(); return m_CoefficientImages; } template inline void MultipleBSplineDeformableTransform ::SetCoefficientImages(std::vector& images) { if (images.size() != m_nLabels) { itkExceptionMacro( << "Mismatched between the number of labels " << m_nLabels << " and the number of coefficient images " << images.size()); } for (unsigned i = 0; i < m_nLabels; ++i) m_trans[i]->SetCoefficientImage(images[i]); } template void MultipleBSplineDeformableTransform ::SetParameters( const ParametersType & parameters ) { if ( parameters.Size() != this->GetNumberOfParameters() ) { itkExceptionMacro(<<"Mismatched between parameters size " << parameters.size() << " and region size " << this->GetNumberOfParameters() ); } // Clean up buffered parameters m_InternalParametersBuffer = ParametersType( 0 ); // Keep a reference to the input parameters m_InputParametersPointer = ¶meters; double * dataPointer = const_cast(m_InputParametersPointer->data_block()); unsigned tot = 0; for (unsigned i = 0; i < m_nLabels; ++i) { unsigned int numberOfParameters = m_trans[i]->GetNumberOfParameters(); m_parameters[i].SetData(dataPointer + tot, numberOfParameters); m_trans[i]->SetParameters(m_parameters[i]); tot += numberOfParameters; } InitJacobian(); this->Modified(); } template void MultipleBSplineDeformableTransform ::SetFixedParameters( const ParametersType & parameters ) { // BSplineSeformableTransform parameters + m_labels pointer if ( parameters.Size() != NInputDimensions * (5 + NInputDimensions) + 4) { itkExceptionMacro(<< "Mismatched between parameters size " << parameters.size() << " and number of fixed parameters " << NInputDimensions * (5 + NInputDimensions) + 4); } ImageLabelPointer tmp2 = ((ImageLabelPointer)( (size_t)parameters[(5+NInputDimensions)*NInputDimensions+2])); if (tmp2 != m_labels) { if (tmp2) { m_labels = tmp2; m_nLabels = parameters[(5+NInputDimensions) * NInputDimensions + 3 ]; m_trans.resize(m_nLabels); m_parameters.resize(m_nLabels); for (unsigned i = 0; i < m_nLabels; ++i) m_trans[i] = TransformType::New(); m_labelInterpolator = ImageLabelInterpolator::New(); m_labelInterpolator->SetInputImage(m_labels); } else { m_labels = tmp2; m_nLabels = 1; m_trans.resize(1); m_parameters.resize(1); m_trans[0] = TransformType::New(); } } unsigned int numberOfParameters = NInputDimensions * (5 + NInputDimensions) + 2; ParametersType tmp(numberOfParameters); for (unsigned j = 0; j < numberOfParameters; ++j) tmp.SetElement(j, parameters.GetElement(j)); LOOP_ON_LABELS(SetFixedParameters, tmp); this->m_FixedParameters = parameters; this->Modified(); } template void MultipleBSplineDeformableTransform ::SetParametersByValue( const ParametersType & parameters ) { if ( parameters.Size() != this->GetNumberOfParameters() ) { itkExceptionMacro(<<"Mismatched between parameters size " << parameters.size() << " and region size " << this->GetNumberOfParameters() ); } // Copy it m_InternalParametersBuffer = parameters; m_InputParametersPointer = &m_InternalParametersBuffer; for (unsigned i = 0, tot = 0; i < m_nLabels; ++i) { unsigned int numberOfParameters = m_trans[i]->GetNumberOfParameters(); ParametersType tmp(numberOfParameters); for (unsigned j = 0; j < numberOfParameters; ++j, ++tot) tmp.SetElement(j, parameters.GetElement(tot)); m_trans[i]->SetParametersByValue(tmp); } InitJacobian(); this->Modified(); } template inline void MultipleBSplineDeformableTransform ::SetBulkTransform(BulkTransformPointer b) { m_BulkTransform = b; LOOP_ON_LABELS(SetBulkTransform, b); } #undef LOOP_ON_LABELS template inline typename MultipleBSplineDeformableTransform::NumberOfParametersType MultipleBSplineDeformableTransform ::GetNumberOfParameters(void) const { unsigned int sum = 0; for (unsigned i = 0; i < m_nLabels; ++i) sum += m_trans[i]->GetNumberOfParameters(); return sum; } template inline unsigned int MultipleBSplineDeformableTransform ::GetNumberOfParametersPerDimension(void) const { unsigned int sum = 0; for (unsigned i = 0; i < m_nLabels; ++i) sum += m_trans[i]->GetNumberOfParametersPerDimension(); return sum; } template inline const typename MultipleBSplineDeformableTransform::ParametersType & MultipleBSplineDeformableTransform ::GetParameters() const { if (NULL == m_InputParametersPointer) { itkExceptionMacro( <<"Cannot GetParameters() because m_InputParametersPointer is NULL. Perhaps SetCoefficientImage() has been called causing the NULL pointer." ); } return (*m_InputParametersPointer); } template inline const typename MultipleBSplineDeformableTransform::ParametersType & MultipleBSplineDeformableTransform ::GetFixedParameters() const { const ParametersType& trans0Para = m_trans[0]->GetFixedParameters(); for (unsigned i = 0; i < trans0Para.Size() ; ++i) this->m_FixedParameters.SetElement(i, trans0Para.GetElement(i)); this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions + 2] = (double)((size_t) m_labels); this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions + 3] = m_nLabels; return this->m_FixedParameters; } template inline void MultipleBSplineDeformableTransform ::PrintSelf(std::ostream &os, itk::Indent indent) const { this->Superclass::PrintSelf(os, indent); os << indent << "nLabels" << m_nLabels << std::endl; itk::Indent ind = indent.GetNextIndent(); for (unsigned i = 0; i < m_nLabels; ++i) { os << indent << "Label " << i << std::endl; m_trans[i]->Print(os, ind); } } template inline bool MultipleBSplineDeformableTransform ::InsideValidRegion( const ContinuousIndexType& index ) const { bool res = false; for (unsigned i = 0; i < m_nLabels; ++i) res |= m_trans[i]->InsideValidRegion(index); return res; } template inline typename MultipleBSplineDeformableTransform::OutputPointType MultipleBSplineDeformableTransform ::TransformPoint(const InputPointType &inputPoint) const { int lidx = 0; if (m_labels) lidx = m_labelInterpolator->Evaluate(inputPoint) - 1; if (lidx == -1) return inputPoint; return m_trans[lidx]->TransformPoint(inputPoint); } template inline typename MultipleBSplineDeformableTransform::OutputPointType MultipleBSplineDeformableTransform ::DeformablyTransformPoint(const InputPointType &inputPoint) const { int lidx = 0; if (m_labels) lidx = m_labelInterpolator->Evaluate(inputPoint) - 1; if (lidx == -1) return inputPoint; return m_trans[lidx]->DeformablyTransformPoint(inputPoint); } template inline void MultipleBSplineDeformableTransform ::ComputeJacobianWithRespectToParameters (const InputPointType &point, JacobianType &jacobian) const { if (m_LastJacobian != -1) m_trans[m_LastJacobian]->ResetJacobian(); int lidx = 0; if (m_labels) lidx = m_labelInterpolator->Evaluate(point) - 1; if (lidx == -1) { m_LastJacobian = lidx; jacobian = this->m_SharedDataBSplineJacobian; return; } JacobianType unused; m_trans[lidx]->ComputeJacobianWithRespectToParameters(point, unused); m_LastJacobian = lidx; jacobian = this->m_SharedDataBSplineJacobian; } template inline void MultipleBSplineDeformableTransform ::TransformPointToContinuousIndex( const InputPointType & point, ContinuousIndexType & index ) const { m_trans[0]->TransformPointToContinuousIndex(point, index); } template inline void MultipleBSplineDeformableTransform::InitJacobian() { unsigned numberOfParameters = this->GetNumberOfParameters(); this->m_SharedDataBSplineJacobian.set_size(OutputDimension, numberOfParameters); JacobianPixelType * jacobianDataPointer = reinterpret_cast(this->m_SharedDataBSplineJacobian.data_block()); memset(jacobianDataPointer, 0, numberOfParameters * sizeof (JacobianPixelType)); unsigned tot = 0; for (unsigned int j = 0; j < OutputDimension; j++) { for (unsigned i = 0; i < m_nLabels; ++i) { unsigned numberOfPixels = m_trans[i]->SetJacobianImageData(jacobianDataPointer, j); jacobianDataPointer += numberOfPixels; tot += numberOfPixels; } } assert(tot == numberOfParameters); } } // namespace clitk #endif // __clitkMultipleBSplineDeformableTransform_txx