/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkRegistrationParameterScalesFromJacobian_hxx #define itkRegistrationParameterScalesFromJacobian_hxx #include "itkRegistrationParameterScalesFromJacobian.h" namespace itk { /** Compute parameter scales from average jacobian norms. * For each parameter, compute the squared norm of its transform Jacobian, * then average the squared norm over the sample points. This average is * used as the scale of this parameter. */ template void RegistrationParameterScalesFromJacobian::EstimateScales(ScalesType & parameterScales) { this->CheckAndSetInputs(); this->SetScalesSamplingStrategy(); this->SampleVirtualDomain(); const SizeValueType numPara = this->GetNumberOfLocalParameters(); parameterScales.SetSize(numPara); ParametersType norms(numPara); const auto numSamples = static_cast(this->m_SamplePoints.size()); norms.Fill(NumericTraits::ZeroValue()); parameterScales.Fill(NumericTraits::OneValue()); // checking each sample point for (SizeValueType c = 0; c < numSamples; c++) { const VirtualPointType point = this->m_SamplePoints[c]; ParametersType squaredNorms(numPara); this->ComputeSquaredJacobianNorms(point, squaredNorms); norms = norms + squaredNorms; } // for numSamples if (numSamples > 0) { for (SizeValueType p = 0; p < numPara; p++) { parameterScales[p] = norms[p] / numSamples; } } } /** * Compute the scale for a STEP, the impact of a STEP on the transform. */ template typename RegistrationParameterScalesFromJacobian::FloatType RegistrationParameterScalesFromJacobian::EstimateStepScale(const ParametersType & step) { this->CheckAndSetInputs(); this->SetStepScaleSamplingStrategy(); this->SampleVirtualDomain(); ScalesType sampleScales; this->ComputeSampleStepScales(step, sampleScales); const auto numSamples = static_cast(this->m_SamplePoints.size()); FloatType scaleSum = NumericTraits::ZeroValue(); // checking each sample point for (SizeValueType c = 0; c < numSamples; c++) { scaleSum += sampleScales[c]; } return scaleSum / numSamples; } /** * Estimate the scales of local steps. For each voxel, we compute the impact * of a STEP on its location as in EstimateStepScale. Then we attribute this * impact to the corresponding local parameters. */ template void RegistrationParameterScalesFromJacobian::EstimateLocalStepScales(const ParametersType & step, ScalesType & localStepScales) { if (!this->IsDisplacementFieldTransform()) { itkExceptionMacro(<< "EstimateLocalStepScales: the transform doesn't have local support."); } this->CheckAndSetInputs(); this->SetStepScaleSamplingStrategy(); this->SampleVirtualDomain(); ScalesType sampleScales; this->ComputeSampleStepScales(step, sampleScales); const auto numSamples = static_cast(this->m_SamplePoints.size()); const SizeValueType numPara = this->GetNumberOfLocalParameters(); const SizeValueType numAllPara = this->GetTransform()->GetNumberOfParameters(); const SizeValueType numLocals = numAllPara / numPara; localStepScales.SetSize(numLocals); localStepScales.Fill(NumericTraits::ZeroValue()); // checking each sample point for (SizeValueType c = 0; c < numSamples; c++) { VirtualPointType & point = this->m_SamplePoints[c]; IndexValueType localId = this->m_Metric->ComputeParameterOffsetFromVirtualPoint(point, NumericTraits::OneValue()); localStepScales[localId] = sampleScales[c]; } } /** * Compute the step scales for samples, i.e. the impacts on each sampled * voxel from a change on the transform. */ template void RegistrationParameterScalesFromJacobian::ComputeSampleStepScales(const ParametersType & step, ScalesType & sampleScales) { const auto numSamples = static_cast(this->m_SamplePoints.size()); const SizeValueType dim = this->GetDimension(); const SizeValueType numPara = this->GetNumberOfLocalParameters(); sampleScales.SetSize(numSamples); itk::Array dTdt(dim); JacobianType jacobianCache; JacobianType jacobian(dim, (this->GetTransformForward() ? this->m_Metric->GetMovingTransform()->GetNumberOfParameters() : this->m_Metric->GetFixedTransform()->GetNumberOfParameters())); // checking each sample point for (SizeValueType c = 0; c < numSamples; c++) { const VirtualPointType & point = this->m_SamplePoints[c]; if (this->GetTransformForward()) { this->m_Metric->GetMovingTransform()->ComputeJacobianWithRespectToParametersCachedTemporaries( point, jacobian, jacobianCache); } else { this->m_Metric->GetFixedTransform()->ComputeJacobianWithRespectToParametersCachedTemporaries( point, jacobian, jacobianCache); } if (!this->IsDisplacementFieldTransform()) { dTdt = jacobian * step; } else { SizeValueType offset = this->m_Metric->ComputeParameterOffsetFromVirtualPoint(point, numPara); ParametersType localStep(numPara); for (SizeValueType p = 0; p < numPara; p++) { localStep[p] = step[offset + p]; } dTdt = jacobian * localStep; } sampleScales[c] = dTdt.two_norm(); } } /** Print the information about this class */ template void RegistrationParameterScalesFromJacobian::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); } } // namespace itk #endif /* itkRegistrationParameterScalesFromJacobian_hxx */