1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
19 #ifndef _clitkCorrelationRatioImageToImageMetric_txx
20 #define _clitkCorrelationRatioImageToImageMetric_txx
23 * @file clitkCorrelationRatioImageToImageMetric.txx
24 * @author Jef Vandemeulebroucke <jef@creatis.insa-lyon.fr>
25 * @date July 30 18:14:53 2007
27 * @brief Compute the correlation ratio between 2 images
32 #include "clitkCorrelationRatioImageToImageMetric.h"
33 #include "itkImageRegionConstIteratorWithIndex.h"
34 #include "itkImageRegionConstIterator.h"
35 #include "itkImageRegionIterator.h"
43 template <class TFixedImage, class TMovingImage>
44 CorrelationRatioImageToImageMetric<TFixedImage,TMovingImage>
45 ::CorrelationRatioImageToImageMetric()
51 template <class TFixedImage, class TMovingImage>
53 CorrelationRatioImageToImageMetric<TFixedImage,TMovingImage>
54 ::Initialize(void) throw ( ExceptionObject )
57 this->Superclass::Initialize();
59 // Compute the minimum and maximum for the FixedImage over the FixedImageRegion.
60 // We can't use StatisticsImageFilter to do this because the filter computes the min/max for the largest possible region
61 double fixedImageMin = NumericTraits<double>::max();
62 double fixedImageMax = NumericTraits<double>::NonpositiveMin();
64 typedef ImageRegionConstIterator<FixedImageType> FixedIteratorType;
65 FixedIteratorType fixedImageIterator(
66 this->m_FixedImage, this->GetFixedImageRegion() );
68 for ( fixedImageIterator.GoToBegin();
69 !fixedImageIterator.IsAtEnd(); ++fixedImageIterator ) {
71 double sample = static_cast<double>( fixedImageIterator.Get() );
73 if ( sample < fixedImageMin ) {
74 fixedImageMin = sample;
77 if ( sample > fixedImageMax ) {
78 fixedImageMax = sample;
82 // Compute binsize for the fixedImage
83 m_FixedImageBinSize = ( fixedImageMax - fixedImageMin ) / m_NumberOfBins;
84 m_FixedImageMin=fixedImageMin;
85 //Allocate mempry and initialise the fixed image bin
86 m_NumberOfPixelsCountedPerBin.resize( m_NumberOfBins, 0 );
87 m_mMSVPB.resize( m_NumberOfBins, 0.0 );
88 m_mSMVPB.resize( m_NumberOfBins, 0.0 );
93 * Get the match Measure
95 template <class TFixedImage, class TMovingImage>
96 typename CorrelationRatioImageToImageMetric<TFixedImage,TMovingImage>::MeasureType
97 CorrelationRatioImageToImageMetric<TFixedImage,TMovingImage>
98 ::GetValue( const TransformParametersType & parameters ) const
101 itkDebugMacro("GetValue( " << parameters << " ) ");
103 FixedImageConstPointer fixedImage = this->m_FixedImage;
106 itkExceptionMacro( << "Fixed image has not been assigned" );
109 typedef itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
112 FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
114 typename FixedImageType::IndexType index;
116 MeasureType measure = itk::NumericTraits< MeasureType >::Zero;
118 this->m_NumberOfPixelsCounted = 0;
119 this->SetTransformParameters( parameters );
122 //temporary measures for the calculation
126 while(!ti.IsAtEnd()) {
128 index = ti.GetIndex();
130 typename Superclass::InputPointType inputPoint;
131 fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
133 // Verify that the point is in the fixed Image Mask
134 if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
139 typename Superclass::OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
141 //Verify that the point is in the moving Image Mask
142 if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
147 // Verify is the interpolated value is in the buffer
148 if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
149 //Accumulate calculations for the correlation ratio
150 //For each pixel the is in both masks and the buffer we adapt the following measures:
151 //movingMeanSquaredValue mMSV; movingSquaredMeanValue mSMV;
152 //movingMeanSquaredValuePerBin[i] mSMVPB; movingSquaredMeanValuePerBin[i] mSMVPB
153 //NumberOfPixelsCounted, NumberOfPixelsCountedPerBin[i]
155 //get the value of the moving image
156 const RealType movingValue = this->m_Interpolator->Evaluate( transformedPoint );
157 // for the variance of the overlapping moving image we accumulate the following measures
158 const RealType movingSquaredValue=movingValue*movingValue;
159 mMSV+=movingSquaredValue;
162 //get the fixed value
163 const RealType fixedValue = ti.Get();
165 //check in which bin the fixed value belongs, get the index
166 const double fixedImageBinTerm = (fixedValue - m_FixedImageMin) / m_FixedImageBinSize;
167 const unsigned int fixedImageBinIndex = static_cast<unsigned int>( vcl_floor(fixedImageBinTerm ) );
168 //adapt the measures per bin
169 this->m_mMSVPB[fixedImageBinIndex]+=movingSquaredValue;
170 this->m_mSMVPB[fixedImageBinIndex]+=movingValue;
171 //increase the fixed image bin and the total pixel count
172 this->m_NumberOfPixelsCountedPerBin[fixedImageBinIndex]+=1;
173 this->m_NumberOfPixelsCounted++;
179 if( !this->m_NumberOfPixelsCounted ) {
180 itkExceptionMacro(<<"All the points mapped to outside of the moving image");
183 //apdapt the measures per bin
184 for (unsigned int i=0; i< m_NumberOfBins; i++ ) {
185 if (this->m_NumberOfPixelsCountedPerBin[i]>0) {
186 measure+=(this->m_mMSVPB[i]-((this->m_mSMVPB[i]*this->m_mSMVPB[i])/this->m_NumberOfPixelsCountedPerBin[i]));
190 //Normalize with the global measures
191 measure /= (mMSV-((mSMV*mSMV)/ this->m_NumberOfPixelsCounted));
202 * Get the Derivative Measure
204 template < class TFixedImage, class TMovingImage>
206 CorrelationRatioImageToImageMetric<TFixedImage,TMovingImage>
207 ::GetDerivative( const TransformParametersType & parameters,
208 DerivativeType & derivative ) const
211 itkDebugMacro("GetDerivative( " << parameters << " ) ");
213 if( !this->GetGradientImage() ) {
214 itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
217 FixedImageConstPointer fixedImage = this->m_FixedImage;
220 itkExceptionMacro( << "Fixed image has not been assigned" );
223 const unsigned int ImageDimension = FixedImageType::ImageDimension;
226 typedef itk::ImageRegionConstIteratorWithIndex<
227 FixedImageType> FixedIteratorType;
229 typedef itk::ImageRegionConstIteratorWithIndex<
230 typename Superclass::GradientImageType> GradientIteratorType;
233 FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
235 typename FixedImageType::IndexType index;
237 this->m_NumberOfPixelsCounted = 0;
239 this->SetTransformParameters( parameters );
241 const unsigned int ParametersDimension = this->GetNumberOfParameters();
242 derivative = DerivativeType( ParametersDimension );
243 derivative.Fill( itk::NumericTraits<typename DerivativeType::ValueType>::Zero );
247 while(!ti.IsAtEnd()) {
249 index = ti.GetIndex();
251 typename Superclass::InputPointType inputPoint;
252 fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
254 if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
259 typename Superclass::OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
261 if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
266 if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
267 const RealType movingValue = this->m_Interpolator->Evaluate( transformedPoint );
269 #if ITK_VERSION_MAJOR >= 4
270 TransformJacobianType jacobian;
271 this->m_Transform->ComputeJacobianWithRespectToParameters( inputPoint , jacobian);
273 const TransformJacobianType & jacobian =
274 this->m_Transform->GetJacobian( inputPoint );
278 const RealType fixedValue = ti.Value();
279 this->m_NumberOfPixelsCounted++;
280 const RealType diff = movingValue - fixedValue;
282 // Get the gradient by NearestNeighboorInterpolation:
283 // which is equivalent to round up the point components.
284 typedef typename Superclass::OutputPointType OutputPointType;
285 typedef typename OutputPointType::CoordRepType CoordRepType;
286 typedef ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
287 MovingImageContinuousIndexType;
289 MovingImageContinuousIndexType tempIndex;
290 this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
292 typename MovingImageType::IndexType mappedIndex;
293 for( unsigned int j = 0; j < MovingImageType::ImageDimension; j++ ) {
294 mappedIndex[j] = static_cast<long>( vnl_math_rnd( tempIndex[j] ) );
297 const GradientPixelType gradient =
298 this->GetGradientImage()->GetPixel( mappedIndex );
300 for(unsigned int par=0; par<ParametersDimension; par++) {
301 RealType sum = NumericTraits< RealType >::Zero;
302 for(unsigned int dim=0; dim<ImageDimension; dim++) {
303 sum += 2.0 * diff * jacobian( dim, par ) * gradient[dim];
305 derivative[par] += sum;
312 if( !this->m_NumberOfPixelsCounted ) {
313 itkExceptionMacro(<<"All the points mapped to outside of the moving image");
315 for(unsigned int i=0; i<ParametersDimension; i++) {
316 derivative[i] /= this->m_NumberOfPixelsCounted;
324 * Get both the match Measure and the Derivative Measure
326 template <class TFixedImage, class TMovingImage>
328 CorrelationRatioImageToImageMetric<TFixedImage,TMovingImage>
329 ::GetValueAndDerivative(const TransformParametersType & parameters,
330 MeasureType & value, DerivativeType & derivative) const
333 itkDebugMacro("GetValueAndDerivative( " << parameters << " ) ");
335 if( !this->GetGradientImage() ) {
336 itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
339 FixedImageConstPointer fixedImage = this->m_FixedImage;
342 itkExceptionMacro( << "Fixed image has not been assigned" );
345 const unsigned int ImageDimension = FixedImageType::ImageDimension;
347 typedef itk::ImageRegionConstIteratorWithIndex<
348 FixedImageType> FixedIteratorType;
350 typedef itk::ImageRegionConstIteratorWithIndex<
351 typename Superclass::GradientImageType> GradientIteratorType;
354 FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
356 typename FixedImageType::IndexType index;
358 MeasureType measure = NumericTraits< MeasureType >::Zero;
360 this->m_NumberOfPixelsCounted = 0;
362 this->SetTransformParameters( parameters );
364 const unsigned int ParametersDimension = this->GetNumberOfParameters();
365 derivative = DerivativeType( ParametersDimension );
366 derivative.Fill( NumericTraits<typename DerivativeType::ValueType>::Zero );
370 while(!ti.IsAtEnd()) {
372 index = ti.GetIndex();
374 typename Superclass::InputPointType inputPoint;
375 fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
377 if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
382 typename Superclass::OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
384 if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
389 if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
390 const RealType movingValue = this->m_Interpolator->Evaluate( transformedPoint );
392 #if ITK_VERSION_MAJOR >= 4
393 TransformJacobianType jacobian;
394 this->m_Transform->ComputeJacobianWithRespectToParameters( inputPoint, jacobian );
396 const TransformJacobianType & jacobian =
397 this->m_Transform->GetJacobian( inputPoint );
401 const RealType fixedValue = ti.Value();
402 this->m_NumberOfPixelsCounted++;
404 const RealType diff = movingValue - fixedValue;
406 measure += diff * diff;
408 // Get the gradient by NearestNeighboorInterpolation:
409 // which is equivalent to round up the point components.
410 typedef typename Superclass::OutputPointType OutputPointType;
411 typedef typename OutputPointType::CoordRepType CoordRepType;
412 typedef ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
413 MovingImageContinuousIndexType;
415 MovingImageContinuousIndexType tempIndex;
416 this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
418 typename MovingImageType::IndexType mappedIndex;
419 for( unsigned int j = 0; j < MovingImageType::ImageDimension; j++ ) {
420 mappedIndex[j] = static_cast<long>( vnl_math_rnd( tempIndex[j] ) );
423 const GradientPixelType gradient =
424 this->GetGradientImage()->GetPixel( mappedIndex );
426 for(unsigned int par=0; par<ParametersDimension; par++) {
427 RealType sum = NumericTraits< RealType >::Zero;
428 for(unsigned int dim=0; dim<ImageDimension; dim++) {
429 sum += 2.0 * diff * jacobian( dim, par ) * gradient[dim];
431 derivative[par] += sum;
438 if( !this->m_NumberOfPixelsCounted ) {
439 itkExceptionMacro(<<"All the points mapped to outside of the moving image");
441 for(unsigned int i=0; i<ParametersDimension; i++) {
442 derivative[i] /= this->m_NumberOfPixelsCounted;
444 measure /= this->m_NumberOfPixelsCounted;
451 } // end namespace itk