]> Creatis software - clitk.git/commitdiff
Added clitkAffineRegistration from Jef's file. Also does translations only and rigid...
authorsrit <srit>
Mon, 14 Jun 2010 17:32:04 +0000 (17:32 +0000)
committersrit <srit>
Mon, 14 Jun 2010 17:32:04 +0000 (17:32 +0000)
37 files changed:
CMakeLists.txt
registration/CMakeLists.txt [new file with mode: 0644]
registration/clitkAffineRegistration.cxx [new file with mode: 0644]
registration/clitkAffineRegistration.ggo [new file with mode: 0644]
registration/clitkAffineRegistrationGenericFilter.cxx [new file with mode: 0644]
registration/clitkAffineRegistrationGenericFilter.h [new file with mode: 0644]
registration/clitkAffineRegistrationGenericFilter.txx [new file with mode: 0644]
registration/clitkCorrelationRatioImageToImageMetric.h [moved from tools/clitkCorrelationRatioImageToImageMetric.h with 89% similarity]
registration/clitkCorrelationRatioImageToImageMetric.txx [moved from tools/clitkCorrelationRatioImageToImageMetric.txx with 99% similarity]
registration/clitkGenericAffineTransform.cxx [new file with mode: 0644]
registration/clitkGenericAffineTransform.h [new file with mode: 0644]
registration/clitkGenericAffineTransform.txx [new file with mode: 0644]
registration/clitkGenericInterpolator.h [new file with mode: 0644]
registration/clitkGenericInterpolator.txx [new file with mode: 0644]
registration/clitkGenericMetric.h [new file with mode: 0644]
registration/clitkGenericMetric.txx [new file with mode: 0644]
registration/clitkGenericOptimizer.h [new file with mode: 0644]
registration/clitkLBFGSBOptimizer.cxx [new file with mode: 0644]
registration/clitkLBFGSBOptimizer.h [new file with mode: 0644]
registration/clitkNormalizedCorrelationImageToImageMetric.h [new file with mode: 0644]
registration/clitkNormalizedCorrelationImageToImageMetric.txx [new file with mode: 0644]
registration/clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h [new file with mode: 0644]
registration/clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx [new file with mode: 0644]
registration/clitkOptNormalizedCorrelationImageToImageMetric.h [new file with mode: 0644]
registration/clitkOptNormalizedCorrelationImageToImageMetric.txx [new file with mode: 0644]
registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h [new file with mode: 0644]
registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx [new file with mode: 0644]
registration/itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h [new file with mode: 0644]
registration/itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx [new file with mode: 0644]
registration/itkMeanSquaresImageToImageMetricFor3DBLUTFFD.h [new file with mode: 0644]
registration/itkMeanSquaresImageToImageMetricFor3DBLUTFFD.txx [new file with mode: 0644]
registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h [new file with mode: 0644]
registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx [new file with mode: 0644]
registration/itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.h [new file with mode: 0644]
registration/itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.txx [new file with mode: 0644]
tools/clitkRigidRegistration.cxx [deleted file]
tools/clitkRigidRegistration.ggo [deleted file]

index c5f31cf17b3255192a8ef354ea245241949680eb..3a74d435f9d6b72959154d2231c7545f1e2cef39 100644 (file)
@@ -76,6 +76,11 @@ IF (CLITK_BUILD_TOOLS)
   add_subdirectory(tools)
 ENDIF(CLITK_BUILD_TOOLS)
 
+OPTION(CLITK_BUILD_REGISTRATION "Build command-line registration tools" OFF)
+IF (CLITK_BUILD_REGISTRATION)
+  add_subdirectory(registration)
+ENDIF(CLITK_BUILD_REGISTRATION)
+
 #OPTION(CLITK_BUILD_SEGMENTATION "Build segmentation tools" OFF)
 #IF (CLITK_BUILD_SEGMENTATION)
 #  add_subdirectory(segmentation)
diff --git a/registration/CMakeLists.txt b/registration/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5963898
--- /dev/null
@@ -0,0 +1,4 @@
+WRAP_GGO(clitkAffineRegistration_GGO_C clitkAffineRegistration.ggo)
+ADD_EXECUTABLE(clitkAffineRegistration clitkAffineRegistration.cxx clitkAffineRegistrationGenericFilter.cxx ${clitkAffineRegistration_GGO_C} clitkLBFGSBOptimizer.cxx clitkGenericAffineTransform.cxx)
+TARGET_LINK_LIBRARIES(clitkAffineRegistration clitkCommon ITKIO clitkFilters ITKNumerics ITKStatistics)
+
diff --git a/registration/clitkAffineRegistration.cxx b/registration/clitkAffineRegistration.cxx
new file mode 100644 (file)
index 0000000..c24bbe9
--- /dev/null
@@ -0,0 +1,36 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+// clitk include
+#include "clitkIO.h"
+#include "clitkAffineRegistrationGenericFilter.h"
+
+int main( int argc, char *argv[] )
+{
+  //init command line and check options
+  GGO(clitkAffineRegistration, args_info);
+  CLITK_INIT;
+
+  //===========================================================================
+  //Set all the options passed through the commandline
+  clitk::AffineRegistrationGenericFilter::Pointer genericFilter=clitk::AffineRegistrationGenericFilter::New();
+  genericFilter->SetArgsInfo(args_info);
+  genericFilter->Update();
+
+  return 1;
+}
diff --git a/registration/clitkAffineRegistration.ggo b/registration/clitkAffineRegistration.ggo
new file mode 100644 (file)
index 0000000..6c9f439
--- /dev/null
@@ -0,0 +1,89 @@
+# file clitkAffineRegistration.ggo
+package "clitk"
+version "1.0"
+purpose "Compute an affine registration between two images." 
+
+option "config"                -       "Config file"                   string          no
+
+section "Run Time"
+
+option "verbose"       v       "Verbose"                               flag    off
+option "gradient"      -       "If verbose, show gradient at each iteration"   flag    off
+option "threads"       -       "Number of threads to use  (default=min(#cores,8))"     int      no
+
+
+section "Input (Both images have to be of the same dimension (2 or 3D). For 2D-3D registrations, give the 2D image a third dimension of 1 and set it to the reference image.)"
+
+option "reference"     i       "Reference or fixed image filename"             string  yes
+option "target"        j       "Target or moving image filename"               string  yes
+option "referenceMask"         m       "Mask to placed over the reference image"       string   no
+option "targetMask"    -       "Mask to placed over the target image"  string   no
+
+section "Output"
+
+option "output"        o       "Transformed object image filename"                                                     string  no
+option "checker_after"  -      "Checherboard representation of the transformed object image and reference image"       string  no
+option "checker_before"  -     "Checherboard representation of the object image and reference image"                   string  no
+option "after"         -       "Difference between the reference image and the transformed object"                     string  no
+option "before"        -       "Difference between the reference image and the original object image"                  string  no
+option "matrix"        -       "Affine matrix (reference to object space) filename "                                   string  no
+
+
+section "Interpolator"
+
+option "interp"                -       "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT"      int     no  default="1"
+option "interpOrder"   -       "Order if BLUT or BSpline (0-5)"                        int     no  default="3"
+option "interpSF"      -       "Sampling factor if BLUT"                               int     no  default="20"
+
+
+section "Transform (Input and Output transformation parameters map the physical space of the fixed or reference image into the physical space of the moving or object image. Positive rotations result in a counter-clockwise rotation for the moving image. Positive translations result in shift along the negative axis for the moving image.)"
+
+option "transform"  - "Type: 0=Identity, 1=Translation, 2=Rigid, 3=Affine" int no  default="2"
+option "transX"     x "1-3: Initial translation in mm along the X axis"  float no  default="0.0"
+option "transY"     y "1-3: Initial translation in mm along the Y axis"  float no  default="0.0"
+option "transZ"     z "1-3: Initial translation in mm along the Z axis"  float no  default="0.0"
+option "initMatrix" - "2-3: Initial matrix (reference to object space) filename " string  no
+option "moment"     - "2-3: Initialize translation by aligning the center of gravities for the respective intensities" flag off
+
+section "Metric (optimized, threaded versions are available for *, compile ITK with REVIEW and OPT_REGISTRATION enabled)"
+
+option "metric"        -       "Type: 0=Mean-Squares*, 1=Normalized CC*, 2=Histogram CC, 3=Gradient-Difference, 4=Viola-Wells MI, 5=Histogram MI, 6=Mattes' MI*, 7=Normalized MI, 8=CR, 9=SSD for BLUT FFD**"  int     no      default="0"
+option "samples"       -       "Specify fraction [0, 1] of samples of the reference image used for the metric (* only). Use high fraction for detailed images (eg. 0.2, 0.5), for smooth images 0.01 might be enough." float   no      default="1"
+option "intThreshold"  -       "Fixed image samples intensity threshold (* only; caution with --normalize)"                            float   no              
+option "subtractMean"  -       "1: Subtract mean for NCC calculation (narrows optimal)"                                                flag    on      
+option "bins"          -       "2,5-8: Number of histogram bins"                                                                       int     no      default="50"
+option "random"        -       "4,6: Samples should be taken randomly, otherwise uniformly"                                            flag    off     
+option "stdDev"                -       "4: specify the standard deviation in mm of the gaussian kernels for both PDF estimations"              float   no      default="0.4"   
+option "explicitPDFDerivatives"        -       "6: Calculate PDF derivatives explicitly (rigid=true; FFD=false)"                               flag    on
+
+
+section "Preprocessing"
+
+option "normalize"     -       "Normalize images before registration (not necessary for metric 1,2,5,6,8; caution with --intThreshold)"                        flag    off     
+option "blur"          -       "Blur images before registration, use Gaussian with std dev (none by default) "         float   no  default="0.0"       
+
+
+section "Optimizer"
+
+option "optimizer"     -       "0=Simplex, 1=Powell, 2=FRPR, 3=Regular Step GD, 4=VersorRigid3D, 5=Conjugated Gradient, 6=L-BFGS, 7=L-BFGS-B" int no default="0" 
+option "delta"         -       "0: Initial delta, otherwise automatic"                                                 double  no                      
+option "step"          -       "1,2,3,4: Initial stepsize (to be multiplied with the gradient)"                        double  no      default="2.0"   
+option "relax"                 -       "3,4: Relaxation of the stepsize (multiplied each time the gradient changes sign)"      double  no      default="0.7"
+option "valueTol"      -       "0,1,2: Tolerance on the function"                                                      double  no      default="0.01"
+option "stepTol"       -       "0,1,3,4: Tolerance on the step size"                                                   double  no      default="0.1"
+option "gradTol"       -       "3,4,6,7: Tolerance on the (projected) gradient magnitude (7: 1=low->1e-10=high precision)"     double  no      default="1e-5"                  
+option "lineAcc"       -       "6: Line accuracy (eg: high=0.1, low=0.9)"      double  no      default="0.9"
+option "convFactor"    -       "7: Convergence factor: terminate if factor*machine_precision>reduction in cost (1e+12 low, 1e+7 moderate and 1e+1 high precision) "    double          no      default="1e+12"
+option "maxIt"         -       "0-7: Maximum number of iterations"                                     int     no      default="500"
+option "maxLineIt"     -       "Maximum number of line iterations"                                     int     no      default="50"    
+option "maxEval"       -       "Maximum number of evaluations"                                         int     no      default="500"
+option "maxCorr"       -       "Maximum number of corrections"                                         int     no      default="5"
+option "selectBound"   -       "7: Select the type of bound: 0=none, 1=u, 2=u&l, 3=l"                  int     no      default="0"
+option "lowerBound"    -       "7: The lower bound"                                                    double  no      
+option "upperBound"    -       "7: The upper bound"                                                    double  no      
+
+option "rWeight"       -       "Weight of 1° of rotation during optimisation (high weight, less change)"            float   no      default="50.0"
+option "tWeight"       -       "Weight of 1mm of translation  during optimisation (high weight, less change)"          float   no      default="1.0"
+option "levels"                -       "Number of resolution levels"                                                           int     no      default="1"                                             
+option "inc"           -       "Increment factor (x)  previous step/tol = new step/tol at next resolution level"       float   no      default="1.2"
+option "dec"           -       "Decrement factor (:)  previous step/tol = new step/tol at next resolution level"       float   no      default="4"
diff --git a/registration/clitkAffineRegistrationGenericFilter.cxx b/registration/clitkAffineRegistrationGenericFilter.cxx
new file mode 100644 (file)
index 0000000..d9bfd28
--- /dev/null
@@ -0,0 +1,98 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef CLITKAFFINEREGISTRATIONGENERICFILTER_CXX
+#define CLITKAFFINEREGISTRATIONGENERICFILTER_CXX
+
+#include "clitkAffineRegistrationGenericFilter.h"
+
+namespace clitk
+{
+
+//====================================================================
+// Constructor
+AffineRegistrationGenericFilter::AffineRegistrationGenericFilter()
+{
+  m_Verbose=false;
+}
+
+//====================================================================
+// Update
+void AffineRegistrationGenericFilter::Update()
+{
+  //Read the PixelType and dimension of the reference image
+  int Dimension;
+  std::string PixelType;
+  clitk::ReadImageDimensionAndPixelType(m_ArgsInfo.reference_arg, Dimension, PixelType);
+  if (Dimension == 2) UpdateWithDim<2>(PixelType);
+  else if (Dimension == 3) UpdateWithDim<3>(PixelType);
+  else {
+    itkExceptionMacro(<< "Reference Image dimension is " << Dimension
+                      << " but I can only work on 2D and 3D images.");
+  }
+}
+
+//void AffineRegistrationGenericFilter::SetTransfo( itk::MultiResolutionImageRegistrationMethod<itk::Image<float,2>,itk::Image<float,2> >::Pointer & registration  )
+//{
+//  typedef itk::Euler2DTransform < double > Transform2DType;
+//  Transform2DType::Pointer t2 =Transform2DType::New();
+//
+//  //Initializing the transform
+//  Transform2DType::OutputVectorType translation;
+//  translation[0] = m_ArgsInfo.transX_arg;
+//  translation[1] = m_ArgsInfo.transY_arg;
+//  t2->SetTranslation(translation);
+//  t2->SetRotation(m_ArgsInfo.rotX_arg);
+//
+//  //For simplicity we set the center to the top left corner
+//  Transform2DType::InputPointType center;
+//  center[0] = 0.;
+//  center[1] = 0.;
+//  t2->SetCenter(center);
+//  registration->SetTransform(t2);
+//  registration->SetInitialTransformParameters(t2->GetParameters());
+//}
+
+//void clitk::AffineRegistrationGenericFilter::SetTransfo( itk::MultiResolutionImageRegistrationMethod<itk::Image<float,3>,itk::Image<float,3> >::Pointer & registration )
+//{
+//  typedef itk::Euler3DTransform < double > Transform3DType;
+//  Transform3DType::Pointer t3 = Transform3DType::New();
+//
+//  t3->SetComputeZYX(true);
+//  //Initializing the transform
+//  Transform3DType::OutputVectorType translation;
+//  translation[0] = m_ArgsInfo.transX_arg;
+//  translation[1] = m_ArgsInfo.transY_arg;
+//  translation[2] = m_ArgsInfo.transZ_arg;
+//  t3->SetTranslation(translation);
+//  t3->SetRotation(m_ArgsInfo.rotX_arg, m_ArgsInfo.rotY_arg, m_ArgsInfo.rotZ_arg);
+//
+//  //For simplicity we set the center to the top left corner
+//  Transform3DType::InputPointType center;
+//  center[0] = 0.;
+//  center[1] = 0.;
+//  center[2] = 0.;
+//  t3->SetCenter(center);
+//  registration->SetTransform(t3);
+//  registration->SetInitialTransformParameters( t3->GetParameters());
+//}
+
+}
+//====================================================================
+
+#endif  //#define CLITKAFFINEREGISTRATIONCGENERICFILTER_CXX
diff --git a/registration/clitkAffineRegistrationGenericFilter.h b/registration/clitkAffineRegistrationGenericFilter.h
new file mode 100644 (file)
index 0000000..830046f
--- /dev/null
@@ -0,0 +1,115 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef CLITKAFFINEREGISTRATIONGENERICFILTER_H
+#define CLITKAFFINEREGISTRATIONGENERICFILTER_H
+
+// clitk include
+#include "clitkIO.h"
+#include "clitkCommon.h"
+#include "clitkAffineRegistration_ggo.h"
+#include "clitkCorrelationRatioImageToImageMetric.h"
+#include "clitkTransformUtilities.h"
+#include "clitkGenericMetric.h"
+#include "clitkGenericOptimizer.h"
+#include "clitkGenericInterpolator.h"
+#include "clitkGenericAffineTransform.h"
+
+//itk include
+#include <itkMultiResolutionImageRegistrationMethod.h>
+#include <itkMultiResolutionPyramidImageFilter.h>
+#include <itkImageToImageMetric.h>
+#include <itkEuler2DTransform.h>
+#include <itkCenteredEuler3DTransform.h>
+#include <itkImage.h>
+#include <itkResampleImageFilter.h>
+#include <itkCastImageFilter.h>
+#include <itkNormalizeImageFilter.h>
+#include <itkDiscreteGaussianImageFilter.h>
+#include <itkImageMaskSpatialObject.h>
+#include <itkCommand.h>
+#include <itkCheckerBoardImageFilter.h>
+#include <itkSubtractImageFilter.h>
+#include <itkLightObject.h>
+#include <itkImageMomentsCalculator.h>
+#include <itkThresholdImageFilter.h>
+
+// other includes
+#include <time.h>
+#include <iostream>
+#include <iomanip>
+
+namespace clitk
+{
+
+//====================================================================
+class AffineRegistrationGenericFilter: public itk::LightObject
+{
+public:
+
+  //================================================
+  typedef AffineRegistrationGenericFilter        Self;
+  typedef itk::LightObject  Superclass;
+  typedef itk::SmartPointer<Self>        Pointer;
+  typedef itk::SmartPointer<const Self> ConstPointer;
+
+  //================================================
+  itkNewMacro(Self);
+
+  //====================================================================
+  // Set methods
+  void SetArgsInfo(const args_info_clitkAffineRegistration args_info) {
+    m_ArgsInfo=args_info;
+    m_Verbose=m_ArgsInfo.verbose_flag;
+  }
+
+  //====================================================================
+  // Update
+  void Update();
+
+protected:
+  const char * GetNameOfClass() const {
+    return "AffineRegistrationGenericFilter";
+  }
+
+  //====================================================================
+  // Constructor & Destructor
+  AffineRegistrationGenericFilter();
+  ~AffineRegistrationGenericFilter() {
+    ;
+  }
+
+  //====================================================================
+  //Templated member functions
+  template <unsigned int Dimension> void UpdateWithDim(std::string PixelType);
+  template <unsigned int Dimension, class PixelType> void UpdateWithDimAndPixelType();
+
+  //====================================================================
+  //Member Data
+public:
+  bool m_Verbose;
+  args_info_clitkAffineRegistration m_ArgsInfo;
+};
+}
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkAffineRegistrationGenericFilter.txx"
+#endif
+
+
+#endif //#define CLITKAFFINEREGISTRATIONGENERICFILTER__H
diff --git a/registration/clitkAffineRegistrationGenericFilter.txx b/registration/clitkAffineRegistrationGenericFilter.txx
new file mode 100644 (file)
index 0000000..90fb6e4
--- /dev/null
@@ -0,0 +1,664 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef CLITKAFFINEREGISTRATIONGENERICFILTER_TXX
+#define CLITKAFFINEREGISTRATIONGENERICFILTER_TXX
+
+namespace clitk
+{
+
+//==============================================================================
+//Creating an observer class that allows us to monitor the registration
+//================================================================================
+class CommandIterationUpdate : public itk::Command
+{
+public:
+  typedef  CommandIterationUpdate   Self;
+  typedef  itk::Command             Superclass;
+  typedef  itk::SmartPointer<Self>  Pointer;
+  itkNewMacro( Self );
+protected:
+  CommandIterationUpdate() {};
+public:
+  typedef   clitk::GenericOptimizer<args_info_clitkAffineRegistration>     OptimizerType;
+  typedef   const OptimizerType   *           OptimizerPointer;
+
+  // Set the generic optimizer
+  void SetOptimizer(OptimizerPointer o) {
+    m_Optimizer=o;
+  }
+
+  // Execute
+  void Execute(itk::Object *caller, const itk::EventObject & event) {
+    Execute( (const itk::Object *)caller, event);
+  }
+
+  void Execute(const itk::Object * object, const itk::EventObject & event) {
+    if( !(itk::IterationEvent().CheckEvent( &event )) ) {
+      return;
+    }
+
+    m_Optimizer->OutputIterationInfo();
+  }
+
+  OptimizerPointer m_Optimizer;
+};
+
+
+//==============================================================================
+//Creating an observer class that allows us to change parameters at subsequent levels
+//==============================================================================
+template <typename TRegistration, class args_info_clitkAffineRegistration>
+class RegistrationInterfaceCommand : public itk::Command
+{
+public:
+  typedef  RegistrationInterfaceCommand   Self;
+  typedef  itk::Command             Superclass;
+  typedef itk::SmartPointer<Self>  Pointer;
+  itkNewMacro( Self );
+protected:
+  RegistrationInterfaceCommand() {};
+public:
+
+  // Registration
+  typedef   TRegistration                              RegistrationType;
+  typedef   RegistrationType *                         RegistrationPointer;
+
+  // Metric
+  typedef typename RegistrationType::FixedImageType    InternalImageType;
+  typedef clitk::GenericMetric<args_info_clitkAffineRegistration, InternalImageType, InternalImageType> GenericMetricType;
+
+  // Two arguments are passed to the Execute() method: the first
+  // is the pointer to the object which invoked the event and the
+  // second is the event that was invoked.
+  void Execute(itk::Object * object, const itk::EventObject & event) {
+    if( !(itk::IterationEvent().CheckEvent( &event )) ) {
+      return;
+    }
+
+    // Get the levels
+    RegistrationPointer registration = dynamic_cast<RegistrationPointer>( object );
+    unsigned int numberOfLevels=registration->GetNumberOfLevels();
+    unsigned int currentLevel=registration->GetCurrentLevel()+1;
+
+    // Output the levels
+    std::cout<<std::endl;
+    std::cout<<"========================================"<<std::endl;
+    std::cout<<"Starting resolution level "<<currentLevel<<" of "<<numberOfLevels<<"..."<<std::endl;
+    std::cout<<"========================================"<<std::endl;
+    std::cout<<std::endl;
+
+    // Higher level?
+    if (currentLevel>1) {
+      // Reinitialize the metric (!= number of samples)
+      typename GenericMetricType::Pointer genericMetric= GenericMetricType::New();
+      genericMetric->SetArgsInfo(m_ArgsInfo);
+      genericMetric->SetFixedImage(registration->GetFixedImagePyramid()->GetOutput(registration->GetCurrentLevel()));
+      if (m_ArgsInfo.referenceMask_given)  genericMetric->SetFixedImageMask(registration->GetMetric()->GetFixedImageMask());
+      typedef itk::ImageToImageMetric< InternalImageType, InternalImageType >  MetricType;
+      typename  MetricType::Pointer metric=genericMetric->GetMetricPointer();
+      registration->SetMetric(metric);
+    }
+  }
+
+  void Execute(const itk::Object * , const itk::EventObject & ) {
+    return;
+  }
+
+  void SetArgsInfo(args_info_clitkAffineRegistration a) {
+    m_ArgsInfo=a;
+  }
+  args_info_clitkAffineRegistration m_ArgsInfo;
+};
+
+
+//==============================================================================
+// Update with the number of dimensions
+//==============================================================================
+template <unsigned int Dimension>
+void AffineRegistrationGenericFilter::UpdateWithDim(std::string PixelType)
+{
+  if (m_Verbose) std::cout  << "Images were detected to be "<< Dimension << "D and " << PixelType << "..." << std::endl;
+  if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and float..." << std::endl;
+  UpdateWithDimAndPixelType<Dimension, float>();
+  // }
+
+}
+
+
+//==============================================================================
+// Update with the number of dimensions and pixeltype
+//==============================================================================
+template <unsigned int Dimension, class PixelType>
+void
+AffineRegistrationGenericFilter::UpdateWithDimAndPixelType()
+{
+  //=============================================================================
+  //Input
+  //=============================================================================
+  bool threadsGiven=m_ArgsInfo.threads_given;
+  int threads=m_ArgsInfo.threads_arg;
+
+  //Coordinate Representation
+  typedef double TCoordRep;
+
+  //The pixeltype of the fixed image will be used for output
+  typedef itk::Image< PixelType, Dimension > FixedImageType;
+
+  //Whatever the pixel type, internally we work with an image represented in float
+  typedef   PixelType     InternalPixelType;
+  typedef itk::Image< InternalPixelType, Dimension > InternalImageType;
+
+  //Read in the reference/fixed image
+  typedef itk::ImageFileReader< InternalImageType > ReaderType;
+  typename ReaderType::Pointer  fixedImageReader  = ReaderType::New();
+  fixedImageReader->SetFileName( m_ArgsInfo.reference_arg);
+
+
+  //Read in the object/moving image
+  typename ReaderType::Pointer movingImageReader = ReaderType::New();
+  movingImageReader->SetFileName( m_ArgsInfo.target_arg );
+  if (m_Verbose) std::cout<<"Reading images..."<<std::endl;
+  fixedImageReader->Update();
+  movingImageReader->Update();
+
+  if (m_Verbose) std::cout  << "Reading images... " << std::endl;
+
+  //we connect pointers to these internal images
+  typename InternalImageType::Pointer fixedImage= fixedImageReader->GetOutput();
+  typename InternalImageType::Pointer movingImage= movingImageReader->GetOutput();
+
+  //We keep the images used for input for possible output
+  typename InternalImageType::Pointer inputFixedImage= fixedImageReader->GetOutput();
+  typename InternalImageType::Pointer inputMovingImage= movingImageReader->GetOutput();
+
+
+  //============================================================================
+  // Preprocessing
+  //============================================================================
+
+  //If given, the intensities of both images are first normalized to a zero mean and SD of 1
+  // (usefull for MI, not necessary for Mattes' MI but performed anyway for the ouput)
+  if ( m_ArgsInfo.normalize_flag ) {
+    typedef itk::NormalizeImageFilter< InternalImageType,InternalImageType >  NormalizeFilterType;
+
+    typename  NormalizeFilterType::Pointer  fixedNormalizeFilter = NormalizeFilterType::New();
+    typename  NormalizeFilterType::Pointer  movingNormalizeFilter = NormalizeFilterType::New();
+
+    fixedNormalizeFilter->SetInput( fixedImage );
+    movingNormalizeFilter->SetInput( movingImage );
+
+    fixedNormalizeFilter->Update();
+    movingNormalizeFilter->Update();
+
+    //We keep the images used for input for possible output
+    inputFixedImage= fixedNormalizeFilter->GetOutput();
+    inputMovingImage= movingNormalizeFilter->GetOutput();
+
+    //the pointers are reconnected for further output
+    fixedImage=fixedNormalizeFilter->GetOutput();
+    movingImage=movingNormalizeFilter->GetOutput();
+
+    if (m_Verbose)  std::cout <<  "Normalizing image intensities to zero mean and SD of 1..." << std::endl;
+  }
+
+
+  //If given, the images are blurred before processing
+  if ( m_ArgsInfo.blur_arg!= 0) {
+    typedef itk::DiscreteGaussianImageFilter<InternalImageType,InternalImageType> GaussianFilterType;
+    typename GaussianFilterType::Pointer fixedSmoother = GaussianFilterType::New();
+    typename GaussianFilterType::Pointer movingSmoother = GaussianFilterType::New();
+    fixedSmoother->SetVariance( m_ArgsInfo.blur_arg );
+    movingSmoother->SetVariance(m_ArgsInfo.blur_arg );
+
+    fixedSmoother->SetInput( fixedImage );
+    movingSmoother->SetInput( movingImage );
+
+    fixedSmoother->Update();
+    movingSmoother->Update();
+
+    fixedImage=fixedSmoother->GetOutput();
+    movingImage=movingSmoother->GetOutput();
+
+    if (m_Verbose)  std::cout <<  "Blurring images with a Gaussian with standard deviation of " << m_ArgsInfo.blur_arg <<"..." << std::endl;
+  }
+
+
+  //============================================================================
+  // Setting up the moving image in a reference system
+  //============================================================================
+  const itk::Vector<double, Dimension> movingResolution = movingImage->GetSpacing();
+  typename InternalImageType::RegionType movingRegion = movingImage->GetLargestPossibleRegion();
+  typename InternalImageType::RegionType::SizeType  movingSize = movingRegion.GetSize();
+
+  // Print the parameters of the moving image
+  if (m_Verbose) {
+    std::cout << "Object or Moving image:"<<std::endl;
+    std::cout << "Size: " << movingSize[0] << ", " << movingSize[1];
+    if (Dimension==3) std::cout<<", " << movingSize[2];
+    std::cout << std::endl;
+
+    std::cout<< "Resolution: "<< movingResolution[0] << ", " << movingResolution[1];
+    if (Dimension==3) std::cout<< ", " << movingResolution[2];
+    std::cout << std::endl;
+  }
+
+
+  //============================================================================
+  // Setting up the fixed image in a reference system
+  //============================================================================
+  const itk::Vector<double, Dimension> fixedResolution = fixedImage->GetSpacing();
+  typename InternalImageType::RegionType fixedRegion = fixedImage->GetLargestPossibleRegion();
+  typename InternalImageType::RegionType::SizeType fixedSize = fixedRegion.GetSize();
+
+  // Print the parameters of the moving image and the transform
+  if (m_Verbose) {
+    std::cout << "Target or Moving image:"<<std::endl;
+    std::cout << "Size: " << fixedSize[0] << ", " << fixedSize[1];
+    if (Dimension==3) std::cout<<", " << fixedSize[2];
+    std::cout << std::endl;
+
+    std::cout<< "Resolution: "<< fixedResolution[0] << ", " << fixedResolution[1];
+    if (Dimension==3) std::cout<< ", " << fixedResolution[2];
+    std::cout << std::endl;
+  }
+
+
+
+  //===========================================================================
+  // If given, we connect a mask to reference or target
+  //============================================================================
+  typedef itk::ImageMaskSpatialObject<  Dimension >   MaskType;
+  typename MaskType::Pointer  fixedMask=NULL;
+  if (m_ArgsInfo.referenceMask_given) {
+    fixedMask= MaskType::New();
+    typedef itk::Image< unsigned char, Dimension >   ImageMaskType;
+    typedef itk::ImageFileReader< ImageMaskType >    MaskReaderType;
+    typename MaskReaderType::Pointer  maskReader = MaskReaderType::New();
+    maskReader->SetFileName(m_ArgsInfo.referenceMask_arg);
+    try {
+      maskReader->Update();
+    } catch( itk::ExceptionObject & err ) {
+      std::cerr << "ExceptionObject caught while reading mask !" << std::endl;
+      std::cerr << err << std::endl;
+      return;
+    }
+    if (m_Verbose)std::cout <<"Reference image mask was read..." <<std::endl;
+
+    // Set the image to the spatialObject
+    fixedMask->SetImage( maskReader->GetOutput() );
+  }
+
+  typedef itk::ImageMaskSpatialObject<  Dimension >   MaskType;
+  typename MaskType::Pointer  movingMask=NULL;
+  if (m_ArgsInfo.targetMask_given) {
+    movingMask= MaskType::New();
+    typedef itk::Image< unsigned char, Dimension >   ImageMaskType;
+    typedef itk::ImageFileReader< ImageMaskType >    MaskReaderType;
+    typename MaskReaderType::Pointer  maskReader = MaskReaderType::New();
+    maskReader->SetFileName(m_ArgsInfo.targetMask_arg);
+    try {
+      maskReader->Update();
+    } catch( itk::ExceptionObject & err ) {
+      std::cerr << "ExceptionObject caught !" << std::endl;
+      std::cerr << err << std::endl;
+    }
+    if (m_Verbose)std::cout <<"Target image mask was read..." <<std::endl;
+
+    movingMask->SetImage( maskReader->GetOutput() );
+  }
+
+
+  //============================================================================
+  // The image pyramids
+  //============================================================================
+  typedef itk::RecursiveMultiResolutionPyramidImageFilter<InternalImageType,InternalImageType >  FixedImagePyramidType;
+  typedef itk::RecursiveMultiResolutionPyramidImageFilter<InternalImageType,InternalImageType >  MovingImagePyramidType;
+  typename FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New();
+  typename MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New();
+  fixedImagePyramid->SetUseShrinkImageFilter(false);
+  fixedImagePyramid->SetInput(fixedImage);
+  fixedImagePyramid->SetNumberOfLevels(m_ArgsInfo.levels_arg);
+  movingImagePyramid->SetUseShrinkImageFilter(false);
+  movingImagePyramid->SetInput(movingImage);
+  movingImagePyramid->SetNumberOfLevels(m_ArgsInfo.levels_arg);
+  if (m_Verbose) std::cout<<"Creating the image pyramid..."<<std::endl;
+  fixedImagePyramid->Update();
+  movingImagePyramid->Update();
+
+
+
+  //============================================================================
+  // We retrieve the type of metric from the command line
+  //============================================================================
+  typedef clitk::GenericMetric<args_info_clitkAffineRegistration, InternalImageType, InternalImageType> GenericMetricType;
+  typename GenericMetricType::Pointer genericMetric=GenericMetricType::New();
+  genericMetric->SetArgsInfo(m_ArgsInfo);
+  genericMetric->SetFixedImage(fixedImagePyramid->GetOutput(0));
+  if (fixedMask) genericMetric->SetFixedImageMask(fixedMask);
+  typedef itk::ImageToImageMetric< InternalImageType, InternalImageType >  MetricType;
+  typename  MetricType::Pointer metric=genericMetric->GetMetricPointer();
+  if (movingMask) metric->SetMovingImageMask(movingMask);
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+  if (threadsGiven) metric->SetNumberOfThreads( threads );
+#else
+  if (m_Verbose) std::cout<<"Not setting the number of threads (not compiled with USE_OPTIMIZED_REGISTRATION_METHODS)..."<<std::endl;
+#endif
+
+  //============================================================================
+  // Initialize using image moments.
+  //============================================================================
+  if (m_ArgsInfo.moment_flag) {
+    typedef itk::ImageMomentsCalculator< InternalImageType > CalculatorType;
+    typename CalculatorType::Pointer fixedCalculator= CalculatorType::New();
+
+    typename InternalImageType::Pointer fixedThresh;
+    if (m_ArgsInfo.intThreshold_given) {
+      typedef itk::ThresholdImageFilter<InternalImageType> ThresholdImageFilterType;
+      typename ThresholdImageFilterType::Pointer thresholder = ThresholdImageFilterType::New();
+      thresholder->SetInput(fixedImage);
+      thresholder->SetLower(m_ArgsInfo.intThreshold_arg);
+      thresholder->Update();
+      fixedThresh=thresholder->GetOutput();
+    } else fixedThresh=fixedImage;
+
+    fixedCalculator->SetImage(fixedThresh);
+    fixedCalculator->Compute();
+    Vector<double, Dimension> fixedCenter=fixedCalculator->GetCenterOfGravity();
+    if(m_Verbose)std::cout<<"The fixed center of gravity is "<<fixedCenter<<"..."<<std::endl;
+
+    typedef itk::ImageMomentsCalculator< InternalImageType > CalculatorType;
+    typename CalculatorType::Pointer movingCalculator= CalculatorType::New();
+
+    typename InternalImageType::Pointer movingThresh;
+    if (m_ArgsInfo.intThreshold_given) {
+      typedef itk::ThresholdImageFilter<InternalImageType> ThresholdImageFilterType;
+      typename ThresholdImageFilterType::Pointer thresholder = ThresholdImageFilterType::New();
+      thresholder->SetInput(movingImage);
+      thresholder->SetLower(m_ArgsInfo.intThreshold_arg);
+      thresholder->Update();
+      movingThresh=thresholder->GetOutput();
+    } else movingThresh=movingImage;
+
+    movingCalculator->SetImage(movingThresh);
+    movingCalculator->Compute();
+    Vector<double, Dimension> movingCenter=movingCalculator->GetCenterOfGravity();
+    if(m_Verbose)std::cout<<"The moving center of gravity is "<<movingCenter<<"..."<<std::endl;
+
+    Vector<double, Dimension> shift= movingCenter-fixedCenter;
+    if(m_Verbose)std::cout<<"The initial shift applied is "<<shift<<"..."<<std::endl;
+
+    m_ArgsInfo.transX_arg= shift [0];
+    m_ArgsInfo.transY_arg= shift [1];
+    if (Dimension==3) m_ArgsInfo.transZ_arg=shift [2];
+  }
+
+  //============================================================================
+  // Transform
+  //============================================================================
+  typedef clitk::GenericAffineTransform<args_info_clitkAffineRegistration, TCoordRep, Dimension > GenericAffineTransformType;
+  typename GenericAffineTransformType::Pointer genericAffineTransform = GenericAffineTransformType::New();
+  genericAffineTransform->SetArgsInfo(m_ArgsInfo);
+  typedef itk::Transform< double, Dimension, Dimension > TransformType;
+  typename TransformType::Pointer transform = genericAffineTransform->GetTransform();
+
+
+  //=======================================================
+  // Interpolator
+  //=======================================================
+  typedef clitk::GenericInterpolator<args_info_clitkAffineRegistration, InternalImageType,TCoordRep > GenericInterpolatorType;
+  typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
+  genericInterpolator->SetArgsInfo(m_ArgsInfo);
+  typedef itk::InterpolateImageFunction< InternalImageType, TCoordRep >  InterpolatorType;
+  typename  InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer();
+
+
+  //============================================================================
+  // Optimizer
+  //============================================================================
+  typedef clitk::GenericOptimizer<args_info_clitkAffineRegistration> GenericOptimizerType;
+  unsigned int nParam = transform->GetNumberOfParameters();
+  GenericOptimizerType::Pointer genericOptimizer=GenericOptimizerType::New();
+  genericOptimizer->SetArgsInfo(m_ArgsInfo);
+  genericOptimizer->SetOutputIteration(m_Verbose);
+  genericOptimizer->SetOutputPosition(m_Verbose);
+  genericOptimizer->SetOutputValue(m_Verbose);
+  genericOptimizer->SetOutputGradient(m_ArgsInfo.gradient_flag);
+  genericOptimizer->SetMaximize(genericMetric->GetMaximize());
+  genericOptimizer->SetNumberOfParameters(nParam);
+  typedef itk::SingleValuedNonLinearOptimizer OptimizerType;
+  OptimizerType::Pointer optimizer=genericOptimizer->GetOptimizerPointer();
+
+  // Scales
+  itk::Optimizer::ScalesType scales( nParam );
+  for (unsigned int i=nParam-Dimension; i<nParam; i++) //Translations
+    scales[i] = m_ArgsInfo.tWeight_arg;
+  for (unsigned int i=0; i<nParam-Dimension; i++)      //Rest
+    scales[i] = m_ArgsInfo.rWeight_arg*180./M_PI;
+  optimizer->SetScales(scales);
+
+  //============================================================================
+  // Multiresolution registration
+  //============================================================================
+  typedef itk::MultiResolutionImageRegistrationMethod< InternalImageType,InternalImageType >  RegistrationType;
+  typename  RegistrationType::Pointer registration = RegistrationType::New();
+  registration->SetFixedImage( fixedImage  );
+  registration->SetFixedImageRegion(fixedImage->GetLargestPossibleRegion());
+  registration->SetMovingImage(  movingImage );
+  registration->SetFixedImagePyramid( fixedImagePyramid );
+  registration->SetMovingImagePyramid( movingImagePyramid );
+  registration->SetTransform( transform );
+  registration->SetInitialTransformParameters( transform->GetParameters() );
+  registration->SetInterpolator( interpolator );
+  registration->SetMetric(metric);
+  registration->SetOptimizer(optimizer);
+  registration->SetNumberOfLevels( m_ArgsInfo.levels_arg );
+  if (m_Verbose) std::cout << "Setting "<< m_ArgsInfo.levels_arg <<" resolution levels..." << std::endl;
+  if (m_Verbose) std::cout << "Initial Transform: "<< registration->GetInitialTransformParameters()<<std::endl;
+
+  //============================================================================
+  // Connecting the commander to the registration to monitor it
+  //============================================================================
+  if (m_Verbose) {
+
+    // Output iteration info
+    CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
+    observer->SetOptimizer(genericOptimizer);
+    optimizer->AddObserver( itk::IterationEvent(), observer );
+
+
+    // Output level info
+    typedef RegistrationInterfaceCommand<RegistrationType, args_info_clitkAffineRegistration> CommandType;
+    typename CommandType::Pointer command = CommandType::New();
+    command->SetArgsInfo(m_ArgsInfo);
+    registration->AddObserver( itk::IterationEvent(), command );
+
+  }
+
+
+  //============================================================================
+  // Finally we can start the registration with the given amount of multiresolution levels
+  //============================================================================
+  if (m_Verbose) std::cout << "Starting the registration now..." << std::endl;
+
+  try {
+    registration->StartRegistration();
+  } catch( itk::ExceptionObject & err ) {
+    std::cerr << "ExceptionObject caught !" << std::endl;
+    std::cerr << err << std::endl;
+  }
+
+
+  //============================================================================
+  // Processing the result of the registration
+  //============================================================================
+  OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters();
+  std::cout<< "Result : " <<std::setprecision(12)<<std::endl;
+
+  for (unsigned int i=nParam-Dimension; i<nParam; i++) //Translations
+    std::cout << " Translation " << i << " = " << finalParameters[i];
+  for (unsigned int i=0; i<nParam-Dimension; i++)      //Rest
+    std::cout << " Other parameter " << i << " = " << finalParameters[i];
+
+
+  itk::Matrix<double,Dimension+1,Dimension+1> matrix;
+  if(m_ArgsInfo.transform_arg == 3) {
+    for(unsigned int i=0; i<Dimension; i++) {
+      matrix[i][3] =  finalParameters[nParam-Dimension+i];
+      for(unsigned int j=0; j<Dimension; j++) {
+        matrix[i][j] = finalParameters[i*3+j];
+      }
+      matrix[3][3] = 1.0;
+    }
+  } else {
+//    matrix = clitk::GetBackwardAffineMatrix3D(finalParameters);
+  }
+
+  std::cout << " Affine transform matrix =" << std::endl;
+  std::cout << matrix <<std::setprecision(6)<< std::endl;
+
+  // Write matrix to a file
+  if(m_ArgsInfo.matrix_given) {
+    std::ofstream mFile;
+    mFile.open(m_ArgsInfo.matrix_arg);
+    mFile<<std::setprecision(12)<<matrix<< std::setprecision(6)<<std::endl;
+    mFile.close();
+  }
+
+  //============================================================================
+  // Prepare the resampling filter in order to transform the moving image.
+  //============================================================================
+  if (m_ArgsInfo.output_given || m_ArgsInfo.checker_after_given || m_ArgsInfo.after_given ) {
+    transform->SetParameters( finalParameters );
+    typedef itk::ResampleImageFilter< InternalImageType,InternalImageType >    ResampleFilterType;
+    typename    ResampleFilterType::Pointer resampler = ResampleFilterType::New();
+
+    resampler->SetTransform( transform );
+    resampler->SetInput( movingImageReader->GetOutput() );
+    resampler->SetSize( fixedImageReader ->GetOutput()->GetLargestPossibleRegion().GetSize() );
+    resampler->SetOutputOrigin(  fixedImageReader ->GetOutput()->GetOrigin() );
+    resampler->SetOutputSpacing( fixedImageReader ->GetOutput()->GetSpacing() );
+    resampler->SetDefaultPixelValue( 0 );
+
+    //Output?
+    if (m_ArgsInfo.output_given) {
+      //We write an output in the same pixeltype then the input
+      typedef itk::ImageFileWriter< FixedImageType >  WriterType;
+      typename WriterType::Pointer outputWriter =  WriterType::New();
+      outputWriter->SetFileName(m_ArgsInfo.output_arg );
+      outputWriter->SetInput( resampler->GetOutput()   );
+      outputWriter->Update();
+    }
+
+
+    //============================================================================
+    // Checker after?
+    //============================================================================
+    if (m_ArgsInfo.checker_after_given) {
+      //To display correctly the checkerboard image, the intensities must lie in the same range (normalized)
+      //We write the image in the internal image type
+      typedef itk::ResampleImageFilter< InternalImageType,InternalImageType >    ResampleFilterType;
+      typename    ResampleFilterType::Pointer internalResampler = ResampleFilterType::New();
+      internalResampler->SetTransform( transform );
+      internalResampler->SetInput( inputMovingImage );
+      internalResampler->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() );
+      internalResampler->SetOutputOrigin(  fixedImage->GetOrigin() );
+      internalResampler->SetOutputSpacing( fixedImage->GetSpacing() );
+      internalResampler->SetDefaultPixelValue( 0 );
+
+      //We pass the normalized images to the checker filter
+      typedef itk::CheckerBoardImageFilter< InternalImageType > CheckerBoardFilterType;
+      typename CheckerBoardFilterType::Pointer checkerFilter= CheckerBoardFilterType::New();
+
+      checkerFilter->SetInput1(inputFixedImage);
+      checkerFilter->SetInput2(internalResampler->GetOutput());
+      typedef itk::ImageFileWriter< InternalImageType >  InternalWriterType;
+      typename  InternalWriterType::Pointer checkerWriter =  InternalWriterType::New();
+      checkerWriter->SetFileName(m_ArgsInfo.checker_after_arg);
+      checkerWriter->SetInput( checkerFilter->GetOutput() );
+      checkerWriter->Update();
+    }
+
+
+    //============================================================================
+    // Checker before?
+    //============================================================================
+    if (m_ArgsInfo.checker_before_given) {
+      //To display correctly the checkerboard image, the intensities must lie in the same range (normalized)
+      //We write the image in the internal image type
+      //We pass the normalized images to the checker filter
+      typedef itk::CheckerBoardImageFilter< InternalImageType > CheckerBoardFilterType;
+      typename CheckerBoardFilterType::Pointer checkerFilter= CheckerBoardFilterType::New();
+
+      checkerFilter->SetInput1(inputFixedImage);
+      checkerFilter->SetInput2(inputMovingImage);
+      typedef itk::ImageFileWriter< InternalImageType >  InternalWriterType;
+      typename  InternalWriterType::Pointer checkerWriter =  InternalWriterType::New();
+      checkerWriter->SetFileName(m_ArgsInfo.checker_before_arg);
+      checkerWriter->SetInput( checkerFilter->GetOutput() );
+      checkerWriter->Update();
+    }
+
+
+    //============================================================================
+    // Difference After?
+    //============================================================================
+    if (m_ArgsInfo.after_given) {
+      typedef itk::SubtractImageFilter< InternalImageType, FixedImageType,FixedImageType > DifferenceImageFilterType;
+      typename DifferenceImageFilterType::Pointer differenceAfterFilter= DifferenceImageFilterType::New();
+
+      differenceAfterFilter->SetInput1(fixedImageReader ->GetOutput());
+      differenceAfterFilter->SetInput2(resampler->GetOutput());
+
+      // Prepare a writer to write the difference image
+      typedef itk::ImageFileWriter< FixedImageType >  WriterType;
+      typename   WriterType::Pointer     differenceAfterWriter =  WriterType::New();
+      differenceAfterWriter->SetFileName(m_ArgsInfo.after_arg );
+      differenceAfterWriter->SetInput( differenceAfterFilter->GetOutput()   );
+      differenceAfterWriter->Update();
+    }
+  }
+
+  //============================================================================
+  // Difference Before?
+  //============================================================================
+  if (m_ArgsInfo.before_given) {
+    typedef itk::CastImageFilter< InternalImageType,FixedImageType > CastFilterType;
+    typename    CastFilterType::Pointer  caster =  CastFilterType::New();
+    caster->SetInput( movingImageReader->GetOutput() );
+
+    typedef itk::SubtractImageFilter< InternalImageType, FixedImageType, FixedImageType > DifferenceImageFilterType;
+    typename DifferenceImageFilterType::Pointer differenceBeforeFilter= DifferenceImageFilterType::New();
+
+
+    differenceBeforeFilter->SetInput1(fixedImageReader ->GetOutput());
+    differenceBeforeFilter->SetInput2(caster->GetOutput());
+
+    // Prepare a writer to write the difference image
+    typedef itk::ImageFileWriter< FixedImageType >  WriterType;
+    typename WriterType::Pointer     differenceBeforeWriter =  WriterType::New();
+    differenceBeforeWriter->SetFileName(m_ArgsInfo.before_arg);
+    differenceBeforeWriter->SetInput( differenceBeforeFilter->GetOutput()   );
+    differenceBeforeWriter->Update();
+  }
+
+}
+}
+#endif  //#define  CLITKAFFINEREGISTRATIONGENERICFILTER_TXX
+
similarity index 89%
rename from tools/clitkCorrelationRatioImageToImageMetric.h
rename to registration/clitkCorrelationRatioImageToImageMetric.h
index e1a5818c2c8c084c76b4ba11feeccfb76ea3a87a..d8ba13282a2877b6568dc6c7d5bd55e6908b4b6a 100644 (file)
@@ -1,7 +1,7 @@
 /*=========================================================================
   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
 
-  Authors belong to: 
+  Authors belong to:
   - University of LYON              http://www.universite-lyon.fr/
   - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
@@ -15,6 +15,7 @@
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
 ======================================================================-====*/
+
 #ifndef __clitkCorrelationRatioImageToImageMetric_h
 #define __clitkCorrelationRatioImageToImageMetric_h
 
  * @file   clitkCorrelationRatioImageToImageMetric.h
  * @author Jef Vandemeulebroucke <jef@creatis.insa-lyon.fr>
  * @date   July 30  18:14:53 2007
- * 
+ *
  * @brief  Compute the correlation ratio between 2 images
- * 
- * 
+ *
+ *
  */
 
 /* This computes the correlation ratio between 2 images
  *
- * This class is templated over the FixedImage type and the MovingImage 
+ * This class is templated over the FixedImage type and the MovingImage
  * type.
  *
  * The fixed and moving images are set via methods SetFixedImage() and
@@ -50,7 +51,7 @@
  *
  * The number of intensity bins used can be set through the SetNumberOfBins() method
  *
- * On Initialize(), we find the min and max intensities in the fixed image and compute the width of 
+ * On Initialize(), we find the min and max intensities in the fixed image and compute the width of
  * the intensity bins. The data structures which hold the bins and related measures are initialised.
  */
 
@@ -63,9 +64,9 @@ using namespace itk;
 namespace clitk
 {
 
-template < class TFixedImage, class TMovingImage > 
-class ITK_EXPORT CorrelationRatioImageToImageMetric: 
-    public ImageToImageMetric< TFixedImage, TMovingImage>
+template < class TFixedImage, class TMovingImage >
+class ITK_EXPORT CorrelationRatioImageToImageMetric:
+  public ImageToImageMetric< TFixedImage, TMovingImage>
 {
 public:
 
@@ -78,11 +79,11 @@ public:
 
   /** Method for creation through the object factory. */
   itkNewMacro(Self);
+
   /** Run-time type information (and related methods). */
   itkTypeMacro(CorrelationRatioImageToImageMetric, ImageToImageMetric);
 
+
   /** Types transferred from the base class */
   typedef typename Superclass::RealType                 RealType;
   typedef typename Superclass::TransformType            TransformType;
@@ -99,11 +100,11 @@ public:
   typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
 
 
- /** 
-   *  Initialize the Metric by 
-   *  (1) making sure that all the components are present and plugged 
-   *      together correctly,
-   *  (3) allocate memory for bin data structures. */
+  /**
+    *  Initialize the Metric by
+    *  (1) making sure that all the components are present and plugged
+    *      together correctly,
+    *  (3) allocate memory for bin data structures. */
   virtual void Initialize(void) throw ( ExceptionObject );
 
   /** Get the derivatives of the match measure. */
@@ -117,10 +118,10 @@ public:
   void GetValueAndDerivative( const TransformParametersType & parameters,
                               MeasureType& Value, DerivativeType& Derivative ) const;
 
- /** Number of bins to used in the calculation. Typical value is 50. */
 /** Number of bins to used in the calculation. Typical value is 50. */
   itkSetClampMacro( NumberOfBins, unsigned long,
                     1, NumericTraits<unsigned long>::max() );
-  itkGetConstReferenceMacro( NumberOfBins, unsigned long);   
+  itkGetConstReferenceMacro( NumberOfBins, unsigned long);
 
 protected:
   CorrelationRatioImageToImageMetric();
@@ -138,7 +139,7 @@ private:
   double m_FixedImageBinSize;
 
   //The number of pixels in the fixed image bins are stored in a vector
-   mutable std::vector<unsigned long> m_NumberOfPixelsCountedPerBin;
+  mutable std::vector<unsigned long> m_NumberOfPixelsCountedPerBin;
 
   //The mMSVPB and the mSMVPB are stored in vectors of realtype
   typedef float ValueType;
similarity index 99%
rename from tools/clitkCorrelationRatioImageToImageMetric.txx
rename to registration/clitkCorrelationRatioImageToImageMetric.txx
index 2b45c2ffc8a84b72e25d3e2f812ae3810b0092e2..595a347eff10748a7b277a9b9d3990831cf7e076 100644 (file)
@@ -15,6 +15,7 @@
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
 ======================================================================-====*/
+
 #ifndef _clitkCorrelationRatioImageToImageMetric_txx
 #define _clitkCorrelationRatioImageToImageMetric_txx
 
diff --git a/registration/clitkGenericAffineTransform.cxx b/registration/clitkGenericAffineTransform.cxx
new file mode 100644 (file)
index 0000000..f1db790
--- /dev/null
@@ -0,0 +1,48 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#include "clitkGenericAffineTransform.h"
+#include "clitkAffineRegistration_ggo.h"
+
+#include <itkEuler2DTransform.h>
+#include <itkEuler3DTransform.h>
+
+namespace clitk
+{
+//=========================================================================================================================
+template<>
+itk::MatrixOffsetTransformBase<double, 2, 2>::Pointer
+clitk::GenericAffineTransform<args_info_clitkAffineRegistration, double, 2>::GetNewEulerTransform()
+{
+  itk::Euler2DTransform< double >::Pointer p = itk::Euler2DTransform< double >::New();
+  itk::MatrixOffsetTransformBase<double, 2, 2>::Pointer pp;
+  pp = p;
+  return pp;
+}
+
+//=========================================================================================================================
+template<>
+itk::MatrixOffsetTransformBase<double, 3, 3>::Pointer
+clitk::GenericAffineTransform<args_info_clitkAffineRegistration, double, 3>::GetNewEulerTransform()
+{
+  itk::Euler3DTransform< double >::Pointer p = itk::Euler3DTransform< double >::New();
+  itk::MatrixOffsetTransformBase<double, 3, 3>::Pointer pp;
+  pp = p;
+  return pp;
+}
+}
diff --git a/registration/clitkGenericAffineTransform.h b/registration/clitkGenericAffineTransform.h
new file mode 100644 (file)
index 0000000..a403074
--- /dev/null
@@ -0,0 +1,95 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericAffineTransform_h
+#define __clitkGenericAffineTransform_h
+
+
+//itk include
+#include <itkIdentityTransform.h>
+#include <itkTranslationTransform.h>
+#include <itkAffineTransform.h>
+
+/*
+
+Requires at least the following section is the .ggo file
+
+option "transform"  - "Type: 0=Identity, 1=Translation, 2=Rigid, 3=Affine" int no  default="2"
+option "transX"     x "1-3: Initial translation in mm along the X axis"  float no  default="0.0"
+option "transY"     y "1-3: Initial translation in mm along the Y axis"  float no  default="0.0"
+option "transZ"     z "1-3: Initial translation in mm along the Z axis"  float no  default="0.0"
+option "initMatrix" - "2-3: Initial matrix (reference to object space) filename " string  no
+option "moment"     - "2-3: Initialize translation by aligning the center of gravities for the respective intensities" flag off
+
+The use will look something like
+
+  typedef clitk::GenericAffineTransform<args_info_clitkAffineRegistration, TCoordRep, Dimension > GenericAffineTransformType;
+  typename GenericAffineTransformType::Pointer genericAffineTransform = GenericAffineTransformType::New();
+  genericAffineTransform->SetArgsInfo(m_ArgsInfo);
+  typedef itk::Transform< double, Dimension, Dimension > TransformType;
+  typename TransformType::Pointer transform = genericAffineTransform->GetTransform();
+*/
+
+namespace clitk
+{
+template <class args_info_type, class TCoordRep, unsigned int Dimension>
+class GenericAffineTransform : public itk::LightObject
+{
+public:
+  //==============================================
+  typedef GenericAffineTransform     Self;
+  typedef itk::LightObject     Superclass;
+  typedef itk::SmartPointer<Self>            Pointer;
+  typedef itk::SmartPointer<const Self>      ConstPointer;
+
+  typedef itk::Transform< TCoordRep, Dimension, Dimension> TransformType;
+  typedef typename TransformType::Pointer TransformPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  //==============================================
+  //Set members
+  void SetArgsInfo(args_info_type args_info) {
+    m_ArgsInfo = args_info;
+    m_Verbose = m_ArgsInfo.verbose_flag;
+  }
+
+  //==============================================
+  //Get members
+  TransformPointer GetTransform(void);
+
+  //==============================================
+protected:
+  GenericAffineTransform();
+  ~GenericAffineTransform() {};
+
+  typename itk::MatrixOffsetTransformBase<TCoordRep, Dimension, Dimension>::Pointer GetNewEulerTransform();
+
+private:
+  args_info_type m_ArgsInfo;
+  TransformPointer m_Transform;
+  bool m_Verbose;
+};
+}
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkGenericAffineTransform.txx"
+#endif
+
+#endif // #define __clitkGenericAffineTransform_h
diff --git a/registration/clitkGenericAffineTransform.txx b/registration/clitkGenericAffineTransform.txx
new file mode 100644 (file)
index 0000000..eb4c6f9
--- /dev/null
@@ -0,0 +1,109 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericAffineTransform_txx
+#define __clitkGenericAffineTransform_txx
+
+#include "clitkTransformUtilities.h"
+
+namespace clitk
+{
+
+//=========================================================================================================================
+//constructor
+template<class args_info_type, class TCoordRep, unsigned int Dimension>
+GenericAffineTransform<args_info_type, TCoordRep, Dimension>::GenericAffineTransform()
+{
+  m_Transform=NULL;
+  m_Verbose=false;
+}
+
+//=========================================================================================================================
+//Get the pointer
+template<class args_info_type, class TCoordRep, unsigned int Dimension>
+typename GenericAffineTransform<args_info_type, TCoordRep, Dimension>::TransformPointer
+GenericAffineTransform<args_info_type, TCoordRep, Dimension>::GetTransform()
+{
+  //============================================================================
+  // We retrieve the type of transform from the command line
+  //============================================================================
+  typedef itk::MatrixOffsetTransformBase<TCoordRep, Dimension, Dimension> MatrixXType;
+  typename MatrixXType::Pointer tMatrix;
+  typedef itk::TranslationTransform< TCoordRep, Dimension> TranslationXType;
+  typename TranslationXType::Pointer tTranslation;
+
+  switch ( m_ArgsInfo.transform_arg ) {
+  case 0:
+    m_Transform= itk::IdentityTransform< TCoordRep, Dimension>::New();
+    if (m_Verbose) std::cout<<"Using identity transform..."<<std::endl;
+    break;
+  case 1:
+    tTranslation = TranslationXType::New();
+    if (m_Verbose) std::cout<<"Using translation transform..."<<std::endl;
+    break;
+  case 2:
+    tMatrix = GetNewEulerTransform();
+    if (m_Verbose) std::cout<<"Using euler transform..."<<std::endl;
+    break;
+  case 3:
+    tMatrix = itk::AffineTransform< TCoordRep, Dimension >::New();
+    if (m_Verbose) std::cout<<"Using affine transform..."<<std::endl;
+    break;
+  }//end of switch
+
+
+  typename MatrixXType::OutputVectorType offset;
+  if(m_ArgsInfo.transform_arg>0) {
+    //Initialize translations
+    offset[0] = m_ArgsInfo.transX_arg;
+    offset[1] = m_ArgsInfo.transY_arg;
+    if(Dimension>2) offset[2] = m_ArgsInfo.transZ_arg;
+    if(m_ArgsInfo.initMatrix_given) {
+      itk::Matrix<double, Dimension+1 , Dimension+1> matHom = ReadMatrix<Dimension>(m_ArgsInfo.initMatrix_arg);
+      offset = GetTranslationPartMatrix(matHom);
+    }
+  }
+  switch(m_ArgsInfo.transform_arg) {
+  case 1:
+    tTranslation->SetOffset(offset);
+    m_Transform=tTranslation;
+    break;
+  case 2:
+  case 3:
+    //Init rigid and affine transform center
+    itk::Point<TCoordRep, Dimension> center;
+    for (unsigned int i=0; i<Dimension; i++)
+      center[i] = 0;
+    tMatrix->SetCenter(center);
+
+    //Initialize transform
+    if(m_ArgsInfo.initMatrix_given) {
+      itk::Matrix<double, Dimension+1 , Dimension+1> matHom = ReadMatrix<Dimension>(m_ArgsInfo.initMatrix_arg);
+      typename MatrixXType::MatrixType matrix = GetRotationalPartMatrix(matHom);
+      tMatrix->SetOffset(offset);
+      tMatrix->SetMatrix(matrix);
+    }
+    m_Transform=tMatrix;
+    break;
+  }
+
+  return m_Transform;
+}
+}
+
+#endif
diff --git a/registration/clitkGenericInterpolator.h b/registration/clitkGenericInterpolator.h
new file mode 100644 (file)
index 0000000..a0b2faf
--- /dev/null
@@ -0,0 +1,93 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericInterpolator_h
+#define __clitkGenericInterpolator_h
+
+//itk include
+#include "itkNearestNeighborInterpolateImageFunction.h"
+#include "itkLinearInterpolateImageFunction.h"
+#include "itkBSplineInterpolateImageFunction.h"
+#include "itkBSplineInterpolateImageFunctionWithLUT.h"
+
+
+/*
+
+Requires at least the following section is the .ggo file
+
+option "interp"                -       "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT"      int     no  default="1"
+option "interpOrder"   -       "Order if BLUT or BSpline (0-5)"                        int     no  default="3"
+option "interpSF"      -       "Sampling factor if BLUT"                               int     no  default="20"
+
+The use will look something like
+
+typedef clitk::GenericInterpolator<InputImageType, double> GenericInterpolatorType;
+typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
+genericInterpolator->SetArgsInfo(m_ArgsInfo);
+typedef itk::InterpolateImageFunction<InputImageType, double> InterpolatorType;
+typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer();
+
+*/
+
+namespace clitk
+{
+
+template <class args_info_type,  class ImageType,  class TCoordRep >
+class GenericInterpolator : public itk::LightObject
+{
+public:
+  //==============================================
+  typedef GenericInterpolator     Self;
+  typedef itk::LightObject     Superclass;
+  typedef itk::SmartPointer<Self>            Pointer;
+  typedef itk::SmartPointer<const Self>      ConstPointer;
+
+  typedef itk::InterpolateImageFunction<ImageType, TCoordRep> InterpolatorType;
+  typedef typename InterpolatorType::Pointer InterpolatorPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  //==============================================
+  //Set members
+  void SetArgsInfo(args_info_type args_info) {
+    m_ArgsInfo= args_info;
+    m_Verbose=m_ArgsInfo.verbose_flag;
+  }
+
+  //==============================================
+  //Get members
+  InterpolatorPointer GetInterpolatorPointer(void);
+
+  //==============================================
+protected:
+  GenericInterpolator();
+  ~GenericInterpolator() {};
+
+private:
+  args_info_type m_ArgsInfo;
+  InterpolatorPointer m_Interpolator;
+  bool m_Verbose;
+};
+
+} // end namespace clitk
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkGenericInterpolator.txx"
+#endif
+
+#endif // #define __clitkGenericInterpolator_h
diff --git a/registration/clitkGenericInterpolator.txx b/registration/clitkGenericInterpolator.txx
new file mode 100644 (file)
index 0000000..c5deffe
--- /dev/null
@@ -0,0 +1,90 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericInterpolator_txx
+#define __clitkGenericInterpolator_txx
+
+#include "clitkGenericInterpolator.h"
+
+
+namespace clitk
+{
+
+//=========================================================================================================================
+//constructor
+template <class args_info_type,  class ImageType, class TCoordRep>
+GenericInterpolator<args_info_type, ImageType, TCoordRep>::GenericInterpolator()
+{
+  m_Interpolator=NULL;
+  m_Verbose=false;
+}
+
+
+//=========================================================================================================================
+//Get the pointer
+template <class args_info_type,  class ImageType, class TCoordRep>
+typename GenericInterpolator<args_info_type, ImageType, TCoordRep>::InterpolatorPointer
+GenericInterpolator<args_info_type, ImageType, TCoordRep>::GetInterpolatorPointer()
+{
+  //============================================================================
+  // We retrieve the type of interpolation from the command line
+  //============================================================================
+  typename InterpolatorType::Pointer interpolator;
+
+  switch ( m_ArgsInfo.interp_arg ) {
+  case 0:
+
+    interpolator= itk::NearestNeighborInterpolateImageFunction< ImageType,TCoordRep >::New();
+    if (m_Verbose) std::cout<<"Using nearestneighbor interpolation..."<<std::endl;
+    break;
+
+  case 1:
+
+    interpolator = itk::LinearInterpolateImageFunction< ImageType,TCoordRep >::New();
+    if (m_Verbose) std::cout<<"Using linear interpolation..."<<std::endl;
+    break;
+
+  case 2: {
+    typename itk::BSplineInterpolateImageFunction< ImageType,TCoordRep >::Pointer m =itk::BSplineInterpolateImageFunction< ImageType,TCoordRep >::New();
+    m->SetSplineOrder(m_ArgsInfo.interpOrder_arg);
+    interpolator=m;
+    if (m_Verbose) std::cout<<"Using Bspline interpolation..."<<std::endl;
+    break;
+  }
+
+  case 3: {
+    typename itk::BSplineInterpolateImageFunctionWithLUT< ImageType,TCoordRep >::Pointer m =itk::BSplineInterpolateImageFunctionWithLUT< ImageType,TCoordRep >::New();
+    m->SetSplineOrder(m_ArgsInfo.interpOrder_arg);
+    m->SetLUTSamplingFactor(m_ArgsInfo.interpSF_arg);
+    interpolator=m;
+    if (m_Verbose) std::cout<<"Using BLUT interpolation..."<<std::endl;
+    break;
+  }
+
+
+  }//end of switch
+
+
+  //============================================================================
+  //return the pointer
+  return interpolator;
+}
+
+}
+
+#endif
diff --git a/registration/clitkGenericMetric.h b/registration/clitkGenericMetric.h
new file mode 100644 (file)
index 0000000..5d71819
--- /dev/null
@@ -0,0 +1,158 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericMetric_h
+#define __clitkGenericMetric_h
+
+//clitk include
+#include "clitkNormalizedCorrelationImageToImageMetric.h"
+#include "clitkCorrelationRatioImageToImageMetric.h"
+#include "itkMeanSquaresImageToImageMetricFor3DBLUTFFD.h"
+#include "itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h"
+#include "clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h"
+
+//itk include
+#include "itkSpatialObject.h"
+#include "itkNormalizeImageFilter.h"
+#include "itkImageToImageMetric.h"
+#include "itkMeanSquaresImageToImageMetric.h"
+#include "itkCorrelationCoefficientHistogramImageToImageMetric.h"
+#include "itkGradientDifferenceImageToImageMetric.h"
+#include "itkMutualInformationImageToImageMetric.h"
+#include "itkMutualInformationHistogramImageToImageMetric.h"
+#include "itkMattesMutualInformationImageToImageMetric.h"
+#include "itkNormalizedMutualInformationHistogramImageToImageMetric.h"
+
+
+
+/*
+
+Requires at least the following section is the .ggo file. Adapt the defaults to the application
+
+
+section "Metric (optimized, threaded versions are available for *, compile ITK with REVIEW and OPT_REGISTRATION enabled. Further optimized versions ** for  BLUT FFD optimizing a !3D! vector field  )"
+
+option "metric"        -       "Type: 0=SSD*, 1=Normalized CC*, 2=Histogram CC, 3=Gradient-Difference, 4=Viola-Wells MI, 5=Histogram MI, 6=Mattes' MI*, 7=Normalized MI, 8=CR, 9=SSD for BLUT FFD**, 10=CC for BLUT FFD**, 11=Mattes' MI for BLUT FFD**"       int     no      default="0"
+option "samples"       -       "Specify fraction [0, 1] of samples of the reference image used for the metric (* only). Use high fraction for detailed images (eg. 0.2, 0.5), for smooth images 0.01 might be enough." float   no      default="1"
+option "intThreshold"  -       "Fixed image samples intensity threshold (* only)"                                                      float   no
+option "subtractMean"  -       "1: Subtract mean for NCC calculation (narrows optimal)"                                                flag    on
+option "bins"          -       "2,5-8: Number of histogram bins"                                                                       int     no      default="50"
+option "random"        -       "4,6: Samples should be taken randomly, otherwise uniformly"                                            flag    off
+option "stdDev"                -       "4: specify the standard deviation in mm of the gaussian kernels for both PDF estimations"              float   no      default="0.4"
+option "explicitPDFDerivatives"        -       "6: Calculate PDF derivatives explicitly (rigid=true; FFD=false)"                               flag    on
+
+
+The use will look something like
+
+typedef clitk::GenericMetric<args_info_type, FixedImageType, MovingImageType> GenericMetricType;
+typename GenericMetricType::Pointer genericMetric=GenericMetricType::New();
+genericMetric->SetArgsInfo(m_ArgsInfo);
+genericMetric->SetFixedImageRegion(fixedImage->GetLargestPossibleRegion());
+genericMetric->SetFixedImage(fixedImage);
+genericMetric->SetFixedImageMask(fixedImageMask);
+typedef itk::ImageToImageMetric<FixedImageType, MovingImageType> MetricType;
+typename MetricType::Pointer metric=genericMetric->GetMetricPointer();
+
+*/
+
+
+namespace clitk
+{
+
+template <  class args_info_type, class FixedImageType,  class MovingImageType >
+class GenericMetric : public itk::LightObject
+{
+public:
+  //==============================================
+  typedef GenericMetric     Self;
+  typedef itk::LightObject     Superclass;
+  typedef itk::SmartPointer<Self>            Pointer;
+  typedef itk::SmartPointer<const Self>      ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Determine the image dimension. */
+  itkStaticConstMacro(FixedImageDimension, unsigned int,
+                      FixedImageType::ImageDimension );
+  itkStaticConstMacro(MovingImageDimension, unsigned int,
+                      MovingImageType::ImageDimension );
+
+  // Typedef
+  typedef itk::ImageToImageMetric<FixedImageType, MovingImageType> MetricType;
+  typedef typename MetricType::Pointer MetricPointer;
+  typedef typename FixedImageType::RegionType FixedImageRegionType;
+  typedef itk::SpatialObject<itkGetStaticConstMacro(FixedImageDimension)> FixedImageMaskType;
+  typedef typename FixedImageMaskType::Pointer MaskPointer;
+  typedef typename FixedImageType::PixelType FixedImagePixelType;
+  typedef typename FixedImageType::IndexType FixedImageIndexType;
+  typedef typename FixedImageType::PointType FixedImagePointType;
+
+  //==============================================
+  //Set members
+  void SetArgsInfo(args_info_type args_info) {
+    m_ArgsInfo= args_info;
+    m_Verbose=m_ArgsInfo.verbose_flag;
+  }
+  void SetFixedImageRegion(const FixedImageRegionType f) {
+    m_FixedImageRegion=f;
+    m_FixedImageRegionGiven=true;
+  }
+  void SetFixedImage(typename FixedImageType::Pointer f) {
+    m_FixedImage=f;
+  }
+  void SetFixedImageMask( const FixedImageMaskType* f) {
+    m_FixedImageMask=f;
+  }
+
+  //==============================================
+  //Get members
+  MetricPointer GetMetricPointer(void);
+  bool GetMaximize(void) {
+    return m_Maximize;
+  }
+
+
+  //==============================================
+protected:
+  GenericMetric();
+  ~GenericMetric() {};
+
+private:
+  args_info_type m_ArgsInfo;
+  MetricPointer m_Metric;
+  bool m_Maximize;
+  bool m_Verbose;
+  bool m_FixedImageRegionGiven;
+  FixedImageRegionType m_FixedImageRegion;
+  typename FixedImageType::Pointer m_FixedImage;
+  typename FixedImageMaskType::ConstPointer m_FixedImageMask;
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+  FixedImagePixelType m_FixedImageSamplesIntensityThreshold;
+  bool m_UseFixedImageSamplesIntensityThreshold;
+#endif
+
+};
+
+} // end namespace clitk
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkGenericMetric.txx"
+#endif
+
+#endif // #define __clitkGenericMetric_h
diff --git a/registration/clitkGenericMetric.txx b/registration/clitkGenericMetric.txx
new file mode 100644 (file)
index 0000000..27c68ed
--- /dev/null
@@ -0,0 +1,401 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericMetric_txx
+#define __clitkGenericMetric_txx
+
+#include "clitkGenericMetric.h"
+
+
+namespace clitk
+{
+
+//=========================================================================================================================
+//constructor
+template <class args_info_type, class FixedImageType, class MovingImageType>
+GenericMetric<args_info_type, FixedImageType, MovingImageType>::GenericMetric()
+{
+  m_Metric=NULL;
+  m_Maximize=false;
+  m_Verbose=false;
+  m_FixedImageRegionGiven=false;
+  m_FixedImageSamplesIntensityThreshold=0;
+  m_UseFixedImageSamplesIntensityThreshold=false;
+  m_FixedImageMask=NULL;
+}
+
+
+//=========================================================================================================================
+//Get the pointer
+template <class args_info_type, class FixedImageType, class MovingImageType>
+typename GenericMetric<args_info_type, FixedImageType, MovingImageType>::MetricPointer
+GenericMetric<args_info_type,FixedImageType, MovingImageType>::GetMetricPointer()
+{
+  //============================================================================
+  // Sanity check:
+  // The image is required for the region and spacing
+  if( ! this->m_FixedImage ) {
+    itkExceptionMacro( "Fixed Image has not been set" );
+  }
+
+  // If the image come from a filter, then update that filter.
+  if( this->m_FixedImage->GetSource() ) {
+    this->m_FixedImage->Update();
+  }
+
+  // The metric region
+  if( !  m_FixedImageRegionGiven ) {
+    m_FixedImageRegion=m_FixedImage->GetLargestPossibleRegion();
+  }
+
+
+  //============================================================================
+  //switch on  the  metric type chosen adn set metric specific members
+  switch (m_ArgsInfo.metric_arg) {
+
+  case 0: {
+    typename itk::MeanSquaresImageToImageMetric< FixedImageType, MovingImageType >::Pointer m =
+      itk::MeanSquaresImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set Parameters for this metric
+    m_Maximize=false;
+    if (m_Verbose) std::cout<<"Using the mean squares metric..."<<std::endl;
+    m_Metric=m;
+    break;
+  }
+
+  case 1: {
+    typename  clitk::NormalizedCorrelationImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    =clitk::NormalizedCorrelationImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set Parameters for this metric
+    m->SetSubtractMean(m_ArgsInfo.subtractMean_flag);
+    m_Maximize=false;
+    if (m_Verbose) {
+      if ( !m_ArgsInfo.subtractMean_flag) std::cout<<"Using the normalized correlation metric without subtracting the mean..."<<std::endl;
+      else  std::cout<<"Using the normalized correlation metric with subtraction of mean..."<<std::endl;
+    }
+    m_Metric=m;
+    break;
+  }
+
+  case 2: {
+    typename itk::CorrelationCoefficientHistogramImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    = itk::CorrelationCoefficientHistogramImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    typename itk::CorrelationCoefficientHistogramImageToImageMetric<FixedImageType, MovingImageType>::HistogramSizeType size;
+    for (unsigned int i=0; i < FixedImageDimension; i++)size[i]=m_ArgsInfo.bins_arg;
+    m->SetHistogramSize(size);
+    m_Maximize=false;
+    if (m_Verbose) std::cout<<"Using the histogram correlation coefficient metric..."<<std::endl;
+    m_Metric = m;
+    break;
+  }
+
+  case 3: {
+    typename itk::GradientDifferenceImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    = itk::GradientDifferenceImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    m_Maximize=false;
+    if (m_Verbose) std::cout<<"Using the gradient difference metric..."<<std::endl;
+    m_Metric=m;
+    break;
+  }
+
+  case 4: {
+    typename itk::MutualInformationImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    = itk::MutualInformationImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    m->SetFixedImageStandardDeviation( m_ArgsInfo.stdDev_arg );
+    m->SetMovingImageStandardDeviation( m_ArgsInfo.stdDev_arg);
+    m_Maximize=true;
+
+    //Randomize samples if demanded
+    if (m_ArgsInfo.random_flag ) m->ReinitializeSeed();
+    else m->ReinitializeSeed(0);
+    if (m_Verbose) std::cout<<"Using Viola-Wells MI..."<<std::endl;
+    m_Metric=m;
+    break;
+  }
+
+  case 5: {
+    typename itk::MutualInformationHistogramImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    = itk::MutualInformationHistogramImageToImageMetric< FixedImageType, MovingImageType>::New();
+
+    //Set parameters for this metric
+    typename itk::MutualInformationHistogramImageToImageMetric<FixedImageType, MovingImageType>::HistogramSizeType size;
+    for (unsigned int i=0; i < FixedImageDimension; i++)size[i]=m_ArgsInfo.bins_arg;
+    m->SetHistogramSize(size);
+    m_Maximize=true;
+    if (m_Verbose) std::cout<<"Using the histogram MI with "<<m_ArgsInfo.bins_arg<<" bins..."<<std::endl;
+    m_Metric=m;
+    break;
+  }
+
+  case 6: {
+    typename itk::MattesMutualInformationImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    = itk::MattesMutualInformationImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    m_Maximize=false;
+    m->SetNumberOfHistogramBins(m_ArgsInfo.bins_arg);
+
+    //Randomize samples if demanded
+    if (m_ArgsInfo.random_flag ) m->ReinitializeSeed();
+    else m->ReinitializeSeed(0);
+
+    // Two ways of calculating the derivatives
+    m->SetUseExplicitPDFDerivatives(m_ArgsInfo.explicitPDFDerivatives_flag);
+
+
+    if (m_Verbose) {
+      std::cout<<"Using Mattes' MI with "<<m_ArgsInfo.bins_arg<<" bins..."<<std::endl;
+      if (m_ArgsInfo.explicitPDFDerivatives_flag) std::cout<<"Calculating PDFs explicitly..."<<std::endl;
+    }
+    m_Metric=m;
+    break;
+  }
+
+  case 7: {
+    typename itk::NormalizedMutualInformationHistogramImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    =itk::NormalizedMutualInformationHistogramImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    typename itk::NormalizedMutualInformationHistogramImageToImageMetric<FixedImageType, MovingImageType>::HistogramSizeType size;
+    for (unsigned int i=0; i < FixedImageDimension; i++)size[i]=m_ArgsInfo.bins_arg;
+    m->SetHistogramSize(size);
+    m_Maximize=false;
+    if (m_Verbose) std::cout<<"Using the normalized MI with "<<m_ArgsInfo.bins_arg<<" bins..."<<std::endl;
+    m_Metric=m;
+    break;
+  }
+
+  case 8: {
+    typename clitk::CorrelationRatioImageToImageMetric< FixedImageType, MovingImageType >::Pointer m
+    = clitk::CorrelationRatioImageToImageMetric< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    m_Maximize=false;
+    m->SetNumberOfBins(m_ArgsInfo.bins_arg);
+    if (m_Verbose) std::cout<<"Using the correlation ratio..."<<std::endl;
+    m_Metric =m;
+    break;
+  }
+
+  case 9: {
+    typename itk::MeanSquaresImageToImageMetricFor3DBLUTFFD< FixedImageType, MovingImageType >::Pointer m
+    = itk::MeanSquaresImageToImageMetricFor3DBLUTFFD< FixedImageType, MovingImageType >::New();
+
+    //Set Parameters for this metric
+    m_Maximize=false;
+    if (m_Verbose) std::cout<<"Using the mean squares metric for 3D BLUT FFD..."<<std::endl;
+    m_Metric=m;
+    break;
+  }
+
+  case 10: {
+    typename  clitk::NormalizedCorrelationImageToImageMetricFor3DBLUTFFD< FixedImageType, MovingImageType >::Pointer m
+    =clitk::NormalizedCorrelationImageToImageMetricFor3DBLUTFFD< FixedImageType, MovingImageType >::New();
+
+    //Set Parameters for this metric
+    m->SetSubtractMean(m_ArgsInfo.subtractMean_flag);
+    m_Maximize=false;
+    if (m_Verbose) {
+      if ( !m_ArgsInfo.subtractMean_flag) std::cout<<"Using the normalized correlation metric for 3D BLUT FFD without subtracting the mean..."<<std::endl;
+      else  std::cout<<"Using the normalized correlation metric 3D BLUT FFD with subtraction of mean..."<<std::endl;
+    }
+    m_Metric=m;
+    break;
+  }
+
+  case 11: {
+    typename itk::MattesMutualInformationImageToImageMetricFor3DBLUTFFD< FixedImageType, MovingImageType >::Pointer m
+    = itk::MattesMutualInformationImageToImageMetricFor3DBLUTFFD< FixedImageType, MovingImageType >::New();
+
+    //Set parameters for this metric
+    m_Maximize=false;
+    m->SetNumberOfHistogramBins(m_ArgsInfo.bins_arg);
+
+    //Randomize samples if demanded
+    if (m_ArgsInfo.random_flag ) m->ReinitializeSeed();
+    else m->ReinitializeSeed(0);
+
+    // Two ways of calculating the derivatives
+    m->SetUseExplicitPDFDerivatives(m_ArgsInfo.explicitPDFDerivatives_flag);
+
+
+    if (m_Verbose) {
+      std::cout<<"Using Mattes' MI for 3D BLUT FFD with "<<m_ArgsInfo.bins_arg<<" bins..."<<std::endl;
+      if (m_ArgsInfo.explicitPDFDerivatives_flag) std::cout<<"Calculating PDFs explicitly..."<<std::endl;
+    }
+    m_Metric=m;
+    break;
+  }
+
+  }
+
+
+  // Common properties
+  if( m_FixedImageMask.IsNotNull() )  m_Metric->SetFixedImageMask(m_FixedImageMask);
+  m_Metric->SetFixedImageRegion(m_FixedImageRegion);
+
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+
+  //============================================================================
+  // Set the lower intensity threshold
+  if (m_ArgsInfo.intThreshold_given) {
+    m_UseFixedImageSamplesIntensityThreshold=true;
+    m_FixedImageSamplesIntensityThreshold=m_ArgsInfo.intThreshold_arg;
+    m_Metric->SetFixedImageSamplesIntensityThreshold(m_FixedImageSamplesIntensityThreshold);
+    if (m_Verbose) std::cout<<"Setting the fixed image intensity threshold to "<<m_FixedImageSamplesIntensityThreshold<<"..."<<std::endl;
+  }
+
+
+  //============================================================================
+  // Set the number of samples
+
+  // Sample all pixel
+  if ( ( m_ArgsInfo.samples_arg==1.0) && (m_FixedImageMask.IsNull()) && (!m_UseFixedImageSamplesIntensityThreshold ) ) {
+    m_Metric->SetUseAllPixels(true);
+    if (m_Verbose) std::cout<<"Using all pixels (a fraction of "<<m_ArgsInfo.samples_arg<<")..."<<std::endl;
+  }
+  // JV the optimized metric will resample points to obtain the number of pixels:
+  // Pass the correct number of spatial samples, with indexes
+  else {
+    std::vector<typename FixedImageType::IndexType> fiic;// fixedImageindexContainer
+    unsigned int numberOfValidPixels=0;
+    FixedImageIndexType index;
+    FixedImagePointType inputPoint;
+
+    // Calculate the number
+    const unsigned int totalNumberOfPixels = m_FixedImageRegion.GetNumberOfPixels();
+    const unsigned int numberOfDemandedPixels =  static_cast< unsigned int >( (double) totalNumberOfPixels *m_ArgsInfo.samples_arg );
+
+    // --------------------------------------------------
+    // Sample whole image sequentially and pass the indexes
+    if (m_ArgsInfo.samples_arg==1.0) {
+      if (m_Verbose) std::cout<<"Sequentially scanning the image for valid pixels..."<<std::endl;
+
+      // Set up a region interator within the user specified fixed image region.
+      typedef ImageRegionConstIteratorWithIndex<FixedImageType> RegionIterator;
+      RegionIterator regionIter( m_FixedImage, m_FixedImageRegion );
+
+      // go over the whole region
+      regionIter.GoToBegin();
+      while(!regionIter.IsAtEnd() ) {
+
+        // Get sampled index
+        index = regionIter.GetIndex();
+
+        // Mask?
+        if( m_FixedImageMask.IsNotNull() ) {
+          // Check if the Index is inside the mask, translate index to point
+          m_FixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+          // If not inside the mask, ignore the point
+          if( !m_FixedImageMask->IsInside( inputPoint ) ) {
+            ++regionIter; // jump to next pixel
+            continue;
+          }
+        }
+
+        // Intensity?
+        if( m_UseFixedImageSamplesIntensityThreshold &&
+            ( regionIter.Get() < m_FixedImageSamplesIntensityThreshold) ) {
+          ++regionIter; // jump to next pixel
+          continue;
+        }
+
+        // Add point to the numbers
+        fiic.push_back(index);
+        ++numberOfValidPixels;
+        ++regionIter;
+      }
+    }
+
+    // --------------------------------------------------
+    // Sample randomly
+    else {
+      if (m_Verbose) std::cout<<"Randomly scanning the image for valid pixels..."<<std::endl;
+
+      // Set up a random interator within the user specified fixed image region.
+      typedef ImageRandomConstIteratorWithIndex<FixedImageType> RandomIterator;
+      RandomIterator randIter( m_FixedImage, m_FixedImageRegion );
+
+      // Randomly sample the image
+      randIter.SetNumberOfSamples( numberOfDemandedPixels * 1000 );
+      randIter.GoToBegin();
+      while( (!randIter.IsAtEnd()) && (numberOfValidPixels<=numberOfDemandedPixels)  ) {
+        // Get sampled index
+        index = randIter.GetIndex();
+
+        // Mask?
+        if( m_FixedImageMask.IsNotNull() ) {
+
+          // Check if the Index is inside the mask, translate index to point
+          m_FixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+          // If not inside the mask, ignore the point
+          if( !m_FixedImageMask->IsInside( inputPoint ) ) {
+            ++randIter; // jump to next pixel
+            continue;
+          }
+
+        }
+
+        // Intensity?
+        if( m_UseFixedImageSamplesIntensityThreshold &&
+            randIter.Get() < m_FixedImageSamplesIntensityThreshold ) {
+          ++randIter;
+          continue;
+        }
+
+        // Add point to the numbers
+        fiic.push_back(index);
+        ++numberOfValidPixels;
+        ++randIter;
+      }
+    }
+
+
+    // Set the indexes of valid samples
+    m_Metric->SetFixedImageIndexes(fiic);
+    // m_Metric->SetNumberOfSpatialSamples( numberOfValidPixels);
+    if (m_Verbose) std::cout<<"A fraction of "<<m_ArgsInfo.samples_arg<<" spatial samples was requested..."<<std::endl;
+    double fraction=(double)numberOfValidPixels/ (double) totalNumberOfPixels;
+    if (m_Verbose) std::cout<<"Found "<<numberOfValidPixels <<" valid pixels for a total of "<<totalNumberOfPixels<<" (a fraction of "<<fraction<<")..."<<std::endl;
+
+  }
+
+#else
+  if (m_Verbose) std::cout<<"Not setting the fixed image intensity threshold or the fraction of samples to use (not compiled with USE_OPTIMIZED_REGISTRATION_METHODS)..."<<std::endl;
+
+
+#endif
+  //============================================================================
+  //return the pointer
+  return m_Metric;
+}
+
+}
+
+#endif
diff --git a/registration/clitkGenericOptimizer.h b/registration/clitkGenericOptimizer.h
new file mode 100644 (file)
index 0000000..1c8ce11
--- /dev/null
@@ -0,0 +1,435 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkGenericOptimizer_h
+#define __clitkGenericOptimizer_h
+
+//clitk include
+#include "clitkLBFGSBOptimizer.h"
+
+//itk include
+#include "itkAmoebaOptimizer.h"
+#include "itkPowellOptimizer.h"
+#include "itkFRPROptimizer.h"
+#include "itkRegularStepGradientDescentOptimizer.h"
+#include "itkVersorRigid3DTransformOptimizer.h"
+#include "itkConjugateGradientOptimizer.h"
+#include "itkLBFGSOptimizer.h"
+#include "itkSPSAOptimizer.h"
+
+// general
+#include <iomanip>
+
+/*Requires at least this section in the associated *.ggo file: (modify defaults to fit application)
+
+option "optimizer"     -       "0=Simplex, 1=Powell, 2=FRPR, 3=Regular Step GD, 4=VersorRigid3D, 5=Conjugated Gradient, 6=L-BFGS, 7=L-BFGS-B" int no default="0"
+option "delta"         -       "0: Initial delta, otherwise automatic"                                                 double  no
+option "step"          -       "1,2,3,4: Initial stepsize (to be multiplied with the gradient)"                        double  no      default="2.0"
+option "relax"                 -       "3,4: Relaxation of the stepsize (multiplied each time the gradient changes sign)"      double  no      default="0.7"
+option "valueTol"      -       "0,1,2: Tolerance on the function"                                                      double  no      default="0.01"
+option "stepTol"       -       "0,1,3,4: Tolerance on the step size"                                                   double  no      default="0.1"
+option "gradTol"       -       "3,4,6,7: Tolerance on the (projected) gradient magnitude (7: 1=low->1e-10=high precision)"     double  no      default="1e-5"
+option "lineAcc"       -       "6: Line accuracy (eg: high=0.1, low=0.9)"      double  no      default="0.9"
+option "convFactor"    -       "7: Convergence factor: terminate if factor*machine_precision>reduction in cost (1e+12 low -> 1e+1 high precision) "    double          no      default="1e+7"
+option "maxIt"         -       "0-7: Maximum number of iterations"                                     int     no      default="500"
+option "maxLineIt"     -       "1,2: Maximum number of line iterations"                                        int     no      default="50"
+option "maxEval"       -       "6,7: Maximum number of evaluations"                                            int     no      default="500"
+option "maxCorr"       -       "7: Maximum number of corrections"                                              int     no      default="5"
+option "selectBound"   -       "7: Select the type of bound: 0=none, 1=u, 2=u&l, 3=l"                  int     no      default="0"
+option "lowerBound"    -       "7: The lower bound"                                                    double  no
+option "upperBound"    -       "7: The upper bound"                                                    double  no
+
+*/
+
+namespace clitk
+{
+template<class args_info_type>
+class GenericOptimizer : public itk::LightObject
+{
+public:
+  //==============================================
+  typedef GenericOptimizer     Self;
+  typedef itk::LightObject     Superclass;
+  typedef itk::SmartPointer<Self>            Pointer;
+  typedef itk::SmartPointer<const Self>      ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+
+  typedef itk::SingleValuedNonLinearOptimizer OptimizerType;
+  typedef OptimizerType::Pointer OptimizerPointer;
+
+  //==============================================
+  //Set members
+  void SetArgsInfo(args_info_type args_info) {
+    m_ArgsInfo= args_info;
+    m_Verbose=m_ArgsInfo.verbose_flag;
+  }
+  void SetMaximize(bool f) {
+    m_Maximize=f;
+    m_MaximizeGiven=true;
+  }
+
+  void SetNumberOfParameters(unsigned int n) {
+    m_NumberOfParameters=n;
+  }
+
+  //==============================================
+  //Get members
+  OptimizerPointer GetOptimizerPointer(void) {
+
+    if (!m_MaximizeGiven)std::cerr<<"Warning: Maximize/Minimize was not given to the optimizer!!"<<std::endl;
+    else if(m_Verbose) {
+      if (m_Maximize)  std::cout<<"Maximizing similarity measure..."<<std::endl;
+      else std::cout<<"Minimizing similarity measure..."<<std::endl;
+    }
+
+
+    //============================================================================
+    //switch on  the  metric type chosen and set metric specific members
+    switch (m_ArgsInfo.optimizer_arg) {
+
+    case 0: {
+      itk::AmoebaOptimizer::Pointer m =
+        itk::AmoebaOptimizer::New();
+      m_OptimizerIsVNL=true;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      if (m_ArgsInfo.delta_given) {
+        itk::Array<double> delta(m_NumberOfParameters);
+        for (unsigned int i =0 ; i < m_NumberOfParameters; i ++)
+          delta[i]=m_ArgsInfo.delta_arg;
+        m->SetInitialSimplexDelta(delta);
+        m->SetAutomaticInitialSimplex(false);
+      } else m->SetAutomaticInitialSimplex(true);
+      m->SetMaximumNumberOfIterations(m_ArgsInfo.maxIt_arg);
+      m->SetFunctionConvergenceTolerance(m_ArgsInfo.valueTol_arg);
+      m->SetParametersConvergenceTolerance(m_ArgsInfo.stepTol_arg);
+      if (m_Verbose) std::cout<<"Using Simplex Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 1: {
+      itk::PowellOptimizer::Pointer m =
+        itk::PowellOptimizer::New();
+      m_OptimizerIsVNL=false;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      m->SetStepLength(m_ArgsInfo.step_arg);
+      m->SetStepTolerance(m_ArgsInfo.stepTol_arg);
+      m->SetValueTolerance (m_ArgsInfo.valueTol_arg);
+      m->SetMaximumIteration(m_ArgsInfo.maxIt_arg);
+      m->SetMaximumLineIteration(m_ArgsInfo.maxLineIt_arg);
+      if (m_Verbose) std::cout<<"Using Powell Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 2: {
+      itk::FRPROptimizer::Pointer m =
+        itk::FRPROptimizer::New();
+      m_OptimizerIsVNL=false;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      m->SetStepLength(m_ArgsInfo.step_arg);
+      m->SetStepTolerance(m_ArgsInfo.stepTol_arg);
+      m->SetValueTolerance (m_ArgsInfo.valueTol_arg);
+      m->SetMaximumIteration(m_ArgsInfo.maxIt_arg);
+      m->SetMaximumLineIteration(m_ArgsInfo.maxLineIt_arg);
+      if (m_Verbose) std::cout<<"Using Powell Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 3: {
+      itk::RegularStepGradientDescentOptimizer::Pointer m =
+        itk::RegularStepGradientDescentOptimizer::New();
+      m_OptimizerIsVNL=false;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      m->SetMinimumStepLength( m_ArgsInfo.stepTol_arg );
+      m->SetRelaxationFactor(  m_ArgsInfo.relax_arg );
+      m->SetMaximumStepLength( m_ArgsInfo.step_arg );
+      m->SetNumberOfIterations(m_ArgsInfo.maxIt_arg  );
+      m->SetGradientMagnitudeTolerance(m_ArgsInfo.gradTol_arg  );
+      if (m_Verbose) std::cout<<"Using Regular Step Gradient Descent Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 4: {
+      itk::VersorRigid3DTransformOptimizer::Pointer m
+      = itk::VersorRigid3DTransformOptimizer::New();
+      m_OptimizerIsVNL=false;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      m->SetMinimumStepLength( m_ArgsInfo.stepTol_arg );
+      m->SetRelaxationFactor(  m_ArgsInfo.relax_arg );
+      m->SetMaximumStepLength( m_ArgsInfo.step_arg );
+      m->SetNumberOfIterations(m_ArgsInfo.maxIt_arg  );
+      m->SetGradientMagnitudeTolerance(m_ArgsInfo.gradTol_arg  );
+      if (m_Verbose) std::cout<<"Using VersorRigid3DTransform Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 5: {
+
+      itk::ConjugateGradientOptimizer::Pointer m
+      = itk::ConjugateGradientOptimizer::New();
+      m_OptimizerIsVNL=true;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      if (m_Verbose) std::cout<<"Using Conjugated Gradient Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 6: {
+      itk::LBFGSOptimizer::Pointer m
+      = itk::LBFGSOptimizer::New();
+      m_OptimizerIsVNL=true;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      m->SetGradientConvergenceTolerance(m_ArgsInfo.gradTol_arg);
+      m->SetLineSearchAccuracy(m_ArgsInfo.lineAcc_arg);
+      m->SetMaximumNumberOfFunctionEvaluations(m_ArgsInfo.maxEval_arg);
+      m->SetTrace(true);
+      if (m_Verbose) std::cout<<"Using L-BFGS Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    case 7: {
+      LBFGSBOptimizer::Pointer m
+      = LBFGSBOptimizer::New();
+      m_OptimizerIsVNL=true;
+
+      //Set Parameters for this optimizer
+      m->SetMaximize(m_Maximize);
+      m->SetMaximumNumberOfEvaluations(m_ArgsInfo.maxEval_arg);
+      m->SetMaximumNumberOfIterations(m_ArgsInfo.maxIt_arg);
+      m->SetMaximumNumberOfCorrections(m_ArgsInfo.maxCorr_arg);
+      m->SetCostFunctionConvergenceFactor( m_ArgsInfo.convFactor_arg);
+      m->SetProjectedGradientTolerance( m_ArgsInfo.gradTol_arg);
+
+      // Bounds
+      clitk::LBFGSBOptimizer::BoundSelectionType boundSelect( m_NumberOfParameters );
+      clitk::LBFGSBOptimizer::BoundValueType upperBound( m_NumberOfParameters );
+      clitk::LBFGSBOptimizer::BoundValueType lowerBound( m_NumberOfParameters );
+      boundSelect.Fill( m_ArgsInfo.selectBound_arg );
+      upperBound.Fill( m_ArgsInfo.upperBound_arg );
+      lowerBound.Fill( m_ArgsInfo.lowerBound_arg );
+      m->SetBoundSelection( boundSelect );
+      m->SetUpperBound( upperBound );
+      m->SetLowerBound( lowerBound );
+
+      if (m_Verbose) std::cout<<"Using L-BFGS-B Optimizer..."<<std::endl;
+      m_Optimizer=m;
+      break;
+    }
+
+    //     case 8:
+    //       {
+    //         itk::SPSAOptimizer::Pointer m =
+    //           itk::SPSAOptimizerr::Pointer::New();
+    //      m_OptimizerIsVNL=false;
+
+    //         //Set Parameters for this optimizer
+    //         m->SetMaximize(m_Maximize);
+    //         m->SetGamma(m_ArgsInfo.gamma_arg);
+    //         m->SetAlpha(m_ArgsInfo.gamma_arg);
+    //         m->SetA(m_ArgsInfo.bigA_arg);
+    //         m->Seta(m_ArgsInfo.littleA_arg);
+    //         m->Setc(m_ArgsInfo.littleC_arg);
+    //         m->SetMaximumNumberOfIterations(m_ArgsInfo.maxIt_arg);
+    //         m->SetMinimumNumberOfIterations(m_ArgsInfo.minIt_arg);
+    //         m->SetNumberOfPerturbations(m_ArgsInfo.per_arg);
+    //         m->SetStateOfConvergenceDecayRate(args_inf.conv_arg);
+    //         if (m_Verbose) std::cout<<"Using SPSA Optimizer..."<<std::endl;
+    //         m_Optimizer=m;
+    //         break;
+    //       }
+
+    }
+
+
+    //============================================================================
+    //return the pointer
+    return m_Optimizer;
+  }
+
+
+  void OutputIterationInfo(void) const {
+    switch (m_ArgsInfo.optimizer_arg) {
+    case 0: {
+      itk::AmoebaOptimizer* o=dynamic_cast<itk::AmoebaOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      //if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCachedCurrentPosition()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetCachedValue()<<std::endl;
+      // if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetCachedDerivative()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 1: {
+      itk::PowellOptimizer* o=dynamic_cast<itk::PowellOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputIteration)  std::cout<<"Line Iteration: "<< o->GetCurrentLineIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCurrentPosition()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetCurrentCost()<<std::endl;
+      //if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetDerivative()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 2: {
+      itk::FRPROptimizer* o=dynamic_cast<itk::FRPROptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputIteration)  std::cout<<"Line Iteration: "<< o->GetCurrentLineIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCurrentPosition()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetCurrentCost()<<std::endl;
+      //if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetDerivative()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 3: {
+      itk::RegularStepGradientDescentOptimizer* o=dynamic_cast<itk::RegularStepGradientDescentOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCurrentPosition()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Step length: "<< o->GetCurrentStepLength()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetValue()<<std::endl;
+      if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetGradient()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 4: {
+      itk::VersorRigid3DTransformOptimizer* o=dynamic_cast<itk::VersorRigid3DTransformOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCurrentPosition()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Step length: "<< o->GetCurrentStepLength()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetValue()<<std::endl;
+      if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetGradient()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 5: {
+      itk::ConjugateGradientOptimizer* o=dynamic_cast<itk::ConjugateGradientOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCachedCurrentPosition()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetCachedValue()<<std::endl;
+      if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetCachedDerivative()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 6: {
+      itk::LBFGSOptimizer* o=dynamic_cast<itk::LBFGSOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      //if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCachedCurrentPosition()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetCachedValue()<<std::endl;
+      //         if (m_OutputValue)  std::cout<<"Norm Projected Gradient: "<< o->GetInfinityNormOfProjectedGradient()<<std::endl;
+      if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetCachedDerivative()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    case 7: {
+      clitk::LBFGSBOptimizer* o=dynamic_cast<clitk::LBFGSBOptimizer*>(m_Optimizer.GetPointer());
+      std::cout<<std::setprecision(6);
+      if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetCurrentIteration()<<std::endl;
+      if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCachedCurrentPosition()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Value: "<< o->GetValue()<<std::endl;
+      if (m_OutputValue)  std::cout<<"Norm Projected Gradient:"<< o->GetInfinityNormOfProjectedGradient()<<std::endl;
+      if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetCachedDerivative()<<std::endl;
+      std::cout<<std::endl;
+      break;
+    }
+    //       case 8:
+    //         {
+    //           itk::VersorRigid3DTransformOptimizer* o=dynamic_cast<itk::VersorRigid3DTransformOptimizer*>(m_Optimizer.GetPointer());
+    //           std::cout<<std::setprecision(6);
+    //           if (m_OutputIteration)  std::cout<<"Iteration: "<< o->GetIteration()<<std::endl;
+    //           if (m_OutputPosition)  std::cout<<"Position: "<< o->GetCurrentPosition()<<std::endl;
+    //           if (m_OutputValue)  std::cout<<"Value: "<< o->GetCurrentCost()<<std::endl;
+    //           if (m_OutputGradient)  std::cout<<"Gradient: "<< o->GetDerivative()<<std::endl;
+    //           std::cout<<std::endl;
+    //         }
+    }
+  }
+
+  void SetOutputIteration(bool o) {
+    m_OutputIteration=o;
+  }
+  void SetOutputPosition(bool o) {
+    m_OutputPosition=o;
+  }
+  void SetOutputValue(bool o) {
+    m_OutputValue=o;
+  }
+  void SetOutputGradient(bool o) {
+    m_OutputGradient=o;
+  }
+
+
+  //==============================================
+protected:
+  GenericOptimizer() {
+    m_Optimizer=NULL;
+    m_Maximize=false;
+    m_Verbose=false;
+    m_MaximizeGiven=false;
+    m_NumberOfParameters=1;
+    m_OptimizerIsVNL=false;
+    m_OutputIteration=true;
+    m_OutputPosition=false;
+    m_OutputValue=true;
+    m_OutputGradient=false;
+
+  }
+  ~GenericOptimizer() {};
+
+private:
+  args_info_type m_ArgsInfo;
+  OptimizerPointer m_Optimizer;
+  bool m_Maximize;
+  bool m_Verbose;
+  bool m_MaximizeGiven;
+  unsigned int m_NumberOfParameters;
+  bool m_OptimizerIsVNL;
+  bool m_OutputIteration;
+  bool m_OutputPosition;
+  bool m_OutputValue;
+  bool m_OutputGradient;
+};
+
+} // end namespace clitk
+
+#endif // #define __clitkGenericOptimizer_h
diff --git a/registration/clitkLBFGSBOptimizer.cxx b/registration/clitkLBFGSBOptimizer.cxx
new file mode 100644 (file)
index 0000000..8767eae
--- /dev/null
@@ -0,0 +1,453 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: clitkLBFGSBOptimizer.cxx,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:06 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __clitkLBFGSBOptimizer_cxx
+#define __clitkLBFGSBOptimizer_cxx
+
+#include "clitkLBFGSBOptimizer.h"
+#include "vnl/algo/vnl_lbfgsb.h"
+#include <vnl/vnl_math.h>
+
+
+namespace clitk
+{
+
+
+/** \class LBFGSBOptimizerHelper
+ * \brief Wrapper helper around vnl_lbfgsb.
+ *
+ * This class is used to translate iteration events, etc, from
+ * vnl_lbfgsb into iteration events in ITK.
+ */
+class ITK_EXPORT LBFGSBOptimizerHelper :
+  public vnl_lbfgsb
+{
+public:
+  typedef LBFGSBOptimizerHelper               Self;
+  typedef vnl_lbfgsb                          Superclass;
+
+  /** Create with a reference to the ITK object */
+  LBFGSBOptimizerHelper( vnl_cost_function& f,
+                         LBFGSBOptimizer* itkObj );
+
+  /** Handle new iteration event */
+  virtual bool report_iter();
+
+private:
+  LBFGSBOptimizer* m_ItkObj;
+};
+
+
+
+
+/**
+ * Constructor
+ */
+LBFGSBOptimizer
+::LBFGSBOptimizer()
+{
+  m_OptimizerInitialized = false;
+  m_VnlOptimizer         = 0;
+
+  m_LowerBound       = InternalBoundValueType(0);
+  m_UpperBound       = InternalBoundValueType(0);
+  m_BoundSelection   = InternalBoundSelectionType(0);
+
+  m_CostFunctionConvergenceFactor   = 1e+7;
+  m_ProjectedGradientTolerance      = 1e-5;
+  m_MaximumNumberOfIterations       = 500;
+  m_MaximumNumberOfEvaluations      = 500;
+  m_MaximumNumberOfCorrections      = 5;
+  m_CurrentIteration                = 0;
+  m_Value                           = 0.0;
+  m_InfinityNormOfProjectedGradient = 0.0;
+
+}
+
+
+/**
+ * Destructor
+ */
+LBFGSBOptimizer
+::~LBFGSBOptimizer()
+{
+  delete m_VnlOptimizer;
+}
+
+/**
+ * PrintSelf
+ */
+void
+LBFGSBOptimizer
+::PrintSelf( std::ostream& os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+
+  os << indent << "LowerBound: " << m_LowerBound << std::endl;
+  os << indent << "UpperBound: " << m_UpperBound << std::endl;
+  os << indent << "BoundSelection: " << m_BoundSelection << std::endl;
+
+  os << indent << "CostFunctionConvergenceFactor: " <<
+     m_CostFunctionConvergenceFactor << std::endl;
+
+  os << indent << "ProjectedGradientTolerance: " <<
+     m_ProjectedGradientTolerance << std::endl;
+
+  os << indent << "MaximumNumberOfIterations: " <<
+     m_MaximumNumberOfIterations << std::endl;
+
+  os << indent << "MaximumNumberOfEvaluations: " <<
+     m_MaximumNumberOfEvaluations << std::endl;
+
+  os << indent << "MaximumNumberOfCorrections: " <<
+     m_MaximumNumberOfCorrections << std::endl;
+
+  os << indent << "CurrentIteration: " <<
+     m_CurrentIteration << std::endl;
+
+  os << indent << "Value: " <<
+     m_Value << std::endl;
+
+  os << indent << "InfinityNormOfProjectedGradient: " <<
+     m_InfinityNormOfProjectedGradient << std::endl;
+
+  if( this->m_VnlOptimizer ) {
+    os << indent << "Vnl LBFGSB Failure Code: " <<
+       this->m_VnlOptimizer->get_failure_code() << std::endl;
+  }
+}
+
+/**
+ * Set lower bound
+ */
+void
+LBFGSBOptimizer
+::SetLowerBound(
+  const BoundValueType& value )
+{
+  m_LowerBound = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_lower_bound( m_LowerBound );
+  }
+
+  this->Modified();
+}
+
+/**
+ * Get lower bound
+ */
+const
+LBFGSBOptimizer
+::BoundValueType &
+LBFGSBOptimizer
+::GetLowerBound()
+{
+  return m_LowerBound;
+}
+
+/**
+ * Set upper bound
+ */
+void
+LBFGSBOptimizer
+::SetUpperBound(
+  const BoundValueType& value )
+{
+  m_UpperBound = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_upper_bound( m_UpperBound );
+  }
+
+  this->Modified();
+}
+
+/**
+ * Get upper bound
+ */
+const
+LBFGSBOptimizer
+::BoundValueType &
+LBFGSBOptimizer
+::GetUpperBound()
+{
+  return m_UpperBound;
+}
+
+
+/**
+ * Set bound selection array
+ */
+void
+LBFGSBOptimizer
+::SetBoundSelection(
+  const BoundSelectionType& value )
+{
+  m_BoundSelection = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_bound_selection( m_BoundSelection );
+  }
+  this->Modified();
+}
+
+/**
+ * Get bound selection array
+ */
+const
+LBFGSBOptimizer
+::BoundSelectionType &
+LBFGSBOptimizer
+::GetBoundSelection()
+{
+  return m_BoundSelection;
+}
+
+
+/** Set/Get the CostFunctionConvergenceFactor. Algorithm terminates
+ * when the reduction in cost function is less than factor * epsmcj
+ * where epsmch is the machine precision.
+ * Typical values for factor: 1e+12 for low accuracy;
+ * 1e+7 for moderate accuracy and 1e+1 for extremely high accuracy.
+ */
+void
+LBFGSBOptimizer
+::SetCostFunctionConvergenceFactor( double value )
+{
+  if( value < 1.0 ) {
+    itkExceptionMacro("Value " << value
+                      << " is too small for SetCostFunctionConvergenceFactor()"
+                      << "a typical range would be from 1.0 to 1e+12");
+  }
+  m_CostFunctionConvergenceFactor = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_cost_function_convergence_factor(
+      m_CostFunctionConvergenceFactor );
+  }
+  this->Modified();
+}
+
+
+/** Set/Get the ProjectedGradientTolerance. Algorithm terminates
+ * when the project gradient is below the tolerance. Default value
+ * is 1e-5.
+ */
+void
+LBFGSBOptimizer
+::SetProjectedGradientTolerance( double value )
+{
+  m_ProjectedGradientTolerance = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_projected_gradient_tolerance(
+      m_ProjectedGradientTolerance );
+  }
+  this->Modified();
+}
+
+
+/** Set/Get the MaximumNumberOfIterations. Default is 500 */
+void
+LBFGSBOptimizer
+::SetMaximumNumberOfIterations( unsigned int value )
+{
+  m_MaximumNumberOfIterations = value;
+  this->Modified();
+}
+
+
+/** Set/Get the MaximumNumberOfEvaluations. Default is 500 */
+void
+LBFGSBOptimizer
+::SetMaximumNumberOfEvaluations( unsigned int value )
+{
+  m_MaximumNumberOfEvaluations = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_max_function_evals( m_MaximumNumberOfEvaluations );
+  }
+  this->Modified();
+}
+
+
+/** Set/Get the MaximumNumberOfCorrections. Default is 5 */
+void
+LBFGSBOptimizer
+::SetMaximumNumberOfCorrections( unsigned int value )
+{
+  m_MaximumNumberOfCorrections = value;
+  if( m_OptimizerInitialized ) {
+    m_VnlOptimizer->set_max_variable_metric_corrections(
+      m_MaximumNumberOfCorrections );
+  }
+  this->Modified();
+}
+
+
+/**
+ * Connect a Cost Function
+ */
+void
+LBFGSBOptimizer::
+SetCostFunction( itk::SingleValuedCostFunction * costFunction )
+{
+  m_CostFunction = costFunction;
+
+  const unsigned int numberOfParameters =
+    costFunction->GetNumberOfParameters();
+
+  CostFunctionAdaptorType * adaptor =
+    new CostFunctionAdaptorType( numberOfParameters );
+
+  adaptor->SetCostFunction( costFunction );
+
+  if( m_OptimizerInitialized ) {
+    delete m_VnlOptimizer;
+  }
+
+  this->SetCostFunctionAdaptor( adaptor );
+
+  m_VnlOptimizer = new InternalOptimizerType( *adaptor, this );
+
+  // set the optimizer parameters
+  m_VnlOptimizer->set_lower_bound( m_LowerBound );
+  m_VnlOptimizer->set_upper_bound( m_UpperBound );
+  m_VnlOptimizer->set_bound_selection( m_BoundSelection );
+  m_VnlOptimizer->set_cost_function_convergence_factor(
+    m_CostFunctionConvergenceFactor );
+  m_VnlOptimizer->set_projected_gradient_tolerance(
+    m_ProjectedGradientTolerance );
+  m_VnlOptimizer->set_max_function_evals( m_MaximumNumberOfEvaluations );
+  m_VnlOptimizer->set_max_variable_metric_corrections(
+    m_MaximumNumberOfCorrections );
+
+  m_OptimizerInitialized = true;
+
+  this->Modified();
+}
+
+
+/**
+ * Start the optimization
+ */
+void
+LBFGSBOptimizer
+::StartOptimization( void )
+{
+
+  // Check if all the bounds parameters are the same size as the initial parameters.
+  unsigned int numberOfParameters = m_CostFunction->GetNumberOfParameters();
+
+  if ( this->GetInitialPosition().Size() < numberOfParameters ) {
+    itkExceptionMacro( << "InitialPosition array does not have sufficient number of elements" );
+  }
+
+  if ( m_LowerBound.size() < numberOfParameters ) {
+    itkExceptionMacro( << "LowerBound array does not have sufficient number of elements" );
+  }
+
+  if ( m_UpperBound.size() < numberOfParameters ) {
+    itkExceptionMacro( << "UppperBound array does not have sufficient number of elements" );
+  }
+
+  if ( m_BoundSelection.size() < numberOfParameters ) {
+    itkExceptionMacro( << "BoundSelection array does not have sufficient number of elements" );
+  }
+
+  if( this->GetMaximize() ) {
+    this->GetNonConstCostFunctionAdaptor()->NegateCostFunctionOn();
+  }
+
+  this->SetCurrentPosition( this->GetInitialPosition() );
+
+  ParametersType parameters( this->GetInitialPosition() );
+
+  // vnl optimizers return the solution by reference
+  // in the variable provided as initial position
+  m_VnlOptimizer->minimize( parameters );
+
+  if ( parameters.size() != this->GetInitialPosition().Size() ) {
+    // set current position to initial position and throw an exception
+    this->SetCurrentPosition( this->GetInitialPosition() );
+    itkExceptionMacro( << "Error occured in optimization" );
+  }
+
+  this->SetCurrentPosition( parameters );
+
+  this->InvokeEvent( itk::EndEvent() );
+
+}
+
+
+/*-------------------------------------------------------------------------
+ * helper class
+ *-------------------------------------------------------------------------
+ */
+
+/** Create with a reference to the ITK object */
+LBFGSBOptimizerHelper
+::LBFGSBOptimizerHelper( vnl_cost_function& f,
+                         LBFGSBOptimizer* itkObj )
+  : vnl_lbfgsb( f ),
+    m_ItkObj( itkObj )
+{
+}
+
+
+/** Handle new iteration event */
+bool
+LBFGSBOptimizerHelper
+::report_iter()
+{
+  Superclass::report_iter();
+
+  m_ItkObj->m_InfinityNormOfProjectedGradient =
+    this->get_inf_norm_projected_gradient();
+
+  m_ItkObj->InvokeEvent( itk::IterationEvent() );
+
+  m_ItkObj->m_CurrentIteration = this->num_iterations_;
+
+  //JV
+  m_ItkObj->m_Value = m_ItkObj->GetCachedValue();
+
+
+  // Return true to terminate the optimization loop.
+  if( this->num_iterations_ > m_ItkObj->m_MaximumNumberOfIterations ) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+
+} // end namespace clitk
+
+#endif
diff --git a/registration/clitkLBFGSBOptimizer.h b/registration/clitkLBFGSBOptimizer.h
new file mode 100644 (file)
index 0000000..5485b76
--- /dev/null
@@ -0,0 +1,215 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: clitkLBFGSBOptimizer.h,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __clitkLBFGSBOptimizer_h
+#define __clitkLBFGSBOptimizer_h
+
+#include "itkSingleValuedNonLinearVnlOptimizer.h"
+
+namespace clitk
+{
+
+/** \class LBFGSBOptimizerHelper
+ * \brief Wrapper helper around vnl_lbfgsb.
+ *
+ * This class is used to translate iteration events, etc, from
+ * vnl_lbfgsb into iteration events in ITK.
+ */
+class ITK_EXPORT LBFGSBOptimizerHelper;
+
+
+/** \class LBFGSBOptimizer
+ * \brief Limited memory Broyden Fletcher Goldfarb Shannon minimization with simple bounds.
+ *
+ * This class is a wrapper for converted fortan code for performing limited
+ * memory Broyden Fletcher Goldfarb Shannon minimization with simple bounds.
+ * The algorithm miminizes a nonlinear function f(x) of n variables subject to
+ * simple bound constraints of l <= x <= u.
+ *
+ * See also the documentation in Numerics/lbfgsb.c
+ *
+ * References:
+ *
+ * [1] R. H. Byrd, P. Lu and J. Nocedal.
+ * A Limited Memory Algorithm for Bound Constrained Optimization, (1995),
+ * SIAM Journal on Scientific and Statistical Computing ,
+ * 16, 5, pp. 1190-1208.
+ *
+ * [2] C. Zhu, R. H. Byrd and J. Nocedal.
+ * L-BFGS-B: Algorithm 778: L-BFGS-B, FORTRAN routines for large scale
+ * bound constrained optimization (1997),
+ * ACM Transactions on Mathematical Software,
+ * Vol 23, Num. 4, pp. 550 - 560.
+ *
+ * \ingroup Numerics Optimizers
+ */
+class ITK_EXPORT LBFGSBOptimizer :
+  public itk::SingleValuedNonLinearVnlOptimizer
+{
+public:
+  /** Standard "Self" typedef. */
+  typedef LBFGSBOptimizer                     Self;
+  typedef itk::SingleValuedNonLinearVnlOptimizer   Superclass;
+  typedef itk::SmartPointer<Self>                  Pointer;
+  typedef itk::SmartPointer<const Self>            ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro( LBFGSBOptimizer, SingleValuedNonLinearVnlOptimizer );
+
+  /**  BoundValue type.
+   *  Use for defining the lower and upper bounds on the variables.
+   */
+  typedef itk::Array<double>             BoundValueType;
+
+  /** BoundSelection type
+   * Use for defining the boundary condition for each variables.
+   */
+  typedef itk::Array<long>                BoundSelectionType;
+
+  /** Internal boundary value storage type */
+  typedef vnl_vector<double>    InternalBoundValueType;
+
+  /** Internal boundary selection storage type */
+  typedef vnl_vector<long>      InternalBoundSelectionType;
+
+  /** The vnl optimizer */
+  typedef LBFGSBOptimizerHelper InternalOptimizerType;
+
+
+  /** Start optimization with an initial value. */
+  void StartOptimization( void );
+
+  /** Plug in a Cost Function into the optimizer  */
+  virtual void SetCostFunction( itk::SingleValuedCostFunction * costFunction );
+
+  /** Set the lower bound value for each variable. */
+  virtual void SetLowerBound( const BoundValueType & value );
+  virtual const BoundValueType & GetLowerBound();
+
+  /** Set the upper bound value for each variable. */
+  virtual void SetUpperBound( const BoundValueType & value );
+  virtual const BoundValueType & GetUpperBound();
+
+  /** Set the boundary condition for each variable, where
+   * select[i] = 0 if x[i] is unbounded,
+   *           = 1 if x[i] has only a lower bound,
+   *           = 2 if x[i] has both lower and upper bounds, and
+   *           = 3 if x[1] has only an upper bound
+   */
+  virtual void SetBoundSelection( const BoundSelectionType & select );
+  virtual const BoundSelectionType & GetBoundSelection();
+
+  /** Set/Get the CostFunctionConvergenceFactor. Algorithm terminates
+   * when the reduction in cost function is less than factor * epsmcj
+   * where epsmch is the machine precision.
+   * Typical values for factor: 1e+12 for low accuracy;
+   * 1e+7 for moderate accuracy and 1e+1 for extremely high accuracy.
+   */
+  virtual void SetCostFunctionConvergenceFactor( double );
+  itkGetMacro( CostFunctionConvergenceFactor, double );
+
+  /** Set/Get the ProjectedGradientTolerance. Algorithm terminates
+   * when the project gradient is below the tolerance. Default value
+   * is 1e-5.
+   */
+  virtual void SetProjectedGradientTolerance( double );
+  itkGetMacro( ProjectedGradientTolerance, double );
+
+  /** Set/Get the MaximumNumberOfIterations. Default is 500 */
+  virtual void SetMaximumNumberOfIterations( unsigned int );
+  itkGetMacro( MaximumNumberOfIterations, unsigned int );
+
+  /** Set/Get the MaximumNumberOfEvaluations. Default is 500 */
+  virtual void SetMaximumNumberOfEvaluations( unsigned int );
+  itkGetMacro( MaximumNumberOfEvaluations, unsigned int );
+
+  /** Set/Get the MaximumNumberOfCorrections. Default is 5 */
+  virtual void SetMaximumNumberOfCorrections( unsigned int );
+  itkGetMacro( MaximumNumberOfCorrections, unsigned int );
+
+  /** This optimizer does not support scaling of the derivatives. */
+  void SetScales( const ScalesType & ) {
+    itkExceptionMacro( << "This optimizer does not support scales." );
+  }
+
+  /** Get the current iteration number. */
+  itkGetConstReferenceMacro( CurrentIteration, unsigned int );
+
+  /** Get the current cost function value. */
+  itkGetConstReferenceMacro( Value, MeasureType );
+
+  /** Get the current infinity norm of the project gradient of the cost
+   * function. */
+  itkGetConstReferenceMacro( InfinityNormOfProjectedGradient, double );
+
+protected:
+  LBFGSBOptimizer();
+  virtual ~LBFGSBOptimizer();
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+  typedef Superclass::CostFunctionAdaptorType   CostFunctionAdaptorType;
+
+private:
+  LBFGSBOptimizer(const Self&); //purposely not implemented
+  void operator=(const Self&); //purposely not implemented
+
+  // give the helper access to member variables, to update iteration
+  // counts, etc.
+  friend class LBFGSBOptimizerHelper;
+
+  bool                     m_OptimizerInitialized;
+  InternalOptimizerType  * m_VnlOptimizer;
+
+  BoundValueType           m_LowerBound;
+  BoundValueType           m_UpperBound;
+  BoundSelectionType       m_BoundSelection;
+
+  double                   m_CostFunctionConvergenceFactor;
+  double                   m_ProjectedGradientTolerance;
+  unsigned int             m_MaximumNumberOfIterations;
+  unsigned int             m_MaximumNumberOfEvaluations;
+  unsigned int             m_MaximumNumberOfCorrections;
+
+  unsigned int             m_CurrentIteration;
+  MeasureType              m_Value;
+  double                   m_InfinityNormOfProjectedGradient;
+
+};
+
+} // end namespace clitk
+
+#endif
diff --git a/registration/clitkNormalizedCorrelationImageToImageMetric.h b/registration/clitkNormalizedCorrelationImageToImageMetric.h
new file mode 100644 (file)
index 0000000..1ef894f
--- /dev/null
@@ -0,0 +1,119 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef _clitkNormalizedCorrelationImageToImageMetric_h
+#define _clitkNormalizedCorrelationImageToImageMetric_h
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "clitkOptNormalizedCorrelationImageToImageMetric.h"
+#else
+
+#include "itkImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+
+
+namespace clitk
+{
+
+template < class TFixedImage, class TMovingImage >
+class ITK_EXPORT NormalizedCorrelationImageToImageMetric :
+  public itk::ImageToImageMetric< TFixedImage, TMovingImage>
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef NormalizedCorrelationImageToImageMetric    Self;
+  typedef itk::ImageToImageMetric<TFixedImage, TMovingImage >  Superclass;
+
+  typedef itk::SmartPointer<Self>         Pointer;
+  typedef itk::SmartPointer<const Self>   ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(NormalizedCorrelationImageToImageMetric, itk::Object);
+
+
+  /** Types transferred from the base class */
+  typedef typename Superclass::RealType                 RealType;
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformParametersType  TransformParametersType;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::GradientPixelType        GradientPixelType;
+  typedef typename Superclass::OutputPointType          OutputPointType;
+  typedef typename Superclass::InputPointType           InputPointType;
+
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const TransformParametersType & parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value for single valued optimizers. */
+  MeasureType GetValue( const TransformParametersType & parameters ) const;
+
+  /**  Get value and derivatives for multiple valued optimizers. */
+  void GetValueAndDerivative( const TransformParametersType & parameters,
+                              MeasureType& Value, DerivativeType& Derivative ) const;
+
+  /** Set/Get SubtractMean boolean. If true, the sample mean is subtracted
+   * from the sample values in the cross-correlation formula and
+   * typically results in narrower valleys in the cost fucntion.
+   * Default value is false. */
+  itkSetMacro( SubtractMean, bool );
+  itkGetConstReferenceMacro( SubtractMean, bool );
+  itkBooleanMacro( SubtractMean );
+
+protected:
+  NormalizedCorrelationImageToImageMetric();
+  virtual ~NormalizedCorrelationImageToImageMetric() {};
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+private:
+  NormalizedCorrelationImageToImageMetric(const Self&); //purposely not implemented
+  void operator=(const Self&); //purposely not implemented
+
+  bool    m_SubtractMean;
+
+};
+
+} // end namespace clitk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkNormalizedCorrelationImageToImageMetric.txx"
+#endif
+
+#endif // opt
+
+#endif // _clitkNormalizedCorrelationImageToImageMetric.txx
+
+
diff --git a/registration/clitkNormalizedCorrelationImageToImageMetric.txx b/registration/clitkNormalizedCorrelationImageToImageMetric.txx
new file mode 100644 (file)
index 0000000..db21bbe
--- /dev/null
@@ -0,0 +1,505 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef _clitkNormalizedCorrelationImageToImageMetric_txx
+#define _clitkNormalizedCorrelationImageToImageMetric_txx
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "clitkOptNormalizedCorrelationImageToImageMetric.txx"
+#else
+
+
+#include "clitkNormalizedCorrelationImageToImageMetric.h"
+
+#include "itkImageRegionConstIteratorWithIndex.h"
+
+
+namespace clitk
+{
+
+/*
+ * Constructor
+ */
+template <class TFixedImage, class TMovingImage>
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::NormalizedCorrelationImageToImageMetric()
+{
+  m_SubtractMean = false;
+}
+
+/*
+ * Get the match Measure
+ */
+template <class TFixedImage, class TMovingImage>
+typename NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>::MeasureType
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetValue( const TransformParametersType & parameters ) const
+{
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  MeasureType measure;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  AccumulateType sff = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType smm = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sfm = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sf  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sm  = itk::NumericTraits< AccumulateType >::Zero;
+
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      sff += fixedValue  * fixedValue;
+      smm += movingValue * movingValue;
+      sfm += fixedValue  * movingValue;
+      if ( this->m_SubtractMean ) {
+        sf += fixedValue;
+        sm += movingValue;
+      }
+      this->m_NumberOfPixelsCounted++;
+    }
+
+    ++ti;
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    measure = sfm / denom;
+  } else {
+    measure = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+  return measure;
+
+}
+
+
+
+
+
+/*
+ * Get the Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetDerivative( const TransformParametersType & parameters,
+                 DerivativeType & derivative ) const
+{
+
+  if( !this->GetGradientImage() ) {
+    itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
+  }
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  const unsigned int dimension = FixedImageType::ImageDimension;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  AccumulateType sff  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType smm  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sfm = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sf  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sm  = itk::NumericTraits< AccumulateType >::Zero;
+
+  const unsigned int ParametersDimension = this->GetNumberOfParameters();
+  derivative = DerivativeType( ParametersDimension );
+  derivative.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeF = DerivativeType( ParametersDimension );
+  derivativeF.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeM = DerivativeType( ParametersDimension );
+  derivativeM.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  ti.GoToBegin();
+  // First compute the sums
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      sff += fixedValue  * fixedValue;
+      smm += movingValue * movingValue;
+      sfm += fixedValue  * movingValue;
+      if ( this->m_SubtractMean ) {
+        sf += fixedValue;
+        sm += movingValue;
+      }
+      this->m_NumberOfPixelsCounted++;
+    }
+
+    ++ti;
+  }
+
+  // Compute contributions to derivatives
+  ti.GoToBegin();
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if ( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if ( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+
+      const TransformJacobianType & jacobian =
+        this->m_Transform->GetJacobian( inputPoint );
+
+      // Get the gradient by NearestNeighboorInterpolation:
+      // which is equivalent to round up the point components.
+      typedef typename OutputPointType::CoordRepType CoordRepType;
+      typedef itk::ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
+      MovingImageContinuousIndexType;
+
+      MovingImageContinuousIndexType tempIndex;
+      this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
+
+      typename MovingImageType::IndexType mappedIndex;
+      mappedIndex.CopyWithRound( tempIndex );
+
+      const GradientPixelType gradient =
+        this->GetGradientImage()->GetPixel( mappedIndex );
+
+      for(unsigned int par=0; par<ParametersDimension; par++) {
+        RealType sumF = itk::NumericTraits< RealType >::Zero;
+        RealType sumM = itk::NumericTraits< RealType >::Zero;
+        for(unsigned int dim=0; dim<dimension; dim++) {
+          const RealType differential = jacobian( dim, par ) * gradient[dim];
+          sumF += fixedValue  * differential;
+          sumM += movingValue * differential;
+          if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+            sumF -= differential * sf / this->m_NumberOfPixelsCounted;
+            sumM -= differential * sm / this->m_NumberOfPixelsCounted;
+          }
+        }
+        derivativeF[par] += sumF;
+        derivativeM[par] += sumM;
+      }
+    }
+
+    ++ti;
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = ( derivativeF[i] - (sfm/smm)* derivativeM[i] ) / denom;
+    }
+  } else {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = itk::NumericTraits< MeasureType >::Zero;
+    }
+  }
+
+}
+
+
+/*
+ * Get both the match Measure and theDerivative Measure
+ */
+template <class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetValueAndDerivative(const TransformParametersType & parameters,
+                        MeasureType & value, DerivativeType  & derivative) const
+{
+
+
+  if( !this->GetGradientImage() ) {
+    itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
+  }
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  const unsigned int dimension = FixedImageType::ImageDimension;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  AccumulateType sff  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType smm  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sfm  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sf   = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sm   = itk::NumericTraits< AccumulateType >::Zero;
+
+  const unsigned int ParametersDimension = this->GetNumberOfParameters();
+  derivative = DerivativeType( ParametersDimension );
+  derivative.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeF = DerivativeType( ParametersDimension );
+  derivativeF.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeM = DerivativeType( ParametersDimension );
+  derivativeM.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeM1 = DerivativeType( ParametersDimension );
+  derivativeM1.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  ti.GoToBegin();
+  // First compute the sums
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      sff += fixedValue  * fixedValue;
+      smm += movingValue * movingValue;
+      sfm += fixedValue  * movingValue;
+      if ( this->m_SubtractMean ) {
+        sf += fixedValue;
+        sm += movingValue;
+      }
+      this->m_NumberOfPixelsCounted++;
+    }
+
+    ++ti;
+  }
+
+
+  // Compute contributions to derivatives
+  ti.GoToBegin();
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue     = ti.Get();
+
+      const TransformJacobianType & jacobian =
+        this->m_Transform->GetJacobian( inputPoint );
+
+      // Get the gradient by NearestNeighboorInterpolation:
+      // which is equivalent to round up the point components.
+      typedef typename OutputPointType::CoordRepType CoordRepType;
+      typedef itk::ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
+      MovingImageContinuousIndexType;
+
+      MovingImageContinuousIndexType tempIndex;
+      this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
+
+      typename MovingImageType::IndexType mappedIndex;
+      mappedIndex.CopyWithRound( tempIndex );
+
+      const GradientPixelType gradient =
+        this->GetGradientImage()->GetPixel( mappedIndex );
+
+      for(unsigned int par=0; par<ParametersDimension; par++) {
+        RealType sumF = itk::NumericTraits< RealType >::Zero;
+        RealType sumM = itk::NumericTraits< RealType >::Zero;
+        for(unsigned int dim=0; dim<dimension; dim++) {
+          const RealType differential = jacobian( dim, par ) * gradient[dim];
+          sumF += fixedValue  * differential;
+          sumM += movingValue * differential;
+          if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+            sumF -= differential * sf / this->m_NumberOfPixelsCounted;
+            sumM -= differential * sm / this->m_NumberOfPixelsCounted;
+          }
+        }
+        derivativeF[par] += sumF;
+        derivativeM[par] += sumM;
+      }
+    }
+    ++ti;
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = ( derivativeF[i] - (sfm/smm)* derivativeM[i] ) / denom;
+    }
+    value = sfm / denom;
+  } else {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = itk::NumericTraits< MeasureType >::Zero;
+    }
+    value = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+
+
+}
+
+template < class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+  os << indent << "SubtractMean: " << m_SubtractMean << std::endl;
+}
+
+} // end namespace itk
+
+
+#endif // opt
+
+#endif // _clitkNormalizedCorrelationImageToImageMetric.txx
diff --git a/registration/clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h b/registration/clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h
new file mode 100644 (file)
index 0000000..053ad93
--- /dev/null
@@ -0,0 +1,119 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef _clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_h
+#define _clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_h
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h"
+#else
+
+#include "itkImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+
+
+namespace clitk
+{
+
+template < class TFixedImage, class TMovingImage >
+class ITK_EXPORT NormalizedCorrelationImageToImageMetricFor3DBLUTFFD :
+  public itk::ImageToImageMetric< TFixedImage, TMovingImage>
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef NormalizedCorrelationImageToImageMetricFor3DBLUTFFD    Self;
+  typedef itk::ImageToImageMetric<TFixedImage, TMovingImage >  Superclass;
+
+  typedef itk::SmartPointer<Self>         Pointer;
+  typedef itk::SmartPointer<const Self>   ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(NormalizedCorrelationImageToImageMetricFor3DBLUTFFD, itk::Object);
+
+
+  /** Types transferred from the base class */
+  typedef typename Superclass::RealType                 RealType;
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformParametersType  TransformParametersType;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::GradientPixelType        GradientPixelType;
+  typedef typename Superclass::OutputPointType          OutputPointType;
+  typedef typename Superclass::InputPointType           InputPointType;
+
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const TransformParametersType & parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value for single valued optimizers. */
+  MeasureType GetValue( const TransformParametersType & parameters ) const;
+
+  /**  Get value and derivatives for multiple valued optimizers. */
+  void GetValueAndDerivative( const TransformParametersType & parameters,
+                              MeasureType& Value, DerivativeType& Derivative ) const;
+
+  /** Set/Get SubtractMean boolean. If true, the sample mean is subtracted
+   * from the sample values in the cross-correlation formula and
+   * typically results in narrower valleys in the cost fucntion.
+   * Default value is false. */
+  itkSetMacro( SubtractMean, bool );
+  itkGetConstReferenceMacro( SubtractMean, bool );
+  itkBooleanMacro( SubtractMean );
+
+protected:
+  NormalizedCorrelationImageToImageMetricFor3DBLUTFFD();
+  virtual ~NormalizedCorrelationImageToImageMetricFor3DBLUTFFD() {};
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+private:
+  NormalizedCorrelationImageToImageMetricFor3DBLUTFFD(const Self&); //purposely not implemented
+  void operator=(const Self&); //purposely not implemented
+
+  bool    m_SubtractMean;
+
+};
+
+} // end namespace clitk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx"
+#endif
+
+#endif // opt
+
+#endif // _clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx
+
+
diff --git a/registration/clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx b/registration/clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx
new file mode 100644 (file)
index 0000000..5fee9e5
--- /dev/null
@@ -0,0 +1,505 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef _clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_txx
+#define _clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_txx
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx"
+#else
+
+
+#include "clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h"
+
+#include "itkImageRegionConstIteratorWithIndex.h"
+
+
+namespace clitk
+{
+
+/*
+ * Constructor
+ */
+template <class TFixedImage, class TMovingImage>
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::NormalizedCorrelationImageToImageMetricFor3DBLUTFFD()
+{
+  m_SubtractMean = false;
+}
+
+/*
+ * Get the match Measure
+ */
+template <class TFixedImage, class TMovingImage>
+typename NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>::MeasureType
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValue( const TransformParametersType & parameters ) const
+{
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  MeasureType measure;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  AccumulateType sff = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType smm = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sfm = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sf  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sm  = itk::NumericTraits< AccumulateType >::Zero;
+
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      sff += fixedValue  * fixedValue;
+      smm += movingValue * movingValue;
+      sfm += fixedValue  * movingValue;
+      if ( this->m_SubtractMean ) {
+        sf += fixedValue;
+        sm += movingValue;
+      }
+      this->m_NumberOfPixelsCounted++;
+    }
+
+    ++ti;
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    measure = sfm / denom;
+  } else {
+    measure = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+  return measure;
+
+}
+
+
+
+
+
+/*
+ * Get the Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetDerivative( const TransformParametersType & parameters,
+                 DerivativeType & derivative ) const
+{
+
+  if( !this->GetGradientImage() ) {
+    itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
+  }
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  const unsigned int dimension = FixedImageType::ImageDimension;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  AccumulateType sff  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType smm  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sfm = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sf  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sm  = itk::NumericTraits< AccumulateType >::Zero;
+
+  const unsigned int ParametersDimension = this->GetNumberOfParameters();
+  derivative = DerivativeType( ParametersDimension );
+  derivative.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeF = DerivativeType( ParametersDimension );
+  derivativeF.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeM = DerivativeType( ParametersDimension );
+  derivativeM.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  ti.GoToBegin();
+  // First compute the sums
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      sff += fixedValue  * fixedValue;
+      smm += movingValue * movingValue;
+      sfm += fixedValue  * movingValue;
+      if ( this->m_SubtractMean ) {
+        sf += fixedValue;
+        sm += movingValue;
+      }
+      this->m_NumberOfPixelsCounted++;
+    }
+
+    ++ti;
+  }
+
+  // Compute contributions to derivatives
+  ti.GoToBegin();
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if ( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if ( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+
+      const TransformJacobianType & jacobian =
+        this->m_Transform->GetJacobian( inputPoint );
+
+      // Get the gradient by NearestNeighboorInterpolation:
+      // which is equivalent to round up the point components.
+      typedef typename OutputPointType::CoordRepType CoordRepType;
+      typedef itk::ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
+      MovingImageContinuousIndexType;
+
+      MovingImageContinuousIndexType tempIndex;
+      this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
+
+      typename MovingImageType::IndexType mappedIndex;
+      mappedIndex.CopyWithRound( tempIndex );
+
+      const GradientPixelType gradient =
+        this->GetGradientImage()->GetPixel( mappedIndex );
+
+      for(unsigned int par=0; par<ParametersDimension; par++) {
+        RealType sumF = itk::NumericTraits< RealType >::Zero;
+        RealType sumM = itk::NumericTraits< RealType >::Zero;
+        for(unsigned int dim=0; dim<dimension; dim++) {
+          const RealType differential = jacobian( dim, par ) * gradient[dim];
+          sumF += fixedValue  * differential;
+          sumM += movingValue * differential;
+          if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+            sumF -= differential * sf / this->m_NumberOfPixelsCounted;
+            sumM -= differential * sm / this->m_NumberOfPixelsCounted;
+          }
+        }
+        derivativeF[par] += sumF;
+        derivativeM[par] += sumM;
+      }
+    }
+
+    ++ti;
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = ( derivativeF[i] - (sfm/smm)* derivativeM[i] ) / denom;
+    }
+  } else {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = itk::NumericTraits< MeasureType >::Zero;
+    }
+  }
+
+}
+
+
+/*
+ * Get both the match Measure and theDerivative Measure
+ */
+template <class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivative(const TransformParametersType & parameters,
+                        MeasureType & value, DerivativeType  & derivative) const
+{
+
+
+  if( !this->GetGradientImage() ) {
+    itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
+  }
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  const unsigned int dimension = FixedImageType::ImageDimension;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  AccumulateType sff  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType smm  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sfm  = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sf   = itk::NumericTraits< AccumulateType >::Zero;
+  AccumulateType sm   = itk::NumericTraits< AccumulateType >::Zero;
+
+  const unsigned int ParametersDimension = this->GetNumberOfParameters();
+  derivative = DerivativeType( ParametersDimension );
+  derivative.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeF = DerivativeType( ParametersDimension );
+  derivativeF.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeM = DerivativeType( ParametersDimension );
+  derivativeM.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  DerivativeType derivativeM1 = DerivativeType( ParametersDimension );
+  derivativeM1.Fill( itk::NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  ti.GoToBegin();
+  // First compute the sums
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      sff += fixedValue  * fixedValue;
+      smm += movingValue * movingValue;
+      sfm += fixedValue  * movingValue;
+      if ( this->m_SubtractMean ) {
+        sf += fixedValue;
+        sm += movingValue;
+      }
+      this->m_NumberOfPixelsCounted++;
+    }
+
+    ++ti;
+  }
+
+
+  // Compute contributions to derivatives
+  ti.GoToBegin();
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue     = ti.Get();
+
+      const TransformJacobianType & jacobian =
+        this->m_Transform->GetJacobian( inputPoint );
+
+      // Get the gradient by NearestNeighboorInterpolation:
+      // which is equivalent to round up the point components.
+      typedef typename OutputPointType::CoordRepType CoordRepType;
+      typedef itk::ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
+      MovingImageContinuousIndexType;
+
+      MovingImageContinuousIndexType tempIndex;
+      this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
+
+      typename MovingImageType::IndexType mappedIndex;
+      mappedIndex.CopyWithRound( tempIndex );
+
+      const GradientPixelType gradient =
+        this->GetGradientImage()->GetPixel( mappedIndex );
+
+      for(unsigned int par=0; par<ParametersDimension; par++) {
+        RealType sumF = itk::NumericTraits< RealType >::Zero;
+        RealType sumM = itk::NumericTraits< RealType >::Zero;
+        for(unsigned int dim=0; dim<dimension; dim++) {
+          const RealType differential = jacobian( dim, par ) * gradient[dim];
+          sumF += fixedValue  * differential;
+          sumM += movingValue * differential;
+          if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+            sumF -= differential * sf / this->m_NumberOfPixelsCounted;
+            sumM -= differential * sm / this->m_NumberOfPixelsCounted;
+          }
+        }
+        derivativeF[par] += sumF;
+        derivativeM[par] += sumM;
+      }
+    }
+    ++ti;
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = ( derivativeF[i] - (sfm/smm)* derivativeM[i] ) / denom;
+    }
+    value = sfm / denom;
+  } else {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] = itk::NumericTraits< MeasureType >::Zero;
+    }
+    value = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+
+
+}
+
+template < class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+  Superclass::PrintSelf(os, indent);
+  os << indent << "SubtractMean: " << m_SubtractMean << std::endl;
+}
+
+} // end namespace itk
+
+
+#endif // opt
+
+#endif // _clitkNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx
diff --git a/registration/clitkOptNormalizedCorrelationImageToImageMetric.h b/registration/clitkOptNormalizedCorrelationImageToImageMetric.h
new file mode 100644 (file)
index 0000000..c4bda86
--- /dev/null
@@ -0,0 +1,159 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkOptNormalizedCorrelationImageToImageMetric_h
+#define __clitkOptNormalizedCorrelationImageToImageMetric_h
+
+#include "itkOptImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+#include "itkIndex.h"
+
+#include "itkMultiThreader.h"
+
+namespace clitk
+{
+
+template <class TFixedImage,class TMovingImage >
+class ITK_EXPORT NormalizedCorrelationImageToImageMetric :
+  public itk::ImageToImageMetric< TFixedImage, TMovingImage >
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef NormalizedCorrelationImageToImageMetric                     Self;
+  typedef itk::ImageToImageMetric< TFixedImage, TMovingImage >   Superclass;
+  typedef itk::SmartPointer<Self>                                Pointer;
+  typedef itk::SmartPointer<const Self>                          ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(NormalizedCorrelationImageToImageMetric, ImageToImageMetric);
+
+  /** Types inherited from Superclass. */
+  typedef typename Superclass::RealType                 RealType;
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::InterpolatorType         InterpolatorType;
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::ParametersType           ParametersType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::MovingImagePointType     MovingImagePointType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+  typedef typename Superclass::CoordinateRepresentationType
+  CoordinateRepresentationType;
+  typedef typename Superclass::FixedImageSampleContainer
+  FixedImageSampleContainer;
+  typedef typename Superclass::ImageDerivativesType     ImageDerivativesType;
+  typedef typename Superclass::WeightsValueType         WeightsValueType;
+  typedef typename Superclass::IndexValueType           IndexValueType;
+
+  // Needed for evaluation of Jacobian.
+  typedef typename Superclass::FixedImagePointType     FixedImagePointType;
+
+  //Accumulators
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  /** The moving image dimension. */
+  itkStaticConstMacro( MovingImageDimension, unsigned int,
+                       MovingImageType::ImageDimension );
+
+
+  /** Set/Get SubtractMean boolean. If true, the sample mean is subtracted
+   * from the sample values in the cross-correlation formula and
+   * typically results in narrower valleys in the cost fucntion.
+   * Default value is false. */
+  itkSetMacro( SubtractMean, bool );
+  itkGetConstReferenceMacro( SubtractMean, bool );
+  itkBooleanMacro( SubtractMean );
+
+  /**
+   *  Initialize the Metric by
+   *  (1) making sure that all the components are present and plugged
+   *      together correctly,
+   *  (2) uniformly select NumberOfSpatialSamples within
+   *      the FixedImageRegion, and
+   *  (3) allocate memory for pdf data structures. */
+  virtual void Initialize(void) throw ( itk::ExceptionObject );
+
+  /**  Get the value. */
+  MeasureType GetValue( const ParametersType & parameters ) const;
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const ParametersType & parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value and derivatives for single valued optimizers. */
+  void GetValueAndDerivative( const ParametersType & parameters,
+                              MeasureType & Value,
+                              DerivativeType & Derivative ) const;
+
+protected:
+
+  NormalizedCorrelationImageToImageMetric();
+  virtual ~NormalizedCorrelationImageToImageMetric();
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+private:
+
+  //purposely not implemented
+  NormalizedCorrelationImageToImageMetric(const Self &);
+  //purposely not implemented
+  void operator=(const Self &);
+
+  /**  Get the value for the derivative computation. */
+  MeasureType ComputeSums( const ParametersType & parameters ) const;
+
+
+  inline bool GetValueThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue ) const;
+
+
+  inline bool GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue,
+      const ImageDerivativesType &
+      movingImageGradientValue ) const;
+
+  AccumulateType *m_ThreaderSFF, *m_ThreaderSMM, *m_ThreaderSFM, *m_ThreaderSF, *m_ThreaderSM;
+  mutable AccumulateType m_SFF, m_SMM, m_SFM, m_SF, m_SM;
+  mutable RealType m_Denom, m_FixedMean, m_MovingMean;
+  DerivativeType * m_ThreaderDerivativeF, *m_ThreaderDerivativeM;
+
+
+  bool m_SubtractMean;
+};
+
+} // end namespace clitk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkOptNormalizedCorrelationImageToImageMetric.txx"
+#endif
+
+#endif
+
+
diff --git a/registration/clitkOptNormalizedCorrelationImageToImageMetric.txx b/registration/clitkOptNormalizedCorrelationImageToImageMetric.txx
new file mode 100644 (file)
index 0000000..41a1af0
--- /dev/null
@@ -0,0 +1,495 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkOptNormalizedCorrelationImageToImageMetric_txx
+#define __clitkOptNormalizedCorrelationImageToImageMetric_txx
+
+#include "clitkOptNormalizedCorrelationImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkImageRandomConstIteratorWithIndex.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageIterator.h"
+#include "vnl/vnl_math.h"
+
+namespace clitk
+{
+
+/**
+ * Constructor
+ */
+template < class TFixedImage, class TMovingImage >
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::NormalizedCorrelationImageToImageMetric()
+{
+  this->SetComputeGradient(true);
+
+  m_ThreaderSFF = NULL;
+  m_ThreaderSMM = NULL;
+  m_ThreaderSFM = NULL;
+  m_ThreaderSF = NULL;
+  m_ThreaderSM = NULL;
+  m_ThreaderDerivativeF = NULL;
+  m_ThreaderDerivativeM = NULL;
+  this->m_WithinThreadPreProcess = false;
+  this->m_WithinThreadPostProcess = false;
+
+  //  For backward compatibility, the default behavior is to use all the pixels
+  //  in the fixed image.
+  this->UseAllPixelsOn();
+
+  m_SubtractMean=false;
+
+}
+
+template < class TFixedImage, class TMovingImage >
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::~NormalizedCorrelationImageToImageMetric()
+{
+  if(m_ThreaderSFF != NULL) {
+    delete [] m_ThreaderSFF;
+  }
+  m_ThreaderSFF = NULL;
+
+  if(m_ThreaderSMM != NULL) {
+    delete [] m_ThreaderSMM;
+  }
+  m_ThreaderSMM = NULL;
+
+  if(m_ThreaderSFM != NULL) {
+    delete [] m_ThreaderSFM;
+  }
+  m_ThreaderSFM = NULL;
+
+  if(m_ThreaderSF != NULL) {
+    delete [] m_ThreaderSF;
+  }
+  m_ThreaderSF = NULL;
+
+  if(m_ThreaderSM != NULL) {
+    delete [] m_ThreaderSM;
+  }
+  m_ThreaderSM = NULL;
+
+  if(m_ThreaderDerivativeF != NULL) {
+    delete [] m_ThreaderDerivativeF;
+  }
+  m_ThreaderDerivativeF = NULL;
+
+  if(m_ThreaderDerivativeM != NULL) {
+    delete [] m_ThreaderDerivativeM;
+  }
+  m_ThreaderDerivativeM = NULL;
+}
+
+/**
+ * Print out internal information about this class
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+
+  Superclass::PrintSelf(os, indent);
+
+}
+
+
+/**
+ * Initialize
+ */
+template <class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::Initialize(void) throw ( itk::ExceptionObject )
+{
+
+  this->Superclass::Initialize();
+  this->Superclass::MultiThreadingInitialize();
+
+
+  /**
+   * Allocate memory for the accumulators (set to zero in GetValue)
+   */
+  if(m_ThreaderSFF != NULL) {
+    delete [] m_ThreaderSFF;
+  }
+  m_ThreaderSFF = new double[this->m_NumberOfThreads];
+
+
+  if(m_ThreaderSMM != NULL) {
+    delete [] m_ThreaderSMM;
+  }
+  m_ThreaderSMM = new double[this->m_NumberOfThreads];
+
+  if(m_ThreaderSFM != NULL) {
+    delete [] m_ThreaderSFM;
+  }
+  m_ThreaderSFM = new double[this->m_NumberOfThreads];
+
+  if(this->m_SubtractMean) {
+    if(m_ThreaderSF != NULL) {
+      delete [] m_ThreaderSF;
+    }
+    m_ThreaderSF = new double[this->m_NumberOfThreads];
+
+    if(m_ThreaderSM != NULL) {
+      delete [] m_ThreaderSM;
+    }
+    m_ThreaderSM = new double[this->m_NumberOfThreads];
+  }
+
+  if(m_ThreaderDerivativeF != NULL) {
+    delete [] m_ThreaderDerivativeF;
+  }
+  m_ThreaderDerivativeF = new DerivativeType[this->m_NumberOfThreads];
+  for(unsigned int threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
+    m_ThreaderDerivativeF[threadID].SetSize( this->m_NumberOfParameters );
+  }
+
+  if(m_ThreaderDerivativeM != NULL) {
+    delete [] m_ThreaderDerivativeM;
+  }
+  m_ThreaderDerivativeM = new DerivativeType[this->m_NumberOfThreads];
+  for(unsigned int threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
+    m_ThreaderDerivativeM[threadID].SetSize( this->m_NumberOfParameters );
+  }
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetValueThreadProcessSample(
+  unsigned int threadID,
+  unsigned long fixedImageSample,
+  const MovingImagePointType & itkNotUsed(mappedPoint),
+  double movingImageValue) const
+{
+  const RealType fixedImageValue= this->m_FixedImageSamples[fixedImageSample].value;
+  m_ThreaderSFF[threadID] += fixedImageValue  * fixedImageValue;
+  m_ThreaderSMM[threadID] += movingImageValue * movingImageValue;
+  m_ThreaderSFM[threadID] += fixedImageValue  * movingImageValue;
+  if ( this->m_SubtractMean ) {
+    m_ThreaderSF[threadID] += fixedImageValue;
+    m_ThreaderSM[threadID] += movingImageValue;
+  }
+
+  return true;
+}
+
+template < class TFixedImage, class TMovingImage  >
+typename NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::MeasureType
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetValue( const ParametersType & parameters ) const
+{
+  itkDebugMacro("GetValue( " << parameters << " ) ");
+
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+
+  //Reset the accumulators
+  memset( m_ThreaderSFF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSMM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSFM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  if(this->m_SubtractMean) {
+    memset( m_ThreaderSF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+    memset( m_ThreaderSM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  }
+
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedInitiate();
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << this->m_NumberOfPixelsCounted << " / "
+                 << this->m_NumberOfFixedImageSamples
+                 << std::endl );
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 4 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  // Accumulate the threads
+  AccumulateType sff, smm, sfm, sf, sm;
+  sff = m_ThreaderSFF[0];
+  smm = m_ThreaderSMM[0];
+  sfm = m_ThreaderSFM[0];
+  sf  = m_ThreaderSF[0];
+  sm  = m_ThreaderSM[0];
+
+  for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
+    sff +=  m_ThreaderSFF[t];
+    smm +=  m_ThreaderSMM[t];
+    sfm +=  m_ThreaderSFM[t];
+    if ( this->m_SubtractMean ) {
+      sf +=  m_ThreaderSF[t];
+      sm +=  m_ThreaderSM[t];
+    }
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+  MeasureType measure;
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    measure = sfm / denom;
+  } else {
+    measure = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+
+  return measure;
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+typename NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::MeasureType
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::ComputeSums( const ParametersType & parameters ) const
+{
+  //No checking for the fixed image,  done in the caller
+  //Reset the accumulators
+  memset( m_ThreaderSFF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSMM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSFM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  if(this->m_SubtractMean) {
+    memset( m_ThreaderSF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+    memset( m_ThreaderSM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  }
+
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedInitiate();
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << this->m_NumberOfPixelsCounted << " / "
+                 << this->m_NumberOfFixedImageSamples
+                 << std::endl );
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 4 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  // Accumulate the threads
+  m_SFF = m_ThreaderSFF[0];
+  m_SMM = m_ThreaderSMM[0];
+  m_SFM = m_ThreaderSFM[0];
+  m_SF  = m_ThreaderSF[0];
+  m_SM  = m_ThreaderSM[0];
+
+  for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
+    m_SFF +=  m_ThreaderSFF[t];
+    m_SMM +=  m_ThreaderSMM[t];
+    m_SFM +=  m_ThreaderSFM[t];
+    if ( this->m_SubtractMean ) {
+      m_SF +=  m_ThreaderSF[t];
+      m_SM +=  m_ThreaderSM[t];
+    }
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    m_SFF -= ( m_SF * m_SF / this->m_NumberOfPixelsCounted );
+    m_SMM -= ( m_SM * m_SM / this->m_NumberOfPixelsCounted );
+    m_SFM -= ( m_SF * m_SM / this->m_NumberOfPixelsCounted );
+    m_FixedMean=m_SF / this->m_NumberOfPixelsCounted;
+    m_MovingMean=m_SM / this->m_NumberOfPixelsCounted;
+  }
+
+
+  m_Denom = -1.0 * vcl_sqrt(m_SFF * m_SMM );
+  MeasureType measure;
+  if( this->m_NumberOfPixelsCounted > 0 && m_Denom != 0.0) {
+    measure = m_SFM / m_Denom;
+  } else {
+    measure = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+  return measure;
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetValueAndDerivativeThreadProcessSample(
+  unsigned int threadID,
+  unsigned long fixedImageSample,
+  const MovingImagePointType & itkNotUsed(mappedPoint),
+  double movingImageValue,
+  const ImageDerivativesType &
+  movingImageGradientValue
+) const
+{
+
+  const RealType fixedImageValue=this->m_FixedImageSamples[fixedImageSample].value;
+  const FixedImagePointType fixedImagePoint = this->m_FixedImageSamples[fixedImageSample].point;
+
+  // Need to use one of the threader transforms if we're
+  // not in thread 0.
+  //
+  // Use a raw pointer here to avoid the overhead of smart pointers.
+  // For instance, Register and UnRegister have mutex locks around
+  // the reference counts.
+  TransformType* transform;
+
+  if (threadID > 0) {
+    transform = this->m_ThreaderTransform[threadID - 1];
+  } else {
+    transform = this->m_Transform;
+  }
+
+  // Jacobian should be evaluated at the unmapped (fixed image) point.
+  const TransformJacobianType & jacobian = transform
+      ->GetJacobian( fixedImagePoint );
+
+  for(unsigned int par=0; par<this->m_NumberOfParameters; par++) {
+    RealType sumF = itk::NumericTraits< RealType >::Zero;
+    RealType sumM = itk::NumericTraits< RealType >::Zero;
+    for(unsigned int dim=0; dim<MovingImageDimension; dim++) {
+      const RealType differential = jacobian( dim, par ) * movingImageGradientValue[dim];
+      if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+        sumF += (fixedImageValue-m_FixedMean)  * differential;
+        sumM += (movingImageValue-m_MovingMean) * differential;
+      } else {
+        sumF += differential * fixedImageValue;
+        sumM += differential * movingImageValue;
+      }
+    }
+    m_ThreaderDerivativeF[threadID][par] += sumF;
+    m_ThreaderDerivativeM[threadID][par] += sumM;
+  }
+
+  return true;
+}
+
+
+/**
+ * Get the both Value and Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetValueAndDerivative( const ParametersType & parameters,
+                         MeasureType & value,
+                         DerivativeType & derivative) const
+{
+
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  //We need the sums and the value to be calculated first
+  value=this->ComputeSums(parameters);
+
+  //Set output values to zero
+  if(derivative.GetSize() != this->m_NumberOfParameters) {
+    derivative = DerivativeType( this->m_NumberOfParameters );
+  }
+  memset( derivative.data_block(),
+          0,
+          this->m_NumberOfParameters * sizeof(ITK_TYPENAME DerivativeType::ValueType) );
+
+  for( unsigned int threadID = 0; threadID<this->m_NumberOfThreads; threadID++ ) {
+    memset( m_ThreaderDerivativeF[threadID].data_block(),
+            0,
+            this->m_NumberOfParameters * sizeof(ITK_TYPENAME DerivativeType::ValueType) );
+
+    memset( m_ThreaderDerivativeM[threadID].data_block(),
+            0,
+            this->m_NumberOfParameters * sizeof(ITK_TYPENAME DerivativeType::ValueType) );
+  }
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueAndDerivativeMultiThreadedInitiate();
+
+  // Accumulate over the threads
+  DerivativeType derivativeF(this->m_NumberOfParameters), derivativeM(this->m_NumberOfParameters);
+  for(unsigned int t=0; t<this->m_NumberOfThreads; t++) {
+    for(unsigned int parameter = 0; parameter < this->m_NumberOfParameters; parameter++) {
+      derivativeF[parameter] += m_ThreaderDerivativeF[t][parameter];
+      derivativeM[parameter] += m_ThreaderDerivativeM[t][parameter];
+    }
+  }
+
+  //Compute derivatives
+  if( this->m_NumberOfPixelsCounted > 0 && m_Denom != 0.0) {
+    for(unsigned int i=0; i<this->m_NumberOfParameters; i++) {
+      derivative[i] = ( derivativeF[i] - (m_SFM/m_SMM)* derivativeM[i] ) / m_Denom;
+    }
+  } else {
+    for(unsigned int i=0; i<this->m_NumberOfParameters; i++) {
+      derivative[i] = itk::NumericTraits< MeasureType >::Zero;
+    }
+  }
+
+}
+
+
+/**
+ * Get the match measure derivative
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+NormalizedCorrelationImageToImageMetric<TFixedImage,TMovingImage>
+::GetDerivative( const ParametersType & parameters,
+                 DerivativeType & derivative ) const
+{
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  MeasureType value;
+  // call the combined version
+  this->GetValueAndDerivative( parameters, value, derivative );
+}
+
+} // end namespace clitk
+
+
+#endif
diff --git a/registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h b/registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h
new file mode 100644 (file)
index 0000000..54503c5
--- /dev/null
@@ -0,0 +1,159 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_h
+#define __clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_h
+
+#include "itkOptImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+#include "itkIndex.h"
+
+#include "itkMultiThreader.h"
+
+namespace clitk
+{
+
+template <class TFixedImage,class TMovingImage >
+class ITK_EXPORT NormalizedCorrelationImageToImageMetricFor3DBLUTFFD :
+  public itk::ImageToImageMetric< TFixedImage, TMovingImage >
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef NormalizedCorrelationImageToImageMetricFor3DBLUTFFD                     Self;
+  typedef itk::ImageToImageMetric< TFixedImage, TMovingImage >   Superclass;
+  typedef itk::SmartPointer<Self>                                Pointer;
+  typedef itk::SmartPointer<const Self>                          ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(NormalizedCorrelationImageToImageMetricFor3DBLUTFFD, ImageToImageMetric);
+
+  /** Types inherited from Superclass. */
+  typedef typename Superclass::RealType                 RealType;
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::InterpolatorType         InterpolatorType;
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::ParametersType           ParametersType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::MovingImagePointType     MovingImagePointType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+  typedef typename Superclass::CoordinateRepresentationType
+  CoordinateRepresentationType;
+  typedef typename Superclass::FixedImageSampleContainer
+  FixedImageSampleContainer;
+  typedef typename Superclass::ImageDerivativesType     ImageDerivativesType;
+  typedef typename Superclass::WeightsValueType         WeightsValueType;
+  typedef typename Superclass::IndexValueType           IndexValueType;
+
+  // Needed for evaluation of Jacobian.
+  typedef typename Superclass::FixedImagePointType     FixedImagePointType;
+
+  //Accumulators
+  typedef  typename itk::NumericTraits< MeasureType >::AccumulateType AccumulateType;
+
+  /** The moving image dimension. */
+  itkStaticConstMacro( MovingImageDimension, unsigned int,
+                       MovingImageType::ImageDimension );
+
+
+  /** Set/Get SubtractMean boolean. If true, the sample mean is subtracted
+   * from the sample values in the cross-correlation formula and
+   * typically results in narrower valleys in the cost fucntion.
+   * Default value is false. */
+  itkSetMacro( SubtractMean, bool );
+  itkGetConstReferenceMacro( SubtractMean, bool );
+  itkBooleanMacro( SubtractMean );
+
+  /**
+   *  Initialize the Metric by
+   *  (1) making sure that all the components are present and plugged
+   *      together correctly,
+   *  (2) uniformly select NumberOfSpatialSamples within
+   *      the FixedImageRegion, and
+   *  (3) allocate memory for pdf data structures. */
+  virtual void Initialize(void) throw ( itk::ExceptionObject );
+
+  /**  Get the value. */
+  MeasureType GetValue( const ParametersType & parameters ) const;
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const ParametersType & parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value and derivatives for single valued optimizers. */
+  void GetValueAndDerivative( const ParametersType & parameters,
+                              MeasureType & Value,
+                              DerivativeType & Derivative ) const;
+
+protected:
+
+  NormalizedCorrelationImageToImageMetricFor3DBLUTFFD();
+  virtual ~NormalizedCorrelationImageToImageMetricFor3DBLUTFFD();
+  void PrintSelf(std::ostream& os, itk::Indent indent) const;
+
+private:
+
+  //purposely not implemented
+  NormalizedCorrelationImageToImageMetricFor3DBLUTFFD(const Self &);
+  //purposely not implemented
+  void operator=(const Self &);
+
+  /**  Get the value for the derivative computation. */
+  MeasureType ComputeSums( const ParametersType & parameters ) const;
+
+
+  inline bool GetValueThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue ) const;
+
+
+  inline bool GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue,
+      const ImageDerivativesType &
+      movingImageGradientValue ) const;
+
+  AccumulateType *m_ThreaderSFF, *m_ThreaderSMM, *m_ThreaderSFM, *m_ThreaderSF, *m_ThreaderSM;
+  mutable AccumulateType m_SFF, m_SMM, m_SFM, m_SF, m_SM;
+  mutable RealType m_Denom, m_FixedMean, m_MovingMean;
+  DerivativeType * m_ThreaderDerivativeF, *m_ThreaderDerivativeM;
+
+
+  bool m_SubtractMean;
+};
+
+} // end namespace clitk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx"
+#endif
+
+#endif
+
+
diff --git a/registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx b/registration/clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.txx
new file mode 100644 (file)
index 0000000..1d2b8cc
--- /dev/null
@@ -0,0 +1,519 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+#ifndef __clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_txx
+#define __clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD_txx
+
+#include "clitkOptNormalizedCorrelationImageToImageMetricFor3DBLUTFFD.h"
+#include "itkCovariantVector.h"
+#include "itkImageRandomConstIteratorWithIndex.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageIterator.h"
+#include "vnl/vnl_math.h"
+
+namespace clitk
+{
+
+/**
+ * Constructor
+ */
+template < class TFixedImage, class TMovingImage >
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::NormalizedCorrelationImageToImageMetricFor3DBLUTFFD()
+{
+  this->SetComputeGradient(true);
+
+  m_ThreaderSFF = NULL;
+  m_ThreaderSMM = NULL;
+  m_ThreaderSFM = NULL;
+  m_ThreaderSF = NULL;
+  m_ThreaderSM = NULL;
+  m_ThreaderDerivativeF = NULL;
+  m_ThreaderDerivativeM = NULL;
+  this->m_WithinThreadPreProcess = false;
+  this->m_WithinThreadPostProcess = false;
+
+  //  For backward compatibility, the default behavior is to use all the pixels
+  //  in the fixed image.
+  this->UseAllPixelsOn();
+
+  m_SubtractMean=false;
+
+}
+
+template < class TFixedImage, class TMovingImage >
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::~NormalizedCorrelationImageToImageMetricFor3DBLUTFFD()
+{
+  if(m_ThreaderSFF != NULL) {
+    delete [] m_ThreaderSFF;
+  }
+  m_ThreaderSFF = NULL;
+
+  if(m_ThreaderSMM != NULL) {
+    delete [] m_ThreaderSMM;
+  }
+  m_ThreaderSMM = NULL;
+
+  if(m_ThreaderSFM != NULL) {
+    delete [] m_ThreaderSFM;
+  }
+  m_ThreaderSFM = NULL;
+
+  if(m_ThreaderSF != NULL) {
+    delete [] m_ThreaderSF;
+  }
+  m_ThreaderSF = NULL;
+
+  if(m_ThreaderSM != NULL) {
+    delete [] m_ThreaderSM;
+  }
+  m_ThreaderSM = NULL;
+
+  if(m_ThreaderDerivativeF != NULL) {
+    delete [] m_ThreaderDerivativeF;
+  }
+  m_ThreaderDerivativeF = NULL;
+
+  if(m_ThreaderDerivativeM != NULL) {
+    delete [] m_ThreaderDerivativeM;
+  }
+  m_ThreaderDerivativeM = NULL;
+}
+
+/**
+ * Print out internal information about this class
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, itk::Indent indent) const
+{
+
+  Superclass::PrintSelf(os, indent);
+
+}
+
+
+/**
+ * Initialize
+ */
+template <class TFixedImage, class TMovingImage>
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::Initialize(void) throw ( itk::ExceptionObject )
+{
+
+  this->Superclass::Initialize();
+  this->Superclass::MultiThreadingInitialize();
+
+
+  /**
+   * Allocate memory for the accumulators (set to zero in GetValue)
+   */
+  if(m_ThreaderSFF != NULL) {
+    delete [] m_ThreaderSFF;
+  }
+  m_ThreaderSFF = new double[this->m_NumberOfThreads];
+
+
+  if(m_ThreaderSMM != NULL) {
+    delete [] m_ThreaderSMM;
+  }
+  m_ThreaderSMM = new double[this->m_NumberOfThreads];
+
+  if(m_ThreaderSFM != NULL) {
+    delete [] m_ThreaderSFM;
+  }
+  m_ThreaderSFM = new double[this->m_NumberOfThreads];
+
+  if(this->m_SubtractMean) {
+    if(m_ThreaderSF != NULL) {
+      delete [] m_ThreaderSF;
+    }
+    m_ThreaderSF = new double[this->m_NumberOfThreads];
+
+    if(m_ThreaderSM != NULL) {
+      delete [] m_ThreaderSM;
+    }
+    m_ThreaderSM = new double[this->m_NumberOfThreads];
+  }
+
+  if(m_ThreaderDerivativeF != NULL) {
+    delete [] m_ThreaderDerivativeF;
+  }
+  m_ThreaderDerivativeF = new DerivativeType[this->m_NumberOfThreads];
+  for(unsigned int threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
+    m_ThreaderDerivativeF[threadID].SetSize( this->m_NumberOfParameters );
+  }
+
+  if(m_ThreaderDerivativeM != NULL) {
+    delete [] m_ThreaderDerivativeM;
+  }
+  m_ThreaderDerivativeM = new DerivativeType[this->m_NumberOfThreads];
+  for(unsigned int threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
+    m_ThreaderDerivativeM[threadID].SetSize( this->m_NumberOfParameters );
+  }
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueThreadProcessSample(
+  unsigned int threadID,
+  unsigned long fixedImageSample,
+  const MovingImagePointType & itkNotUsed(mappedPoint),
+  double movingImageValue) const
+{
+  const RealType fixedImageValue= this->m_FixedImageSamples[fixedImageSample].value;
+  m_ThreaderSFF[threadID] += fixedImageValue  * fixedImageValue;
+  m_ThreaderSMM[threadID] += movingImageValue * movingImageValue;
+  m_ThreaderSFM[threadID] += fixedImageValue  * movingImageValue;
+  if ( this->m_SubtractMean ) {
+    m_ThreaderSF[threadID] += fixedImageValue;
+    m_ThreaderSM[threadID] += movingImageValue;
+  }
+
+  return true;
+}
+
+template < class TFixedImage, class TMovingImage  >
+typename NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeasureType
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValue( const ParametersType & parameters ) const
+{
+  itkDebugMacro("GetValue( " << parameters << " ) ");
+
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+
+  //Reset the accumulators
+  memset( m_ThreaderSFF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSMM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSFM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  if(this->m_SubtractMean) {
+    memset( m_ThreaderSF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+    memset( m_ThreaderSM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  }
+
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedInitiate();
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << this->m_NumberOfPixelsCounted << " / "
+                 << this->m_NumberOfFixedImageSamples
+                 << std::endl );
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 4 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  // Accumulate the threads
+  AccumulateType sff, smm, sfm, sf, sm;
+  sff = m_ThreaderSFF[0];
+  smm = m_ThreaderSMM[0];
+  sfm = m_ThreaderSFM[0];
+  sf  = m_ThreaderSF[0];
+  sm  = m_ThreaderSM[0];
+
+  for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
+    sff +=  m_ThreaderSFF[t];
+    smm +=  m_ThreaderSMM[t];
+    sfm +=  m_ThreaderSFM[t];
+    if ( this->m_SubtractMean ) {
+      sf +=  m_ThreaderSF[t];
+      sm +=  m_ThreaderSM[t];
+    }
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    sff -= ( sf * sf / this->m_NumberOfPixelsCounted );
+    smm -= ( sm * sm / this->m_NumberOfPixelsCounted );
+    sfm -= ( sf * sm / this->m_NumberOfPixelsCounted );
+  }
+
+
+  const RealType denom = -1.0 * vcl_sqrt(sff * smm );
+  MeasureType measure;
+  if( this->m_NumberOfPixelsCounted > 0 && denom != 0.0) {
+    measure = sfm / denom;
+  } else {
+    measure = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+
+  return measure;
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+typename NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeasureType
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ComputeSums( const ParametersType & parameters ) const
+{
+  //No checking for the fixed image,  done in the caller
+  //Reset the accumulators
+  memset( m_ThreaderSFF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSMM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  memset( m_ThreaderSFM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  if(this->m_SubtractMean) {
+    memset( m_ThreaderSF,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+    memset( m_ThreaderSM,  0,  this->m_NumberOfThreads * sizeof(AccumulateType) );
+  }
+
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedInitiate();
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << this->m_NumberOfPixelsCounted << " / "
+                 << this->m_NumberOfFixedImageSamples
+                 << std::endl );
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 4 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  // Accumulate the threads
+  m_SFF = m_ThreaderSFF[0];
+  m_SMM = m_ThreaderSMM[0];
+  m_SFM = m_ThreaderSFM[0];
+  m_SF  = m_ThreaderSF[0];
+  m_SM  = m_ThreaderSM[0];
+
+  for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
+    m_SFF +=  m_ThreaderSFF[t];
+    m_SMM +=  m_ThreaderSMM[t];
+    m_SFM +=  m_ThreaderSFM[t];
+    if ( this->m_SubtractMean ) {
+      m_SF +=  m_ThreaderSF[t];
+      m_SM +=  m_ThreaderSM[t];
+    }
+  }
+
+  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+    m_SFF -= ( m_SF * m_SF / this->m_NumberOfPixelsCounted );
+    m_SMM -= ( m_SM * m_SM / this->m_NumberOfPixelsCounted );
+    m_SFM -= ( m_SF * m_SM / this->m_NumberOfPixelsCounted );
+    m_FixedMean=m_SF / this->m_NumberOfPixelsCounted;
+    m_MovingMean=m_SM / this->m_NumberOfPixelsCounted;
+  }
+
+
+  m_Denom = -1.0 * vcl_sqrt(m_SFF * m_SMM );
+  MeasureType measure;
+  if( this->m_NumberOfPixelsCounted > 0 && m_Denom != 0.0) {
+    measure = m_SFM / m_Denom;
+  } else {
+    measure = itk::NumericTraits< MeasureType >::Zero;
+  }
+
+  return measure;
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivativeThreadProcessSample(
+  unsigned int threadID,
+  unsigned long fixedImageSample,
+  const MovingImagePointType & itkNotUsed(mappedPoint),
+  double movingImageValue,
+  const ImageDerivativesType &
+  movingImageGradientValue
+) const
+{
+
+  const RealType fixedImageValue=this->m_FixedImageSamples[fixedImageSample].value;
+  const FixedImagePointType fixedImagePoint = this->m_FixedImageSamples[fixedImageSample].point;
+
+  // Need to use one of the threader transforms if we're
+  // not in thread 0.
+  //
+  // Use a raw pointer here to avoid the overhead of smart pointers.
+  // For instance, Register and UnRegister have mutex locks around
+  // the reference counts.
+  TransformType* transform;
+
+  if (threadID > 0) {
+    transform = this->m_ThreaderTransform[threadID - 1];
+  } else {
+    transform = this->m_Transform;
+  }
+
+  // Jacobian should be evaluated at the unmapped (fixed image) point.
+  const TransformJacobianType & jacobian = transform->GetJacobian( fixedImagePoint );
+
+//          for(unsigned int par=0; par<this->m_NumberOfParameters; par++)
+//            {
+//              RealType sumF = itk::NumericTraits< RealType >::Zero;
+//              RealType sumM = itk::NumericTraits< RealType >::Zero;
+//              for(unsigned int dim=0; dim<MovingImageDimension; dim++)
+//                {
+//                  const RealType differential = jacobian( dim, par ) * movingImageGradientValue[dim];
+//                  if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 )
+//                    {
+//                      sumF += (fixedImageValue-m_FixedMean)  * differential;
+//                      sumM += (movingImageValue-m_MovingMean) * differential;
+//                    }
+//                  else
+//                    {
+//                      sumF += differential * fixedImageValue;
+//                      sumM += differential * movingImageValue;
+//                    }
+//                }
+//              m_ThreaderDerivativeF[threadID][par] += sumF;
+//              m_ThreaderDerivativeM[threadID][par] += sumM;
+//            }
+
+  // JV
+  unsigned int par, dim;
+  RealType differential;
+  for( par=0; par<this->m_NumberOfParameters; par+=3) {
+    // JV only for 3D Space BLUT FFD: if J(0, par)=0, then J(1,par+1)=0 & ...
+    if (jacobian( 0, par ) ) {
+      for(dim=0; dim<3; dim++) {
+        differential = jacobian( dim, par+dim ) * movingImageGradientValue[dim];
+
+        if ( this->m_SubtractMean && this->m_NumberOfPixelsCounted > 0 ) {
+          m_ThreaderDerivativeF[threadID][par+dim]+= (fixedImageValue-m_FixedMean)  * differential;
+          m_ThreaderDerivativeM[threadID][par+dim]+= (movingImageValue-m_MovingMean) * differential;
+        } else {
+          m_ThreaderDerivativeF[threadID][par+dim]+= differential * fixedImageValue;
+          m_ThreaderDerivativeM[threadID][par+dim]+= differential * movingImageValue;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+
+/**
+ * Get the both Value and Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivative( const ParametersType & parameters,
+                         MeasureType & value,
+                         DerivativeType & derivative) const
+{
+
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  //We need the sums and the value to be calculated first
+  value=this->ComputeSums(parameters);
+
+  //Set output values to zero
+  if(derivative.GetSize() != this->m_NumberOfParameters) {
+    derivative = DerivativeType( this->m_NumberOfParameters );
+  }
+  memset( derivative.data_block(),
+          0,
+          this->m_NumberOfParameters * sizeof(ITK_TYPENAME DerivativeType::ValueType) );
+
+  for( unsigned int threadID = 0; threadID<this->m_NumberOfThreads; threadID++ ) {
+    memset( m_ThreaderDerivativeF[threadID].data_block(),
+            0,
+            this->m_NumberOfParameters * sizeof(ITK_TYPENAME DerivativeType::ValueType) );
+
+    memset( m_ThreaderDerivativeM[threadID].data_block(),
+            0,
+            this->m_NumberOfParameters * sizeof(ITK_TYPENAME DerivativeType::ValueType) );
+  }
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueAndDerivativeMultiThreadedInitiate();
+
+  // Accumulate over the threads
+  DerivativeType derivativeF(this->m_NumberOfParameters), derivativeM(this->m_NumberOfParameters);
+  for(unsigned int t=0; t<this->m_NumberOfThreads; t++) {
+    for(unsigned int parameter = 0; parameter < this->m_NumberOfParameters; parameter++) {
+      derivativeF[parameter] += m_ThreaderDerivativeF[t][parameter];
+      derivativeM[parameter] += m_ThreaderDerivativeM[t][parameter];
+    }
+  }
+
+  //Compute derivatives
+  if( this->m_NumberOfPixelsCounted > 0 && m_Denom != 0.0) {
+    for(unsigned int i=0; i<this->m_NumberOfParameters; i++) {
+      derivative[i] = ( derivativeF[i] - (m_SFM/m_SMM)* derivativeM[i] ) / m_Denom;
+    }
+  } else {
+    for(unsigned int i=0; i<this->m_NumberOfParameters; i++) {
+      derivative[i] = itk::NumericTraits< MeasureType >::Zero;
+    }
+  }
+
+}
+
+
+/**
+ * Get the match measure derivative
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+NormalizedCorrelationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetDerivative( const ParametersType & parameters,
+                 DerivativeType & derivative ) const
+{
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  MeasureType value;
+  // call the combined version
+  this->GetValueAndDerivative( parameters, value, derivative );
+}
+
+} // end namespace clitk
+
+
+#endif
diff --git a/registration/itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h b/registration/itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h
new file mode 100644 (file)
index 0000000..d2f6f53
--- /dev/null
@@ -0,0 +1,535 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD_h
+#define __itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD_h
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h"
+#else
+
+#include "itkImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+#include "itkIndex.h"
+#include "itkBSplineKernelFunction.h"
+#include "itkBSplineDerivativeKernelFunction.h"
+#include "itkCentralDifferenceImageFunction.h"
+#include "itkBSplineInterpolateImageFunction.h"
+#include "itkBSplineDeformableTransform.h"
+#include "itkArray2D.h"
+
+namespace itk
+{
+
+/** \class MattesMutualInformationImageToImageMetricFor3DBLUTFFD
+ * \brief Computes the mutual information between two images to be
+ * registered using the method of Mattes et al.
+ *
+ * MattesMutualInformationImageToImageMetricFor3DBLUTFFD computes the mutual
+ * information between a fixed and moving image to be registered.
+ *
+ * This class is templated over the FixedImage type and the MovingImage
+ * type.
+ *
+ * The fixed and moving images are set via methods SetFixedImage() and
+ * SetMovingImage(). This metric makes use of user specified Transform and
+ * Interpolator. The Transform is used to map points from the fixed image to
+ * the moving image domain. The Interpolator is used to evaluate the image
+ * intensity at user specified geometric points in the moving image.
+ * The Transform and Interpolator are set via methods SetTransform() and
+ * SetInterpolator().
+ *
+ * If a BSplineInterpolationFunction is used, this class obtain
+ * image derivatives from the BSpline interpolator. Otherwise,
+ * image derivatives are computed using central differencing.
+ *
+ * \warning This metric assumes that the moving image has already been
+ * connected to the interpolator outside of this class.
+ *
+ * The method GetValue() computes of the mutual information
+ * while method GetValueAndDerivative() computes
+ * both the mutual information and its derivatives with respect to the
+ * transform parameters.
+ *
+ * The calculations are based on the method of Mattes et al [1,2]
+ * where the probability density distribution are estimated using
+ * Parzen histograms. Since the fixed image PDF does not contribute
+ * to the derivatives, it does not need to be smooth. Hence,
+ * a zero order (box car) BSpline kernel is used
+ * for the fixed image intensity PDF. On the other hand, to ensure
+ * smoothness a third order BSpline kernel is used for the
+ * moving image intensity PDF.
+ *
+ * On Initialize(), the FixedImage is uniformly sampled within
+ * the FixedImageRegion. The number of samples used can be set
+ * via SetNumberOfSpatialSamples(). Typically, the number of
+ * spatial samples used should increase with the image size.
+ *
+ * The option UseAllPixelOn() disables the random sampling and uses
+ * all the pixels of the FixedImageRegion in order to estimate the
+ * joint intensity PDF.
+ *
+ * During each call of GetValue(), GetDerivatives(),
+ * GetValueAndDerivatives(), marginal and joint intensity PDF's
+ * values are estimated at discrete position or bins.
+ * The number of bins used can be set via SetNumberOfHistogramBins().
+ * To handle data with arbitray magnitude and dynamic range,
+ * the image intensity is scale such that any contribution to the
+ * histogram will fall into a valid bin.
+ *
+ * One the PDF's have been contructed, the mutual information
+ * is obtained by doubling summing over the discrete PDF values.
+ *
+ *
+ * Notes:
+ * 1. This class returns the negative mutual information value.
+ * 2. This class in not thread safe due the private data structures
+ *     used to the store the sampled points and the marginal and joint pdfs.
+ *
+ * References:
+ * [1] "Nonrigid multimodality image registration"
+ *      D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank
+ *      Medical Imaging 2001: Image Processing, 2001, pp. 1609-1620.
+ * [2] "PET-CT Image Registration in the Chest Using Free-form Deformations"
+ *      D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank
+ *      IEEE Transactions in Medical Imaging. Vol.22, No.1,
+        January 2003. pp.120-128.
+ * [3] "Optimization of Mutual Information for MultiResolution Image
+ *      Registration"
+ *      P. Thevenaz and M. Unser
+ *      IEEE Transactions in Image Processing, 9(12) December 2000.
+ *
+ * \ingroup RegistrationMetrics
+ * \ingroup ThreadUnSafe
+ */
+template <class TFixedImage,class TMovingImage >
+class ITK_EXPORT MattesMutualInformationImageToImageMetricFor3DBLUTFFD :
+  public ImageToImageMetric< TFixedImage, TMovingImage >
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef MattesMutualInformationImageToImageMetricFor3DBLUTFFD           Self;
+  typedef ImageToImageMetric< TFixedImage, TMovingImage >     Superclass;
+  typedef SmartPointer<Self>                                  Pointer;
+  typedef SmartPointer<const Self>                            ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(MattesMutualInformationImageToImageMetricFor3DBLUTFFD, ImageToImageMetric);
+
+  /** Types inherited from Superclass. */
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::InterpolatorType         InterpolatorType;
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::ParametersType           ParametersType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageCosntPointer;
+  typedef typename Superclass::InputPointType           InputPointType;
+  typedef typename Superclass::OutputPointType          OutputPointType;
+
+  typedef typename Superclass::CoordinateRepresentationType
+  CoordinateRepresentationType;
+
+  /** Index and Point typedef support. */
+  typedef typename FixedImageType::IndexType           FixedImageIndexType;
+  typedef typename FixedImageIndexType::IndexValueType FixedImageIndexValueType;
+  typedef typename MovingImageType::IndexType          MovingImageIndexType;
+  typedef typename TransformType::InputPointType       FixedImagePointType;
+  typedef typename TransformType::OutputPointType      MovingImagePointType;
+
+  /** The moving image dimension. */
+  itkStaticConstMacro( MovingImageDimension, unsigned int,
+                       MovingImageType::ImageDimension );
+
+  /**
+   *  Initialize the Metric by
+   *  (1) making sure that all the components are present and plugged
+   *      together correctly,
+   *  (2) uniformly select NumberOfSpatialSamples within
+   *      the FixedImageRegion, and
+   *  (3) allocate memory for pdf data structures. */
+  virtual void Initialize(void) throw ( ExceptionObject );
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const ParametersType& parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value. */
+  MeasureType GetValue( const ParametersType& parameters ) const;
+
+  /**  Get the value and derivatives for single valued optimizers. */
+  void GetValueAndDerivative( const ParametersType& parameters,
+                              MeasureType& Value,
+                              DerivativeType& Derivative ) const;
+
+  /** Number of spatial samples to used to compute metric */
+  itkSetClampMacro( NumberOfSpatialSamples, unsigned long,
+                    1, NumericTraits<unsigned long>::max() );
+  itkGetConstReferenceMacro( NumberOfSpatialSamples, unsigned long);
+
+  /** Number of bins to used in the histogram. Typical value is 50. */
+  itkSetClampMacro( NumberOfHistogramBins, unsigned long,
+                    1, NumericTraits<unsigned long>::max() );
+  itkGetConstReferenceMacro( NumberOfHistogramBins, unsigned long);
+
+  /** Reinitialize the seed of the random number generator that selects the
+   * sample of pixels used for estimating the image histograms and the joint
+   * histogram. By nature, this metric is not deterministic, since at each run
+   * it may select a different set of pixels. By initializing the random number
+   * generator seed to the same value you can restore determinism. On the other
+   * hand, calling the method ReinitializeSeed() without arguments will use the
+   * clock from your machine in order to have a very random initialization of
+   * the seed. This will indeed increase the non-deterministic behavior of the
+   * metric. */
+  void ReinitializeSeed();
+  void ReinitializeSeed(int);
+
+  /** Select whether the metric will be computed using all the pixels on the
+   * fixed image region, or only using a set of randomly selected pixels. */
+  itkSetMacro(UseAllPixels,bool);
+  itkGetConstReferenceMacro(UseAllPixels,bool);
+  itkBooleanMacro(UseAllPixels);
+
+  /** This variable selects the method to be used for computing the Metric
+   * derivatives with respect to the Transform parameters. Two modes of
+   * computation are available. The choice between one and the other is a
+   * trade-off between computation speed and memory allocations. The two modes
+   * are described in detail below:
+   *
+   * UseExplicitPDFDerivatives = True
+   * will compute the Metric derivative by first calculating the derivatives of
+   * each one of the Joint PDF bins with respect to each one of the Transform
+   * parameters and then accumulating these contributions in the final metric
+   * derivative array by using a bin-specific weight.  The memory required for
+   * storing the intermediate derivatives is a 3D array of doubles with size
+   * equals to the product of (number of histogram bins)^2 times number of
+   * transform parameters. This method is well suited for Transform with a small
+   * number of parameters.
+   *
+   * UseExplicitPDFDerivatives = False will compute the Metric derivative by
+   * first computing the weights for each one of the Joint PDF bins and caching
+   * them into an array. Then it will revisit each one of the PDF bins for
+   * computing its weighted contribution to the full derivative array. In this
+   * method an extra 2D array is used for storing the weights of each one of
+   * the PDF bins. This is an array of doubles with size equals to (number of
+   * histogram bins)^2. This method is well suited for Transforms with a large
+   * number of parameters, such as, BSplineDeformableTransforms. */
+  itkSetMacro(UseExplicitPDFDerivatives,bool);
+  itkGetConstReferenceMacro(UseExplicitPDFDerivatives,bool);
+  itkBooleanMacro(UseExplicitPDFDerivatives);
+
+  /** This boolean flag is only relevant when this metric is used along
+   * with a BSplineDeformableTransform. The flag enables/disables the
+   * caching of values computed when a physical point is mapped through
+   * the BSplineDeformableTransform. In particular it will cache the
+   * values of the BSpline weights for that points, and the indexes
+   * indicating what BSpline-grid nodes are relevant for that specific
+   * point. This caching is made optional due to the fact that the
+   * memory arrays used for the caching can reach large sizes even for
+   * moderate image size problems. For example, for a 3D image of
+   * 256^3, using 20% of pixels, these arrays will take about 1
+   * Gigabyte of RAM for storage. The ratio of computing time between
+   * using the cache or not using the cache can reach 1:5, meaning that
+   * using the caching can provide a five times speed up. It is
+   * therefore, interesting to enable the caching, if enough memory is
+   * available for it. The caching is enabled by default, in order to
+   * preserve backward compatibility with previous versions of ITK. */
+  itkSetMacro(UseCachingOfBSplineWeights,bool);
+  itkGetConstReferenceMacro(UseCachingOfBSplineWeights,bool);
+  itkBooleanMacro(UseCachingOfBSplineWeights);
+
+protected:
+
+  MattesMutualInformationImageToImageMetricFor3DBLUTFFD();
+  virtual ~MattesMutualInformationImageToImageMetricFor3DBLUTFFD() {};
+  void PrintSelf(std::ostream& os, Indent indent) const;
+
+  /** \class FixedImageSpatialSample
+   * A fixed image spatial sample consists of the fixed domain point
+   * and the fixed image value at that point. */
+  /// @cond
+  class FixedImageSpatialSample
+  {
+  public:
+    FixedImageSpatialSample():FixedImageValue(0.0) {
+      FixedImagePointValue.Fill(0.0);
+    }
+    ~FixedImageSpatialSample() {};
+
+    FixedImagePointType           FixedImagePointValue;
+    double                        FixedImageValue;
+    unsigned int                  FixedImageParzenWindowIndex;
+  };
+  /// @endcond
+
+  /** FixedImageSpatialSample typedef support. */
+  typedef std::vector<FixedImageSpatialSample>
+  FixedImageSpatialSampleContainer;
+
+  /** Container to store a set of points and fixed image values. */
+  FixedImageSpatialSampleContainer    m_FixedImageSamples;
+
+  /** Uniformly select a sample set from the fixed image domain. */
+  virtual void SampleFixedImageDomain(
+    FixedImageSpatialSampleContainer& samples);
+
+  /** Gather all the pixels from the fixed image domain. */
+  virtual void SampleFullFixedImageDomain(
+    FixedImageSpatialSampleContainer& samples);
+
+  /** Transform a point from FixedImage domain to MovingImage domain.
+   * This function also checks if mapped point is within support region. */
+  virtual void TransformPoint( unsigned int sampleNumber,
+                               const ParametersType& parameters,
+                               MovingImagePointType& mappedPoint,
+                               bool& sampleWithinSupportRegion,
+                               double& movingImageValue ) const;
+
+private:
+
+  //purposely not implemented
+  MattesMutualInformationImageToImageMetricFor3DBLUTFFD(const Self&);
+  //purposely not implemented
+  void operator=(const Self&);
+
+
+  /** The marginal PDFs are stored as std::vector. */
+  typedef float                       PDFValueType;
+  typedef std::vector<PDFValueType>   MarginalPDFType;
+
+  /** The fixed image marginal PDF. */
+  mutable MarginalPDFType             m_FixedImageMarginalPDF;
+
+  /** The moving image marginal PDF. */
+  mutable MarginalPDFType             m_MovingImageMarginalPDF;
+
+  /** Helper array for storing the values of the JointPDF ratios. */
+  typedef double                      PRatioType;
+  typedef Array2D< PRatioType >       PRatioArrayType;
+  mutable PRatioArrayType             m_PRatioArray;
+
+  /** Helper variable for accumulating the derivative of the metric. */
+  mutable DerivativeType              m_MetricDerivative;
+
+  /** Typedef for the joint PDF and PDF derivatives are stored as ITK Images. */
+  typedef Image<PDFValueType,2>                 JointPDFType;
+  typedef JointPDFType::IndexType               JointPDFIndexType;
+  typedef JointPDFType::PixelType               JointPDFValueType;
+  typedef JointPDFType::RegionType              JointPDFRegionType;
+  typedef JointPDFType::SizeType                JointPDFSizeType;
+  typedef Image<PDFValueType,3>                 JointPDFDerivativesType;
+  typedef JointPDFDerivativesType::IndexType    JointPDFDerivativesIndexType;
+  typedef JointPDFDerivativesType::PixelType    JointPDFDerivativesValueType;
+  typedef JointPDFDerivativesType::RegionType   JointPDFDerivativesRegionType;
+  typedef JointPDFDerivativesType::SizeType     JointPDFDerivativesSizeType;
+
+  /** The joint PDF and PDF derivatives. */
+  typename JointPDFType::Pointer                m_JointPDF;
+  typename JointPDFDerivativesType::Pointer     m_JointPDFDerivatives;
+
+  unsigned long                                 m_NumberOfSpatialSamples;
+  unsigned long                                 m_NumberOfParameters;
+
+  /** Variables to define the marginal and joint histograms. */
+  unsigned long  m_NumberOfHistogramBins;
+  double         m_MovingImageNormalizedMin;
+  double         m_FixedImageNormalizedMin;
+  double         m_MovingImageTrueMin;
+  double         m_MovingImageTrueMax;
+  double         m_FixedImageBinSize;
+  double         m_MovingImageBinSize;
+
+  /** Typedefs for BSpline kernel and derivative functions. */
+  typedef BSplineKernelFunction<3>           CubicBSplineFunctionType;
+  typedef BSplineDerivativeKernelFunction<3> CubicBSplineDerivativeFunctionType;
+
+  /** Cubic BSpline kernel for computing Parzen histograms. */
+  typename CubicBSplineFunctionType::Pointer   m_CubicBSplineKernel;
+  typename CubicBSplineDerivativeFunctionType::Pointer
+  m_CubicBSplineDerivativeKernel;
+
+  /** Precompute fixed image parzen window indices. */
+  virtual void ComputeFixedImageParzenWindowIndices(
+    FixedImageSpatialSampleContainer& samples );
+
+  /**
+   * Types and variables related to image derivative calculations.
+   * If a BSplineInterpolationFunction is used, this class obtain
+   * image derivatives from the BSpline interpolator. Otherwise,
+   * image derivatives are computed using central differencing.
+   */
+  typedef CovariantVector< double,
+          itkGetStaticConstMacro(MovingImageDimension) >
+          ImageDerivativesType;
+
+  /** Compute image derivatives at a point. */
+  virtual void ComputeImageDerivatives( const MovingImagePointType& mappedPoint,
+                                        ImageDerivativesType& gradient ) const;
+
+  /** Boolean to indicate if the interpolator BSpline. */
+  bool m_InterpolatorIsBSpline;
+
+  /** Typedefs for using BSpline interpolator. */
+  typedef
+  BSplineInterpolateImageFunction<MovingImageType,
+                                  CoordinateRepresentationType>
+                                  BSplineInterpolatorType;
+
+  /** Pointer to BSplineInterpolator. */
+  typename BSplineInterpolatorType::Pointer m_BSplineInterpolator;
+
+  /** Typedefs for using central difference calculator. */
+  typedef CentralDifferenceImageFunction<MovingImageType,
+          CoordinateRepresentationType>
+          DerivativeFunctionType;
+
+  /** Pointer to central difference calculator. */
+  typename DerivativeFunctionType::Pointer m_DerivativeCalculator;
+
+
+  /** Compute PDF derivative contribution for each parameter. */
+  virtual void ComputePDFDerivatives( unsigned int sampleNumber,
+                                      int movingImageParzenWindowIndex,
+                                      const ImageDerivativesType&
+                                      movingImageGradientValue,
+                                      double cubicBSplineDerivativeValue
+                                    ) const;
+
+  /**
+   * Types and variables related to BSpline deformable transforms.
+   * If the transform is of type third order BSplineDeformableTransform,
+   * then we can speed up the metric derivative calculation by
+   * only inspecting the parameters within the support region
+   * of a mapped point.
+   */
+
+  /** Boolean to indicate if the transform is BSpline deformable. */
+  bool m_TransformIsBSpline;
+
+  /** The number of BSpline parameters per image dimension. */
+  long m_NumParametersPerDim;
+
+  /**
+   * The number of BSpline transform weights is the number of
+   * of parameter in the support region (per dimension ). */
+  unsigned long m_NumBSplineWeights;
+
+  /** The fixed image dimension. */
+  itkStaticConstMacro( FixedImageDimension, unsigned int,
+                       FixedImageType::ImageDimension );
+
+  /**
+   * Enum of the deformabtion field spline order.
+   */
+  enum { DeformationSplineOrder = 3 };
+
+  /**
+   * Typedefs for the BSplineDeformableTransform.
+   */
+  typedef BSplineDeformableTransform<
+  CoordinateRepresentationType,
+  ::itk::GetImageDimension<FixedImageType>::ImageDimension,
+  DeformationSplineOrder> BSplineTransformType;
+  typedef typename BSplineTransformType::WeightsType
+  BSplineTransformWeightsType;
+  typedef typename BSplineTransformType::ParameterIndexArrayType
+  BSplineTransformIndexArrayType;
+
+  /**
+   * Variables used when transform is of type BSpline deformable.
+   */
+  typename BSplineTransformType::Pointer m_BSplineTransform;
+
+  /**
+   * Cache pre-transformed points, weights, indices and
+   * within support region flag.
+   */
+  typedef typename BSplineTransformWeightsType::ValueType    WeightsValueType;
+  typedef          Array2D<WeightsValueType>                 BSplineTransformWeightsArrayType;
+  typedef typename BSplineTransformIndexArrayType::ValueType IndexValueType;
+  typedef          Array2D<IndexValueType>                   BSplineTransformIndicesArrayType;
+  typedef          std::vector<MovingImagePointType>         MovingImagePointArrayType;
+  typedef          std::vector<bool>                         BooleanArrayType;
+
+  BSplineTransformWeightsArrayType      m_BSplineTransformWeightsArray;
+  BSplineTransformIndicesArrayType      m_BSplineTransformIndicesArray;
+  MovingImagePointArrayType             m_PreTransformPointsArray;
+  BooleanArrayType                      m_WithinSupportRegionArray;
+
+  typedef FixedArray<unsigned long,
+          ::itk::GetImageDimension<FixedImageType>::ImageDimension>
+          ParametersOffsetType;
+  ParametersOffsetType                  m_ParametersOffset;
+
+  bool             m_UseAllPixels;
+
+  virtual void PreComputeTransformValues();
+
+  bool             m_ReseedIterator;
+  int              m_RandomSeed;
+
+  // Selection of explicit or implicit computation of PDF derivatives
+  // with respect to Transform parameters.
+  bool             m_UseExplicitPDFDerivatives;
+
+  // Variables needed for optionally caching values when using a BSpline transform.
+  bool                                    m_UseCachingOfBSplineWeights;
+  mutable BSplineTransformWeightsType     m_Weights;
+  mutable BSplineTransformIndexArrayType  m_Indices;
+
+};
+
+} // end namespace itk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx"
+#endif
+
+#endif
+
+#endif
diff --git a/registration/itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx b/registration/itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx
new file mode 100644 (file)
index 0000000..171ed47
--- /dev/null
@@ -0,0 +1,1586 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
+#define __itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
+
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx"
+#else
+
+
+#include "itkMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h"
+#include "itkBSplineInterpolateImageFunction.h"
+#include "itkCovariantVector.h"
+#include "itkImageRandomConstIteratorWithIndex.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageIterator.h"
+#include "vnl/vnl_math.h"
+#include "itkBSplineDeformableTransform.h"
+
+namespace itk
+{
+
+
+/**
+ * Constructor
+ */
+template < class TFixedImage, class TMovingImage >
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
+{
+
+  m_NumberOfSpatialSamples = 500;
+  m_NumberOfHistogramBins = 50;
+
+  this->SetComputeGradient(false); // don't use the default gradient for now
+
+  m_InterpolatorIsBSpline = false;
+  m_TransformIsBSpline    = false;
+
+  // Initialize PDFs to NULL
+  m_JointPDF = NULL;
+  m_JointPDFDerivatives = NULL;
+
+  m_UseExplicitPDFDerivatives = true;
+
+  typename BSplineTransformType::Pointer transformer =
+    BSplineTransformType::New();
+  this->SetTransform (transformer);
+
+  typename BSplineInterpolatorType::Pointer interpolator =
+    BSplineInterpolatorType::New();
+  this->SetInterpolator (interpolator);
+
+  // Initialize memory
+  m_MovingImageNormalizedMin = 0.0;
+  m_FixedImageNormalizedMin = 0.0;
+  m_MovingImageTrueMin = 0.0;
+  m_MovingImageTrueMax = 0.0;
+  m_FixedImageBinSize = 0.0;
+  m_MovingImageBinSize = 0.0;
+  m_CubicBSplineDerivativeKernel = NULL;
+  m_BSplineInterpolator = NULL;
+  m_DerivativeCalculator = NULL;
+  m_NumParametersPerDim = 0;
+  m_NumBSplineWeights = 0;
+  m_BSplineTransform = NULL;
+  m_NumberOfParameters = 0;
+  m_UseAllPixels = false;
+  m_ReseedIterator = false;
+  m_RandomSeed = -1;
+  m_UseCachingOfBSplineWeights = true;
+}
+
+
+/**
+ * Print out internal information about this class
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, Indent indent) const
+{
+
+  Superclass::PrintSelf(os, indent);
+
+  os << indent << "NumberOfSpatialSamples: ";
+  os << m_NumberOfSpatialSamples << std::endl;
+  os << indent << "NumberOfHistogramBins: ";
+  os << m_NumberOfHistogramBins << std::endl;
+  os << indent << "UseAllPixels: ";
+  os << m_UseAllPixels << std::endl;
+
+  // Debugging information
+  os << indent << "NumberOfParameters: ";
+  os << m_NumberOfParameters << std::endl;
+  os << indent << "FixedImageNormalizedMin: ";
+  os << m_FixedImageNormalizedMin << std::endl;
+  os << indent << "MovingImageNormalizedMin: ";
+  os << m_MovingImageNormalizedMin << std::endl;
+  os << indent << "MovingImageTrueMin: ";
+  os << m_MovingImageTrueMin << std::endl;
+  os << indent << "MovingImageTrueMax: ";
+  os << m_MovingImageTrueMax << std::endl;
+  os << indent << "FixedImageBinSize: ";
+  os << m_FixedImageBinSize << std::endl;
+  os << indent << "MovingImageBinSize: ";
+  os << m_MovingImageBinSize << std::endl;
+  os << indent << "InterpolatorIsBSpline: ";
+  os << m_InterpolatorIsBSpline << std::endl;
+  os << indent << "TransformIsBSpline: ";
+  os << m_TransformIsBSpline << std::endl;
+  os << indent << "UseCachingOfBSplineWeights: ";
+  os << m_UseCachingOfBSplineWeights << std::endl;
+  os << indent << "UseExplicitPDFDerivatives: ";
+  os << m_UseExplicitPDFDerivatives << std::endl;
+
+}
+
+
+/**
+ * Initialize
+ */
+template <class TFixedImage, class TMovingImage>
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::Initialize(void) throw ( ExceptionObject )
+{
+  this->Superclass::Initialize();
+
+  // Cache the number of transformation parameters
+  m_NumberOfParameters = this->m_Transform->GetNumberOfParameters();
+
+  /**
+   * Compute the minimum and maximum for the FixedImage over
+   * the FixedImageRegion.
+   *
+   * NB: We can't use StatisticsImageFilter to do this because
+   * the filter computes the min/max for the largest possible region
+   */
+  double fixedImageMin = NumericTraits<double>::max();
+  double fixedImageMax = NumericTraits<double>::NonpositiveMin();
+
+  typedef ImageRegionConstIterator<FixedImageType> FixedIteratorType;
+  FixedIteratorType fixedImageIterator(
+    this->m_FixedImage, this->GetFixedImageRegion() );
+
+  for ( fixedImageIterator.GoToBegin();
+        !fixedImageIterator.IsAtEnd(); ++fixedImageIterator ) {
+
+    double sample = static_cast<double>( fixedImageIterator.Get() );
+
+    if ( sample < fixedImageMin ) {
+      fixedImageMin = sample;
+    }
+
+    if ( sample > fixedImageMax ) {
+      fixedImageMax = sample;
+    }
+  }
+
+
+  /**
+   * Compute the minimum and maximum for the entire moving image
+   * in the buffer.
+   */
+  double movingImageMin = NumericTraits<double>::max();
+  double movingImageMax = NumericTraits<double>::NonpositiveMin();
+
+  typedef ImageRegionConstIterator<MovingImageType> MovingIteratorType;
+  MovingIteratorType movingImageIterator(
+    this->m_MovingImage, this->m_MovingImage->GetBufferedRegion() );
+
+  for ( movingImageIterator.GoToBegin();
+        !movingImageIterator.IsAtEnd(); ++movingImageIterator) {
+    double sample = static_cast<double>( movingImageIterator.Get() );
+
+    if ( sample < movingImageMin ) {
+      movingImageMin = sample;
+    }
+
+    if ( sample > movingImageMax ) {
+      movingImageMax = sample;
+    }
+  }
+
+  m_MovingImageTrueMin = movingImageMin;
+  m_MovingImageTrueMax = movingImageMax;
+
+  itkDebugMacro( " FixedImageMin: " << fixedImageMin <<
+                 " FixedImageMax: " << fixedImageMax << std::endl );
+  itkDebugMacro( " MovingImageMin: " << movingImageMin <<
+                 " MovingImageMax: " << movingImageMax << std::endl );
+
+
+  /**
+   * Compute binsize for the histograms.
+   *
+   * The binsize for the image intensities needs to be adjusted so that
+   * we can avoid dealing with boundary conditions using the cubic
+   * spline as the Parzen window.  We do this by increasing the size
+   * of the bins so that the joint histogram becomes "padded" at the
+   * borders. Because we are changing the binsize,
+   * we also need to shift the minimum by the padded amount in order to
+   * avoid minimum values filling in our padded region.
+   *
+   * Note that there can still be non-zero bin values in the padded region,
+   * it's just that these bins will never be a central bin for the Parzen
+   * window.
+   *
+   */
+  const int padding = 2;  // this will pad by 2 bins
+
+  m_FixedImageBinSize = ( fixedImageMax - fixedImageMin ) /
+                        static_cast<double>( m_NumberOfHistogramBins - 2 * padding );
+  m_FixedImageNormalizedMin = fixedImageMin / m_FixedImageBinSize -
+                              static_cast<double>( padding );
+
+  m_MovingImageBinSize = ( movingImageMax - movingImageMin ) /
+                         static_cast<double>( m_NumberOfHistogramBins - 2 * padding );
+  m_MovingImageNormalizedMin = movingImageMin / m_MovingImageBinSize -
+                               static_cast<double>( padding );
+
+
+  itkDebugMacro( "FixedImageNormalizedMin: " << m_FixedImageNormalizedMin );
+  itkDebugMacro( "MovingImageNormalizedMin: " << m_MovingImageNormalizedMin );
+  itkDebugMacro( "FixedImageBinSize: " << m_FixedImageBinSize );
+  itkDebugMacro( "MovingImageBinSize; " << m_MovingImageBinSize );
+
+  if( m_UseAllPixels ) {
+    m_NumberOfSpatialSamples =
+      this->GetFixedImageRegion().GetNumberOfPixels();
+  }
+
+  /**
+   * Allocate memory for the fixed image sample container.
+   */
+  m_FixedImageSamples.resize( m_NumberOfSpatialSamples );
+
+
+  /**
+   * Allocate memory for the marginal PDF and initialize values
+   * to zero. The marginal PDFs are stored as std::vector.
+   */
+  m_FixedImageMarginalPDF.resize( m_NumberOfHistogramBins, 0.0 );
+  m_MovingImageMarginalPDF.resize( m_NumberOfHistogramBins, 0.0 );
+
+  /**
+   * Allocate memory for the joint PDF and joint PDF derivatives.
+   * The joint PDF and joint PDF derivatives are store as itk::Image.
+   */
+  m_JointPDF = JointPDFType::New();
+
+  // Instantiate a region, index, size
+  JointPDFRegionType            jointPDFRegion;
+  JointPDFIndexType              jointPDFIndex;
+  JointPDFSizeType              jointPDFSize;
+
+  // Deallocate the memory that may have been allocated for
+  // previous runs of the metric.
+  this->m_JointPDFDerivatives = NULL;  // by destroying the dynamic array
+  this->m_PRatioArray.SetSize( 1, 1 ); // and by allocating very small the static ones
+  this->m_MetricDerivative = DerivativeType( 1 );
+
+  //
+  // Now allocate memory according to the user-selected method.
+  //
+  if( this->m_UseExplicitPDFDerivatives ) {
+    this->m_JointPDFDerivatives = JointPDFDerivativesType::New();
+    JointPDFDerivativesRegionType  jointPDFDerivativesRegion;
+    JointPDFDerivativesIndexType  jointPDFDerivativesIndex;
+    JointPDFDerivativesSizeType    jointPDFDerivativesSize;
+
+    // For the derivatives of the joint PDF define a region starting from {0,0,0}
+    // with size {m_NumberOfParameters,m_NumberOfHistogramBins,
+    // m_NumberOfHistogramBins}. The dimension represents transform parameters,
+    // fixed image parzen window index and moving image parzen window index,
+    // respectively.
+    jointPDFDerivativesIndex.Fill( 0 );
+    jointPDFDerivativesSize[0] = m_NumberOfParameters;
+    jointPDFDerivativesSize[1] = m_NumberOfHistogramBins;
+    jointPDFDerivativesSize[2] = m_NumberOfHistogramBins;
+
+    jointPDFDerivativesRegion.SetIndex( jointPDFDerivativesIndex );
+    jointPDFDerivativesRegion.SetSize( jointPDFDerivativesSize );
+
+    // Set the regions and allocate
+    m_JointPDFDerivatives->SetRegions( jointPDFDerivativesRegion );
+    m_JointPDFDerivatives->Allocate();
+  } else {
+    /** Allocate memory for helper array that will contain the pRatios
+     *  for each bin of the joint histogram. This is part of the effort
+     *  for flattening the computation of the PDF Jacobians.
+     */
+    this->m_PRatioArray.SetSize( this->m_NumberOfHistogramBins, this->m_NumberOfHistogramBins );
+    this->m_MetricDerivative = DerivativeType( this->GetNumberOfParameters() );
+  }
+
+  // For the joint PDF define a region starting from {0,0}
+  // with size {m_NumberOfHistogramBins, m_NumberOfHistogramBins}.
+  // The dimension represents fixed image parzen window index
+  // and moving image parzen window index, respectively.
+  jointPDFIndex.Fill( 0 );
+  jointPDFSize.Fill( m_NumberOfHistogramBins );
+
+  jointPDFRegion.SetIndex( jointPDFIndex );
+  jointPDFRegion.SetSize( jointPDFSize );
+
+  // Set the regions and allocate
+  m_JointPDF->SetRegions( jointPDFRegion );
+  m_JointPDF->Allocate();
+
+
+  /**
+   * Setup the kernels used for the Parzen windows.
+   */
+  m_CubicBSplineKernel = CubicBSplineFunctionType::New();
+  m_CubicBSplineDerivativeKernel = CubicBSplineDerivativeFunctionType::New();
+
+
+  if( m_UseAllPixels ) {
+    /**
+     * Take all the pixels within the fixed image region)
+     * to create the sample points list.
+     */
+    this->SampleFullFixedImageDomain( m_FixedImageSamples );
+  } else {
+    /**
+     * Uniformly sample the fixed image (within the fixed image region)
+     * to create the sample points list.
+     */
+    this->SampleFixedImageDomain( m_FixedImageSamples );
+  }
+
+  /**
+   * Pre-compute the fixed image parzen window index for
+   * each point of the fixed image sample points list.
+   */
+  this->ComputeFixedImageParzenWindowIndices( m_FixedImageSamples );
+
+  /**
+   * Check if the interpolator is of type BSplineInterpolateImageFunction.
+   * If so, we can make use of its EvaluateDerivatives method.
+   * Otherwise, we instantiate an external central difference
+   * derivative calculator.
+   *
+   * TODO: Also add it the possibility of using the default gradient
+   * provided by the superclass.
+   *
+   */
+  m_InterpolatorIsBSpline = true;
+
+  BSplineInterpolatorType * testPtr = dynamic_cast<BSplineInterpolatorType *>(
+                                        this->m_Interpolator.GetPointer() );
+  if ( !testPtr ) {
+    m_InterpolatorIsBSpline = false;
+
+    m_DerivativeCalculator = DerivativeFunctionType::New();
+
+#ifdef ITK_USE_ORIENTED_IMAGE_DIRECTION
+    m_DerivativeCalculator->UseImageDirectionOn();
+#endif
+
+    m_DerivativeCalculator->SetInputImage( this->m_MovingImage );
+
+    m_BSplineInterpolator = NULL;
+    itkDebugMacro( "Interpolator is not BSpline" );
+  } else {
+    m_BSplineInterpolator = testPtr;
+
+#ifdef ITK_USE_ORIENTED_IMAGE_DIRECTION
+    m_BSplineInterpolator->UseImageDirectionOn();
+#endif
+
+    m_DerivativeCalculator = NULL;
+    itkDebugMacro( "Interpolator is BSpline" );
+  }
+
+  /**
+   * Check if the transform is of type BSplineDeformableTransform.
+   *
+   * If so, several speed up features are implemented.
+   * [1] Precomputing the results of bulk transform for each sample point.
+   * [2] Precomputing the BSpline weights for each sample point,
+   *     to be used later to directly compute the deformation vector
+   * [3] Precomputing the indices of the parameters within the
+   *     the support region of each sample point.
+   */
+  m_TransformIsBSpline = true;
+
+  BSplineTransformType * testPtr2 = dynamic_cast<BSplineTransformType *>(
+                                      this->m_Transform.GetPointer() );
+  if( !testPtr2 ) {
+    m_TransformIsBSpline = false;
+    m_BSplineTransform = NULL;
+    itkDebugMacro( "Transform is not BSplineDeformable" );
+  } else {
+    m_BSplineTransform = testPtr2;
+    m_NumParametersPerDim =
+      m_BSplineTransform->GetNumberOfParametersPerDimension();
+    m_NumBSplineWeights = m_BSplineTransform->GetNumberOfWeights();
+    itkDebugMacro( "Transform is BSplineDeformable" );
+  }
+
+  if( this->m_TransformIsBSpline ) {
+    // First, deallocate memory that may have been used from previous run of the Metric
+    this->m_BSplineTransformWeightsArray.SetSize( 1, 1 );
+    this->m_BSplineTransformIndicesArray.SetSize( 1, 1 );
+    this->m_PreTransformPointsArray.resize( 1 );
+    this->m_WithinSupportRegionArray.resize( 1 );
+    this->m_Weights.SetSize( 1 );
+    this->m_Indices.SetSize( 1 );
+
+
+    if( this->m_UseCachingOfBSplineWeights ) {
+      m_BSplineTransformWeightsArray.SetSize(
+        m_NumberOfSpatialSamples, m_NumBSplineWeights );
+      m_BSplineTransformIndicesArray.SetSize(
+        m_NumberOfSpatialSamples, m_NumBSplineWeights );
+      m_PreTransformPointsArray.resize( m_NumberOfSpatialSamples );
+      m_WithinSupportRegionArray.resize( m_NumberOfSpatialSamples );
+
+      this->PreComputeTransformValues();
+    } else {
+      this->m_Weights.SetSize( this->m_NumBSplineWeights );
+      this->m_Indices.SetSize( this->m_NumBSplineWeights );
+    }
+
+    for ( unsigned int j = 0; j < FixedImageDimension; j++ ) {
+      m_ParametersOffset[j] = j *
+                              m_BSplineTransform->GetNumberOfParametersPerDimension();
+    }
+  }
+
+}
+
+
+/**
+ * Uniformly sample the fixed image domain using a random walk
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::SampleFixedImageDomain( FixedImageSpatialSampleContainer& samples )
+{
+
+  // Set up a random interator within the user specified fixed image region.
+  typedef ImageRandomConstIteratorWithIndex<FixedImageType> RandomIterator;
+  RandomIterator randIter( this->m_FixedImage, this->GetFixedImageRegion() );
+
+  randIter.SetNumberOfSamples( m_NumberOfSpatialSamples );
+  randIter.GoToBegin();
+
+  typename FixedImageSpatialSampleContainer::iterator iter;
+  typename FixedImageSpatialSampleContainer::const_iterator end=samples.end();
+
+  if( this->m_FixedImageMask ) {
+
+    InputPointType inputPoint;
+
+    iter=samples.begin();
+    int count = 0;
+    int samples_found = 0;
+    int maxcount = m_NumberOfSpatialSamples * 10;
+    while( iter != end ) {
+
+      if ( count > maxcount ) {
+#if 0
+        itkExceptionMacro(
+          "Drew too many samples from the mask (is it too small?): "
+          << maxcount << std::endl );
+#else
+samples.resize(samples_found);
+//        this->SetNumberOfSpatialSamples(sample_found);
+break;
+#endif
+      }
+      count++;
+
+      // Get sampled index
+      FixedImageIndexType index = randIter.GetIndex();
+      // Check if the Index is inside the mask, translate index to point
+      this->m_FixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+      // If not inside the mask, ignore the point
+      if( !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+        ++randIter; // jump to another random position
+        continue;
+      }
+
+      // Get sampled fixed image value
+      (*iter).FixedImageValue = randIter.Get();
+      // Translate index to point
+      (*iter).FixedImagePointValue = inputPoint;
+      samples_found++;
+      // Jump to random position
+      ++randIter;
+      ++iter;
+    }
+  } else {
+    for( iter=samples.begin(); iter != end; ++iter ) {
+      // Get sampled index
+      FixedImageIndexType index = randIter.GetIndex();
+      // Get sampled fixed image value
+      (*iter).FixedImageValue = randIter.Get();
+      // Translate index to point
+      this->m_FixedImage->TransformIndexToPhysicalPoint( index,
+          (*iter).FixedImagePointValue );
+      // Jump to random position
+      ++randIter;
+
+    }
+  }
+}
+
+/**
+ * Sample the fixed image domain using all pixels in the Fixed image region
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::SampleFullFixedImageDomain( FixedImageSpatialSampleContainer& samples )
+{
+
+  // Set up a region interator within the user specified fixed image region.
+  typedef ImageRegionConstIteratorWithIndex<FixedImageType> RegionIterator;
+  RegionIterator regionIter( this->m_FixedImage, this->GetFixedImageRegion() );
+
+  regionIter.GoToBegin();
+
+  typename FixedImageSpatialSampleContainer::iterator iter;
+  typename FixedImageSpatialSampleContainer::const_iterator end=samples.end();
+
+  if( this->m_FixedImageMask ) {
+    InputPointType inputPoint;
+
+    iter=samples.begin();
+    unsigned long nSamplesPicked = 0;
+
+    while( iter != end && !regionIter.IsAtEnd() ) {
+      // Get sampled index
+      FixedImageIndexType index = regionIter.GetIndex();
+      // Check if the Index is inside the mask, translate index to point
+      this->m_FixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+      // If not inside the mask, ignore the point
+      if( !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+        ++regionIter; // jump to next pixel
+        continue;
+      }
+
+      // Get sampled fixed image value
+      (*iter).FixedImageValue = regionIter.Get();
+      // Translate index to point
+      (*iter).FixedImagePointValue = inputPoint;
+
+      ++regionIter;
+      ++iter;
+      ++nSamplesPicked;
+    }
+
+    // If we picked fewer samples than the desired number,
+    // resize the container
+    if (nSamplesPicked != this->m_NumberOfSpatialSamples) {
+      this->m_NumberOfSpatialSamples = nSamplesPicked;
+      samples.resize(this->m_NumberOfSpatialSamples);
+    }
+  } else { // not restricting sample throwing to a mask
+
+    // cannot sample more than the number of pixels in the image region
+    if (  this->m_NumberOfSpatialSamples
+          > this->GetFixedImageRegion().GetNumberOfPixels()) {
+      this->m_NumberOfSpatialSamples
+      = this->GetFixedImageRegion().GetNumberOfPixels();
+      samples.resize(this->m_NumberOfSpatialSamples);
+    }
+
+    for( iter=samples.begin(); iter != end; ++iter ) {
+      // Get sampled index
+      FixedImageIndexType index = regionIter.GetIndex();
+      // Get sampled fixed image value
+      (*iter).FixedImageValue = regionIter.Get();
+      // Translate index to point
+      this->m_FixedImage->TransformIndexToPhysicalPoint( index,
+          (*iter).FixedImagePointValue );
+      ++regionIter;
+    }
+  }
+}
+
+/**
+ * Uniformly sample the fixed image domain using a random walk
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ComputeFixedImageParzenWindowIndices(
+  FixedImageSpatialSampleContainer& samples )
+{
+
+  typename FixedImageSpatialSampleContainer::iterator iter;
+  typename FixedImageSpatialSampleContainer::const_iterator end=samples.end();
+
+  for( iter=samples.begin(); iter != end; ++iter ) {
+
+    // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
+    double windowTerm =
+      static_cast<double>( (*iter).FixedImageValue ) / m_FixedImageBinSize -
+      m_FixedImageNormalizedMin;
+    unsigned int pindex = static_cast<unsigned int>( vcl_floor(windowTerm ) );
+
+    // Make sure the extreme values are in valid bins
+    if ( pindex < 2 ) {
+      pindex = 2;
+    } else if ( pindex > (m_NumberOfHistogramBins - 3) ) {
+      pindex = m_NumberOfHistogramBins - 3;
+    }
+
+    (*iter).FixedImageParzenWindowIndex = pindex;
+
+  }
+
+}
+
+/**
+ * Get the match Measure
+ */
+template < class TFixedImage, class TMovingImage  >
+typename MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeasureType
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValue( const ParametersType& parameters ) const
+{
+
+  // Reset marginal pdf to all zeros.
+  // Assumed the size has already been set to NumberOfHistogramBins
+  // in Initialize().
+  for ( unsigned int j = 0; j < m_NumberOfHistogramBins; j++ ) {
+    m_FixedImageMarginalPDF[j]  = 0.0;
+    m_MovingImageMarginalPDF[j] = 0.0;
+  }
+
+  // Reset the joint pdfs to zero
+  m_JointPDF->FillBuffer( 0.0 );
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+
+
+  // Declare iterators for iteration over the sample container
+  typename FixedImageSpatialSampleContainer::const_iterator fiter;
+  typename FixedImageSpatialSampleContainer::const_iterator fend =
+    m_FixedImageSamples.end();
+
+  unsigned long nSamples=0;
+  unsigned long nFixedImageSamples=0;
+
+
+  for ( fiter = m_FixedImageSamples.begin(); fiter != fend; ++fiter ) {
+
+    // Get moving image value
+    MovingImagePointType mappedPoint;
+    bool sampleOk;
+    double movingImageValue;
+
+    this->TransformPoint( nFixedImageSamples, parameters, mappedPoint,
+                          sampleOk, movingImageValue );
+
+    ++nFixedImageSamples;
+
+    if( sampleOk ) {
+
+      ++nSamples;
+
+      /**
+       * Compute this sample's contribution to the marginal and
+       * joint distributions.
+       *
+       */
+
+      // Determine parzen window arguments (see eqn 6 of Mattes paper [2])
+      double movingImageParzenWindowTerm =
+        movingImageValue / m_MovingImageBinSize - m_MovingImageNormalizedMin;
+      unsigned int movingImageParzenWindowIndex =
+        static_cast<unsigned int>( vcl_floor(movingImageParzenWindowTerm ) );
+
+      // Make sure the extreme values are in valid bins
+      if ( movingImageParzenWindowIndex < 2 ) {
+        movingImageParzenWindowIndex = 2;
+      } else if ( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
+        movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
+      }
+
+
+      // Since a zero-order BSpline (box car) kernel is used for
+      // the fixed image marginal pdf, we need only increment the
+      // fixedImageParzenWindowIndex by value of 1.0.
+      m_FixedImageMarginalPDF[(*fiter).FixedImageParzenWindowIndex] +=
+        static_cast<PDFValueType>( 1 );
+
+      /**
+       * The region of support of the parzen window determines which bins
+       * of the joint PDF are effected by the pair of image values.
+       * Since we are using a cubic spline for the moving image parzen
+       * window, four bins are affected.  The fixed image parzen window is
+       * a zero-order spline (box car) and thus effects only one bin.
+       *
+       *  The PDF is arranged so that moving image bins corresponds to the
+       * zero-th (column) dimension and the fixed image bins corresponds
+       * to the first (row) dimension.
+       *
+       */
+
+      // Pointer to affected bin to be updated
+      JointPDFValueType *pdfPtr = m_JointPDF->GetBufferPointer() +
+                                  ( (*fiter).FixedImageParzenWindowIndex
+                                    * m_JointPDF->GetOffsetTable()[1] );
+
+      // Move the pointer to the first affected bin
+      int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
+      pdfPtr += pdfMovingIndex;
+
+      for (; pdfMovingIndex <= static_cast<int>( movingImageParzenWindowIndex )
+           + 2;
+           pdfMovingIndex++, pdfPtr++ ) {
+
+        // Update PDF for the current intensity pair
+        double movingImageParzenWindowArg =
+          static_cast<double>( pdfMovingIndex ) -
+          static_cast<double>( movingImageParzenWindowTerm );
+
+        *(pdfPtr) += static_cast<PDFValueType>(
+                       m_CubicBSplineKernel->Evaluate( movingImageParzenWindowArg ) );
+
+      }  //end parzen windowing for loop
+
+    } //end if-block check sampleOk
+  } // end iterating over fixed image spatial sample container for loop
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << nSamples << " / " << m_NumberOfSpatialSamples
+                 << std::endl );
+
+  if( nSamples < m_NumberOfSpatialSamples / 16 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << nSamples << " / " << m_NumberOfSpatialSamples
+                       << std::endl );
+  }
+
+  this->m_NumberOfPixelsCounted = nSamples;
+
+
+  /**
+   * Normalize the PDFs, compute moving image marginal PDF
+   *
+   */
+  typedef ImageRegionIterator<JointPDFType> JointPDFIteratorType;
+  JointPDFIteratorType jointPDFIterator ( m_JointPDF,
+                                          m_JointPDF->GetBufferedRegion() );
+
+  jointPDFIterator.GoToBegin();
+
+  // Compute joint PDF normalization factor
+  // (to ensure joint PDF sum adds to 1.0)
+  double jointPDFSum = 0.0;
+
+  while( !jointPDFIterator.IsAtEnd() ) {
+    jointPDFSum += jointPDFIterator.Get();
+    ++jointPDFIterator;
+  }
+
+  if ( jointPDFSum == 0.0 ) {
+    itkExceptionMacro( "Joint PDF summed to zero" );
+  }
+
+
+  // Normalize the PDF bins
+  jointPDFIterator.GoToEnd();
+  while( !jointPDFIterator.IsAtBegin() ) {
+    --jointPDFIterator;
+    jointPDFIterator.Value() /= static_cast<PDFValueType>( jointPDFSum );
+  }
+
+
+  // Normalize the fixed image marginal PDF
+  double fixedPDFSum = 0.0;
+  for( unsigned int bin = 0; bin < m_NumberOfHistogramBins; bin++ ) {
+    fixedPDFSum += m_FixedImageMarginalPDF[bin];
+  }
+
+  if ( fixedPDFSum == 0.0 ) {
+    itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
+  }
+
+  for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
+    m_FixedImageMarginalPDF[bin] /= static_cast<PDFValueType>( fixedPDFSum );
+  }
+
+
+  // Compute moving image marginal PDF by summing over fixed image bins.
+  typedef ImageLinearIteratorWithIndex<JointPDFType> JointPDFLinearIterator;
+  JointPDFLinearIterator linearIter( m_JointPDF,
+                                     m_JointPDF->GetBufferedRegion() );
+
+  linearIter.SetDirection( 1 );
+  linearIter.GoToBegin();
+  unsigned int movingIndex1 = 0;
+
+  while( !linearIter.IsAtEnd() ) {
+
+    double sum = 0.0;
+
+    while( !linearIter.IsAtEndOfLine() ) {
+      sum += linearIter.Get();
+      ++linearIter;
+    }
+
+    m_MovingImageMarginalPDF[movingIndex1] = static_cast<PDFValueType>(sum);
+
+    linearIter.NextLine();
+    ++movingIndex1;
+
+  }
+
+  /**
+   * Compute the metric by double summation over histogram.
+   */
+
+  // Setup pointer to point to the first bin
+  JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
+
+  // Initialze sum to zero
+  double sum = 0.0;
+
+  for( unsigned int fixedIndex = 0;
+       fixedIndex < m_NumberOfHistogramBins;
+       ++fixedIndex ) {
+
+    double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
+
+    for( unsigned int movingIndex = 0;
+         movingIndex < m_NumberOfHistogramBins;
+         ++movingIndex, jointPDFPtr++ ) {
+
+      double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
+      double jointPDFValue = *(jointPDFPtr);
+
+      // check for non-zero bin contribution
+      if( jointPDFValue > 1e-16 &&  movingImagePDFValue > 1e-16 ) {
+
+        double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
+        if( fixedImagePDFValue > 1e-16) {
+          sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
+        }
+
+      }  // end if-block to check non-zero bin contribution
+    }  // end for-loop over moving index
+  }  // end for-loop over fixed index
+
+  return static_cast<MeasureType>( -1.0 * sum );
+
+}
+
+
+/**
+ * Get the both Value and Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivative(
+  const ParametersType& parameters,
+  MeasureType& value,
+  DerivativeType& derivative) const
+{
+
+  // Set output values to zero
+  value = NumericTraits< MeasureType >::Zero;
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    m_JointPDFDerivatives->FillBuffer( 0.0 );
+    derivative = DerivativeType( this->GetNumberOfParameters() );
+    derivative.Fill( NumericTraits< MeasureType >::Zero );
+  } else {
+    this->m_MetricDerivative.Fill( NumericTraits< MeasureType >::Zero );
+    this->m_PRatioArray.Fill( 0.0 );
+  }
+
+  // Reset marginal pdf to all zeros.
+  // Assumed the size has already been set to NumberOfHistogramBins
+  // in Initialize().
+  for ( unsigned int j = 0; j < m_NumberOfHistogramBins; j++ ) {
+    m_FixedImageMarginalPDF[j]  = 0.0;
+    m_MovingImageMarginalPDF[j] = 0.0;
+  }
+
+  // Reset the joint pdfs to zero
+  m_JointPDF->FillBuffer( 0.0 );
+
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+
+
+  // Declare iterators for iteration over the sample container
+  typename FixedImageSpatialSampleContainer::const_iterator fiter;
+  typename FixedImageSpatialSampleContainer::const_iterator fend =
+    m_FixedImageSamples.end();
+
+  unsigned long nSamples=0;
+  unsigned long nFixedImageSamples=0;
+
+  for ( fiter = m_FixedImageSamples.begin(); fiter != fend; ++fiter ) {
+
+    // Get moving image value
+    MovingImagePointType mappedPoint;
+    bool sampleOk;
+    double movingImageValue;
+
+
+    this->TransformPoint( nFixedImageSamples, parameters, mappedPoint,
+                          sampleOk, movingImageValue );
+
+    if( sampleOk ) {
+      ++nSamples;
+
+      // Get moving image derivative at the mapped position
+      ImageDerivativesType movingImageGradientValue;
+      this->ComputeImageDerivatives( mappedPoint, movingImageGradientValue );
+
+
+      /**
+       * Compute this sample's contribution to the marginal
+       *   and joint distributions.
+       *
+       */
+
+      // Determine parzen window arguments (see eqn 6 of Mattes paper [2])
+      double movingImageParzenWindowTerm =
+        movingImageValue / m_MovingImageBinSize - m_MovingImageNormalizedMin;
+      unsigned int movingImageParzenWindowIndex =
+        static_cast<unsigned int>( vcl_floor(movingImageParzenWindowTerm ) );
+
+      // Make sure the extreme values are in valid bins
+      if ( movingImageParzenWindowIndex < 2 ) {
+        movingImageParzenWindowIndex = 2;
+      } else if ( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
+        movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
+      }
+
+
+      // Since a zero-order BSpline (box car) kernel is used for
+      // the fixed image marginal pdf, we need only increment the
+      // fixedImageParzenWindowIndex by value of 1.0.
+      m_FixedImageMarginalPDF[(*fiter).FixedImageParzenWindowIndex] +=
+        static_cast<PDFValueType>( 1 );
+
+      /**
+       * The region of support of the parzen window determines which bins
+       * of the joint PDF are effected by the pair of image values.
+       * Since we are using a cubic spline for the moving image parzen
+       * window, four bins are effected.  The fixed image parzen window is
+       * a zero-order spline (box car) and thus effects only one bin.
+       *
+       *  The PDF is arranged so that moving image bins corresponds to the
+       * zero-th (column) dimension and the fixed image bins corresponds
+       * to the first (row) dimension.
+       *
+       */
+
+      // Pointer to affected bin to be updated
+      JointPDFValueType *pdfPtr = m_JointPDF->GetBufferPointer() +
+                                  ( (*fiter).FixedImageParzenWindowIndex * m_NumberOfHistogramBins );
+
+      // Move the pointer to the fist affected bin
+      int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
+      pdfPtr += pdfMovingIndex;
+
+      for (; pdfMovingIndex <= static_cast<int>( movingImageParzenWindowIndex )
+           + 2;
+           pdfMovingIndex++, pdfPtr++ ) {
+        // Update PDF for the current intensity pair
+        double movingImageParzenWindowArg =
+          static_cast<double>( pdfMovingIndex ) -
+          static_cast<double>(movingImageParzenWindowTerm);
+
+        *(pdfPtr) += static_cast<PDFValueType>(
+                       m_CubicBSplineKernel->Evaluate( movingImageParzenWindowArg ) );
+
+        if( this->m_UseExplicitPDFDerivatives ) {
+          // Compute the cubicBSplineDerivative for later repeated use.
+          double cubicBSplineDerivativeValue =
+            m_CubicBSplineDerivativeKernel->Evaluate(
+              movingImageParzenWindowArg );
+
+          // Compute PDF derivative contribution.
+          this->ComputePDFDerivatives( nFixedImageSamples,
+                                       pdfMovingIndex,
+                                       movingImageGradientValue,
+                                       cubicBSplineDerivativeValue );
+        }
+
+      }  //end parzen windowing for loop
+
+    } //end if-block check sampleOk
+
+    ++nFixedImageSamples;
+
+  } // end iterating over fixed image spatial sample container for loop
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << nSamples << " / " << m_NumberOfSpatialSamples
+                 << std::endl );
+
+  if( nSamples < m_NumberOfSpatialSamples / 16 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << nSamples << " / " << m_NumberOfSpatialSamples
+                       << std::endl );
+  }
+
+  this->m_NumberOfPixelsCounted = nSamples;
+
+  /**
+   * Normalize the PDFs, compute moving image marginal PDF
+   *
+   */
+  typedef ImageRegionIterator<JointPDFType> JointPDFIteratorType;
+  JointPDFIteratorType jointPDFIterator ( m_JointPDF,
+                                          m_JointPDF->GetBufferedRegion() );
+
+  jointPDFIterator.GoToBegin();
+
+
+  // Compute joint PDF normalization factor
+  // (to ensure joint PDF sum adds to 1.0)
+  double jointPDFSum = 0.0;
+
+  while( !jointPDFIterator.IsAtEnd() ) {
+    jointPDFSum += jointPDFIterator.Get();
+    ++jointPDFIterator;
+  }
+
+  if ( jointPDFSum == 0.0 ) {
+    itkExceptionMacro( "Joint PDF summed to zero" );
+  }
+
+
+  // Normalize the PDF bins
+  jointPDFIterator.GoToEnd();
+  while( !jointPDFIterator.IsAtBegin() ) {
+    --jointPDFIterator;
+    jointPDFIterator.Value() /= static_cast<PDFValueType>( jointPDFSum );
+  }
+
+
+  // Normalize the fixed image marginal PDF
+  double fixedPDFSum = 0.0;
+  for( unsigned int bin = 0; bin < m_NumberOfHistogramBins; bin++ ) {
+    fixedPDFSum += m_FixedImageMarginalPDF[bin];
+  }
+
+  if ( fixedPDFSum == 0.0 ) {
+    itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
+  }
+
+  for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
+    m_FixedImageMarginalPDF[bin] /= static_cast<PDFValueType>( fixedPDFSum );
+  }
+
+
+  // Compute moving image marginal PDF by summing over fixed image bins.
+  typedef ImageLinearIteratorWithIndex<JointPDFType> JointPDFLinearIterator;
+  JointPDFLinearIterator linearIter(
+    m_JointPDF, m_JointPDF->GetBufferedRegion() );
+
+  linearIter.SetDirection( 1 );
+  linearIter.GoToBegin();
+  unsigned int movingIndex1 = 0;
+
+  while( !linearIter.IsAtEnd() ) {
+
+    double sum = 0.0;
+
+    while( !linearIter.IsAtEndOfLine() ) {
+      sum += linearIter.Get();
+      ++linearIter;
+    }
+
+    m_MovingImageMarginalPDF[movingIndex1] = static_cast<PDFValueType>(sum);
+
+    linearIter.NextLine();
+    ++movingIndex1;
+
+  }
+
+  double nFactor = 1.0 / ( m_MovingImageBinSize
+                           * static_cast<double>( nSamples ) );
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    // Normalize the joint PDF derivatives by the test image binsize and nSamples
+    typedef ImageRegionIterator<JointPDFDerivativesType>
+    JointPDFDerivativesIteratorType;
+    JointPDFDerivativesIteratorType jointPDFDerivativesIterator (
+      m_JointPDFDerivatives,
+      m_JointPDFDerivatives->GetBufferedRegion()
+    );
+
+    jointPDFDerivativesIterator.GoToBegin();
+
+    while( !jointPDFDerivativesIterator.IsAtEnd() ) {
+      jointPDFDerivativesIterator.Value() *= nFactor;
+      ++jointPDFDerivativesIterator;
+    }
+  }
+
+  /**
+   * Compute the metric by double summation over histogram.
+   */
+
+  // Setup pointer to point to the first bin
+  JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
+
+  // Initialize sum to zero
+  double sum = 0.0;
+
+  for( unsigned int fixedIndex = 0;
+       fixedIndex < m_NumberOfHistogramBins;
+       ++fixedIndex ) {
+    double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
+
+    for( unsigned int movingIndex = 0; movingIndex < m_NumberOfHistogramBins;
+         ++movingIndex, jointPDFPtr++ ) {
+      double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
+      double jointPDFValue = *(jointPDFPtr);
+
+      // check for non-zero bin contribution
+      if( jointPDFValue > 1e-16 &&  movingImagePDFValue > 1e-16 ) {
+
+        double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
+
+        if( fixedImagePDFValue > 1e-16) {
+          sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
+        }
+
+        if( this->m_UseExplicitPDFDerivatives ) {
+          // move joint pdf derivative pointer to the right position
+          JointPDFValueType * derivPtr = m_JointPDFDerivatives->GetBufferPointer()
+                                         + ( fixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
+                                         + ( movingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
+
+          for( unsigned int parameter=0; parameter < m_NumberOfParameters; ++parameter, derivPtr++ ) {
+            // Ref: eqn 23 of Thevenaz & Unser paper [3]
+            derivative[parameter] -= (*derivPtr) * pRatio;
+          }  // end for-loop over parameters
+        } else {
+          this->m_PRatioArray[fixedIndex][movingIndex] = pRatio * nFactor;
+        }
+      }  // end if-block to check non-zero bin contribution
+    }  // end for-loop over moving index
+  }  // end for-loop over fixed index
+
+  if( !(this->m_UseExplicitPDFDerivatives ) ) {
+    // Second pass: This one is done for accumulating the contributions
+    //              to the derivative array.
+
+    nFixedImageSamples = 0;
+
+    for ( fiter = m_FixedImageSamples.begin(); fiter != fend; ++fiter ) {
+
+      // Get moving image value
+      MovingImagePointType mappedPoint;
+      bool sampleOk;
+      double movingImageValue;
+
+      this->TransformPoint( nFixedImageSamples, parameters, mappedPoint,
+                            sampleOk, movingImageValue );
+
+      if( sampleOk ) {
+        // Get moving image derivative at the mapped position
+        ImageDerivativesType movingImageGradientValue;
+        this->ComputeImageDerivatives( mappedPoint, movingImageGradientValue );
+
+
+        /**
+         * Compute this sample's contribution to the marginal
+         *   and joint distributions.
+         *
+         */
+
+        // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
+        double movingImageParzenWindowTerm =
+          movingImageValue / m_MovingImageBinSize - m_MovingImageNormalizedMin;
+        unsigned int movingImageParzenWindowIndex =
+          static_cast<unsigned int>( vcl_floor(movingImageParzenWindowTerm ) );
+
+        // Make sure the extreme values are in valid bins
+        if ( movingImageParzenWindowIndex < 2 ) {
+          movingImageParzenWindowIndex = 2;
+        } else if ( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
+          movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
+        }
+
+
+        // Move the pointer to the fist affected bin
+        int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
+
+        for (; pdfMovingIndex <= static_cast<int>( movingImageParzenWindowIndex )
+             + 2;
+             pdfMovingIndex++ ) {
+
+          // Update PDF for the current intensity pair
+          double movingImageParzenWindowArg =
+            static_cast<double>( pdfMovingIndex ) -
+            static_cast<double>(movingImageParzenWindowTerm);
+
+          // Compute the cubicBSplineDerivative for later repeated use.
+          double cubicBSplineDerivativeValue =
+            m_CubicBSplineDerivativeKernel->Evaluate(
+              movingImageParzenWindowArg );
+
+          // Compute PDF derivative contribution.
+          this->ComputePDFDerivatives( nFixedImageSamples,
+                                       pdfMovingIndex,
+                                       movingImageGradientValue,
+                                       cubicBSplineDerivativeValue );
+
+
+        }  //end parzen windowing for loop
+
+      } //end if-block check sampleOk
+
+      ++nFixedImageSamples;
+
+    } // end iterating over fixed image spatial sample container for loop
+
+
+    derivative = this->m_MetricDerivative;
+  }
+
+  value = static_cast<MeasureType>( -1.0 * sum );
+}
+
+
+/**
+ * Get the match measure derivative
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetDerivative( const ParametersType& parameters,
+                 DerivativeType & derivative ) const
+{
+  MeasureType value;
+  // call the combined version
+  this->GetValueAndDerivative( parameters, value, derivative );
+}
+
+
+/**
+ * Compute image derivatives using a central difference function
+ * if we are not using a BSplineInterpolator, which includes
+ * derivatives.
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ComputeImageDerivatives(
+  const MovingImagePointType& mappedPoint,
+  ImageDerivativesType& gradient ) const
+{
+
+  if( m_InterpolatorIsBSpline ) {
+    // Computed moving image gradient using derivative BSpline kernel.
+    gradient = m_BSplineInterpolator->EvaluateDerivative( mappedPoint );
+  } else {
+    // For all generic interpolator use central differencing.
+    gradient = m_DerivativeCalculator->Evaluate( mappedPoint );
+  }
+
+}
+
+
+/**
+ * Transform a point from FixedImage domain to MovingImage domain.
+ * This function also checks if mapped point is within support region.
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::TransformPoint(
+  unsigned int sampleNumber,
+  const ParametersType& parameters,
+  MovingImagePointType& mappedPoint,
+  bool& sampleOk,
+  double& movingImageValue ) const
+{
+
+  if ( !m_TransformIsBSpline ) {
+    // Use generic transform to compute mapped position
+    mappedPoint = this->m_Transform->TransformPoint(
+                    m_FixedImageSamples[sampleNumber].FixedImagePointValue );
+
+    // Check if mapped point inside image buffer
+    sampleOk = this->m_Interpolator->IsInsideBuffer( mappedPoint );
+  } else {
+
+    if( this->m_UseCachingOfBSplineWeights ) {
+      // If the transform is BSplineDeformable, we can use the precomputed
+      // weights and indices to obtained the mapped position
+      //
+      const WeightsValueType * weights =
+        m_BSplineTransformWeightsArray[sampleNumber];
+      const IndexValueType   * indices =
+        m_BSplineTransformIndicesArray[sampleNumber];
+      mappedPoint.Fill( 0.0 );
+
+      if ( m_WithinSupportRegionArray[sampleNumber] ) {
+        for ( unsigned int k = 0; k < m_NumBSplineWeights; k++ ) {
+          for ( unsigned int j = 0; j < FixedImageDimension; j++ ) {
+            mappedPoint[j] += weights[k] *
+                              parameters[ indices[k] + m_ParametersOffset[j] ];
+          }
+        }
+      }
+
+      for( unsigned int j = 0; j < FixedImageDimension; j++ ) {
+        mappedPoint[j] += m_PreTransformPointsArray[sampleNumber][j];
+      }
+
+      // Check if mapped point inside image buffer
+      sampleOk = this->m_Interpolator->IsInsideBuffer( mappedPoint );
+
+      // Check if mapped point is within the support region of a grid point.
+      // This is neccessary for computing the metric gradient
+      sampleOk = sampleOk && m_WithinSupportRegionArray[sampleNumber];
+    } else {
+      // If not caching values, we invoke the Transform to recompute the
+      // mapping of the point.
+      this->m_BSplineTransform->TransformPoint(
+        this->m_FixedImageSamples[sampleNumber].FixedImagePointValue,
+        mappedPoint, this->m_Weights, this->m_Indices, sampleOk);
+
+      // Check if mapped point inside image buffer
+      sampleOk = sampleOk && this->m_Interpolator->IsInsideBuffer( mappedPoint );
+    }
+
+  }
+
+  // If user provided a mask over the Moving image
+  if ( this->m_MovingImageMask ) {
+    // Check if mapped point is within the support region of the moving image
+    // mask
+    sampleOk = sampleOk && this->m_MovingImageMask->IsInside( mappedPoint );
+  }
+
+
+  if ( sampleOk ) {
+    movingImageValue = this->m_Interpolator->Evaluate( mappedPoint );
+
+    if ( movingImageValue < m_MovingImageTrueMin ||
+         movingImageValue > m_MovingImageTrueMax ) {
+      // need to throw out this sample as it will not fall into a valid bin
+      sampleOk = false;
+    }
+  }
+}
+
+
+/**
+ * Compute PDF derivatives contribution for each parameter
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ComputePDFDerivatives(
+  unsigned int sampleNumber,
+  int pdfMovingIndex,
+  const ImageDerivativesType& movingImageGradientValue,
+  double cubicBSplineDerivativeValue ) const
+{
+
+  const int pdfFixedIndex =
+    m_FixedImageSamples[sampleNumber].FixedImageParzenWindowIndex;
+
+  JointPDFValueType * derivPtr = NULL;
+  double precomputedWeight = 0.0;
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    // Update bins in the PDF derivatives for the current intensity pair
+    derivPtr = m_JointPDFDerivatives->GetBufferPointer() +
+               ( pdfFixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] ) +
+               ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
+  } else {
+    // Recover the precomputed weight for this specific PDF bin
+    precomputedWeight = this->m_PRatioArray[pdfFixedIndex][pdfMovingIndex];
+  }
+
+  if( !m_TransformIsBSpline ) {
+
+    /**
+     * Generic version which works for all transforms.
+     */
+
+    // Compute the transform Jacobian.
+    typedef typename TransformType::JacobianType JacobianType;
+    const JacobianType& jacobian =
+      this->m_Transform->GetJacobian(
+        m_FixedImageSamples[sampleNumber].FixedImagePointValue );
+
+    for ( unsigned int mu = 0; mu < m_NumberOfParameters; mu++ ) {
+      double innerProduct = 0.0;
+      for ( unsigned int dim = 0; dim < FixedImageDimension; dim++ ) {
+        innerProduct += jacobian[dim][mu] * movingImageGradientValue[dim];
+      }
+
+      const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
+
+      if( this->m_UseExplicitPDFDerivatives ) {
+        *(derivPtr) -= derivativeContribution;
+        ++derivPtr;
+      } else {
+        this->m_MetricDerivative[mu] += precomputedWeight * derivativeContribution;
+      }
+    }
+
+  } else {
+    const WeightsValueType * weights = NULL;
+    const IndexValueType   * indices = NULL;
+
+    if( this->m_UseCachingOfBSplineWeights ) {
+      /**
+       * If the transform is of type BSplineDeformableTransform,
+       * we can obtain a speed up by only processing the affected parameters.
+       * Note that these pointers are just pointing to pre-allocated rows
+       * of the caching arrays. There is therefore, no need to free this
+       * memory.
+       */
+      weights = m_BSplineTransformWeightsArray[sampleNumber];
+      indices = m_BSplineTransformIndicesArray[sampleNumber];
+    } else {
+      m_BSplineTransform->GetJacobian(
+        m_FixedImageSamples[sampleNumber].FixedImagePointValue, m_Weights, m_Indices );
+    }
+
+    for( unsigned int dim = 0; dim < FixedImageDimension; dim++ ) {
+
+      double innerProduct;
+      int parameterIndex;
+
+      for( unsigned int mu = 0; mu < m_NumBSplineWeights; mu++ ) {
+
+        /* The array weights contains the Jacobian values in a 1-D array
+         * (because for each parameter the Jacobian is non-zero in only 1 of the
+         * possible dimensions) which is multiplied by the moving image
+         * gradient. */
+        if( this->m_UseCachingOfBSplineWeights ) {
+          innerProduct = movingImageGradientValue[dim] * weights[mu];
+          parameterIndex = indices[mu] + m_ParametersOffset[dim];
+        } else {
+          innerProduct = movingImageGradientValue[dim] * this->m_Weights[mu];
+          parameterIndex = this->m_Indices[mu] + this->m_ParametersOffset[dim];
+        }
+
+        const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
+
+        if( this->m_UseExplicitPDFDerivatives ) {
+          JointPDFValueType * ptr = derivPtr + parameterIndex;
+          *(ptr) -= derivativeContribution;
+        } else {
+          this->m_MetricDerivative[parameterIndex] += precomputedWeight * derivativeContribution;
+        }
+
+      } //end mu for loop
+    } //end dim for loop
+
+  } // end if-block transform is BSpline
+
+}
+
+
+// Method to reinitialize the seed of the random number generator
+template < class TFixedImage, class TMovingImage  > void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ReinitializeSeed()
+{
+  Statistics::MersenneTwisterRandomVariateGenerator::GetInstance()->SetSeed();
+}
+
+// Method to reinitialize the seed of the random number generator
+template < class TFixedImage, class TMovingImage  > void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ReinitializeSeed(int seed)
+{
+  Statistics::MersenneTwisterRandomVariateGenerator::GetInstance()->SetSeed(
+    seed);
+}
+
+
+/**
+ * Cache pre-transformed points, weights and indices.
+ * This method is only called if the flag UseCachingOfBSplineWeights is ON.
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::PreComputeTransformValues()
+{
+  // Create all zero dummy transform parameters
+  ParametersType dummyParameters( this->m_Transform->GetNumberOfParameters() );
+  dummyParameters.Fill( 0.0 );
+  this->m_Transform->SetParameters( dummyParameters );
+
+  // Cycle through each sampled fixed image point
+  BSplineTransformWeightsType weights( m_NumBSplineWeights );
+  BSplineTransformIndexArrayType indices( m_NumBSplineWeights );
+  bool valid;
+  MovingImagePointType mappedPoint;
+
+  // Declare iterators for iteration over the sample container
+  typename FixedImageSpatialSampleContainer::const_iterator fiter;
+  typename FixedImageSpatialSampleContainer::const_iterator fend =
+    m_FixedImageSamples.end();
+  unsigned long counter = 0;
+
+  for( fiter = m_FixedImageSamples.begin(); fiter != fend; ++fiter, counter++ ) {
+    m_BSplineTransform->TransformPoint(
+      m_FixedImageSamples[counter].FixedImagePointValue,
+      mappedPoint, weights, indices, valid );
+
+    for( unsigned long k = 0; k < m_NumBSplineWeights; k++ ) {
+      m_BSplineTransformWeightsArray[counter][k] = weights[k];
+      m_BSplineTransformIndicesArray[counter][k] = indices[k];
+    }
+
+    m_PreTransformPointsArray[counter]      = mappedPoint;
+    m_WithinSupportRegionArray[counter]     = valid;
+
+  }
+
+}
+
+
+} // end namespace itk
+
+
+#endif
+
+#endif
diff --git a/registration/itkMeanSquaresImageToImageMetricFor3DBLUTFFD.h b/registration/itkMeanSquaresImageToImageMetricFor3DBLUTFFD.h
new file mode 100644 (file)
index 0000000..17b6379
--- /dev/null
@@ -0,0 +1,151 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkMeanSquaresImageToImageMetricFor3DBLUTFFD.h,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkMeanSquaresImageToImageMetricFor3DBLUTFFD_h
+#define __itkMeanSquaresImageToImageMetricFor3DBLUTFFD_h
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.h"
+#else
+
+#include "itkImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+
+
+namespace itk
+{
+/** \class MeanSquaresImageToImageMetricFor3DBLUTFFD
+ * \brief Computes similarity between two objects to be registered
+ *
+ * This Class is templated over the type of the fixed and moving
+ * images to be compared.
+ *
+ * This metric computes the sum of squared differences between pixels in
+ * the moving image and pixels in the fixed image. The spatial correspondance
+ * between both images is established through a Transform. Pixel values are
+ * taken from the Moving image. Their positions are mapped to the Fixed image
+ * and result in general in non-grid position on it. Values at these non-grid
+ * position of the Fixed image are interpolated using a user-selected Interpolator.
+ *
+ * \ingroup RegistrationMetrics
+ */
+template < class TFixedImage, class TMovingImage >
+class ITK_EXPORT MeanSquaresImageToImageMetricFor3DBLUTFFD :
+  public ImageToImageMetric< TFixedImage, TMovingImage>
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef MeanSquaresImageToImageMetricFor3DBLUTFFD                  Self;
+  typedef ImageToImageMetric<TFixedImage, TMovingImage > Superclass;
+  typedef SmartPointer<Self>                             Pointer;
+  typedef SmartPointer<const Self>                       ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(MeanSquaresImageToImageMetricFor3DBLUTFFD, ImageToImageMetric);
+
+
+  /** Types transferred from the base class */
+  typedef typename Superclass::RealType                 RealType;
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformParametersType  TransformParametersType;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::GradientPixelType        GradientPixelType;
+  typedef typename Superclass::GradientImageType        GradientImageType;
+  typedef typename Superclass::InputPointType           InputPointType;
+  typedef typename Superclass::OutputPointType          OutputPointType;
+
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const TransformParametersType & parameters,
+                      DerivativeType & derivative ) const;
+
+  /**  Get the value for single valued optimizers. */
+  MeasureType GetValue( const TransformParametersType & parameters ) const;
+
+  /**  Get value and derivatives for multiple valued optimizers. */
+  void GetValueAndDerivative( const TransformParametersType & parameters,
+                              MeasureType& Value, DerivativeType& Derivative ) const;
+
+#ifdef ITK_USE_CONCEPT_CHECKING
+  /** Begin concept checking */
+  itkConceptMacro(MovingPixelTypeHasNumericTraitsCheck,
+                  (Concept::HasNumericTraits<typename TMovingImage::PixelType>));
+  itkConceptMacro(MovingRealTypeAdditivieOperatorsCheck,
+                  (Concept::AdditiveOperators<
+                   typename NumericTraits<typename TMovingImage::PixelType>::RealType>));
+  itkConceptMacro(MovingRealTypeMultiplyOperatorCheck,
+                  (Concept::MultiplyOperator<
+                   typename NumericTraits<typename TMovingImage::PixelType>::RealType>));
+
+  /** End concept checking */
+#endif
+
+protected:
+  MeanSquaresImageToImageMetricFor3DBLUTFFD();
+  virtual ~MeanSquaresImageToImageMetricFor3DBLUTFFD() {};
+
+private:
+  MeanSquaresImageToImageMetricFor3DBLUTFFD(const Self&); //purposely not implemented
+  void operator=(const Self&); //purposely not implemented
+
+};
+
+} // end namespace itk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "itkMeanSquaresImageToImageMetricFor3DBLUTFFD.txx"
+#endif
+
+#endif
+
+#endif
+
diff --git a/registration/itkMeanSquaresImageToImageMetricFor3DBLUTFFD.txx b/registration/itkMeanSquaresImageToImageMetricFor3DBLUTFFD.txx
new file mode 100644 (file)
index 0000000..c9d7861
--- /dev/null
@@ -0,0 +1,370 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkMeanSquaresImageToImageMetricFor3DBLUTFFD.txx,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkMeanSquaresImageToImageMetricFor3DBLUTFFD_txx
+#define __itkMeanSquaresImageToImageMetricFor3DBLUTFFD_txx
+
+// First make sure that the configuration is available.
+// This line can be removed once the optimized versions
+// gets integrated into the main directories.
+#include "itkConfigure.h"
+
+#ifdef ITK_USE_OPTIMIZED_REGISTRATION_METHODS
+#include "itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.txx"
+#else
+
+#include "itkMeanSquaresImageToImageMetricFor3DBLUTFFD.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+
+namespace itk
+{
+
+/**
+ * Constructor
+ */
+template <class TFixedImage, class TMovingImage>
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeanSquaresImageToImageMetricFor3DBLUTFFD()
+{
+  itkDebugMacro("Constructor");
+}
+
+/**
+ * Get the match Measure
+ */
+template <class TFixedImage, class TMovingImage>
+typename MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>::MeasureType
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValue( const TransformParametersType & parameters ) const
+{
+
+  itkDebugMacro("GetValue( " << parameters << " ) ");
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<FixedImageType> FixedIteratorType;
+
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  MeasureType measure = NumericTraits< MeasureType >::Zero;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+      const RealType fixedValue   = ti.Get();
+      this->m_NumberOfPixelsCounted++;
+      const RealType diff = movingValue - fixedValue;
+      measure += diff * diff;
+    }
+
+    ++ti;
+  }
+
+  if( !this->m_NumberOfPixelsCounted ) {
+    itkExceptionMacro(<<"All the points mapped to outside of the moving image");
+  } else {
+    measure /= this->m_NumberOfPixelsCounted;
+  }
+
+  return measure;
+
+}
+
+/**
+ * Get the Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage>
+void
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetDerivative( const TransformParametersType & parameters,
+                 DerivativeType & derivative  ) const
+{
+
+  itkDebugMacro("GetDerivative( " << parameters << " ) ");
+
+  if( !this->GetGradientImage() ) {
+    itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
+  }
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  const unsigned int ImageDimension = FixedImageType::ImageDimension;
+
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<
+  FixedImageType> FixedIteratorType;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<GradientImageType> GradientIteratorType;
+
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  const unsigned int ParametersDimension = this->GetNumberOfParameters();
+  derivative = DerivativeType( ParametersDimension );
+  derivative.Fill( NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  ti.GoToBegin();
+
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+
+      const TransformJacobianType & jacobian =
+        this->m_Transform->GetJacobian( inputPoint );
+
+
+      const RealType fixedValue     = ti.Value();
+      this->m_NumberOfPixelsCounted++;
+      const RealType diff = movingValue - fixedValue;
+
+      // Get the gradient by NearestNeighboorInterpolation:
+      // which is equivalent to round up the point components.
+      typedef typename OutputPointType::CoordRepType CoordRepType;
+      typedef ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
+      MovingImageContinuousIndexType;
+
+      MovingImageContinuousIndexType tempIndex;
+      this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
+
+      typename MovingImageType::IndexType mappedIndex;
+      mappedIndex.CopyWithRound( tempIndex );
+
+      const GradientPixelType gradient =
+        this->GetGradientImage()->GetPixel( mappedIndex );
+
+      for(unsigned int par=0; par<ParametersDimension; par++) {
+        RealType sum = NumericTraits< RealType >::Zero;
+        for(unsigned int dim=0; dim<ImageDimension; dim++) {
+          sum += 2.0 * diff * jacobian( dim, par ) * gradient[dim];
+        }
+        derivative[par] += sum;
+      }
+    }
+
+    ++ti;
+  }
+
+  if( !this->m_NumberOfPixelsCounted ) {
+    itkExceptionMacro(<<"All the points mapped to outside of the moving image");
+  } else {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] /= this->m_NumberOfPixelsCounted;
+    }
+  }
+
+}
+
+
+/*
+ * Get both the match Measure and theDerivative Measure
+ */
+template <class TFixedImage, class TMovingImage>
+void
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivative(const TransformParametersType & parameters,
+                        MeasureType & value, DerivativeType  & derivative) const
+{
+
+  itkDebugMacro("GetValueAndDerivative( " << parameters << " ) ");
+
+  if( !this->GetGradientImage() ) {
+    itkExceptionMacro(<<"The gradient image is null, maybe you forgot to call Initialize()");
+  }
+
+  FixedImageConstPointer fixedImage = this->m_FixedImage;
+
+  if( !fixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  const unsigned int ImageDimension = FixedImageType::ImageDimension;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<
+  FixedImageType> FixedIteratorType;
+
+  typedef  itk::ImageRegionConstIteratorWithIndex<GradientImageType> GradientIteratorType;
+
+
+  FixedIteratorType ti( fixedImage, this->GetFixedImageRegion() );
+
+  typename FixedImageType::IndexType index;
+
+  MeasureType measure = NumericTraits< MeasureType >::Zero;
+
+  this->m_NumberOfPixelsCounted = 0;
+
+  this->SetTransformParameters( parameters );
+
+  const unsigned int ParametersDimension = this->GetNumberOfParameters();
+  derivative = DerivativeType( ParametersDimension );
+  derivative.Fill( NumericTraits<ITK_TYPENAME DerivativeType::ValueType>::Zero );
+
+  ti.GoToBegin();
+
+  while(!ti.IsAtEnd()) {
+
+    index = ti.GetIndex();
+
+    InputPointType inputPoint;
+    fixedImage->TransformIndexToPhysicalPoint( index, inputPoint );
+
+    if( this->m_FixedImageMask && !this->m_FixedImageMask->IsInside( inputPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    OutputPointType transformedPoint = this->m_Transform->TransformPoint( inputPoint );
+
+    if( this->m_MovingImageMask && !this->m_MovingImageMask->IsInside( transformedPoint ) ) {
+      ++ti;
+      continue;
+    }
+
+    if( this->m_Interpolator->IsInsideBuffer( transformedPoint ) ) {
+      const RealType movingValue  = this->m_Interpolator->Evaluate( transformedPoint );
+
+      const TransformJacobianType & jacobian =
+        this->m_Transform->GetJacobian( inputPoint );
+
+
+      const RealType fixedValue     = ti.Value();
+      this->m_NumberOfPixelsCounted++;
+
+      const RealType diff = movingValue - fixedValue;
+
+      measure += diff * diff;
+
+      // Get the gradient by NearestNeighboorInterpolation:
+      // which is equivalent to round up the point components.
+      typedef typename OutputPointType::CoordRepType CoordRepType;
+      typedef ContinuousIndex<CoordRepType,MovingImageType::ImageDimension>
+      MovingImageContinuousIndexType;
+
+      MovingImageContinuousIndexType tempIndex;
+      this->m_MovingImage->TransformPhysicalPointToContinuousIndex( transformedPoint, tempIndex );
+
+      typename MovingImageType::IndexType mappedIndex;
+      mappedIndex.CopyWithRound( tempIndex );
+
+      const GradientPixelType gradient =
+        this->GetGradientImage()->GetPixel( mappedIndex );
+
+      for(unsigned int par=0; par<ParametersDimension; par++) {
+        RealType sum = NumericTraits< RealType >::Zero;
+        for(unsigned int dim=0; dim<ImageDimension; dim++) {
+          sum += 2.0 * diff * jacobian( dim, par ) * gradient[dim];
+        }
+        derivative[par] += sum;
+      }
+    }
+
+    ++ti;
+  }
+
+  if( !this->m_NumberOfPixelsCounted ) {
+    itkExceptionMacro(<<"All the points mapped to outside of the moving image");
+  } else {
+    for(unsigned int i=0; i<ParametersDimension; i++) {
+      derivative[i] /= this->m_NumberOfPixelsCounted;
+    }
+    measure /= this->m_NumberOfPixelsCounted;
+  }
+
+  value = measure;
+
+}
+
+} // end namespace itk
+
+
+#endif
+
+#endif
diff --git a/registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h b/registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h
new file mode 100644 (file)
index 0000000..ea56932
--- /dev/null
@@ -0,0 +1,362 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_h
+#define __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_h
+
+#include "itkOptImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+#include "itkIndex.h"
+#include "itkBSplineKernelFunction.h"
+#include "itkBSplineDerivativeKernelFunction.h"
+#include "itkCentralDifferenceImageFunction.h"
+#include "itkBSplineInterpolateImageFunction.h"
+#include "itkBSplineDeformableTransform.h"
+#include "itkArray2D.h"
+
+#include "itkMultiThreader.h"
+
+namespace itk
+{
+
+/** \class MattesMutualInformationImageToImageMetricFor3DBLUTFFD
+ * \brief Computes the mutual information between two images to be
+ * registered using the method of Mattes et al.
+ *
+ * MattesMutualInformationImageToImageMetricFor3DBLUTFFD computes the mutual
+ * information between a fixed and moving image to be registered.
+ *
+ * This class is templated over the FixedImage type and the MovingImage
+ * type.
+ *
+ * The fixed and moving images are set via methods SetFixedImage() and
+ * SetMovingImage(). This metric makes use of user specified Transform and
+ * Interpolator. The Transform is used to map points from the fixed image to
+ * the moving image domain. The Interpolator is used to evaluate the image
+ * intensity at user specified geometric points in the moving image.
+ * The Transform and Interpolator are set via methods SetTransform() and
+ * SetInterpolator().
+ *
+ * If a BSplineInterpolationFunction is used, this class obtain
+ * image derivatives from the BSpline interpolator. Otherwise,
+ * image derivatives are computed using central differencing.
+ *
+ * \warning This metric assumes that the moving image has already been
+ * connected to the interpolator outside of this class.
+ *
+ * The method GetValue() computes of the mutual information
+ * while method GetValueAndDerivative() computes
+ * both the mutual information and its derivatives with respect to the
+ * transform parameters.
+ *
+ * The calculations are based on the method of Mattes et al [1,2]
+ * where the probability density distribution are estimated using
+ * Parzen histograms. Since the fixed image PDF does not contribute
+ * to the derivatives, it does not need to be smooth. Hence,
+ * a zero order (box car) BSpline kernel is used
+ * for the fixed image intensity PDF. On the other hand, to ensure
+ * smoothness a third order BSpline kernel is used for the
+ * moving image intensity PDF.
+ *
+ * On Initialize(), the FixedImage is uniformly sampled within
+ * the FixedImageRegion. The number of samples used can be set
+ * via SetNumberOfSpatialSamples(). Typically, the number of
+ * spatial samples used should increase with the image size.
+ *
+ * The option UseAllPixelOn() disables the random sampling and uses
+ * all the pixels of the FixedImageRegion in order to estimate the
+ * joint intensity PDF.
+ *
+ * During each call of GetValue(), GetDerivatives(),
+ * GetValueAndDerivatives(), marginal and joint intensity PDF's
+ * values are estimated at discrete position or bins.
+ * The number of bins used can be set via SetNumberOfHistogramBins().
+ * To handle data with arbitray magnitude and dynamic range,
+ * the image intensity is scale such that any contribution to the
+ * histogram will fall into a valid bin.
+ *
+ * One the PDF's have been contructed, the mutual information
+ * is obtained by doubling summing over the discrete PDF values.
+ *
+ *
+ * Notes:
+ * 1. This class returns the negative mutual information value.
+ * 2. This class in not thread safe due the private data structures
+ *     used to the store the sampled points and the marginal and joint pdfs.
+ *
+ * References:
+ * [1] "Nonrigid multimodality image registration"
+ *      D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank
+ *      Medical Imaging 2001: Image Processing, 2001, pp. 1609-1620.
+ * [2] "PET-CT Image Registration in the Chest Using Free-form Deformations"
+ *      D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank
+ *      IEEE Transactions in Medical Imaging. Vol.22, No.1,
+        January 2003. pp.120-128.
+ * [3] "Optimization of Mutual Information for MultiResolution Image
+ *      Registration"
+ *      P. Thevenaz and M. Unser
+ *      IEEE Transactions in Image Processing, 9(12) December 2000.
+ *
+ * \ingroup RegistrationMetrics
+ */
+template <class TFixedImage,class TMovingImage >
+class ITK_EXPORT MattesMutualInformationImageToImageMetricFor3DBLUTFFD :
+  public ImageToImageMetric< TFixedImage, TMovingImage >
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef MattesMutualInformationImageToImageMetricFor3DBLUTFFD           Self;
+  typedef ImageToImageMetric< TFixedImage, TMovingImage >     Superclass;
+  typedef SmartPointer<Self>                                  Pointer;
+  typedef SmartPointer<const Self>                            ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(MattesMutualInformationImageToImageMetricFor3DBLUTFFD,
+               ImageToImageMetric);
+
+  /** Types inherited from Superclass. */
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::InterpolatorType         InterpolatorType;
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::ParametersType           ParametersType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::MovingImagePointType     MovingImagePointType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+  typedef typename Superclass::BSplineTransformWeightsType
+  BSplineTransformWeightsType;
+  typedef typename Superclass::BSplineTransformIndexArrayType
+  BSplineTransformIndexArrayType;
+
+  typedef typename Superclass::CoordinateRepresentationType
+  CoordinateRepresentationType;
+  typedef typename Superclass::FixedImageSampleContainer
+  FixedImageSampleContainer;
+  typedef typename Superclass::ImageDerivativesType     ImageDerivativesType;
+  typedef typename Superclass::WeightsValueType         WeightsValueType;
+  typedef typename Superclass::IndexValueType           IndexValueType;
+
+  /** The moving image dimension. */
+  itkStaticConstMacro( MovingImageDimension, unsigned int,
+                       MovingImageType::ImageDimension );
+
+  /**
+   *  Initialize the Metric by
+   *  (1) making sure that all the components are present and plugged
+   *      together correctly,
+   *  (2) uniformly select NumberOfSpatialSamples within
+   *      the FixedImageRegion, and
+   *  (3) allocate memory for pdf data structures. */
+  virtual void Initialize(void) throw ( ExceptionObject );
+
+  /**  Get the value. */
+  MeasureType GetValue( const ParametersType & parameters ) const;
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const ParametersType & parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value and derivatives for single valued optimizers. */
+  void GetValueAndDerivative( const ParametersType & parameters,
+                              MeasureType & Value,
+                              DerivativeType & Derivative ) const;
+
+  /** Number of bins to used in the histogram. Typical value is 50. */
+  itkSetClampMacro( NumberOfHistogramBins, unsigned long,
+                    1, NumericTraits<unsigned long>::max() );
+  itkGetConstReferenceMacro( NumberOfHistogramBins, unsigned long);
+
+  /** This variable selects the method to be used for computing the Metric
+   * derivatives with respect to the Transform parameters. Two modes of
+   * computation are available. The choice between one and the other is a
+   * trade-off between computation speed and memory allocations. The two modes
+   * are described in detail below:
+   *
+   * UseExplicitPDFDerivatives = True
+   * will compute the Metric derivative by first calculating the derivatives of
+   * each one of the Joint PDF bins with respect to each one of the Transform
+   * parameters and then accumulating these contributions in the final metric
+   * derivative array by using a bin-specific weight.  The memory required for
+   * storing the intermediate derivatives is a 3D array of doubles with size
+   * equals to the product of (number of histogram bins)^2 times number of
+   * transform parameters. This method is well suited for Transform with a small
+   * number of parameters.
+   *
+   * UseExplicitPDFDerivatives = False will compute the Metric derivative by
+   * first computing the weights for each one of the Joint PDF bins and caching
+   * them into an array. Then it will revisit each one of the PDF bins for
+   * computing its weighted contribution to the full derivative array. In this
+   * method an extra 2D array is used for storing the weights of each one of
+   * the PDF bins. This is an array of doubles with size equals to (number of
+   * histogram bins)^2. This method is well suited for Transforms with a large
+   * number of parameters, such as, BSplineDeformableTransforms. */
+  itkSetMacro(UseExplicitPDFDerivatives,bool);
+  itkGetConstReferenceMacro(UseExplicitPDFDerivatives,bool);
+  itkBooleanMacro(UseExplicitPDFDerivatives);
+
+protected:
+
+  MattesMutualInformationImageToImageMetricFor3DBLUTFFD();
+  virtual ~MattesMutualInformationImageToImageMetricFor3DBLUTFFD();
+  void PrintSelf(std::ostream& os, Indent indent) const;
+
+private:
+
+  //purposely not implemented
+  MattesMutualInformationImageToImageMetricFor3DBLUTFFD(const Self &);
+  //purposely not implemented
+  void operator=(const Self &);
+
+
+  /** The marginal PDFs are stored as std::vector. */
+  typedef float                       PDFValueType;
+  typedef float *                     MarginalPDFType;
+
+  mutable MarginalPDFType             m_FixedImageMarginalPDF;
+
+  /** The moving image marginal PDF. */
+  mutable MarginalPDFType             m_MovingImageMarginalPDF;
+
+  /** Helper array for storing the values of the JointPDF ratios. */
+  typedef double                      PRatioType;
+  typedef Array2D< PRatioType >       PRatioArrayType;
+  mutable PRatioArrayType             m_PRatioArray;
+
+  /** Helper variable for accumulating the derivative of the metric. */
+  mutable DerivativeType              m_MetricDerivative;
+  mutable DerivativeType            * m_ThreaderMetricDerivative;
+
+  /** Typedef for the joint PDF and PDF derivatives are stored as ITK Images. */
+  typedef Image<PDFValueType,2>                 JointPDFType;
+  typedef Image<PDFValueType,3>                 JointPDFDerivativesType;
+  typedef JointPDFType::IndexType               JointPDFIndexType;
+  typedef JointPDFType::PixelType               JointPDFValueType;
+  typedef JointPDFType::RegionType              JointPDFRegionType;
+  typedef JointPDFType::SizeType                JointPDFSizeType;
+  typedef JointPDFDerivativesType::IndexType    JointPDFDerivativesIndexType;
+  typedef JointPDFDerivativesType::PixelType    JointPDFDerivativesValueType;
+  typedef JointPDFDerivativesType::RegionType   JointPDFDerivativesRegionType;
+  typedef JointPDFDerivativesType::SizeType     JointPDFDerivativesSizeType;
+
+  /** The joint PDF and PDF derivatives. */
+  typename JointPDFType::Pointer                m_JointPDF;
+  unsigned long                                 m_JointPDFBufferSize;
+  typename JointPDFDerivativesType::Pointer     m_JointPDFDerivatives;
+  unsigned long                                 m_JointPDFDerivativesBufferSize;
+
+  /** Variables to define the marginal and joint histograms. */
+  unsigned long  m_NumberOfHistogramBins;
+  double         m_MovingImageNormalizedMin;
+  double         m_FixedImageNormalizedMin;
+  double         m_FixedImageTrueMin;
+  double         m_FixedImageTrueMax;
+  double         m_MovingImageTrueMin;
+  double         m_MovingImageTrueMax;
+  double         m_FixedImageBinSize;
+  double         m_MovingImageBinSize;
+
+  /** Typedefs for BSpline kernel and derivative functions. */
+  typedef BSplineKernelFunction<3>           CubicBSplineFunctionType;
+  typedef BSplineDerivativeKernelFunction<3> CubicBSplineDerivativeFunctionType;
+
+  /** Cubic BSpline kernel for computing Parzen histograms. */
+  typename CubicBSplineFunctionType::Pointer   m_CubicBSplineKernel;
+  typename CubicBSplineDerivativeFunctionType::Pointer
+  m_CubicBSplineDerivativeKernel;
+
+  /** Precompute fixed image parzen window indices. */
+  virtual void ComputeFixedImageParzenWindowIndices(
+    FixedImageSampleContainer & samples );
+
+  /** Compute PDF derivative contribution for each parameter. */
+  virtual void ComputePDFDerivatives( unsigned int threadID,
+                                      unsigned int sampleNumber,
+                                      int movingImageParzenWindowIndex,
+                                      const ImageDerivativesType
+                                      &  movingImageGradientValue,
+                                      double cubicBSplineDerivativeValue
+                                    ) const;
+
+  PDFValueType                                * m_ThreaderFixedImageMarginalPDF;
+  typename JointPDFType::Pointer              * m_ThreaderJointPDF;
+  typename JointPDFDerivativesType::Pointer   * m_ThreaderJointPDFDerivatives;
+  int                                         * m_ThreaderJointPDFStartBin;
+  int                                         * m_ThreaderJointPDFEndBin;
+  mutable double                              * m_ThreaderJointPDFSum;
+  mutable double                                m_JointPDFSum;
+
+  bool                                          m_UseExplicitPDFDerivatives;
+  mutable bool                                  m_ImplicitDerivativesSecondPass;
+
+
+  virtual inline void GetValueThreadPreProcess( unsigned int threadID,
+      bool withinSampleThread ) const;
+  virtual inline bool GetValueThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue ) const;
+  virtual inline void GetValueThreadPostProcess( unsigned int threadID,
+      bool withinSampleThread ) const;
+
+  virtual inline void GetValueAndDerivativeThreadPreProcess(
+    unsigned int threadID,
+    bool withinSampleThread ) const;
+  virtual inline bool GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue,
+      const ImageDerivativesType &
+      movingImageGradientValue ) const;
+  virtual inline void GetValueAndDerivativeThreadPostProcess(
+    unsigned int threadID,
+    bool withinSampleThread ) const;
+
+};
+
+} // end namespace itk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx"
+#endif
+
+#endif
diff --git a/registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx b/registration/itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx
new file mode 100644 (file)
index 0000000..6d890e3
--- /dev/null
@@ -0,0 +1,1268 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+Program:   Insight Segmentation & Registration Toolkit
+Module:    $RCSfile: itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.txx,v $
+Language:  C++
+Date:      $Date: 2010/06/14 17:32:07 $
+Version:   $Revision: 1.1 $
+
+Copyright (c) Insight Software Consortium. All rights reserved.
+See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+This software is distributed WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
+#define __itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD_txx
+
+#include "itkOptMattesMutualInformationImageToImageMetricFor3DBLUTFFD.h"
+#include "itkCovariantVector.h"
+#include "itkImageRandomConstIteratorWithIndex.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageIterator.h"
+#include "vnl/vnl_math.h"
+#include "itkStatisticsImageFilter.h"
+
+#include "vnl/vnl_vector.txx"
+#include "vnl/vnl_c_vector.txx"
+
+namespace itk
+{
+
+/**
+ * Constructor
+ */
+template < class TFixedImage, class TMovingImage >
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
+{
+  m_NumberOfHistogramBins = 50;
+
+  this->SetComputeGradient(false); // don't use the default gradient for now
+
+  // Initialize PDFs to NULL
+  m_JointPDF = NULL;
+  m_JointPDFDerivatives = NULL;
+
+  // Initialize memory
+  m_FixedImageMarginalPDF = NULL;
+  m_MovingImageMarginalPDF = NULL;
+
+  m_MovingImageNormalizedMin = 0.0;
+  m_FixedImageNormalizedMin = 0.0;
+  m_MovingImageTrueMin = 0.0;
+  m_MovingImageTrueMax = 0.0;
+  m_FixedImageBinSize = 0.0;
+  m_MovingImageBinSize = 0.0;
+
+  m_CubicBSplineDerivativeKernel = NULL;
+
+  // For multi-threading the metric
+  m_ThreaderFixedImageMarginalPDF = NULL;
+  m_ThreaderJointPDF = NULL;
+  m_ThreaderJointPDFDerivatives = NULL;
+  m_ThreaderJointPDFStartBin = NULL;
+  m_ThreaderJointPDFEndBin = NULL;
+  m_ThreaderJointPDFSum = NULL;
+  this->m_WithinThreadPreProcess = true;
+  this->m_WithinThreadPostProcess = false;
+
+  this->m_ThreaderMetricDerivative = NULL;
+  this->m_UseExplicitPDFDerivatives = true;
+  this->m_ImplicitDerivativesSecondPass = false;
+}
+
+template < class TFixedImage, class TMovingImage >
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::~MattesMutualInformationImageToImageMetricFor3DBLUTFFD()
+{
+
+  if(m_FixedImageMarginalPDF != NULL) {
+    delete [] m_FixedImageMarginalPDF;
+  }
+  m_FixedImageMarginalPDF = NULL;
+  if(m_MovingImageMarginalPDF != NULL) {
+    delete [] m_MovingImageMarginalPDF;
+  }
+  m_MovingImageMarginalPDF = NULL;
+  if(m_ThreaderJointPDF != NULL) {
+    delete [] m_ThreaderJointPDF;
+  }
+  m_ThreaderJointPDF = NULL;
+
+  if(m_ThreaderJointPDFDerivatives != NULL) {
+    delete [] m_ThreaderJointPDFDerivatives;
+  }
+  m_ThreaderJointPDFDerivatives = NULL;
+
+  if(m_ThreaderFixedImageMarginalPDF != NULL) {
+    delete [] m_ThreaderFixedImageMarginalPDF;
+  }
+  m_ThreaderFixedImageMarginalPDF = NULL;
+
+  if(m_ThreaderJointPDFStartBin != NULL) {
+    delete [] m_ThreaderJointPDFStartBin;
+  }
+  m_ThreaderJointPDFStartBin = NULL;
+
+  if(m_ThreaderJointPDFEndBin != NULL) {
+    delete [] m_ThreaderJointPDFEndBin;
+  }
+  m_ThreaderJointPDFEndBin = NULL;
+
+  if(m_ThreaderJointPDFSum != NULL) {
+    delete [] m_ThreaderJointPDFSum;
+  }
+  m_ThreaderJointPDFSum = NULL;
+
+  if( this->m_ThreaderMetricDerivative != NULL ) {
+    delete [] this->m_ThreaderMetricDerivative;
+  }
+  this->m_ThreaderMetricDerivative = NULL;
+}
+
+/**
+ * Print out internal information about this class
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, Indent indent) const
+{
+
+  Superclass::PrintSelf(os, indent);
+
+  os << indent << "NumberOfHistogramBins: ";
+  os << this->m_NumberOfHistogramBins << std::endl;
+
+  // Debugging information
+  os << indent << "FixedImageNormalizedMin: ";
+  os << this->m_FixedImageNormalizedMin << std::endl;
+  os << indent << "MovingImageNormalizedMin: ";
+  os << this->m_MovingImageNormalizedMin << std::endl;
+  os << indent << "MovingImageTrueMin: ";
+  os << this->m_MovingImageTrueMin << std::endl;
+  os << indent << "MovingImageTrueMax: ";
+  os << this->m_MovingImageTrueMax << std::endl;
+  os << indent << "FixedImageBinSize: ";
+  os << this->m_FixedImageBinSize << std::endl;
+  os << indent << "MovingImageBinSize: ";
+  os << this->m_MovingImageBinSize << std::endl;
+  os << indent << "UseExplicitPDFDerivatives: ";
+  os << this->m_UseExplicitPDFDerivatives << std::endl;
+  os << indent << "ImplicitDerivativesSecondPass: ";
+  os << this->m_ImplicitDerivativesSecondPass << std::endl;
+
+}
+
+
+/**
+ * Initialize
+ */
+template <class TFixedImage, class TMovingImage>
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::Initialize(void) throw ( ExceptionObject )
+{
+  this->Superclass::Initialize();
+  this->Superclass::MultiThreadingInitialize();
+
+  typedef StatisticsImageFilter<FixedImageType> FixedImageStatisticsFilterType;
+  typename FixedImageStatisticsFilterType::Pointer fixedImageStats =
+    FixedImageStatisticsFilterType::New();
+  fixedImageStats->SetInput( this->m_FixedImage );
+  fixedImageStats->SetNumberOfThreads( this->m_NumberOfThreads );
+  fixedImageStats->Update();
+
+  m_FixedImageTrueMin = fixedImageStats->GetMinimum();
+  m_FixedImageTrueMax = fixedImageStats->GetMaximum();
+  double fixedImageMin = m_FixedImageTrueMin;
+  double fixedImageMax = m_FixedImageTrueMax;
+
+  typedef StatisticsImageFilter<MovingImageType>
+  MovingImageStatisticsFilterType;
+  typename MovingImageStatisticsFilterType::Pointer movingImageStats =
+    MovingImageStatisticsFilterType::New();
+  movingImageStats->SetInput( this->m_MovingImage );
+  movingImageStats->SetNumberOfThreads( this->m_NumberOfThreads );
+  movingImageStats->Update();
+
+  m_MovingImageTrueMin = movingImageStats->GetMinimum();
+  m_MovingImageTrueMax = movingImageStats->GetMaximum();
+  double movingImageMin = m_MovingImageTrueMin;
+  double movingImageMax = m_MovingImageTrueMax;
+
+  itkDebugMacro( " FixedImageMin: " << fixedImageMin <<
+                 " FixedImageMax: " << fixedImageMax << std::endl );
+  itkDebugMacro( " MovingImageMin: " << movingImageMin <<
+                 " MovingImageMax: " << movingImageMax << std::endl );
+
+
+  /**
+   * Compute binsize for the histograms.
+   *
+   * The binsize for the image intensities needs to be adjusted so that
+   * we can avoid dealing with boundary conditions using the cubic
+   * spline as the Parzen window.  We do this by increasing the size
+   * of the bins so that the joint histogram becomes "padded" at the
+   * borders. Because we are changing the binsize,
+   * we also need to shift the minimum by the padded amount in order to
+   * avoid minimum values filling in our padded region.
+   *
+   * Note that there can still be non-zero bin values in the padded region,
+   * it's just that these bins will never be a central bin for the Parzen
+   * window.
+   *
+   */
+  const int padding = 2;  // this will pad by 2 bins
+
+  m_FixedImageBinSize = ( fixedImageMax - fixedImageMin )
+                        / static_cast<double>( m_NumberOfHistogramBins
+                            - 2 * padding );
+  m_FixedImageNormalizedMin = fixedImageMin / m_FixedImageBinSize
+                              - static_cast<double>( padding );
+
+  m_MovingImageBinSize = ( movingImageMax - movingImageMin )
+                         / static_cast<double>( m_NumberOfHistogramBins
+                             - 2 * padding );
+  m_MovingImageNormalizedMin = movingImageMin / m_MovingImageBinSize
+                               - static_cast<double>( padding );
+
+  itkDebugMacro( "FixedImageNormalizedMin: " << m_FixedImageNormalizedMin );
+  itkDebugMacro( "MovingImageNormalizedMin: " << m_MovingImageNormalizedMin );
+  itkDebugMacro( "FixedImageBinSize: " << m_FixedImageBinSize );
+  itkDebugMacro( "MovingImageBinSize; " << m_MovingImageBinSize );
+
+
+  /**
+   * Allocate memory for the marginal PDF and initialize values
+   * to zero. The marginal PDFs are stored as std::vector.
+   */
+  if(m_FixedImageMarginalPDF != NULL) {
+    delete [] m_FixedImageMarginalPDF;
+  }
+  m_FixedImageMarginalPDF = new PDFValueType[m_NumberOfHistogramBins];
+  if(m_MovingImageMarginalPDF != NULL) {
+    delete [] m_MovingImageMarginalPDF;
+  }
+  m_MovingImageMarginalPDF = new PDFValueType[m_NumberOfHistogramBins];
+
+  /**
+   * Allocate memory for the joint PDF and joint PDF derivatives.
+   * The joint PDF and joint PDF derivatives are store as itk::Image.
+   */
+  m_JointPDF = JointPDFType::New();
+  m_JointPDFDerivatives = JointPDFDerivativesType::New();
+
+  // Instantiate a region, index, size
+  JointPDFRegionType             jointPDFRegion;
+  JointPDFIndexType              jointPDFIndex;
+  JointPDFSizeType               jointPDFSize;
+
+  // Deallocate the memory that may have been allocated for
+  // previous runs of the metric.
+  this->m_JointPDFDerivatives = NULL;  // by destroying the dynamic array
+  this->m_PRatioArray.SetSize( 1, 1 ); // and by allocating very small the static ones
+  this->m_MetricDerivative = DerivativeType( 1 );
+
+  JointPDFDerivativesRegionType  jointPDFDerivativesRegion;
+
+  //
+  // Now allocate memory according to the user-selected method.
+  //
+  if( this->m_UseExplicitPDFDerivatives ) {
+    this->m_JointPDFDerivatives = JointPDFDerivativesType::New();
+
+    JointPDFDerivativesIndexType  jointPDFDerivativesIndex;
+    JointPDFDerivativesSizeType    jointPDFDerivativesSize;
+
+    // For the derivatives of the joint PDF define a region starting from {0,0,0}
+    // with size {m_NumberOfParameters,m_NumberOfHistogramBins,
+    // m_NumberOfHistogramBins}. The dimension represents transform parameters,
+    // fixed image parzen window index and moving image parzen window index,
+    // respectively.
+    jointPDFDerivativesIndex.Fill( 0 );
+    jointPDFDerivativesSize[0] = this->m_NumberOfParameters;
+    jointPDFDerivativesSize[1] = this->m_NumberOfHistogramBins;
+    jointPDFDerivativesSize[2] = this->m_NumberOfHistogramBins;
+
+    jointPDFDerivativesRegion.SetIndex( jointPDFDerivativesIndex );
+    jointPDFDerivativesRegion.SetSize( jointPDFDerivativesSize );
+
+    // Set the regions and allocate
+    m_JointPDFDerivatives->SetRegions( jointPDFDerivativesRegion );
+    m_JointPDFDerivatives->Allocate();
+    m_JointPDFDerivativesBufferSize = jointPDFDerivativesSize[0]
+                                      * jointPDFDerivativesSize[1]
+                                      * jointPDFDerivativesSize[2]
+                                      * sizeof(JointPDFDerivativesValueType);
+
+  } else {
+    /** Allocate memory for helper array that will contain the pRatios
+     *  for each bin of the joint histogram. This is part of the effort
+     *  for flattening the computation of the PDF Jacobians.
+     */
+    this->m_PRatioArray.SetSize( this->m_NumberOfHistogramBins, this->m_NumberOfHistogramBins );
+    this->m_MetricDerivative = DerivativeType( this->GetNumberOfParameters() );
+  }
+
+  // For the joint PDF define a region starting from {0,0}
+  // with size {m_NumberOfHistogramBins, m_NumberOfHistogramBins}.
+  // The dimension represents fixed image parzen window index
+  // and moving image parzen window index, respectively.
+  jointPDFIndex.Fill( 0 );
+  jointPDFSize.Fill( m_NumberOfHistogramBins );
+
+  jointPDFRegion.SetIndex( jointPDFIndex );
+  jointPDFRegion.SetSize( jointPDFSize );
+
+  // Set the regions and allocate
+  m_JointPDF->SetRegions( jointPDFRegion );
+  m_JointPDF->Allocate();
+
+  m_JointPDFBufferSize = jointPDFSize[0] * jointPDFSize[1] * sizeof(PDFValueType);
+
+
+  /**
+   * Setup the kernels used for the Parzen windows.
+   */
+  m_CubicBSplineKernel = CubicBSplineFunctionType::New();
+  m_CubicBSplineDerivativeKernel = CubicBSplineDerivativeFunctionType::New();
+
+  /**
+   * Pre-compute the fixed image parzen window index for
+   * each point of the fixed image sample points list.
+   */
+  this->ComputeFixedImageParzenWindowIndices( this->m_FixedImageSamples );
+
+
+  if(m_ThreaderFixedImageMarginalPDF != NULL) {
+    delete [] m_ThreaderFixedImageMarginalPDF;
+  }
+  // Assumes number of threads doesn't change between calls to Initialize
+  m_ThreaderFixedImageMarginalPDF = new
+  PDFValueType[(this->m_NumberOfThreads-1)
+               * m_NumberOfHistogramBins];
+
+  if(m_ThreaderJointPDF != NULL) {
+    delete [] m_ThreaderJointPDF;
+  }
+  m_ThreaderJointPDF = new typename
+  JointPDFType::Pointer[this->m_NumberOfThreads-1];
+
+  if(m_ThreaderJointPDFStartBin != NULL) {
+    delete [] m_ThreaderJointPDFStartBin;
+  }
+  m_ThreaderJointPDFStartBin = new int[this->m_NumberOfThreads];
+
+  if(m_ThreaderJointPDFEndBin != NULL) {
+    delete [] m_ThreaderJointPDFEndBin;
+  }
+  m_ThreaderJointPDFEndBin = new int[this->m_NumberOfThreads];
+
+  if(m_ThreaderJointPDFSum != NULL) {
+    delete [] m_ThreaderJointPDFSum;
+  }
+  m_ThreaderJointPDFSum = new double[this->m_NumberOfThreads];
+
+  unsigned int threadID;
+
+  int binRange = m_NumberOfHistogramBins / this->m_NumberOfThreads;
+
+  for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
+    m_ThreaderJointPDF[threadID] = JointPDFType::New();
+    m_ThreaderJointPDF[threadID]->SetRegions( jointPDFRegion );
+    m_ThreaderJointPDF[threadID]->Allocate();
+
+    m_ThreaderJointPDFStartBin[threadID] = threadID * binRange;
+    m_ThreaderJointPDFEndBin[threadID] = (threadID + 1) * binRange - 1;
+  }
+
+  m_ThreaderJointPDFStartBin[this->m_NumberOfThreads-1] =
+    (this->m_NumberOfThreads - 1 ) * binRange;
+
+  m_ThreaderJointPDFEndBin[this->m_NumberOfThreads-1] = m_NumberOfHistogramBins - 1;
+
+  // Release memory of arrays that may have been used for
+  // previous executions of this metric with different settings
+  // of the memory caching flags.
+  if(m_ThreaderJointPDFDerivatives != NULL) {
+    delete [] m_ThreaderJointPDFDerivatives;
+  }
+  m_ThreaderJointPDFDerivatives = NULL;
+
+  if(m_ThreaderMetricDerivative != NULL) {
+    delete [] m_ThreaderMetricDerivative;
+  }
+  m_ThreaderMetricDerivative = NULL;
+
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    m_ThreaderJointPDFDerivatives = new typename
+    JointPDFDerivativesType::Pointer[this->m_NumberOfThreads-1];
+
+    for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
+      m_ThreaderJointPDFDerivatives[threadID] = JointPDFDerivativesType::New();
+      m_ThreaderJointPDFDerivatives[threadID]->SetRegions(
+        jointPDFDerivativesRegion );
+      m_ThreaderJointPDFDerivatives[threadID]->Allocate();
+    }
+  } else {
+    m_ThreaderMetricDerivative = new DerivativeType[this->m_NumberOfThreads-1];
+
+    for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) {
+      this->m_ThreaderMetricDerivative[threadID] = DerivativeType( this->GetNumberOfParameters() );
+    }
+  }
+}
+
+/**
+ * Uniformly sample the fixed image domain using a random walk
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ComputeFixedImageParzenWindowIndices(
+  FixedImageSampleContainer& samples )
+{
+
+  typename FixedImageSampleContainer::iterator iter;
+  typename FixedImageSampleContainer::const_iterator end=samples.end();
+
+  for( iter=samples.begin(); iter != end; ++iter ) {
+
+    // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
+    double windowTerm = static_cast<double>( (*iter).value )
+                        / m_FixedImageBinSize
+                        - m_FixedImageNormalizedMin;
+    unsigned int pindex = static_cast<unsigned int>( windowTerm );
+
+    // Make sure the extreme values are in valid bins
+    if ( pindex < 2 ) {
+      pindex = 2;
+    } else if ( pindex > (m_NumberOfHistogramBins - 3) ) {
+      pindex = m_NumberOfHistogramBins - 3;
+    }
+
+    (*iter).valueIndex = pindex;
+  }
+
+}
+
+template < class TFixedImage, class TMovingImage  >
+inline void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueThreadPreProcess( unsigned int threadID,
+                            bool withinSampleThread ) const
+{
+
+  this->Superclass::GetValueThreadPreProcess( threadID, withinSampleThread );
+
+  if(threadID > 0) {
+    memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(),
+            0,
+            m_JointPDFBufferSize );
+    memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1)
+              *m_NumberOfHistogramBins]),
+            0,
+            m_NumberOfHistogramBins*sizeof(PDFValueType) );
+  } else {
+    // zero-th thread uses the variables directly
+    memset( m_JointPDF->GetBufferPointer(),
+            0,
+            m_JointPDFBufferSize );
+    memset( m_FixedImageMarginalPDF,
+            0,
+            m_NumberOfHistogramBins*sizeof(PDFValueType) );
+  }
+}
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueThreadProcessSample( unsigned int threadID,
+                               unsigned long fixedImageSample,
+                               const MovingImagePointType & itkNotUsed(mappedPoint),
+                               double movingImageValue) const
+{
+  /**
+   * Compute this sample's contribution to the marginal and
+   * joint distributions.
+   *
+   */
+
+  if(movingImageValue < m_MovingImageTrueMin) {
+    return false;
+  } else if(movingImageValue > m_MovingImageTrueMax) {
+    return false;
+  }
+
+  // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
+  double movingImageParzenWindowTerm = movingImageValue
+                                       / m_MovingImageBinSize
+                                       - m_MovingImageNormalizedMin;
+  // Same as floor
+  unsigned int movingImageParzenWindowIndex =
+    static_cast<unsigned int>( movingImageParzenWindowTerm );
+  if( movingImageParzenWindowIndex < 2 ) {
+    movingImageParzenWindowIndex = 2;
+  } else if( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
+    movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
+  }
+
+  unsigned int fixedImageParzenWindowIndex =
+    this->m_FixedImageSamples[fixedImageSample].valueIndex;
+  if(threadID > 0) {
+    m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins
+                                    + fixedImageParzenWindowIndex] += 1;
+  } else {
+    m_FixedImageMarginalPDF[fixedImageParzenWindowIndex] += 1;
+  }
+
+  // Pointer to affected bin to be updated
+  JointPDFValueType *pdfPtr;
+  if(threadID > 0) {
+    pdfPtr = m_ThreaderJointPDF[threadID-1]->GetBufferPointer() +
+             ( fixedImageParzenWindowIndex
+               * m_ThreaderJointPDF[threadID-1]
+               ->GetOffsetTable()[1] );
+  } else {
+    pdfPtr = m_JointPDF->GetBufferPointer() +
+             ( fixedImageParzenWindowIndex
+               * m_JointPDF->GetOffsetTable()[1] );
+  }
+
+  // Move the pointer to the first affected bin
+  int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
+  pdfPtr += pdfMovingIndex;
+  int pdfMovingIndexMax = static_cast<int>(movingImageParzenWindowIndex) + 2;
+
+  double movingImageParzenWindowArg =
+    static_cast<double>( pdfMovingIndex )
+    - movingImageParzenWindowTerm;
+
+  while( pdfMovingIndex <= pdfMovingIndexMax ) {
+    *(pdfPtr++) += static_cast<PDFValueType>( m_CubicBSplineKernel
+                   ->Evaluate(
+                     movingImageParzenWindowArg ) );
+    movingImageParzenWindowArg += 1;
+    ++pdfMovingIndex;
+  }
+
+  return true;
+}
+
+template < class TFixedImage, class TMovingImage  >
+inline void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueThreadPostProcess( unsigned int threadID,
+                             bool itkNotUsed(withinSampleThread) ) const
+{
+  unsigned int t;
+  int i;
+  int maxI;
+  maxI = m_NumberOfHistogramBins
+         * ( m_ThreaderJointPDFEndBin[threadID]
+             - m_ThreaderJointPDFStartBin[threadID] + 1);
+  JointPDFValueType *pdfPtr;
+  JointPDFValueType *pdfPtrStart;
+  pdfPtrStart = m_JointPDF->GetBufferPointer()
+                + ( m_ThreaderJointPDFStartBin[threadID]
+                    * m_JointPDF->GetOffsetTable()[1] );
+  JointPDFValueType *tPdfPtr;
+  JointPDFValueType *tPdfPtrEnd;
+  unsigned int       tPdfPtrOffset;
+  tPdfPtrOffset = ( m_ThreaderJointPDFStartBin[threadID]
+                    * m_JointPDF->GetOffsetTable()[1] );
+  for(t=0; t<this->m_NumberOfThreads-1; t++) {
+    pdfPtr = pdfPtrStart;
+    tPdfPtr = m_ThreaderJointPDF[t]->GetBufferPointer() + tPdfPtrOffset;
+    tPdfPtrEnd = tPdfPtr + maxI;
+    //for(i=0; i < maxI; i++)
+    while(tPdfPtr < tPdfPtrEnd) {
+      *(pdfPtr++) += *(tPdfPtr++);
+    }
+    for(i = m_ThreaderJointPDFStartBin[threadID];
+        i <= m_ThreaderJointPDFEndBin[threadID];
+        i++) {
+      m_FixedImageMarginalPDF[i] += m_ThreaderFixedImageMarginalPDF[
+                                      (t*m_NumberOfHistogramBins) + i];
+    }
+  }
+  double jointPDFSum = 0.0;
+  pdfPtr = pdfPtrStart;
+  for(i = 0; i < maxI; i++) {
+    jointPDFSum += *(pdfPtr++);
+  }
+  if(threadID > 0) {
+    m_ThreaderJointPDFSum[threadID-1] = jointPDFSum;
+  } else {
+    m_JointPDFSum = jointPDFSum;
+  }
+}
+
+template < class TFixedImage, class TMovingImage  >
+typename MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeasureType
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValue( const ParametersType & parameters ) const
+{
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedInitiate();
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedPostProcessInitiate();
+
+  for(unsigned int threadID = 0; threadID<this->m_NumberOfThreads-1; threadID++) {
+    m_JointPDFSum += m_ThreaderJointPDFSum[threadID];
+  }
+  if ( m_JointPDFSum == 0.0 ) {
+    itkExceptionMacro( "Joint PDF summed to zero" );
+  }
+
+  memset( m_MovingImageMarginalPDF,
+          0,
+          m_NumberOfHistogramBins*sizeof(PDFValueType) );
+
+  JointPDFValueType * pdfPtr;
+  PDFValueType * movingMarginalPtr;
+  unsigned int i, j;
+  double fixedPDFSum = 0.0;
+  double nFactor = 1.0 / m_JointPDFSum;
+  pdfPtr = m_JointPDF->GetBufferPointer();
+  for(i=0; i<m_NumberOfHistogramBins; i++) {
+    fixedPDFSum += m_FixedImageMarginalPDF[i];
+    movingMarginalPtr = m_MovingImageMarginalPDF;
+    for(j=0; j<m_NumberOfHistogramBins; j++) {
+      *(pdfPtr) *= nFactor;
+      *(movingMarginalPtr++) += *(pdfPtr++);
+    }
+  }
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 16 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  // Normalize the fixed image marginal PDF
+  if ( fixedPDFSum == 0.0 ) {
+    itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
+  }
+  for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
+    m_FixedImageMarginalPDF[bin] /= fixedPDFSum;
+  }
+
+  /**
+   * Compute the metric by double summation over histogram.
+   */
+
+  // Setup pointer to point to the first bin
+  JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
+
+  double sum = 0.0;
+
+  for( unsigned int fixedIndex = 0;
+       fixedIndex < m_NumberOfHistogramBins;
+       ++fixedIndex ) {
+    double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
+
+    for( unsigned int movingIndex = 0;
+         movingIndex < m_NumberOfHistogramBins;
+         ++movingIndex, jointPDFPtr++ ) {
+      double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
+      double jointPDFValue = *(jointPDFPtr);
+
+      // check for non-zero bin contribution
+      if( jointPDFValue > 1e-16 &&  movingImagePDFValue > 1e-16 ) {
+
+        double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
+        if( fixedImagePDFValue > 1e-16) {
+          sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
+        }
+
+      }  // end if-block to check non-zero bin contribution
+    }  // end for-loop over moving index
+  }  // end for-loop over fixed index
+
+  return static_cast<MeasureType>( -1.0 * sum );
+
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+inline void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivativeThreadPreProcess( unsigned int threadID,
+    bool itkNotUsed(withinSampleThread) ) const
+{
+  if(threadID > 0) {
+    memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(),
+            0,
+            m_JointPDFBufferSize );
+
+    memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1)
+              * m_NumberOfHistogramBins]),
+            0,
+            m_NumberOfHistogramBins*sizeof(PDFValueType) );
+
+    if( this->m_UseExplicitPDFDerivatives ) {
+      memset( m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer(),
+              0,
+              m_JointPDFDerivativesBufferSize );
+    }
+  } else {
+    memset( m_JointPDF->GetBufferPointer(),
+            0,
+            m_JointPDFBufferSize );
+    memset( m_FixedImageMarginalPDF,
+            0,
+            m_NumberOfHistogramBins*sizeof(PDFValueType) );
+
+    if( this->m_UseExplicitPDFDerivatives ) {
+      memset( m_JointPDFDerivatives->GetBufferPointer(),
+              0,
+              m_JointPDFDerivativesBufferSize );
+    }
+  }
+}
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
+    unsigned long fixedImageSample,
+    const MovingImagePointType & itkNotUsed(mappedPoint),
+    double movingImageValue,
+    const ImageDerivativesType &
+    movingImageGradientValue) const
+{
+  /**
+   * Compute this sample's contribution to the marginal
+   *   and joint distributions.
+   *
+   */
+  if(movingImageValue < m_MovingImageTrueMin) {
+    return false;
+  } else if(movingImageValue > m_MovingImageTrueMax) {
+    return false;
+  }
+
+  unsigned int fixedImageParzenWindowIndex =
+    this->m_FixedImageSamples[fixedImageSample].valueIndex;
+
+  // Determine parzen window arguments (see eqn 6 of Mattes paper [2]).
+  double movingImageParzenWindowTerm = movingImageValue
+                                       / m_MovingImageBinSize
+                                       - m_MovingImageNormalizedMin;
+  unsigned int movingImageParzenWindowIndex =
+    static_cast<unsigned int>( movingImageParzenWindowTerm );
+
+  // Make sure the extreme values are in valid bins
+  if ( movingImageParzenWindowIndex < 2 ) {
+    movingImageParzenWindowIndex = 2;
+  } else if ( movingImageParzenWindowIndex > (m_NumberOfHistogramBins - 3) ) {
+    movingImageParzenWindowIndex = m_NumberOfHistogramBins - 3;
+  }
+
+  // Since a zero-order BSpline (box car) kernel is used for
+  // the fixed image marginal pdf, we need only increment the
+  // fixedImageParzenWindowIndex by value of 1.0.
+  if(threadID > 0) {
+    ++m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins
+                                      + fixedImageParzenWindowIndex];
+  } else {
+    ++m_FixedImageMarginalPDF[fixedImageParzenWindowIndex];
+  }
+
+  /**
+   * The region of support of the parzen window determines which bins
+   * of the joint PDF are effected by the pair of image values.
+   * Since we are using a cubic spline for the moving image parzen
+   * window, four bins are effected.  The fixed image parzen window is
+   * a zero-order spline (box car) and thus effects only one bin.
+   *
+   *  The PDF is arranged so that moving image bins corresponds to the
+   * zero-th (column) dimension and the fixed image bins corresponds
+   * to the first (row) dimension.
+   *
+   */
+
+  // Pointer to affected bin to be updated
+  JointPDFValueType *pdfPtr;
+  if(threadID > 0) {
+    pdfPtr = m_ThreaderJointPDF[threadID-1]
+             ->GetBufferPointer() +
+             ( fixedImageParzenWindowIndex
+               * m_NumberOfHistogramBins );
+  } else {
+    pdfPtr = m_JointPDF->GetBufferPointer() +
+             ( fixedImageParzenWindowIndex
+               * m_NumberOfHistogramBins );
+  }
+
+  // Move the pointer to the fist affected bin
+  int pdfMovingIndex = static_cast<int>( movingImageParzenWindowIndex ) - 1;
+  pdfPtr += pdfMovingIndex;
+  int pdfMovingIndexMax = static_cast<int>(movingImageParzenWindowIndex) + 2;
+
+  double movingImageParzenWindowArg = static_cast<double>( pdfMovingIndex )
+                                      - static_cast<double>( movingImageParzenWindowTerm );
+
+  while( pdfMovingIndex <= pdfMovingIndexMax ) {
+    *(pdfPtr++) += static_cast<PDFValueType>( m_CubicBSplineKernel
+                   ->Evaluate(
+                     movingImageParzenWindowArg ) );
+
+    if( this->m_UseExplicitPDFDerivatives || this->m_ImplicitDerivativesSecondPass ) {
+      // Compute the cubicBSplineDerivative for later repeated use.
+      double cubicBSplineDerivativeValue =
+        m_CubicBSplineDerivativeKernel->Evaluate( movingImageParzenWindowArg );
+
+      // Compute PDF derivative contribution.
+      this->ComputePDFDerivatives( threadID,
+                                   fixedImageSample,
+                                   pdfMovingIndex,
+                                   movingImageGradientValue,
+                                   cubicBSplineDerivativeValue );
+    }
+
+    movingImageParzenWindowArg += 1;
+    ++pdfMovingIndex;
+  }
+
+  return true;
+}
+
+template < class TFixedImage, class TMovingImage  >
+inline void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivativeThreadPostProcess( unsigned int threadID,
+    bool withinSampleThread ) const
+{
+  this->GetValueThreadPostProcess( threadID, withinSampleThread );
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    const unsigned int rowSize = this->m_NumberOfParameters * m_NumberOfHistogramBins;
+
+    const unsigned int maxI =
+      rowSize * ( m_ThreaderJointPDFEndBin[threadID]
+                  - m_ThreaderJointPDFStartBin[threadID] + 1 );
+
+    JointPDFDerivativesValueType *pdfDPtr;
+    JointPDFDerivativesValueType *pdfDPtrStart;
+    pdfDPtrStart = m_JointPDFDerivatives->GetBufferPointer()
+                   + ( m_ThreaderJointPDFStartBin[threadID] * rowSize );
+    JointPDFDerivativesValueType *tPdfDPtr;
+    JointPDFDerivativesValueType *tPdfDPtrEnd;
+    unsigned int tPdfDPtrOffset;
+    tPdfDPtrOffset = m_ThreaderJointPDFStartBin[threadID] *  rowSize;
+    for(unsigned int t=0; t<this->m_NumberOfThreads-1; t++) {
+      pdfDPtr = pdfDPtrStart;
+      tPdfDPtr = m_ThreaderJointPDFDerivatives[t]->GetBufferPointer()
+                 + tPdfDPtrOffset;
+      tPdfDPtrEnd = tPdfDPtr + maxI;
+      // for(i = 0; i < maxI; i++)
+      while(tPdfDPtr < tPdfDPtrEnd) {
+        *(pdfDPtr++) += *(tPdfDPtr++);
+      }
+    }
+
+    double nFactor = 1.0 / (m_MovingImageBinSize
+                            * this->m_NumberOfPixelsCounted);
+
+    pdfDPtr = pdfDPtrStart;
+    tPdfDPtrEnd = pdfDPtrStart + maxI;
+    //for(int i = 0; i < maxI; i++)
+    while(pdfDPtr < tPdfDPtrEnd) {
+      *(pdfDPtr++) *= nFactor;
+    }
+  }
+}
+
+/**
+ * Get the both Value and Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivative( const ParametersType & parameters,
+                         MeasureType & value,
+                         DerivativeType & derivative) const
+{
+  // Set output values to zero
+  value = NumericTraits< MeasureType >::Zero;
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    // Set output values to zero
+    if(derivative.GetSize() != this->m_NumberOfParameters) {
+      derivative = DerivativeType( this->m_NumberOfParameters );
+    }
+    memset( derivative.data_block(),
+            0,
+            this->m_NumberOfParameters * sizeof(double) );
+  } else {
+    this->m_PRatioArray.Fill( 0.0 );
+    this->m_MetricDerivative.Fill( NumericTraits< MeasureType >::Zero );
+    for(unsigned int threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++ ) {
+      this->m_ThreaderMetricDerivative[threadID].Fill( NumericTraits< MeasureType >::Zero );
+    }
+    this->m_ImplicitDerivativesSecondPass = false;
+  }
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES
+  this->GetValueAndDerivativeMultiThreadedInitiate();
+
+  // CALL IF DOING THREADED POST PROCESSING
+  this->GetValueAndDerivativeMultiThreadedPostProcessInitiate();
+
+  for(unsigned int threadID = 0; threadID<this->m_NumberOfThreads-1; threadID++) {
+    m_JointPDFSum += m_ThreaderJointPDFSum[threadID];
+  }
+  if ( m_JointPDFSum == 0.0 ) {
+    itkExceptionMacro( "Joint PDF summed to zero" );
+  }
+
+  memset( m_MovingImageMarginalPDF,
+          0,
+          m_NumberOfHistogramBins*sizeof(PDFValueType) );
+
+  JointPDFValueType * pdfPtr;
+  PDFValueType * movingMarginalPtr;
+  unsigned int i, j;
+  double fixedPDFSum = 0.0;
+  const double normalizationFactor = 1.0 / m_JointPDFSum;
+
+  pdfPtr = m_JointPDF->GetBufferPointer();
+  for(i=0; i<m_NumberOfHistogramBins; i++) {
+    fixedPDFSum += m_FixedImageMarginalPDF[i];
+    movingMarginalPtr = m_MovingImageMarginalPDF;
+    for(j=0; j<m_NumberOfHistogramBins; j++) {
+      *(pdfPtr) *= normalizationFactor;
+      *(movingMarginalPtr++) += *(pdfPtr++);
+    }
+  }
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 16 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  // Normalize the fixed image marginal PDF
+  if ( fixedPDFSum == 0.0 ) {
+    itkExceptionMacro( "Fixed image marginal PDF summed to zero" );
+  }
+  for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) {
+    m_FixedImageMarginalPDF[bin] /= fixedPDFSum;
+  }
+
+  /**
+   * Compute the metric by double summation over histogram.
+   */
+
+  // Setup pointer to point to the first bin
+  JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer();
+
+  // Initialize sum to zero
+  double sum = 0.0;
+
+  const double nFactor = 1.0 / (m_MovingImageBinSize
+                                * this->m_NumberOfPixelsCounted);
+
+  for( unsigned int fixedIndex = 0;
+       fixedIndex < m_NumberOfHistogramBins;
+       ++fixedIndex ) {
+    double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex];
+
+    for( unsigned int movingIndex = 0;
+         movingIndex < m_NumberOfHistogramBins;
+         ++movingIndex, jointPDFPtr++ ) {
+      double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex];
+      double jointPDFValue = *(jointPDFPtr);
+
+      // check for non-zero bin contribution
+      if( jointPDFValue > 1e-16 &&  movingImagePDFValue > 1e-16 ) {
+
+        double pRatio = vcl_log(jointPDFValue / movingImagePDFValue );
+
+        if( fixedImagePDFValue > 1e-16) {
+          sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) );
+        }
+
+        if( this->m_UseExplicitPDFDerivatives ) {
+          // move joint pdf derivative pointer to the right position
+          JointPDFValueType * derivPtr = m_JointPDFDerivatives->GetBufferPointer()
+                                         + ( fixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
+                                         + ( movingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
+
+          for( unsigned int parameter=0; parameter < this->m_NumberOfParameters; ++parameter, derivPtr++ ) {
+
+            // Ref: eqn 23 of Thevenaz & Unser paper [3]
+            derivative[parameter] -= (*derivPtr) * pRatio;
+
+          }  // end for-loop over parameters
+        } else {
+          this->m_PRatioArray[fixedIndex][movingIndex] = pRatio * nFactor;
+        }
+      }  // end if-block to check non-zero bin contribution
+    }  // end for-loop over moving index
+  }  // end for-loop over fixed index
+
+  if( !(this->m_UseExplicitPDFDerivatives ) ) {
+    // Second pass: This one is done for accumulating the contributions
+    //              to the derivative array.
+    //
+    this->m_ImplicitDerivativesSecondPass = true;
+    //
+    // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES
+    this->GetValueAndDerivativeMultiThreadedInitiate();
+
+    // CALL IF DOING THREADED POST PROCESSING
+    this->GetValueAndDerivativeMultiThreadedPostProcessInitiate();
+
+    // Consolidate the contributions from each one of the threads to the total
+    // derivative.
+    for(unsigned int t = 0; t < this->m_NumberOfThreads-1; t++ ) {
+      DerivativeType * source = &(this->m_ThreaderMetricDerivative[t]);
+      for(unsigned int pp=0; pp < this->m_NumberOfParameters; pp++ ) {
+        this->m_MetricDerivative[pp] += (*source)[pp];
+      }
+    }
+
+    derivative = this->m_MetricDerivative;
+  }
+
+  value = static_cast<MeasureType>( -1.0 * sum );
+
+}
+
+/**
+ * Get the match measure derivative
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetDerivative( const ParametersType & parameters,
+                 DerivativeType & derivative ) const
+{
+  MeasureType value;
+  // call the combined version
+  this->GetValueAndDerivative( parameters, value, derivative );
+}
+
+
+/**
+ * Compute PDF derivatives contribution for each parameter
+ */
+template < class TFixedImage, class TMovingImage >
+void
+MattesMutualInformationImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::ComputePDFDerivatives( unsigned int threadID,
+                         unsigned int sampleNumber,
+                         int pdfMovingIndex,
+                         const ImageDerivativesType & movingImageGradientValue,
+                         double cubicBSplineDerivativeValue ) const
+{
+  // Update bins in the PDF derivatives for the current intensity pair
+  // Could pre-compute
+  JointPDFDerivativesValueType * derivPtr;
+
+  double precomputedWeight = 0.0;
+
+  const int pdfFixedIndex = this->m_FixedImageSamples[sampleNumber].valueIndex;
+
+  DerivativeType * derivativeHelperArray = NULL;
+
+  if( this->m_UseExplicitPDFDerivatives ) {
+    if(threadID > 0) {
+      derivPtr = m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer()
+                 + ( pdfFixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
+                 + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
+    } else {
+      derivPtr = m_JointPDFDerivatives->GetBufferPointer()
+                 + ( pdfFixedIndex  * m_JointPDFDerivatives->GetOffsetTable()[2] )
+                 + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] );
+    }
+  } else {
+    derivPtr = 0;
+    // Recover the precomputed weight for this specific PDF bin
+    precomputedWeight = this->m_PRatioArray[pdfFixedIndex][pdfMovingIndex];
+    if(threadID > 0) {
+      derivativeHelperArray = &(this->m_ThreaderMetricDerivative[threadID-1]);
+    } else {
+      derivativeHelperArray = &(this->m_MetricDerivative);
+    }
+
+  }
+
+  if( !this->m_TransformIsBSpline ) {
+    /**
+     * Generic version which works for all transforms.
+     */
+
+    // Compute the transform Jacobian.
+    // Should pre-compute
+    typedef typename TransformType::JacobianType JacobianType;
+
+    // Need to use one of the threader transforms if we're
+    // not in thread 0.
+    //
+    // Use a raw pointer here to avoid the overhead of smart pointers.
+    // For instance, Register and UnRegister have mutex locks around
+    // the reference counts.
+    TransformType* transform;
+
+    if (threadID > 0) {
+      transform = this->m_ThreaderTransform[threadID - 1];
+    } else {
+      transform = this->m_Transform;
+    }
+
+    const JacobianType& jacobian =
+      transform->GetJacobian( this->m_FixedImageSamples[sampleNumber].point );
+
+    //     for ( unsigned int mu = 0; mu < this->m_NumberOfParameters; mu++ )
+    //       {
+    //       double innerProduct = 0.0;
+    //       for ( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ )
+    //         {
+    //         innerProduct += jacobian[dim][mu] * movingImageGradientValue[dim];
+    //         }
+
+    //       const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
+
+    //       if( this->m_UseExplicitPDFDerivatives )
+    //         {
+    //         *(derivPtr) -= derivativeContribution;
+    //         ++derivPtr;
+    //         }
+    //       else
+    //         {
+    //         (*derivativeHelperArray)[mu] += precomputedWeight * derivativeContribution;
+    //         }
+    //       }
+    //    }
+    // JV
+    unsigned int mu, dim;
+    double innerProduct,derivativeContribution;
+    for ( mu = 0; mu < this->m_NumberOfParameters; mu+=3 ) {
+      // JV only for 3D Space BLUT FFD: if J(0, par)=0, then J(1,par+1)=0 & ...
+      if (jacobian[0][mu])
+        for ( dim = 0; dim < Superclass::FixedImageDimension; dim++ ) {
+          innerProduct = jacobian[dim][mu+dim] * movingImageGradientValue[dim];
+          derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
+
+          if( this->m_UseExplicitPDFDerivatives ) {
+            *(derivPtr) -= derivativeContribution;
+            ++derivPtr;
+          } else {
+            (*derivativeHelperArray)[mu+dim] += precomputedWeight * derivativeContribution;
+          }
+        }
+      else  if( this->m_UseExplicitPDFDerivatives ) derivPtr+=3;
+    }
+  } else {
+    const WeightsValueType * weights = NULL;
+    const IndexValueType   * indices = NULL;
+
+
+    BSplineTransformWeightsType    * weightsHelper = NULL;
+    BSplineTransformIndexArrayType * indicesHelper = NULL;
+
+    if( this->m_UseCachingOfBSplineWeights ) {
+      //
+      // If the transform is of type BSplineDeformableTransform, we can obtain
+      // a speed up by only processing the affected parameters.  Note that
+      // these pointers are just pointing to pre-allocated rows of the caching
+      // arrays. There is therefore, no need to free this memory.
+      //
+      weights = this->m_BSplineTransformWeightsArray[sampleNumber];
+      indices = this->m_BSplineTransformIndicesArray[sampleNumber];
+    } else {
+      if( threadID > 0 ) {
+        weightsHelper = &(this->m_ThreaderBSplineTransformWeights[threadID-1]);
+        indicesHelper = &(this->m_ThreaderBSplineTransformIndices[threadID-1]);
+      } else {
+        weightsHelper = &(this->m_BSplineTransformWeights);
+        indicesHelper = &(this->m_BSplineTransformIndices);
+      }
+
+      this->m_BSplineTransform->GetJacobian(
+        this->m_FixedImageSamples[sampleNumber].point,
+        *weightsHelper, *indicesHelper );
+    }
+
+    for( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ ) {
+
+      double innerProduct;
+      int parameterIndex;
+
+      for( unsigned int mu = 0; mu < this->m_NumBSplineWeights; mu++ ) {
+
+        /* The array weights contains the Jacobian values in a 1-D array
+         * (because for each parameter the Jacobian is non-zero in only 1 of the
+         * possible dimensions) which is multiplied by the moving image
+         * gradient. */
+        if( this->m_UseCachingOfBSplineWeights ) {
+          innerProduct = movingImageGradientValue[dim] * weights[mu];
+          parameterIndex = indices[mu] + this->m_BSplineParametersOffset[dim];
+        } else {
+          innerProduct = movingImageGradientValue[dim] * (*weightsHelper)[mu];
+          parameterIndex = (*indicesHelper)[mu] + this->m_BSplineParametersOffset[dim];
+        }
+
+        const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue;
+
+        if( this->m_UseExplicitPDFDerivatives ) {
+          JointPDFValueType * ptr = derivPtr + parameterIndex;
+          *(ptr) -= derivativeContribution;
+        } else {
+          (*derivativeHelperArray)[parameterIndex] += precomputedWeight * derivativeContribution;
+        }
+
+      } //end mu for loop
+    } //end dim for loop
+
+  } // end if-block transform is BSpline
+
+}
+
+
+} // end namespace itk
+
+
+#endif
diff --git a/registration/itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.h b/registration/itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.h
new file mode 100644 (file)
index 0000000..78bf91c
--- /dev/null
@@ -0,0 +1,151 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.h,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD_h
+#define __itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD_h
+
+#include "itkOptImageToImageMetric.h"
+#include "itkCovariantVector.h"
+#include "itkPoint.h"
+#include "itkIndex.h"
+
+#include "itkMultiThreader.h"
+
+namespace itk
+{
+
+template <class TFixedImage,class TMovingImage >
+class ITK_EXPORT MeanSquaresImageToImageMetricFor3DBLUTFFD :
+  public ImageToImageMetric< TFixedImage, TMovingImage >
+{
+public:
+
+  /** Standard class typedefs. */
+  typedef MeanSquaresImageToImageMetricFor3DBLUTFFD                     Self;
+  typedef ImageToImageMetric< TFixedImage, TMovingImage >   Superclass;
+  typedef SmartPointer<Self>                                Pointer;
+  typedef SmartPointer<const Self>                          ConstPointer;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(MeanSquaresImageToImageMetricFor3DBLUTFFD, ImageToImageMetric);
+
+  /** Types inherited from Superclass. */
+  typedef typename Superclass::TransformType            TransformType;
+  typedef typename Superclass::TransformPointer         TransformPointer;
+  typedef typename Superclass::TransformJacobianType    TransformJacobianType;
+  typedef typename Superclass::InterpolatorType         InterpolatorType;
+  typedef typename Superclass::MeasureType              MeasureType;
+  typedef typename Superclass::DerivativeType           DerivativeType;
+  typedef typename Superclass::ParametersType           ParametersType;
+  typedef typename Superclass::FixedImageType           FixedImageType;
+  typedef typename Superclass::MovingImageType          MovingImageType;
+  typedef typename Superclass::MovingImagePointType     MovingImagePointType;
+  typedef typename Superclass::FixedImageConstPointer   FixedImageConstPointer;
+  typedef typename Superclass::MovingImageConstPointer  MovingImageConstPointer;
+  typedef typename Superclass::CoordinateRepresentationType
+  CoordinateRepresentationType;
+  typedef typename Superclass::FixedImageSampleContainer
+  FixedImageSampleContainer;
+  typedef typename Superclass::ImageDerivativesType     ImageDerivativesType;
+  typedef typename Superclass::WeightsValueType         WeightsValueType;
+  typedef typename Superclass::IndexValueType           IndexValueType;
+
+  // Needed for evaluation of Jacobian.
+  typedef typename Superclass::FixedImagePointType     FixedImagePointType;
+
+  /** The moving image dimension. */
+  itkStaticConstMacro( MovingImageDimension, unsigned int,
+                       MovingImageType::ImageDimension );
+
+  /**
+   *  Initialize the Metric by
+   *  (1) making sure that all the components are present and plugged
+   *      together correctly,
+   *  (2) uniformly select NumberOfSpatialSamples within
+   *      the FixedImageRegion, and
+   *  (3) allocate memory for pdf data structures. */
+  virtual void Initialize(void) throw ( ExceptionObject );
+
+  /**  Get the value. */
+  MeasureType GetValue( const ParametersType & parameters ) const;
+
+  /** Get the derivatives of the match measure. */
+  void GetDerivative( const ParametersType & parameters,
+                      DerivativeType & Derivative ) const;
+
+  /**  Get the value and derivatives for single valued optimizers. */
+  void GetValueAndDerivative( const ParametersType & parameters,
+                              MeasureType & Value,
+                              DerivativeType & Derivative ) const;
+
+protected:
+
+  MeanSquaresImageToImageMetricFor3DBLUTFFD();
+  virtual ~MeanSquaresImageToImageMetricFor3DBLUTFFD();
+  void PrintSelf(std::ostream& os, Indent indent) const;
+
+private:
+
+  //purposely not implemented
+  MeanSquaresImageToImageMetricFor3DBLUTFFD(const Self &);
+  //purposely not implemented
+  void operator=(const Self &);
+
+  inline bool GetValueThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue ) const;
+
+  inline bool GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
+      unsigned long fixedImageSample,
+      const MovingImagePointType & mappedPoint,
+      double movingImageValue,
+      const ImageDerivativesType &
+      movingImageGradientValue ) const;
+
+  MeasureType    * m_ThreaderMSE;
+  DerivativeType * m_ThreaderMSEDerivatives;
+
+};
+
+} // end namespace itk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.txx"
+#endif
+
+#endif
diff --git a/registration/itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.txx b/registration/itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.txx
new file mode 100644 (file)
index 0000000..d949e9b
--- /dev/null
@@ -0,0 +1,331 @@
+/*=========================================================================
+  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
+
+  Authors belong to:
+  - University of LYON              http://www.universite-lyon.fr/
+  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
+
+  This software is distributed WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE.  See the copyright notices for more information.
+
+  It is distributed under dual licence
+
+  - BSD        See included LICENSE.txt file
+  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+======================================================================-====*/
+
+/*=========================================================================
+
+  Program:   Insight Segmentation & Registration Toolkit
+  Module:    $RCSfile: itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.txx,v $
+  Language:  C++
+  Date:      $Date: 2010/06/14 17:32:07 $
+  Version:   $Revision: 1.1 $
+
+  Copyright (c) Insight Software Consortium. All rights reserved.
+  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef __itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD_txx
+#define __itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD_txx
+
+#include "itkOptMeanSquaresImageToImageMetricFor3DBLUTFFD.h"
+#include "itkCovariantVector.h"
+#include "itkImageRandomConstIteratorWithIndex.h"
+#include "itkImageRegionConstIterator.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageIterator.h"
+#include "vnl/vnl_math.h"
+
+namespace itk
+{
+
+/**
+ * Constructor
+ */
+template < class TFixedImage, class TMovingImage >
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeanSquaresImageToImageMetricFor3DBLUTFFD()
+{
+  this->SetComputeGradient(true);
+
+  m_ThreaderMSE = NULL;
+  m_ThreaderMSEDerivatives = NULL;
+  this->m_WithinThreadPreProcess = false;
+  this->m_WithinThreadPostProcess = false;
+
+  //  For backward compatibility, the default behavior is to use all the pixels
+  //  in the fixed image.
+  this->UseAllPixelsOn();
+}
+
+template < class TFixedImage, class TMovingImage >
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::~MeanSquaresImageToImageMetricFor3DBLUTFFD()
+{
+  if(m_ThreaderMSE != NULL) {
+    delete [] m_ThreaderMSE;
+  }
+  m_ThreaderMSE = NULL;
+
+  if(m_ThreaderMSEDerivatives != NULL) {
+    delete [] m_ThreaderMSEDerivatives;
+  }
+  m_ThreaderMSEDerivatives = NULL;
+}
+
+/**
+ * Print out internal information about this class
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::PrintSelf(std::ostream& os, Indent indent) const
+{
+
+  Superclass::PrintSelf(os, indent);
+
+}
+
+
+/**
+ * Initialize
+ */
+template <class TFixedImage, class TMovingImage>
+void
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::Initialize(void) throw ( ExceptionObject )
+{
+
+  this->Superclass::Initialize();
+  this->Superclass::MultiThreadingInitialize();
+
+  if(m_ThreaderMSE != NULL) {
+    delete [] m_ThreaderMSE;
+  }
+  m_ThreaderMSE = new double[this->m_NumberOfThreads];
+
+  if(m_ThreaderMSEDerivatives != NULL) {
+    delete [] m_ThreaderMSEDerivatives;
+  }
+  m_ThreaderMSEDerivatives = new DerivativeType[this->m_NumberOfThreads];
+  for(unsigned int threadID=0; threadID<this->m_NumberOfThreads; threadID++) {
+    m_ThreaderMSEDerivatives[threadID].SetSize( this->m_NumberOfParameters );
+  }
+}
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueThreadProcessSample( unsigned int threadID,
+                               unsigned long fixedImageSample,
+                               const MovingImagePointType & itkNotUsed(mappedPoint),
+                               double movingImageValue) const
+{
+  double diff = movingImageValue - this->m_FixedImageSamples[fixedImageSample].value;
+
+  m_ThreaderMSE[threadID] += diff*diff;
+
+  return true;
+}
+
+template < class TFixedImage, class TMovingImage  >
+typename MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::MeasureType
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValue( const ParametersType & parameters ) const
+{
+  itkDebugMacro("GetValue( " << parameters << " ) ");
+
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  memset( m_ThreaderMSE,
+          0,
+          this->m_NumberOfThreads * sizeof(MeasureType) );
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueMultiThreadedInitiate();
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << this->m_NumberOfPixelsCounted << " / "
+                 << this->m_NumberOfFixedImageSamples
+                 << std::endl );
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 4 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  double mse = m_ThreaderMSE[0];
+  for(unsigned int t=1; t<this->m_NumberOfThreads; t++) {
+    mse += m_ThreaderMSE[t];
+  }
+  mse /= this->m_NumberOfPixelsCounted;
+
+  return mse;
+}
+
+
+template < class TFixedImage, class TMovingImage  >
+inline bool
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivativeThreadProcessSample( unsigned int threadID,
+    unsigned long fixedImageSample,
+    const MovingImagePointType & itkNotUsed(mappedPoint),
+    double movingImageValue,
+    const ImageDerivativesType &
+    movingImageGradientValue ) const
+{
+  double diff = movingImageValue - this->m_FixedImageSamples[fixedImageSample].value;
+
+  m_ThreaderMSE[threadID] += diff*diff;
+
+  //JV
+  //FixedImagePointType fixedImagePoint = this->m_FixedImageSamples[fixedImageSample].point;
+
+  // Need to use one of the threader transforms if we're
+  // not in thread 0.
+  //
+  // Use a raw pointer here to avoid the overhead of smart pointers.
+  // For instance, Register and UnRegister have mutex locks around
+  // the reference counts.
+  TransformType* transform;
+
+  if (threadID > 0) {
+    transform = this->m_ThreaderTransform[threadID - 1];
+  } else {
+    transform = this->m_Transform;
+  }
+
+  // Jacobian should be evaluated at the unmapped (fixed image) point.
+  const TransformJacobianType & jacobian = transform ->GetJacobian( this->m_FixedImageSamples[fixedImageSample].point );
+  //double sum;
+  unsigned int par, dim;
+  for( par=0; par<this->m_NumberOfParameters; par+=3) {
+    //     double sum = 0.0;
+    //     for(unsigned int dim=0; dim<MovingImageDimension; dim++)
+    //       {
+    //       sum += 2.0 * diff * jacobian( dim, par ) * movingImageGradientValue[dim];
+    //       }
+    //     m_ThreaderMSEDerivatives[threadID][par] += sum;
+
+    // JV only for 3D BLUT FFD
+    if (jacobian( 0, par ) )
+      for( dim=0; dim<3; dim++)
+        m_ThreaderMSEDerivatives[threadID][par+dim  ]  += 2.0 * diff* jacobian( dim, par+dim   ) * movingImageGradientValue[dim];
+
+  }
+  return true;
+}
+
+/**
+ * Get the both Value and Derivative Measure
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetValueAndDerivative( const ParametersType & parameters,
+                         MeasureType & value,
+                         DerivativeType & derivative) const
+{
+
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  // Set up the parameters in the transform
+  this->m_Transform->SetParameters( parameters );
+  this->m_Parameters = parameters;
+
+  // Reset the joint pdfs to zero
+  memset( m_ThreaderMSE,
+          0,
+          this->m_NumberOfThreads * sizeof(MeasureType) );
+
+  // Set output values to zero
+  if(derivative.GetSize() != this->m_NumberOfParameters) {
+    derivative = DerivativeType( this->m_NumberOfParameters );
+  }
+  memset( derivative.data_block(),
+          0,
+          this->m_NumberOfParameters * sizeof(double) );
+
+  for( unsigned int threadID = 0; threadID<this->m_NumberOfThreads; threadID++ ) {
+    memset( m_ThreaderMSEDerivatives[threadID].data_block(),
+            0,
+            this->m_NumberOfParameters * sizeof(double) );
+  }
+
+  // MUST BE CALLED TO INITIATE PROCESSING
+  this->GetValueAndDerivativeMultiThreadedInitiate();
+
+  itkDebugMacro( "Ratio of voxels mapping into moving image buffer: "
+                 << this->m_NumberOfPixelsCounted << " / "
+                 << this->m_NumberOfFixedImageSamples
+                 << std::endl );
+
+  if( this->m_NumberOfPixelsCounted <
+      this->m_NumberOfFixedImageSamples / 4 ) {
+    itkExceptionMacro( "Too many samples map outside moving image buffer: "
+                       << this->m_NumberOfPixelsCounted << " / "
+                       << this->m_NumberOfFixedImageSamples
+                       << std::endl );
+  }
+
+  value = 0;
+  for(unsigned int t=0; t<this->m_NumberOfThreads; t++) {
+    value += m_ThreaderMSE[t];
+    for(unsigned int parameter = 0; parameter < this->m_NumberOfParameters;
+        parameter++) {
+      derivative[parameter] += m_ThreaderMSEDerivatives[t][parameter];
+    }
+  }
+
+  value /= this->m_NumberOfPixelsCounted;
+  for(unsigned int parameter = 0; parameter < this->m_NumberOfParameters;
+      parameter++) {
+    derivative[parameter] /= this->m_NumberOfPixelsCounted;
+    // JV
+    //DD(parameter<<"\t"<<derivative[parameter]);
+  }
+
+}
+
+
+/**
+ * Get the match measure derivative
+ */
+template < class TFixedImage, class TMovingImage  >
+void
+MeanSquaresImageToImageMetricFor3DBLUTFFD<TFixedImage,TMovingImage>
+::GetDerivative( const ParametersType & parameters,
+                 DerivativeType & derivative ) const
+{
+  if( !this->m_FixedImage ) {
+    itkExceptionMacro( << "Fixed image has not been assigned" );
+  }
+
+  MeasureType value;
+  // call the combined version
+  this->GetValueAndDerivative( parameters, value, derivative );
+}
+
+} // end namespace itk
+
+
+#endif
diff --git a/tools/clitkRigidRegistration.cxx b/tools/clitkRigidRegistration.cxx
deleted file mode 100644 (file)
index 1db3e75..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*=========================================================================
-  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
-
-  Authors belong to:
-  - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
-  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the copyright notices for more information.
-
-  It is distributed under dual licence
-
-  - BSD        See included LICENSE.txt file
-  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-======================================================================-====*/
-/**
- -------------------------------------------------
- * @file   clitkRigidRegistration.cxx
- * @author Jef Vandemeulebroucke <jef.Vandemeulebroucke@creatis.insa-lyon.fr>
- * @date   14 August 2007
- *
- * @brief Perform a rigid registration between 2 images
- *
- -------------------------------------------------*/
-
-
-// clitk include
-#include "clitkIO.h"
-#include "clitkImageCommon.h"
-#include "clitkRigidRegistration_ggo.h"
-#include "clitkRigidRegistrationGenericFilter.h"
-
-using namespace clitk;
-using namespace std;
-
-
-int main( int argc, char *argv[] )
-{
-  //init command line and check options
-  GGO(args_info);
-  CLITK_INIT;
-
-  //---------------------------------------------------------------------------
-  //Set all the options passed through the commandline
-
-  RigidRegistrationGenericFilter rigidRegistration;
-
-  rigidRegistration.SetVerbose(args_info.verbose_flag);
-  rigidRegistration.SetGradient(args_info.gradient_flag);
-  rigidRegistration.SetZeroOrigin(args_info.zero_origin_flag);
-
-//Input
-  rigidRegistration.SetFixedImageName(args_info.reference_arg);
-  rigidRegistration.SetMovingImageName(args_info.object_arg);
-  rigidRegistration.SetFixedImageMaskGiven(args_info.mask_given);
-  if (args_info.mask_given)   rigidRegistration.SetFixedImageMaskName(args_info.mask_arg);
-
-  //Output
-  rigidRegistration.SetOutputGiven(args_info.output_given);
-  if (args_info.output_given)  rigidRegistration.SetOutputName(args_info.output_arg);
-  rigidRegistration.SetCheckerAfterGiven(args_info.checker_after_given);
-  if (args_info.checker_after_given)  rigidRegistration.SetCheckerAfterName(args_info.checker_after_arg);
-  rigidRegistration.SetCheckerBeforeGiven(args_info.checker_before_given);
-  if (args_info.checker_before_given)  rigidRegistration.SetCheckerBeforeName(args_info.checker_before_arg);
-  rigidRegistration.SetBeforeGiven(args_info.before_given);
-  if (args_info.before_given)  rigidRegistration.SetBeforeName(args_info.before_arg);
-  rigidRegistration.SetAfterGiven(args_info.after_given);
-  if (args_info.after_given)  rigidRegistration.SetAfterName(args_info.after_arg);
-  rigidRegistration.SetMatrixGiven(args_info.matrix_given);
-  if (args_info.matrix_given)  rigidRegistration.SetMatrixName(args_info.matrix_arg);
-
-  //Interp
-  rigidRegistration.SetInterpType(args_info.interp_arg);
-
-  //Transform
-  rigidRegistration.SetRotX(args_info.rotX_arg);
-  rigidRegistration.SetRotY(args_info.rotY_arg);
-  rigidRegistration.SetRotZ(args_info.rotZ_arg);
-  rigidRegistration.SetTransX(args_info.transX_arg);
-  rigidRegistration.SetTransY(args_info.transY_arg);
-  rigidRegistration.SetTransZ(args_info.transZ_arg);
-
-  //Optimizer
-  rigidRegistration.SetLevels(args_info.levels_arg);
-  rigidRegistration.SetIstep(args_info.Istep_arg);
-  rigidRegistration.SetFstep(args_info.Fstep_arg);
-  rigidRegistration.SetRelax(args_info.relax_arg);
-  rigidRegistration.SetInc(args_info.inc_arg);
-  rigidRegistration.SetDec(args_info.dec_arg);
-  rigidRegistration.SetIter(args_info.iter_arg);
-  rigidRegistration.SetRweight(args_info.Rweight_arg);
-  rigidRegistration.SetTweight(args_info.Tweight_arg);
-
-  //Metric
-  rigidRegistration.SetMetricType(args_info.metric_arg);
-  rigidRegistration.SetSamples(args_info.samples_arg);
-  rigidRegistration.SetBins(args_info.bins_arg);
-  rigidRegistration.SetRandom(args_info.random_flag);
-  rigidRegistration.SetStdDev(args_info.stdDev_arg);
-
-  //Preprocessing
-  rigidRegistration.SetBlur(args_info.blur_arg);
-  rigidRegistration.SetNormalize(args_info.normalize_flag);
-
-  rigidRegistration.Update();
-
-}
diff --git a/tools/clitkRigidRegistration.ggo b/tools/clitkRigidRegistration.ggo
deleted file mode 100644 (file)
index 5002e60..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# file clitkRigidRegistration.ggo
-Package "clitkRigidRegistration"
-version "1.0"
-purpose "Compute a rigid registration between two images." 
-
-option "config"                -       "Config file"                           string  no
-option "verbose"       v       "Verbose"                               flag    off
-option "gradient"      -       "If verbose, show gradient at each iteration"   flag    off
-
-section "Input (Both images have to be of the same dimension (2 or 3D). For 2D-3D registrations, give the 2D image a third dimension of 1 and set it to the reference image.)"
-option "reference"     i       "Reference or fixed image filename"             string  yes
-option "object"        j       "Object or moving image filename"               string  yes
-option "mask"          m       "Mask to placed over the reference image"       string   no     
-
-section "Output"
-option "output"        o       "Transformed object image filename"                                                     string  no
-option "checker_after"  -      "Checherboard representation of the transformed object image and reference image"       string  no
-option "checker_before"  -     "Checherboard representation of the object image and reference image"                   string  no
-option "after"         -       "Difference between the reference image and the transformed object"                     string  no
-option "before"        -       "Difference between the reference image and the original object image"                  string  no
-option "matrix"        -       "Affine matrix (reference to object space) filename "                                   string  no
-
-section "Interpolator"
-option "interp"        -       "Interpolator used during registration: 0=nearestneighbor, 1=linear, 2=bspline"         int     no      default="1"
-
-section "Transform (Input and Output transformation parameters map the physical space of the fixed or reference image into the physical space of the moving or object image. Positive rotations result in a counter-clockwise rotation for the moving image. Positive translations result in shift along the negative axis for the moving image.)"
-option "transX"        x       "Initial translation in mm along the X axis"    float   no      default="0.0"
-option "transY"        y       "Initial translation in mm along the Y axis"    float   no      default="0.0"
-option "transZ"        z       "Initial translation in mm along the Z axis"    float   no      default="0.0"
-option "rotX"          X       "Initial rotation in rad along the X axis"      float   no      default="0.0"
-option "rotY"          Y       "Initial rotation in rad along the Y axis"      float   no      default="0.0"
-option "rotZ"          Z       "Initial rotation in rad along the Z axis"      float   no      default="0.0"
-
-section "Optimizer"
-option "levels"        l       "Number of multiresolution levels"                                                              int      no     default="1"
-option "Istep"                 -       "Initial stepsize in mm in the first level(to be multiplied with the gradient)"                 float   no      default="2.0"
-option "Fstep"                 -       "Final  stepsize in mm in the first level (to be multiplied with the gradient)"                 float   no      default="0.1"
-option "relax"                 -       "Relaxation of the stepsize (multiplied each time the gradient changes sign)"                   float   no      default="0.7"
-option "inc"           -       "Increment factor x  previous stepsize = new stepsize when going to next level"         float   no      default="1.2"
-option "dec"           -       "Decrement factor(:) previous stepsize = new final stepsize when going to next level" float     no      default="4.0"
-option "iter"          -       "Maximum number of iterations at each level"                                            int     no      default="200"
-option "Rweight"       -       "Weight of 1° of rotation during optimisation (high weight, less change)"                      float   no      default="50.0"
-option "Tweight"       -       "Weight of 1mm of translation  during optimisation (high weight, less change)"                  float   no      default="1.0"
-
-section "Metric (Use a high fraction of samples for detailed images (eg. 0.2, 0.5). For smooth images 0.01 might be enough. Use enough bins to cover the dynamique range. Randomizing the samples will make each execution different.)"
-option "metric"        -       "Metric used during registration: 0=MS, 1=MI, 2=Mattes' MI, 3=CR"                                       int     no      default="0"
-option "samples"       -       "If using MI or Mattes' MI, specify fraction [0, 1] of samples of the reference image"                          float   no      default="0.2"
-option "bins"          -       "If using Mattes' MI, specify the number of histogram bins for the PDF estimation of the reference image"       int     no      default="50"
-option "random"        -       "If using Mattes' MI and MI, specify if the set of samples should be taken randomly"                            flag    off     
-option "stdDev"                -       "If using MI, specify the standard deviation in mm of the gaussian kernels for both PDF estimations"                    float   no      default="0.4"   
-
-section "Preprocessing"
-option "normalize"     -       "Normalize images before registration (not necessary for Mattes' MI)"                   flag    off     
-option "blur"          -       "Blur images before registration, use Gaussian with std dev (none by default) "         float   no  default="0.0"       
-option "zero_origin"   -       "Reset the input images' origins to zero, to avoid additional shifts according to jef"  flag    off