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 /*=========================================================================
21 Program: Insight Segmentation & Registration Toolkit
22 Module: $RCSfile: itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx,v $
24 Date: $Date: 2010/06/14 17:32:07 $
25 Version: $Revision: 1.1 $
27 Copyright (c) Insight Software Consortium. All rights reserved.
28 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
30 This software is distributed WITHOUT ANY WARRANTY; without even
31 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
32 PURPOSE. See the above copyright notices for more information.
34 =========================================================================*/
35 #ifndef __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
36 #define __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
38 #include "itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h"
39 #include "itkCovariantVector.h"
40 #include "itkImageRandomConstIteratorWithIndex.h"
41 #include "itkImageRegionConstIterator.h"
42 #include "itkImageRegionIterator.h"
43 #include "itkImageIterator.h"
44 #include "vnl/vnl_math.h"
45 #include "itkStatisticsImageFilter.h"
47 #include "vnl/vnl_vector.h"
48 #include "vnl/vnl_c_vector.h"
56 template < class TFixedImage, class TMovingImage >
57 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
58 ::MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
60 m_NumberOfHistogramBins = 50;
62 this->SetComputeGradient(false); // don't use the default gradient for now
64 // Initialize PDFs to NULL
66 m_JointPDFDerivatives = NULL;
69 m_FixedImageMarginalPDF = NULL;
70 m_MovingImageMarginalPDF = NULL;
72 m_MovingImageNormalizedMin = 0.0;
73 m_FixedImageNormalizedMin = 0.0;
74 m_MovingImageTrueMin = 0.0;
75 m_MovingImageTrueMax = 0.0;
76 m_FixedImageBinSize = 0.0;
77 m_MovingImageBinSize = 0.0;
79 m_CubicBSplineDerivativeKernel = NULL;
81 // For multi-threading the metric
82 m_ThreaderFixedImageMarginalPDF = NULL;
83 m_ThreaderJointPDF = NULL;
84 m_ThreaderJointPDFDerivatives = NULL;
85 m_ThreaderJointPDFStartBin = NULL;
86 m_ThreaderJointPDFEndBin = NULL;
87 m_ThreaderJointPDFSum = NULL;
88 this->m_WithinThreadPreProcess = true;
89 this->m_WithinThreadPostProcess = false;
91 this->m_ThreaderMetricDerivative = NULL;
92 this->m_UseExplicitPDFDerivatives = true;
93 this->m_ImplicitDerivativesSecondPass = false;
96 template < class TFixedImage, class TMovingImage >
97 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
98 ::~MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
101 if(m_FixedImageMarginalPDF != NULL) {
102 delete [] m_FixedImageMarginalPDF;
104 m_FixedImageMarginalPDF = NULL;
105 if(m_MovingImageMarginalPDF != NULL) {
106 delete [] m_MovingImageMarginalPDF;
108 m_MovingImageMarginalPDF = NULL;
109 if(m_ThreaderJointPDF != NULL) {
110 delete [] m_ThreaderJointPDF;
112 m_ThreaderJointPDF = NULL;
114 if(m_ThreaderJointPDFDerivatives != NULL) {
115 delete [] m_ThreaderJointPDFDerivatives;
117 m_ThreaderJointPDFDerivatives = NULL;
119 if(m_ThreaderFixedImageMarginalPDF != NULL) {
120 delete [] m_ThreaderFixedImageMarginalPDF;
122 m_ThreaderFixedImageMarginalPDF = NULL;
124 if(m_ThreaderJointPDFStartBin != NULL) {
125 delete [] m_ThreaderJointPDFStartBin;
127 m_ThreaderJointPDFStartBin = NULL;
129 if(m_ThreaderJointPDFEndBin != NULL) {
130 delete [] m_ThreaderJointPDFEndBin;
132 m_ThreaderJointPDFEndBin = NULL;
134 if(m_ThreaderJointPDFSum != NULL) {
135 delete [] m_ThreaderJointPDFSum;
137 m_ThreaderJointPDFSum = NULL;
139 if( this->m_ThreaderMetricDerivative != NULL ) {
140 delete [] this->m_ThreaderMetricDerivative;
142 this->m_ThreaderMetricDerivative = NULL;
146 * Print out internal information about this class
148 template < class TFixedImage, class TMovingImage >
150 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
151 ::PrintSelf(std::ostream& os, Indent indent) const
154 Superclass::PrintSelf(os, indent);
156 os << indent << "NumberOfHistogramBins: ";
157 os << this->m_NumberOfHistogramBins << std::endl;
159 // Debugging information
160 os << indent << "FixedImageNormalizedMin: ";
161 os << this->m_FixedImageNormalizedMin << std::endl;
162 os << indent << "MovingImageNormalizedMin: ";
163 os << this->m_MovingImageNormalizedMin << std::endl;
164 os << indent << "MovingImageTrueMin: ";
165 os << this->m_MovingImageTrueMin << std::endl;
166 os << indent << "MovingImageTrueMax: ";
167 os << this->m_MovingImageTrueMax << std::endl;
168 os << indent << "FixedImageBinSize: ";
169 os << this->m_FixedImageBinSize << std::endl;
170 os << indent << "MovingImageBinSize: ";
171 os << this->m_MovingImageBinSize << std::endl;
172 os << indent << "UseExplicitPDFDerivatives: ";
173 os << this->m_UseExplicitPDFDerivatives << std::endl;
174 os << indent << "ImplicitDerivativesSecondPass: ";
175 os << this->m_ImplicitDerivativesSecondPass << std::endl;
183 template <class TFixedImage, class TMovingImage>
185 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
188 this->Superclass::Initialize();
189 this->Superclass::MultiThreadingInitialize();
191 typedef StatisticsImageFilter<FixedImageType> FixedImageStatisticsFilterType;
192 typename FixedImageStatisticsFilterType::Pointer fixedImageStats =
193 FixedImageStatisticsFilterType::New();
194 fixedImageStats->SetInput( this->m_FixedImage );
195 #if ITK_VERSION_MAJOR <= 4
196 fixedImageStats->SetNumberOfThreads( this->m_NumberOfThreads );
198 fixedImageStats->SetNumberOfWorkUnits( this->m_NumberOfWorkUnits );
200 fixedImageStats->Update();
202 m_FixedImageTrueMin = fixedImageStats->GetMinimum();
203 m_FixedImageTrueMax = fixedImageStats->GetMaximum();
204 double fixedImageMin = m_FixedImageTrueMin;
205 double fixedImageMax = m_FixedImageTrueMax;
207 typedef StatisticsImageFilter<MovingImageType>
208 MovingImageStatisticsFilterType;
209 typename MovingImageStatisticsFilterType::Pointer movingImageStats =
210 MovingImageStatisticsFilterType::New();
211 movingImageStats->SetInput( this->m_MovingImage );
212 #if ITK_VERSION_MAJOR <= 4
213 movingImageStats->SetNumberOfThreads( this->m_NumberOfThreads );
215 movingImageStats->SetNumberOfWorkUnits( this->m_NumberOfWorkUnits );
217 movingImageStats->Update();
219 m_MovingImageTrueMin = movingImageStats->GetMinimum();
220 m_MovingImageTrueMax = movingImageStats->GetMaximum();
221 double movingImageMin = m_MovingImageTrueMin;
222 double movingImageMax = m_MovingImageTrueMax;
224 itkDebugMacro( " FixedImageMin: " << fixedImageMin <<
225 " FixedImageMax: " << fixedImageMax << std::endl );
226 itkDebugMacro( " MovingImageMin: " << movingImageMin <<
227 " MovingImageMax: " << movingImageMax << std::endl );
231 * Compute binsize for the histograms.
233 * The binsize for the image intensities needs to be adjusted so that
234 * we can avoid dealing with boundary conditions using the cubic
235 * spline as the Parzen window. We do this by increasing the size
236 * of the bins so that the joint histogram becomes "padded" at the
237 * borders. Because we are changing the binsize,
238 * we also need to shift the minimum by the padded amount in order to
239 * avoid minimum values filling in our padded region.
241 * Note that there can still be non-zero bin values in the padded region,
242 * it's just that these bins will never be a central bin for the Parzen
246 const int padding = 2; // this will pad by 2 bins
248 m_FixedImageBinSize = ( fixedImageMax - fixedImageMin )
249 / static_cast<double>( m_NumberOfHistogramBins
251 m_FixedImageNormalizedMin = fixedImageMin / m_FixedImageBinSize
252 - static_cast<double>( padding );
254 m_MovingImageBinSize = ( movingImageMax - movingImageMin )
255 / static_cast<double>( m_NumberOfHistogramBins
257 m_MovingImageNormalizedMin = movingImageMin / m_MovingImageBinSize
258 - static_cast<double>( padding );
260 itkDebugMacro( "FixedImageNormalizedMin: " << m_FixedImageNormalizedMin );
261 itkDebugMacro( "MovingImageNormalizedMin: " << m_MovingImageNormalizedMin );
262 itkDebugMacro( "FixedImageBinSize: " << m_FixedImageBinSize );
263 itkDebugMacro( "MovingImageBinSize; " << m_MovingImageBinSize );
267 * Allocate memory for the marginal PDF and initialize values
268 * to zero. The marginal PDFs are stored as std::vector.
270 if(m_FixedImageMarginalPDF != NULL) {
271 delete [] m_FixedImageMarginalPDF;
273 m_FixedImageMarginalPDF = new PDFValueType[m_NumberOfHistogramBins];
274 if(m_MovingImageMarginalPDF != NULL) {
275 delete [] m_MovingImageMarginalPDF;
277 m_MovingImageMarginalPDF = new PDFValueType[m_NumberOfHistogramBins];
280 * Allocate memory for the joint PDF and joint PDF derivatives.
281 * The joint PDF and joint PDF derivatives are store as itk::Image.
283 m_JointPDF = JointPDFType::New();
284 m_JointPDFDerivatives = JointPDFDerivativesType::New();
286 // Instantiate a region, index, size
287 JointPDFRegionType jointPDFRegion;
288 JointPDFIndexType jointPDFIndex;
289 JointPDFSizeType jointPDFSize;
291 // Deallocate the memory that may have been allocated for
292 // previous runs of the metric.
293 this->m_JointPDFDerivatives = NULL; // by destroying the dynamic array
294 this->m_PRatioArray.SetSize( 1, 1 ); // and by allocating very small the static ones
295 this->m_MetricDerivative = DerivativeType( 1 );
297 JointPDFDerivativesRegionType jointPDFDerivativesRegion;
300 // Now allocate memory according to the user-selected method.
302 if( this->m_UseExplicitPDFDerivatives ) {
303 this->m_JointPDFDerivatives = JointPDFDerivativesType::New();
305 JointPDFDerivativesIndexType jointPDFDerivativesIndex;
306 JointPDFDerivativesSizeType jointPDFDerivativesSize;
308 // For the derivatives of the joint PDF define a region starting from {0,0,0}
309 // with size {m_NumberOfParameters,m_NumberOfHistogramBins,
310 // m_NumberOfHistogramBins}. The dimension represents transform parameters,
311 // fixed image parzen window index and moving image parzen window index,
313 jointPDFDerivativesIndex.Fill( 0 );
314 jointPDFDerivativesSize[0] = this->m_NumberOfParameters;
315 jointPDFDerivativesSize[1] = this->m_NumberOfHistogramBins;
316 jointPDFDerivativesSize[2] = this->m_NumberOfHistogramBins;
318 jointPDFDerivativesRegion.SetIndex( jointPDFDerivativesIndex );
319 jointPDFDerivativesRegion.SetSize( jointPDFDerivativesSize );
321 // Set the regions and allocate
322 m_JointPDFDerivatives->SetRegions( jointPDFDerivativesRegion );
323 m_JointPDFDerivatives->Allocate();
324 m_JointPDFDerivativesBufferSize = jointPDFDerivativesSize[0]
325 * jointPDFDerivativesSize[1]
326 * jointPDFDerivativesSize[2]
327 * sizeof(JointPDFDerivativesValueType);
330 /** Allocate memory for helper array that will contain the pRatios
331 * for each bin of the joint histogram. This is part of the effort
332 * for flattening the computation of the PDF Jacobians.
334 this->m_PRatioArray.SetSize( this->m_NumberOfHistogramBins, this->m_NumberOfHistogramBins );
335 this->m_MetricDerivative = DerivativeType( this->GetNumberOfParameters() );
338 // For the joint PDF define a region starting from {0,0}
339 // with size {m_NumberOfHistogramBins, m_NumberOfHistogramBins}.
340 // The dimension represents fixed image parzen window index
341 // and moving image parzen window index, respectively.
342 jointPDFIndex.Fill( 0 );
343 jointPDFSize.Fill( m_NumberOfHistogramBins );
345 jointPDFRegion.SetIndex( jointPDFIndex );
346 jointPDFRegion.SetSize( jointPDFSize );
348 // Set the regions and allocate
349 m_JointPDF->SetRegions( jointPDFRegion );
350 m_JointPDF->Allocate();
352 m_JointPDFBufferSize = jointPDFSize[0] * jointPDFSize[1] * sizeof(PDFValueType);
356 * Setup the kernels used for the Parzen windows.
358 m_CubicBSplineKernel = CubicBSplineFunctionType::New();
359 m_CubicBSplineDerivativeKernel = CubicBSplineDerivativeFunctionType::New();
362 * Pre-compute the fixed image parzen window index for
363 * each point of the fixed image sample points list.
365 this->ComputeFixedImageParzenWindowIndices( this->m_FixedImageSamples );
368 if(m_ThreaderFixedImageMarginalPDF != NULL) {
369 delete [] m_ThreaderFixedImageMarginalPDF;
371 // Assumes number of threads doesn't change between calls to Initialize
372 m_ThreaderFixedImageMarginalPDF = new
373 #if ITK_VERSION_MAJOR <= 4
374 PDFValueType[(this->m_NumberOfThreads-1) * m_NumberOfHistogramBins];
376 PDFValueType[(this->m_NumberOfWorkUnits-1) * m_NumberOfHistogramBins];
379 if(m_ThreaderJointPDF != NULL) {
380 delete [] m_ThreaderJointPDF;
382 m_ThreaderJointPDF = new typename
383 #if ITK_VERSION_MAJOR <= 4
384 JointPDFType::Pointer[this->m_NumberOfThreads-1];
386 JointPDFType::Pointer[this->m_NumberOfWorkUnits-1];
389 if(m_ThreaderJointPDFStartBin != NULL) {
390 delete [] m_ThreaderJointPDFStartBin;
392 #if ITK_VERSION_MAJOR <= 4
393 m_ThreaderJointPDFStartBin = new int[this->m_NumberOfThreads];
395 m_ThreaderJointPDFStartBin = new int[this->m_NumberOfWorkUnits];
398 if(m_ThreaderJointPDFEndBin != NULL) {
399 delete [] m_ThreaderJointPDFEndBin;
401 #if ITK_VERSION_MAJOR <= 4
402 m_ThreaderJointPDFEndBin = new int[this->m_NumberOfThreads];
404 m_ThreaderJointPDFEndBin = new int[this->m_NumberOfWorkUnits];
407 if(m_ThreaderJointPDFSum != NULL) {
408 delete [] m_ThreaderJointPDFSum;
410 #if ITK_VERSION_MAJOR <= 4
411 m_ThreaderJointPDFSum = new double[this->m_NumberOfThreads];
413 m_ThreaderJointPDFSum = new double[this->m_NumberOfWorkUnits];
416 unsigned int threadID;
418 #if ITK_VERSION_MAJOR <= 4
419 int binRange = m_NumberOfHistogramBins / this->m_NumberOfThreads;
421 int binRange = m_NumberOfHistogramBins / this->m_NumberOfWorkUnits;
424 #if ITK_VERSION_MAJOR <= 4
425 for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
427 for(threadID = 0; threadID < this->m_NumberOfWorkUnits-1; threadID++) {
429 m_ThreaderJointPDF[threadID] = JointPDFType::New();
430 m_ThreaderJointPDF[threadID]->SetRegions( jointPDFRegion );
431 m_ThreaderJointPDF[threadID]->Allocate();
433 m_ThreaderJointPDFStartBin[threadID] = threadID * binRange;
434 m_ThreaderJointPDFEndBin[threadID] = (threadID + 1) * binRange - 1;
437 #if ITK_VERSION_MAJOR <= 4
438 m_ThreaderJointPDFStartBin[this->m_NumberOfThreads-1] = (this->m_NumberOfThreads - 1 ) * binRange;
439 m_ThreaderJointPDFEndBin[this->m_NumberOfThreads-1] = m_NumberOfHistogramBins - 1;
441 m_ThreaderJointPDFStartBin[this->m_NumberOfWorkUnits-1] = (this->m_NumberOfWorkUnits - 1 ) * binRange;
442 m_ThreaderJointPDFEndBin[this->m_NumberOfWorkUnits-1] = m_NumberOfHistogramBins - 1;
445 // Release memory of arrays that may have been used for
446 // previous executions of this metric with different settings
447 // of the memory caching flags.
448 if(m_ThreaderJointPDFDerivatives != NULL) {
449 delete [] m_ThreaderJointPDFDerivatives;
451 m_ThreaderJointPDFDerivatives = NULL;
453 if(m_ThreaderMetricDerivative != NULL) {
454 delete [] m_ThreaderMetricDerivative;
456 m_ThreaderMetricDerivative = NULL;
459 if( this->m_UseExplicitPDFDerivatives ) {
460 m_ThreaderJointPDFDerivatives = new typename
461 #if ITK_VERSION_MAJOR <= 4
462 JointPDFDerivativesType::Pointer[this->m_NumberOfThreads-1];
464 JointPDFDerivativesType::Pointer[this->m_NumberOfWorkUnits-1];
467 #if ITK_VERSION_MAJOR <= 4
468 for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
470 for(threadID = 0; threadID < this->m_NumberOfWorkUnits-1; threadID++) {
472 m_ThreaderJointPDFDerivatives[threadID] = JointPDFDerivativesType::New();
473 m_ThreaderJointPDFDerivatives[threadID]->SetRegions(
474 jointPDFDerivativesRegion );
475 m_ThreaderJointPDFDerivatives[threadID]->Allocate();
478 #if ITK_VERSION_MAJOR <= 4
479 m_ThreaderMetricDerivative = new DerivativeType[this->m_NumberOfThreads-1];
481 m_ThreaderMetricDerivative = new DerivativeType[this->m_NumberOfWorkUnits-1];
484 #if ITK_VERSION_MAJOR <= 4
485 for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
487 for(threadID = 0; threadID < this->m_NumberOfWorkUnits-1; threadID++) {
489 this->m_ThreaderMetricDerivative[threadID] = DerivativeType( this->GetNumberOfParameters() );
495 * Uniformly sample the fixed image domain using a random walk
497 template < class TFixedImage, class TMovingImage >
499 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
500 ::ComputeFixedImageParzenWindowIndices(
501 FixedImageSampleContainer& samples )
504 typename FixedImageSampleContainer::iterator iter;
505 typename FixedImageSampleContainer::const_iterator end=samples.end();
507 for( iter=samples.begin(); iter != end; ++iter ) {
509 // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
510 double windowTerm = static_cast<double>( (*iter).value )
511 / m_FixedImageBinSize
512 - m_FixedImageNormalizedMin;
513 unsigned int pindex = static_cast<unsigned int>( windowTerm );
515 // Make sure the extreme values are in valid bins
518 } else if ( pindex > (m_NumberOfHistogramBins - 3) ) {
519 pindex = m_NumberOfHistogramBins - 3;
522 (*iter).valueIndex = pindex;
527 template < class TFixedImage, class TMovingImage >
529 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
530 ::GetValueThreadPreProcess( unsigned int threadID,
531 bool withinSampleThread ) const
534 this->Superclass::GetValueThreadPreProcess( threadID, withinSampleThread );
537 memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(),
539 m_JointPDFBufferSize );
540 memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1)
541 *m_NumberOfHistogramBins]),
543 m_NumberOfHistogramBins*sizeof(PDFValueType) );
545 // zero-th thread uses the variables directly
546 memset( m_JointPDF->GetBufferPointer(),
548 m_JointPDFBufferSize );
549 memset( m_FixedImageMarginalPDF,
551 m_NumberOfHistogramBins*sizeof(PDFValueType) );
555 template < class TFixedImage, class TMovingImage >
557 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
558 ::GetValueThreadProcessSample( unsigned int threadID,
559 unsigned long fixedImageSample,
560 const MovingImagePointType & itkNotUsed(mappedPoint),
561 double movingImageValue) const
564 * Compute this sample's contribution to the marginal and
565 * joint distributions.
569 if(movingImageValue < m_MovingImageTrueMin) {
571 } else if(movingImageValue > m_MovingImageTrueMax) {
575 // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
576 double movingImageParzenWindowTerm = movingImageValue
577 / m_MovingImageBinSize
578 - m_MovingImageNormalizedMin;
580 unsigned int movingImageParzenWindowIndex =
581 static_cast<unsigned int>( movingImageParzenWindowTerm );
582 if( movingImageParzenWindowIndex < 2 ) {
583 movingImageParzenWindowIndex = 2;
584 } else if( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
585 movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
588 unsigned int fixedImageParzenWindowIndex =
589 this->m_FixedImageSamples[fixedImageSample].valueIndex;
591 m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins
592 + fixedImageParzenWindowIndex] += 1;
594 m_FixedImageMarginalPDF[fixedImageParzenWindowIndex] += 1;
597 // Pointer to affected bin to be updated
598 JointPDFValueType *pdfPtr;
600 pdfPtr = m_ThreaderJointPDF[threadID-1]->GetBufferPointer() +
601 ( fixedImageParzenWindowIndex
602 * m_ThreaderJointPDF[threadID-1]
603 ->GetOffsetTable()[1] );
605 pdfPtr = m_JointPDF->GetBufferPointer() +
606 ( fixedImageParzenWindowIndex
607 * m_JointPDF->GetOffsetTable()[1] );
610 // Move the pointer to the first affected bin
611 int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
612 pdfPtr += pdfMovingIndex;
613 int pdfMovingIndexMax = static_cast<int>(movingImageParzenWindowIndex) + 2;
615 double movingImageParzenWindowArg =
616 static_cast<double>( pdfMovingIndex )
617 - movingImageParzenWindowTerm;
619 while( pdfMovingIndex <= pdfMovingIndexMax ) {
620 *(pdfPtr++) += static_cast<PDFValueType>( m_CubicBSplineKernel
622 movingImageParzenWindowArg ) );
623 movingImageParzenWindowArg += 1;
630 template < class TFixedImage, class TMovingImage >
632 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
633 ::GetValueThreadPostProcess( unsigned int threadID,
634 bool itkNotUsed(withinSampleThread) ) const
639 maxI = m_NumberOfHistogramBins
640 * ( m_ThreaderJointPDFEndBin[threadID]
641 - m_ThreaderJointPDFStartBin[threadID] + 1);
642 JointPDFValueType *pdfPtr;
643 JointPDFValueType *pdfPtrStart;
644 pdfPtrStart = m_JointPDF->GetBufferPointer()
645 + ( m_ThreaderJointPDFStartBin[threadID]
646 * m_JointPDF->GetOffsetTable()[1] );
647 JointPDFValueType *tPdfPtr;
648 JointPDFValueType *tPdfPtrEnd;
649 unsigned int tPdfPtrOffset;
650 tPdfPtrOffset = ( m_ThreaderJointPDFStartBin[threadID]
651 * m_JointPDF->GetOffsetTable()[1] );
652 #if ITK_VERSION_MAJOR <= 4
653 for(t=0; t<this->m_NumberOfThreads-1; t++) {
655 for(t=0; t<this->m_NumberOfWorkUnits-1; t++) {
657 pdfPtr = pdfPtrStart;
658 tPdfPtr = m_ThreaderJointPDF[t]->GetBufferPointer() + tPdfPtrOffset;
659 tPdfPtrEnd = tPdfPtr + maxI;
660 //for(i=0; i < maxI; i++)
661 while(tPdfPtr < tPdfPtrEnd) {
662 *(pdfPtr++) += *(tPdfPtr++);
664 for(i = m_ThreaderJointPDFStartBin[threadID];
665 i <= m_ThreaderJointPDFEndBin[threadID];
667 m_FixedImageMarginalPDF[i] += m_ThreaderFixedImageMarginalPDF[
668 (t*m_NumberOfHistogramBins) + i];
671 double jointPDFSum = 0.0;
672 pdfPtr = pdfPtrStart;
673 for(i = 0; i < maxI; i++) {
674 jointPDFSum += *(pdfPtr++);
677 m_ThreaderJointPDFSum[threadID-1] = jointPDFSum;
679 m_JointPDFSum = jointPDFSum;
683 template < class TFixedImage, class TMovingImage >
684 typename MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
686 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
687 ::GetValue( const ParametersType & parameters ) const
689 // Set up the parameters in the transform
690 this->m_Transform->SetParameters( parameters );
692 // MUST BE CALLED TO INITIATE PROCESSING
693 this->GetValueMultiThreadedInitiate();
695 // MUST BE CALLED TO INITIATE PROCESSING
696 this->GetValueMultiThreadedPostProcessInitiate();
698 #if ITK_VERSION_MAJOR <= 4
699 for(unsigned int threadID = 0; threadID<this->m_NumberOfThreads-1; threadID++) {
701 for(unsigned int threadID = 0; threadID<this->m_NumberOfWorkUnits-1; threadID++) {
703 m_JointPDFSum += m_ThreaderJointPDFSum[threadID];
705 if ( m_JointPDFSum == 0.0 ) {
706 itkExceptionMacro( "Joint PDF summed to zero" );
709 memset( m_MovingImageMarginalPDF,
711 m_NumberOfHistogramBins*sizeof(PDFValueType) );
713 JointPDFValueType * pdfPtr;
714 PDFValueType * movingMarginalPtr;
716 double fixedPDFSum = 0.0;
717 double nFactor = 1.0 / m_JointPDFSum;
718 pdfPtr = m_JointPDF->GetBufferPointer();
719 for(i=0; i<m_NumberOfHistogramBins; i++) {
720 fixedPDFSum += m_FixedImageMarginalPDF[i];
721 movingMarginalPtr = m_MovingImageMarginalPDF;
722 for(j=0; j<m_NumberOfHistogramBins; j++) {
723 *(pdfPtr) *= nFactor;
724 *(movingMarginalPtr++) += *(pdfPtr++);
728 if( this->m_NumberOfPixelsCounted <
729 this->m_NumberOfFixedImageSamples / 16 ) {
730 itkExceptionMacro( "Too many samples map outside moving image buffer: "
731 << this->m_NumberOfPixelsCounted << " / "
732 << this->m_NumberOfFixedImageSamples
736 // Normalize the fixed image marginal PDF
737 if ( fixedPDFSum == 0.0 ) {
738 itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
740 for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
741 m_FixedImageMarginalPDF[bin] /= fixedPDFSum;
745 * Compute the metric by double summation over histogram.
748 // Setup pointer to point to the first bin
749 JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
753 for( unsigned int fixedIndex = 0;
754 fixedIndex < m_NumberOfHistogramBins;
756 double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
758 for( unsigned int movingIndex = 0;
759 movingIndex < m_NumberOfHistogramBins;
760 ++movingIndex, jointPDFPtr++ ) {
761 double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
762 double jointPDFValue = *(jointPDFPtr);
764 // check for non-zero bin contribution
765 if( jointPDFValue > 1e-16 && movingImagePDFValue > 1e-16 ) {
767 double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
768 if( fixedImagePDFValue > 1e-16) {
769 sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
772 } // end if-block to check non-zero bin contribution
773 } // end for-loop over moving index
774 } // end for-loop over fixed index
776 return static_cast<MeasureType>( -1.0 * sum );
781 template < class TFixedImage, class TMovingImage >
783 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
784 ::GetValueAndDerivativeThreadPreProcess( unsigned int threadID,
785 bool itkNotUsed(withinSampleThread) ) const
788 memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(),
790 m_JointPDFBufferSize );
792 memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1)
793 * m_NumberOfHistogramBins]),
795 m_NumberOfHistogramBins*sizeof(PDFValueType) );
797 if( this->m_UseExplicitPDFDerivatives ) {
798 memset( m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer(),
800 m_JointPDFDerivativesBufferSize );
803 memset( m_JointPDF->GetBufferPointer(),
805 m_JointPDFBufferSize );
806 memset( m_FixedImageMarginalPDF,
808 m_NumberOfHistogramBins*sizeof(PDFValueType) );
810 if( this->m_UseExplicitPDFDerivatives ) {
811 memset( m_JointPDFDerivatives->GetBufferPointer(),
813 m_JointPDFDerivativesBufferSize );
818 template < class TFixedImage, class TMovingImage >
820 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
821 ::GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
822 unsigned long fixedImageSample,
823 const MovingImagePointType & itkNotUsed(mappedPoint),
824 double movingImageValue,
825 const ImageDerivativesType &
826 movingImageGradientValue) const
829 * Compute this sample's contribution to the marginal
830 * and joint distributions.
833 if(movingImageValue < m_MovingImageTrueMin) {
835 } else if(movingImageValue > m_MovingImageTrueMax) {
839 unsigned int fixedImageParzenWindowIndex =
840 this->m_FixedImageSamples[fixedImageSample].valueIndex;
842 // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
843 double movingImageParzenWindowTerm = movingImageValue
844 / m_MovingImageBinSize
845 - m_MovingImageNormalizedMin;
846 unsigned int movingImageParzenWindowIndex =
847 static_cast<unsigned int>( movingImageParzenWindowTerm );
849 // Make sure the extreme values are in valid bins
850 if ( movingImageParzenWindowIndex < 2 ) {
851 movingImageParzenWindowIndex = 2;
852 } else if ( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
853 movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
856 // Since a zero-order BSpline (box car) kernel is used for
857 // the fixed image marginal pdf, we need only increment the
858 // fixedImageParzenWindowIndex by value of 1.0.
860 ++m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins
861 + fixedImageParzenWindowIndex];
863 ++m_FixedImageMarginalPDF[fixedImageParzenWindowIndex];
867 * The region of support of the parzen window determines which bins
868 * of the joint PDF are effected by the pair of image values.
869 * Since we are using a cubic spline for the moving image parzen
870 * window, four bins are effected. The fixed image parzen window is
871 * a zero-order spline (box car) and thus effects only one bin.
873 * The PDF is arranged so that moving image bins corresponds to the
874 * zero-th (column) dimension and the fixed image bins corresponds
875 * to the first (row) dimension.
879 // Pointer to affected bin to be updated
880 JointPDFValueType *pdfPtr;
882 pdfPtr = m_ThreaderJointPDF[threadID-1]
883 ->GetBufferPointer() +
884 ( fixedImageParzenWindowIndex
885 * m_NumberOfHistogramBins );
887 pdfPtr = m_JointPDF->GetBufferPointer() +
888 ( fixedImageParzenWindowIndex
889 * m_NumberOfHistogramBins );
892 // Move the pointer to the fist affected bin
893 int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
894 pdfPtr += pdfMovingIndex;
895 int pdfMovingIndexMax = static_cast<int>(movingImageParzenWindowIndex) + 2;
897 double movingImageParzenWindowArg = static_cast<double>( pdfMovingIndex )
898 - static_cast<double>( movingImageParzenWindowTerm );
900 while( pdfMovingIndex <= pdfMovingIndexMax ) {
901 *(pdfPtr++) += static_cast<PDFValueType>( m_CubicBSplineKernel
903 movingImageParzenWindowArg ) );
905 if( this->m_UseExplicitPDFDerivatives || this->m_ImplicitDerivativesSecondPass ) {
906 // Compute the cubicBSplineDerivative for later repeated use.
907 double cubicBSplineDerivativeValue =
908 m_CubicBSplineDerivativeKernel->Evaluate( movingImageParzenWindowArg );
910 // Compute PDF derivative contribution.
911 this->ComputePDFDerivatives( threadID,
914 movingImageGradientValue,
915 cubicBSplineDerivativeValue );
918 movingImageParzenWindowArg += 1;
925 template < class TFixedImage, class TMovingImage >
927 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
928 ::GetValueAndDerivativeThreadPostProcess( unsigned int threadID,
929 bool withinSampleThread ) const
931 this->GetValueThreadPostProcess( threadID, withinSampleThread );
933 if( this->m_UseExplicitPDFDerivatives ) {
934 const unsigned int rowSize = this->m_NumberOfParameters * m_NumberOfHistogramBins;
936 const unsigned int maxI =
937 rowSize * ( m_ThreaderJointPDFEndBin[threadID]
938 - m_ThreaderJointPDFStartBin[threadID] + 1 );
940 JointPDFDerivativesValueType *pdfDPtr;
941 JointPDFDerivativesValueType *pdfDPtrStart;
942 pdfDPtrStart = m_JointPDFDerivatives->GetBufferPointer()
943 + ( m_ThreaderJointPDFStartBin[threadID] * rowSize );
944 JointPDFDerivativesValueType *tPdfDPtr;
945 JointPDFDerivativesValueType *tPdfDPtrEnd;
946 unsigned int tPdfDPtrOffset;
947 tPdfDPtrOffset = m_ThreaderJointPDFStartBin[threadID] * rowSize;
948 #if ITK_VERSION_MAJOR <= 4
949 for(unsigned int t=0; t<this->m_NumberOfThreads-1; t++) {
951 for(unsigned int t=0; t<this->m_NumberOfWorkUnits-1; t++) {
953 pdfDPtr = pdfDPtrStart;
954 tPdfDPtr = m_ThreaderJointPDFDerivatives[t]->GetBufferPointer()
956 tPdfDPtrEnd = tPdfDPtr + maxI;
957 // for(i = 0; i < maxI; i++)
958 while(tPdfDPtr < tPdfDPtrEnd) {
959 *(pdfDPtr++) += *(tPdfDPtr++);
963 double nFactor = 1.0 / (m_MovingImageBinSize
964 * this->m_NumberOfPixelsCounted);
966 pdfDPtr = pdfDPtrStart;
967 tPdfDPtrEnd = pdfDPtrStart + maxI;
968 //for(int i = 0; i < maxI; i++)
969 while(pdfDPtr < tPdfDPtrEnd) {
970 *(pdfDPtr++) *= nFactor;
976 * Get the both Value and Derivative Measure
978 template < class TFixedImage, class TMovingImage >
980 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
981 ::GetValueAndDerivative( const ParametersType & parameters,
983 DerivativeType & derivative) const
985 // Set output values to zero
986 value = NumericTraits< MeasureType >::Zero;
988 if( this->m_UseExplicitPDFDerivatives ) {
989 // Set output values to zero
990 if(derivative.GetSize() != this->m_NumberOfParameters) {
991 derivative = DerivativeType( this->m_NumberOfParameters );
993 memset( derivative.data_block(),
995 this->m_NumberOfParameters * sizeof(double) );
997 this->m_PRatioArray.Fill( 0.0 );
998 this->m_MetricDerivative.Fill( NumericTraits< MeasureType >::Zero );
999 #if ITK_VERSION_MAJOR <= 4
1000 for(unsigned int threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++ ) {
1002 for(unsigned int threadID = 0; threadID < this->m_NumberOfWorkUnits-1; threadID++ ) {
1004 this->m_ThreaderMetricDerivative[threadID].Fill( NumericTraits< MeasureType >::Zero );
1006 this->m_ImplicitDerivativesSecondPass = false;
1009 // Set up the parameters in the transform
1010 this->m_Transform->SetParameters( parameters );
1012 // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES
1013 this->GetValueAndDerivativeMultiThreadedInitiate();
1015 // CALL IF DOING THREADED POST PROCESSING
1016 this->GetValueAndDerivativeMultiThreadedPostProcessInitiate();
1018 #if ITK_VERSION_MAJOR <= 4
1019 for(unsigned int threadID = 0; threadID<this->m_NumberOfThreads-1; threadID++) {
1021 for(unsigned int threadID = 0; threadID<this->m_NumberOfWorkUnits-1; threadID++) {
1023 m_JointPDFSum += m_ThreaderJointPDFSum[threadID];
1025 if ( m_JointPDFSum == 0.0 ) {
1026 itkExceptionMacro( "Joint PDF summed to zero" );
1029 memset( m_MovingImageMarginalPDF,
1031 m_NumberOfHistogramBins*sizeof(PDFValueType) );
1033 JointPDFValueType * pdfPtr;
1034 PDFValueType * movingMarginalPtr;
1036 double fixedPDFSum = 0.0;
1037 const double normalizationFactor = 1.0 / m_JointPDFSum;
1039 pdfPtr = m_JointPDF->GetBufferPointer();
1040 for(i=0; i<m_NumberOfHistogramBins; i++) {
1041 fixedPDFSum += m_FixedImageMarginalPDF[i];
1042 movingMarginalPtr = m_MovingImageMarginalPDF;
1043 for(j=0; j<m_NumberOfHistogramBins; j++) {
1044 *(pdfPtr) *= normalizationFactor;
1045 *(movingMarginalPtr++) += *(pdfPtr++);
1049 if( this->m_NumberOfPixelsCounted <
1050 this->m_NumberOfFixedImageSamples / 16 ) {
1051 itkExceptionMacro( "Too many samples map outside moving image buffer: "
1052 << this->m_NumberOfPixelsCounted << " / "
1053 << this->m_NumberOfFixedImageSamples
1057 // Normalize the fixed image marginal PDF
1058 if ( fixedPDFSum == 0.0 ) {
1059 itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
1061 for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
1062 m_FixedImageMarginalPDF[bin] /= fixedPDFSum;
1066 * Compute the metric by double summation over histogram.
1069 // Setup pointer to point to the first bin
1070 JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
1072 // Initialize sum to zero
1075 const double nFactor = 1.0 / (m_MovingImageBinSize
1076 * this->m_NumberOfPixelsCounted);
1078 for( unsigned int fixedIndex = 0;
1079 fixedIndex < m_NumberOfHistogramBins;
1081 double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
1083 for( unsigned int movingIndex = 0;
1084 movingIndex < m_NumberOfHistogramBins;
1085 ++movingIndex, jointPDFPtr++ ) {
1086 double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
1087 double jointPDFValue = *(jointPDFPtr);
1089 // check for non-zero bin contribution
1090 if( jointPDFValue > 1e-16 && movingImagePDFValue > 1e-16 ) {
1092 double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
1094 if( fixedImagePDFValue > 1e-16) {
1095 sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
1098 if( this->m_UseExplicitPDFDerivatives ) {
1099 // move joint pdf derivative pointer to the right position
1100 JointPDFValueType * derivPtr = m_JointPDFDerivatives->GetBufferPointer()
1101 + ( fixedIndex * m_JointPDFDerivatives->GetOffsetTable()[2] )
1102 + ( movingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
1104 for( unsigned int parameter=0; parameter < this->m_NumberOfParameters; ++parameter, derivPtr++ ) {
1106 // Ref: eqn 23 of Thevenaz & Unser paper [3]
1107 derivative[parameter] -= (*derivPtr) * pRatio;
1109 } // end for-loop over parameters
1111 this->m_PRatioArray[fixedIndex][movingIndex] = pRatio * nFactor;
1113 } // end if-block to check non-zero bin contribution
1114 } // end for-loop over moving index
1115 } // end for-loop over fixed index
1117 if( !(this->m_UseExplicitPDFDerivatives ) ) {
1118 // Second pass: This one is done for accumulating the contributions
1119 // to the derivative array.
1121 this->m_ImplicitDerivativesSecondPass = true;
1123 // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES
1124 this->GetValueAndDerivativeMultiThreadedInitiate();
1126 // CALL IF DOING THREADED POST PROCESSING
1127 this->GetValueAndDerivativeMultiThreadedPostProcessInitiate();
1129 // Consolidate the contributions from each one of the threads to the total
1131 #if ITK_VERSION_MAJOR <= 4
1132 for(unsigned int t = 0; t < this->m_NumberOfThreads-1; t++ ) {
1134 for(unsigned int t = 0; t < this->m_NumberOfWorkUnits-1; t++ ) {
1136 DerivativeType * source = &(this->m_ThreaderMetricDerivative[t]);
1137 for(unsigned int pp=0; pp < this->m_NumberOfParameters; pp++ ) {
1138 this->m_MetricDerivative[pp] += (*source)[pp];
1142 derivative = this->m_MetricDerivative;
1145 value = static_cast<MeasureType>( -1.0 * sum );
1150 * Get the match measure derivative
1152 template < class TFixedImage, class TMovingImage >
1154 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
1155 ::GetDerivative( const ParametersType & parameters,
1156 DerivativeType & derivative ) const
1159 // call the combined version
1160 this->GetValueAndDerivative( parameters, value, derivative );
1165 * Compute PDF derivatives contribution for each parameter
1167 template < class TFixedImage, class TMovingImage >
1169 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
1170 ::ComputePDFDerivatives( unsigned int threadID,
1171 unsigned int sampleNumber,
1173 const ImageDerivativesType & movingImageGradientValue,
1174 double cubicBSplineDerivativeValue ) const
1176 // Update bins in the PDF derivatives for the current intensity pair
1177 // Could pre-compute
1178 JointPDFDerivativesValueType * derivPtr;
1180 double precomputedWeight = 0.0;
1182 const int pdfFixedIndex = this->m_FixedImageSamples[sampleNumber].valueIndex;
1184 DerivativeType * derivativeHelperArray = NULL;
1186 if( this->m_UseExplicitPDFDerivatives ) {
1188 derivPtr = m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer()
1189 + ( pdfFixedIndex * m_JointPDFDerivatives->GetOffsetTable()[2] )
1190 + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
1192 derivPtr = m_JointPDFDerivatives->GetBufferPointer()
1193 + ( pdfFixedIndex * m_JointPDFDerivatives->GetOffsetTable()[2] )
1194 + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
1198 // Recover the precomputed weight for this specific PDF bin
1199 precomputedWeight = this->m_PRatioArray[pdfFixedIndex][pdfMovingIndex];
1201 derivativeHelperArray = &(this->m_ThreaderMetricDerivative[threadID-1]);
1203 derivativeHelperArray = &(this->m_MetricDerivative);
1208 if( !this->m_TransformIsBSpline ) {
1210 * Generic version which works for all transforms.
1213 // Compute the transform Jacobian.
1214 // Should pre-compute
1215 typedef typename TransformType::JacobianType JacobianType;
1217 // Need to use one of the threader transforms if we're
1220 // Use a raw pointer here to avoid the overhead of smart pointers.
1221 // For instance, Register and UnRegister have mutex locks around
1222 // the reference counts.
1223 TransformType* transform;
1226 transform = this->m_ThreaderTransform[threadID - 1];
1228 transform = this->m_Transform;
1231 JacobianType jacobian;
1232 transform->ComputeJacobianWithRespectToParameters(this->m_FixedImageSamples[sampleNumber].point, jacobian);
1234 // for ( unsigned int mu = 0; mu < this->m_NumberOfParameters; mu++ )
1236 // double innerProduct = 0.0;
1237 // for ( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ )
1239 // innerProduct += jacobian[dim][mu] * movingImageGradientValue[dim];
1242 // const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
1244 // if( this->m_UseExplicitPDFDerivatives )
1246 // *(derivPtr) -= derivativeContribution;
1251 // (*derivativeHelperArray)[mu] += precomputedWeight * derivativeContribution;
1256 unsigned int mu, dim;
1257 double innerProduct,derivativeContribution;
1258 for ( mu = 0; mu < this->m_NumberOfParameters; mu+=3 ) {
1259 // JV only for 3D Space BLUT FFD: if J(0, par)=0, then J(1,par+1)=0 & ...
1260 if (jacobian[0][mu])
1261 for ( dim = 0; dim < Superclass::FixedImageDimension; dim++ ) {
1262 innerProduct = jacobian[dim][mu+dim] * movingImageGradientValue[dim];
1263 derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
1265 if( this->m_UseExplicitPDFDerivatives ) {
1266 *(derivPtr) -= derivativeContribution;
1269 (*derivativeHelperArray)[mu+dim] += precomputedWeight * derivativeContribution;
1272 else if( this->m_UseExplicitPDFDerivatives ) derivPtr+=3;
1275 const WeightsValueType * weights = NULL;
1276 const IndexValueType * indices = NULL;
1279 BSplineTransformWeightsType * weightsHelper = NULL;
1280 BSplineTransformIndexArrayType * indicesHelper = NULL;
1282 if( this->m_UseCachingOfBSplineWeights ) {
1284 // If the transform is of type BSplineDeformableTransform, we can obtain
1285 // a speed up by only processing the affected parameters. Note that
1286 // these pointers are just pointing to pre-allocated rows of the caching
1287 // arrays. There is therefore, no need to free this memory.
1289 weights = this->m_BSplineTransformWeightsArray[sampleNumber];
1290 indices = this->m_BSplineTransformIndicesArray[sampleNumber];
1292 if( threadID > 0 ) {
1293 weightsHelper = &(this->m_ThreaderBSplineTransformWeights[threadID-1]);
1294 indicesHelper = &(this->m_ThreaderBSplineTransformIndices[threadID-1]);
1296 weightsHelper = &(this->m_BSplineTransformWeights);
1297 indicesHelper = &(this->m_BSplineTransformIndices);
1300 this->m_BSplineTransform->ComputeJacobianFromBSplineWeightsWithRespectToPosition(
1301 this->m_FixedImageSamples[sampleNumber].point,
1302 *weightsHelper, *indicesHelper );
1305 for( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ ) {
1307 double innerProduct;
1310 for( unsigned int mu = 0; mu < this->m_NumBSplineWeights; mu++ ) {
1312 /* The array weights contains the Jacobian values in a 1-D array
1313 * (because for each parameter the Jacobian is non-zero in only 1 of the
1314 * possible dimensions) which is multiplied by the moving image
1316 if( this->m_UseCachingOfBSplineWeights ) {
1317 innerProduct = movingImageGradientValue[dim] * weights[mu];
1318 parameterIndex = indices[mu] + this->m_BSplineParametersOffset[dim];
1320 innerProduct = movingImageGradientValue[dim] * (*weightsHelper)[mu];
1321 parameterIndex = (*indicesHelper)[mu] + this->m_BSplineParametersOffset[dim];
1324 const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
1326 if( this->m_UseExplicitPDFDerivatives ) {
1327 JointPDFValueType * ptr = derivPtr + parameterIndex;
1328 *(ptr) -= derivativeContribution;
1330 (*derivativeHelperArray)[parameterIndex] += precomputedWeight * derivativeContribution;
1334 } //end dim for loop
1336 } // end if-block transform is BSpline
1341 } // end namespace itk