]> Creatis software - clitk.git/blob - registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx
Remove ITK3 and ITK4.2 tests and dependencies
[clitk.git] / registration / itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to:
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
8
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.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18
19 /*=========================================================================
20
21 Program:   Insight Segmentation & Registration Toolkit
22 Module:    $RCSfile: itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx,v $
23 Language:  C++
24 Date:      $Date: 2010/06/14 17:32:07 $
25 Version:   $Revision: 1.1 $
26
27 Copyright (c) Insight Software Consortium. All rights reserved.
28 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
29
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.
33
34 =========================================================================*/
35 #ifndef __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
36 #define __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
37
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"
46
47 #include "vnl/vnl_vector.txx"
48 #include "vnl/vnl_c_vector.txx"
49
50 namespace itk
51 {
52
53 /**
54  * Constructor
55  */
56 template < class TFixedImage, class TMovingImage >
57 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
58 ::MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
59 {
60   m_NumberOfHistogramBins = 50;
61
62   this->SetComputeGradient(false); // don't use the default gradient for now
63
64   // Initialize PDFs to NULL
65   m_JointPDF = NULL;
66   m_JointPDFDerivatives = NULL;
67
68   // Initialize memory
69   m_FixedImageMarginalPDF = NULL;
70   m_MovingImageMarginalPDF = NULL;
71
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;
78
79   m_CubicBSplineDerivativeKernel = NULL;
80
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;
90
91   this->m_ThreaderMetricDerivative = NULL;
92   this->m_UseExplicitPDFDerivatives = true;
93   this->m_ImplicitDerivativesSecondPass = false;
94 }
95
96 template < class TFixedImage, class TMovingImage >
97 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
98 ::~MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
99 {
100
101   if(m_FixedImageMarginalPDF != NULL) {
102     delete [] m_FixedImageMarginalPDF;
103   }
104   m_FixedImageMarginalPDF = NULL;
105   if(m_MovingImageMarginalPDF != NULL) {
106     delete [] m_MovingImageMarginalPDF;
107   }
108   m_MovingImageMarginalPDF = NULL;
109   if(m_ThreaderJointPDF != NULL) {
110     delete [] m_ThreaderJointPDF;
111   }
112   m_ThreaderJointPDF = NULL;
113
114   if(m_ThreaderJointPDFDerivatives != NULL) {
115     delete [] m_ThreaderJointPDFDerivatives;
116   }
117   m_ThreaderJointPDFDerivatives = NULL;
118
119   if(m_ThreaderFixedImageMarginalPDF != NULL) {
120     delete [] m_ThreaderFixedImageMarginalPDF;
121   }
122   m_ThreaderFixedImageMarginalPDF = NULL;
123
124   if(m_ThreaderJointPDFStartBin != NULL) {
125     delete [] m_ThreaderJointPDFStartBin;
126   }
127   m_ThreaderJointPDFStartBin = NULL;
128
129   if(m_ThreaderJointPDFEndBin != NULL) {
130     delete [] m_ThreaderJointPDFEndBin;
131   }
132   m_ThreaderJointPDFEndBin = NULL;
133
134   if(m_ThreaderJointPDFSum != NULL) {
135     delete [] m_ThreaderJointPDFSum;
136   }
137   m_ThreaderJointPDFSum = NULL;
138
139   if( this->m_ThreaderMetricDerivative != NULL ) {
140     delete [] this->m_ThreaderMetricDerivative;
141   }
142   this->m_ThreaderMetricDerivative = NULL;
143 }
144
145 /**
146  * Print out internal information about this class
147  */
148 template < class TFixedImage, class TMovingImage  >
149 void
150 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
151 ::PrintSelf(std::ostream& os, Indent indent) const
152 {
153
154   Superclass::PrintSelf(os, indent);
155
156   os << indent << "NumberOfHistogramBins: ";
157   os << this->m_NumberOfHistogramBins << std::endl;
158
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;
176
177 }
178
179
180 /**
181  * Initialize
182  */
183 template <class TFixedImage, class TMovingImage>
184 void
185 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
186 ::Initialize(void) throw ( ExceptionObject )
187 {
188   this->Superclass::Initialize();
189   this->Superclass::MultiThreadingInitialize();
190
191   typedef StatisticsImageFilter<FixedImageType> FixedImageStatisticsFilterType;
192   typename FixedImageStatisticsFilterType::Pointer fixedImageStats =
193     FixedImageStatisticsFilterType::New();
194   fixedImageStats->SetInput( this->m_FixedImage );
195   fixedImageStats->SetNumberOfThreads( this->m_NumberOfThreads );
196   fixedImageStats->Update();
197
198   m_FixedImageTrueMin = fixedImageStats->GetMinimum();
199   m_FixedImageTrueMax = fixedImageStats->GetMaximum();
200   double fixedImageMin = m_FixedImageTrueMin;
201   double fixedImageMax = m_FixedImageTrueMax;
202
203   typedef StatisticsImageFilter<MovingImageType>
204   MovingImageStatisticsFilterType;
205   typename MovingImageStatisticsFilterType::Pointer movingImageStats =
206     MovingImageStatisticsFilterType::New();
207   movingImageStats->SetInput( this->m_MovingImage );
208   movingImageStats->SetNumberOfThreads( this->m_NumberOfThreads );
209   movingImageStats->Update();
210
211   m_MovingImageTrueMin = movingImageStats->GetMinimum();
212   m_MovingImageTrueMax = movingImageStats->GetMaximum();
213   double movingImageMin = m_MovingImageTrueMin;
214   double movingImageMax = m_MovingImageTrueMax;
215
216   itkDebugMacro( " FixedImageMin: " << fixedImageMin <<
217                  " FixedImageMax: " << fixedImageMax << std::endl );
218   itkDebugMacro( " MovingImageMin: " << movingImageMin <<
219                  " MovingImageMax: " << movingImageMax << std::endl );
220
221
222   /**
223    * Compute binsize for the histograms.
224    *
225    * The binsize for the image intensities needs to be adjusted so that
226    * we can avoid dealing with boundary conditions using the cubic
227    * spline as the Parzen window.  We do this by increasing the size
228    * of the bins so that the joint histogram becomes "padded" at the
229    * borders. Because we are changing the binsize,
230    * we also need to shift the minimum by the padded amount in order to
231    * avoid minimum values filling in our padded region.
232    *
233    * Note that there can still be non-zero bin values in the padded region,
234    * it's just that these bins will never be a central bin for the Parzen
235    * window.
236    *
237    */
238   const int padding = 2;  // this will pad by 2 bins
239
240   m_FixedImageBinSize = ( fixedImageMax - fixedImageMin )
241                         / static_cast<double>( m_NumberOfHistogramBins
242                             - 2 * padding );
243   m_FixedImageNormalizedMin = fixedImageMin / m_FixedImageBinSize
244                               - static_cast<double>( padding );
245
246   m_MovingImageBinSize = ( movingImageMax - movingImageMin )
247                          / static_cast<double>( m_NumberOfHistogramBins
248                              - 2 * padding );
249   m_MovingImageNormalizedMin = movingImageMin / m_MovingImageBinSize
250                                - static_cast<double>( padding );
251
252   itkDebugMacro( "FixedImageNormalizedMin: " << m_FixedImageNormalizedMin );
253   itkDebugMacro( "MovingImageNormalizedMin: " << m_MovingImageNormalizedMin );
254   itkDebugMacro( "FixedImageBinSize: " << m_FixedImageBinSize );
255   itkDebugMacro( "MovingImageBinSize; " << m_MovingImageBinSize );
256
257
258   /**
259    * Allocate memory for the marginal PDF and initialize values
260    * to zero. The marginal PDFs are stored as std::vector.
261    */
262   if(m_FixedImageMarginalPDF != NULL) {
263     delete [] m_FixedImageMarginalPDF;
264   }
265   m_FixedImageMarginalPDF = new PDFValueType[m_NumberOfHistogramBins];
266   if(m_MovingImageMarginalPDF != NULL) {
267     delete [] m_MovingImageMarginalPDF;
268   }
269   m_MovingImageMarginalPDF = new PDFValueType[m_NumberOfHistogramBins];
270
271   /**
272    * Allocate memory for the joint PDF and joint PDF derivatives.
273    * The joint PDF and joint PDF derivatives are store as itk::Image.
274    */
275   m_JointPDF = JointPDFType::New();
276   m_JointPDFDerivatives = JointPDFDerivativesType::New();
277
278   // Instantiate a region, index, size
279   JointPDFRegionType             jointPDFRegion;
280   JointPDFIndexType              jointPDFIndex;
281   JointPDFSizeType               jointPDFSize;
282
283   // Deallocate the memory that may have been allocated for
284   // previous runs of the metric.
285   this->m_JointPDFDerivatives = NULL;  // by destroying the dynamic array
286   this->m_PRatioArray.SetSize( 1, 1 ); // and by allocating very small the static ones
287   this->m_MetricDerivative = DerivativeType( 1 );
288
289   JointPDFDerivativesRegionType  jointPDFDerivativesRegion;
290
291   //
292   // Now allocate memory according to the user-selected method.
293   //
294   if( this->m_UseExplicitPDFDerivatives ) {
295     this->m_JointPDFDerivatives = JointPDFDerivativesType::New();
296
297     JointPDFDerivativesIndexType  jointPDFDerivativesIndex;
298     JointPDFDerivativesSizeType    jointPDFDerivativesSize;
299
300     // For the derivatives of the joint PDF define a region starting from {0,0,0}
301     // with size {m_NumberOfParameters,m_NumberOfHistogramBins,
302     // m_NumberOfHistogramBins}. The dimension represents transform parameters,
303     // fixed image parzen window index and moving image parzen window index,
304     // respectively.
305     jointPDFDerivativesIndex.Fill( 0 );
306     jointPDFDerivativesSize[0] = this->m_NumberOfParameters;
307     jointPDFDerivativesSize[1] = this->m_NumberOfHistogramBins;
308     jointPDFDerivativesSize[2] = this->m_NumberOfHistogramBins;
309
310     jointPDFDerivativesRegion.SetIndex( jointPDFDerivativesIndex );
311     jointPDFDerivativesRegion.SetSize( jointPDFDerivativesSize );
312
313     // Set the regions and allocate
314     m_JointPDFDerivatives->SetRegions( jointPDFDerivativesRegion );
315     m_JointPDFDerivatives->Allocate();
316     m_JointPDFDerivativesBufferSize = jointPDFDerivativesSize[0]
317                                       * jointPDFDerivativesSize[1]
318                                       * jointPDFDerivativesSize[2]
319                                       * sizeof(JointPDFDerivativesValueType);
320
321   } else {
322     /** Allocate memory for helper array that will contain the pRatios
323      *  for each bin of the joint histogram. This is part of the effort
324      *  for flattening the computation of the PDF Jacobians.
325      */
326     this->m_PRatioArray.SetSize( this->m_NumberOfHistogramBins, this->m_NumberOfHistogramBins );
327     this->m_MetricDerivative = DerivativeType( this->GetNumberOfParameters() );
328   }
329
330   // For the joint PDF define a region starting from {0,0}
331   // with size {m_NumberOfHistogramBins, m_NumberOfHistogramBins}.
332   // The dimension represents fixed image parzen window index
333   // and moving image parzen window index, respectively.
334   jointPDFIndex.Fill( 0 );
335   jointPDFSize.Fill( m_NumberOfHistogramBins );
336
337   jointPDFRegion.SetIndex( jointPDFIndex );
338   jointPDFRegion.SetSize( jointPDFSize );
339
340   // Set the regions and allocate
341   m_JointPDF->SetRegions( jointPDFRegion );
342   m_JointPDF->Allocate();
343
344   m_JointPDFBufferSize = jointPDFSize[0] * jointPDFSize[1] * sizeof(PDFValueType);
345
346
347   /**
348    * Setup the kernels used for the Parzen windows.
349    */
350   m_CubicBSplineKernel = CubicBSplineFunctionType::New();
351   m_CubicBSplineDerivativeKernel = CubicBSplineDerivativeFunctionType::New();
352
353   /**
354    * Pre-compute the fixed image parzen window index for
355    * each point of the fixed image sample points list.
356    */
357   this->ComputeFixedImageParzenWindowIndices( this->m_FixedImageSamples );
358
359
360   if(m_ThreaderFixedImageMarginalPDF != NULL) {
361     delete [] m_ThreaderFixedImageMarginalPDF;
362   }
363   // Assumes number of threads doesn't change between calls to Initialize
364   m_ThreaderFixedImageMarginalPDF = new
365   PDFValueType[(this->m_NumberOfThreads-1)
366                * m_NumberOfHistogramBins];
367
368   if(m_ThreaderJointPDF != NULL) {
369     delete [] m_ThreaderJointPDF;
370   }
371   m_ThreaderJointPDF = new typename
372   JointPDFType::Pointer[this->m_NumberOfThreads-1];
373
374   if(m_ThreaderJointPDFStartBin != NULL) {
375     delete [] m_ThreaderJointPDFStartBin;
376   }
377   m_ThreaderJointPDFStartBin = new int[this->m_NumberOfThreads];
378
379   if(m_ThreaderJointPDFEndBin != NULL) {
380     delete [] m_ThreaderJointPDFEndBin;
381   }
382   m_ThreaderJointPDFEndBin = new int[this->m_NumberOfThreads];
383
384   if(m_ThreaderJointPDFSum != NULL) {
385     delete [] m_ThreaderJointPDFSum;
386   }
387   m_ThreaderJointPDFSum = new double[this->m_NumberOfThreads];
388
389   unsigned int threadID;
390
391   int binRange = m_NumberOfHistogramBins / this->m_NumberOfThreads;
392
393   for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
394     m_ThreaderJointPDF[threadID] = JointPDFType::New();
395     m_ThreaderJointPDF[threadID]->SetRegions( jointPDFRegion );
396     m_ThreaderJointPDF[threadID]->Allocate();
397
398     m_ThreaderJointPDFStartBin[threadID] = threadID * binRange;
399     m_ThreaderJointPDFEndBin[threadID] = (threadID + 1) * binRange - 1;
400   }
401
402   m_ThreaderJointPDFStartBin[this->m_NumberOfThreads-1] =
403     (this->m_NumberOfThreads - 1 ) * binRange;
404
405   m_ThreaderJointPDFEndBin[this->m_NumberOfThreads-1] = m_NumberOfHistogramBins - 1;
406
407   // Release memory of arrays that may have been used for
408   // previous executions of this metric with different settings
409   // of the memory caching flags.
410   if(m_ThreaderJointPDFDerivatives != NULL) {
411     delete [] m_ThreaderJointPDFDerivatives;
412   }
413   m_ThreaderJointPDFDerivatives = NULL;
414
415   if(m_ThreaderMetricDerivative != NULL) {
416     delete [] m_ThreaderMetricDerivative;
417   }
418   m_ThreaderMetricDerivative = NULL;
419
420
421   if( this->m_UseExplicitPDFDerivatives ) {
422     m_ThreaderJointPDFDerivatives = new typename
423     JointPDFDerivativesType::Pointer[this->m_NumberOfThreads-1];
424
425     for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
426       m_ThreaderJointPDFDerivatives[threadID] = JointPDFDerivativesType::New();
427       m_ThreaderJointPDFDerivatives[threadID]->SetRegions(
428         jointPDFDerivativesRegion );
429       m_ThreaderJointPDFDerivatives[threadID]->Allocate();
430     }
431   } else {
432     m_ThreaderMetricDerivative = new DerivativeType[this->m_NumberOfThreads-1];
433
434     for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
435       this->m_ThreaderMetricDerivative[threadID] = DerivativeType( this->GetNumberOfParameters() );
436     }
437   }
438 }
439
440 /**
441  * Uniformly sample the fixed image domain using a random walk
442  */
443 template < class TFixedImage, class TMovingImage >
444 void
445 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
446 ::ComputeFixedImageParzenWindowIndices(
447   FixedImageSampleContainer& samples )
448 {
449
450   typename FixedImageSampleContainer::iterator iter;
451   typename FixedImageSampleContainer::const_iterator end=samples.end();
452
453   for( iter=samples.begin(); iter != end; ++iter ) {
454
455     // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
456     double windowTerm = static_cast<double>( (*iter).value )
457                         / m_FixedImageBinSize
458                         - m_FixedImageNormalizedMin;
459     unsigned int pindex = static_cast<unsigned int>( windowTerm );
460
461     // Make sure the extreme values are in valid bins
462     if ( pindex < 2 ) {
463       pindex = 2;
464     } else if ( pindex > (m_NumberOfHistogramBins - 3) ) {
465       pindex = m_NumberOfHistogramBins - 3;
466     }
467
468     (*iter).valueIndex = pindex;
469   }
470
471 }
472
473 template < class TFixedImage, class TMovingImage  >
474 inline void
475 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
476 ::GetValueThreadPreProcess( unsigned int threadID,
477                             bool withinSampleThread ) const
478 {
479
480   this->Superclass::GetValueThreadPreProcess( threadID, withinSampleThread );
481
482   if(threadID > 0) {
483     memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(),
484             0,
485             m_JointPDFBufferSize );
486     memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1)
487               *m_NumberOfHistogramBins]),
488             0,
489             m_NumberOfHistogramBins*sizeof(PDFValueType) );
490   } else {
491     // zero-th thread uses the variables directly
492     memset( m_JointPDF->GetBufferPointer(),
493             0,
494             m_JointPDFBufferSize );
495     memset( m_FixedImageMarginalPDF,
496             0,
497             m_NumberOfHistogramBins*sizeof(PDFValueType) );
498   }
499 }
500
501 template < class TFixedImage, class TMovingImage  >
502 inline bool
503 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
504 ::GetValueThreadProcessSample( unsigned int threadID,
505                                unsigned long fixedImageSample,
506                                const MovingImagePointType & itkNotUsed(mappedPoint),
507                                double movingImageValue) const
508 {
509   /**
510    * Compute this sample's contribution to the marginal and
511    * joint distributions.
512    *
513    */
514
515   if(movingImageValue < m_MovingImageTrueMin) {
516     return false;
517   } else if(movingImageValue > m_MovingImageTrueMax) {
518     return false;
519   }
520
521   // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
522   double movingImageParzenWindowTerm = movingImageValue
523                                        / m_MovingImageBinSize
524                                        - m_MovingImageNormalizedMin;
525   // Same as floor
526   unsigned int movingImageParzenWindowIndex =
527     static_cast<unsigned int>( movingImageParzenWindowTerm );
528   if( movingImageParzenWindowIndex < 2 ) {
529     movingImageParzenWindowIndex = 2;
530   } else if( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
531     movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
532   }
533
534   unsigned int fixedImageParzenWindowIndex =
535     this->m_FixedImageSamples[fixedImageSample].valueIndex;
536   if(threadID > 0) {
537     m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins
538                                     + fixedImageParzenWindowIndex] += 1;
539   } else {
540     m_FixedImageMarginalPDF[fixedImageParzenWindowIndex] += 1;
541   }
542
543   // Pointer to affected bin to be updated
544   JointPDFValueType *pdfPtr;
545   if(threadID > 0) {
546     pdfPtr = m_ThreaderJointPDF[threadID-1]->GetBufferPointer() +
547              ( fixedImageParzenWindowIndex
548                * m_ThreaderJointPDF[threadID-1]
549                ->GetOffsetTable()[1] );
550   } else {
551     pdfPtr = m_JointPDF->GetBufferPointer() +
552              ( fixedImageParzenWindowIndex
553                * m_JointPDF->GetOffsetTable()[1] );
554   }
555
556   // Move the pointer to the first affected bin
557   int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
558   pdfPtr += pdfMovingIndex;
559   int pdfMovingIndexMax = static_cast<int>(movingImageParzenWindowIndex) + 2;
560
561   double movingImageParzenWindowArg =
562     static_cast<double>( pdfMovingIndex )
563     - movingImageParzenWindowTerm;
564
565   while( pdfMovingIndex <= pdfMovingIndexMax ) {
566     *(pdfPtr++) += static_cast<PDFValueType>( m_CubicBSplineKernel
567                    ->Evaluate(
568                      movingImageParzenWindowArg ) );
569     movingImageParzenWindowArg += 1;
570     ++pdfMovingIndex;
571   }
572
573   return true;
574 }
575
576 template < class TFixedImage, class TMovingImage  >
577 inline void
578 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
579 ::GetValueThreadPostProcess( unsigned int threadID,
580                              bool itkNotUsed(withinSampleThread) ) const
581 {
582   unsigned int t;
583   int i;
584   int maxI;
585   maxI = m_NumberOfHistogramBins
586          * ( m_ThreaderJointPDFEndBin[threadID]
587              - m_ThreaderJointPDFStartBin[threadID] + 1);
588   JointPDFValueType *pdfPtr;
589   JointPDFValueType *pdfPtrStart;
590   pdfPtrStart = m_JointPDF->GetBufferPointer()
591                 + ( m_ThreaderJointPDFStartBin[threadID]
592                     * m_JointPDF->GetOffsetTable()[1] );
593   JointPDFValueType *tPdfPtr;
594   JointPDFValueType *tPdfPtrEnd;
595   unsigned int       tPdfPtrOffset;
596   tPdfPtrOffset = ( m_ThreaderJointPDFStartBin[threadID]
597                     * m_JointPDF->GetOffsetTable()[1] );
598   for(t=0; t<this->m_NumberOfThreads-1; t++) {
599     pdfPtr = pdfPtrStart;
600     tPdfPtr = m_ThreaderJointPDF[t]->GetBufferPointer() + tPdfPtrOffset;
601     tPdfPtrEnd = tPdfPtr + maxI;
602     //for(i=0; i < maxI; i++)
603     while(tPdfPtr < tPdfPtrEnd) {
604       *(pdfPtr++) += *(tPdfPtr++);
605     }
606     for(i = m_ThreaderJointPDFStartBin[threadID];
607         i <= m_ThreaderJointPDFEndBin[threadID];
608         i++) {
609       m_FixedImageMarginalPDF[i] += m_ThreaderFixedImageMarginalPDF[
610                                       (t*m_NumberOfHistogramBins) + i];
611     }
612   }
613   double jointPDFSum = 0.0;
614   pdfPtr = pdfPtrStart;
615   for(i = 0; i < maxI; i++) {
616     jointPDFSum += *(pdfPtr++);
617   }
618   if(threadID > 0) {
619     m_ThreaderJointPDFSum[threadID-1] = jointPDFSum;
620   } else {
621     m_JointPDFSum = jointPDFSum;
622   }
623 }
624
625 template < class TFixedImage, class TMovingImage  >
626 typename MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
627 ::MeasureType
628 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
629 ::GetValue( const ParametersType & parameters ) const
630 {
631   // Set up the parameters in the transform
632   this->m_Transform->SetParameters( parameters );
633
634   // MUST BE CALLED TO INITIATE PROCESSING
635   this->GetValueMultiThreadedInitiate();
636
637   // MUST BE CALLED TO INITIATE PROCESSING
638   this->GetValueMultiThreadedPostProcessInitiate();
639
640   for(unsigned int threadID = 0; threadID<this->m_NumberOfThreads-1; threadID++) {
641     m_JointPDFSum += m_ThreaderJointPDFSum[threadID];
642   }
643   if ( m_JointPDFSum == 0.0 ) {
644     itkExceptionMacro( "Joint PDF summed to zero" );
645   }
646
647   memset( m_MovingImageMarginalPDF,
648           0,
649           m_NumberOfHistogramBins*sizeof(PDFValueType) );
650
651   JointPDFValueType * pdfPtr;
652   PDFValueType * movingMarginalPtr;
653   unsigned int i, j;
654   double fixedPDFSum = 0.0;
655   double nFactor = 1.0 / m_JointPDFSum;
656   pdfPtr = m_JointPDF->GetBufferPointer();
657   for(i=0; i<m_NumberOfHistogramBins; i++) {
658     fixedPDFSum += m_FixedImageMarginalPDF[i];
659     movingMarginalPtr = m_MovingImageMarginalPDF;
660     for(j=0; j<m_NumberOfHistogramBins; j++) {
661       *(pdfPtr) *= nFactor;
662       *(movingMarginalPtr++) += *(pdfPtr++);
663     }
664   }
665
666   if( this->m_NumberOfPixelsCounted <
667       this->m_NumberOfFixedImageSamples / 16 ) {
668     itkExceptionMacro( "Too many samples map outside moving image buffer: "
669                        << this->m_NumberOfPixelsCounted << " / "
670                        << this->m_NumberOfFixedImageSamples
671                        << std::endl );
672   }
673
674   // Normalize the fixed image marginal PDF
675   if ( fixedPDFSum == 0.0 ) {
676     itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
677   }
678   for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
679     m_FixedImageMarginalPDF[bin] /= fixedPDFSum;
680   }
681
682   /**
683    * Compute the metric by double summation over histogram.
684    */
685
686   // Setup pointer to point to the first bin
687   JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
688
689   double sum = 0.0;
690
691   for( unsigned int fixedIndex = 0;
692        fixedIndex < m_NumberOfHistogramBins;
693        ++fixedIndex ) {
694     double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
695
696     for( unsigned int movingIndex = 0;
697          movingIndex < m_NumberOfHistogramBins;
698          ++movingIndex, jointPDFPtr++ ) {
699       double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
700       double jointPDFValue = *(jointPDFPtr);
701
702       // check for non-zero bin contribution
703       if( jointPDFValue > 1e-16 &&  movingImagePDFValue > 1e-16 ) {
704
705         double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
706         if( fixedImagePDFValue > 1e-16) {
707           sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
708         }
709
710       }  // end if-block to check non-zero bin contribution
711     }  // end for-loop over moving index
712   }  // end for-loop over fixed index
713
714   return static_cast<MeasureType>( -1.0 * sum );
715
716 }
717
718
719 template < class TFixedImage, class TMovingImage  >
720 inline void
721 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
722 ::GetValueAndDerivativeThreadPreProcess( unsigned int threadID,
723     bool itkNotUsed(withinSampleThread) ) const
724 {
725   if(threadID > 0) {
726     memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(),
727             0,
728             m_JointPDFBufferSize );
729
730     memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1)
731               * m_NumberOfHistogramBins]),
732             0,
733             m_NumberOfHistogramBins*sizeof(PDFValueType) );
734
735     if( this->m_UseExplicitPDFDerivatives ) {
736       memset( m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer(),
737               0,
738               m_JointPDFDerivativesBufferSize );
739     }
740   } else {
741     memset( m_JointPDF->GetBufferPointer(),
742             0,
743             m_JointPDFBufferSize );
744     memset( m_FixedImageMarginalPDF,
745             0,
746             m_NumberOfHistogramBins*sizeof(PDFValueType) );
747
748     if( this->m_UseExplicitPDFDerivatives ) {
749       memset( m_JointPDFDerivatives->GetBufferPointer(),
750               0,
751               m_JointPDFDerivativesBufferSize );
752     }
753   }
754 }
755
756 template < class TFixedImage, class TMovingImage  >
757 inline bool
758 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
759 ::GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
760     unsigned long fixedImageSample,
761     const MovingImagePointType & itkNotUsed(mappedPoint),
762     double movingImageValue,
763     const ImageDerivativesType &
764     movingImageGradientValue) const
765 {
766   /**
767    * Compute this sample's contribution to the marginal
768    *   and joint distributions.
769    *
770    */
771   if(movingImageValue < m_MovingImageTrueMin) {
772     return false;
773   } else if(movingImageValue > m_MovingImageTrueMax) {
774     return false;
775   }
776
777   unsigned int fixedImageParzenWindowIndex =
778     this->m_FixedImageSamples[fixedImageSample].valueIndex;
779
780   // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
781   double movingImageParzenWindowTerm = movingImageValue
782                                        / m_MovingImageBinSize
783                                        - m_MovingImageNormalizedMin;
784   unsigned int movingImageParzenWindowIndex =
785     static_cast<unsigned int>( movingImageParzenWindowTerm );
786
787   // Make sure the extreme values are in valid bins
788   if ( movingImageParzenWindowIndex < 2 ) {
789     movingImageParzenWindowIndex = 2;
790   } else if ( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
791     movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
792   }
793
794   // Since a zero-order BSpline (box car) kernel is used for
795   // the fixed image marginal pdf, we need only increment the
796   // fixedImageParzenWindowIndex by value of 1.0.
797   if(threadID > 0) {
798     ++m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins
799                                       + fixedImageParzenWindowIndex];
800   } else {
801     ++m_FixedImageMarginalPDF[fixedImageParzenWindowIndex];
802   }
803
804   /**
805    * The region of support of the parzen window determines which bins
806    * of the joint PDF are effected by the pair of image values.
807    * Since we are using a cubic spline for the moving image parzen
808    * window, four bins are effected.  The fixed image parzen window is
809    * a zero-order spline (box car) and thus effects only one bin.
810    *
811    *  The PDF is arranged so that moving image bins corresponds to the
812    * zero-th (column) dimension and the fixed image bins corresponds
813    * to the first (row) dimension.
814    *
815    */
816
817   // Pointer to affected bin to be updated
818   JointPDFValueType *pdfPtr;
819   if(threadID > 0) {
820     pdfPtr = m_ThreaderJointPDF[threadID-1]
821              ->GetBufferPointer() +
822              ( fixedImageParzenWindowIndex
823                * m_NumberOfHistogramBins );
824   } else {
825     pdfPtr = m_JointPDF->GetBufferPointer() +
826              ( fixedImageParzenWindowIndex
827                * m_NumberOfHistogramBins );
828   }
829
830   // Move the pointer to the fist affected bin
831   int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
832   pdfPtr += pdfMovingIndex;
833   int pdfMovingIndexMax = static_cast<int>(movingImageParzenWindowIndex) + 2;
834
835   double movingImageParzenWindowArg = static_cast<double>( pdfMovingIndex )
836                                       - static_cast<double>( movingImageParzenWindowTerm );
837
838   while( pdfMovingIndex <= pdfMovingIndexMax ) {
839     *(pdfPtr++) += static_cast<PDFValueType>( m_CubicBSplineKernel
840                    ->Evaluate(
841                      movingImageParzenWindowArg ) );
842
843     if( this->m_UseExplicitPDFDerivatives || this->m_ImplicitDerivativesSecondPass ) {
844       // Compute the cubicBSplineDerivative for later repeated use.
845       double cubicBSplineDerivativeValue =
846         m_CubicBSplineDerivativeKernel->Evaluate( movingImageParzenWindowArg );
847
848       // Compute PDF derivative contribution.
849       this->ComputePDFDerivatives( threadID,
850                                    fixedImageSample,
851                                    pdfMovingIndex,
852                                    movingImageGradientValue,
853                                    cubicBSplineDerivativeValue );
854     }
855
856     movingImageParzenWindowArg += 1;
857     ++pdfMovingIndex;
858   }
859
860   return true;
861 }
862
863 template < class TFixedImage, class TMovingImage  >
864 inline void
865 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
866 ::GetValueAndDerivativeThreadPostProcess( unsigned int threadID,
867     bool withinSampleThread ) const
868 {
869   this->GetValueThreadPostProcess( threadID, withinSampleThread );
870
871   if( this->m_UseExplicitPDFDerivatives ) {
872     const unsigned int rowSize = this->m_NumberOfParameters * m_NumberOfHistogramBins;
873
874     const unsigned int maxI =
875       rowSize * ( m_ThreaderJointPDFEndBin[threadID]
876                   - m_ThreaderJointPDFStartBin[threadID] + 1 );
877
878     JointPDFDerivativesValueType *pdfDPtr;
879     JointPDFDerivativesValueType *pdfDPtrStart;
880     pdfDPtrStart = m_JointPDFDerivatives->GetBufferPointer()
881                    + ( m_ThreaderJointPDFStartBin[threadID] * rowSize );
882     JointPDFDerivativesValueType *tPdfDPtr;
883     JointPDFDerivativesValueType *tPdfDPtrEnd;
884     unsigned int tPdfDPtrOffset;
885     tPdfDPtrOffset = m_ThreaderJointPDFStartBin[threadID] *  rowSize;
886     for(unsigned int t=0; t<this->m_NumberOfThreads-1; t++) {
887       pdfDPtr = pdfDPtrStart;
888       tPdfDPtr = m_ThreaderJointPDFDerivatives[t]->GetBufferPointer()
889                  + tPdfDPtrOffset;
890       tPdfDPtrEnd = tPdfDPtr + maxI;
891       // for(i = 0; i < maxI; i++)
892       while(tPdfDPtr < tPdfDPtrEnd) {
893         *(pdfDPtr++) += *(tPdfDPtr++);
894       }
895     }
896
897     double nFactor = 1.0 / (m_MovingImageBinSize
898                             * this->m_NumberOfPixelsCounted);
899
900     pdfDPtr = pdfDPtrStart;
901     tPdfDPtrEnd = pdfDPtrStart + maxI;
902     //for(int i = 0; i < maxI; i++)
903     while(pdfDPtr < tPdfDPtrEnd) {
904       *(pdfDPtr++) *= nFactor;
905     }
906   }
907 }
908
909 /**
910  * Get the both Value and Derivative Measure
911  */
912 template < class TFixedImage, class TMovingImage  >
913 void
914 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
915 ::GetValueAndDerivative( const ParametersType & parameters,
916                          MeasureType & value,
917                          DerivativeType & derivative) const
918 {
919   // Set output values to zero
920   value = NumericTraits< MeasureType >::Zero;
921
922   if( this->m_UseExplicitPDFDerivatives ) {
923     // Set output values to zero
924     if(derivative.GetSize() != this->m_NumberOfParameters) {
925       derivative = DerivativeType( this->m_NumberOfParameters );
926     }
927     memset( derivative.data_block(),
928             0,
929             this->m_NumberOfParameters * sizeof(double) );
930   } else {
931     this->m_PRatioArray.Fill( 0.0 );
932     this->m_MetricDerivative.Fill( NumericTraits< MeasureType >::Zero );
933     for(unsigned int threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++ ) {
934       this->m_ThreaderMetricDerivative[threadID].Fill( NumericTraits< MeasureType >::Zero );
935     }
936     this->m_ImplicitDerivativesSecondPass = false;
937   }
938
939   // Set up the parameters in the transform
940   this->m_Transform->SetParameters( parameters );
941
942   // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES
943   this->GetValueAndDerivativeMultiThreadedInitiate();
944
945   // CALL IF DOING THREADED POST PROCESSING
946   this->GetValueAndDerivativeMultiThreadedPostProcessInitiate();
947
948   for(unsigned int threadID = 0; threadID<this->m_NumberOfThreads-1; threadID++) {
949     m_JointPDFSum += m_ThreaderJointPDFSum[threadID];
950   }
951   if ( m_JointPDFSum == 0.0 ) {
952     itkExceptionMacro( "Joint PDF summed to zero" );
953   }
954
955   memset( m_MovingImageMarginalPDF,
956           0,
957           m_NumberOfHistogramBins*sizeof(PDFValueType) );
958
959   JointPDFValueType * pdfPtr;
960   PDFValueType * movingMarginalPtr;
961   unsigned int i, j;
962   double fixedPDFSum = 0.0;
963   const double normalizationFactor = 1.0 / m_JointPDFSum;
964
965   pdfPtr = m_JointPDF->GetBufferPointer();
966   for(i=0; i<m_NumberOfHistogramBins; i++) {
967     fixedPDFSum += m_FixedImageMarginalPDF[i];
968     movingMarginalPtr = m_MovingImageMarginalPDF;
969     for(j=0; j<m_NumberOfHistogramBins; j++) {
970       *(pdfPtr) *= normalizationFactor;
971       *(movingMarginalPtr++) += *(pdfPtr++);
972     }
973   }
974
975   if( this->m_NumberOfPixelsCounted <
976       this->m_NumberOfFixedImageSamples / 16 ) {
977     itkExceptionMacro( "Too many samples map outside moving image buffer: "
978                        << this->m_NumberOfPixelsCounted << " / "
979                        << this->m_NumberOfFixedImageSamples
980                        << std::endl );
981   }
982
983   // Normalize the fixed image marginal PDF
984   if ( fixedPDFSum == 0.0 ) {
985     itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
986   }
987   for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
988     m_FixedImageMarginalPDF[bin] /= fixedPDFSum;
989   }
990
991   /**
992    * Compute the metric by double summation over histogram.
993    */
994
995   // Setup pointer to point to the first bin
996   JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
997
998   // Initialize sum to zero
999   double sum = 0.0;
1000
1001   const double nFactor = 1.0 / (m_MovingImageBinSize
1002                                 * this->m_NumberOfPixelsCounted);
1003
1004   for( unsigned int fixedIndex = 0;
1005        fixedIndex < m_NumberOfHistogramBins;
1006        ++fixedIndex ) {
1007     double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
1008
1009     for( unsigned int movingIndex = 0;
1010          movingIndex < m_NumberOfHistogramBins;
1011          ++movingIndex, jointPDFPtr++ ) {
1012       double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
1013       double jointPDFValue = *(jointPDFPtr);
1014
1015       // check for non-zero bin contribution
1016       if( jointPDFValue > 1e-16 &&  movingImagePDFValue > 1e-16 ) {
1017
1018         double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
1019
1020         if( fixedImagePDFValue > 1e-16) {
1021           sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
1022         }
1023
1024         if( this->m_UseExplicitPDFDerivatives ) {
1025           // move joint pdf derivative pointer to the right position
1026           JointPDFValueType * derivPtr = m_JointPDFDerivatives->GetBufferPointer()
1027                                          + ( fixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
1028                                          + ( movingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
1029
1030           for( unsigned int parameter=0; parameter < this->m_NumberOfParameters; ++parameter, derivPtr++ ) {
1031
1032             // Ref: eqn 23 of Thevenaz & Unser paper [3]
1033             derivative[parameter] -= (*derivPtr) * pRatio;
1034
1035           }  // end for-loop over parameters
1036         } else {
1037           this->m_PRatioArray[fixedIndex][movingIndex] = pRatio * nFactor;
1038         }
1039       }  // end if-block to check non-zero bin contribution
1040     }  // end for-loop over moving index
1041   }  // end for-loop over fixed index
1042
1043   if( !(this->m_UseExplicitPDFDerivatives ) ) {
1044     // Second pass: This one is done for accumulating the contributions
1045     //              to the derivative array.
1046     //
1047     this->m_ImplicitDerivativesSecondPass = true;
1048     //
1049     // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES
1050     this->GetValueAndDerivativeMultiThreadedInitiate();
1051
1052     // CALL IF DOING THREADED POST PROCESSING
1053     this->GetValueAndDerivativeMultiThreadedPostProcessInitiate();
1054
1055     // Consolidate the contributions from each one of the threads to the total
1056     // derivative.
1057     for(unsigned int t = 0; t < this->m_NumberOfThreads-1; t++ ) {
1058       DerivativeType * source = &(this->m_ThreaderMetricDerivative[t]);
1059       for(unsigned int pp=0; pp < this->m_NumberOfParameters; pp++ ) {
1060         this->m_MetricDerivative[pp] += (*source)[pp];
1061       }
1062     }
1063
1064     derivative = this->m_MetricDerivative;
1065   }
1066
1067   value = static_cast<MeasureType>( -1.0 * sum );
1068
1069 }
1070
1071 /**
1072  * Get the match measure derivative
1073  */
1074 template < class TFixedImage, class TMovingImage  >
1075 void
1076 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
1077 ::GetDerivative( const ParametersType & parameters,
1078                  DerivativeType & derivative ) const
1079 {
1080   MeasureType value;
1081   // call the combined version
1082   this->GetValueAndDerivative( parameters, value, derivative );
1083 }
1084
1085
1086 /**
1087  * Compute PDF derivatives contribution for each parameter
1088  */
1089 template < class TFixedImage, class TMovingImage >
1090 void
1091 MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
1092 ::ComputePDFDerivatives( unsigned int threadID,
1093                          unsigned int sampleNumber,
1094                          int pdfMovingIndex,
1095                          const ImageDerivativesType & movingImageGradientValue,
1096                          double cubicBSplineDerivativeValue ) const
1097 {
1098   // Update bins in the PDF derivatives for the current intensity pair
1099   // Could pre-compute
1100   JointPDFDerivativesValueType * derivPtr;
1101
1102   double precomputedWeight = 0.0;
1103
1104   const int pdfFixedIndex = this->m_FixedImageSamples[sampleNumber].valueIndex;
1105
1106   DerivativeType * derivativeHelperArray = NULL;
1107
1108   if( this->m_UseExplicitPDFDerivatives ) {
1109     if(threadID > 0) {
1110       derivPtr = m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer()
1111                  + ( pdfFixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
1112                  + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
1113     } else {
1114       derivPtr = m_JointPDFDerivatives->GetBufferPointer()
1115                  + ( pdfFixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
1116                  + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
1117     }
1118   } else {
1119     derivPtr = 0;
1120     // Recover the precomputed weight for this specific PDF bin
1121     precomputedWeight = this->m_PRatioArray[pdfFixedIndex][pdfMovingIndex];
1122     if(threadID > 0) {
1123       derivativeHelperArray = &(this->m_ThreaderMetricDerivative[threadID-1]);
1124     } else {
1125       derivativeHelperArray = &(this->m_MetricDerivative);
1126     }
1127
1128   }
1129
1130   if( !this->m_TransformIsBSpline ) {
1131     /**
1132      * Generic version which works for all transforms.
1133      */
1134
1135     // Compute the transform Jacobian.
1136     // Should pre-compute
1137     typedef typename TransformType::JacobianType JacobianType;
1138
1139     // Need to use one of the threader transforms if we're
1140     // not in thread 0.
1141     //
1142     // Use a raw pointer here to avoid the overhead of smart pointers.
1143     // For instance, Register and UnRegister have mutex locks around
1144     // the reference counts.
1145     TransformType* transform;
1146
1147     if (threadID > 0) {
1148       transform = this->m_ThreaderTransform[threadID - 1];
1149     } else {
1150       transform = this->m_Transform;
1151     }
1152
1153     JacobianType jacobian;
1154     transform->ComputeJacobianWithRespectToParameters(this->m_FixedImageSamples[sampleNumber].point, jacobian);
1155
1156     //     for ( unsigned int mu = 0; mu < this->m_NumberOfParameters; mu++ )
1157     //       {
1158     //       double innerProduct = 0.0;
1159     //       for ( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ )
1160     //         {
1161     //         innerProduct += jacobian[dim][mu] * movingImageGradientValue[dim];
1162     //         }
1163
1164     //       const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
1165
1166     //       if( this->m_UseExplicitPDFDerivatives )
1167     //         {
1168     //         *(derivPtr) -= derivativeContribution;
1169     //         ++derivPtr;
1170     //         }
1171     //       else
1172     //         {
1173     //         (*derivativeHelperArray)[mu] += precomputedWeight * derivativeContribution;
1174     //         }
1175     //       }
1176     //    }
1177     // JV
1178     unsigned int mu, dim;
1179     double innerProduct,derivativeContribution;
1180     for ( mu = 0; mu < this->m_NumberOfParameters; mu+=3 ) {
1181       // JV only for 3D Space BLUT FFD: if J(0, par)=0, then J(1,par+1)=0 & ...
1182       if (jacobian[0][mu])
1183         for ( dim = 0; dim < Superclass::FixedImageDimension; dim++ ) {
1184           innerProduct = jacobian[dim][mu+dim] * movingImageGradientValue[dim];
1185           derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
1186
1187           if( this->m_UseExplicitPDFDerivatives ) {
1188             *(derivPtr) -= derivativeContribution;
1189             ++derivPtr;
1190           } else {
1191             (*derivativeHelperArray)[mu+dim] += precomputedWeight * derivativeContribution;
1192           }
1193         }
1194       else  if( this->m_UseExplicitPDFDerivatives ) derivPtr+=3;
1195     }
1196   } else {
1197     const WeightsValueType * weights = NULL;
1198     const IndexValueType   * indices = NULL;
1199
1200
1201     BSplineTransformWeightsType    * weightsHelper = NULL;
1202     BSplineTransformIndexArrayType * indicesHelper = NULL;
1203
1204     if( this->m_UseCachingOfBSplineWeights ) {
1205       //
1206       // If the transform is of type BSplineDeformableTransform, we can obtain
1207       // a speed up by only processing the affected parameters.  Note that
1208       // these pointers are just pointing to pre-allocated rows of the caching
1209       // arrays. There is therefore, no need to free this memory.
1210       //
1211       weights = this->m_BSplineTransformWeightsArray[sampleNumber];
1212       indices = this->m_BSplineTransformIndicesArray[sampleNumber];
1213     } else {
1214       if( threadID > 0 ) {
1215         weightsHelper = &(this->m_ThreaderBSplineTransformWeights[threadID-1]);
1216         indicesHelper = &(this->m_ThreaderBSplineTransformIndices[threadID-1]);
1217       } else {
1218         weightsHelper = &(this->m_BSplineTransformWeights);
1219         indicesHelper = &(this->m_BSplineTransformIndices);
1220       }
1221
1222       this->m_BSplineTransform->ComputeJacobianFromBSplineWeightsWithRespectToPosition(
1223         this->m_FixedImageSamples[sampleNumber].point,
1224         *weightsHelper, *indicesHelper );
1225     }
1226
1227     for( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ ) {
1228
1229       double innerProduct;
1230       int parameterIndex;
1231
1232       for( unsigned int mu = 0; mu < this->m_NumBSplineWeights; mu++ ) {
1233
1234         /* The array weights contains the Jacobian values in a 1-D array
1235          * (because for each parameter the Jacobian is non-zero in only 1 of the
1236          * possible dimensions) which is multiplied by the moving image
1237          * gradient. */
1238         if( this->m_UseCachingOfBSplineWeights ) {
1239           innerProduct = movingImageGradientValue[dim] * weights[mu];
1240           parameterIndex = indices[mu] + this->m_BSplineParametersOffset[dim];
1241         } else {
1242           innerProduct = movingImageGradientValue[dim] * (*weightsHelper)[mu];
1243           parameterIndex = (*indicesHelper)[mu] + this->m_BSplineParametersOffset[dim];
1244         }
1245
1246         const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
1247
1248         if( this->m_UseExplicitPDFDerivatives ) {
1249           JointPDFValueType * ptr = derivPtr + parameterIndex;
1250           *(ptr) -= derivativeContribution;
1251         } else {
1252           (*derivativeHelperArray)[parameterIndex] += precomputedWeight * derivativeContribution;
1253         }
1254
1255       } //end mu for loop
1256     } //end dim for loop
1257
1258   } // end if-block transform is BSpline
1259
1260 }
1261
1262
1263 } // end namespace itk
1264
1265
1266 #endif