]> Creatis software - clitk.git/blob - registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx
147c6fbcbb2252259209c6799ea645b9e20dcaf8
[clitk.git] / registration / clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.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 #ifndef __clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_txx
20 #define __clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_txx
21
22 #include "clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h"
23 #include "itkCovariantVector.h"
24 #include "itkImageRandomConstIteratorWithIndex.h"
25 #include "itkImageRegionConstIterator.h"
26 #include "itkImageRegionIterator.h"
27 #include "itkImageIterator.h"
28 #include "vnl/vnl_math.h"
29
30 namespace clitk
31 {
32
33 /**
34  * Constructor
35  */
36 template < class TFixedImage, class TMovingImage >
37 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
38 ::NormalizedCorrelationImageToImageMetricFor3DBLUTFFD()
39 {
40   this->SetComputeGradient(true);
41
42   m_ThreaderSFF = NULL;
43   m_ThreaderSMM = NULL;
44   m_ThreaderSFM = NULL;
45   m_ThreaderSF = NULL;
46   m_ThreaderSM = NULL;
47   m_ThreaderDerivativeF = NULL;
48   m_ThreaderDerivativeM = NULL;
49   this->m_WithinThreadPreProcess = false;
50   this->m_WithinThreadPostProcess = false;
51
52   //  For backward compatibility, the default behavior is to use all the pixels
53   //  in the fixed image.
54   this->UseAllPixelsOn();
55
56   m_SubtractMean=false;
57
58 }
59
60 template < class TFixedImage, class TMovingImage >
61 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
62 ::~NormalizedCorrelationImageToImageMetricFor3DBLUTFFD()
63 {
64   if(m_ThreaderSFF != NULL) {
65     delete [] m_ThreaderSFF;
66   }
67   m_ThreaderSFF = NULL;
68
69   if(m_ThreaderSMM != NULL) {
70     delete [] m_ThreaderSMM;
71   }
72   m_ThreaderSMM = NULL;
73
74   if(m_ThreaderSFM != NULL) {
75     delete [] m_ThreaderSFM;
76   }
77   m_ThreaderSFM = NULL;
78
79   if(m_ThreaderSF != NULL) {
80     delete [] m_ThreaderSF;
81   }
82   m_ThreaderSF = NULL;
83
84   if(m_ThreaderSM != NULL) {
85     delete [] m_ThreaderSM;
86   }
87   m_ThreaderSM = NULL;
88
89   if(m_ThreaderDerivativeF != NULL) {
90     delete [] m_ThreaderDerivativeF;
91   }
92   m_ThreaderDerivativeF = NULL;
93
94   if(m_ThreaderDerivativeM != NULL) {
95     delete [] m_ThreaderDerivativeM;
96   }
97   m_ThreaderDerivativeM = NULL;
98 }
99
100 /**
101  * Print out internal information about this class
102  */
103 template < class TFixedImage, class TMovingImage  >
104 void
105 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
106 ::PrintSelf(std::ostream& os, itk::Indent indent) const
107 {
108
109   Superclass::PrintSelf(os, indent);
110
111 }
112
113
114 /**
115  * Initialize
116  */
117 template <class TFixedImage, class TMovingImage>
118 void
119 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
120 ::Initialize(void) throw ( itk::ExceptionObject )
121 {
122
123   this->Superclass::Initialize();
124   this->Superclass::MultiThreadingInitialize();
125
126
127   /**
128    * Allocate memory for the accumulators (set to zero in GetValue)
129    */
130   if(m_ThreaderSFF != NULL) {
131     delete [] m_ThreaderSFF;
132   }
133   m_ThreaderSFF = new double[this->m_NumberOfThreads];
134
135
136   if(m_ThreaderSMM != NULL) {
137     delete [] m_ThreaderSMM;
138   }
139   m_ThreaderSMM = new double[this->m_NumberOfThreads];
140
141   if(m_ThreaderSFM != NULL) {
142     delete [] m_ThreaderSFM;
143   }
144   m_ThreaderSFM = new double[this->m_NumberOfThreads];
145
146   if(this->m_SubtractMean) {
147     if(m_ThreaderSF != NULL) {
148       delete [] m_ThreaderSF;
149     }
150     m_ThreaderSF = new double[this->m_NumberOfThreads];
151
152     if(m_ThreaderSM != NULL) {
153       delete [] m_ThreaderSM;
154     }
155     m_ThreaderSM = new double[this->m_NumberOfThreads];
156   }
157
158   if(m_ThreaderDerivativeF != NULL) {
159     delete [] m_ThreaderDerivativeF;
160   }
161   m_ThreaderDerivativeF = new DerivativeType[this->m_NumberOfThreads];
162   for(ThreadIdType threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
163     m_ThreaderDerivativeF[threadID].SetSize( this->m_NumberOfParameters );
164   }
165
166   if(m_ThreaderDerivativeM != NULL) {
167     delete [] m_ThreaderDerivativeM;
168   }
169   m_ThreaderDerivativeM = new DerivativeType[this->m_NumberOfThreads];
170   for(ThreadIdType threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
171     m_ThreaderDerivativeM[threadID].SetSize( this->m_NumberOfParameters );
172   }
173 }
174
175
176 template < class TFixedImage, class TMovingImage  >
177 inline bool
178 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
179 ::GetValueThreadProcessSample(
180   ThreadIdType threadID,
181   unsigned long fixedImageSample,
182   const MovingImagePointType & itkNotUsed(mappedPoint),
183   double movingImageValue) const
184 {
185   const RealType fixedImageValue= this->m_FixedImageSamples[fixedImageSample].value;
186   m_ThreaderSFF[threadID] += fixedImageValue  * fixedImageValue;
187   m_ThreaderSMM[threadID] += movingImageValue * movingImageValue;
188   m_ThreaderSFM[threadID] += fixedImageValue  * movingImageValue;
189   if ( this->m_SubtractMean ) {
190     m_ThreaderSF[threadID] += fixedImageValue;
191     m_ThreaderSM[threadID] += movingImageValue;
192   }
193
194   return true;
195 }
196
197 template < class TFixedImage, class TMovingImage  >
198 typename NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
199 ::MeasureType
200 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
201 ::GetValue( const ParametersType & parameters ) const
202 {
203   itkDebugMacro("GetValue( " << parameters << " ) ");
204
205   if( !this->m_FixedImage ) {
206     itkExceptionMacro( << "Fixed image has not been assigned" );
207   }
208
209
210   //Reset the accumulators
211   memset( m_ThreaderSFF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
212   memset( m_ThreaderSMM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
213   memset( m_ThreaderSFM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
214   if(this->m_SubtractMean) {
215     memset( m_ThreaderSF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
216     memset( m_ThreaderSM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
217   }
218
219
220   // Set up the parameters in the transform
221   this->m_Transform->SetParameters( parameters );
222   this->m_Parameters = parameters;
223
224   // MUST BE CALLED TO INITIATE PROCESSING
225   this->GetValueMultiThreadedInitiate();
226
227   itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
228                  << this->m_NumberOfPixelsCounted << " / "
229                  << this->m_NumberOfFixedImageSamples
230                  << std::endl );
231
232   if( this->m_NumberOfPixelsCounted <
233       this->m_NumberOfFixedImageSamples / 4 ) {
234     itkExceptionMacro( "Too many samples map outside moving image buffer: "
235                        << this->m_NumberOfPixelsCounted << " / "
236                        << this->m_NumberOfFixedImageSamples
237                        << std::endl );
238   }
239
240   // Accumulate the threads
241   AccumulateType sff, smm, sfm, sf, sm;
242   sff = m_ThreaderSFF[0];
243   smm = m_ThreaderSMM[0];
244   sfm = m_ThreaderSFM[0];
245   sf  = m_ThreaderSF[0];
246   sm  = m_ThreaderSM[0];
247
248   for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
249     sff +=  m_ThreaderSFF[t];
250     smm +=  m_ThreaderSMM[t];
251     sfm +=  m_ThreaderSFM[t];
252     if ( this->m_SubtractMean ) {
253       sf +=  m_ThreaderSF[t];
254       sm +=  m_ThreaderSM[t];
255     }
256   }
257
258   if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
259     sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
260     smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
261     sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
262   }
263
264
265   const RealType denom = -1.0 * vcl_sqrt(sff * smm );
266   MeasureType measure;
267   if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
268     measure = sfm / denom;
269   } else {
270     measure = itk::NumericTraits< MeasureType >::Zero;
271   }
272
273
274   return measure;
275 }
276
277
278 template < class TFixedImage, class TMovingImage  >
279 typename NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
280 ::MeasureType
281 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
282 ::ComputeSums( const ParametersType & parameters ) const
283 {
284   //No checking for the fixed image,  done in the caller
285   //Reset the accumulators
286   memset( m_ThreaderSFF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
287   memset( m_ThreaderSMM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
288   memset( m_ThreaderSFM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
289   if(this->m_SubtractMean) {
290     memset( m_ThreaderSF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
291     memset( m_ThreaderSM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
292   }
293
294
295   // Set up the parameters in the transform
296   this->m_Transform->SetParameters( parameters );
297   this->m_Parameters = parameters;
298
299   // MUST BE CALLED TO INITIATE PROCESSING
300   this->GetValueMultiThreadedInitiate();
301
302   itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
303                  << this->m_NumberOfPixelsCounted << " / "
304                  << this->m_NumberOfFixedImageSamples
305                  << std::endl );
306
307   if( this->m_NumberOfPixelsCounted <
308       this->m_NumberOfFixedImageSamples / 4 ) {
309     itkExceptionMacro( "Too many samples map outside moving image buffer: "
310                        << this->m_NumberOfPixelsCounted << " / "
311                        << this->m_NumberOfFixedImageSamples
312                        << std::endl );
313   }
314
315   // Accumulate the threads
316   m_SFF = m_ThreaderSFF[0];
317   m_SMM = m_ThreaderSMM[0];
318   m_SFM = m_ThreaderSFM[0];
319   m_SF  = m_ThreaderSF[0];
320   m_SM  = m_ThreaderSM[0];
321
322   for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
323     m_SFF +=  m_ThreaderSFF[t];
324     m_SMM +=  m_ThreaderSMM[t];
325     m_SFM +=  m_ThreaderSFM[t];
326     if ( this->m_SubtractMean ) {
327       m_SF +=  m_ThreaderSF[t];
328       m_SM +=  m_ThreaderSM[t];
329     }
330   }
331
332   if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
333     m_SFF -= ( m_SF * m_SF / this->m_NumberOfPixelsCounted );
334     m_SMM -= ( m_SM * m_SM / this->m_NumberOfPixelsCounted );
335     m_SFM -= ( m_SF * m_SM / this->m_NumberOfPixelsCounted );
336     m_FixedMean=m_SF / this->m_NumberOfPixelsCounted;
337     m_MovingMean=m_SM / this->m_NumberOfPixelsCounted;
338   }
339
340
341   m_Denom = -1.0 * vcl_sqrt(m_SFF * m_SMM );
342   MeasureType measure;
343   if( this->m_NumberOfPixelsCounted > 0 && m_Denom != 0.0) {
344     measure = m_SFM / m_Denom;
345   } else {
346     measure = itk::NumericTraits< MeasureType >::Zero;
347   }
348
349   return measure;
350 }
351
352
353 template < class TFixedImage, class TMovingImage  >
354 inline bool
355 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
356 ::GetValueAndDerivativeThreadProcessSample(
357   ThreadIdType threadID,
358   unsigned long fixedImageSample,
359   const MovingImagePointType & itkNotUsed(mappedPoint),
360   double movingImageValue,
361   const ImageDerivativesType &
362   movingImageGradientValue
363 ) const
364 {
365
366   const RealType fixedImageValue=this->m_FixedImageSamples[fixedImageSample].value;
367   const FixedImagePointType fixedImagePoint = this->m_FixedImageSamples[fixedImageSample].point;
368
369   // Need to use one of the threader transforms if we're
370   // not in thread 0.
371   //
372   // Use a raw pointer here to avoid the overhead of smart pointers.
373   // For instance, Register and UnRegister have mutex locks around
374   // the reference counts.
375   TransformType* transform;
376
377   if (threadID > 0) {
378     transform = this->m_ThreaderTransform[threadID - 1];
379   } else {
380     transform = this->m_Transform;
381   }
382
383   // Jacobian should be evaluated at the unmapped (fixed image) point.
384 #if ITK_VERSION_MAJOR >= 4
385   TransformJacobianType jacobian;
386   transform->ComputeJacobianWithRespectToParameters( fixedImagePoint, jacobian );
387 #else
388   const TransformJacobianType & jacobian = transform->GetJacobian( fixedImagePoint );
389 #endif
390
391 //          for(unsigned int par=0; par<this->m_NumberOfParameters; par++)
392 //            {
393 //       RealType sumF = itk::NumericTraits< RealType >::Zero;
394 //       RealType sumM = itk::NumericTraits< RealType >::Zero;
395 //       for(unsigned int dim=0; dim<MovingImageDimension; dim++)
396 //         {
397 //           const RealType differential = jacobian( dim, par ) * movingImageGradientValue[dim];
398 //           if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 )
399 //             {
400 //               sumF += (fixedImageValue-m_FixedMean)  * differential;
401 //               sumM += (movingImageValue-m_MovingMean) * differential;
402 //             }
403 //           else
404 //             {
405 //               sumF += differential * fixedImageValue;
406 //               sumM += differential * movingImageValue;
407 //             }
408 //         }
409 //       m_ThreaderDerivativeF[threadID][par] += sumF;
410 //       m_ThreaderDerivativeM[threadID][par] += sumM;
411 //            }
412
413   // JV
414   unsigned int par, dim;
415   RealType differential;
416   for( par=0; par<this->m_NumberOfParameters; par+=3) {
417     // JV only for 3D Space BLUT FFD: if J(0, par)=0, then J(1,par+1)=0 & ...
418     if (jacobian( 0, par ) ) {
419       for(dim=0; dim<3; dim++) {
420         differential = jacobian( dim, par+dim ) * movingImageGradientValue[dim];
421
422         if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
423           m_ThreaderDerivativeF[threadID][par+dim]+= (fixedImageValue-m_FixedMean)  * differential;
424           m_ThreaderDerivativeM[threadID][par+dim]+= (movingImageValue-m_MovingMean) * differential;
425         } else {
426           m_ThreaderDerivativeF[threadID][par+dim]+= differential * fixedImageValue;
427           m_ThreaderDerivativeM[threadID][par+dim]+= differential * movingImageValue;
428         }
429       }
430     }
431   }
432
433   return true;
434 }
435
436
437 /**
438  * Get the both Value and Derivative Measure
439  */
440 template < class TFixedImage, class TMovingImage  >
441 void
442 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
443 ::GetValueAndDerivative( const ParametersType & parameters,
444                          MeasureType & value,
445                          DerivativeType & derivative) const
446 {
447
448   if( !this->m_FixedImage ) {
449     itkExceptionMacro( << "Fixed image has not been assigned" );
450   }
451
452   // Set up the parameters in the transform
453   this->m_Transform->SetParameters( parameters );
454   this->m_Parameters = parameters;
455
456   //We need the sums and the value to be calculated first
457   value=this->ComputeSums(parameters);
458
459   //Set output values to zero
460   if(derivative.GetSize() != this->m_NumberOfParameters) {
461     derivative = DerivativeType( this->m_NumberOfParameters );
462   }
463   memset( derivative.data_block(),
464           0,
465           this->m_NumberOfParameters * sizeof(typename DerivativeType::ValueType) );
466
467   for( ThreadIdType threadID = 0; threadID<this->m_NumberOfThreads; threadID++ ) {
468     memset( m_ThreaderDerivativeF[threadID].data_block(),
469             0,
470             this->m_NumberOfParameters * sizeof(typename DerivativeType::ValueType) );
471
472     memset( m_ThreaderDerivativeM[threadID].data_block(),
473             0,
474             this->m_NumberOfParameters * sizeof(typename DerivativeType::ValueType) );
475   }
476
477   // MUST BE CALLED TO INITIATE PROCESSING
478   this->GetValueAndDerivativeMultiThreadedInitiate();
479
480   // Accumulate over the threads
481   DerivativeType derivativeF(this->m_NumberOfParameters), derivativeM(this->m_NumberOfParameters);
482   for(unsigned int t=0; t<this->m_NumberOfThreads; t++) {
483     for(unsigned int parameter = 0; parameter < this->m_NumberOfParameters; parameter++) {
484       derivativeF[parameter] += m_ThreaderDerivativeF[t][parameter];
485       derivativeM[parameter] += m_ThreaderDerivativeM[t][parameter];
486     }
487   }
488
489   //Compute derivatives
490   if( this->m_NumberOfPixelsCounted > 0 && m_Denom != 0.0) {
491     for(unsigned int i=0; i<this->m_NumberOfParameters; i++) {
492       derivative[i] = ( derivativeF[i] - (m_SFM/m_SMM)* derivativeM[i] ) / m_Denom;
493     }
494   } else {
495     for(unsigned int i=0; i<this->m_NumberOfParameters; i++) {
496       derivative[i] = itk::NumericTraits< MeasureType >::Zero;
497     }
498   }
499
500 }
501
502
503 /**
504  * Get the match measure derivative
505  */
506 template < class TFixedImage, class TMovingImage  >
507 void
508 NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
509 ::GetDerivative( const ParametersType & parameters,
510                  DerivativeType & derivative ) const
511 {
512   if( !this->m_FixedImage ) {
513     itkExceptionMacro( << "Fixed image has not been assigned" );
514   }
515
516   MeasureType value;
517   // call the combined version
518   this->GetValueAndDerivative( parameters, value, derivative );
519 }
520
521 } // end namespace clitk
522
523
524 #endif