From 657652a78c2e2717a6f77e027049173442ca29f0 Mon Sep 17 00:00:00 2001 From: jef Date: Thu, 22 Jul 2010 14:36:11 +0000 Subject: [PATCH] *** empty log message *** --- registration/CMakeLists.txt | 55 + registration/clitkAffineRegistration.ggo | 8 +- registration/clitkBLUTDIR.cxx | 51 + registration/clitkBLUTDIR.ggo | 87 + registration/clitkBLUTDIRGenericFilter.cxx | 73 + registration/clitkBLUTDIRGenericFilter.h | 139 + registration/clitkBLUTDIRGenericFilter.txx | 848 ++++ .../clitkBSplineDeformableRegistration.cxx | 48 + .../clitkBSplineDeformableRegistration.ggo | 87 + ...ineDeformableRegistrationGenericFilter.cxx | 51 + ...plineDeformableRegistrationGenericFilter.h | 120 + ...ineDeformableRegistrationGenericFilter.txx | 857 ++++ .../clitkBSplineDeformableTransform.h | 365 ++ .../clitkBSplineDeformableTransform.txx | 1043 ++++ ...itkBSplineDeformableTransformInitializer.h | 174 + ...kBSplineDeformableTransformInitializer.txx | 244 + registration/clitkBSplinePyramid.cxx | 51 + registration/clitkBSplinePyramid.ggo | 15 + .../clitkBSplinePyramidGenericFilter.cxx | 72 + .../clitkBSplinePyramidGenericFilter.h | 120 + .../clitkBSplinePyramidGenericFilter.txx | 398 ++ registration/clitkCalculateTRE.cxx | 51 + registration/clitkCalculateTRE.ggo | 33 + .../clitkCalculateTREGenericFilter.cxx | 137 + registration/clitkCalculateTREGenericFilter.h | 124 + .../clitkCalculateTREGenericFilter.txx | 606 +++ ...kConvertBSplineDeformableTransformToVF.cxx | 51 + ...kConvertBSplineDeformableTransformToVF.ggo | 25 + ...neDeformableTransformToVFGenericFilter.cxx | 417 ++ ...lineDeformableTransformToVFGenericFilter.h | 117 + registration/clitkConvertPointList.cxx | 81 + registration/clitkConvertPointList.ggo | 15 + registration/clitkDeformationFieldTransform.h | 86 + .../clitkDeformationFieldTransform.txx | 61 + .../clitkDeformationListStatisticsFilter.h | 86 + .../clitkDeformationListStatisticsFilter.txx | 205 + .../clitkDemonsDeformableRegistration.cxx | 47 + .../clitkDemonsDeformableRegistration.ggo | 48 + ...onsDeformableRegistrationGenericFilter.cxx | 52 + ...emonsDeformableRegistrationGenericFilter.h | 112 + ...onsDeformableRegistrationGenericFilter.txx | 691 +++ registration/clitkDifferenceImageFilter.h | 73 + registration/clitkDifferenceImageFilter.txx | 85 + registration/clitkExtractImageFilter.h | 113 + registration/clitkExtractImageFilter.txx | 274 ++ registration/clitkGenericVectorInterpolator.h | 93 + .../clitkGenericVectorInterpolator.txx | 90 + registration/clitkLBFGSBOptimizer.cxx | 257 +- registration/clitkLBFGSBOptimizer.h | 60 +- .../clitkLinearCombinationImageFilter.h | 94 + .../clitkLinearCombinationImageFilter.txx | 210 + registration/clitkList.h | 85 + registration/clitkList.txx | 363 ++ registration/clitkLists.h | 83 + registration/clitkLists.txx | 180 + registration/clitkMatrixTransformToVF.cxx | 51 + registration/clitkMatrixTransformToVF.ggo | 18 + .../clitkMatrixTransformToVFGenericFilter.cxx | 71 + .../clitkMatrixTransformToVFGenericFilter.h | 115 + .../clitkMatrixTransformToVFGenericFilter.txx | 145 + ...MultiResolutionPDEDeformableRegistration.h | 235 + ...ltiResolutionPDEDeformableRegistration.txx | 574 +++ registration/clitkMultiResolutionPyramid.cxx | 51 + registration/clitkMultiResolutionPyramid.ggo | 18 + ...itkMultiResolutionPyramidGenericFilter.cxx | 72 + ...clitkMultiResolutionPyramidGenericFilter.h | 117 + ...itkMultiResolutionPyramidGenericFilter.txx | 162 + .../clitkMultiResolutionPyramidRegionFilter.h | 115 + ...litkMultiResolutionPyramidRegionFilter.txx | 88 + registration/clitkPointListReader.h | 71 + registration/clitkPointListReader.txx | 75 + registration/clitkPointListTransform.h | 95 + registration/clitkPointListTransform.txx | 146 + registration/clitkPointListWriter.h | 78 + registration/clitkPointListWriter.txx | 90 + registration/clitkPointTrajectory.cxx | 51 + registration/clitkPointTrajectory.ggo | 26 + .../clitkPointTrajectoryGenericFilter.cxx | 380 ++ .../clitkPointTrajectoryGenericFilter.h | 110 + ...emporalMultiResolutionPyramidImageFilter.h | 94 + ...poralMultiResolutionPyramidImageFilter.txx | 479 ++ ...litkResampleBSplineDeformableTransform.cxx | 51 + ...litkResampleBSplineDeformableTransform.ggo | 22 + ...SplineDeformableTransformGenericFilter.cxx | 71 + ...eBSplineDeformableTransformGenericFilter.h | 116 + ...SplineDeformableTransformGenericFilter.txx | 158 + ...pleBSplineDeformableTransformImageFilter.h | 179 + ...eBSplineDeformableTransformImageFilter.txx | 138 + registration/clitkSelectPoints.cxx | 51 + registration/clitkSelectPoints.ggo | 24 + .../clitkSelectPointsGenericFilter.cxx | 141 + registration/clitkSelectPointsGenericFilter.h | 103 + .../clitkShapedBLUTSpatioTemporalDIR.cxx | 51 + .../clitkShapedBLUTSpatioTemporalDIR.ggo | 90 + ...apedBLUTSpatioTemporalDIRGenericFilter.cxx | 70 + ...ShapedBLUTSpatioTemporalDIRGenericFilter.h | 130 + ...apedBLUTSpatioTemporalDIRGenericFilter.txx | 929 ++++ ...pedBLUTSpatioTemporalDeformableTransform.h | 445 ++ ...dBLUTSpatioTemporalDeformableTransform.txx | 4340 +++++++++++++++++ ...ioTemporalDeformableTransformInitializer.h | 183 + ...TemporalDeformableTransformInitializer.txx | 503 ++ ...alMultiResolutionImageRegistrationMethod.h | 247 + ...MultiResolutionImageRegistrationMethod.txx | 528 ++ ...emporalMultiResolutionPyramidImageFilter.h | 162 + ...poralMultiResolutionPyramidImageFilter.txx | 629 +++ .../clitkTransformToDeformationFieldSource.h | 223 + ...clitkTransformToDeformationFieldSource.txx | 380 ++ 107 files changed, 23369 insertions(+), 133 deletions(-) create mode 100755 registration/clitkBLUTDIR.cxx create mode 100755 registration/clitkBLUTDIR.ggo create mode 100755 registration/clitkBLUTDIRGenericFilter.cxx create mode 100755 registration/clitkBLUTDIRGenericFilter.h create mode 100755 registration/clitkBLUTDIRGenericFilter.txx create mode 100755 registration/clitkBSplineDeformableRegistration.cxx create mode 100755 registration/clitkBSplineDeformableRegistration.ggo create mode 100755 registration/clitkBSplineDeformableRegistrationGenericFilter.cxx create mode 100755 registration/clitkBSplineDeformableRegistrationGenericFilter.h create mode 100755 registration/clitkBSplineDeformableRegistrationGenericFilter.txx create mode 100644 registration/clitkBSplineDeformableTransform.h create mode 100644 registration/clitkBSplineDeformableTransform.txx create mode 100644 registration/clitkBSplineDeformableTransformInitializer.h create mode 100644 registration/clitkBSplineDeformableTransformInitializer.txx create mode 100644 registration/clitkBSplinePyramid.cxx create mode 100644 registration/clitkBSplinePyramid.ggo create mode 100644 registration/clitkBSplinePyramidGenericFilter.cxx create mode 100644 registration/clitkBSplinePyramidGenericFilter.h create mode 100644 registration/clitkBSplinePyramidGenericFilter.txx create mode 100755 registration/clitkCalculateTRE.cxx create mode 100755 registration/clitkCalculateTRE.ggo create mode 100755 registration/clitkCalculateTREGenericFilter.cxx create mode 100755 registration/clitkCalculateTREGenericFilter.h create mode 100755 registration/clitkCalculateTREGenericFilter.txx create mode 100755 registration/clitkConvertBSplineDeformableTransformToVF.cxx create mode 100755 registration/clitkConvertBSplineDeformableTransformToVF.ggo create mode 100755 registration/clitkConvertBSplineDeformableTransformToVFGenericFilter.cxx create mode 100755 registration/clitkConvertBSplineDeformableTransformToVFGenericFilter.h create mode 100755 registration/clitkConvertPointList.cxx create mode 100755 registration/clitkConvertPointList.ggo create mode 100644 registration/clitkDeformationFieldTransform.h create mode 100644 registration/clitkDeformationFieldTransform.txx create mode 100644 registration/clitkDeformationListStatisticsFilter.h create mode 100644 registration/clitkDeformationListStatisticsFilter.txx create mode 100755 registration/clitkDemonsDeformableRegistration.cxx create mode 100755 registration/clitkDemonsDeformableRegistration.ggo create mode 100755 registration/clitkDemonsDeformableRegistrationGenericFilter.cxx create mode 100755 registration/clitkDemonsDeformableRegistrationGenericFilter.h create mode 100755 registration/clitkDemonsDeformableRegistrationGenericFilter.txx create mode 100755 registration/clitkDifferenceImageFilter.h create mode 100755 registration/clitkDifferenceImageFilter.txx create mode 100644 registration/clitkExtractImageFilter.h create mode 100644 registration/clitkExtractImageFilter.txx create mode 100755 registration/clitkGenericVectorInterpolator.h create mode 100755 registration/clitkGenericVectorInterpolator.txx create mode 100644 registration/clitkLinearCombinationImageFilter.h create mode 100644 registration/clitkLinearCombinationImageFilter.txx create mode 100644 registration/clitkList.h create mode 100644 registration/clitkList.txx create mode 100644 registration/clitkLists.h create mode 100644 registration/clitkLists.txx create mode 100755 registration/clitkMatrixTransformToVF.cxx create mode 100755 registration/clitkMatrixTransformToVF.ggo create mode 100755 registration/clitkMatrixTransformToVFGenericFilter.cxx create mode 100755 registration/clitkMatrixTransformToVFGenericFilter.h create mode 100755 registration/clitkMatrixTransformToVFGenericFilter.txx create mode 100755 registration/clitkMultiResolutionPDEDeformableRegistration.h create mode 100755 registration/clitkMultiResolutionPDEDeformableRegistration.txx create mode 100644 registration/clitkMultiResolutionPyramid.cxx create mode 100644 registration/clitkMultiResolutionPyramid.ggo create mode 100644 registration/clitkMultiResolutionPyramidGenericFilter.cxx create mode 100644 registration/clitkMultiResolutionPyramidGenericFilter.h create mode 100644 registration/clitkMultiResolutionPyramidGenericFilter.txx create mode 100644 registration/clitkMultiResolutionPyramidRegionFilter.h create mode 100644 registration/clitkMultiResolutionPyramidRegionFilter.txx create mode 100644 registration/clitkPointListReader.h create mode 100644 registration/clitkPointListReader.txx create mode 100644 registration/clitkPointListTransform.h create mode 100644 registration/clitkPointListTransform.txx create mode 100644 registration/clitkPointListWriter.h create mode 100644 registration/clitkPointListWriter.txx create mode 100755 registration/clitkPointTrajectory.cxx create mode 100755 registration/clitkPointTrajectory.ggo create mode 100755 registration/clitkPointTrajectoryGenericFilter.cxx create mode 100755 registration/clitkPointTrajectoryGenericFilter.h create mode 100644 registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.h create mode 100644 registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.txx create mode 100644 registration/clitkResampleBSplineDeformableTransform.cxx create mode 100644 registration/clitkResampleBSplineDeformableTransform.ggo create mode 100644 registration/clitkResampleBSplineDeformableTransformGenericFilter.cxx create mode 100644 registration/clitkResampleBSplineDeformableTransformGenericFilter.h create mode 100644 registration/clitkResampleBSplineDeformableTransformGenericFilter.txx create mode 100644 registration/clitkResampleBSplineDeformableTransformImageFilter.h create mode 100644 registration/clitkResampleBSplineDeformableTransformImageFilter.txx create mode 100755 registration/clitkSelectPoints.cxx create mode 100755 registration/clitkSelectPoints.ggo create mode 100755 registration/clitkSelectPointsGenericFilter.cxx create mode 100755 registration/clitkSelectPointsGenericFilter.h create mode 100755 registration/clitkShapedBLUTSpatioTemporalDIR.cxx create mode 100755 registration/clitkShapedBLUTSpatioTemporalDIR.ggo create mode 100755 registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.cxx create mode 100755 registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.h create mode 100755 registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.txx create mode 100755 registration/clitkShapedBLUTSpatioTemporalDeformableTransform.h create mode 100755 registration/clitkShapedBLUTSpatioTemporalDeformableTransform.txx create mode 100755 registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.h create mode 100755 registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.txx create mode 100644 registration/clitkSpatioTemporalMultiResolutionImageRegistrationMethod.h create mode 100644 registration/clitkSpatioTemporalMultiResolutionImageRegistrationMethod.txx create mode 100644 registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.h create mode 100644 registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.txx create mode 100644 registration/clitkTransformToDeformationFieldSource.h create mode 100644 registration/clitkTransformToDeformationFieldSource.txx diff --git a/registration/CMakeLists.txt b/registration/CMakeLists.txt index 5963898..ebefbd8 100644 --- a/registration/CMakeLists.txt +++ b/registration/CMakeLists.txt @@ -1,4 +1,59 @@ +############################## registration algorithms + 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) +WRAP_GGO(clitkDemonsDeformableRegistration_GGO_C clitkDemonsDeformableRegistration.ggo) +ADD_EXECUTABLE(clitkDemonsDeformableRegistration clitkDemonsDeformableRegistration.cxx ${clitkDemonsDeformableRegistration_GGO_C} clitkDemonsDeformableRegistrationGenericFilter.cxx) +TARGET_LINK_LIBRARIES(clitkDemonsDeformableRegistration ITKNumerics ITKIO clitkCommon) + +WRAP_GGO(clitkBLUTDIR_GGO_C clitkBLUTDIR.ggo) +ADD_EXECUTABLE(clitkBLUTDIR clitkBLUTDIR.cxx clitkBLUTDIRGenericFilter.cxx ${clitkBLUTDIR_GGO_C} clitkLBFGSBOptimizer.cxx ) +TARGET_LINK_LIBRARIES(clitkBLUTDIR clitkCommon ITKIO ITKNumerics ITKStatistics) + +WRAP_GGO(clitkShapedBLUTSpatioTemporalDIR_GGO_C clitkShapedBLUTSpatioTemporalDIR.ggo) +ADD_EXECUTABLE(clitkShapedBLUTSpatioTemporalDIR clitkShapedBLUTSpatioTemporalDIR.cxx clitkShapedBLUTSpatioTemporalDIRGenericFilter.cxx ${clitkShapedBLUTSpatioTemporalDIR_GGO_C} clitkLBFGSBOptimizer.cxx) +TARGET_LINK_LIBRARIES(clitkShapedBLUTSpatioTemporalDIR clitkCommon ITKNumerics ITKStatistics ITKIO) + +WRAP_GGO(clitkBSplineDeformableRegistration_GGO_C clitkBSplineDeformableRegistration.ggo) +ADD_EXECUTABLE(clitkBSplineDeformableRegistration clitkBSplineDeformableRegistration.cxx clitkBSplineDeformableRegistrationGenericFilter.cxx ${clitkBSplineDeformableRegistration_GGO_C} clitkLBFGSBOptimizer.cxx) +TARGET_LINK_LIBRARIES(clitkBSplineDeformableRegistration clitkCommon ITKNumerics ITKStatistics ITKIO) + + +############################## registration-related tools to process points, bsplines, vf and image pyramids +WRAP_GGO(clitkConvertPointList_GGO_C clitkConvertPointList.ggo) +ADD_EXECUTABLE(clitkConvertPointList clitkConvertPointList.cxx ${clitkConvertPointList_GGO_C}) +TARGET_LINK_LIBRARIES(clitkConvertPointList ITKIO clitkCommon ) + +WRAP_GGO(clitkSelectPoints_GGO_C clitkSelectPoints.ggo) +ADD_EXECUTABLE(clitkSelectPoints clitkSelectPoints.cxx clitkSelectPointsGenericFilter.cxx ${clitkSelectPoints_GGO_C}) +TARGET_LINK_LIBRARIES(clitkSelectPoints clitkCommon ITKIO) + +WRAP_GGO(clitkPointTrajectory_GGO_C clitkPointTrajectory.ggo) +ADD_EXECUTABLE(clitkPointTrajectory clitkPointTrajectory.cxx clitkPointTrajectoryGenericFilter.cxx ${clitkPointTrajectory_GGO_C}) +TARGET_LINK_LIBRARIES(clitkPointTrajectory clitkCommon ITKIO) + +WRAP_GGO(clitkCalculateTRE_GGO_C clitkCalculateTRE.ggo) +ADD_EXECUTABLE(clitkCalculateTRE clitkCalculateTRE.cxx clitkCalculateTREGenericFilter.cxx ${clitkCalculateTRE_GGO_C}) +TARGET_LINK_LIBRARIES(clitkCalculateTRE clitkCommon ITKIO ) + +WRAP_GGO(clitkMatrixTransformToVF_GGO_C clitkMatrixTransformToVF.ggo) +ADD_EXECUTABLE(clitkMatrixTransformToVF clitkMatrixTransformToVF.cxx clitkMatrixTransformToVFGenericFilter.cxx ${clitkMatrixTransformToVF_GGO_C}) +TARGET_LINK_LIBRARIES(clitkMatrixTransformToVF ITKIO clitkCommon) + +WRAP_GGO(clitkConvertBSplineDeformableTransformToVF_GGO_C clitkConvertBSplineDeformableTransformToVF.ggo) +ADD_EXECUTABLE(clitkConvertBSplineDeformableTransformToVF clitkConvertBSplineDeformableTransformToVF.cxx clitkConvertBSplineDeformableTransformToVFGenericFilter.cxx ${clitkConvertBSplineDeformableTransformToVF_GGO_C}) +TARGET_LINK_LIBRARIES(clitkConvertBSplineDeformableTransformToVF clitkCommon ITKIO) + +WRAP_GGO(clitkMultiResolutionPyramid_GGO_C clitkMultiResolutionPyramid.ggo) +ADD_EXECUTABLE(clitkMultiResolutionPyramid clitkMultiResolutionPyramid.cxx clitkMultiResolutionPyramidGenericFilter.cxx ${clitkMultiResolutionPyramid_GGO_C}) +TARGET_LINK_LIBRARIES(clitkMultiResolutionPyramid clitkCommon ITKIO) + +WRAP_GGO(clitkBSplinePyramid_GGO_C clitkBSplinePyramid.ggo) +ADD_EXECUTABLE(clitkBSplinePyramid clitkBSplinePyramid.cxx clitkBSplinePyramidGenericFilter.cxx ${clitkBSplinePyramid_GGO_C}) +TARGET_LINK_LIBRARIES(clitkBSplinePyramid clitkCommon ITKIO) + +WRAP_GGO(clitkResampleBSplineDeformableTransform_GGO_C clitkResampleBSplineDeformableTransform.ggo) +ADD_EXECUTABLE(clitkResampleBSplineDeformableTransform clitkResampleBSplineDeformableTransform.cxx clitkResampleBSplineDeformableTransformGenericFilter.cxx ${clitkResampleBSplineDeformableTransform_GGO_C}) +TARGET_LINK_LIBRARIES(clitkResampleBSplineDeformableTransform clitkCommon ITKIO) diff --git a/registration/clitkAffineRegistration.ggo b/registration/clitkAffineRegistration.ggo index 6c26878..a5d0385 100644 --- a/registration/clitkAffineRegistration.ggo +++ b/registration/clitkAffineRegistration.ggo @@ -1,7 +1,7 @@ # file clitkAffineRegistration.ggo package "clitk" version "1.0" -purpose "Compute an affine registration between two images." +purpose "Perform an affine registration between two images." option "config" - "Config file" string no @@ -12,7 +12,7 @@ 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.)" +section "Input (Both images have to be of the same dimension (2 or 3D). For 2D-3D (non-projective) 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 @@ -54,7 +54,7 @@ option "subtractMean" - "1: Subtract mean for NCC calculation (narrows opt 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 +option "explicitPDFDerivatives" - "6: Calculate PDF derivatives explicitly (affine=true; FFD=false)" flag on section "Preprocessing" @@ -82,7 +82,7 @@ option "selectBound" - "7: Select the type of bound: 0=none, 1=u, 2=u&l, 3=l" 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 "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" diff --git a/registration/clitkBLUTDIR.cxx b/registration/clitkBLUTDIR.cxx new file mode 100755 index 0000000..2570b7b --- /dev/null +++ b/registration/clitkBLUTDIR.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkBLUTDIR.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkBLUTDIR_ggo.h" +#include "clitkIO.h" +#include "clitkBLUTDIRGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkBLUTDIR, args_info); + CLITK_INIT; + + // Filter + clitk::BLUTDIRGenericFilter::Pointer genericFilter=clitk::BLUTDIRGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkBLUTDIR.ggo b/registration/clitkBLUTDIR.ggo new file mode 100755 index 0000000..152c67f --- /dev/null +++ b/registration/clitkBLUTDIR.ggo @@ -0,0 +1,87 @@ +#File clitkBLUTDIR.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 11 Jan 2009 10.35 + +Package "clitk" +Version "Register 2 images using optimized BLUT FFD..." + +option "config" - "Config file" string no + + +section "Run Time" + +option "verbose" v "Verbose" flag off +option "threads" - "Number of threads to use (default=min(#cores,8))" int no + + +section "Input" + +option "reference" r "Input reference 3D image (float)" string yes +option "target" t "Input target 2D image (float)" 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 "vf" - "Result DVF" string yes +option "coeff" - "Result coefficient images" string no +option "output" o "Deformed target image" string yes +option "before" - "Difference image before (but after rigid transform)" string no +option "after" - "Difference image after " string no + + +section "Transform (Note that only one of --control, --spacing is required. The other will be adjusted to fit the region and allow exact representation. SamplingFactor will be set accordingly" + +option "initMatrix" - "Prior rigid/affine transform matrix from reference to target space" string no +option "initCoeff" - "Initial coefficient image" string no +option "order" - "Spline Order FFD" int no multiple default="3" +option "control" - "Internal control points for each dimension" int no multiple +option "spacing" - "Control point spacing for each dimension (mm)" double no multiple +option "samplingFactor" - "LUT sampling factor" int no multiple + + +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 "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 off + + +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="7" +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 default="0.0" +option "upperBound" - "7: The upper bound" double no default="0.0" + + +Section "Registration" + +option "levels" - "Number of resolution levels" int no default="1" +option "intermediate" - "Write the coefficient image of the intermediate levels (provide levels filenames)" string no multiple + diff --git a/registration/clitkBLUTDIRGenericFilter.cxx b/registration/clitkBLUTDIRGenericFilter.cxx new file mode 100755 index 0000000..c728fcd --- /dev/null +++ b/registration/clitkBLUTDIRGenericFilter.cxx @@ -0,0 +1,73 @@ +/*========================================================================= + 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 clitkBLUTDIRGenericFilter_cxx +#define clitkBLUTDIRGenericFilter_cxx + +/* ================================================= + * @file clitkBLUTDIRGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkBLUTDIRGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + BLUTDIRGenericFilter::BLUTDIRGenericFilter() + { + m_Verbose=false; + m_ReferenceFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void BLUTDIRGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_ReferenceFileName, Dimension, PixelType); + + + // Call UpdateWithDim + //if(Dimension==2) UpdateWithDim<2>(PixelType); + //else + if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( BLUTDIRGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkBLUTDIR & a) + { + m_ArgsInfo=a; + m_ReferenceFileName=m_ArgsInfo.reference_arg; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + BLUTDIRGenericFilter(); + ~BLUTDIRGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkBLUTDIR m_ArgsInfo; + bool m_Verbose; + std::string m_ReferenceFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkBLUTDIRGenericFilter.txx" +#endif + +#endif // #define clitkBLUTDIRGenericFilter_h diff --git a/registration/clitkBLUTDIRGenericFilter.txx b/registration/clitkBLUTDIRGenericFilter.txx new file mode 100755 index 0000000..08f0d74 --- /dev/null +++ b/registration/clitkBLUTDIRGenericFilter.txx @@ -0,0 +1,848 @@ +/*========================================================================= + 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 clitkBLUTDIRGenericFilter_txx +#define clitkBLUTDIRGenericFilter_txx + +/* ================================================= + * @file clitkBLUTDIRGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkBLUTDIRGenericFilter.h" + +namespace clitk +{ + + //============================================================================== + // Creating an observer class that allows output at each iteration + //============================================================================== + class CommandIterationUpdate : public itk::Command + { + public: + typedef CommandIterationUpdate Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + itkNewMacro( Self ); + protected: + CommandIterationUpdate() {}; + public: + typedef clitk::GenericOptimizer 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 + class RegistrationInterfaceCommand : public itk::Command + { + public: + typedef RegistrationInterfaceCommand Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + itkNewMacro( Self ); + protected: + RegistrationInterfaceCommand() {}; + public: + + // Registration + typedef TRegistration RegistrationType; + typedef RegistrationType * RegistrationPointer; + + // Transform + typedef typename RegistrationType::FixedImageType FixedImageType; + typedef typename FixedImageType::RegionType RegionType; + itkStaticConstMacro(ImageDimension, unsigned int,FixedImageType::ImageDimension); + typedef clitk::BSplineDeformableTransform TransformType; + typedef clitk::BSplineDeformableTransformInitializer InitializerType; + typedef typename InitializerType::CoefficientImageType CoefficientImageType; + typedef itk::CastImageFilter CastImageFilterType; + typedef typename TransformType::ParametersType ParametersType; + typedef typename InitializerType::Pointer InitializerPointer; + typedef CommandIterationUpdate::Pointer CommandIterationUpdatePointer; + + // Optimizer + typedef clitk::GenericOptimizer GenericOptimizerType; + typedef typename GenericOptimizerType::Pointer GenericOptimizerPointer; + + // Metric + typedef typename RegistrationType::FixedImageType InternalImageType; + typedef clitk::GenericMetric GenericMetricType; + typedef typename GenericMetricType::Pointer GenericMetricPointer; + + // 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( object ); + unsigned int numberOfLevels=registration->GetNumberOfLevels(); + unsigned int currentLevel=registration->GetCurrentLevel()+1; + + // Output the levels + std::cout<1) + { + // fixed image region pyramid + typedef clitk::MultiResolutionPyramidRegionFilter FixedImageRegionPyramidType; + typename FixedImageRegionPyramidType::Pointer fixedImageRegionPyramid=FixedImageRegionPyramidType::New(); + fixedImageRegionPyramid->SetRegion(m_MetricRegion); + fixedImageRegionPyramid->SetSchedule(registration->GetFixedImagePyramid()->GetSchedule()); + + // Reinitialize the metric (!= number of samples) + m_GenericMetric= GenericMetricType::New(); + m_GenericMetric->SetArgsInfo(m_ArgsInfo); + m_GenericMetric->SetFixedImage(registration->GetFixedImagePyramid()->GetOutput(registration->GetCurrentLevel())); + if (m_ArgsInfo.referenceMask_given) m_GenericMetric->SetFixedImageMask(registration->GetMetric()->GetFixedImageMask()); + m_GenericMetric->SetFixedImageRegion(fixedImageRegionPyramid->GetOutput(registration->GetCurrentLevel())); + typedef itk::ImageToImageMetric< InternalImageType, InternalImageType > MetricType; + typename MetricType::Pointer metric=m_GenericMetric->GetMetricPointer(); + registration->SetMetric(metric); + + // Get the current coefficient image and make a COPY + typename itk::ImageDuplicator::Pointer caster=itk::ImageDuplicator::New(); + caster->SetInputImage(m_Initializer->GetTransform()->GetCoefficientImage()); + caster->Update(); + typename CoefficientImageType::Pointer currentCoefficientImage=caster->GetOutput(); + + // Write the intermediate result? + if (m_ArgsInfo.intermediate_given>=numberOfLevels) + writeImage(currentCoefficientImage, m_ArgsInfo.intermediate_arg[currentLevel-2], m_ArgsInfo.verbose_flag); + + // Set the new transform properties + m_Initializer->SetImage(registration->GetFixedImagePyramid()->GetOutput(currentLevel-1)); + if( m_Initializer->m_ControlPointSpacingIsGiven) + m_Initializer->SetControlPointSpacing(m_Initializer->m_ControlPointSpacingArray[registration->GetCurrentLevel()]); + if( m_Initializer->m_NumberOfControlPointsIsGiven) + m_Initializer->SetNumberOfControlPointsInsideTheImage(m_Initializer->m_NumberOfControlPointsInsideTheImageArray[registration->GetCurrentLevel()]); + + // Reinitialize the transform + if (m_ArgsInfo.verbose_flag) std::cout<<"Initializing transform for level "<InitializeTransform(); + ParametersType* newParameters= new typename TransformType::ParametersType(m_Initializer->GetTransform()->GetNumberOfParameters()); + + // Reinitialize an Optimizer (!= number of parameters) + m_GenericOptimizer = GenericOptimizerType::New(); + m_GenericOptimizer->SetArgsInfo(m_ArgsInfo); + m_GenericOptimizer->SetMaximize(m_Maximize); + m_GenericOptimizer->SetNumberOfParameters(m_Initializer->GetTransform()->GetNumberOfParameters()); + typedef itk::SingleValuedNonLinearOptimizer OptimizerType; + OptimizerType::Pointer optimizer = m_GenericOptimizer->GetOptimizerPointer(); + optimizer->AddObserver( itk::IterationEvent(), m_CommandIterationUpdate); + registration->SetOptimizer(optimizer); + m_CommandIterationUpdate->SetOptimizer(m_GenericOptimizer); + + // Set the previous transform parameters to the registration + // if(m_Initializer->m_Parameters!=NULL )delete m_Initializer->m_Parameters; + m_Initializer->SetInitialParameters(currentCoefficientImage,*newParameters); + registration->SetInitialTransformParametersOfNextLevel(*newParameters); + } + } + + void Execute(const itk::Object * , const itk::EventObject & ) + { return; } + + + // Members + void SetInitializer(InitializerPointer i){m_Initializer=i;} + InitializerPointer m_Initializer; + + void SetArgsInfo(args_info_clitkBLUTDIR a){m_ArgsInfo=a;} + args_info_clitkBLUTDIR m_ArgsInfo; + + void SetCommandIterationUpdate(CommandIterationUpdatePointer c){m_CommandIterationUpdate=c;}; + CommandIterationUpdatePointer m_CommandIterationUpdate; + + GenericOptimizerPointer m_GenericOptimizer; + void SetMaximize(bool b){m_Maximize=b;} + bool m_Maximize; + + GenericMetricPointer m_GenericMetric; + void SetMetricRegion(RegionType i){m_MetricRegion=i;} + RegionType m_MetricRegion; + + + }; + + + //============================================================================== + // Update with the number of dimensions + //============================================================================== + template + void BLUTDIRGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "unsigned_char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + //============================================================================== + // Update with the number of dimensions and pixeltype + //============================================================================== + template + void + BLUTDIRGenericFilter::UpdateWithDimAndPixelType() + { + + + //============================================================================= + //Input + //============================================================================= + bool threadsGiven=m_ArgsInfo.threads_given; + int threads=m_ArgsInfo.threads_arg; + + typedef itk::Image< PixelType, ImageDimension > FixedImageType; + typedef itk::Image< PixelType, ImageDimension > MovingImageType; + const unsigned int SpaceDimension = ImageDimension; + typedef double TCoordRep; + + + //======================================================= + //Input + //======================================================= + typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; + typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType; + + typename FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); + typename MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); + + fixedImageReader->SetFileName( m_ArgsInfo.reference_arg ); + movingImageReader->SetFileName( m_ArgsInfo.target_arg ); + if (m_Verbose) std::cout<<"Reading images..."<Update(); + movingImageReader->Update(); + + typename FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); + typename MovingImageType::Pointer movingImage =movingImageReader->GetOutput(); + typename FixedImageType::Pointer croppedFixedImage=fixedImage; + + + //======================================================= + // Regions + //======================================================= + + // The original input region + typename FixedImageType::RegionType fixedImageRegion = fixedImage->GetLargestPossibleRegion(); + + // The transform region with respect to the input region: + // where should the transform be DEFINED (depends on mask) + typename FixedImageType::RegionType transformRegion = fixedImage->GetLargestPossibleRegion(); + typename FixedImageType::RegionType::SizeType transformRegionSize=transformRegion.GetSize(); + typename FixedImageType::RegionType::IndexType transformRegionIndex=transformRegion.GetIndex(); + typename FixedImageType::PointType transformRegionOrigin=fixedImage->GetOrigin(); + + // The metric region with respect to the extracted transform region: + // where should the metric be CALCULATED (depends on transform) + typename FixedImageType::RegionType metricRegion = fixedImage->GetLargestPossibleRegion(); + typename FixedImageType::RegionType::SizeType metricRegionSize=metricRegion.GetSize(); + typename FixedImageType::RegionType::IndexType metricRegionIndex=metricRegion.GetIndex(); + typename FixedImageType::PointType metricRegionOrigin=fixedImage->GetOrigin(); + + + //=========================================================================== + // If given, we connect a mask to reference or target + //============================================================================ + typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; + typename MaskType::Pointer fixedMask=NULL; + if (m_ArgsInfo.referenceMask_given) + { + fixedMask= MaskType::New(); + typedef itk::Image< unsigned char, ImageDimension > 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..." <SetImage( maskReader->GetOutput() ); + + // Find the bounding box of the "inside" label + typedef itk::LabelStatisticsImageFilter StatisticsImageFilterType; + typename StatisticsImageFilterType::Pointer statisticsImageFilter=StatisticsImageFilterType::New(); + statisticsImageFilter->SetInput(maskReader->GetOutput()); + statisticsImageFilter->SetLabelInput(maskReader->GetOutput()); + statisticsImageFilter->Update(); + typename StatisticsImageFilterType::BoundingBoxType boundingBox = statisticsImageFilter->GetBoundingBox(1); + + // Limit the transform region to the mask + for (unsigned int i=0; iTransformIndexToPhysicalPoint(transformRegion.GetIndex(), transformRegionOrigin); + + // Crop the fixedImage to the bounding box to facilitate multi-resolution + typedef itk::ExtractImageFilter ExtractImageFilterType; + typename ExtractImageFilterType::Pointer extractImageFilter=ExtractImageFilterType::New(); + extractImageFilter->SetInput(fixedImage); + extractImageFilter->SetExtractionRegion(transformRegion); + extractImageFilter->Update(); + croppedFixedImage=extractImageFilter->GetOutput(); + + // Update the metric region + metricRegion = croppedFixedImage->GetLargestPossibleRegion(); + metricRegionIndex=metricRegion.GetIndex(); + croppedFixedImage->TransformIndexToPhysicalPoint(metricRegionIndex, metricRegionOrigin); + + // Set start index to zero (with respect to croppedFixedImage/transform region) + metricRegionIndex.Fill(0); + metricRegion.SetIndex(metricRegionIndex); + croppedFixedImage->SetRegions(metricRegion); + croppedFixedImage->SetOrigin(metricRegionOrigin); + } + + typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; + typename MaskType::Pointer movingMask=NULL; + if (m_ArgsInfo.targetMask_given) + { + movingMask= MaskType::New(); + typedef itk::Image< unsigned char, ImageDimension > 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..." <SetImage( maskReader->GetOutput() ); + } + + + //======================================================= + // Output Regions + //======================================================= + + if (m_Verbose) + { + // Fixed image region + std::cout<<"The fixed image has its origin at "<GetOrigin()< FixedImagePyramidType; + typedef itk::RecursiveMultiResolutionPyramidImageFilter< MovingImageType, MovingImageType> MovingImagePyramidType; + typename FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New(); + typename MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New(); + fixedImagePyramid->SetUseShrinkImageFilter(false); + fixedImagePyramid->SetInput(croppedFixedImage); + 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..."<Update(); + movingImagePyramid->Update(); + typedef clitk::MultiResolutionPyramidRegionFilter FixedImageRegionPyramidType; + typename FixedImageRegionPyramidType::Pointer fixedImageRegionPyramid=FixedImageRegionPyramidType::New(); + fixedImageRegionPyramid->SetRegion(metricRegion); + fixedImageRegionPyramid->SetSchedule(fixedImagePyramid->GetSchedule()); + + + //======================================================= + // Rigid or Affine Transform + //======================================================= + typedef itk::AffineTransform RigidTransformType; + RigidTransformType::Pointer rigidTransform=NULL; + if (m_ArgsInfo.initMatrix_given) + { + if(m_Verbose) std::cout<<"Reading the prior transform matrix "<< m_ArgsInfo.initMatrix_arg<<"..."< rigidTransformMatrix=clitk::ReadMatrix3D(m_ArgsInfo.initMatrix_arg); + + //Set the rotation + itk::Matrix finalRotation = clitk::GetRotationalPartMatrix3D(rigidTransformMatrix); + rigidTransform->SetMatrix(finalRotation); + + //Set the translation + itk::Vector finalTranslation = clitk::GetTranslationPartMatrix3D(rigidTransformMatrix); + rigidTransform->SetTranslation(finalTranslation); + } + + + //======================================================= + // B-LUT FFD Transform + //======================================================= + typedef clitk::BSplineDeformableTransform TransformType; + typename TransformType::Pointer transform= TransformType::New(); + if (fixedMask) transform->SetMask( fixedMask ); + if (rigidTransform) transform->SetBulkTransform( rigidTransform ); + + //------------------------------------------------------------------------- + // The transform initializer + //------------------------------------------------------------------------- + typedef clitk::BSplineDeformableTransformInitializer< TransformType,FixedImageType> InitializerType; + typename InitializerType::Pointer initializer = InitializerType::New(); + initializer->SetVerbose(m_Verbose); + initializer->SetImage(fixedImagePyramid->GetOutput(0)); + initializer->SetTransform(transform); + + //------------------------------------------------------------------------- + // Order + //------------------------------------------------------------------------- + typename FixedImageType::RegionType::SizeType splineOrders ; + splineOrders.Fill(3); + if (m_ArgsInfo.order_given) + for(unsigned int i=0; iSetSplineOrders(splineOrders); + + //------------------------------------------------------------------------- + // Levels + //------------------------------------------------------------------------- + + // Spacing + if (m_ArgsInfo.spacing_given) + { + initializer->m_ControlPointSpacingArray.resize(m_ArgsInfo.levels_arg); + initializer->SetControlPointSpacing(m_ArgsInfo.spacing_arg); + initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1]=initializer->m_ControlPointSpacing; + if (m_Verbose) std::cout<<"Using a control point spacing of "<m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1] + <<" at level "<m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i]=initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-i]*2; + if (m_Verbose) std::cout<<"Using a control point spacing of "<m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i] + <<" at level "<m_NumberOfControlPointsInsideTheImageArray.resize(m_ArgsInfo.levels_arg); + initializer->SetNumberOfControlPointsInsideTheImage(m_ArgsInfo.control_arg); + initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1]=initializer->m_NumberOfControlPointsInsideTheImage; + if (m_Verbose) std::cout<<"Using "<< initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1]<<"control points inside the image" + <<" at level "<m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i][j]=ceil ((double)initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-i][j]/2.); + // initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i]=ceil ((double)initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-i]/2.); + if (m_Verbose) std::cout<<"Using "<< initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i]<<"control points inside the image" + <<" at level "<SetControlPointSpacing( initializer->m_ControlPointSpacingArray[0]); + if (m_ArgsInfo.control_given) initializer->SetNumberOfControlPointsInsideTheImage(initializer->m_NumberOfControlPointsInsideTheImageArray[0]); + if (m_ArgsInfo.samplingFactor_given) initializer->SetSamplingFactors(m_ArgsInfo.samplingFactor_arg); + + // Initialize + initializer->InitializeTransform(); + + //------------------------------------------------------------------------- + // Initial parameters (passed by reference) + //------------------------------------------------------------------------- + typedef typename TransformType::ParametersType ParametersType; + const unsigned int numberOfParameters = transform->GetNumberOfParameters(); + ParametersType parameters(numberOfParameters); + parameters.Fill( 0.0 ); + transform->SetParameters( parameters ); + if (m_ArgsInfo.initCoeff_given) initializer->SetInitialParameters(m_ArgsInfo.initCoeff_arg, parameters); + + + //======================================================= + // Interpolator + //======================================================= + typedef clitk::GenericInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + typedef itk::InterpolateImageFunction< FixedImageType, TCoordRep > InterpolatorType; + typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + + + //======================================================= + // Metric + //======================================================= + typedef clitk::GenericMetric GenericMetricType; + typename GenericMetricType::Pointer genericMetric=GenericMetricType::New(); + genericMetric->SetArgsInfo(m_ArgsInfo); + genericMetric->SetFixedImage(fixedImagePyramid->GetOutput(0)); + if (fixedMask) genericMetric->SetFixedImageMask(fixedMask); + genericMetric->SetFixedImageRegion(fixedImageRegionPyramid->GetOutput(0)); + typedef itk::ImageToImageMetric< FixedImageType, MovingImageType > 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)..."< GenericOptimizerType; + GenericOptimizerType::Pointer genericOptimizer = GenericOptimizerType::New(); + genericOptimizer->SetArgsInfo(m_ArgsInfo); + genericOptimizer->SetMaximize(genericMetric->GetMaximize()); + genericOptimizer->SetNumberOfParameters(transform->GetNumberOfParameters()); + typedef itk::SingleValuedNonLinearOptimizer OptimizerType; + OptimizerType::Pointer optimizer = genericOptimizer->GetOptimizerPointer(); + + + //======================================================= + // Registration + //======================================================= + typedef itk::MultiResolutionImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType; + typename RegistrationType::Pointer registration = RegistrationType::New(); + registration->SetMetric( metric ); + registration->SetOptimizer( optimizer ); + registration->SetInterpolator( interpolator ); + registration->SetTransform (transform); + if(threadsGiven) registration->SetNumberOfThreads(threads); + registration->SetFixedImage( croppedFixedImage ); + registration->SetMovingImage( movingImage ); + registration->SetFixedImageRegion( metricRegion ); + registration->SetFixedImagePyramid( fixedImagePyramid ); + registration->SetMovingImagePyramid( movingImagePyramid ); + registration->SetInitialTransformParameters( transform->GetParameters() ); + registration->SetNumberOfLevels( m_ArgsInfo.levels_arg ); + if (m_Verbose) std::cout<<"Setting the number of resolution levels to "<SetOptimizer(genericOptimizer); + optimizer->AddObserver( itk::IterationEvent(), observer ); + + // Output level info + typedef RegistrationInterfaceCommand CommandType; + typename CommandType::Pointer command = CommandType::New(); + command->SetInitializer(initializer); + command->SetArgsInfo(m_ArgsInfo); + command->SetCommandIterationUpdate(observer); + command->SetMaximize(genericMetric->GetMaximize()); + command->SetMetricRegion(metricRegion); + registration->AddObserver( itk::IterationEvent(), command ); + } + + + //======================================================= + // Let's go + //======================================================= + if (m_Verbose) std::cout << std::endl << "Starting Registration" << std::endl; + + try + { + registration->StartRegistration(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught while registering!" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Get the result + //======================================================= + OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters(); + transform->SetParameters( finalParameters ); + if (m_Verbose) + { + std::cout<<"Stop condition description: " + <GetOptimizer()->GetStopConditionDescription()<GetCoefficientImage(); + typedef itk::ImageFileWriter CoeffWriterType; + typename CoeffWriterType::Pointer coeffWriter=CoeffWriterType::New(); + coeffWriter->SetInput(coefficientImage); + coeffWriter->SetFileName(m_ArgsInfo.coeff_arg); + coeffWriter->Update(); + } + + + + //======================================================= + // Compute the DVF (only deformable transform) + //======================================================= + typedef itk::Vector< float, SpaceDimension > DisplacementType; + typedef itk::Image< DisplacementType, ImageDimension > DeformationFieldType; + typedef itk::TransformToDeformationFieldSource ConvertorType; + typename ConvertorType::Pointer filter= ConvertorType::New(); + filter->SetNumberOfThreads(1); + transform->SetBulkTransform(NULL); + filter->SetTransform(transform); + filter->SetOutputParametersFromImage(fixedImage); + filter->Update(); + typename DeformationFieldType::Pointer field = filter->GetOutput(); + + + //======================================================= + // Write the DVF + //======================================================= + typedef itk::ImageFileWriter< DeformationFieldType > FieldWriterType; + typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New(); + fieldWriter->SetFileName( m_ArgsInfo.vf_arg ); + fieldWriter->SetInput( field ); + try + { + fieldWriter->Update(); + } + catch( itk::ExceptionObject & excp ) + { + std::cerr << "Exception thrown writing the DVF" << std::endl; + std::cerr << excp << std::endl; + return; + } + + + //======================================================= + // Resample the moving image + //======================================================= + typedef itk::ResampleImageFilter< MovingImageType, FixedImageType > ResampleFilterType; + typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); + if (rigidTransform) transform->SetBulkTransform(rigidTransform); + resampler->SetTransform( transform ); + resampler->SetInput( movingImageReader->GetOutput() ); + resampler->SetOutputParametersFromImage(fixedImage); + resampler->Update(); + typename FixedImageType::Pointer result=resampler->GetOutput(); + + // typedef itk::WarpImageFilter< MovingImageType, FixedImageType, DeformationFieldType > WarpFilterType; + // typename WarpFilterType::Pointer warp = WarpFilterType::New(); + + // warp->SetDeformationField( field ); + // warp->SetInput( movingImageReader->GetOutput() ); + // warp->SetOutputOrigin( fixedImage->GetOrigin() ); + // warp->SetOutputSpacing( fixedImage->GetSpacing() ); + // warp->SetOutputDirection( fixedImage->GetDirection() ); + // warp->SetEdgePaddingValue( 0.0 ); + // warp->Update(); + + + //======================================================= + // Write the warped image + //======================================================= + typedef itk::ImageFileWriter< FixedImageType > WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName( m_ArgsInfo.output_arg ); + writer->SetInput( result ); + + try + { + writer->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Calculate the difference after the deformable transform + //======================================================= + typedef clitk::DifferenceImageFilter< FixedImageType, FixedImageType> DifferenceFilterType; + if (m_ArgsInfo.after_given) + { + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( result ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + differenceWriter->SetInput(difference->GetOutput()); + differenceWriter->SetFileName(m_ArgsInfo.after_arg); + differenceWriter->Update(); + + } + + + //======================================================= + // Calculate the difference before the deformable transform + //======================================================= + if( m_ArgsInfo.before_given ) + { + + typename FixedImageType::Pointer moving=FixedImageType::New(); + if (m_ArgsInfo.initMatrix_given) + { + typedef itk::ResampleImageFilter ResamplerType; + typename ResamplerType::Pointer resampler=ResamplerType::New(); + resampler->SetInput(movingImage); + resampler->SetOutputOrigin(fixedImage->GetOrigin()); + resampler->SetSize(fixedImage->GetLargestPossibleRegion().GetSize()); + resampler->SetOutputSpacing(fixedImage->GetSpacing()); + resampler->SetDefaultPixelValue( 0. ); + if (rigidTransform ) resampler->SetTransform(rigidTransform); + resampler->Update(); + moving=resampler->GetOutput(); + } + else + moving=movingImage; + + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( moving ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + writer->SetFileName( m_ArgsInfo.before_arg ); + writer->SetInput( difference->GetOutput() ); + writer->Update( ); + } + + return; + + } +}//end clitk + +#endif // #define clitkBLUTDIRGenericFilter_txx diff --git a/registration/clitkBSplineDeformableRegistration.cxx b/registration/clitkBSplineDeformableRegistration.cxx new file mode 100755 index 0000000..1cdef2b --- /dev/null +++ b/registration/clitkBSplineDeformableRegistration.cxx @@ -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 +======================================================================-====*/ +/** + * @file clitkBSplineDeformableRegistration.cxx + * @author Jef Vandemeulebroucke + * @date February 16 10:14:53 2009 + * + * @brief Optimized BSpline-FFD(itk=accellaration+additional memory requirements) or BLUT-FFD (clitk) + * + */ + +// clitk include +#include "clitkBSplineDeformableRegistration_ggo.h" +#include "clitkBSplineDeformableRegistrationGenericFilter.h" +#include "clitkIO.h" +#include "clitkImageCommon.h" + + +int main( int argc, char *argv[] ) +{ + //======================================================= + // Init command line + //======================================================= + GGO(clitkBSplineDeformableRegistration, args_info); + CLITK_INIT; + + //filter + clitk::BSplineDeformableRegistrationGenericFilter::Pointer genericFilter=clitk::BSplineDeformableRegistrationGenericFilter::New(); + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +} diff --git a/registration/clitkBSplineDeformableRegistration.ggo b/registration/clitkBSplineDeformableRegistration.ggo new file mode 100755 index 0000000..2853860 --- /dev/null +++ b/registration/clitkBSplineDeformableRegistration.ggo @@ -0,0 +1,87 @@ +#File clitkBSplineDeformableRegistration.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 15 July 2008 16.35 + +Package "clitk" +Version "Register 2 images using optimized ITK FFD (high memory requirements) or BLUT FFD. Both implementations are provided, mainly for debugging purposes.." + +option "config" - "Config file" string no + + +section "Run Time" + +option "verbose" v "Verbose" flag off +option "threads" - "Number of threads to use for intensive algorithms (default=min(cores,8))" int no + + +section "Input" + +option "reference" r "Input reference 3D image (float)" string yes +option "target" t "Input target 2D image (float)" string yes +option "mask" m "Mask to placed over the reference image" string no + + +section "Output" + +option "vf" - "Result DVF" string yes +option "coeff" - "Result coefficient images" string no multiple +option "output" o "Deformed target image" string yes +option "before" - "Difference image before (but after rigid transform)" string no +option "after" - "Difference image after " string no + + +section "Transform (Note that for BLUT FFD only one of --control, --spacing is required. The other will be adjusted to fit the region and allow exact representation. SamplingFactor will be set accordingly" + +option "init" - "Initial coefficient images" string no multiple +option "rigid" - "Prior rigid transform matrix from reference to target space" string no +option "order" - "Spline Order FFD" int no multiple default="3" +option "control" - "Internal control points for each dimension" int no multiple +option "spacing" - "Control point spacing for each dimension (mm)" double no multiple +option "wlut" - "With LUT for BSpline calculation" flag off +option "samplingFactor" - "LUT sampling factor" int no multiple + + +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 "Metric (optimized, threaded (opt) versions are marked *)" + +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="9" +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 off + + +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="7" +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 default="0.0" +option "upperBound" - "7: The upper bound" double no default="0.0" + + +Section "Registration" + +option "levels" - "Number of resolution levels" int no default="1" + + diff --git a/registration/clitkBSplineDeformableRegistrationGenericFilter.cxx b/registration/clitkBSplineDeformableRegistrationGenericFilter.cxx new file mode 100755 index 0000000..788eb5d --- /dev/null +++ b/registration/clitkBSplineDeformableRegistrationGenericFilter.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 _clitkBSplineDeformableRegistrationGenericFilter_cxx +#define _clitkBSplineDeformableRegistrationGenericFilter_cxx +#include "clitkBSplineDeformableRegistrationGenericFilter.h" + + +namespace clitk { + + clitk::BSplineDeformableRegistrationGenericFilter::BSplineDeformableRegistrationGenericFilter() + { + m_Verbose=false; + } + + + void clitk::BSplineDeformableRegistrationGenericFilter::Update() + { + //Get the image Dimension and PixelType + int Dimension; + std::string PixelType; + + clitk::ReadImageDimensionAndPixelType(m_ReferenceFileName, Dimension, PixelType); + + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + //else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 and 3 Dimensions!!!"< + * @date 14 March 2009 + * + * @brief + * + =================================================*/ + +// clitk +#include "clitkBSplineDeformableRegistration_ggo.h" +#include "clitkIO.h" +#include "clitkImageCommon.h" +#include "clitkDifferenceImageFilter.h" +#include "clitkTransformUtilities.h" +#include "clitkLBFGSBOptimizer.h" +#include "clitkBSplineDeformableTransform.h" +#include "clitkGenericOptimizer.h" +#include "clitkGenericInterpolator.h" +#include "clitkGenericMetric.h" + +// itk include +#include "itkMultiResolutionImageRegistrationMethod.h" +#include "itkMultiResolutionPyramidImageFilter.h" +#include "itkImage.h" +#include "itkBSplineDeformableTransform.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkResampleImageFilter.h" +#include "itkCommand.h" +#include "itkImageMaskSpatialObject.h" +#include "itkEuler3DTransform.h" +#include "itkWarpImageFilter.h" +#include "itkLightObject.h" +#include "itkImageToImageMetric.h" +#include "itkInterpolateImageFunction.h" +#include "itkLabelStatisticsImageFilter.h" + + +namespace clitk +{ + + class ITK_EXPORT BSplineDeformableRegistrationGenericFilter : public itk::LightObject + + { + public: + typedef BSplineDeformableRegistrationGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( BSplineDeformableRegistrationGenericFilter, LightObject ); + + + //==================================================================== + // Set methods + void SetArgsInfo(const args_info_clitkBSplineDeformableRegistration& a) + { + m_ArgsInfo=a; + m_ReferenceFileName=m_ArgsInfo.reference_arg; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + //==================================================================== + // Update + virtual void Update(); + + protected: + //const char * GetNameOfClass() const { return "BSplineDeformableRegistrationGenericFilter"; } + + //==================================================================== + // Constructor & Destructor + BSplineDeformableRegistrationGenericFilter(); + ~BSplineDeformableRegistrationGenericFilter(){;} + + //==================================================================== + //Protected member functions + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + args_info_clitkBSplineDeformableRegistration m_ArgsInfo; + bool m_Verbose; + std::string m_ReferenceFileName; + + }; + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkBSplineDeformableRegistrationGenericFilter.txx" +#endif + +#endif //#define _clitkBSplineDeformableRegistrationGenericFilter_h + + + + diff --git a/registration/clitkBSplineDeformableRegistrationGenericFilter.txx b/registration/clitkBSplineDeformableRegistrationGenericFilter.txx new file mode 100755 index 0000000..f76c8fa --- /dev/null +++ b/registration/clitkBSplineDeformableRegistrationGenericFilter.txx @@ -0,0 +1,857 @@ +/*========================================================================= + 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 __clitkBSplineDeformableRegistrationGenericFilter_txx +#define __clitkBSplineDeformableRegistrationGenericFilter_txx +#include "clitkBSplineDeformableRegistrationGenericFilter.h" + + +namespace clitk +{ + + //============================================================================== + //Creating an observer class that allows us to change parameters at subsequent levels + //============================================================================== + template + class RegistrationInterfaceCommand : public itk::Command + { + public: + typedef RegistrationInterfaceCommand Self; + + + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + itkNewMacro( Self ); + protected: + RegistrationInterfaceCommand() {}; + public: + typedef TRegistration RegistrationType; + typedef RegistrationType * RegistrationPointer; + + // 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; + } + RegistrationPointer registration = dynamic_cast( object ); + unsigned int numberOfLevels=registration->GetNumberOfLevels(); + unsigned int currentLevel=registration->GetCurrentLevel()+1; + std::cout< Pointer; + itkNewMacro( Self ); + protected: + CommandIterationUpdate() {}; + public: + typedef clitk::GenericOptimizer OptimizerType; + typedef const OptimizerType * OptimizerPointer; + + // We 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; + }; + + + //============================================================================== + // Update with the number of dimensions + //============================================================================== + template + void BSplineDeformableRegistrationGenericFilter::UpdateWithDim(std::string PixelType) + { + + if (m_Verbose) std::cout << "Images were detected to be "<< Dimension << "D and " << PixelType << "..." << std::endl; + + if(PixelType == "short"){ + if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and signed short..." << std::endl; + UpdateWithDimAndPixelType(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "unsigned_char"){ + // if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and unsigned_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + + //============================================================================== + // Update with the number of dimensions and pixeltype + //============================================================================== + template + void BSplineDeformableRegistrationGenericFilter::UpdateWithDimAndPixelType() + { + + //======================================================= + // Run-time + //======================================================= + bool threadsGiven=m_ArgsInfo.threads_given; + int threads=m_ArgsInfo.threads_arg; + + typedef itk::Image< PixelType, ImageDimension > FixedImageType; + typedef itk::Image< PixelType, ImageDimension > MovingImageType; + const unsigned int SpaceDimension = ImageDimension; + typedef double TCoordRep; + + + //======================================================= + //Input + //======================================================= + typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; + typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType; + + typename FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); + typename MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); + + fixedImageReader->SetFileName( m_ArgsInfo.reference_arg ); + movingImageReader->SetFileName( m_ArgsInfo.target_arg ); + if (m_Verbose) std::cout<<"Reading images..."<Update(); + movingImageReader->Update(); + + typename FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); + typename MovingImageType::Pointer movingImage =movingImageReader->GetOutput(); + typename FixedImageType::RegionType fixedImageRegion = fixedImage->GetLargestPossibleRegion(); + + // The metric region: where should the metric be CALCULATED (depends on mask) + typename FixedImageType::RegionType metricRegion = fixedImage->GetLargestPossibleRegion(); + typename FixedImageType::RegionType::SizeType metricRegionSize=metricRegion.GetSize(); + typename FixedImageType::RegionType::IndexType metricRegionIndex=metricRegion.GetIndex(); + typename FixedImageType::PointType metricRegionOrigin=fixedImage->GetOrigin(); + + // The transform region: where should the transform be DEFINED (depends on mask) + typename FixedImageType::RegionType transformRegion = fixedImage->GetLargestPossibleRegion(); + typename FixedImageType::RegionType::SizeType transformRegionSize=transformRegion.GetSize(); + typename FixedImageType::RegionType::IndexType transformRegionIndex=transformRegion.GetIndex(); + typename FixedImageType::PointType transformRegionOrigin=fixedImage->GetOrigin(); + + + //======================================================= + // If given, we connect a mask to the fixed image + //====================================================== + typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; + typename MaskType::Pointer spatialObjectMask=NULL; + + if (m_ArgsInfo.mask_given) + { + typedef itk::Image< unsigned char, ImageDimension > ImageMaskType; + typedef itk::ImageFileReader< ImageMaskType > MaskReaderType; + typename MaskReaderType::Pointer maskReader = MaskReaderType::New(); + maskReader->SetFileName(m_ArgsInfo.mask_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..." <SetImage( maskReader->GetOutput() ); + + // Find the bounding box of the "inside" label + typedef itk::LabelStatisticsImageFilter StatisticsImageFilterType; + typename StatisticsImageFilterType::Pointer statisticsImageFilter=StatisticsImageFilterType::New(); + statisticsImageFilter->SetInput(maskReader->GetOutput()); + statisticsImageFilter->SetLabelInput(maskReader->GetOutput()); + statisticsImageFilter->Update(); + typename StatisticsImageFilterType::BoundingBoxType boundingBox = statisticsImageFilter->GetBoundingBox(1); + + // Limit the transform region to the mask + for (unsigned int i=0; iTransformIndexToPhysicalPoint(transformRegion.GetIndex(), transformRegionOrigin); + + // Limit the metric region to the mask + metricRegion=transformRegion; + fixedImage->TransformIndexToPhysicalPoint(metricRegion.GetIndex(), metricRegionOrigin); + + } + + + + //======================================================= + // Regions + //===================================================== + if (m_Verbose) + { + // Fixed image region + std::cout<<"The fixed image has its origin at "<GetOrigin()< FixedImagePyramidType; + typedef itk::RecursiveMultiResolutionPyramidImageFilter< MovingImageType, MovingImageType> MovingImagePyramidType; + typename FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New(); + typename MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New(); + + + // //======================================================= + // // Rigid Transform + // //======================================================= + // typedef itk::Euler3DTransform RigidTransformType; + // RigidTransformType::Pointer rigidTransform=RigidTransformType::New(); + + // if (m_ArgsInfo.rigid_given) + // { + // itk::Matrix rigidTransformMatrix=clitk::ReadMatrix3D(m_ArgsInfo.rigid_arg); + + // //Set the rotation + // itk::Matrix finalRotation = clitk::GetRotationalPartMatrix3D(rigidTransformMatrix); + // rigidTransform->SetMatrix(finalRotation); + + // //Set the translation + // itk::Vector finalTranslation = clitk::GetTranslationPartMatrix3D(rigidTransformMatrix); + // rigidTransform->SetTranslation(finalTranslation); + + // } + + + //======================================================= + // BSpline Transform + //======================================================= + typename FixedImageType::RegionType::SizeType splineOrders ; + + //Default is cubic splines + splineOrders.Fill(3); + if (m_ArgsInfo.order_given) + for(unsigned int i=0; i TransformType; + typename TransformType::Pointer transform; + typedef itk::BSplineDeformableTransform BSplineTransformType; + typedef BSplineTransformType* BSplineTransformPointer; + typedef clitk::BSplineDeformableTransform BLUTTransformType; + typedef BLUTTransformType* BLUTTransformPointer; + + // JV parameter array is passed by reference, create outside context so it exists afterwards!!!!! + typedef typename TransformType::ParametersType ParametersType; + ParametersType parameters; + + + // CLITK BLUT transform + if(m_ArgsInfo.wlut_flag) + { + typename BLUTTransformType::Pointer bsplineTransform = BLUTTransformType::New(); + if (m_Verbose) std::cout<<"Setting the spline orders to "<SetSplineOrders(splineOrders); + + //------------------------------------------------------------------------- + // Define the region: Either the spacing or the number of CP should be given + //------------------------------------------------------------------------- + + // Region + typedef typename BSplineTransformType::RegionType RegionType; + RegionType bsplineRegion; + typename RegionType::SizeType gridSizeOnImage; + typename RegionType::SizeType gridBorderSize; + typename RegionType::SizeType totalGridSize; + + // Spacing + typedef typename BSplineTransformType::SpacingType SpacingType; + SpacingType fixedImageSpacing, chosenSpacing, adaptedSpacing; + fixedImageSpacing = fixedImage->GetSpacing(); + + // Only spacing given: adjust if necessary + if (m_ArgsInfo.spacing_given && !m_ArgsInfo.control_given) + { + for(unsigned int r=0; rGetDirection(); + SpacingType gridOriginOffset = gridDirection * adaptedSpacing; + + // Origin: 1 CP border for spatial dimensions + typedef typename BSplineTransformType::OriginType OriginType; + OriginType gridOrigin = transformRegionOrigin - gridOriginOffset; + if (m_Verbose) std::cout<<"The control point grid origin was set to "<SetGridSpacing( adaptedSpacing ); + bsplineTransform->SetGridOrigin( gridOrigin ); + bsplineTransform->SetGridRegion( bsplineRegion ); + bsplineTransform->SetGridDirection( gridDirection ); + + //Bulk transform + //if (m_Verbose) std::cout<<"Setting rigid transform..."<SetBulkTransform( rigidTransform ); + + //Vector BSpline interpolator + //bsplineTransform->SetOutputSpacing(fixedImage->GetSpacing()); + typename RegionType::SizeType samplingFactors; + for (unsigned int i=0; i< ImageDimension; i++) + { + if (m_Verbose) std::cout<<"For dimension "<GetSpacing()[i]); + if (m_Verbose) std::cout<<"Setting sampling factor "<SetLUTSamplingFactors(samplingFactors); + + //initial parameters + if (m_ArgsInfo.init_given) + { + typedef itk::ImageFileReader CoefficientReaderType; + typename CoefficientReaderType::Pointer coeffReader=CoefficientReaderType::New(); + coeffReader->SetFileName(m_ArgsInfo.init_arg[0]); + coeffReader->Update(); + bsplineTransform->SetCoefficientImage(coeffReader->GetOutput()); + } + else + { + //typedef typename TransformType::ParametersType ParametersType; + const unsigned int numberOfParameters = bsplineTransform->GetNumberOfParameters(); + parameters=ParametersType( numberOfParameters ); + parameters.Fill( 0.0 ); + bsplineTransform->SetParameters( parameters ); + } + + // Mask + if (spatialObjectMask) bsplineTransform->SetMask( spatialObjectMask ); + + // Pass + transform=bsplineTransform; + } + + //ITK BSpline transform + else + { + typename BSplineTransformType::Pointer bsplineTransform = BSplineTransformType::New(); + + // Define the region + typedef typename BSplineTransformType::RegionType RegionType; + RegionType bsplineRegion; + typename RegionType::SizeType gridSizeOnImage; + typename RegionType::SizeType gridBorderSize; + typename RegionType::SizeType totalGridSize; + + //Set the number of control points + for(unsigned int r=0; rGetSpacing(); + typename FixedImageType::SizeType fixedImageSize = fixedImageRegion.GetSize(); + if (m_ArgsInfo.spacing_given) + { + + for(unsigned int r=0; r(fixedImageSize[r] - 1) / + static_cast(gridSizeOnImage[r] - 1); + } + } + if (m_Verbose) std::cout<<"The control points spacing was set to "<GetDirection(); + SpacingType gridOriginOffset = gridDirection * spacing; + + // Origin + typedef typename BSplineTransformType::OriginType OriginType; + OriginType origin = fixedImage->GetOrigin(); + OriginType gridOrigin = origin - gridOriginOffset; + + // Set + bsplineTransform->SetGridSpacing( spacing ); + bsplineTransform->SetGridOrigin( gridOrigin ); + bsplineTransform->SetGridRegion( bsplineRegion ); + bsplineTransform->SetGridDirection( gridDirection ); + + // Bulk transform + // if (m_Verbose) std::cout<<"Setting rigid transform..."<SetBulkTransform( rigidTransform ); + + // Initial parameters + if (m_ArgsInfo.init_given) + { + typedef itk::ImageFileReader CoefficientReaderType; + typename BSplineTransformType::ImageType::Pointer coeffImages[SpaceDimension]; + for(unsigned int i=0; iSetFileName(m_ArgsInfo.init_arg[i]); + coeffReader->Update(); + coeffImages[i]=coeffReader->GetOutput(); + } + bsplineTransform->SetCoefficientImage(coeffImages); + } + else + { + const unsigned int numberOfParameters = bsplineTransform->GetNumberOfParameters(); + parameters=ParametersType( numberOfParameters ); + parameters.Fill( 0.0 ); + bsplineTransform->SetParameters( parameters ); + } + + // Pass + transform=bsplineTransform; + + } + + + //======================================================= + // Interpolator + //======================================================= + typedef clitk::GenericInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + typedef itk::InterpolateImageFunction< FixedImageType, TCoordRep > InterpolatorType; + typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + + + //======================================================= + // Metric + //======================================================= + typedef clitk::GenericMetric GenericMetricType; + typename GenericMetricType::Pointer genericMetric=GenericMetricType::New(); + genericMetric->SetArgsInfo(m_ArgsInfo); + genericMetric->SetFixedImageRegion(metricRegion); + typedef itk::ImageToImageMetric< FixedImageType, MovingImageType > MetricType; + typename MetricType::Pointer metric=genericMetric->GetMetricPointer(); + if (spatialObjectMask) metric->SetFixedImageMask( spatialObjectMask ); + +#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)..."< GenericOptimizerType; + GenericOptimizerType::Pointer genericOptimizer = GenericOptimizerType::New(); + genericOptimizer->SetArgsInfo(m_ArgsInfo); + genericOptimizer->SetMaximize(genericMetric->GetMaximize()); + genericOptimizer->SetNumberOfParameters(transform->GetNumberOfParameters()); + typedef itk::SingleValuedNonLinearOptimizer OptimizerType; + OptimizerType::Pointer optimizer = genericOptimizer->GetOptimizerPointer(); + + + //======================================================= + // Registration + //======================================================= + typedef itk::MultiResolutionImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType; + typename RegistrationType::Pointer registration = RegistrationType::New(); + registration->SetMetric( metric ); + registration->SetOptimizer( optimizer ); + registration->SetInterpolator( interpolator ); + registration->SetTransform (transform); + if(threadsGiven) registration->SetNumberOfThreads(threads); + registration->SetFixedImage( fixedImage ); + registration->SetMovingImage( movingImage ); + registration->SetFixedImageRegion( metricRegion ); + registration->SetFixedImagePyramid( fixedImagePyramid ); + registration->SetMovingImagePyramid( movingImagePyramid ); + registration->SetInitialTransformParameters( transform->GetParameters() ); + registration->SetNumberOfLevels(m_ArgsInfo.levels_arg); + if (m_Verbose) std::cout<<"Setting the number of resolution levels to "<SetOptimizer(genericOptimizer); + optimizer->AddObserver( itk::IterationEvent(), observer ); + + + // Output level info + typedef RegistrationInterfaceCommand CommandType; + typename CommandType::Pointer command = CommandType::New(); + registration->AddObserver( itk::IterationEvent(), command ); + } + + + //======================================================= + // Let's go + //======================================================= + if (m_Verbose) std::cout << std::endl << "Starting Registration" << std::endl; + + try + { + registration->StartRegistration(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught while registering!" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Get the result + //======================================================= + OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters(); + transform->SetParameters( finalParameters ); + + + //======================================================= + // Get the BSpline coefficient images and write them + //======================================================= + if (m_ArgsInfo.coeff_given) + { + if(m_ArgsInfo.wlut_flag) + { + BLUTTransformPointer bsplineTransform=dynamic_cast(registration->GetTransform()); + typedef itk::Image, ImageDimension> CoefficientImageType; + typename CoefficientImageType::Pointer coefficientImage =bsplineTransform->GetCoefficientImage(); + typedef itk::ImageFileWriter CoeffWriterType; + typename CoeffWriterType::Pointer coeffWriter=CoeffWriterType::New(); + coeffWriter->SetInput(coefficientImage); + coeffWriter->SetFileName(m_ArgsInfo.coeff_arg[0]); + coeffWriter->Update(); + } + else + { + BSplineTransformPointer bsplineTransform=dynamic_cast(registration->GetTransform()); + typedef itk::Image CoefficientImageType; + typename CoefficientImageType::Pointer *coefficientImages =bsplineTransform->GetCoefficientImage(); + typedef itk::ImageFileWriter CoeffWriterType; + for (unsigned int i=0;iSetInput(coefficientImages[i]); + coeffWriter->SetFileName(m_ArgsInfo.coeff_arg[i]); + coeffWriter->Update(); + } + } + } + + + //======================================================= + // Generate the DVF + //======================================================= + typedef itk::Vector< float, SpaceDimension > DisplacementType; + typedef itk::Image< DisplacementType, ImageDimension > DeformationFieldType; + + typename DeformationFieldType::Pointer field = DeformationFieldType::New(); + field->SetRegions( fixedImageRegion ); + field->SetOrigin( fixedImage->GetOrigin() ); + field->SetSpacing( fixedImage->GetSpacing() ); + field->SetDirection( fixedImage->GetDirection() ); + field->Allocate(); + + typedef itk::ImageRegionIteratorWithIndex< DeformationFieldType > FieldIterator; + FieldIterator fi( field, fixedImageRegion ); + fi.GoToBegin(); + + typename TransformType::InputPointType fixedPoint; + typename TransformType::OutputPointType movingPoint; + typename DeformationFieldType::IndexType index; + + DisplacementType displacement; + while( ! fi.IsAtEnd() ) + { + index = fi.GetIndex(); + field->TransformIndexToPhysicalPoint( index, fixedPoint ); + movingPoint = transform->TransformPoint( fixedPoint ); + displacement = movingPoint - fixedPoint; + fi.Set( displacement ); + ++fi; + } + + + //======================================================= + // Write the DVF + //======================================================= + typedef itk::ImageFileWriter< DeformationFieldType > FieldWriterType; + typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New(); + fieldWriter->SetFileName( m_ArgsInfo.vf_arg ); + fieldWriter->SetInput( field ); + try + { + fieldWriter->Update(); + } + catch( itk::ExceptionObject & excp ) + { + std::cerr << "Exception thrown writing the DVF" << std::endl; + std::cerr << excp << std::endl; + return; + } + + + //======================================================= + // Resample the moving image + //======================================================= + typedef itk::WarpImageFilter< MovingImageType, FixedImageType, DeformationFieldType > WarpFilterType; + typename WarpFilterType::Pointer warp = WarpFilterType::New(); + + warp->SetDeformationField( field ); + warp->SetInput( movingImageReader->GetOutput() ); + warp->SetOutputOrigin( fixedImage->GetOrigin() ); + warp->SetOutputSpacing( fixedImage->GetSpacing() ); + warp->SetOutputDirection( fixedImage->GetDirection() ); + warp->SetEdgePaddingValue( 0.0 ); + warp->Update(); + + + //======================================================= + // Write the warped image + //======================================================= + typedef itk::ImageFileWriter< FixedImageType > WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName( m_ArgsInfo.output_arg ); + writer->SetInput( warp->GetOutput() ); + + try + { + writer->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Calculate the difference after the deformable transform + //======================================================= + typedef clitk::DifferenceImageFilter< FixedImageType, FixedImageType> DifferenceFilterType; + if (m_ArgsInfo.after_given) + { + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( warp->GetOutput() ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + differenceWriter->SetInput(difference->GetOutput()); + differenceWriter->SetFileName(m_ArgsInfo.after_arg); + differenceWriter->Update(); + + } + + + //======================================================= + // Calculate the difference before the deformable transform + //======================================================= + if( m_ArgsInfo.before_given ) + { + + typename FixedImageType::Pointer moving=FixedImageType::New(); + if (m_ArgsInfo.rigid_given) + { + typedef itk::ResampleImageFilter ResamplerType; + typename ResamplerType::Pointer resampler=ResamplerType::New(); + resampler->SetInput(movingImage); + resampler->SetOutputOrigin(fixedImage->GetOrigin()); + resampler->SetSize(fixedImage->GetLargestPossibleRegion().GetSize()); + resampler->SetOutputSpacing(fixedImage->GetSpacing()); + resampler->SetDefaultPixelValue( 0. ); + //resampler->SetTransform(rigidTransform); + resampler->Update(); + moving=resampler->GetOutput(); + } + else + moving=movingImage; + + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( moving ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + writer->SetFileName( m_ArgsInfo.before_arg ); + writer->SetInput( difference->GetOutput() ); + writer->Update( ); + } + + return; + } +} + +#endif // __clitkBSplineDeformableRegistrationGenericFilter_txx diff --git a/registration/clitkBSplineDeformableTransform.h b/registration/clitkBSplineDeformableTransform.h new file mode 100644 index 0000000..2aeaac6 --- /dev/null +++ b/registration/clitkBSplineDeformableTransform.h @@ -0,0 +1,365 @@ +/*========================================================================= + 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 __clitkBSplineDeformableTransform_h +#define __clitkBSplineDeformableTransform_h +#include "clitkVectorBSplineResampleImageFunctionWithLUT.h" + +//itk include +#include "itkTransform.h" +#include "itkImage.h" +#include "itkImageRegion.h" +#include "itkSpatialObject.h" + +namespace clitk +{ + + template < + class TCoordRep = double, // Data type for scalars, coordinate representation,vectors + unsigned int NInputDimensions = 3, // Number of input dimensions + unsigned int NOutputDimensions = 3 > // Number of output dimensions + class ITK_EXPORT BSplineDeformableTransform : + public itk::Transform< TCoordRep, NInputDimensions, NOutputDimensions > + { + public: + + //==================================================================== + // Typedefs + //==================================================================== + typedef BSplineDeformableTransform Self; + typedef itk::Transform< TCoordRep, NInputDimensions, NOutputDimensions > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** New macro for creation of through the object factory.*/ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( BSplineDeformableTransform, Transform ); + + /** Dimension of the domain space. */ + itkStaticConstMacro(OutputDimension, unsigned int, NOutputDimensions); + + /** Dimension of the input model. */ + itkStaticConstMacro(InputDimension, unsigned int, NInputDimensions); + + /** Standard scalar type for this class. */ + typedef typename Superclass::ScalarType ScalarType; + + /** Standard parameters container. */ + typedef typename Superclass::ParametersType ParametersType; + + /** Standard Jacobian container. */ + typedef typename Superclass::JacobianType JacobianType; + + /** Standard vector type for this class. */ + typedef itk::Vector InputVectorType; + typedef itk::Vector OutputVectorType; + + /** Standard covariant vector type for this class. */ + typedef itk::CovariantVector InputCovariantVectorType; + typedef itk::CovariantVector OutputCovariantVectorType; + + /** Standard vnl_vector type for this class. */ + typedef vnl_vector_fixed InputVnlVectorType; + typedef vnl_vector_fixed OutputVnlVectorType; + + /** Standard coordinate point type for this class. */ + typedef itk::Point InputPointType; + typedef itk::Point OutputPointType; + + //JV Parameters as images with OutputDimension number of components per Pixel + typedef typename ParametersType::ValueType ParametersValueType; + typedef typename itk::Vector PixelType; + typedef itk::Image CoefficientImageType; + typedef typename CoefficientImageType::Pointer CoefficientImagePointer; + + + /** Typedefs for specifying the extend to the grid. */ + typedef itk::ImageRegion RegionType; + typedef typename RegionType::IndexType IndexType; + typedef typename RegionType::SizeType SizeType; + typedef typename CoefficientImageType::SpacingType SpacingType; + typedef typename CoefficientImageType::DirectionType DirectionType; + typedef typename CoefficientImageType::PointType OriginType; + typedef itk::ContinuousIndex ContinuousIndexType; + + //JV added for the BLUT interpolator + //typedef itk::Vector OutputSpacingType; + + //JV m_VectorInterpolator + typedef VectorBSplineResampleImageFunctionWithLUT + VectorInterpolatorType; + typedef typename VectorInterpolatorType::CoefficientDataType CoefficientDataType; + typedef typename VectorInterpolatorType::CoefficientDataType WeightsDataType; + + /** Typedef of the bulk transform. */ + typedef itk::Transform BulkTransformType; + typedef BulkTransformType* BulkTransformPointer; + + /** Typedef of the mask */ + typedef itk::SpatialObject< InputDimension > MaskType; + typedef MaskType* MaskPointer; + + //==================================================================== + // Set et Gets + //==================================================================== + //JV added for the BLUT interpolator + void SetSplineOrder(const unsigned int & splineOrder); + void SetSplineOrders(const SizeType & splineOrders); + itkGetMacro( SplineOrders, SizeType ); + itkGetConstMacro( SplineOrders, SizeType ); + void SetLUTSamplingFactor(const int & samplingFactor); + void SetLUTSamplingFactors(const SizeType & samplingFactors); + itkGetMacro( LUTSamplingFactors, SizeType ); + itkGetConstMacro( LUTSamplingFactors,SizeType ); + //void SetOutputSpacing(const OutputSpacingType & outputSpacing); + //itkGetMacro( OutputSpacing, OutputSpacingType ); + //itkGetConstMacro( OutputSpacing, OutputSpacingType ); + + void SetParameters(const ParametersType & parameters); + + void SetFixedParameters(const ParametersType & parameters); + + void SetParametersByValue(const ParametersType & parameters); + + void SetIdentity(); + + /** Get the Transformation Parameters. */ + virtual const ParametersType& GetParameters(void) const; + + /** Get the Transformation Fixed Parameters. */ + virtual const ParametersType& GetFixedParameters(void) const; + + // The coefficientImage + virtual CoefficientImagePointer GetCoefficientImage() + { return m_CoefficientImage; } + virtual const CoefficientImagePointer GetCoefficientImage() const + { return m_CoefficientImage; } + virtual void SetCoefficientImage(CoefficientImagePointer image); + + /** This method specifies the region over which the grid resides. */ + virtual void SetGridRegion( const RegionType& region ); + itkGetMacro( GridRegion, RegionType ); + itkGetConstMacro( GridRegion, RegionType ); + + /** This method specifies the grid spacing or resolution. */ + virtual void SetGridSpacing( const SpacingType& spacing ); + itkGetMacro( GridSpacing, SpacingType ); + itkGetConstMacro( GridSpacing, SpacingType ); + + /** This method specifies the grid directions . */ + virtual void SetGridDirection( const DirectionType & spacing ); + itkGetMacro( GridDirection, DirectionType ); + itkGetConstMacro( GridDirection, DirectionType ); + + /** This method specifies the grid origin. */ + virtual void SetGridOrigin( const OriginType& origin ); + itkGetMacro( GridOrigin, OriginType ); + itkGetConstMacro( GridOrigin, OriginType ); + + // Set the bulk transform, real pointer + // itkSetConstObjectMacro( BulkTransform, BulkTransformType ); + // itkGetConstObjectMacro( BulkTransform, BulkTransformType ); + void SetBulkTransform(BulkTransformPointer b){m_BulkTransform=b;} + BulkTransformPointer GetBulkTransform(void) {return m_BulkTransform;} + + //Set mask, inside transform applies, outside zero, real pointer + void SetMask(MaskPointer m){m_Mask=m;} + MaskPointer GetMask(void){return m_Mask;} + // itkSetConstObjectMacro( Mask, MaskType ); + // itkGetConstObjectMacro( Mask, MaskType ); + + /** Transform points by a BSpline deformable transformation. */ + OutputPointType TransformPoint(const InputPointType &point ) const; + + // JV added for just the deformable part, without bulk + OutputPointType DeformablyTransformPoint(const InputPointType &point ) const; + + /** Parameter index array type. */ + typedef itk::Array ParameterIndexArrayType; + + /** Transform points by a BSpline deformable transformation. + * On return, weights contains the interpolation weights used to compute the + * deformation and indices of the x (zeroth) dimension coefficient parameters + * in the support region used to compute the deformation. + * Parameter indices for the i-th dimension can be obtained by adding + * ( i * this->GetNumberOfParametersPerDimension() ) to the indices array. + */ + + // JV not implemented + // virtual void TransformPoint( const InputPointType & inputPoint, + // OutputPointType & outputPoint, + // WeightsType & weights, + // ParameterIndexArrayType & indices, + // bool & inside ) const; + // virtual void DeformablyTransformPoint( const InputPointType & inputPoint, + // OutputPointType & outputPoint, + // WeightsType & weights, + // ParameterIndexArrayType & indices, + // bool & inside ) const; + // virtual void GetJacobian( const InputPointType & inputPoint, + // WeightsType & weights, + // ParameterIndexArrayType & indices + // ) const; + + /** Method to transform a vector - + * not applicable for this type of transform. */ + virtual OutputVectorType TransformVector(const InputVectorType &) const + { + itkExceptionMacro(<< "Method not applicable for deformable transform." ); + return OutputVectorType(); + } + + /** Method to transform a vnl_vector - + * not applicable for this type of transform */ + virtual OutputVnlVectorType TransformVector(const InputVnlVectorType &) const + { + itkExceptionMacro(<< "Method not applicable for deformable transform. "); + return OutputVnlVectorType(); + } + + /** Method to transform a CovariantVector - + * not applicable for this type of transform */ + virtual OutputCovariantVectorType TransformCovariantVector( + const InputCovariantVectorType &) const + { + itkExceptionMacro(<< "Method not applicable for deformable transfrom. "); + return OutputCovariantVectorType(); + } + + /** Compute the Jacobian Matrix of the transformation at one point */ + virtual const JacobianType& GetJacobian(const InputPointType &point ) const; + + /** Return the number of parameters that completely define the Transfom */ + virtual unsigned int GetNumberOfParameters(void) const; + + /** Return the number of parameters per dimension */ + unsigned int GetNumberOfParametersPerDimension(void) const; + + /** Return the region of the grid wholly within the support region */ + itkGetConstReferenceMacro( ValidRegion, RegionType ); + + /** Indicates that this transform is linear. That is, given two + * points P and Q, and scalar coefficients a and b, then + * + * T( a*P + b*Q ) = a * T(P) + b * T(Q) + */ + virtual bool IsLinear() const { return false; } + + //unsigned int GetNumberOfAffectedWeights() const; + + protected: + /** Print contents of an BSplineDeformableTransform. */ + void PrintSelf(std::ostream &os, itk::Indent indent) const; + + + BSplineDeformableTransform(); + virtual ~BSplineDeformableTransform(); + + /** Wrap flat array into images of coefficients. */ + void WrapAsImages(); + + /** Convert an input point to a continuous index inside the BSpline grid */ + void TransformPointToContinuousIndex( const InputPointType & point, ContinuousIndexType & index ) const; + + private: + BSplineDeformableTransform(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** The bulk transform. */ + BulkTransformPointer m_BulkTransform; + MaskPointer m_Mask; + + // JV added for BLUT interpolator + SizeType m_SplineOrders; + SizeType m_LUTSamplingFactors; + + /** Variables defining the coefficient grid extend. */ + RegionType m_GridRegion; + SpacingType m_GridSpacing; + DirectionType m_GridDirection; + OriginType m_GridOrigin; + + DirectionType m_PointToIndex; + DirectionType m_IndexToPoint; + + RegionType m_ValidRegion; + + /** Variables defining the interpolation support region. */ + SizeType m_Offset; + itk::FixedArray m_SplineOrderOdd; + SizeType m_SupportSize; + IndexType m_ValidRegionLast; + + /** Array holding images wrapped from the flat parameters. */ + CoefficientImagePointer m_WrappedImage; + + /** Vector image representing the B-spline coefficients + * in each dimension. */ + CoefficientImagePointer m_CoefficientImage; + + /** Jacobian as OutputDimension number of images. */ + typedef typename JacobianType::ValueType JacobianValueType; + typedef typename itk::Vector JacobianPixelType; + typedef itk::Image JacobianImageType; + typename JacobianImageType::Pointer m_JacobianImage[OutputDimension]; + typedef itk::ImageRegionIterator IteratorType; + + /** Keep track of last support region used in computing the Jacobian + * for fast resetting of Jacobian to zero. + */ + //JV for J calculation + mutable RegionType m_SupportRegion; + mutable IndexType m_SupportIndex; + mutable IndexType m_LastJacobianIndex; + mutable IteratorType m_Iterator[OutputDimension]; + mutable JacobianPixelType m_ZeroVector; + mutable ContinuousIndexType m_Index; + + /** Keep a pointer to the input parameters. */ + const ParametersType * m_InputParametersPointer; + + /** Internal parameters buffer. */ + ParametersType m_InternalParametersBuffer; + + //JV the BLUT interpolator + typename VectorInterpolatorType::Pointer m_VectorInterpolator; + + /** Check if a continuous index is inside the valid region. */ + bool InsideValidRegion( const ContinuousIndexType& index ) const; + + + }; //class BSplineDeformableTransform + + +} // namespace itk + +#if ITK_TEMPLATE_TXX +# include "clitkBSplineDeformableTransform.txx" +#endif + + +#endif // __clitkBSplineDeformableTransform_h diff --git a/registration/clitkBSplineDeformableTransform.txx b/registration/clitkBSplineDeformableTransform.txx new file mode 100644 index 0000000..4290191 --- /dev/null +++ b/registration/clitkBSplineDeformableTransform.txx @@ -0,0 +1,1043 @@ +/*========================================================================= + 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 __clitkBSplineDeformableTransform_txx +#define __clitkBSplineDeformableTransform_tx +#include "clitkBSplineDeformableTransform.h" + +//itk +#include "itkContinuousIndex.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkIdentityTransform.h" + +namespace clitk +{ + + // Constructor with default arguments + template + BSplineDeformableTransform + ::BSplineDeformableTransform():Superclass(OutputDimension,0) + { + unsigned int i; + + //JV default spline order + for ( i=0;iSetLUTSamplingFactors(m_LUTSamplingFactors); + m_VectorInterpolator->SetSplineOrders(m_SplineOrders); + + // Set Bulk transform to NULL (no bulk performed) + m_BulkTransform = NULL; + + // Mask + m_Mask=NULL; + + // Default grid size is zero + typename RegionType::SizeType size; + typename RegionType::IndexType index; + size.Fill( 0 ); + index.Fill( 0 ); + m_GridRegion.SetSize( size ); + m_GridRegion.SetIndex( index ); + + m_GridOrigin.Fill( 0.0 ); // default origin is all zeros + m_GridSpacing.Fill( 1.0 ); // default spacing is all ones + m_GridDirection.SetIdentity(); // default spacing is all ones + + m_InternalParametersBuffer = ParametersType(0); + // Make sure the parameters pointer is not NULL after construction. + m_InputParametersPointer = &m_InternalParametersBuffer; + + // Initialize coeffient images + m_WrappedImage = CoefficientImageType::New(); + m_WrappedImage->SetRegions( m_GridRegion ); + m_WrappedImage->SetOrigin( m_GridOrigin.GetDataPointer() ); + m_WrappedImage->SetSpacing( m_GridSpacing.GetDataPointer() ); + m_WrappedImage->SetDirection( m_GridDirection ); + m_CoefficientImage = NULL; + + // Variables for computing interpolation + for (i=0; i SetRegions( m_GridRegion ); + m_JacobianImage[i]->SetOrigin( m_GridOrigin.GetDataPointer() ); + m_JacobianImage[i]->SetSpacing( m_GridSpacing.GetDataPointer() ); + m_JacobianImage[i]->SetDirection( m_GridDirection ); + } + + /** Fixed Parameters store the following information: + * Grid Size + * Grid Origin + * Grid Spacing + * Grid Direction */ + //JV we add the splineOrders, LUTsamplingfactor, m_Mask and m_BulkTransform + /* + Spline orders + Sampling factors + m_Mask + m_BulkTransform + The size of these is equal to the NInputDimensions + *********************************************************/ + this->m_FixedParameters.SetSize ( NInputDimensions * (NInputDimensions + 5)+2 ); + this->m_FixedParameters.Fill ( 0.0 ); + for ( i=0; im_FixedParameters[2*NInputDimensions+i] = m_GridSpacing[i]; + } + for (unsigned int di=0; dim_FixedParameters[3*NInputDimensions+(di*NInputDimensions+dj)] = m_GridDirection[di][dj]; + } + } + + //JV add splineOrders + for ( i=0; im_FixedParameters[ ( (3+NInputDimensions)*NInputDimensions)+i] = (this->GetSplineOrders())[i]; + } + + //JV add LUTsamplingFactors + for ( i=0; im_FixedParameters[( (4+NInputDimensions)*NInputDimensions)+i ] = this->GetLUTSamplingFactors()[i]; + } + + // JV add the mask pointer + this->m_FixedParameters[( (5+NInputDimensions)*NInputDimensions)]=(double)((size_t)m_Mask); + + // JV add the bulkTransform pointer + this->m_FixedParameters[( (5+NInputDimensions)*NInputDimensions) +1]=(double)((size_t)m_BulkTransform); + + + // Calculate the PointToIndex matrices + DirectionType scale; + for( unsigned int i=0; i::Zero; + + } + + + // Destructor + template + BSplineDeformableTransform + ::~BSplineDeformableTransform() + { + + } + + + // JV set Spline Order + template + void + BSplineDeformableTransform + ::SetSplineOrder(const unsigned int & splineOrder) + { + SizeType splineOrders; + for (unsigned int i=0;iSetSplineOrders(splineOrders); + } + + + // JV set Spline Orders + template + void + BSplineDeformableTransform + ::SetSplineOrders(const SizeType & splineOrders) + { + if(m_SplineOrders!=splineOrders) + { + m_SplineOrders=splineOrders; + + //update the interpolation function + m_VectorInterpolator->SetSplineOrders(m_SplineOrders); + + //update the varaibles for computing interpolation + for (unsigned int i=0; i Modified(); + } + } + + + // JV set sampling factor + template + void + BSplineDeformableTransform + ::SetLUTSamplingFactor( const int & samplingFactor) + { + SizeType samplingFactors; + for (unsigned int i=0; iSetLUTSamplingFactors(samplingFactors); + } + + + // JV set sampling factors + template + void + BSplineDeformableTransform + ::SetLUTSamplingFactors( const SizeType & samplingFactors) + { + if(m_LUTSamplingFactors!=samplingFactors) + { + for (unsigned int i=0; iSetLUTSamplingFactors(m_LUTSamplingFactors); + + this->Modified(); + } + } + + + // Get the number of parameters + template + unsigned int + BSplineDeformableTransform + ::GetNumberOfParameters(void) const + { + + // The number of parameters equal OutputDimension * number of + // of pixels in the grid region. + return ( static_cast( OutputDimension ) * + static_cast( m_GridRegion.GetNumberOfPixels() ) ); + + } + + + // Get the number of parameters per dimension + template + unsigned int + BSplineDeformableTransform + ::GetNumberOfParametersPerDimension(void) const + { + // The number of parameters per dimension equal number of + // of pixels in the grid region. + return ( static_cast( m_GridRegion.GetNumberOfPixels() ) ); + + } + + + // Set the grid region + template + void + BSplineDeformableTransform + ::SetGridRegion( const RegionType & region ) + { + if ( m_GridRegion != region ) + { + m_GridRegion = region; + + // set regions for each coefficient and jacobian image + m_WrappedImage->SetRegions( m_GridRegion ); + for (unsigned int j=0; j SetRegions( m_GridRegion ); + + // Set the valid region + // If the grid spans the interval [start, last]. + // The valid interval for evaluation is [start+offset, last-offset] + // when spline order is even. + // The valid interval for evaluation is [start+offset, last-offset) + // when spline order is odd. + // Where offset = vcl_floor(spline / 2 ). + // Note that the last pixel is not included in the valid region + // with odd spline orders. + typename RegionType::SizeType size = m_GridRegion.GetSize(); + typename RegionType::IndexType index = m_GridRegion.GetIndex(); + for ( unsigned int j = 0; j < NInputDimensions; j++ ) + { + index[j] += + static_cast< typename RegionType::IndexValueType >( m_Offset[j] ); + size[j] -= + static_cast< typename RegionType::SizeValueType> ( 2 * m_Offset[j] ); + m_ValidRegionLast[j] = index[j] + + static_cast< typename RegionType::IndexValueType >( size[j] ) - 1; + } + m_ValidRegion.SetSize( size ); + m_ValidRegion.SetIndex( index ); + + // If we are using the default parameters, update their size and set to identity. + // Input parameters point to internal buffer => using default parameters. + if (m_InputParametersPointer == &m_InternalParametersBuffer) + { + // Check if we need to resize the default parameter buffer. + if ( m_InternalParametersBuffer.GetSize() != this->GetNumberOfParameters() ) + { + m_InternalParametersBuffer.SetSize( this->GetNumberOfParameters() ); + // Fill with zeros for identity. + m_InternalParametersBuffer.Fill( 0 ); + } + } + + this->Modified(); + } + } + + + // Set the grid spacing + template + void + BSplineDeformableTransform + ::SetGridSpacing( const SpacingType & spacing ) + { + if ( m_GridSpacing != spacing ) + { + m_GridSpacing = spacing; + + // Set spacing for each coefficient and jacobian image + m_WrappedImage->SetSpacing( m_GridSpacing.GetDataPointer() ); + for (unsigned int j=0; j SetSpacing( m_GridSpacing.GetDataPointer() ); + + // Set scale + DirectionType scale; + for( unsigned int i=0; iModified(); + } + + } + + // Set the grid direction + template + void + BSplineDeformableTransform + ::SetGridDirection( const DirectionType & direction ) + { + if ( m_GridDirection != direction ) + { + m_GridDirection = direction; + + // Set direction for each coefficient and jacobian image + m_WrappedImage->SetDirection( m_GridDirection ); + for (unsigned int j=0; j SetDirection( m_GridDirection ); + + // Set scale + DirectionType scale; + for( unsigned int i=0; iModified(); + } + + } + + + // Set the grid origin + template + void + BSplineDeformableTransform + ::SetGridOrigin( const OriginType& origin ) + { + if ( m_GridOrigin != origin ) + { + m_GridOrigin = origin; + + // Set origin for each coefficient and jacobianimage + m_WrappedImage->SetOrigin( m_GridOrigin.GetDataPointer() ); + for (unsigned int j=0; j SetOrigin( m_GridOrigin.GetDataPointer() ); + + this->Modified(); + } + + } + + + // Set the parameters + template + void + BSplineDeformableTransform + ::SetIdentity() + { + if( m_InputParametersPointer ) + { + ParametersType * parameters = + const_cast( m_InputParametersPointer ); + parameters->Fill( 0.0 ); + this->Modified(); + } + else + { + itkExceptionMacro( << "Input parameters for the spline haven't been set ! " + << "Set them using the SetParameters or SetCoefficientImage method first." ); + } + } + + + // Set the parameters + template + void + BSplineDeformableTransform + ::SetParameters( const ParametersType & parameters ) + { + + // Check if the number of parameters match the + // Expected number of parameters + if ( parameters.Size() != this->GetNumberOfParameters() ) + { + itkExceptionMacro(<<"Mismatched between parameters size " + << parameters.size() + << " and region size " + << m_GridRegion.GetNumberOfPixels() ); + } + + // Clean up buffered parameters + m_InternalParametersBuffer = ParametersType( 0 ); + + // Keep a reference to the input parameters + m_InputParametersPointer = ¶meters; + + // Wrap flat array as images of coefficients + this->WrapAsImages(); + + //Set input to vector interpolator + m_VectorInterpolator->SetInputImage(this->GetCoefficientImage()); + + // Modified is always called since we just have a pointer to the + // parameters and cannot know if the parameters have changed. + this->Modified(); + } + + + // Set the Fixed Parameters + template + void + BSplineDeformableTransform + ::SetFixedParameters( const ParametersType & parameters ) + { + + // JV number should be exact, no defaults for spacing + if ( parameters.Size() != NInputDimensions * (5 + NInputDimensions)+2 ) + { + itkExceptionMacro(<< "Mismatched between parameters size " + << parameters.size() + << " and number of fixed parameters " + << NInputDimensions * (5 + NInputDimensions)+2 ); + } + /********************************************************* + Fixed Parameters store the following information: + Grid Size + Grid Origin + Grid Spacing + Grid Direction */ + // JV we add the splineOrders, LUTsamplingfactor, mask pointer and bulktransform pointer + /* + Spline orders + Sampling factors + m_Mask + m_BulkTransform + The size of these is equal to the NInputDimensions + *********************************************************/ + + /** Set the Grid Parameters */ + SizeType gridSize; + for (unsigned int i=0; i (parameters[i]); + } + RegionType bsplineRegion; + bsplineRegion.SetSize( gridSize ); + + /** Set the Origin Parameters */ + OriginType origin; + for (unsigned int i=0; iSetGridSpacing( spacing ); + this->SetGridDirection( direction ); + this->SetGridOrigin( origin ); + this->SetGridRegion( bsplineRegion ); + + //JV add the LUT parameters + this->SetSplineOrders( splineOrders ); + this->SetLUTSamplingFactors( samplingFactors ); + + } + + + // Wrap flat parameters as images + template + void + BSplineDeformableTransform + ::WrapAsImages() + { + //JV Wrap parameter array in vectorial image, changed parameter order: A1x A1y A1z, A2x .... + PixelType * dataPointer =reinterpret_cast( const_cast(m_InputParametersPointer->data_block() )) ; + unsigned int numberOfPixels = m_GridRegion.GetNumberOfPixels(); + + m_WrappedImage->GetPixelContainer()->SetImportPointer( dataPointer,numberOfPixels);//InputDimension + m_CoefficientImage = m_WrappedImage; + + //JV Wrap jacobian into OutputDimension X Vectorial images + this->m_Jacobian.set_size( OutputDimension, this->GetNumberOfParameters() ); + + // Use memset to set the memory + JacobianPixelType * jacobianDataPointer = reinterpret_cast(this->m_Jacobian.data_block()); + memset(jacobianDataPointer, 0, OutputDimension*numberOfPixels*sizeof(JacobianPixelType)); + m_LastJacobianIndex = m_ValidRegion.GetIndex(); + + for (unsigned int j=0; jGetPixelContainer()-> + SetImportPointer( jacobianDataPointer, numberOfPixels ); + jacobianDataPointer += numberOfPixels; + } + } + + + // Set the parameters by value + template + void + BSplineDeformableTransform + ::SetParametersByValue( const ParametersType & parameters ) + { + + // Check if the number of parameters match the + // Expected number of parameters + if ( parameters.Size() != this->GetNumberOfParameters() ) + { + itkExceptionMacro(<<"Mismatched between parameters size " + << parameters.size() + << " and region size " + << m_GridRegion.GetNumberOfPixels() ); + } + + // Copy it + m_InternalParametersBuffer = parameters; + m_InputParametersPointer = &m_InternalParametersBuffer; + + // Wrap flat array as images of coefficients + this->WrapAsImages(); + + // Modified is always called since we just have a pointer to the + // Parameters and cannot know if the parameters have changed. + this->Modified(); + + } + + // Get the parameters + template + const + typename BSplineDeformableTransform + ::ParametersType & + BSplineDeformableTransform + ::GetParameters( void ) const + { + /** NOTE: For efficiency, this class does not keep a copy of the parameters - + * it just keeps pointer to input parameters. + */ + if (NULL == m_InputParametersPointer) + { + itkExceptionMacro( <<"Cannot GetParameters() because m_InputParametersPointer is NULL. Perhaps SetCoefficientImage() has been called causing the NULL pointer." ); + } + + return (*m_InputParametersPointer); + } + + + // Get the parameters + template + const + typename BSplineDeformableTransform + ::ParametersType & + BSplineDeformableTransform + ::GetFixedParameters( void ) const + { + RegionType resRegion = this->GetGridRegion( ); + + for (unsigned int i=0; im_FixedParameters[i] = (resRegion.GetSize())[i]; + } + for (unsigned int i=0; im_FixedParameters[NInputDimensions+i] = (this->GetGridOrigin())[i]; + } + for (unsigned int i=0; im_FixedParameters[2*NInputDimensions+i] = (this->GetGridSpacing())[i]; + } + for (unsigned int di=0; dim_FixedParameters[3*NInputDimensions+(di*NInputDimensions+dj)] = (this->GetGridDirection())[di][dj]; + } + } + + //JV add splineOrders + for (unsigned int i=0; im_FixedParameters[(3+NInputDimensions)*NInputDimensions+i] = (this->GetSplineOrders())[i]; + } + + //JV add LUTsamplingFactor + for (unsigned int i=0; im_FixedParameters[(4+NInputDimensions)*NInputDimensions+i] = (this->GetLUTSamplingFactors())[i]; + } + + //JV add the mask + this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions]=(double)((size_t) m_Mask); + + //JV add the bulktransform pointer + this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions+1]=(double)((size_t) m_BulkTransform); + + return (this->m_FixedParameters); + } + + + // Set the B-Spline coefficients using input images + template + void + BSplineDeformableTransform + ::SetCoefficientImage( CoefficientImagePointer image ) + { + + this->SetGridRegion( image->GetBufferedRegion() ); + this->SetGridSpacing( image->GetSpacing() ); + this->SetGridDirection( image->GetDirection() ); + this->SetGridOrigin( image->GetOrigin() ); + m_CoefficientImage = image; + + // Update the interpolator + m_VectorInterpolator->SetInputImage(this->GetCoefficientImage()); + + // Clean up buffered parameters + m_InternalParametersBuffer = ParametersType( 0 ); + m_InputParametersPointer = NULL; + + } + + + // Print self + template + void + BSplineDeformableTransform + ::PrintSelf(std::ostream &os, itk::Indent indent) const + { + + this->Superclass::PrintSelf(os, indent); + + os << indent << "GridRegion: " << m_GridRegion << std::endl; + os << indent << "GridOrigin: " << m_GridOrigin << std::endl; + os << indent << "GridSpacing: " << m_GridSpacing << std::endl; + os << indent << "GridDirection: " << m_GridDirection << std::endl; + os << indent << "IndexToPoint: " << m_IndexToPoint << std::endl; + os << indent << "PointToIndex: " << m_PointToIndex << std::endl; + + os << indent << "CoefficientImage: [ "; + os << m_CoefficientImage.GetPointer() << " ]" << std::endl; + + os << indent << "WrappedImage: [ "; + os << m_WrappedImage.GetPointer() << " ]" << std::endl; + + os << indent << "InputParametersPointer: " + << m_InputParametersPointer << std::endl; + os << indent << "ValidRegion: " << m_ValidRegion << std::endl; + os << indent << "LastJacobianIndex: " << m_LastJacobianIndex << std::endl; + os << indent << "BulkTransform: "; + os << m_BulkTransform << std::endl; + + if ( m_BulkTransform ) + { + os << indent << "BulkTransformType: " + << m_BulkTransform->GetNameOfClass() << std::endl; + } + os << indent << "VectorBSplineInterpolator: "; + os << m_VectorInterpolator.GetPointer() << std::endl; + os << indent << "Mask: "; + os << m_Mask<< std::endl; + } + + + // Verify + template + bool + BSplineDeformableTransform + ::InsideValidRegion( const ContinuousIndexType& index ) const + { + bool inside = true; + + if ( !m_ValidRegion.IsInside( index ) ) + { + inside = false; + } + //JV verify for each input dimension + if ( inside) + { + typedef typename ContinuousIndexType::ValueType ValueType; + for( unsigned int j = 0; j < InputDimension; j++ ) + { + if (m_SplineOrderOdd[j]) + { + if ( index[j] >= static_cast( m_ValidRegionLast[j] ) ) + { + inside = false; + break; + } + } + } + } + + return inside; + } + + + // Transform a point + template + typename BSplineDeformableTransform + ::OutputPointType + BSplineDeformableTransform + ::TransformPoint(const InputPointType &inputPoint) const + { + + InputPointType transformedPoint; + OutputPointType outputPoint; + + // BulkTransform + if ( m_BulkTransform ) + { + transformedPoint = m_BulkTransform->TransformPoint( inputPoint ); + } + else + { + transformedPoint = inputPoint; + } + + // Deformable transform + if ( m_CoefficientImage ) + { + // Check if inside mask + if(m_Mask && !(m_Mask->IsInside(inputPoint) ) ) + { + // Outside: no (deformable) displacement + return transformedPoint; + } + + // Check if inside valid region + bool inside = true; + ContinuousIndexType index; + this->TransformPointToContinuousIndex( inputPoint, index ); + inside = this->InsideValidRegion( index ); + if ( !inside ) + { + // Outside: no (deformable) displacement + return transformedPoint; + } + + // Call the vector interpolator + itk::Vector displacement=m_VectorInterpolator->EvaluateAtContinuousIndex(index); + + // Return the results + outputPoint = transformedPoint+displacement; + + } + + else + { + itkWarningMacro( << "B-spline coefficients have not been set" ); + outputPoint = transformedPoint; + } + + return outputPoint; + } + + + + //JV Deformably transform a point + template + typename BSplineDeformableTransform + ::OutputPointType + BSplineDeformableTransform + ::DeformablyTransformPoint(const InputPointType &inputPoint) const + { + OutputPointType outputPoint; + if ( m_CoefficientImage ) + { + + // Check if inside mask + if(m_Mask && !(m_Mask->IsInside(inputPoint) ) ) + { + // Outside: no (deformable) displacement + return inputPoint; + } + + // Check if inside + bool inside = true; + ContinuousIndexType index; + this->TransformPointToContinuousIndex( inputPoint, index ); + inside = this->InsideValidRegion( index ); + + if ( !inside ) + { + //outside: no (deformable) displacement + return inputPoint; + //return outputPoint; + } + + // Call the vector interpolator + itk::Vector displacement=m_VectorInterpolator->EvaluateAtContinuousIndex(index); + + // Return the results + outputPoint = inputPoint+displacement; + } + + // No coefficients available + else + { + itkWarningMacro( << "B-spline coefficients have not been set" ); + outputPoint = inputPoint; + } + + return outputPoint; + } + + + // JV weights are identical as for transformpoint, could be done simultaneously in metric!!!! + // Compute the Jacobian in one position + template + const + typename BSplineDeformableTransform + ::JacobianType & + BSplineDeformableTransform + ::GetJacobian( const InputPointType & point ) const + { + // Can only compute Jacobian if parameters are set via + // SetParameters or SetParametersByValue + // if( m_InputParametersPointer == NULL ) + // { + // itkExceptionMacro( <<"Cannot compute Jacobian: parameters not set" ); + // } + + + //======================================================== + // Zero all components of jacobian + //======================================================== + // JV not thread safe (m_LastJacobianIndex), instantiate N transforms + // NOTE: for efficiency, we only need to zero out the coefficients + // that got fill last time this method was called. + + unsigned int j=0; + + //Define the region for each jacobian image + m_SupportRegion.SetIndex( m_LastJacobianIndex ); + + //Initialize the iterators + for ( j = 0; j < OutputDimension; j++ ) + m_Iterator[j] = IteratorType( m_JacobianImage[j], m_SupportRegion); + + //Set the previously-set to zero + while ( ! (m_Iterator[0]).IsAtEnd() ) + { + for ( j = 0; j < OutputDimension; j++ ) + { + m_Iterator[j].Set( m_ZeroVector ); + ++(m_Iterator[j]); + } + } + + //======================================================== + // For each dimension, copy the weight to the support region + //======================================================== + + // Check if inside mask + if(m_Mask && !(m_Mask->IsInside(point) ) ) + { + // Outside: no (deformable) displacement + return this->m_Jacobian; + } + + //Get index + this->TransformPointToContinuousIndex( point, m_Index ); + + // NOTE: if the support region does not lie totally within the grid + // we assume zero displacement and return the input point + if ( !this->InsideValidRegion( m_Index ) ) + { + return this->m_Jacobian; + } + + //Compute interpolation weights + const WeightsDataType *weights=NULL; + m_VectorInterpolator->EvaluateWeightsAtContinuousIndex( m_Index, &weights, m_LastJacobianIndex); + m_SupportRegion.SetIndex( m_LastJacobianIndex ); + + //Reset the iterators + for ( j = 0; j < OutputDimension; j++ ) + m_Iterator[j] = IteratorType( m_JacobianImage[j], m_SupportRegion); + + // For each dimension, copy the weight to the support region + while ( ! (m_Iterator[0]).IsAtEnd() ) + { + //copy weight to jacobian image + for ( j = 0; j < OutputDimension; j++ ) + { + m_ZeroVector[j]=*weights; + (m_Iterator[j]).Set( m_ZeroVector); + m_ZeroVector[j]=itk::NumericTraits::Zero; + ++(m_Iterator[j]); + } + // go to next coefficient in the support region + weights++; + } + + // Return the result + return this->m_Jacobian; + + } + + + template + void + BSplineDeformableTransform + ::TransformPointToContinuousIndex( const InputPointType & point, ContinuousIndexType & index ) const + { + unsigned int j; + + itk::Vector tvector; + + for ( j = 0; j < OutputDimension; j++ ) + { + tvector[j] = point[j] - this->m_GridOrigin[j]; + } + + itk::Vector cvector; + + cvector = m_PointToIndex * tvector; + + for ( j = 0; j < OutputDimension; j++ ) + { + index[j] = static_cast< typename ContinuousIndexType::CoordRepType >( cvector[j] ); + } + } + + +} // namespace + +#endif diff --git a/registration/clitkBSplineDeformableTransformInitializer.h b/registration/clitkBSplineDeformableTransformInitializer.h new file mode 100644 index 0000000..6b2971a --- /dev/null +++ b/registration/clitkBSplineDeformableTransformInitializer.h @@ -0,0 +1,174 @@ +/*========================================================================= + 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 __clitkBSplineDeformableTransformInitializer_h +#define __clitkBSplineDeformableTransformInitializer_h +#include "clitkResampleBSplineDeformableTransformImageFilter.h" + +#include "itkObject.h" +#include "itkObjectFactory.h" +#include + +namespace clitk +{ + + +template < class TTransform, class TImage > +class ITK_EXPORT BSplineDeformableTransformInitializer : public itk::Object +{ +public: + /** Standard class typedefs. */ + typedef BSplineDeformableTransformInitializer Self; + typedef itk::Object Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** New macro for creation of through a Smart Pointer. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( BSplineDeformableTransformInitializer, Object ); + + // Typedefs + typedef TTransform TransformType; + typedef typename TransformType::Pointer TransformPointer; + typedef typename TransformType::RegionType RegionType; + typedef typename RegionType::SizeType SizeType; + typedef typename TransformType::SpacingType SpacingType; + itkStaticConstMacro(InputDimension, unsigned int, TransformType::InputDimension); + typedef TImage ImageType; + typedef typename ImageType::ConstPointer ImagePointer; + typedef typename TransformType::CoefficientImageType CoefficientImageType; + typedef typename TransformType::ParametersType ParametersType; + + // Set and Get + itkBooleanMacro(Verbose); + itkSetMacro( Verbose, bool); + itkGetConstReferenceMacro( Verbose, bool); + itkSetObjectMacro( Transform, TransformType ); + itkGetConstObjectMacro( Transform, TransformType ); + itkSetObjectMacro( Image, ImageType ); + itkGetConstObjectMacro( Image, ImageType ); + void SetSplineOrder(const unsigned int & splineOrder) + { + SizeType s; + s.Fill(splineOrder); + this->SetSplineOrders(s); + } + void SetSplineOrders(const SizeType & splineOrders) + { + m_SplineOrders=splineOrders; + } + void SetNumberOfControlPointsInsideTheImage( SizeType & n ) + { + m_NumberOfControlPointsInsideTheImage=n; + m_NumberOfControlPointsIsGiven=true; + this->Modified(); + } + void SetNumberOfControlPointsInsideTheImage( int * n) + { + SizeType s; + for (unsigned int i=0;iSetNumberOfControlPointsInsideTheImage( s ); + } + void SetNumberOfControlPointsInsideTheImage( unsigned int & n ) + { + SizeType s; + s.Fill( n );; + this->SetNumberOfControlPointsInsideTheImage( s ); + } + void SetControlPointSpacing( SpacingType n ) + { + m_ControlPointSpacing= n; + m_ControlPointSpacingIsGiven=true; + this->Modified(); + } + void SetControlPointSpacing( double*& n ) + { + SpacingType s( n ); + this->SetControlPointSpacing(s); + } + void SetControlPointSpacing( double n ) + { + SpacingType s; + s.Fill( n ); + this->SetControlPointSpacing(s); + } + void SetSamplingFactors( SizeType n ) + { + m_SamplingFactors=n; + m_SamplingFactorIsGiven=true; + this->Modified(); + } + void SetSamplingFactors( int *& n) + { + SizeType s; + for (unsigned int i=0;i SetSamplingFactors( s ); + } + void SetSamplingFactors( unsigned int n ) + { + SizeType s; + s.Fill( n ); + this-> SetSamplingFactors( s ); + } + virtual void InitializeTransform(); + void SetInitialParameters(const typename CoefficientImageType::Pointer coefficientImage, ParametersType& params); + void SetInitialParameters(const std::string & s, ParametersType& params); + + // For easy acces, declared public + std::vector m_NumberOfControlPointsInsideTheImageArray; + std::vector m_SamplingFactorsArray; + std::vector m_ControlPointSpacingArray; + + SpacingType m_ControlPointSpacing; + SizeType m_SamplingFactors; + SizeType m_SplineOrders; + SpacingType m_ChosenSpacing; + SizeType m_NumberOfControlPointsInsideTheImage; + bool m_NumberOfControlPointsIsGiven; + bool m_ControlPointSpacingIsGiven; + bool m_SamplingFactorIsGiven; + bool m_TransformRegionIsGiven; + + typename TransformType::ParametersType* m_Parameters; + +protected: + BSplineDeformableTransformInitializer(); + ~BSplineDeformableTransformInitializer(){}; + +private: + BSplineDeformableTransformInitializer(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + bool m_Verbose; + TransformPointer m_Transform; + ImagePointer m_Image; + +}; //class BSplineDeformableTransformInitializer + + +} // namespace clitk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkBSplineDeformableTransformInitializer.txx" +#endif + +#endif /* __clitkBSplineDeformableTransformInitializer_h */ diff --git a/registration/clitkBSplineDeformableTransformInitializer.txx b/registration/clitkBSplineDeformableTransformInitializer.txx new file mode 100644 index 0000000..0a93ab0 --- /dev/null +++ b/registration/clitkBSplineDeformableTransformInitializer.txx @@ -0,0 +1,244 @@ +/*========================================================================= + 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 __clitkBSplineDeformableTransformInitializer_txx +#define __clitkBSplineDeformableTransformInitializer_txx +#include "clitkBSplineDeformableTransformInitializer.h" + +namespace clitk +{ + + + template < class TTransform, class TImage > + BSplineDeformableTransformInitializer + ::BSplineDeformableTransformInitializer() + { + this->m_NumberOfControlPointsInsideTheImage.Fill( 5 ); + this->m_ControlPointSpacing.Fill(64.); + this->m_ChosenSpacing.Fill(64.); + m_NumberOfControlPointsIsGiven=false; + m_ControlPointSpacingIsGiven=false; + m_TransformRegionIsGiven=false; + m_SamplingFactorIsGiven=false; + m_SplineOrders.Fill(3); + m_Parameters=NULL; + } + + template < class TTransform, class TImage > + void + BSplineDeformableTransformInitializer + ::InitializeTransform() + { + // Sanity check: + // The image is required for the region and spacing + if( ! this->m_Image ) + { + itkExceptionMacro( "Reference Image has not been set" ); + return; + } + + // A pointer to the transform is required + if( ! this->m_Transform ) + { + itkExceptionMacro( "Transform has not been set" ); + return; + } + + // If the image come from a filter, then update that filter. + if( this->m_Image->GetSource() ) + { + this->m_Image->GetSource()->Update(); + } + + + //-------------------------------------- + // Spacing & Size on image + //-------------------------------------- + SpacingType fixedImageSpacing = m_Image->GetSpacing(); + SizeType fixedImageSize=m_Image->GetLargestPossibleRegion().GetSize(); + typename RegionType::SizeType gridBorderSize; + typename RegionType::SizeType totalGridSize; + + // Only spacing given: adjust if necessary + if (m_ControlPointSpacingIsGiven && !m_NumberOfControlPointsIsGiven) + { + for(unsigned int r=0; rTransformIndexToPhysicalPoint(m_Image->GetLargestPossibleRegion().GetIndex(),fixedImageOrigin); + typename ImageType::DirectionType gridDirection = m_Image->GetDirection(); + SizeType orderShift; + + // Shift depends on order + for(unsigned int r=0; rm_Transform->SetSplineOrders(m_SplineOrders); + this->m_Transform->SetGridRegion( gridRegion ); + this->m_Transform->SetGridOrigin( gridOrigin ); + this->m_Transform->SetGridSpacing( m_ControlPointSpacing ); + this->m_Transform->SetGridDirection( gridDirection ); + this->m_Transform->SetLUTSamplingFactors(m_SamplingFactors); + + } + + template < class TTransform, class TImage > + void + BSplineDeformableTransformInitializer + ::SetInitialParameters( const std::string& s, ParametersType& params) + { + //--------------------------------------- + // Read Initial parameters + //--------------------------------------- + typedef itk::ImageFileReader CoefficientReaderType; + typename CoefficientReaderType::Pointer coeffReader=CoefficientReaderType::New(); + coeffReader->SetFileName(s); + if(m_Verbose) std::cout<<"Reading initial coefficients from file: "<Update(); + typename CoefficientImageType::Pointer coefficientImage=coeffReader->GetOutput(); + this->SetInitialParameters(coefficientImage, params); + } + + template < class TTransform, class TImage > + void + BSplineDeformableTransformInitializer + ::SetInitialParameters(const typename CoefficientImageType::Pointer coefficientImage, ParametersType& params) + { + // Keep a reference + m_Parameters=¶ms; + + // Resample + typedef ResampleBSplineDeformableTransformImageFilter ResamplerType; + typename ResamplerType::Pointer resampler=ResamplerType::New(); + resampler->SetInput(coefficientImage); + resampler->SetOutputParametersFromImage(m_Transform->GetCoefficientImage()); + if(m_Verbose) std::cout<<"Resampling initial coefficients..."<Update(); + + // Copy parameters into the existing array, I know its crappy + typedef itk::ImageRegionConstIterator Iterator; + Iterator it (resampler->GetOutput(), resampler->GetOutput()->GetLargestPossibleRegion() ); + it.GoToBegin(); + unsigned int i=0; + while(! it.IsAtEnd()) + { + for (unsigned int j=0; jm_Transform->SetParameters(params); + } + + + +} // namespace itk + +#endif diff --git a/registration/clitkBSplinePyramid.cxx b/registration/clitkBSplinePyramid.cxx new file mode 100644 index 0000000..c06d83f --- /dev/null +++ b/registration/clitkBSplinePyramid.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkBSplinePyramid.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkBSplinePyramid_ggo.h" +#include "clitkIO.h" +#include "clitkBSplinePyramidGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkBSplinePyramid, args_info); + CLITK_INIT; + + // Filter + clitk::BSplinePyramidGenericFilter::Pointer genericFilter=clitk::BSplinePyramidGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkBSplinePyramid.ggo b/registration/clitkBSplinePyramid.ggo new file mode 100644 index 0000000..823135e --- /dev/null +++ b/registration/clitkBSplinePyramid.ggo @@ -0,0 +1,15 @@ +#File clitkBSplinePyramid.ggo +Package "clitkBSplinePyramid" +version "1.0" +purpose "Down (or Up) sample with a factor 2 using Bspline pyramids. BSplineDownsampleImageFilter is BUGGED! See the ITK post of jvdmb@hotmail.com." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes + + +option "up" u "Upsample instead of downsample" flag off +option "resamplerType" t "The type of B-spline resampler used: 0=resampler, 1=L2, 2=centered, 3=L2 centered" int no default="0" +option "splineOrder" - "Spline order" int no default="3" diff --git a/registration/clitkBSplinePyramidGenericFilter.cxx b/registration/clitkBSplinePyramidGenericFilter.cxx new file mode 100644 index 0000000..2c1ff64 --- /dev/null +++ b/registration/clitkBSplinePyramidGenericFilter.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + 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 clitkBSplinePyramidGenericFilter_cxx +#define clitkBSplinePyramidGenericFilter_cxx + +/* ================================================= + * @file clitkBSplinePyramidGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkBSplinePyramidGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + BSplinePyramidGenericFilter::BSplinePyramidGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void BSplinePyramidGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType, Components); + else if(Dimension==3) UpdateWithDim<3>(PixelType, Components); + else if (Dimension==4)UpdateWithDim<4>(PixelType, Components); + else + { + std::cout<<"Error, Only for 2, 3 or 4 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( BSplinePyramidGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkBSplinePyramid & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + BSplinePyramidGenericFilter(); + ~BSplinePyramidGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType, unsigned int Components); + template void UpdateWithDimAndPixelType(); + template void UpdateWithDimAndVectorType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkBSplinePyramid m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkBSplinePyramidGenericFilter.txx" +#endif + +#endif // #define clitkBSplinePyramidGenericFilter_h diff --git a/registration/clitkBSplinePyramidGenericFilter.txx b/registration/clitkBSplinePyramidGenericFilter.txx new file mode 100644 index 0000000..c0768b9 --- /dev/null +++ b/registration/clitkBSplinePyramidGenericFilter.txx @@ -0,0 +1,398 @@ +/*========================================================================= + 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 clitkBSplinePyramidGenericFilter_txx +#define clitkBSplinePyramidGenericFilter_txx + +/* ================================================= + * @file clitkBSplinePyramidGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + BSplinePyramidGenericFilter::UpdateWithDim(std::string PixelType, unsigned int Components) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + else if (Components==3) + { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and 3D float (DVF)" << std::endl; + UpdateWithDimAndVectorType >(); + } + else std::cerr<<"Number of components is "< + void + BSplinePyramidGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + // Resampler Types + typedef itk::BSplineResampleImageFilterBase ResamplerType; + typedef itk::BSplineCenteredResampleImageFilterBase CenteredResamplerType; + typedef itk::BSplineL2ResampleImageFilterBase L2ResamplerType; + typedef itk::BSplineCenteredL2ResampleImageFilterBase CenteredL2ResamplerType; + + // Filter + typedef itk::ImageToImageFilter< InputImageType, InputImageType > ImageToImageFilterType; + typename ImageToImageFilterType::Pointer filter; + + if (!m_ArgsInfo.up_flag) + { + switch (m_ArgsInfo.resamplerType_arg) + { + + // Resampler + case 0: { + typename itk::BSplineDownsampleImageFilter< InputImageType,InputImageType, ResamplerType >::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType, ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with standard Resampler"<::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType, CenteredResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with centered Resampler"<::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType,L2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with L2 Resampler"<::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType,CenteredL2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with L2 centered Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType, ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with standard Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType, CenteredResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with centered Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType,L2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with L2 Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType,CenteredL2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with L2 centered Resampler"<SetInput(input); + filter->Update(); + typename OutputImageType::Pointer output=filter->GetOutput(); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + void + BSplinePyramidGenericFilter::UpdateWithDimAndVectorType() + { + + // ImageTypes + typedef typename VectorType::ValueType PixelType; + typedef itk::Image VectorInputImageType; + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + typedef itk::Image VectorOutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename VectorInputImageType::Pointer vectorInput= reader->GetOutput(); + + // Process components separetely and gather afterwards + std::vector components; + + for (unsigned int i=0; i<3;i++) + { + // Extract component + typedef clitk::VectorImageToImageFilter FilterType; + typename FilterType::Pointer dfilter=FilterType::New(); + dfilter->SetInput(vectorInput); + dfilter->SetComponentIndex(i); + dfilter->Update(); + typename InputImageType::Pointer input=dfilter->GetOutput(); + + //============================================================================================ + // Resampler Types + typedef itk::BSplineResampleImageFilterBase ResamplerType; + typedef itk::BSplineCenteredResampleImageFilterBase CenteredResamplerType; + typedef itk::BSplineL2ResampleImageFilterBase L2ResamplerType; + typedef itk::BSplineCenteredL2ResampleImageFilterBase CenteredL2ResamplerType; + + // Filter + typedef itk::ImageToImageFilter< InputImageType, InputImageType > ImageToImageFilterType; + typename ImageToImageFilterType::Pointer filter; + + if (!m_ArgsInfo.up_flag) + { + switch (m_ArgsInfo.resamplerType_arg) + { + + // Resampler + case 0: { + typename itk::BSplineDownsampleImageFilter< InputImageType,InputImageType, ResamplerType >::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType, ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with standard Resampler"<::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType, CenteredResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with centered Resampler"<::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType,L2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with L2 Resampler"<::Pointer df + = itk::BSplineDownsampleImageFilter< InputImageType,InputImageType,CenteredL2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline downsample image filter with L2 centered Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType, ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with standard Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType, CenteredResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with centered Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType,L2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with L2 Resampler"<::Pointer df + = itk::BSplineUpsampleImageFilter< InputImageType,InputImageType,CenteredL2ResamplerType >::New(); + df->SetSplineOrder(m_ArgsInfo.splineOrder_arg); + filter=df; + if (m_Verbose) std::cout<<"Using the BSpline upsample image filter with L2 centered Resampler"<SetInput(input); + filter->Update(); + typename OutputImageType::Pointer output=filter->GetOutput(); + + //=============================================================================== + // keep component + components.push_back(output); + } + + // Join + typedef itk::Compose3DVectorImageFilter ComposeFilterType; + typename ComposeFilterType::Pointer composeFilter=ComposeFilterType::New(); + for (unsigned int i=0; i<3;i++) + composeFilter->SetInput(i,components[i]); + composeFilter->Update(); + typename VectorOutputImageType::Pointer vectorOutput = composeFilter->GetOutput(); + + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(vectorOutput); + writer->Update(); + + } + +}//end clitk + +#endif //#define clitkBSplinePyramidGenericFilter_txx diff --git a/registration/clitkCalculateTRE.cxx b/registration/clitkCalculateTRE.cxx new file mode 100755 index 0000000..af66b75 --- /dev/null +++ b/registration/clitkCalculateTRE.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkCalculateTRE.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkCalculateTRE_ggo.h" +#include "clitkIO.h" +#include "clitkCalculateTREGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkCalculateTRE, args_info); + CLITK_INIT; + + // Filter + clitk::CalculateTREGenericFilter::Pointer genericFilter=clitk::CalculateTREGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkCalculateTRE.ggo b/registration/clitkCalculateTRE.ggo new file mode 100755 index 0000000..3a79d16 --- /dev/null +++ b/registration/clitkCalculateTRE.ggo @@ -0,0 +1,33 @@ +#File clitkCalculateTRE.ggo +Package "clitkCalculateTRE" +version "1.0" +purpose "Calculate TRE: give a reference point list and 1 or more target point lists. In case of the latter, the number of DVF (or the size of the 4th D) given should match the number of lists. Use --shipFirst to skip the first phase of a 4D DVF. General summarizes for all points (mean, SD, max) in magnitude and par component. Tre and warp gives all values for all points. " + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + + +section "Input" + +option "ref" - "List of points in reference" string yes +option "input" i "Lists of points in targets" string multiple yes +option "vf" - "Input deformation fields" string multiple yes +option "skip" - "Skip a phase of a 4D DVF" int no + +section "Interpolation" + +option "interpVF" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpVFOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpVFSF" - "Sampling factor if BLUT" int no default="20" + + +section "Output" + +option "general" - "Summarized TRE values (mean, SD, max)" string no +option "original" - "Original distances: base filename" string no +option "originalMag" - "Original magnitude of distances: base filename" string no +option "displacement" - "Estmated displacements: base filename" string no +option "displacementMag" - "Estimated magnitude displacements: base filename" string no +option "tre" - "All TRE values: base filename" string no +option "treMag" - "All TRE magnitude values: base filename" string no +option "warp" - "All warped points: base filename" string no diff --git a/registration/clitkCalculateTREGenericFilter.cxx b/registration/clitkCalculateTREGenericFilter.cxx new file mode 100755 index 0000000..1da773b --- /dev/null +++ b/registration/clitkCalculateTREGenericFilter.cxx @@ -0,0 +1,137 @@ +/*========================================================================= + 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 clitkCalculateTREGenericFilter_cxx +#define clitkCalculateTREGenericFilter_cxx + +/* ================================================= + * @file clitkCalculateTREGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkCalculateTREGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + CalculateTREGenericFilter::CalculateTREGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void CalculateTREGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components); + + + // Call UpdateWithDim + if(Dimension==2) ReadVectorFields<2,2>(); + else if(Dimension==3) ReadVectorFields<3,3>(); + else if (Dimension==4)ReadVectorFields<4,3>(); + else + { + std::cout<<"Error, Only for 2, 3 or 4 Dimensions!!!"< + void + CalculateTREGenericFilter::ProcessVectorFields<4,3>(std::vector, 4>::Pointer > dvfs, char** filenames ) + { + // Typedefs + typedef itk::Vector PixelType; + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // IO + InputImageType::Pointer input=dvfs[0]; + std::vector, 3>::Pointer > new_dvfs; + + // Split vector field + typedef itk::ExtractImageFilter FilterType; + unsigned int splitDimension=3; + + // Make new file names + std::vector new_filenames; + std::string base = filenames[0]; + + // Set the extract region + InputImageType::SizeType size=input->GetLargestPossibleRegion().GetSize(); + size[splitDimension]=0; + InputImageType::RegionType extracted_region; + extracted_region.SetSize(size); + InputImageType::IndexType index=input->GetLargestPossibleRegion().GetIndex(); + + + // Loop + for (unsigned int i=0;iGetLargestPossibleRegion().GetSize()[splitDimension];i++) + { + + // Skip? + if (m_ArgsInfo.skip_given && i==(unsigned int) m_ArgsInfo.skip_arg) continue; + + // extract dvf + FilterType::Pointer filter= FilterType::New(); + filter->SetInput(input); + index[splitDimension]=i; + extracted_region.SetIndex(index); + filter->SetExtractionRegion(extracted_region); + filter->Update(); + new_dvfs.push_back(filter->GetOutput()); + + // make name + std::ostringstream number_dvf; + number_dvf << i; + std::string number = number_dvf.str(); + new_filenames.push_back(base+"_"+number); + } + + // Update + this->UpdateWithDim<3>(new_dvfs, new_filenames); + + } + + + + + +} //end clitk + +#endif //#define clitkCalculateTREGenericFilter_cxx diff --git a/registration/clitkCalculateTREGenericFilter.h b/registration/clitkCalculateTREGenericFilter.h new file mode 100755 index 0000000..d9caea1 --- /dev/null +++ b/registration/clitkCalculateTREGenericFilter.h @@ -0,0 +1,124 @@ +/*========================================================================= + 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 clitkCalculateTREGenericFilter_h +#define clitkCalculateTREGenericFilter_h + +/* ================================================= + * @file clitkCalculateTREGenericFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkCalculateTRE_ggo.h" +#include "clitkGenericVectorInterpolator.h" +#include "clitkPointListWriter.h" +#include "clitkPointListReader.h" +#include "clitkDeformationListStatisticsFilter.h" +#include "clitkList.h" + +//itk include +#include "itkLightObject.h" +#include "itkExtractImageFilter.h" + +//general +#include + +namespace clitk +{ + + + class ITK_EXPORT CalculateTREGenericFilter : public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef CalculateTREGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( CalculateTREGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkCalculateTRE& a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.vf_arg[0]; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + CalculateTREGenericFilter(); + ~CalculateTREGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void ReadVectorFields(void); + template void ProcessVectorFields(std::vector< typename itk::Image, Dimension>::Pointer > dvfs, char** filenames); + template void UpdateWithDim( std::vector, Dimension>::Pointer > dvfs, std::vector filenames); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkCalculateTRE m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkCalculateTREGenericFilter.txx" +#endif + +#endif // #define clitkCalculateTREGenericFilter_h diff --git a/registration/clitkCalculateTREGenericFilter.txx b/registration/clitkCalculateTREGenericFilter.txx new file mode 100755 index 0000000..1198ac8 --- /dev/null +++ b/registration/clitkCalculateTREGenericFilter.txx @@ -0,0 +1,606 @@ +/*========================================================================= + 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 clitkCalculateTREGenericFilter_txx +#define clitkCalculateTREGenericFilter_txx + +/* ================================================= + * @file clitkCalculateTREGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //----------------------------- + // Read DVF + //----------------------------- + template + void + CalculateTREGenericFilter::ReadVectorFields(void) + { + + typedef itk::Vector VectorType; + typedef itk::Image DeformationFieldType; + + typedef itk::ImageFileReader InputReaderType; + std::vector dvfs; + for (unsigned int i=0; i< m_ArgsInfo.vf_given; i++) + { + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_ArgsInfo.vf_arg[i]); + if (m_Verbose) std::cout<<"Reading vector field "<< i <<"..."<Update(); + dvfs.push_back( reader->GetOutput() ); + } + + ProcessVectorFields(dvfs, m_ArgsInfo.vf_arg); + } + + //----------------------------- + // Process DVF + //----------------------------- + template + void + CalculateTREGenericFilter::ProcessVectorFields(std::vector, Dimension>::Pointer > dvfs, char** filenames ) + { + + std::vector new_filenames; + for (unsigned int i=0;i(dvfs, new_filenames); + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + CalculateTREGenericFilter::UpdateWithDim(std::vector, Dimension>::Pointer > dvfs, std::vector filenames) + { + if (m_Verbose) std::cout << "Image was detected to be "< MeasureListType; + + typedef itk::Point PointType; + typedef clitk::List PointListType; + typedef clitk::Lists PointListsType; + + typedef itk::Vector VectorType; + typedef clitk::List VectorListType; + typedef clitk::Lists VectorListsType; + + typedef itk::Vector DeformationVectorType; + typedef itk::Image DeformationFieldType; + + //----------------------------- + // Number of inputs + //----------------------------- + unsigned int numberOfFields=filenames.size(); + unsigned int numberOfLists=m_ArgsInfo.input_given; + if ( (numberOfLists!=numberOfFields) && (numberOfLists!=1) ) + { + std::cerr<<"Error: Number of lists (="< GenericVectorInterpolatorType; + typename GenericVectorInterpolatorType::Pointer genericInterpolator=GenericVectorInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + typedef itk::VectorInterpolateImageFunction InterpolatorType; + typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + + + //===================================================================================== + // Original distance between points + //===================================================================================== + VectorListsType originalDistanceLists(numberOfFields); + + //----------------------------- + // Calculate original distances + //----------------------------- + PointType referencePoint; + VectorType distance; + for (unsigned int phaseIndex=0; phaseIndex StatisticsFilterType; + typename StatisticsFilterType::Pointer statisticsFilter=StatisticsFilterType::New(); + + // Statistics (magnitude) + MeasureListType oMeanList, oStdList, oMaxList; + ValueType oMean, oStd, oMax; + statisticsFilter->GetStatistics(originalDistanceLists, oMean, oStd, oMax, oMeanList, oStdList, oMaxList); + + // Statistics (per component) + VectorListType oMeanXYZList, oStdXYZList,oMaxXYZList; + VectorType oMeanXYZ, oStdXYZ, oMaxXYZ; + statisticsFilter->GetStatistics(originalDistanceLists, oMeanXYZ, oStdXYZ, oMaxXYZ, oMeanXYZList, oStdXYZList, oMaxXYZList); + + + //----------------------------- + // Output + //----------------------------- + std::vector labels; + labels.push_back("MeanX\tSDX"); + labels.push_back("MeanY\tSDY"); + labels.push_back("MeanZ\tSDZ"); + labels.push_back("MeanT\tSDT"); + labels.push_back("MaxX"); + labels.push_back("MaxY"); + labels.push_back("MaxZ"); + labels.push_back("MaxT"); + + + // Output to screen + if(m_Verbose) + { + + // Numbers of DVF + std::cout<<"# Number\tDVF"<SetInputImage( dvfs[phaseIndex]); + for (unsigned int pointIndex=0; pointIndexIsInsideBuffer(referencePoint) ) + displacement=interpolator->Evaluate(referencePoint); + else + displacement.Fill(0.0); + + // Warp + warpedPoint=referencePoint+displacement; + displacementLists[phaseIndex].push_back(displacement); + warpedPointLists[phaseIndex].push_back(warpedPoint); + tre=pointLists[phaseIndex][pointIndex]-warpedPoint; + treLists[phaseIndex].push_back(tre); + } + } + + + //----------------------------- + // Statistics displacements + //----------------------------- + + // Statistics (magnitude) + MeasureListType dmeanList, dstdList, dmaxList; + ValueType dmean, dstd, dmax; + statisticsFilter->GetStatistics(displacementLists, dmean, dstd, dmax, dmeanList, dstdList, dmaxList); + + // Statistics (per component) + VectorListType dmeanXYZList, dstdXYZList,dmaxXYZList; + VectorType dmeanXYZ, dstdXYZ, dmaxXYZ; + statisticsFilter->GetStatistics(displacementLists, dmeanXYZ, dstdXYZ, dmaxXYZ,dmeanXYZList, dstdXYZList, dmaxXYZList); + + + //----------------------------- + // Statistics TRE + //----------------------------- + + // Statistics (magnitude) + MeasureListType meanList, stdList, maxList; + ValueType mean, std, max; + statisticsFilter->GetStatistics(treLists, mean, std, max, meanList, stdList, maxList); + + // Statistics (per component) + VectorListType meanXYZList, stdXYZList,maxXYZList; + VectorType meanXYZ, stdXYZ, maxXYZ; + statisticsFilter->GetStatistics(treLists, meanXYZ, stdXYZ, maxXYZ, meanXYZList, stdXYZList, maxXYZList); + + + // Output to screen + if(m_Verbose) + { + + std::cout< filenames; + for (unsigned int i=0;i > originalDistanceListsMag=originalDistanceLists.Norm(); + std::vector filenames; + for (unsigned int i=0;i filenames; + for (unsigned int i=0;i > displacementListsMag=displacementLists.Norm(); + std::vector filenames; + for (unsigned int i=0;i filenames; + for (unsigned int i=0;i filenames; + for (unsigned int i=0;i > treMagLists=treLists.Norm(); + + std::vector filenames; + for (unsigned int i=0;iSetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkConvertBSplineDeformableTransformToVF.ggo b/registration/clitkConvertBSplineDeformableTransformToVF.ggo new file mode 100755 index 0000000..1ee3f8f --- /dev/null +++ b/registration/clitkConvertBSplineDeformableTransformToVF.ggo @@ -0,0 +1,25 @@ +#File clitkConvertBSplineDeformableTransformToVF.ggo +Package "clitkConvertBSplineDeformableTransformToVF" +version "1.0" +purpose "Convert a BSpline transform to a DVF with given properties" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + + +section "IO" +option "input" i "Input coefficient image filename" string yes +option "output" o "Output image filename" string yes + + +section "Output Image Properties" +option "like" - "Make output like this image" string no +option "origin" - "Origin for the output image" double multiple no default="0.0" +option "size" - "Size for the output image" int multiple no default="100" +option "spacing" - "Spacing for the output image" double multiple no default="1.0" + + +section "Transform" +option "order" - "Spline order" int multiple no +option "mask" - "Mask image filename" string no +option "shape" - "Transform shape: 0=egg, 1=diamond" int no default="0" diff --git a/registration/clitkConvertBSplineDeformableTransformToVFGenericFilter.cxx b/registration/clitkConvertBSplineDeformableTransformToVFGenericFilter.cxx new file mode 100755 index 0000000..0d3929a --- /dev/null +++ b/registration/clitkConvertBSplineDeformableTransformToVFGenericFilter.cxx @@ -0,0 +1,417 @@ +/*========================================================================= + 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 clitkConvertBSplineDeformableTransformToVFGenericFilter_cxx +#define clitkConvertBSplineDeformableTransformToVFGenericFilter_cxx + +/* ================================================= + * @file clitkConvertBSplineDeformableTransformToVFGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkConvertBSplineDeformableTransformToVFGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + ConvertBSplineDeformableTransformToVFGenericFilter::ConvertBSplineDeformableTransformToVFGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template<> + void + ConvertBSplineDeformableTransformToVFGenericFilter::UpdateWithDim<3>(std::string PixelType, int Components) + { + // Components + if (Components !=3) + { + std::cerr<<"Number of components is "< InputPixelType; + typedef itk::Vector OutputPixelType; + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + InputImageType::Pointer input= reader->GetOutput(); + + + // ----------------------------------------------- + // Filter + // ----------------------------------------------- + typedef itk::TransformToDeformationFieldSource ConvertorType; + ConvertorType::Pointer filter= ConvertorType::New(); + + //Output image info + if (m_ArgsInfo.like_given) + { + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader2=ReaderType::New(); + reader2->SetFileName(m_ArgsInfo.like_arg); + reader2->Update(); + + OutputImageType::Pointer image=reader2->GetOutput(); + filter->SetOutputParametersFromImage(image); + } + else + { + unsigned int i=0; + if(m_ArgsInfo.origin_given) + { + OutputImageType::PointType origin; + for(i=0;iSetOutputOrigin(origin); + } + if (m_ArgsInfo.spacing_given) + { + OutputImageType::SpacingType spacing; + for(i=0;iSetOutputSpacing(spacing); + } + if (m_ArgsInfo.spacing_given) + { + OutputImageType::SizeType size; + for(i=0;iSetOutputSize(size); + } + } + + if (m_Verbose) + { + std::cout<< "Setting output origin to "<GetOutputOrigin()<<"..."<GetOutputSpacing()<<"..."<GetOutputSize()<<"..."< TransformType; + TransformType::Pointer transform=TransformType::New(); + + // Spline orders: Default is cubic splines + InputImageType::RegionType::SizeType splineOrders ; + splineOrders.Fill(3); + if (m_ArgsInfo.order_given) + for(unsigned int i=0; i MaskType; + MaskType::Pointer spatialObjectMask=NULL; + if (m_ArgsInfo.mask_given) + { + typedef itk::Image< unsigned char, Dimension > ImageMaskType; + typedef itk::ImageFileReader< ImageMaskType > MaskReaderType; + MaskReaderType::Pointer maskReader = MaskReaderType::New(); + maskReader->SetFileName(m_ArgsInfo.mask_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 <<"Mask was read..." <SetImage( maskReader->GetOutput() ); + } + + + // Samplingfactors + InputImageType::SizeType samplingFactors; + for (unsigned int i=0; i< Dimension; i++) + { + samplingFactors[i]= (int) ( input->GetSpacing()[i]/ filter->GetOutputSpacing()[i]); + if (m_Verbose) std::cout<<"Setting sampling factor "<SetSplineOrders(splineOrders); + transform->SetMask(spatialObjectMask); + transform->SetLUTSamplingFactors(samplingFactors); + transform->SetCoefficientImage(input); + filter->SetTransform(transform); + + + // ----------------------------------------------- + // Update + // ----------------------------------------------- + if (m_Verbose)std::cout<< "Converting the BSpline transform..."<Update(); + } + catch (itk::ExceptionObject) + { + std::cerr<<"Error: Exception thrown during execution convertion filter!"<GetOutput(); + + + // ----------------------------------------------- + // Output + // ----------------------------------------------- + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template<> + void + ConvertBSplineDeformableTransformToVFGenericFilter::UpdateWithDim<4>(std::string PixelType, int Components) + { + // Components + if (Components !=3) + { + std::cerr<<"Number of components is "< InputPixelType; + typedef itk::Vector OutputPixelType; + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + InputImageType::Pointer input= reader->GetOutput(); + + + // ----------------------------------------------- + // Filter + // ----------------------------------------------- + typedef clitk::TransformToDeformationFieldSource ConvertorType; + ConvertorType::Pointer filter= ConvertorType::New(); + + //Output image info + if (m_ArgsInfo.like_given) + { + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader2=ReaderType::New(); + reader2->SetFileName(m_ArgsInfo.like_arg); + reader2->Update(); + + OutputImageType::Pointer image=reader2->GetOutput(); + filter->SetOutputParametersFromImage(image); + } + else + { + unsigned int i=0; + if(m_ArgsInfo.origin_given) + { + OutputImageType::PointType origin; + for(i=0;iSetOutputOrigin(origin); + } + if (m_ArgsInfo.spacing_given) + { + OutputImageType::SpacingType spacing; + for(i=0;iSetOutputSpacing(spacing); + } + if (m_ArgsInfo.spacing_given) + { + OutputImageType::SizeType size; + for(i=0;iSetOutputSize(size); + } + } + //Output image info + if (m_Verbose) + { + std::cout<< "Setting output origin to "<GetOutputOrigin()<<"..."<GetOutputSpacing()<<"..."<GetOutputSize()<<"..."< TransformType; + TransformType::Pointer transform=TransformType::New(); + transform->SetTransformShape(m_ArgsInfo.shape_arg); + + // Spline orders: Default is cubic splines + InputImageType::RegionType::SizeType splineOrders ; + splineOrders.Fill(3); + if (m_ArgsInfo.order_given) + for(unsigned int i=0; i MaskType; + MaskType::Pointer spatialObjectMask=NULL; + if (m_ArgsInfo.mask_given) + { + typedef itk::Image< unsigned char, Dimension > ImageMaskType; + typedef itk::ImageFileReader< ImageMaskType > MaskReaderType; + MaskReaderType::Pointer maskReader = MaskReaderType::New(); + maskReader->SetFileName(m_ArgsInfo.mask_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 <<"Mask was read..." <SetImage( maskReader->GetOutput() ); + } + + + // Samplingfactors + InputImageType::SizeType samplingFactors; + for (unsigned int i=0; i< Dimension; i++) + { + samplingFactors[i]= (int) ( input->GetSpacing()[i]/ filter->GetOutputSpacing()[i]); + if (m_Verbose) std::cout<<"Setting sampling factor "<SetSplineOrders(splineOrders); + transform->SetMask(spatialObjectMask); + transform->SetLUTSamplingFactors(samplingFactors); + transform->SetCoefficientImage(input); + filter->SetTransform(transform); + + + // ----------------------------------------------- + // Update + // ----------------------------------------------- + if (m_Verbose)std::cout<< "Converting the BSpline transform..."<Update(); + } + catch (itk::ExceptionObject) + { + std::cerr<<"Error: Exception thrown during execution convertion filter!"<GetOutput(); + + + // ----------------------------------------------- + // Output + // ----------------------------------------------- + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void ConvertBSplineDeformableTransformToVFGenericFilter::Update() + { + + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components); + + // Call UpdateWithDim + //if(Dimension==2) UpdateWithDim<2>(PixelType, Components); + if(Dimension==3) UpdateWithDim<3>(PixelType, Components); + else if (Dimension==4) UpdateWithDim<4>(PixelType, Components); + else + { + std::cout<<"Error, Only for 3 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( ConvertBSplineDeformableTransformToVFGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkConvertBSplineDeformableTransformToVF & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + ConvertBSplineDeformableTransformToVFGenericFilter(); + ~ConvertBSplineDeformableTransformToVFGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType, int Components); + // template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkConvertBSplineDeformableTransformToVF m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + + +#endif // #define clitkConvertBSplineDeformableTransformToVFGenericFilter_h diff --git a/registration/clitkConvertPointList.cxx b/registration/clitkConvertPointList.cxx new file mode 100755 index 0000000..716de80 --- /dev/null +++ b/registration/clitkConvertPointList.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + 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 clitkConvertPointList.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkConvertPointList_ggo.h" +#include "clitkIO.h" +#include "clitkImageCommon.h" +#include "clitkList.h" +#include "clitkLists.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkConvertPointList, args_info); + CLITK_INIT; + + // List + typedef itk::Point PointType; + typedef clitk::List ListType; + typedef clitk::Lists ListsType; + ListType refList; + ListsType targetLists; + + // Image + typedef itk::Image ImageType; + ImageType::Pointer referenceImage=clitk::readImage(args_info.refIm_arg, args_info.verbose_flag); + + // Filenames + std::vector< std::string> fileNames; + for(unsigned int i=0; i< args_info.lists_given; i++) + { + fileNames.push_back(args_info.lists_arg[i]); + if (args_info.verbose_flag) std::cout<<"Adding input point list "< oFileNames; + for(unsigned int i=0; i< args_info.targets_given; i++) + oFileNames.push_back(args_info.targets_arg[i]); + targetLists.Write(oFileNames, args_info.verbose_flag); + } + + return EXIT_SUCCESS; + +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkConvertPointList.ggo b/registration/clitkConvertPointList.ggo new file mode 100755 index 0000000..9c7ac9e --- /dev/null +++ b/registration/clitkConvertPointList.ggo @@ -0,0 +1,15 @@ +#File clitkConvertPointList.ggo +Package "clitkConvertPointList" +version "1.0" +purpose "Convert IX point pair lists (generated using the software described in Murphy2008,MICCAI) to a vv point pair lists" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +section "I/O" + +option "lists" l "Input IX lists filenames" string yes multiple +option "refIm" i "Input reference image filename" string yes +option "ref" r "Output reference list filename" string yes +option "targets" c "Output target lists filenames" string yes multiple + diff --git a/registration/clitkDeformationFieldTransform.h b/registration/clitkDeformationFieldTransform.h new file mode 100644 index 0000000..273376b --- /dev/null +++ b/registration/clitkDeformationFieldTransform.h @@ -0,0 +1,86 @@ +/*========================================================================= + 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 __clitkDeformationFieldTransform_h +#define __clitkDeformationFieldTransform_h +#include "clitkList.h" +#include "clitkLists.h" + +// itk +#include "itkTransform.h" +#include "itkVectorInterpolateImageFunction.h" +#include "itkVectorLinearInterpolateImageFunction.h" + +namespace clitk +{ + + template < class TScalarType=double, unsigned int InputDimension=4,unsigned int OutputDimension=4, unsigned int SpaceDimension=3 > + class ITK_EXPORT DeformationFieldTransform : public itk::Transform< TScalarType, InputDimension, OutputDimension > + { + public: + /** Standard class typedefs. */ + typedef DeformationFieldTransform Self; + typedef itk::Transform< TScalarType, InputDimension, OutputDimension > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** New macro for creation of through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( DeformationFieldTransform, Transform ); + + /** Standard coordinate point type for this class. */ + typedef itk::Point InputPointType; + typedef itk::Point OutputPointType; + + // typedef + typedef itk::Point SpacePointType; + typedef itk::Vector DisplacementType; + typedef itk::Image DeformationFieldType; + typedef itk::VectorInterpolateImageFunction InterpolatorType; + typedef itk::VectorLinearInterpolateImageFunction DefaultInterpolatorType; + + // Members + void SetDeformationField (typename DeformationFieldType::Pointer p){m_DeformationField=p; m_Interpolator->SetInputImage(m_DeformationField);} + void SetInterpolator (typename InterpolatorType::Pointer i){ m_Interpolator=i; m_Interpolator->SetInputImage(m_DeformationField);} + OutputPointType TransformPoint(const InputPointType &point ) const; + + protected: + DeformationFieldTransform(); + ~DeformationFieldTransform(){;} + + private: + DeformationFieldTransform(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + typename DeformationFieldType::Pointer m_DeformationField; + typename InterpolatorType::Pointer m_Interpolator; + + + }; //class DeformationFieldTransform + + + +} // namespace itk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkDeformationFieldTransform.txx" +#endif + +#endif /* __clitkDeformationFieldTransform_h */ diff --git a/registration/clitkDeformationFieldTransform.txx b/registration/clitkDeformationFieldTransform.txx new file mode 100644 index 0000000..af003f4 --- /dev/null +++ b/registration/clitkDeformationFieldTransform.txx @@ -0,0 +1,61 @@ +/*========================================================================= + 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 __clitkDeformationFieldTransform_txx +#define __clitkDeformationFieldTransform_txx +#include "clitkDeformationFieldTransform.h" + + +namespace clitk +{ + + // Constructor + template + DeformationFieldTransform + ::DeformationFieldTransform():Superclass(OutputDimension,1) + { + m_DeformationField=NULL; + m_Interpolator=DefaultInterpolatorType::New(); + } + + // Transform a point + template + typename DeformationFieldTransform::OutputPointType + DeformationFieldTransform:: + TransformPoint(const InputPointType &inputPoint) const + { + OutputPointType outputPoint; + outputPoint.Fill(0.); + for (unsigned int i=0;iIsInsideBuffer(inputPoint) ) + { + displacement=m_Interpolator->Evaluate(inputPoint); + for (unsigned int i=0;i + class ITK_EXPORT DeformationListStatisticsFilter : public itk::LightObject + + { + public: + typedef DeformationListStatisticsFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + //==================================== + //Typedefs + typedef typename ListItemType::ValueType ValueType; + itkStaticConstMacro(Dimension, unsigned int, ListItemType::Dimension); + //typedef itk::Vector ListItemType; + typedef std::vector ValueListType; + typedef clitk::List ListType; + typedef clitk::Lists ListsType; + + //==================================== + //Get + void GetStatistics( const ListType &, ValueType & mean, ValueType & sd, ValueType & max); + void GetStatistics( const ListsType &, ValueListType & mean, ValueListType & sd, ValueListType & max); + void GetStatistics( const ListsType &, ValueType & mean , ValueType & sd, ValueType & max, ValueListType & meanList, ValueListType & sdList, ValueListType & maxList); + + void GetStatistics( const ListType &, ListItemType & meanXYZ, ListItemType & sdXYZ, ListItemType & maxXYZ ); + void GetStatistics( const ListsType &, ListType & meanXYZ, ListType & sdXYZ, ListType & maxXYZ ); + void GetStatistics( const ListsType &, ListItemType & mean , ListItemType & sd, ListItemType & max, ListType & meanXYZList, ListType & sdXYZList, ListType & maxXYZList ); + + protected: + DeformationListStatisticsFilter(){}; + ~DeformationListStatisticsFilter() {}; + + private: + + }; + + + + + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkDeformationListStatisticsFilter.txx" +#endif + +#endif // #define __clitkDeformationListStatistics_h diff --git a/registration/clitkDeformationListStatisticsFilter.txx b/registration/clitkDeformationListStatisticsFilter.txx new file mode 100644 index 0000000..21911a0 --- /dev/null +++ b/registration/clitkDeformationListStatisticsFilter.txx @@ -0,0 +1,205 @@ +/*========================================================================= + 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 __clitkDeformationFieldStatisticsFilter_txx +#define __clitkDeformationFieldStatisticsFilter_txx +#include "clitkDeformationListStatisticsFilter.h" + + +namespace clitk +{ + + //------------------------------------------------------ + //Magnitude + //------------------------------------------------------ + template + void + DeformationListStatisticsFilter::GetStatistics(const ListType& list, ValueType & mean, ValueType & sd, ValueType & max) + { + // Initialize + ValueType norm; + mean=0; + sd=0; + max=0; + + // loop over the list of displacements + for (unsigned int i=0;i + void + DeformationListStatisticsFilter::GetStatistics(const ListsType& list, ValueListType & mean, ValueListType & sd, ValueListType & max) + { + + mean.resize(list.size()); + sd.resize(list.size()); + max.resize(list.size()); + + for (unsigned int i=0;i + void + DeformationListStatisticsFilter::GetStatistics(const ListsType& list, ValueType& mean, ValueType &sd, ValueType & max, ValueListType & meanList, ValueListType & sdList, ValueListType & maxList) + { + // Calculate statistics per list + GetStatistics(list, meanList, sdList, maxList); + + // Initialize + mean=0; + sd=0; + max=0; + + // Loop + for (unsigned int i=0;i + void + DeformationListStatisticsFilter::GetStatistics(const ListType& list, ListItemType & mean, ListItemType & sd, ListItemType & max) + { + // Initialize + ListItemType displacement; + mean.Fill(itk::NumericTraits::Zero); + sd.Fill(itk::NumericTraits::Zero); + max.Fill(itk::NumericTraits::Zero); + + // Loop over the list of displacements + for (unsigned int i=0;i + void + DeformationListStatisticsFilter::GetStatistics(const ListsType& list, ListType & mean, ListType & sd, ListType & max) + { + mean.resize(list.size()); + sd.resize(list.size()); + max.resize(list.size()); + + for (unsigned int i=0;i + void + DeformationListStatisticsFilter::GetStatistics(const ListsType& list, ListItemType& mean, ListItemType &sd, ListItemType & max, ListType & meanList, ListType & sdList, ListType & maxList) + { + // Calculate statistics par list + GetStatistics(list, meanList, sdList, maxList); + + // Initialize + mean.Fill(itk::NumericTraits::Zero); + sd.Fill(itk::NumericTraits::Zero); + max.Fill(itk::NumericTraits::Zero); + ListItemType displacement; + + // Loop + for (unsigned int i=0;i + * @date April 24 10:14:53 2009 + * + * @brief Demons deformable registration + * + */ + + +// clitk include +//#include "clitkDemonsDeformableRegistration_ggo.h" +#include "clitkIO.h" +#include "clitkDemonsDeformableRegistrationGenericFilter.h" +//#include "clitkImageCommon.h" + + +int main( int argc, char *argv[] ) +{ + + GGO(clitkDemonsDeformableRegistration,args_info); + CLITK_INIT; + + //generic Filter + clitk::DemonsDeformableRegistrationGenericFilter::Pointer genericFilter = clitk::DemonsDeformableRegistrationGenericFilter::New(); + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +} diff --git a/registration/clitkDemonsDeformableRegistration.ggo b/registration/clitkDemonsDeformableRegistration.ggo new file mode 100755 index 0000000..bb58207 --- /dev/null +++ b/registration/clitkDemonsDeformableRegistration.ggo @@ -0,0 +1,48 @@ +#File clitkDemonsDeformableRegistration.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 13 Februari 2009 16.35 + +Package "clitk" +Version "Apply Demons registration between (2D or 3D) images..." + + +option "config" - "Config file" string no + + +section "Run Time" + +option "verbose" v "Verbose" flag off +option "threads" - "Number of threads to use for intensive algorithms (default=min(cores,8))" int no +option "debug" - "Give debug info" flag off + + +section "Input" + +option "reference" r "Input reference image" string yes +option "target" t "Input target image" string yes +option "init" - "Input initial deformation field" string no + +section "Output" + +option "vf" - "Result DVF" string yes +option "output" o "Deformed target image" string yes +option "before" - "Difference image before " string no +option "after" - "Difference image after " string no + +section "Demons" + +option "demons" - "Type: 0=normal, 1=symm, 2=fast symm, 3=diffeomorphic" int no default="3" +option "levels" - "Number of resolution levels" int no default="1" +option "maxIter" - "Maximum number of iterations at each resolution level" int no multiple default="50" +option "maxRMSError" - "Maximum RMS error at each resolution level" double no multiple default="1" +option "stop" - "Maximum oscillations at each resolution level (-1=unset)" int no multiple default="-1" +option "sd" - "SD (in mm) for smoothing in each dimension" double no multiple default="2.0" +option "maxStep" - "2,3: Maximum step size (mm)" double no default="2" +option "scaleSD" - "Scale SD to coarse resolution levels" flag off +option "scaleStep" - "2,3: Scale maximum step size to coarse resolution levels" flag off +option "fluid" - "Smooth update field instead of deformation field" flag off +option "spacing" - "Use image spacing for derivatives (non-isotropic voxels)" flag off +option "intThreshold" - "0,1,2: Intensity threshold to consider intensity equal" double no default="0.001" +option "movGrad" - "1: Use moving image gradient" flag off +option "gradType" - "2,3: 0=Symmetric, 1=fixed, 2=warpedMoving, 3=mappedMoving" int no default="0" +option "firstOrder" - "3: Use first order approx for exponential" flag off diff --git a/registration/clitkDemonsDeformableRegistrationGenericFilter.cxx b/registration/clitkDemonsDeformableRegistrationGenericFilter.cxx new file mode 100755 index 0000000..899ab8c --- /dev/null +++ b/registration/clitkDemonsDeformableRegistrationGenericFilter.cxx @@ -0,0 +1,52 @@ +/*========================================================================= + 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 _clitkDemonsDeformableRegistrationGenericFilter_cxx +#define _clitkDemonsDeformableRegistrationGenericFilter_cxx +#include "clitkDemonsDeformableRegistrationGenericFilter.h" + + +namespace clitk { + + clitk::DemonsDeformableRegistrationGenericFilter::DemonsDeformableRegistrationGenericFilter() + { + m_Verbose=false; + } + + + void clitk::DemonsDeformableRegistrationGenericFilter::Update() + { + //Get the image Dimension and PixelType + int Dimension; + std::string PixelType; + + clitk::ReadImageDimensionAndPixelType(m_ReferenceFileName, Dimension, PixelType); + + // if(Dimension==2) UpdateWithDim<2>(PixelType); + // else + if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< + * @date 14 March 2009 + * + * @brief + * + =================================================*/ + +// clitk +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkDemonsDeformableRegistration_ggo.h" +#include "clitkDifferenceImageFilter.h" +#include "clitkMultiResolutionPDEDeformableRegistration.h" + +// itk include +#include "itkMultiResolutionPDEDeformableRegistration.h" +#include "itkPDEDeformableRegistrationFilter.h" +#include "itkDemonsRegistrationFilter.h" +#include "itkSymmetricForcesDemonsRegistrationFilter.h" +#include "itkFastSymmetricForcesDemonsRegistrationFilter.h" +#include "itkDiffeomorphicDemonsRegistrationFilter.h" +#include "itkRecursiveMultiResolutionPyramidImageFilter.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkCommand.h" +#include "itkWarpImageFilter.h" +#include "itkLightObject.h" + + +namespace clitk +{ + + class ITK_EXPORT DemonsDeformableRegistrationGenericFilter : public itk::LightObject + + { + public: + typedef DemonsDeformableRegistrationGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods) */ + itkTypeMacro( DemonsDeformableRegistrationGenericFilter, LightObject ); + + + //==================================================================== + // Set methods + void SetArgsInfo(const args_info_clitkDemonsDeformableRegistration a) + { + m_ArgsInfo=a; + m_ReferenceFileName=m_ArgsInfo.reference_arg; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + //==================================================================== + // Update + virtual void Update(); + + protected: + //const char * GetNameOfClass() const { return "DemonsDeformableRegistrationGenericFilter"; } + + //==================================================================== + // Constructor & Destructor + DemonsDeformableRegistrationGenericFilter(); + ~DemonsDeformableRegistrationGenericFilter(){;} + + //==================================================================== + //Protected member functions + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + args_info_clitkDemonsDeformableRegistration m_ArgsInfo; + bool m_Verbose; + std::string m_ReferenceFileName; + + }; + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkDemonsDeformableRegistrationGenericFilter.txx" +#endif + +#endif //#define _clitkDemonsDeformableRegistrationGenericFilter_h + + + + diff --git a/registration/clitkDemonsDeformableRegistrationGenericFilter.txx b/registration/clitkDemonsDeformableRegistrationGenericFilter.txx new file mode 100755 index 0000000..55406bb --- /dev/null +++ b/registration/clitkDemonsDeformableRegistrationGenericFilter.txx @@ -0,0 +1,691 @@ +/*========================================================================= + 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 __clitkDemonsDeformableRegistrationGenericFilter_txx +#define __clitkDemonsDeformableRegistrationGenericFilter_txx +#include "clitkDemonsDeformableRegistrationGenericFilter.h" + + +namespace clitk +{ + + //============================================================================== + //Creating an observer class that allows us to change parameters at subsequent levels + //============================================================================== + template + class CommandResolutionLevelUpdate : public itk::Command + { + public: + typedef CommandResolutionLevelUpdate Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + itkNewMacro( Self ); + + //Typedefs + itkStaticConstMacro(ImageDimension, unsigned int, MultiRegistrationFilterType::ImageDimension); + typedef typename MultiRegistrationFilterType::FixedImageType FixedImageType; + typedef typename MultiRegistrationFilterType::MovingImageType MovingImageType; + typedef typename MultiRegistrationFilterType::DeformationFieldType DeformationFieldType; + typedef typename MultiRegistrationFilterType::RegistrationType RegistrationType; + typedef typename RegistrationType::FixedImageType InternalImageType; + typedef itk::DiffeomorphicDemonsRegistrationFilter DiffFilterType; + typedef itk::FastSymmetricForcesDemonsRegistrationFilter SymFilterType; + + protected: + CommandResolutionLevelUpdate() + { + m_CurrentLevel=0; + m_MaxStep=2; + m_ScaleStep=false; + m_ScaleSD=false; + } + + public: + + //Set + void SetMaxRMSError(double* m){m_MaxRMSError=m;} + void SetSD(double* m){m_SD=m;} + void SetMaxStep(double m){m_MaxStep=m;} + void SetScaleSD(bool m){m_ScaleSD=m;} + void SetScaleStep(bool m){m_ScaleStep=m;} + void SetRegistrationType(unsigned int i){m_RegistrationType=i;} + + //Execute + void Execute(const itk::Object * caller, const itk::EventObject & event ) + { + std::cout << "Warning: The const Execute method shouldn't be called" << std::endl; + } + void Execute(itk::Object *caller, const itk::EventObject & event) + { + + // Check event + if( !(itk::IterationEvent().CheckEvent( &event )) ) + { + return; + } + + //Cast caller + MultiRegistrationFilterType * filter = dynamic_cast< MultiRegistrationFilterType * >( caller ); + + // Get the level + m_CurrentLevel=filter->GetCurrentLevel(); + unsigned int numberOfLevels=filter->GetNumberOfLevels(); + unsigned int expandFactor=1<< (numberOfLevels-m_CurrentLevel-1); + double * sd = m_SD; + double maxStep=m_MaxStep; + + // Scale the SD + if (m_ScaleSD) + { + for (unsigned int i=0 ; iGetRegistrationFilter()->SetStandardDeviations(sd); + filter->GetRegistrationFilter()->SetUpdateFieldStandardDeviations(sd); + } + + // Scale max step: 2 & 3 only! + if (m_ScaleStep) + { + maxStep= m_MaxStep*expandFactor; + if (m_RegistrationType==2) + { + SymFilterType* symFilter=dynamic_cast< SymFilterType* >(filter->GetRegistrationFilter()); + symFilter->SetMaximumUpdateStepLength(maxStep); + } + else if (m_RegistrationType==3) + { + DiffFilterType* diffFilter=dynamic_cast< DiffFilterType* >(filter->GetRegistrationFilter()); + diffFilter->SetMaximumUpdateStepLength(maxStep); + } + } + + // Set maxRMS + filter->GetRegistrationFilter()->SetMaximumRMSError(m_MaxRMSError[m_CurrentLevel]); + + //Print All + std::cout << "--------------------------------------------------" << std::endl; + std::cout << "Starting resolution level "<GetNumberOfLevels()<<"..."< + class CommandIterationUpdate : public itk::Command + { + public: + typedef CommandIterationUpdate Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + itkNewMacro( Self ); + + + //find the multiresolution filter + // typedef typename RegistrationFilterType::FixedImageType InternalImageType; + // typedef typename RegistrationFilterType::MovingImageType MovingImageType; + typedef typename RegistrationFilterType::DeformationFieldType DeformationFieldType; + typedef clitk::MultiResolutionPDEDeformableRegistration MultiResolutionRegistrationType; + typedef CommandResolutionLevelUpdate LevelObserver; + + protected: + CommandIterationUpdate(){}; + + public: + + // Sets + void SetStop( int* s){m_Stop=s;} + void SetLevelObserver(LevelObserver* o ){m_LevelObserver=o;} + + + //Execute + void Execute(const itk::Object *, const itk::EventObject & ) + { + std::cout << "Warning: The const Execute method shouldn't be called" << std::endl; + } + + void Execute(itk::Object *caller, const itk::EventObject & event) + { + if( !(itk::IterationEvent().CheckEvent( &event )) ) + { + return; + } + + //Cast + RegistrationFilterType * filter = dynamic_cast< RegistrationFilterType * >( caller ); + + if(filter) + { + // Get info + m_Iteration=filter->GetElapsedIterations(); + m_Metric=filter->GetMetric(); + + // Output + std::cout << m_Iteration<<"\t Field Tolerance= "<GetMaximumRMSError(); + std::cout <<"\t DVF Change= " << filter->GetRMSChange()<<"\t RMS= "<m_CurrentLevel]>=0) + { + // First iteration + if(m_Iteration==1) + { + m_Minimum=m_Metric; + m_StopCounter=0; + } + + // Less then minimum + else if(m_Metric=m_Stop[m_LevelObserver->m_CurrentLevel]) + filter->StopRegistration(); + } + + // Output + std::cout <<"\t Stop= "<m_CurrentLevel]< + void DemonsDeformableRegistrationGenericFilter::UpdateWithDim(std::string PixelType) + { + if(PixelType == "short"){ + if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and signed short..." << std::endl; + UpdateWithDimAndPixelType(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "unsigned_char"){ + // if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and unsigned_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching warp in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + + //============================================================================== + // Update with the number of dimensions and pixeltype + //============================================================================== + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + template + void DemonsDeformableRegistrationGenericFilter::UpdateWithDimAndPixelType() + { + //======================================================= + // Run-time + //======================================================= + bool threadsGiven=m_ArgsInfo.threads_given; + int threads=m_ArgsInfo.threads_arg; + + typedef itk::Image< PixelType, ImageDimension > FixedImageType; + typedef itk::Image< PixelType, ImageDimension > MovingImageType; + typedef itk::Image< float, ImageDimension > InternalImageType; + typedef double TCoordRep; + + + //======================================================= + //Input + //======================================================= + typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; + typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType; + + typename FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); + typename MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); + + fixedImageReader->SetFileName( m_ArgsInfo.reference_arg ); + movingImageReader->SetFileName( m_ArgsInfo.target_arg ); + if (m_Verbose) std::cout<<"Reading images..."<Update(); + movingImageReader->Update(); + + typename FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); + typename MovingImageType::Pointer movingImage =movingImageReader->GetOutput(); + typename FixedImageType::RegionType fixedRegion = fixedImage->GetBufferedRegion(); + + + //======================================================= + //Output + //======================================================= + typedef itk::Vector< float, ImageDimension > VectorPixelType; + typedef itk::Image< VectorPixelType, ImageDimension > DeformationFieldType; + + + //======================================================= + //Pyramids + //======================================================= + typedef itk::RecursiveMultiResolutionPyramidImageFilter< FixedImageType, InternalImageType> FixedImagePyramidType; + typedef itk::RecursiveMultiResolutionPyramidImageFilter< MovingImageType, InternalImageType> MovingImagePyramidType; + // typedef itk::MultiResolutionPyramidImageFilter< FixedImageType, FixedImageType> FixedImagePyramidType; + // typedef itk::MultiResolutionPyramidImageFilter< MovingImageType, MovingImageType> MovingImagePyramidType; + typename FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New(); + typename MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New(); + + + // ======================================================= + // Define the registation filters + // ======================================================= + typedef itk::PDEDeformableRegistrationFilter< InternalImageType, InternalImageType, DeformationFieldType> RegistrationFilterType; + typename RegistrationFilterType::Pointer pdeFilter; + typedef clitk::MultiResolutionPDEDeformableRegistration MultiResolutionRegistrationFilterType; + typename MultiResolutionRegistrationFilterType::Pointer multiResolutionFilter = MultiResolutionRegistrationFilterType::New(); + typedef itk::ESMDemonsRegistrationFunction RegistrationFunctionType; + + + // ======================================================= + // The multiresolution scheme + // ======================================================= + if (threadsGiven) multiResolutionFilter->SetNumberOfThreads(threads); + unsigned int nLevels=m_ArgsInfo.levels_arg; + if (m_Verbose) std::cout<<"Setting the number of resolution levels to "<SetFixedImage( fixedImage ); + multiResolutionFilter->SetMovingImage( movingImage ); + multiResolutionFilter->SetNumberOfLevels( nLevels ); + multiResolutionFilter->SetFixedImagePyramid( fixedImagePyramid ); + multiResolutionFilter->SetMovingImagePyramid( movingImagePyramid ); + if (threadsGiven) multiResolutionFilter->SetNumberOfThreads( threads ); + + //------------------------------------ + //Set the number of iterations + //------------------------------------ + unsigned int nIterations[nLevels]; + for (unsigned int i=0 ; iSetNumberOfIterations( nIterations ); + if(m_Verbose) { + std::cout<<"Setting the number of iterations to: "<::Pointer levelObserver = + CommandResolutionLevelUpdate::New(); + multiResolutionFilter->AddObserver( itk::IterationEvent(), levelObserver ); + levelObserver->SetMaxRMSError(maxRMSError); + levelObserver->SetMaxStep(m_ArgsInfo.maxStep_arg); + levelObserver->SetSD(sd); + levelObserver->SetScaleStep(m_ArgsInfo.scaleStep_flag); + levelObserver->SetScaleSD(m_ArgsInfo.scaleSD_flag); + levelObserver->SetRegistrationType(m_ArgsInfo.demons_arg); + + + // ======================================================= + // The type of filter + // ======================================================= + switch (m_ArgsInfo.demons_arg){ + + case 0: + { + typedef itk::DemonsRegistrationFilter< InternalImageType, InternalImageType, DeformationFieldType > DemonsFilterType; + typename DemonsFilterType::Pointer m =DemonsFilterType::New(); + + //Set Parameters for this filter + m->SetIntensityDifferenceThreshold( m_ArgsInfo.intThreshold_arg); + m->SetUseMovingImageGradient( m_ArgsInfo.movGrad_flag); + typename CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); + observer->SetStop(stop); + observer->SetLevelObserver(levelObserver); + m->AddObserver( itk::IterationEvent(), observer ); + if (m_Verbose) std::cout<<"Using the demons registration filter..."< DemonsFilterType; + typename DemonsFilterType::Pointer m =DemonsFilterType::New(); + + //Set Parameters for this filter + m->SetIntensityDifferenceThreshold( m_ArgsInfo.intThreshold_arg); + typename CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); + observer->SetStop(stop); + observer->SetLevelObserver(levelObserver); + m->AddObserver( itk::IterationEvent(), observer ); + if (m_Verbose) std::cout<<"Using the symmetric forces demons registration filter..."< DemonsFilterType; + typename DemonsFilterType::Pointer m = DemonsFilterType::New(); + + //Set Parameters for this filter + m->SetIntensityDifferenceThreshold( m_ArgsInfo.intThreshold_arg); + m->SetMaximumUpdateStepLength( m_ArgsInfo.maxStep_arg); + m->SetUseGradientType(grad); + typename CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); + observer->SetStop(stop); + observer->SetLevelObserver(levelObserver); + m->AddObserver( itk::IterationEvent(), observer ); + if (m_Verbose) std::cout<<"Using the fast symmetric forces demons registration filter..."< DemonsFilterType; + typename DemonsFilterType::Pointer m = DemonsFilterType::New(); + + //Set Parameters for this filter + m->SetMaximumUpdateStepLength( m_ArgsInfo.maxStep_arg); + m->SetUseFirstOrderExp(m_ArgsInfo.firstOrder_flag); + m->SetUseGradientType(grad); + typename CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); + observer->SetStop(stop); + observer->SetLevelObserver(levelObserver); + m->AddObserver( itk::IterationEvent(), observer ); + if (m_Verbose) std::cout<<"Using the diffeomorphic demons registration filter..."<SetStandardDeviations( sd ); + pdeFilter->SetUpdateFieldStandardDeviations( sd ); + //JV TODO + // pdeFilter->SetMaximumError(m_ArgsInfo.maxError_arg); + // pdeFilter->SetMaximumKernelWidth(m_ArgsInfo.maxError_arg); + pdeFilter->SetSmoothDeformationField(!m_ArgsInfo.fluid_flag); + pdeFilter->SetSmoothUpdateField(m_ArgsInfo.fluid_flag); + pdeFilter->SetUseImageSpacing( m_ArgsInfo.spacing_flag ); + + //Pass to the multi resolution scheme + multiResolutionFilter->SetRegistrationFilter( pdeFilter ); + + + // ======================================================= + // The initial solution + // ======================================================= + if (m_ArgsInfo.init_given) + { + typedef itk::ImageFileReader DeformationFieldReaderType; + typename DeformationFieldReaderType::Pointer defReader=DeformationFieldReaderType::New(); + defReader->SetFileName(m_ArgsInfo.init_arg); + defReader->Update(); + multiResolutionFilter->SetArbitraryInitialDeformationField(defReader->GetOutput()); + } + + + // ======================================================= + // Execute + // ======================================================= + try + { + multiResolutionFilter->Update(); + } + catch( itk::ExceptionObject & excp ) + { + std::cerr <<"Error executing the demons filter: "<< excp << std::endl; + return; + } + + + //======================================================= + // Get the output + //======================================================= + typename DeformationFieldType::Pointer deformationField=multiResolutionFilter->GetOutput(); + + + //======================================================= + // Write the DVF + //======================================================= + typedef itk::ImageFileWriter< DeformationFieldType > FieldWriterType; + typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New(); + fieldWriter->SetInput( deformationField ); + fieldWriter->SetFileName( m_ArgsInfo.vf_arg ); + try + { + fieldWriter->Update(); + } + catch( itk::ExceptionObject & excp ) + { + std::cerr << "Exception thrown writing the DVF" << std::endl; + std::cerr << excp << std::endl; + return; + } + + + //======================================================= + // Warp the moving image + //======================================================= + typedef itk::WarpImageFilter< MovingImageType, FixedImageType, DeformationFieldType > WarpFilterType; + typename WarpFilterType::Pointer warp = WarpFilterType::New(); + + warp->SetDeformationField( deformationField ); + warp->SetInput( movingImageReader->GetOutput() ); + warp->SetOutputOrigin( fixedImage->GetOrigin() ); + warp->SetOutputSpacing( fixedImage->GetSpacing() ); + warp->SetOutputDirection( fixedImage->GetDirection() ); + warp->SetEdgePaddingValue( 0.0 ); + warp->Update(); + + + //======================================================= + // Write the warped image + //======================================================= + typedef itk::ImageFileWriter< FixedImageType > WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName( m_ArgsInfo.output_arg ); + writer->SetInput( warp->GetOutput() ); + + try + { + writer->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Calculate the difference after the deformable transform + //======================================================= + typedef clitk::DifferenceImageFilter< FixedImageType, FixedImageType> DifferenceFilterType; + if (m_ArgsInfo.after_given) + { + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( warp->GetOutput() ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + differenceWriter->SetInput(difference->GetOutput()); + differenceWriter->SetFileName(m_ArgsInfo.after_arg); + differenceWriter->Update(); + + } + + + //======================================================= + // Calculate the difference before the deformable transform + //======================================================= + if( m_ArgsInfo.before_given ) + { + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( movingImage ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + writer->SetFileName( m_ArgsInfo.before_arg ); + writer->SetInput( difference->GetOutput() ); + writer->Update( ); + } + + return; + } + +}//end namespace + +#endif // __clitkDemonsDeformableRegistrationGenericFilter_txx diff --git a/registration/clitkDifferenceImageFilter.h b/registration/clitkDifferenceImageFilter.h new file mode 100755 index 0000000..29b2844 --- /dev/null +++ b/registration/clitkDifferenceImageFilter.h @@ -0,0 +1,73 @@ +/*========================================================================= + 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 __clitkDifferenceImageFilter_h +#define __clitkDifferenceImageFilter_h +#include "clitkImageCommon.h" + +//itk include +#include "itkImageToImageFilter.h" +#include "itkImage.h" +#include "itkImageRegionConstIterator.h" +#include "itkNumericTraits.h" + +namespace clitk +{ + + template < class InputImageType , class OutputImageType> + class DifferenceImageFilter : public itk::ImageToImageFilter + + { + public: + typedef DifferenceImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Determine the image dimension. */ + itkStaticConstMacro(ImageDimension, unsigned int, + InputImageType::ImageDimension ); + + /** Inherit some types from the superclass. */ + typedef typename OutputImageType::RegionType OutputImageRegionType; + + //Set + void SetValidInput(const typename InputImageType::Pointer input); + void SetTestInput( const typename InputImageType::Pointer input); + + protected: + DifferenceImageFilter(); + ~DifferenceImageFilter() {}; + void ThreadedGenerateData(const OutputImageRegionType& threadRegion, int threadId); + + + }; + + + + + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkDifferenceImageFilter.txx" +#endif + +#endif // #define __clitkDifferenceImageFilter_h diff --git a/registration/clitkDifferenceImageFilter.txx b/registration/clitkDifferenceImageFilter.txx new file mode 100755 index 0000000..9c267e3 --- /dev/null +++ b/registration/clitkDifferenceImageFilter.txx @@ -0,0 +1,85 @@ +/*========================================================================= + 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 __clitkDifferenceImageFilter_txx +#define __clitkDifferenceImageFilter_txx +#include "clitkDifferenceImageFilter.h" + + +namespace clitk +{ + + //========================================================================================================================= + // DifferenceImageFilter + //========================================================================================================================= + + //========================================================================================================================= + //constructor + template + DifferenceImageFilter::DifferenceImageFilter() + { + this->SetNumberOfRequiredInputs(2); + } + + //========================================================================================================================= + //set input + template + void DifferenceImageFilter::SetValidInput(const typename InputImageType::Pointer input) + { + this->SetNthInput(0,input); + } + + template + void DifferenceImageFilter::SetTestInput(const typename InputImageType::Pointer input) + { + this->SetNthInput(1,input); + } + + + //========================================================================================================================= + //Update + template + void DifferenceImageFilter::ThreadedGenerateData(const OutputImageRegionType &threadRegion, int threadId) + { + //Pointers to input and output + typename InputImageType::ConstPointer input1=this->GetInput(0); + typename InputImageType::ConstPointer input2=this->GetInput(1); + typename OutputImageType::Pointer output=this->GetOutput(); + + //Iterator over input1, input0 and output + typedef itk::ImageRegionConstIterator InputIteratortype; + typedef itk::ImageRegionIterator OutputIteratortype; + InputIteratortype input1Iterator (input1, threadRegion); + InputIteratortype input2Iterator (input2, threadRegion); + OutputIteratortype outputIterator (output, threadRegion); + input1Iterator.GoToBegin(); + input2Iterator.GoToBegin(); + outputIterator.GoToBegin(); + + while (!outputIterator.IsAtEnd()) + { + outputIterator.Set(input1Iterator.Get()-input2Iterator.Get()); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + +} + + +#endif diff --git a/registration/clitkExtractImageFilter.h b/registration/clitkExtractImageFilter.h new file mode 100644 index 0000000..12880ac --- /dev/null +++ b/registration/clitkExtractImageFilter.h @@ -0,0 +1,113 @@ +/*========================================================================= + 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 __clitkExtractImageFilter_h +#define __clitkExtractImageFilter_h +#include "itkImageToImageFilter.h" +#include "itkSmartPointer.h" +#include "itkExtractImageFilterRegionCopier.h" + +namespace clitk +{ + +template +class ITK_EXPORT ExtractImageFilter: + public itk::ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + typedef ExtractImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractImageFilter, ImageToImageFilter); + + /** Image type information. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + + /** Typedef to describe the output and input image region types. */ + typedef typename TOutputImage::RegionType OutputImageRegionType; + typedef typename TInputImage::RegionType InputImageRegionType; + + /** Typedef to describe the type of pixel. */ + typedef typename TOutputImage::PixelType OutputImagePixelType; + typedef typename TInputImage::PixelType InputImagePixelType; + + /** Typedef to describe the output and input image index and size types. */ + typedef typename TOutputImage::IndexType OutputImageIndexType; + typedef typename TInputImage::IndexType InputImageIndexType; + typedef typename TOutputImage::SizeType OutputImageSizeType; + typedef typename TInputImage::SizeType InputImageSizeType; + + /** ImageDimension enumeration */ + itkStaticConstMacro(InputImageDimension, unsigned int, + TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, + TOutputImage::ImageDimension); + + typedef itk::ImageToImageFilterDetail::ExtractImageFilterRegionCopier< + itkGetStaticConstMacro(InputImageDimension), + itkGetStaticConstMacro(OutputImageDimension)> ExtractImageFilterRegionCopierType; + + void SetExtractionRegion(InputImageRegionType extractRegion); + itkGetMacro(ExtractionRegion, InputImageRegionType); + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(InputCovertibleToOutputCheck, + (itk::Concept::Convertible)); + /** End concept checking */ +#endif + +protected: + ExtractImageFilter(); + ~ExtractImageFilter() {}; + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + + virtual void GenerateOutputInformation(); + + + virtual void CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion, + const OutputImageRegionType &srcRegion); + + + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + int threadId ); + InputImageRegionType m_ExtractionRegion; + OutputImageRegionType m_OutputImageRegion; + +private: + ExtractImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractImageFilter.txx" +#endif + +#endif diff --git a/registration/clitkExtractImageFilter.txx b/registration/clitkExtractImageFilter.txx new file mode 100644 index 0000000..f4aa402 --- /dev/null +++ b/registration/clitkExtractImageFilter.txx @@ -0,0 +1,274 @@ +/*========================================================================= + 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 _clitkExtractImageFilter_txx +#define _clitkExtractImageFilter_txx +#include "clitkExtractImageFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkObjectFactory.h" +#include "itkExtractImageFilterRegionCopier.h" +#include "itkProgressReporter.h" + + +namespace clitk +{ + +/** + * + */ +template +ExtractImageFilter +::ExtractImageFilter() +{ +} + + +/** + * + */ +template +void +ExtractImageFilter +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os,indent); + + os << indent << "ExtractionRegion: " << m_ExtractionRegion << std::endl; + os << indent << "OutputImageRegion: " << m_OutputImageRegion << std::endl; +} + + +template +void +ExtractImageFilter +::CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion, + const OutputImageRegionType &srcRegion) +{ + ExtractImageFilterRegionCopierType extractImageRegionCopier; + extractImageRegionCopier(destRegion, srcRegion, m_ExtractionRegion); +} + + +template +void +ExtractImageFilter +::SetExtractionRegion(InputImageRegionType extractRegion) +{ + m_ExtractionRegion = extractRegion; + + unsigned int nonzeroSizeCount = 0; + InputImageSizeType inputSize = extractRegion.GetSize(); + OutputImageSizeType outputSize; + OutputImageIndexType outputIndex; + + /** + * check to see if the number of non-zero entries in the extraction region + * matches the number of dimensions in the output image. + **/ + for (unsigned int i = 0; i < InputImageDimension; ++i) + { + if (inputSize[i]) + { + outputSize[nonzeroSizeCount] = inputSize[i]; + outputIndex[nonzeroSizeCount] = extractRegion.GetIndex()[i]; + nonzeroSizeCount++; + } + } + + if (nonzeroSizeCount != OutputImageDimension) + { + itkExceptionMacro("Extraction Region not consistent with output image"); + } + + m_OutputImageRegion.SetSize(outputSize); + m_OutputImageRegion.SetIndex(outputIndex); + this->Modified(); +} + + + +/** + * ExtractImageFilter can produce an image which is a different resolution + * than its input image. As such, ExtractImageFilter needs to provide an + * implementation for GenerateOutputInformation() in order to inform + * the pipeline execution model. The original documentation of this + * method is below. + * + * \sa ProcessObject::GenerateOutputInformaton() + */ +template +void +ExtractImageFilter +::GenerateOutputInformation() +{ + // do not call the superclass' implementation of this method since + // this filter allows the input and the output to be of different dimensions + + // get pointers to the input and output + typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); + typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); + + if ( !outputPtr || !inputPtr) + { + return; + } + + // Set the output image size to the same value as the extraction region. + outputPtr->SetLargestPossibleRegion( m_OutputImageRegion ); + + // Set the output spacing and origin + const itk::ImageBase *phyData; + + phyData + = dynamic_cast*>(this->GetInput()); + + if (phyData) + { + // Copy what we can from the image from spacing and origin of the input + // This logic needs to be augmented with logic that select which + // dimensions to copy + + unsigned int i; + const typename InputImageType::SpacingType& + inputSpacing = inputPtr->GetSpacing(); + const typename InputImageType::DirectionType& + inputDirection = inputPtr->GetDirection(); + const typename InputImageType::PointType& + inputOrigin = inputPtr->GetOrigin(); + + typename OutputImageType::SpacingType outputSpacing; + typename OutputImageType::DirectionType outputDirection; + typename OutputImageType::PointType outputOrigin; + + if ( static_cast(OutputImageDimension) > + static_cast(InputImageDimension ) ) + { + // copy the input to the output and fill the rest of the + // output with zeros. + for (i=0; i < InputImageDimension; ++i) + { + outputSpacing[i] = inputSpacing[i]; + outputOrigin[i] = inputOrigin[i]; + for (unsigned int dim = 0; dim < InputImageDimension; ++dim) + { + outputDirection[i][dim] = inputDirection[i][dim]; + } + } + for (; i < OutputImageDimension; ++i) + { + outputSpacing[i] = 1.0; + outputOrigin[i] = 0.0; + for (unsigned int dim = 0; dim < InputImageDimension; ++dim) + { + outputDirection[i][dim] = 0.0; + } + outputDirection[i][i] = 1.0; + } + } + else + { + // copy the non-collapsed part of the input spacing and origing to the output + int nonZeroCount = 0; + for (i=0; i < InputImageDimension; ++i) + { + if (m_ExtractionRegion.GetSize()[i]) + { + outputSpacing[nonZeroCount] = inputSpacing[i]; + outputOrigin[nonZeroCount] = inputOrigin[i]; + int nonZeroCount2 = 0; + for (unsigned int dim = 0; dim < InputImageDimension; ++dim) + { + if (m_ExtractionRegion.GetSize()[dim]) + { + outputDirection[nonZeroCount][nonZeroCount2] = + inputDirection[i][dim]; + ++nonZeroCount2; + } + } + nonZeroCount++; + } + } + } + + // set the spacing and origin + outputPtr->SetSpacing( outputSpacing ); + outputPtr->SetDirection( outputDirection ); + outputPtr->SetOrigin( outputOrigin ); + outputPtr->SetNumberOfComponentsPerPixel(inputPtr->GetNumberOfComponentsPerPixel() ); + } + else + { + // pointer could not be cast back down + itkExceptionMacro(<< "itk::ExtractImageFilter::GenerateOutputInformation " + << "cannot cast input to " + << typeid(itk::ImageBase*).name() ); + } +} + +/** + * ExtractImageFilter can be implemented as a multithreaded filter. + * Therefore, this implementation provides a ThreadedGenerateData() + * routine which is called for each processing thread. The output + * image data is allocated automatically by the superclass prior to + * calling ThreadedGenerateData(). ThreadedGenerateData can only + * write to the portion of the output image specified by the + * parameter "outputRegionForThread" + * + * \sa ImageToImageFilter::ThreadedGenerateData(), + * ImageToImageFilter::GenerateData() + */ +template +void +ExtractImageFilter +::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + int threadId) +{ + itkDebugMacro(<<"Actually executing"); + + // Get the input and output pointers + typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); + typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); + + // support progress methods/callbacks + itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); + + // Define the portion of the input to walk for this thread + InputImageRegionType inputRegionForThread; + this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread); + + // Define the iterators. + typedef itk::ImageRegionIterator OutputIterator; + typedef itk::ImageRegionConstIterator InputIterator; + + OutputIterator outIt(outputPtr, outputRegionForThread); + InputIterator inIt(inputPtr, inputRegionForThread); + + // walk the output region, and sample the input image + while( !outIt.IsAtEnd() ) + { + // copy the input pixel to the output + outIt.Set( static_cast(inIt.Get())); + ++outIt; + ++inIt; + progress.CompletedPixel(); + } +} + +} // end namespace clitk + +#endif diff --git a/registration/clitkGenericVectorInterpolator.h b/registration/clitkGenericVectorInterpolator.h new file mode 100755 index 0000000..557d419 --- /dev/null +++ b/registration/clitkGenericVectorInterpolator.h @@ -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 __clitkGenericVectorInterpolator_h +#define __clitkGenericVectorInterpolator_h +#include "clitkImageCommon.h" + +//itk include +#include "itkVectorNearestNeighborInterpolateImageFunction.h" +#include "itkVectorLinearInterpolateImageFunction.h" +#include "clitkVectorBSplineInterpolateImageFunction.h" +#include "clitkVectorBSplineInterpolateImageFunctionWithLUT.h" + +/* + +Requires at least the following section is the .ggo file + +option "interpVF" - "Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpVFOrder" - "Order if BLUT or BSpline (0-5)" int no default="3" +option "interpVFSF" - "Sampling factor if BLUT" int no default="20" + +The use will look something like + +typedef clitk::GenericVectorInterpolator GenericVectorInterpolatorType; +typename GenericVectorInterpolatorType::Pointer genericInterpolator=GenericVectorInterpolatorType::New(); +genericInterpolator->SetArgsInfo(m_ArgsInfo); +typedef itk::VectorInterpolateImageFunction InterpolatorType; +typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + +*/ + +namespace clitk +{ + + template + class GenericVectorInterpolator : public itk::LightObject + { + public: + //============================================== + typedef GenericVectorInterpolator Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + typedef itk::VectorInterpolateImageFunction 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: + GenericVectorInterpolator(); + ~GenericVectorInterpolator() {}; + + private: + args_info_type m_ArgsInfo; + InterpolatorPointer m_Interpolator; + bool m_Verbose; + }; + +} // end namespace clitk +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkGenericVectorInterpolator.txx" +#endif + +#endif // #define __clitkGenericVectorInterpolator_h diff --git a/registration/clitkGenericVectorInterpolator.txx b/registration/clitkGenericVectorInterpolator.txx new file mode 100755 index 0000000..9fd6892 --- /dev/null +++ b/registration/clitkGenericVectorInterpolator.txx @@ -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 __clitkGenericVectorInterpolator_txx +#define __clitkGenericVectorInterpolator_txx +#include "clitkGenericVectorInterpolator.h" + + +namespace clitk +{ + + //========================================================================================================================= + //constructor + template + GenericVectorInterpolator::GenericVectorInterpolator() + { + m_Interpolator=NULL; + m_Verbose=false; + } + + + //========================================================================================================================= + //Get the pointer + template + typename GenericVectorInterpolator::InterpolatorPointer + GenericVectorInterpolator::GetInterpolatorPointer() + { + //============================================================================ + // We retrieve the type of interpolation from the command line + //============================================================================ + typename InterpolatorType::Pointer interpolator; + + switch ( m_ArgsInfo.interpVF_arg ) + { + case 0: + + interpolator= itk::VectorNearestNeighborInterpolateImageFunction< ImageType,TCoordRep >::New(); + if (m_Verbose) std::cout<<"Using nearestneighbor interpolation..."<::New(); + if (m_Verbose) std::cout<<"Using linear interpolation..."<::Pointer m =clitk::VectorBSplineInterpolateImageFunction< ImageType,TCoordRep >::New(); + m->SetSplineOrder(m_ArgsInfo.interpVFOrder_arg); + interpolator=m; + if (m_Verbose) std::cout<<"Using Bspline interpolation..."<::Pointer m =clitk::VectorBSplineInterpolateImageFunctionWithLUT< ImageType,TCoordRep >::New(); + m->SetSplineOrder(m_ArgsInfo.interpVFOrder_arg); + m->SetLUTSamplingFactor(m_ArgsInfo.interpVFSF_arg); + interpolator=m; + if (m_Verbose) std::cout<<"Using BLUT interpolation..."< +extern "C" { + extern double v3p_netlib_dpmeps_(); +} namespace clitk { @@ -51,7 +36,7 @@ namespace clitk * vnl_lbfgsb into iteration events in ITK. */ class ITK_EXPORT LBFGSBOptimizerHelper : - public vnl_lbfgsb + public vnl_lbfgsb { public: typedef LBFGSBOptimizerHelper Self; @@ -68,7 +53,7 @@ private: LBFGSBOptimizer* m_ItkObj; }; - + /** @@ -81,7 +66,7 @@ LBFGSBOptimizer m_VnlOptimizer = 0; m_LowerBound = InternalBoundValueType(0); - m_UpperBound = InternalBoundValueType(0); + m_UpperBound = InternalBoundValueType(0); m_BoundSelection = InternalBoundSelectionType(0); m_CostFunctionConvergenceFactor = 1e+7; @@ -92,7 +77,8 @@ LBFGSBOptimizer m_CurrentIteration = 0; m_Value = 0.0; m_InfinityNormOfProjectedGradient = 0.0; - + m_StopConditionDescription.str(""); + } @@ -111,41 +97,42 @@ LBFGSBOptimizer 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 << "CostFunctionConvergenceFactor: " << + m_CostFunctionConvergenceFactor << std::endl; os << indent << "ProjectedGradientTolerance: " << - m_ProjectedGradientTolerance << std::endl; + m_ProjectedGradientTolerance << std::endl; os << indent << "MaximumNumberOfIterations: " << - m_MaximumNumberOfIterations << std::endl; + m_MaximumNumberOfIterations << std::endl; os << indent << "MaximumNumberOfEvaluations: " << - m_MaximumNumberOfEvaluations << std::endl; + m_MaximumNumberOfEvaluations << std::endl; - os << indent << "MaximumNumberOfCorrections: " << - m_MaximumNumberOfCorrections << std::endl; + os << indent << "MaximumNumberOfCorrections: " << + m_MaximumNumberOfCorrections << std::endl; - os << indent << "CurrentIteration: " << - m_CurrentIteration << std::endl; + os << indent << "CurrentIteration: " << + m_CurrentIteration << std::endl; os << indent << "Value: " << - m_Value << std::endl; + m_Value << std::endl; os << indent << "InfinityNormOfProjectedGradient: " << - m_InfinityNormOfProjectedGradient << std::endl; + m_InfinityNormOfProjectedGradient << std::endl; - if( this->m_VnlOptimizer ) { - os << indent << "Vnl LBFGSB Failure Code: " << - this->m_VnlOptimizer->get_failure_code() << std::endl; - } + if( this->m_VnlOptimizer ) + { + os << indent << "Vnl LBFGSB Failure Code: " << + this->m_VnlOptimizer->get_failure_code() << std::endl; + } } /** @@ -154,12 +141,13 @@ LBFGSBOptimizer void LBFGSBOptimizer ::SetLowerBound( - const BoundValueType& value ) +const BoundValueType& value ) { m_LowerBound = value; - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_lower_bound( m_LowerBound ); - } + } this->Modified(); } @@ -168,13 +156,13 @@ LBFGSBOptimizer * Get lower bound */ const -LBFGSBOptimizer +LBFGSBOptimizer ::BoundValueType & LBFGSBOptimizer ::GetLowerBound() { return m_LowerBound; -} +} /** * Set upper bound @@ -182,12 +170,13 @@ LBFGSBOptimizer void LBFGSBOptimizer ::SetUpperBound( - const BoundValueType& value ) +const BoundValueType& value ) { m_UpperBound = value; - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_upper_bound( m_UpperBound ); - } + } this->Modified(); } @@ -196,13 +185,13 @@ LBFGSBOptimizer * Get upper bound */ const -LBFGSBOptimizer +LBFGSBOptimizer ::BoundValueType & LBFGSBOptimizer ::GetUpperBound() { return m_UpperBound; -} +} /** @@ -211,12 +200,13 @@ LBFGSBOptimizer void LBFGSBOptimizer ::SetBoundSelection( - const BoundSelectionType& value ) +const BoundSelectionType& value ) { m_BoundSelection = value; - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_bound_selection( m_BoundSelection ); - } + } this->Modified(); } @@ -224,35 +214,37 @@ LBFGSBOptimizer * Get bound selection array */ const -LBFGSBOptimizer +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; + * 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"); - } + 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 ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_cost_function_convergence_factor( m_CostFunctionConvergenceFactor ); - } + } this->Modified(); } @@ -266,10 +258,11 @@ LBFGSBOptimizer ::SetProjectedGradientTolerance( double value ) { m_ProjectedGradientTolerance = value; - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_projected_gradient_tolerance( m_ProjectedGradientTolerance ); - } + } this->Modified(); } @@ -290,9 +283,10 @@ LBFGSBOptimizer ::SetMaximumNumberOfEvaluations( unsigned int value ) { m_MaximumNumberOfEvaluations = value; - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_max_function_evals( m_MaximumNumberOfEvaluations ); - } + } this->Modified(); } @@ -303,10 +297,11 @@ LBFGSBOptimizer ::SetMaximumNumberOfCorrections( unsigned int value ) { m_MaximumNumberOfCorrections = value; - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { m_VnlOptimizer->set_max_variable_metric_corrections( m_MaximumNumberOfCorrections ); - } + } this->Modified(); } @@ -320,18 +315,19 @@ SetCostFunction( itk::SingleValuedCostFunction * costFunction ) { m_CostFunction = costFunction; - const unsigned int numberOfParameters = + const unsigned int numberOfParameters = costFunction->GetNumberOfParameters(); - CostFunctionAdaptorType * adaptor = + CostFunctionAdaptorType * adaptor = new CostFunctionAdaptorType( numberOfParameters ); - + adaptor->SetCostFunction( costFunction ); - if( m_OptimizerInitialized ) { + if( m_OptimizerInitialized ) + { delete m_VnlOptimizer; - } - + } + this->SetCostFunctionAdaptor( adaptor ); m_VnlOptimizer = new InternalOptimizerType( *adaptor, this ); @@ -342,7 +338,7 @@ SetCostFunction( itk::SingleValuedCostFunction * costFunction ) m_VnlOptimizer->set_bound_selection( m_BoundSelection ); m_VnlOptimizer->set_cost_function_convergence_factor( m_CostFunctionConvergenceFactor ); - m_VnlOptimizer->set_projected_gradient_tolerance( + m_VnlOptimizer->set_projected_gradient_tolerance( m_ProjectedGradientTolerance ); m_VnlOptimizer->set_max_function_evals( m_MaximumNumberOfEvaluations ); m_VnlOptimizer->set_max_variable_metric_corrections( @@ -361,43 +357,52 @@ 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 ) { + if ( this->GetInitialPosition().Size() < numberOfParameters ) + { itkExceptionMacro( << "InitialPosition array does not have sufficient number of elements" ); - } + } - if ( m_LowerBound.size() < numberOfParameters ) { + if ( m_LowerBound.size() < numberOfParameters ) + { itkExceptionMacro( << "LowerBound array does not have sufficient number of elements" ); - } + } - if ( m_UpperBound.size() < numberOfParameters ) { + if ( m_UpperBound.size() < numberOfParameters ) + { itkExceptionMacro( << "UppperBound array does not have sufficient number of elements" ); - } + } - if ( m_BoundSelection.size() < numberOfParameters ) { + if ( m_BoundSelection.size() < numberOfParameters ) + { itkExceptionMacro( << "BoundSelection array does not have sufficient number of elements" ); - } + } - if( this->GetMaximize() ) { + if( this->GetMaximize() ) + { this->GetNonConstCostFunctionAdaptor()->NegateCostFunctionOn(); - } + } this->SetCurrentPosition( this->GetInitialPosition() ); ParametersType parameters( this->GetInitialPosition() ); - // vnl optimizers return the solution by reference + // Clear the description + m_StopConditionDescription.str(""); + + // vnl optimizers return the solution by reference // in the variable provided as initial position m_VnlOptimizer->minimize( parameters ); - if ( parameters.size() != this->GetInitialPosition().Size() ) { + 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 ); @@ -440,13 +445,81 @@ LBFGSBOptimizerHelper // Return true to terminate the optimization loop. - if( this->num_iterations_ > m_ItkObj->m_MaximumNumberOfIterations ) { + if( this->num_iterations_ > m_ItkObj->m_MaximumNumberOfIterations ) + { + m_ItkObj->m_StopConditionDescription << + "Too many iterations. Iterations = " << + m_ItkObj->m_MaximumNumberOfIterations; return true; - } else { + } + else + { return false; - } + } } +const std::string +LBFGSBOptimizer:: +GetStopConditionDescription() const +{ + if (m_VnlOptimizer) + { + m_StopConditionDescription.str(""); + m_StopConditionDescription << this->GetNameOfClass() << ": "; + switch (m_VnlOptimizer->get_failure_code()) + { + case vnl_nonlinear_minimizer::ERROR_FAILURE: + m_StopConditionDescription << "Failure"; + break; + case vnl_nonlinear_minimizer::ERROR_DODGY_INPUT: + m_StopConditionDescription << "Dodgy input"; + break; + case vnl_nonlinear_minimizer::CONVERGED_FTOL: + m_StopConditionDescription << "Function tolerance reached after " + << m_CurrentIteration + << " iterations. " + << "The relative reduction of the cost function <= " + << m_CostFunctionConvergenceFactor * v3p_netlib_dpmeps_() + << " = CostFunctionConvergenceFactor (" + << m_CostFunctionConvergenceFactor + << ") * machine precision (" + << v3p_netlib_dpmeps_() + << ")."; + break; + case vnl_nonlinear_minimizer::CONVERGED_XTOL: + m_StopConditionDescription << "Solution tolerance reached"; + break; + case vnl_nonlinear_minimizer::CONVERGED_XFTOL: + m_StopConditionDescription << "Solution and Function tolerance both reached"; + break; + case vnl_nonlinear_minimizer::CONVERGED_GTOL: + m_StopConditionDescription << "Gradient tolerance reached. " + << "Projected gradient tolerance is " + << m_ProjectedGradientTolerance; + break; + case vnl_nonlinear_minimizer::FAILED_TOO_MANY_ITERATIONS: + m_StopConditionDescription << "Too many iterations. Iterations = " + << m_MaximumNumberOfEvaluations; + break; + case vnl_nonlinear_minimizer::FAILED_FTOL_TOO_SMALL: + m_StopConditionDescription << "Function tolerance too small"; + break; + case vnl_nonlinear_minimizer::FAILED_XTOL_TOO_SMALL: + m_StopConditionDescription << "Solution tolerance too small"; + break; + case vnl_nonlinear_minimizer::FAILED_GTOL_TOO_SMALL: + m_StopConditionDescription << "Gradient tolerance too small"; + break; + case vnl_nonlinear_minimizer::FAILED_USER_REQUEST: + break; + } + return m_StopConditionDescription.str(); + } + else + { + return std::string(""); + } +} } // end namespace clitk diff --git a/registration/clitkLBFGSBOptimizer.h b/registration/clitkLBFGSBOptimizer.h index 5485b76..cfc8007 100644 --- a/registration/clitkLBFGSBOptimizer.h +++ b/registration/clitkLBFGSBOptimizer.h @@ -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,26 +15,8 @@ - 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 @@ -61,21 +43,21 @@ class ITK_EXPORT LBFGSBOptimizerHelper; * * 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. + * [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. + * [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 +class ITK_EXPORT LBFGSBOptimizer : + public itk::SingleValuedNonLinearVnlOptimizer { public: /** Standard "Self" typedef. */ @@ -83,7 +65,7 @@ public: typedef itk::SingleValuedNonLinearVnlOptimizer Superclass; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; - + /** Method for creation through the object factory. */ itkNewMacro(Self); @@ -91,12 +73,12 @@ public: itkTypeMacro( LBFGSBOptimizer, SingleValuedNonLinearVnlOptimizer ); /** BoundValue type. - * Use for defining the lower and upper bounds on the variables. + * Use for defining the lower and upper bounds on the variables. */ typedef itk::Array BoundValueType; /** BoundSelection type - * Use for defining the boundary condition for each variables. + * Use for defining the boundary condition for each variables. */ typedef itk::Array BoundSelectionType; @@ -136,7 +118,7 @@ public: /** 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; + * 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 ); @@ -162,9 +144,10 @@ public: itkGetMacro( MaximumNumberOfCorrections, unsigned int ); /** This optimizer does not support scaling of the derivatives. */ - void SetScales( const ScalesType & ) { + void SetScales( const ScalesType & ) + { itkExceptionMacro( << "This optimizer does not support scales." ); - } + } /** Get the current iteration number. */ itkGetConstReferenceMacro( CurrentIteration, unsigned int ); @@ -176,6 +159,9 @@ public: * function. */ itkGetConstReferenceMacro( InfinityNormOfProjectedGradient, double ); + /** Get the reason for termination */ + const std::string GetStopConditionDescription() const; + protected: LBFGSBOptimizer(); virtual ~LBFGSBOptimizer(); @@ -193,7 +179,7 @@ private: bool m_OptimizerInitialized; InternalOptimizerType * m_VnlOptimizer; - + mutable itk::OStringStream m_StopConditionDescription; BoundValueType m_LowerBound; BoundValueType m_UpperBound; BoundSelectionType m_BoundSelection; diff --git a/registration/clitkLinearCombinationImageFilter.h b/registration/clitkLinearCombinationImageFilter.h new file mode 100644 index 0000000..eaa16dd --- /dev/null +++ b/registration/clitkLinearCombinationImageFilter.h @@ -0,0 +1,94 @@ +/*========================================================================= + 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 __itkLinearCombinationImageFilter_h +#define __itkLinearCombinationImageFilter_h +#include "itkImageToImageFilter.h" +#include "itkNumericTraits.h" + + +namespace clitk +{ + + + template + class ITK_EXPORT LinearCombinationImageFilter : + public itk::ImageToImageFilter + { + public: + //----------------------------------- + /** Standard class typedefs. */ + //----------------------------------- + typedef LinearCombinationImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Runtime information support. */ + itkTypeMacro(LinearCombinationImageFilter, ImageToImageFilter); + + //----------------------------------- + //Typedefs + //----------------------------------- + typedef typename TInputImage::Pointer InputPointer; + typedef typename TInputImage::ConstPointer InputConstPointer; + typedef typename TInputImage::PixelType InputPixelType; + + typedef typename TOutputImage::Pointer OutputPointer; + typedef typename TOutputImage::PixelType OutputPixelType; + typedef typename TOutputImage::RegionType OutputImageRegionType; + //----------------------------------- + //Set/Get + //---------------------------------- + void SetFirstInput (const InputPointer i); + void SetFirstInput ( const InputConstPointer i); + void SetSecondInput (const InputPointer i); + void SetSecondInput (const InputConstPointer i); + + itkSetMacro(A, double); + itkGetMacro(A, double); + itkSetMacro(B, double); + itkGetMacro(B, double); + itkSetMacro(C, double); + itkGetMacro(C, double); + + protected: + LinearCombinationImageFilter(); + virtual ~LinearCombinationImageFilter(){}; + + virtual void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId); + + private: + LinearCombinationImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + double m_A; + double m_B; + double m_C; + + }; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkLinearCombinationImageFilter.txx" +#endif + +#endif diff --git a/registration/clitkLinearCombinationImageFilter.txx b/registration/clitkLinearCombinationImageFilter.txx new file mode 100644 index 0000000..b2ec7d9 --- /dev/null +++ b/registration/clitkLinearCombinationImageFilter.txx @@ -0,0 +1,210 @@ +/*========================================================================= + 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 __clitkLinearCombinationImageFilter_txx +#define __clitkLinearCombinationImageFilter_txx +#include "clitkLinearCombinationImageFilter.h" + + +namespace clitk +{ + + //========================================================================================================================= + // LinearCombinationImageFilter + //========================================================================================================================= + + //========================================================================================================================= + //constructor + template + LinearCombinationImageFilter + ::LinearCombinationImageFilter() + { + this->SetNumberOfRequiredInputs(2); + m_A=1.; + m_B=1.; + m_C=0.; + + } + + //========================================================================================================================= + //set input + template + void LinearCombinationImageFilter::SetFirstInput(const typename InputImageType::Pointer input) + { + this->SetInput(0,input); + } + template + void LinearCombinationImageFilter::SetSecondInput(const typename InputImageType::Pointer input) + { + this->SetInput(1,input); + } + + + template + void LinearCombinationImageFilter::SetFirstInput(const typename InputImageType::ConstPointer input) + { + this->SetInput(0,input); + } + template + void LinearCombinationImageFilter::SetSecondInput(const typename InputImageType::ConstPointer input) + { + this->SetInput(1,input); + } + + + //========================================================================================================================= + //Update + template + void + LinearCombinationImageFilter + ::ThreadedGenerateData(const OutputImageRegionType &threadRegion, int threadId) + { + //Pointers to input and output + typename InputImageType::ConstPointer input1=this->GetInput(0); + typename InputImageType::ConstPointer input2=this->GetInput(1); + typename OutputImageType::Pointer output=this->GetOutput(); + + //Iterator over input1, input0 and output + typedef itk::ImageRegionConstIterator InputIteratortype; + typedef itk::ImageRegionIterator OutputIteratortype; + InputIteratortype input1Iterator (input1, threadRegion); + InputIteratortype input2Iterator (input2, threadRegion); + OutputIteratortype outputIterator (output, threadRegion); + input1Iterator.GoToBegin(); + input2Iterator.GoToBegin(); + outputIterator.GoToBegin(); + + //Find which coefficient should be applied + + if (m_C==0.) + { + if (m_B==1.) + { + if (m_A==1.) + { + while (!outputIterator.IsAtEnd()) + { + // outputIterator.Set(static_cast(input1Iterator.Get()+input2Iterator.Get())); + outputIterator.Set(input1Iterator.Get()+input2Iterator.Get()); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + else + { + while (!outputIterator.IsAtEnd()) + { + // outputIterator.Set(static_cast(m_A* input1Iterator.Get()+input2Iterator.Get())); + outputIterator.Set(m_A* input1Iterator.Get()+input2Iterator.Get()); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + } + // case B not 1 + else + { + if (m_A==1.) + { + + while (!outputIterator.IsAtEnd()) + { + //outputIterator.Set(static_cast(input1Iterator.Get()+m_B *input2Iterator.Get())); + outputIterator.Set(input1Iterator.Get()+m_B *input2Iterator.Get()); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + else + { + while (!outputIterator.IsAtEnd()) + { + //outputIterator.Set(static_cast(m_A* input1Iterator.Get()+ m_B*input2Iterator.Get())); + outputIterator.Set(m_A* input1Iterator.Get()+ m_B*input2Iterator.Get()); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + } + + } + + //Case C not 0 + else + { + if (m_B==1.) + { + if (m_A==1.) + { + + while (!outputIterator.IsAtEnd()) + { + outputIterator.Set(static_cast(input1Iterator.Get()+input2Iterator.Get())+ m_C); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + else + { + while (!outputIterator.IsAtEnd()) + { + outputIterator.Set(static_cast(m_A* input1Iterator.Get()+input2Iterator.Get()+ m_C) ); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + } + // case B not 1 + else + { + if (m_A==1.) + { + + while (!outputIterator.IsAtEnd()) + { + outputIterator.Set(static_cast(input1Iterator.Get()+m_B *input2Iterator.Get()+ m_C) ); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + else + { + while (!outputIterator.IsAtEnd()) + { + outputIterator.Set(static_cast(m_A* input1Iterator.Get()+ m_B*input2Iterator.Get()+ m_C) ); + ++input1Iterator; + ++input2Iterator; + ++outputIterator; + } + } + } + } + + } + +}// end of namespace clitk + + + +#endif diff --git a/registration/clitkList.h b/registration/clitkList.h new file mode 100644 index 0000000..c98ecc5 --- /dev/null +++ b/registration/clitkList.h @@ -0,0 +1,85 @@ +/*========================================================================= + 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 CLITKLIST_H +#define CLITKLIST_H +/** + ================================================= + * @file clitkList.h + * @author Jef Vandemeulebroucke + * @date 30 April 2008 + * + * @brief + * + =================================================*/ + +#include "clitkCommon.h" +#include "clitkIO.h" + +// itk include +#include "itkLightObject.h" + +using namespace std; + +namespace clitk{ + + template + class List: public std::vector + { + + public: + //===================================================================================== + //Typedefs + typedef typename ListItemType::ValueType ValueType; + itkStaticConstMacro(Dimension, unsigned int, ListItemType::Dimension); + typedef List ListType; + typedef itk::ContinuousIndex IndexType; + typedef itk::Image ImageType; + + //===================================================================================== + // IO + void Read(const string& fileName, bool verbose=false); + void ReadAndConvertPointPairs(const string& fileName, List& correspList, const typename ImageType::Pointer referenceImage , bool verbose=false); + bool ReadPointPair(const string& fileName, const unsigned int& pointNumber, IndexType& item1, IndexType& item2, bool& veryUnsure); + void Write(const string fileName, const bool verbose); + void Print(); + + //===================================================================================== + // Members + List > Norm(void); + + //===================================================================================== + //Constructors - Destructors + List(){}; + List(const string fileName, bool verbose=false ){Read(fileName, verbose);} + List(unsigned int size) { this->resize(size); }; + ~List(){}; + + protected: + + + }; + + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkList.txx" +#endif + +#endif + diff --git a/registration/clitkList.txx b/registration/clitkList.txx new file mode 100644 index 0000000..208a4c5 --- /dev/null +++ b/registration/clitkList.txx @@ -0,0 +1,363 @@ +/*========================================================================= + 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 CLITKLIST_TXX +#define CLITKLIST_TXX +#include "clitkList.h" + +using namespace std; + +namespace clitk +{ + + + //--------------------------------------------------------------------- + // Read + //--------------------------------------------------------------------- + template + void List< ListItemType>::Read(const string& filename, bool verbose) + { + std::ifstream is; + openFileForReading(is, filename); + + this->resize(0); + ListItemType item; + ValueType x; + + if(verbose)std::cout<<"Reading "<> x; + item[dim]=x; + } + + while (!is.eof()) + { + this->push_back(item); + for (unsigned int dim=0; dim> x; + item[dim]=x; + } + } + } + + + //--------------------------------------------------------------------- + // ReadPointPairs (specific for DARS- IX point list format) + //--------------------------------------------------------------------- + template + void + List::ReadAndConvertPointPairs(const std::string& fileName, List& correspList, const typename ImageType::Pointer referenceImage, bool verbose) + { + // Init + this->resize(0); + correspList.resize(0); + + // Tags + IndexType item1, item2; + itk::Point point1,point2; + unsigned int pointNumber=0; + bool veryUnsure=false; + + // Read first point + bool pointWasFound=ReadPointPair(fileName, pointNumber, item1, item2, veryUnsure); + + // Loop over all points + while (pointWasFound) + { + // Store the values + if(veryUnsure) + { + if (verbose) std::cout<<"Omitting item "<TransformContinuousIndexToPhysicalPoint(item1, point1); + referenceImage->TransformContinuousIndexToPhysicalPoint(item2, point2); + if (verbose) std::cout<<"Converted items "<push_back(point1); + correspList.push_back(point2); + } + + // Next point + pointNumber++; + pointWasFound=ReadPointPair(fileName, pointNumber, item1, item2, veryUnsure); + } + } + + //--------------------------------------------------------------------- + // Read one point + //--------------------------------------------------------------------- + template + bool + List< ListItemType>::ReadPointPair(const std::string& fileName, const unsigned int& pointNumber, IndexType& item1, IndexType& item2, bool& veryUnsure) + { + // bool + bool pointWasFound=false; + veryUnsure=false; + item1.Fill(0.0); + item2.Fill(0.0); + + // Open the file + ifstream listStream(fileName.c_str()); + string line; + if(!listStream.is_open()){ + std::cerr << "ERROR: Couldn't open file " << fileName << " in List::Read" << std::endl; + return false; + } + + // Skip the configuration lines + while ( !listStream.eof()) + { + // Get the line + skipComment(listStream); + getline(listStream, line); + + // Get the line type + unsigned int endIndexItemType= line.find_first_of ("_",0)-1; + string typeString= line.substr(0 , endIndexItemType+1); + + // Check + if (typeString=="Point") + break; + } + + // Get the point number + unsigned int beginIndexItemNumber= line.find_first_of ("_",0)+1; + unsigned int endIndexItemNumber= line.find_first_of ("->",0)-1; + stringstream numberString( line.substr(beginIndexItemNumber , endIndexItemNumber-beginIndexItemNumber+1) ); + unsigned int itemNumber; + numberString>> itemNumber; + + // FF to the pointNumber + while ( (itemNumber != pointNumber) && (!listStream.eof()) ) + { + // Skipcomment + skipComment(listStream); + + // Get Line + getline(listStream, line); + + // Get the point number + beginIndexItemNumber= line.find_first_of ("_",0)+1; + endIndexItemNumber= line.find_first_of ("->",0)-1; + stringstream numberString( line.substr(beginIndexItemNumber , endIndexItemNumber-beginIndexItemNumber+1) ); + numberString>> itemNumber; + } + + // Go over all fields of the pointNumber + while (itemNumber == pointNumber && (!listStream.eof()) ) + { + // point found + pointWasFound=true; + + // Get the tag + unsigned int beginIndexItemTag= line.find_first_of ("->",0)+2; + unsigned int endIndexItemTag= line.find_first_of ("=",0)-1; + string itemTag= line.substr(beginIndexItemTag , endIndexItemTag-beginIndexItemTag+1); + + // Get the point Value + unsigned int beginIndexItemValue= line.find_first_of ("=",0)+1; + stringstream valueString( line.substr(beginIndexItemValue) ); + double itemValue; + valueString>> itemValue; + + // Fill the items + if (itemTag=="X") + item1[0]=itemValue; + if (itemTag=="Y") + item1[1]=itemValue; + if (itemTag=="Z") + item1[2]=itemValue; + if (itemTag=="X_Corresp") + item2[0]=itemValue; + if (itemTag=="Y_Corresp") + item2[1]=itemValue; + if (itemTag=="Z_Corresp") + item2[2]=itemValue; + if (itemTag=="VeryUnsure") + veryUnsure=itemValue; + + // Get the next line + skipComment(listStream); + getline(listStream, line); + + // Get the point number + unsigned int beginIndexItemNumber= line.find_first_of ("_",0)+1; + unsigned int endIndexItemNumber= line.find_first_of ("->",0)-1; + stringstream numberString( line.substr(beginIndexItemNumber , endIndexItemNumber-beginIndexItemNumber+1) ); + numberString >> itemNumber; + } + + return pointWasFound; + } + + + //--------------------------------------------------------------------- + // Print + //--------------------------------------------------------------------- + template + void List< ListItemType>::Print() + { + for (unsigned int i=0; i< this->size(); i++) + std::cout<at(i)< + void List::Write(const string fileName, const bool verbose) + { + ofstream listStream(fileName.c_str()); + if(!listStream.is_open()){ + cerr << "ERROR: Couldn't open file " << fileName << " in List::Write" << endl; + return; + } + + typename ListType::iterator it=this->begin(); + while(it!=this->end()) { + listStream << (*it)[0]; + for (unsigned int i=1; i< this->at(0).Size(); i++) + listStream <<" "<< (*it)[i]; + listStream<< endl; + it++; + } + listStream.close(); + } + + //--------------------------------------------------------------------- + // Norm + //--------------------------------------------------------------------- + template + List > List< ListItemType>::Norm() + { + List > norm; + itk::FixedArray n; + unsigned int d; + for (unsigned int i=0; i< this->size(); i++) + { + n[0]=0; + for (d=0; d< Dimension; d++) + n[0]+=this->at(i)[d] * this->at(i)[d]; + n[0]=sqrt(n[0]); + norm.push_back(n); + } + return norm; + } + + + + +} + +#endif //#define CLITKLIST + + + // // Open the file + // ifstream listStream(fileName.c_str()); + // ListItemType item; + // string line; + // if(!listStream.is_open()){ + // std::cerr << "ERROR: Couldn't open file " << fileName << " in List::Read" << std::endl; + // return; + // } + // skipComment(listStream); + + // // Skip the configuration lines + // while (true) + // { + // // Get the line + // skipComment(listStream); + // getline(listStream, line); + + // // Get the line type + // unsigned int endIndexItemType= line.find_first_of ("_",0)-1; + // string typeString= line.substr(0 , endIndexItemType+1); + + // // Check + // if (typeString=="Point") + // break; + // } + + // // Get the point number + // unsigned int beginIndexItemNumber= line.find_first_of ("_",0)+1; + // unsigned int endIndexItemNumber= line.find_first_of ("->",0)-1; + // stringstream numberString( line.substr(beginIndexItemNumber , endIndexItemNumber-beginIndexItemNumber+1) ); + // unsigned int itemNumber; + // numberString>> itemNumber; + + // // Go over all the lines + // while(!listStream.eof()) + // { + // // Stored data + // itk::Point point1, point2; + // point1.Fill(0.); + // point2.Fill(0.); + // bool veryUnsure=false; + + // // Retrieved data + // itk::ContinuousIndex item1, item2; + // item1.Fill(0.); + // item2.Fill(0.); + + // // Go over all lines corresponding to this point + // unsigned int currentNumber=itemNumber; + // while (itemNumber == currentNumber && (!listStream.eof()) ) + // { + // // Get the tag + // unsigned int beginIndexItemTag= line.find_first_of ("->",0)+2; + // unsigned int endIndexItemTag= line.find_first_of ("=",0)-1; + // string itemTag= line.substr(beginIndexItemTag , endIndexItemTag-beginIndexItemTag+1); + + // // Get the point Value + // unsigned int beginIndexItemValue= line.find_first_of ("=",0)+1; + // stringstream valueString( line.substr(beginIndexItemValue) ); + // double itemValue; + // valueString>> itemValue; + + // // Fill the items + // if (itemTag=="X") + // item1[0]=itemValue; + // if (itemTag=="Y") + // item1[1]=itemValue; + // if (itemTag=="Z") + // item1[2]=itemValue; + // if (itemTag=="X_Corresp") + // item2[0]=itemValue; + // if (itemTag=="Y_Corresp") + // item2[1]=itemValue; + // if (itemTag=="Z_Corresp") + // item2[2]=itemValue; + // if (itemTag=="VeryUnsure") + // veryUnsure=itemValue; + + // // Get the next line + // skipComment(listStream); + // getline(listStream, line); + + // // Get the point number + // unsigned int beginIndexItemNumber= line.find_first_of ("_",0)+1; + // unsigned int endIndexItemNumber= line.find_first_of ("->",0)-1; + // stringstream numberString( line.substr(beginIndexItemNumber , endIndexItemNumber-beginIndexItemNumber+1) ); + // numberString>> itemNumber; + // } diff --git a/registration/clitkLists.h b/registration/clitkLists.h new file mode 100644 index 0000000..ada58de --- /dev/null +++ b/registration/clitkLists.h @@ -0,0 +1,83 @@ +/*========================================================================= + 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 clitkLists_h +#define clitkLists_h +/** + ================================================= + * @file clitkLists.h + * @author Jef Vandemeulebroucke + * @date 30 April 2008 + * + * @brief + * + =================================================*/ + +#include "clitkCommon.h" +#include "clitkIO.h" +#include "clitkList.h" + +// itk include +#include "itkLightObject.h" + +using namespace std; + +namespace clitk{ + + template + class Lists: public std::vector > + { + public: + //===================================================================================== + //Typedefs + typedef typename ListItemType::ValueType ValueType; + itkStaticConstMacro(Dimension, unsigned int, ListItemType::Dimension); + typedef List ListType; + typedef itk::Image ImageType; + + //===================================================================================== + // IO + void Read(const std::vector& fileNames, bool verbose=false); + void ReadAndConvertPointPairs(const std::vector& fileNames, ListType& refList, const typename ImageType::Pointer referenceImage , bool verbose=false); + void Write(const std::vector fileNames, const bool verbose); + void Print(); + + //===================================================================================== + // Members + Lists< itk::FixedArray > Norm(void); + + //===================================================================================== + //Constructors - Destructors + Lists(){}; + Lists(unsigned int size){this->resize(size);}; + Lists(const std::vector fileNames, bool verbose=false ){Read(fileNames, verbose);} + ~Lists(){}; + + + protected: + + + }; + + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkLists.txx" +#endif + +#endif diff --git a/registration/clitkLists.txx b/registration/clitkLists.txx new file mode 100644 index 0000000..bd404c6 --- /dev/null +++ b/registration/clitkLists.txx @@ -0,0 +1,180 @@ +/*========================================================================= + 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 clitkLists_txx +#define clitkLists_txx +#include "clitkLists.h" + +using namespace std; + +namespace clitk +{ + + //--------------------------------------------------------------------- + // Read + //--------------------------------------------------------------------- + template + void Lists< ListItemType>::Read(const std::vector& filenames, bool verbose) + { + + // Make the lists + this->resize(filenames.size()); + + // Read the lists + for (unsigned int i=0; iat(i).Read(filenames[i],verbose); + + } + + //--------------------------------------------------------------------- + // Norm + //--------------------------------------------------------------------- + template + Lists > Lists::Norm(void) + { + Lists > norm; + + // Normalize the lists + for (unsigned int i=0; isize();i++) + norm.push_back(this->at(i).Norm()); + + return norm; + } + + //--------------------------------------------------------------------- + // ReadPointPairs (specific for DARS- IX point list format) + //--------------------------------------------------------------------- + template + void + Lists::ReadAndConvertPointPairs(const std::vector& fileNames, ListType& refList, const typename ImageType::Pointer referenceImage, bool verbose) + { + + // Init + this->resize(fileNames.size()); + refList.resize(0); + bool pointWasFound=true; + unsigned int pointNumber=0; + itk::ContinuousIndex item1; + std::vector > item2(fileNames.size()); + itk::Point point1, point2; + unsigned int totalNumberOfPoints=0; + std::vector addedNumberOfPoints,ommittedNumberOfPoints; + std::vector pointIsUnsure(fileNames.size()); + std::vector > ommittedNumberOfPointsUnsure; + + // Loop over the points + while (pointWasFound) + { + + if (verbose) std::cout<at(i).ReadPointPair(fileNames[i],pointNumber,item1,item2[i],veryUnsure); + if (verbose && pointWasFound) std::cout<<" "<TransformContinuousIndexToPhysicalPoint(item1, point1); + refList.push_back(point1); + } + referenceImage->TransformContinuousIndexToPhysicalPoint(item2[i], point2); + if (verbose) std::cout<<"Converted items "<at(i).push_back(point2); + } + } + } + + // Next point + pointNumber++; + + } + + if (verbose) + { + std::cout< + void Lists::Write(const std::vector fileNames, const bool verbose) + { + for (unsigned int i =0; i< fileNames.size(); i++) + this->at(i).Write(fileNames[i], verbose); + } + + +} // namespace + +#endif diff --git a/registration/clitkMatrixTransformToVF.cxx b/registration/clitkMatrixTransformToVF.cxx new file mode 100755 index 0000000..40af4d3 --- /dev/null +++ b/registration/clitkMatrixTransformToVF.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkMatrixTransformToVF.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkMatrixTransformToVF_ggo.h" +#include "clitkIO.h" +#include "clitkMatrixTransformToVFGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkMatrixTransformToVF, args_info); + CLITK_INIT; + + // Filter + clitk::MatrixTransformToVFGenericFilter::Pointer genericFilter=clitk::MatrixTransformToVFGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkMatrixTransformToVF.ggo b/registration/clitkMatrixTransformToVF.ggo new file mode 100755 index 0000000..e30742f --- /dev/null +++ b/registration/clitkMatrixTransformToVF.ggo @@ -0,0 +1,18 @@ +#File clitkMatrixTransformToVF.ggo +Package "clitkMatrixTransformToVF" +version "1.0" +purpose "Convert a matrix to a DVF with given properties" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "matrix" i "Input matrix filename" string yes +option "output" o "Output image filename" string yes +option "dim" d "Dimension" int no default="3" + +section "Output Image Properties" +option "like" - "Make output like this image" string no +option "origin" - "Origin for the output image" double multiple no default="0.0" +option "size" - "Size for the output image" int multiple no default="100" +option "spacing" - "Spacing for the output image" double multiple no default="1.0" + diff --git a/registration/clitkMatrixTransformToVFGenericFilter.cxx b/registration/clitkMatrixTransformToVFGenericFilter.cxx new file mode 100755 index 0000000..2d49066 --- /dev/null +++ b/registration/clitkMatrixTransformToVFGenericFilter.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + 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 clitkMatrixTransformToVFGenericFilter_cxx +#define clitkMatrixTransformToVFGenericFilter_cxx + +/* ================================================= + * @file clitkMatrixTransformToVFGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkMatrixTransformToVFGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + MatrixTransformToVFGenericFilter::MatrixTransformToVFGenericFilter() + { + m_Verbose=false; + + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void MatrixTransformToVFGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension=m_ArgsInfo.dim_arg; + //std::string PixelType; + //ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(); + else if(Dimension==3) UpdateWithDim<3>(); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( MatrixTransformToVFGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkMatrixTransformToVF & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + MatrixTransformToVFGenericFilter(); + ~MatrixTransformToVFGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(); + //template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkMatrixTransformToVF m_ArgsInfo; + bool m_Verbose; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkMatrixTransformToVFGenericFilter.txx" +#endif + +#endif // #define clitkMatrixTransformToVFGenericFilter_h diff --git a/registration/clitkMatrixTransformToVFGenericFilter.txx b/registration/clitkMatrixTransformToVFGenericFilter.txx new file mode 100755 index 0000000..df1ed8a --- /dev/null +++ b/registration/clitkMatrixTransformToVFGenericFilter.txx @@ -0,0 +1,145 @@ +/*========================================================================= + 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 clitkMatrixTransformToVFGenericFilter_txx +#define clitkMatrixTransformToVFGenericFilter_txx + +/* ================================================= + * @file clitkMatrixTransformToVFGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + MatrixTransformToVFGenericFilter::UpdateWithDim() + { + // if (m_Verbose) std::cout << "Image was detected to be "<(); +// } +// // else if(PixelType == "unsigned_short"){ +// // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; +// // UpdateWithDimAndPixelType(); +// // } + +// else if (PixelType == "unsigned_char"){ +// if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; +// UpdateWithDimAndPixelType(); +// } + +// // else if (PixelType == "char"){ +// // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; +// // UpdateWithDimAndPixelType(); +// // } +// else { +// if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; +// UpdateWithDimAndPixelType(); +// } +// } + + +// //------------------------------------------------------------------- +// // Update with the number of dimensions and the pixeltype +// //------------------------------------------------------------------- +// template +// void +// MatrixTransformToVFGenericFilter::UpdateWithDimAndPixelType() +// { + + // ImageTypes + typedef itk::Vector Displacement; + typedef itk::Image OutputImageType; + + // Filter + typedef itk::TransformToDeformationFieldSource ConvertorType; + typename ConvertorType::Pointer filter= ConvertorType::New(); + + // Output image info + if (m_ArgsInfo.like_given) + { + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader2=ReaderType::New(); + reader2->SetFileName(m_ArgsInfo.like_arg); + reader2->Update(); + + typename OutputImageType::Pointer image=reader2->GetOutput(); + filter->SetOutputParametersFromImage(image); + } + else + { + unsigned int i=0; + if(m_ArgsInfo.origin_given) + { + typename OutputImageType::PointType origin; + for(i=0;iSetOutputOrigin(origin); + } + if (m_ArgsInfo.spacing_given) + { + typename OutputImageType::SpacingType spacing; + for(i=0;iSetOutputSpacing(spacing); + } + if (m_ArgsInfo.size_given) + { + typename OutputImageType::SizeType size; + for(i=0;iSetOutputSize(size); + } + } + + // Transform + typedef itk::AffineTransform TransformType; + typename TransformType::Pointer transform =TransformType::New(); + itk::Matrix homMatrix= ReadMatrix( m_ArgsInfo.matrix_arg); + itk::Matrix matrix =GetRotationalPartMatrix( homMatrix); + itk::Vector offset= GetTranslationPartMatrix( homMatrix); + transform->SetMatrix(matrix); + transform->SetOffset(offset); + filter->SetTransform(transform); + filter->Update(); + typename OutputImageType::Pointer output=filter->GetOutput(); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + +}//end clitk + +#endif //#define clitkMatrixTransformToVFGenericFilter_txx diff --git a/registration/clitkMultiResolutionPDEDeformableRegistration.h b/registration/clitkMultiResolutionPDEDeformableRegistration.h new file mode 100755 index 0000000..3487208 --- /dev/null +++ b/registration/clitkMultiResolutionPDEDeformableRegistration.h @@ -0,0 +1,235 @@ +/*========================================================================= + 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 __clitkMultiResolutionPDEDeformableRegistration_h +#define __clitkMultiResolutionPDEDeformableRegistration_h +#include "itkImage.h" +#include "itkImageToImageFilter.h" +#include "itkPDEDeformableRegistrationFilter.h" +#include "itkDemonsRegistrationFilter.h" +#include "itkMultiResolutionPyramidImageFilter.h" +#include "itkVectorResampleImageFilter.h" +#include "itkRecursiveGaussianImageFilter.h" +#include + +namespace clitk +{ + +template +class ITK_EXPORT MultiResolutionPDEDeformableRegistration : + public itk::ImageToImageFilter +{ +public: + /** Standard class typedefs */ + typedef MultiResolutionPDEDeformableRegistration Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro( MultiResolutionPDEDeformableRegistration, + ImageToImageFilter ); + + /** Fixed image type. */ + typedef TFixedImage FixedImageType; + typedef typename FixedImageType::Pointer FixedImagePointer; + typedef typename FixedImageType::ConstPointer FixedImageConstPointer; + + /** Moving image type. */ + typedef TMovingImage MovingImageType; + typedef typename MovingImageType::Pointer MovingImagePointer; + typedef typename MovingImageType::ConstPointer MovingImageConstPointer; + + /** Deformation field image type. */ + typedef TDeformationField DeformationFieldType; + typedef typename DeformationFieldType::Pointer DeformationFieldPointer; + + /** ImageDimension. */ + itkStaticConstMacro(ImageDimension, unsigned int, + FixedImageType::ImageDimension); + + /** Internal float image type. */ + typedef itk::Image FloatImageType; + + /** The internal registration type. */ + typedef itk::PDEDeformableRegistrationFilter< + FloatImageType, FloatImageType, DeformationFieldType > RegistrationType; + typedef typename RegistrationType::Pointer RegistrationPointer; + + /** The default registration type. */ + typedef itk::DemonsRegistrationFilter< + FloatImageType, FloatImageType, DeformationFieldType > DefaultRegistrationType; + + /** The fixed multi-resolution image pyramid type. */ + typedef itk::MultiResolutionPyramidImageFilter< + FixedImageType, FloatImageType > FixedImagePyramidType; + typedef typename FixedImagePyramidType::Pointer FixedImagePyramidPointer; + + /** The moving multi-resolution image pyramid type. */ +typedef itk::MultiResolutionPyramidImageFilter< + MovingImageType, FloatImageType > MovingImagePyramidType; + typedef typename MovingImagePyramidType::Pointer MovingImagePyramidPointer; + + /** The deformation field expander type. */ +typedef itk::VectorResampleImageFilter< + DeformationFieldType, DeformationFieldType > FieldExpanderType; + typedef typename FieldExpanderType::Pointer FieldExpanderPointer; + + /** Set the fixed image. */ + virtual void SetFixedImage( const FixedImageType * ptr ); + + /** Get the fixed image. */ + const FixedImageType * GetFixedImage(void) const; + + /** Set the moving image. */ + virtual void SetMovingImage( const MovingImageType * ptr ); + + /** Get the moving image. */ + const MovingImageType * GetMovingImage(void) const; + + /** Set initial deformation field to be used as is (no smoothing, no + * subsampling at the coarsest level of the pyramid. */ + virtual void SetInitialDeformationField( DeformationFieldType * ptr ) + { + this->m_InitialDeformationField=ptr; + } + + /** Set initial deformation field. No assumption is made on the + * input. It will therefore be smoothed and resampled to match the + * images characteristics at the coarsest level of the pyramid. */ + virtual void SetArbitraryInitialDeformationField( DeformationFieldType * ptr ) + { + this->SetInput( ptr ); + } + + /** Get output deformation field. */ + const DeformationFieldType * GetDeformationField(void) + { return this->GetOutput(); } + + /** Get the number of valid inputs. For + * MultiResolutionPDEDeformableRegistration, this checks whether the + * fixed and moving images have been set. While + * MultiResolutionPDEDeformableRegistration can take a third input + * as an initial deformation field, this input is not a required input. + */ + virtual std::vector >::size_type GetNumberOfValidRequiredInputs() const; + + /** Set the internal registrator. */ + itkSetObjectMacro( RegistrationFilter, RegistrationType ); + + /** Get the internal registrator. */ + itkGetObjectMacro( RegistrationFilter, RegistrationType ); + + /** Set the fixed image pyramid. */ + itkSetObjectMacro( FixedImagePyramid, FixedImagePyramidType ); + + /** Get the fixed image pyramid. */ + itkGetObjectMacro( FixedImagePyramid, FixedImagePyramidType ); + + /** Set the moving image pyramid. */ + itkSetObjectMacro( MovingImagePyramid, MovingImagePyramidType ); + + /** Get the moving image pyramid. */ + itkGetObjectMacro( MovingImagePyramid, MovingImagePyramidType ); + + /** Set number of multi-resolution levels. */ + virtual void SetNumberOfLevels( unsigned int num ); + + /** Get number of multi-resolution levels. */ + itkGetConstReferenceMacro( NumberOfLevels, unsigned int ); + + /** Get the current resolution level being processed. */ + itkGetConstReferenceMacro( CurrentLevel, unsigned int ); + + /** Set number of iterations per multi-resolution levels. */ + itkSetVectorMacro( NumberOfIterations, unsigned int, m_NumberOfLevels ); + + /** Set the moving image pyramid. */ + itkSetObjectMacro( FieldExpander, FieldExpanderType ); + + /** Get the moving image pyramid. */ + itkGetObjectMacro( FieldExpander, FieldExpanderType ); + + /** Get number of iterations per multi-resolution levels. */ + virtual const unsigned int * GetNumberOfIterations() const + { return &(m_NumberOfIterations[0]); } + + /** Stop the registration after the current iteration. */ + virtual void StopRegistration(); + +protected: + MultiResolutionPDEDeformableRegistration(); + ~MultiResolutionPDEDeformableRegistration() {} +void PrintSelf(std::ostream& os, itk::Indent indent) const; + + /** Generate output data by performing the registration + * at each resolution level. */ + virtual void GenerateData(); + + /** The current implementation of this class does not support + * streaming. As such it requires the largest possible region + * for the moving, fixed and input deformation field. */ + virtual void GenerateInputRequestedRegion(); + + /** By default, the output deformation field has the same + * spacing, origin and LargestPossibleRegion as the input/initial + * deformation field. + * + * If the initial deformation field is not set, the output + * information is copied from the fixed image. */ + virtual void GenerateOutputInformation(); + + /** The current implementation of this class does not supprot + * streaming. As such it produces the output for the largest + * possible region. */ + virtual void EnlargeOutputRequestedRegion( itk::DataObject *ptr ); + + /** This method returns true to indicate that the registration should + * terminate at the current resolution level. */ + virtual bool Halt(); + +private: + MultiResolutionPDEDeformableRegistration(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + RegistrationPointer m_RegistrationFilter; + FixedImagePyramidPointer m_FixedImagePyramid; + MovingImagePyramidPointer m_MovingImagePyramid; + FieldExpanderPointer m_FieldExpander; + DeformationFieldPointer m_InitialDeformationField; + + unsigned int m_NumberOfLevels; + unsigned int m_CurrentLevel; + std::vector m_NumberOfIterations; + + /** Flag to indicate user stop registration request. */ + bool m_StopRegistrationFlag; + +}; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkMultiResolutionPDEDeformableRegistration.txx" +#endif + + +#endif diff --git a/registration/clitkMultiResolutionPDEDeformableRegistration.txx b/registration/clitkMultiResolutionPDEDeformableRegistration.txx new file mode 100755 index 0000000..933f169 --- /dev/null +++ b/registration/clitkMultiResolutionPDEDeformableRegistration.txx @@ -0,0 +1,574 @@ +/*========================================================================= + 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 _clitkMultiResolutionPDEDeformableRegistration_txx +#define _clitkMultiResolutionPDEDeformableRegistration_txx +#include "clitkMultiResolutionPDEDeformableRegistration.h" + +#include "itkRecursiveMultiResolutionPyramidImageFilter.h" +#include "itkImageRegionIterator.h" +#include "vnl/vnl_math.h" + +namespace clitk { + +/* + * Default constructor + */ +template +MultiResolutionPDEDeformableRegistration +::MultiResolutionPDEDeformableRegistration() +{ + + this->SetNumberOfRequiredInputs(2); + + typename DefaultRegistrationType::Pointer registrator = + DefaultRegistrationType::New(); + m_RegistrationFilter = static_cast( + registrator.GetPointer() ); + + m_MovingImagePyramid = MovingImagePyramidType::New(); + m_FixedImagePyramid = FixedImagePyramidType::New(); + m_FieldExpander = FieldExpanderType::New(); + m_InitialDeformationField = NULL; + + m_NumberOfLevels = 3; + m_NumberOfIterations.resize( m_NumberOfLevels ); + m_FixedImagePyramid->SetNumberOfLevels( m_NumberOfLevels ); + m_MovingImagePyramid->SetNumberOfLevels( m_NumberOfLevels ); + + unsigned int ilevel; + for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ ) + { + m_NumberOfIterations[ilevel] = 10; + } + m_CurrentLevel = 0; + + m_StopRegistrationFlag = false; + +} + + +/* + * Set the moving image image. + */ +template +void +MultiResolutionPDEDeformableRegistration +::SetMovingImage( +const MovingImageType * ptr ) +{ + this->itk::ProcessObject::SetNthInput( 2, const_cast< MovingImageType * >( ptr ) ); +} + + +/* + * Get the moving image image. + */ +template +const typename MultiResolutionPDEDeformableRegistration +::MovingImageType * +MultiResolutionPDEDeformableRegistration +::GetMovingImage(void) const +{ + return dynamic_cast< const MovingImageType * > + ( this->itk::ProcessObject::GetInput( 2 ) ); +} + + +/* + * Set the fixed image. + */ +template +void +MultiResolutionPDEDeformableRegistration +::SetFixedImage( +const FixedImageType * ptr ) +{ + this->itk::ProcessObject::SetNthInput( 1, const_cast< FixedImageType * >( ptr ) ); +} + + +/* + * Get the fixed image. + */ +template +const typename MultiResolutionPDEDeformableRegistration +::FixedImageType * +MultiResolutionPDEDeformableRegistration +::GetFixedImage(void) const +{ + return dynamic_cast< const FixedImageType * > + ( this->itk::ProcessObject::GetInput( 1 ) ); +} + +/* + * + */ +template +std::vector >::size_type +MultiResolutionPDEDeformableRegistration +::GetNumberOfValidRequiredInputs() const +{ + typename std::vector >::size_type num = 0; + + if (this->GetFixedImage()) + { + num++; + } + + if (this->GetMovingImage()) + { + num++; + } + + return num; +} + + +/* + * Set the number of multi-resolution levels + */ +template +void +MultiResolutionPDEDeformableRegistration +::SetNumberOfLevels( +unsigned int num ) +{ + if( m_NumberOfLevels != num ) + { + this->Modified(); + m_NumberOfLevels = num; + m_NumberOfIterations.resize( m_NumberOfLevels ); + } + + if( m_MovingImagePyramid && m_MovingImagePyramid->GetNumberOfLevels() != num ) + { + m_MovingImagePyramid->SetNumberOfLevels( m_NumberOfLevels ); + } + if( m_FixedImagePyramid && m_FixedImagePyramid->GetNumberOfLevels() != num ) + { + m_FixedImagePyramid->SetNumberOfLevels( m_NumberOfLevels ); + } +} + + +/* + * Standard PrintSelf method. + */ +template +void +MultiResolutionPDEDeformableRegistration +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os, indent); + os << indent << "NumberOfLevels: " << m_NumberOfLevels << std::endl; + os << indent << "CurrentLevel: " << m_CurrentLevel << std::endl; + + os << indent << "NumberOfIterations: ["; + unsigned int ilevel; + for( ilevel = 0; ilevel < m_NumberOfLevels - 1; ilevel++ ) + { + os << m_NumberOfIterations[ilevel] << ", "; + } + os << m_NumberOfIterations[ilevel] << "]" << std::endl; + + os << indent << "RegistrationFilter: "; + os << m_RegistrationFilter.GetPointer() << std::endl; + os << indent << "MovingImagePyramid: "; + os << m_MovingImagePyramid.GetPointer() << std::endl; + os << indent << "FixedImagePyramid: "; + os << m_FixedImagePyramid.GetPointer() << std::endl; + + os << indent << "FieldExpander: "; + os << m_FieldExpander.GetPointer() << std::endl; + + os << indent << "StopRegistrationFlag: "; + os << m_StopRegistrationFlag << std::endl; + +} + +/* + * Perform a the deformable registration using a multiresolution scheme + * using an internal mini-pipeline + * + * ref_pyramid -> registrator -> field_expander --|| tempField + * test_pyramid -> | | + * | | + * -------------------------------- + * + * A tempField image is used to break the cycle between the + * registrator and field_expander. + * + */ +template +void +MultiResolutionPDEDeformableRegistration +::GenerateData() +{ + // Check for NULL images and pointers + MovingImageConstPointer movingImage = this->GetMovingImage(); + FixedImageConstPointer fixedImage = this->GetFixedImage(); + + if( !movingImage || !fixedImage ) + { + itkExceptionMacro( << "Fixed and/or moving image not set" ); + } + + if( !m_MovingImagePyramid || !m_FixedImagePyramid ) + { + itkExceptionMacro( << "Fixed and/or moving pyramid not set" ); + } + + if( !m_RegistrationFilter ) + { + itkExceptionMacro( << "Registration filter not set" ); + } + + if( this->m_InitialDeformationField && this->GetInput(0) ) + { + itkExceptionMacro( << "Only one initial deformation can be given. " + << "SetInitialDeformationField should not be used in " + << "cunjunction with SetArbitraryInitialDeformationField " + << "or SetInput."); + } + + //Update the number of levels for the pyramids + this->SetNumberOfLevels(m_NumberOfLevels); + + // Create the image pyramids. + m_MovingImagePyramid->SetInput( movingImage ); + m_MovingImagePyramid->UpdateLargestPossibleRegion(); + + m_FixedImagePyramid->SetInput( fixedImage ); + m_FixedImagePyramid->UpdateLargestPossibleRegion(); + + // Initializations + m_CurrentLevel = 0; + m_StopRegistrationFlag = false; + + unsigned int movingLevel = vnl_math_min( (int) m_CurrentLevel, + (int) m_MovingImagePyramid->GetNumberOfLevels() ); + + unsigned int fixedLevel = vnl_math_min( (int) m_CurrentLevel, + (int) m_FixedImagePyramid->GetNumberOfLevels() ); + + DeformationFieldPointer tempField = NULL; + + DeformationFieldPointer inputPtr = + const_cast< DeformationFieldType * >( this->GetInput(0) ); + + if ( this->m_InitialDeformationField ) + { + tempField = this->m_InitialDeformationField; + } + else if( inputPtr ) + { + // Arbitrary initial deformation field is set. + // smooth it and resample + + // First smooth it + tempField = inputPtr; + + typedef itk::RecursiveGaussianImageFilter< DeformationFieldType, + DeformationFieldType> GaussianFilterType; + typename GaussianFilterType::Pointer smoother + = GaussianFilterType::New(); + + for (unsigned int dim=0; dim( + m_FixedImagePyramid->GetSchedule()[fixedLevel][dim] ); + + // but also for a possible discrepancy in the spacing + sigma *= fixedImage->GetSpacing()[dim] + / inputPtr->GetSpacing()[dim]; + + smoother->SetInput( tempField ); + smoother->SetSigma( sigma ); + smoother->SetDirection( dim ); + + smoother->Update(); + + tempField = smoother->GetOutput(); + tempField->DisconnectPipeline(); + } + + + // Now resample + m_FieldExpander->SetInput( tempField ); + + typename FloatImageType::Pointer fi = + m_FixedImagePyramid->GetOutput( fixedLevel ); + m_FieldExpander->SetSize( + fi->GetLargestPossibleRegion().GetSize() ); + m_FieldExpander->SetOutputStartIndex( + fi->GetLargestPossibleRegion().GetIndex() ); + m_FieldExpander->SetOutputOrigin( fi->GetOrigin() ); + m_FieldExpander->SetOutputSpacing( fi->GetSpacing()); + m_FieldExpander->SetOutputDirection( fi->GetDirection()); + + m_FieldExpander->UpdateLargestPossibleRegion(); + m_FieldExpander->SetInput( NULL ); + tempField = m_FieldExpander->GetOutput(); + tempField->DisconnectPipeline(); + } + + + bool lastShrinkFactorsAllOnes = false; + while ( !this->Halt() ) + { + + if( tempField.IsNull() ) + { + m_RegistrationFilter->SetInitialDeformationField( NULL ); + } + else + { + // Resample the field to be the same size as the fixed image + // at the current level + m_FieldExpander->SetInput( tempField ); + + typename FloatImageType::Pointer fi = + m_FixedImagePyramid->GetOutput( fixedLevel ); + m_FieldExpander->SetSize( + fi->GetLargestPossibleRegion().GetSize() ); + m_FieldExpander->SetOutputStartIndex( + fi->GetLargestPossibleRegion().GetIndex() ); + m_FieldExpander->SetOutputOrigin( fi->GetOrigin() ); + m_FieldExpander->SetOutputSpacing( fi->GetSpacing()); + + m_FieldExpander->UpdateLargestPossibleRegion(); + m_FieldExpander->SetInput( NULL ); + tempField = m_FieldExpander->GetOutput(); + tempField->DisconnectPipeline(); + + m_RegistrationFilter->SetInitialDeformationField( tempField ); + + } + + // setup registration filter and pyramids + m_RegistrationFilter->SetMovingImage( m_MovingImagePyramid->GetOutput(movingLevel) ); + m_RegistrationFilter->SetFixedImage( m_FixedImagePyramid->GetOutput(fixedLevel) ); + m_RegistrationFilter->SetNumberOfIterations( + m_NumberOfIterations[m_CurrentLevel] ); + + // cache shrink factors for computing the next expand factors. + lastShrinkFactorsAllOnes = true; + for( unsigned int idim = 0; idim < ImageDimension; idim++ ) + { + if ( m_FixedImagePyramid->GetSchedule()[fixedLevel][idim] > 1 ) + { + lastShrinkFactorsAllOnes = false; + break; + } + } + + // Invoke an iteration event. + this->InvokeEvent( itk::IterationEvent() ); + + // compute new deformation field + m_RegistrationFilter->UpdateLargestPossibleRegion(); + tempField = m_RegistrationFilter->GetOutput(); + tempField->DisconnectPipeline(); + + // Increment level counter. + m_CurrentLevel++; + movingLevel = vnl_math_min( (int) m_CurrentLevel, + (int) m_MovingImagePyramid->GetNumberOfLevels() ); + fixedLevel = vnl_math_min( (int) m_CurrentLevel, + (int) m_FixedImagePyramid->GetNumberOfLevels() ); + + // We can release data from pyramid which are no longer required. + if ( movingLevel > 0 ) + { + m_MovingImagePyramid->GetOutput( movingLevel - 1 )->ReleaseData(); + } + if( fixedLevel > 0 ) + { + m_FixedImagePyramid->GetOutput( fixedLevel - 1 )->ReleaseData(); + } + + } // while not Halt() + + if( !lastShrinkFactorsAllOnes ) + { + // Some of the last shrink factors are not one + // graft the output of the expander filter to + // to output of this filter + + // resample the field to the same size as the fixed image + m_FieldExpander->SetInput( tempField ); + m_FieldExpander->SetSize( + fixedImage->GetLargestPossibleRegion().GetSize() ); + m_FieldExpander->SetOutputStartIndex( + fixedImage->GetLargestPossibleRegion().GetIndex() ); + m_FieldExpander->SetOutputOrigin( fixedImage->GetOrigin() ); + m_FieldExpander->SetOutputSpacing( fixedImage->GetSpacing()); + m_FieldExpander->UpdateLargestPossibleRegion(); + this->GraftOutput( m_FieldExpander->GetOutput() ); + } + else + { + // all the last shrink factors are all ones + // graft the output of registration filter to + // to output of this filter + this->GraftOutput( tempField ); + } + + // Release memory + m_FieldExpander->SetInput( NULL ); + m_FieldExpander->GetOutput()->ReleaseData(); + m_RegistrationFilter->SetInput( NULL ); + m_RegistrationFilter->GetOutput()->ReleaseData(); + +} + + +template +void +MultiResolutionPDEDeformableRegistration +::StopRegistration() +{ + m_RegistrationFilter->StopRegistration(); + m_StopRegistrationFlag = true; +} + +template +bool +MultiResolutionPDEDeformableRegistration +::Halt() +{ + // Halt the registration after the user-specified number of levels + if (m_NumberOfLevels != 0) + { + this->UpdateProgress( static_cast( m_CurrentLevel ) / + static_cast( m_NumberOfLevels ) ); + } + + if ( m_CurrentLevel >= m_NumberOfLevels ) + { + return true; + } + if ( m_StopRegistrationFlag ) + { + return true; + } + else + { + return false; + } + +} + + +template +void +MultiResolutionPDEDeformableRegistration +::GenerateOutputInformation() +{ + + typename itk::DataObject::Pointer output; + + if( this->GetInput(0) ) + { + // Initial deformation field is set. + // Copy information from initial field. + this->Superclass::GenerateOutputInformation(); + + } + else if( this->GetFixedImage() ) + { + // Initial deforamtion field is not set. + // Copy information from the fixed image. + for (unsigned int idx = 0; idx < + this->GetNumberOfOutputs(); ++idx ) + { + output = this->GetOutput(idx); + if (output) + { + output->CopyInformation(this->GetFixedImage()); + } + } + + } + +} + + +template +void +MultiResolutionPDEDeformableRegistration +::GenerateInputRequestedRegion() +{ + + // call the superclass's implementation + Superclass::GenerateInputRequestedRegion(); + + // request the largest possible region for the moving image + MovingImagePointer movingPtr = + const_cast< MovingImageType * >( this->GetMovingImage() ); + if( movingPtr ) + { + movingPtr->SetRequestedRegionToLargestPossibleRegion(); + } + + // just propagate up the output requested region for + // the fixed image and initial deformation field. + DeformationFieldPointer inputPtr = + const_cast< DeformationFieldType * >( this->GetInput() ); + DeformationFieldPointer outputPtr = this->GetOutput(); + FixedImagePointer fixedPtr = + const_cast< FixedImageType *>( this->GetFixedImage() ); + + if( inputPtr ) + { + inputPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() ); + } + + if( fixedPtr ) + { + fixedPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() ); + } + +} + + +template +void +MultiResolutionPDEDeformableRegistration +::EnlargeOutputRequestedRegion( + itk::DataObject * ptr ) +{ + // call the superclass's implementation + Superclass::EnlargeOutputRequestedRegion( ptr ); + + // set the output requested region to largest possible. + DeformationFieldType * outputPtr; + outputPtr = dynamic_cast( ptr ); + + if( outputPtr ) + { + outputPtr->SetRequestedRegionToLargestPossibleRegion(); + } + +} + + +} // end namespace itk + +#endif diff --git a/registration/clitkMultiResolutionPyramid.cxx b/registration/clitkMultiResolutionPyramid.cxx new file mode 100644 index 0000000..e4480ee --- /dev/null +++ b/registration/clitkMultiResolutionPyramid.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkMultiResolutionPyramid.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkMultiResolutionPyramid_ggo.h" +#include "clitkIO.h" +#include "clitkMultiResolutionPyramidGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkMultiResolutionPyramid, args_info); + CLITK_INIT; + + // Filter + clitk::MultiResolutionPyramidGenericFilter::Pointer genericFilter=clitk::MultiResolutionPyramidGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkMultiResolutionPyramid.ggo b/registration/clitkMultiResolutionPyramid.ggo new file mode 100644 index 0000000..91f13bf --- /dev/null +++ b/registration/clitkMultiResolutionPyramid.ggo @@ -0,0 +1,18 @@ +#File clitkMultiResolutionPyramid.ggo +Package "clitkMultiResolutionPyramid" +version "1.0" +purpose "Compute the multi-resolution (MR) image pyramid. The conventional filter will also modify the image at the original resolution, the recursive not. The spatio-temporal filters leave the last dimension untouched." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +section "IO" +option "input" i "Input image filename" string yes +option "output" o "Output image (level) filenames" string yes multiple + +section "Pyramid" +option "type" t "0=MR, 1= recursive MR, 2=spatio-temporal MR, 3 recursive spatio-temporal MR" int no default="0" +option "levels" l "Number of resolution levels" int no default="2" + + + diff --git a/registration/clitkMultiResolutionPyramidGenericFilter.cxx b/registration/clitkMultiResolutionPyramidGenericFilter.cxx new file mode 100644 index 0000000..d7038e0 --- /dev/null +++ b/registration/clitkMultiResolutionPyramidGenericFilter.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + 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 clitkMultiResolutionPyramidGenericFilter_cxx +#define clitkMultiResolutionPyramidGenericFilter_cxx + +/* ================================================= + * @file clitkMultiResolutionPyramidGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkMultiResolutionPyramidGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + MultiResolutionPyramidGenericFilter::MultiResolutionPyramidGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void MultiResolutionPyramidGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2,3 or 4 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( MultiResolutionPyramidGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkMultiResolutionPyramid & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + MultiResolutionPyramidGenericFilter(); + ~MultiResolutionPyramidGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkMultiResolutionPyramid m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkMultiResolutionPyramidGenericFilter.txx" +#endif + +#endif // #define clitkMultiResolutionPyramidGenericFilter_h diff --git a/registration/clitkMultiResolutionPyramidGenericFilter.txx b/registration/clitkMultiResolutionPyramidGenericFilter.txx new file mode 100644 index 0000000..11b7ad5 --- /dev/null +++ b/registration/clitkMultiResolutionPyramidGenericFilter.txx @@ -0,0 +1,162 @@ +/*========================================================================= + 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 clitkMultiResolutionPyramidGenericFilter_txx +#define clitkMultiResolutionPyramidGenericFilter_txx + +/* ================================================= + * @file clitkMultiResolutionPyramidGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + MultiResolutionPyramidGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithDimAndPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + void + MultiResolutionPyramidGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + // Filter + typedef itk::ImageToImageFilter FilterType; + typename FilterType::Pointer filter; + switch(m_ArgsInfo.type_arg) + { + case 0: + { + typedef itk::MultiResolutionPyramidImageFilter MRFilterType; + typename MRFilterType::Pointer rmFilter =MRFilterType::New(); + if (m_Verbose) std::cout<<"Using the multi-resolution filter..."<SetNumberOfLevels(m_ArgsInfo.levels_arg); + filter=rmFilter; + break; + } + case 1: + { + typedef itk::RecursiveMultiResolutionPyramidImageFilter RecursiveFilterType; + typename RecursiveFilterType::Pointer rFilter=RecursiveFilterType::New(); + if (m_Verbose) std::cout<<"Using the recursive multi-resolution filter..."<SetNumberOfLevels(m_ArgsInfo.levels_arg); + rFilter->SetUseShrinkImageFilter(false); + filter=rFilter; + break; + } + case 2: + { + typedef clitk::SpatioTemporalMultiResolutionPyramidImageFilter SpatioTemporalFilterType; + typename SpatioTemporalFilterType::Pointer spFilter=SpatioTemporalFilterType::New(); + if (m_Verbose) std::cout<<"Using the spatio-temporal multi-resolution filter..."<SetNumberOfLevels(m_ArgsInfo.levels_arg); + filter=spFilter; + break; + } + case 3: + { + typedef clitk::RecursiveSpatioTemporalMultiResolutionPyramidImageFilter RecursiveSpatioTemporalFilterType; + typename RecursiveSpatioTemporalFilterType::Pointer rspFilter=RecursiveSpatioTemporalFilterType::New(); + if (m_Verbose) std::cout<<"Using the recursive spatio-temporal multi-resolution filter..."<SetNumberOfLevels(m_ArgsInfo.levels_arg); + rspFilter->SetUseShrinkImageFilter(false); + filter=rspFilter; + break; + } + } + + // Common + filter->SetInput(input); + try + { + filter->Update(); + } + catch (itk::ExceptionObject) + { + std::cerr<<"Exception thrown during update() of the multi-resolution pyramid filter!"<GetOutput(i); + + // Write + writeImage(output,m_ArgsInfo.output_arg[i], m_Verbose); +// typedef itk::ImageFileWriter WriterType; +// typename WriterType::Pointer writer = WriterType::New(); +// writer->SetFileName(m_ArgsInfo.output_arg[i]); +// writer->SetInput(output); +// writer->Update(); + } + } + + +}//end clitk + +#endif //#define clitkMultiResolutionPyramidGenericFilter_txx diff --git a/registration/clitkMultiResolutionPyramidRegionFilter.h b/registration/clitkMultiResolutionPyramidRegionFilter.h new file mode 100644 index 0000000..1d43cfe --- /dev/null +++ b/registration/clitkMultiResolutionPyramidRegionFilter.h @@ -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 clitkMultiResolutionPyramidRegionFilter_h +#define clitkMultiResolutionPyramidRegionFilter_h + +/* ================================================= + * @file clitkMultiResolutionPyramidRegionFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" + +//itk include +#include "itkLightObject.h" + +namespace clitk +{ + + template + class ITK_EXPORT MultiResolutionPyramidRegionFilter : + public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef MultiResolutionPyramidRegionFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( MultiResolutionPyramidRegionFilter, LightObject ); + + /** Dimension of the domain space. */ + itkStaticConstMacro(InputImageDimension, unsigned int, InputImageType::ImageDimension); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + typedef itk::ImageRegion RegionType; + typedef itk::Array2D ScheduleType; + typedef typename InputImageType::SizeType SizeType; + typedef typename InputImageType::IndexType IndexType; + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetRegion(RegionType r){m_Region=r;} + void SetSchedule(ScheduleType r){m_Schedule=r;} + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(void); + RegionType GetOutput(unsigned int i) + { + this->Update(); + return m_RegionPyramid[i]; + } + + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + MultiResolutionPyramidRegionFilter(); + ~MultiResolutionPyramidRegionFilter() {}; + + //---------------------------------------- + // Data members + //---------------------------------------- + RegionType m_Region; + std::vector m_RegionPyramid; + ScheduleType m_Schedule; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkMultiResolutionPyramidRegionFilter.txx" +#endif + +#endif // #define clitkMultiResolutionPyramidRegionFilter_h + + diff --git a/registration/clitkMultiResolutionPyramidRegionFilter.txx b/registration/clitkMultiResolutionPyramidRegionFilter.txx new file mode 100644 index 0000000..bed3a50 --- /dev/null +++ b/registration/clitkMultiResolutionPyramidRegionFilter.txx @@ -0,0 +1,88 @@ +/*========================================================================= + 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 clitkMultiResolutionPyramidRegionFilter_txx +#define clitkMultiResolutionPyramidRegionFilter_txx + +/* ================================================= + * @file clitkMultiResolutionPyramidRegionFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + MultiResolutionPyramidRegionFilter::MultiResolutionPyramidRegionFilter() + { + ; + } + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + void + MultiResolutionPyramidRegionFilter::Update() + { + + // Compute the FixedImageRegion corresponding to each level of the + // pyramid. This uses the same algorithm of the ShrinkImageFilter + // since the regions should be compatible. + unsigned int numberOfLevels=m_Schedule.rows(); + m_RegionPyramid.reserve( numberOfLevels ); + m_RegionPyramid.resize( numberOfLevels ); + SizeType inputSize =m_Region.GetSize(); + IndexType inputStart =m_Region.GetIndex(); + + for ( unsigned int level=0; level < numberOfLevels; level++ ) + { + + SizeType size; + IndexType start; + for ( unsigned int dim = 0; dim < InputImageDimension; dim++) + { + const float scaleFactor = static_cast( m_Schedule[ level ][ dim ] ); + + size[ dim ] = static_cast( + vcl_floor(static_cast( inputSize[ dim ] ) / scaleFactor ) ); + if( size[ dim ] < 1 ) + { + size[ dim ] = 1; + } + + start[ dim ] = static_cast( + vcl_ceil(static_cast( inputStart[ dim ] ) / scaleFactor ) ); + } + m_RegionPyramid[ level ].SetSize( size ); + m_RegionPyramid[ level ].SetIndex( start ); + } + } + + +}//end clitk + +#endif //#define clitkMultiResolutionPyramidRegionFilter_txx diff --git a/registration/clitkPointListReader.h b/registration/clitkPointListReader.h new file mode 100644 index 0000000..be3b9ad --- /dev/null +++ b/registration/clitkPointListReader.h @@ -0,0 +1,71 @@ +/*========================================================================= + 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 __clitkPointListReader_h +#define __clitkPointListReader_h +#include "clitkPointListReader.h" + +namespace clitk +{ + + + template + class ITK_EXPORT PointListReader : + public itk::LightObject + { + public: + //------------------------------------ + // Standard itk typedefs + //----------------------------------- + typedef PointListReader Self; + typedef LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(PointListReader, PointListReader); + + // Typedefs + typedef itk::Point PointType; + typedef std::vector PointListType; + typedef std::vector< PointListType> PointListsType; + + void SetVerbose(bool a){m_Verbose=a;} + PointListType Read(const std::string &); + PointListsType Read(char**, const unsigned int &); + + + protected: + + // Constructor & Destructor + PointListReader(); + ~PointListReader(){}; + + bool m_Verbose; + + }; + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkPointListReader.txx" +#endif + +#endif diff --git a/registration/clitkPointListReader.txx b/registration/clitkPointListReader.txx new file mode 100644 index 0000000..c50927a --- /dev/null +++ b/registration/clitkPointListReader.txx @@ -0,0 +1,75 @@ +/*========================================================================= + 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 __clitkPointListReader_txx +#define __clitkPointListReader_txx +#include "clitkPointListReader.h" + +namespace clitk +{ + + template + PointListReader< Dimension > + ::PointListReader() + { + m_Verbose=false; + } + + template + typename PointListReader< Dimension >::PointListType + PointListReader< Dimension > + ::Read(const std::string& filename) + { + std::ifstream is; + openFileForReading(is, filename); + PointListType list; + PointType point; + double x; + + if(m_Verbose)std::cout<<"Reading "<> x; + point[dim]=x; + } + while (!is.eof()) + { + list.push_back(point); + for (unsigned int dim=0; dim> x; + point[dim]=x; + } + } + return list; + } + + template + typename PointListReader< Dimension >::PointListsType + PointListReader< Dimension > + ::Read(char** filename, const unsigned int& n) + { + PointListsType lists; + for (unsigned int number=0; number + class ITK_EXPORT PointListTransform : public itk::Transform< TScalarType, NDimensions, NOutputDimensions > + { + public: + /** Standard class typedefs. */ + typedef PointListTransform Self; + typedef itk::Transform< TScalarType, NDimensions, NOutputDimensions > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** New macro for creation of through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( PointListTransform, Transform ); + + /** Dimension of the domain space. */ + itkStaticConstMacro(SpaceDimension, unsigned int, NDimensions-1); + itkStaticConstMacro(ImageDimension, unsigned int, NDimensions); + + // typedef + typedef itk::Point SpacePointType; + typedef itk::Point SpaceTimePointType; + typedef clitk::List PointListType; + typedef clitk::Lists PointListsType; + typedef itk::Vector PointListImagePixelType; + typedef itk::Image PointListImageType; + typedef itk::VectorInterpolateImageFunction InterpolatorType; + + void SetPointList (PointListType p){m_PointList=p;} + void SetPointLists (PointListsType p){m_PointLists=p;} + void SetInterpolator (typename InterpolatorType::Pointer i){ m_Interpolator=i;} + + /** Standard coordinate point type for this class. */ + typedef itk::Point InputPointType; + typedef itk::Point OutputPointType; + + + PointListType GetCorrespondingPointList(const InputPointType &inputPoint) const; + OutputPointType TransformPoint(const InputPointType &point ) const; + + protected: + PointListTransform(); + ~PointListTransform(){;} + + private: + PointListTransform(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + PointListsType m_PointLists; + mutable PointListType m_PointList; + typename InterpolatorType::Pointer m_Interpolator; + + + }; //class PointListTransform + + + +} // namespace itk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkPointListTransform.txx" +#endif + +#endif /* __clitkPointListTransform_h */ diff --git a/registration/clitkPointListTransform.txx b/registration/clitkPointListTransform.txx new file mode 100644 index 0000000..ef4a08e --- /dev/null +++ b/registration/clitkPointListTransform.txx @@ -0,0 +1,146 @@ +/*========================================================================= + 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 __clitkPointListTransform_txx +#define __clitkPointListTransform_txx +#include "clitkPointListTransform.h" + + +namespace clitk +{ + + // Constructor + template + PointListTransform + ::PointListTransform():Superclass(NOutputDimensions,1) + { + m_PointLists.resize(0); + m_PointList.resize(1); + } + + // Find the point list in the lists + template + typename PointListTransform::PointListType + PointListTransform:: + GetCorrespondingPointList(const InputPointType &inputPoint) const + { + SpacePointType point; + for(unsigned int j=0; j< SpaceDimension;j++) + point[j]=inputPoint[j]; + + if(m_PointList[0]==point) return m_PointList; + else + { + for (unsigned int i=0; i< m_PointLists.size();i++) + if(m_PointLists[i][0]==point) return m_PointLists[i]; + } + + itkExceptionMacro(<<"Point List not found"); + } + + + // Transform a point + template + typename PointListTransform::OutputPointType + PointListTransform:: + TransformPoint(const InputPointType &inputPoint) const + { + + // ------------------------------- + // Get the corresponding point list + m_PointList = this->GetCorrespondingPointList(inputPoint); + + // ------------------------------- + // Create 1D vector image + typename PointListImageType::Pointer pointListImage=PointListImageType::New(); + typename PointListImageType::RegionType region; + region.SetSize(0,m_PointList.size()+6); + pointListImage->SetRegions(region); + pointListImage->Allocate(); + typename PointListImageType::SpacingType spacing; + spacing[0]=1; + pointListImage->SetSpacing(spacing); + typename PointListImageType::PointType origin; + origin[0]=-2.; + pointListImage->SetOrigin(origin); + + + // ------------------------------- + // Copy Point list to image + typedef itk::ImageRegionIterator IteratorType; + IteratorType it(pointListImage, pointListImage->GetLargestPossibleRegion()); + + // First points are the last + PointListImagePixelType pixel; + for (unsigned int j=0; j<2;j++) + { + for (unsigned int i=0; i SetInputImage(pointListImage); + + + // ------------------------------- + // Evaluate at phase value + typename PointListImageType::PointType t; + t[0]=inputPoint[ImageDimension-1]; + + // Inside valid region? + if ( (t[0] >= 0) && + (t[0] < m_PointList.size()) ) + { + pixel= m_Interpolator->Evaluate(t); + OutputPointType outputPoint; + for (unsigned int i=0; i < SpaceDimension; i++) + outputPoint[i]=pixel[i]; + outputPoint[ImageDimension-1]=t[0]; + return outputPoint; + } + // No displacement + else return inputPoint; + + } + + +} // namespace clitk + +#endif diff --git a/registration/clitkPointListWriter.h b/registration/clitkPointListWriter.h new file mode 100644 index 0000000..efe866c --- /dev/null +++ b/registration/clitkPointListWriter.h @@ -0,0 +1,78 @@ +/*========================================================================= + 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 __clitkPointListWriter_h +#define __clitkPointListWriter_h +#include "clitkPointListWriter.h" + +namespace clitk +{ + + + template + class ITK_EXPORT PointListWriter : + public itk::LightObject + { + public: + //------------------------------------ + // Standard itk typedefs + //----------------------------------- + typedef PointListWriter Self; + typedef LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(PointListWriter, LightObject); + + // Typedefs + typedef itk::Point PointType; + typedef std::vector PointListType; + typedef std::vector< PointListType> PointListsType; + typedef itk::Vector DisplacementType; + typedef std::vector DisplacementListType; + typedef std::vector< DisplacementListType> DisplacementListsType; + + // Members + void Write(const PointListType & , const std::string &); + void Write(const PointListsType & , char** ); + void Write(const PointListsType & , const std::string &){;}; + + void Write(const DisplacementListType & , const std::string &); + void Write(const DisplacementListsType & , char**); + void Write(const DisplacementListsType & , const std::string &){;}; + + + protected: + + // Constructor & Destructor+ + PointListWriter(); + ~PointListWriter(){}; + + + }; + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkPointListWriter.txx" +#endif + +#endif diff --git a/registration/clitkPointListWriter.txx b/registration/clitkPointListWriter.txx new file mode 100644 index 0000000..faefeed --- /dev/null +++ b/registration/clitkPointListWriter.txx @@ -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 __clitkPointListWriter_txx +#define __clitkPointListWriter_txx +#include "clitkPointListWriter.h" + +namespace clitk +{ + + template + PointListWriter< Dimension > + ::PointListWriter() + { + + } + + template + void + PointListWriter< Dimension > + ::Write(const PointListType& list, const std::string& filename ) + { + std::ofstream os; + openFileForWriting(os, filename); + + for (unsigned int pointIndex=0; pointIndex + void + PointListWriter< Dimension > + ::Write(const DisplacementListType& list, const std::string& filename ) + { + std::ofstream os; + openFileForWriting(os, filename); + + for (unsigned int pointIndex=0; pointIndex + void + PointListWriter< Dimension > + ::Write(const PointListsType& lists, char** filename) + { + for (unsigned int number =0; number + void + PointListWriter< Dimension > + ::Write(const DisplacementListsType& lists, char** filename) + { + for (unsigned int number =0; numberSetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkPointTrajectory.ggo b/registration/clitkPointTrajectory.ggo new file mode 100755 index 0000000..b95e0c3 --- /dev/null +++ b/registration/clitkPointTrajectory.ggo @@ -0,0 +1,26 @@ +#File clitkPointTrajectory.ggo +Package "clitkPointTrajectory" +version "1.0" +purpose "Compute the cyclic trajectory of a point based input transform. The transform can be given by N lists of (manually identified) landmarks, a 4DDVF or a ST transform. Interpolation is performed between " + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +section "IO" + +option "ref" r "Reference point list" string no +option "phaseIncrement" p "Phase step size for the trajectory [0,10)" double no default="0.1" +option "trajectory" o "Base filename for the trajectory files(+pointNumber) " string yes + + +section "Transform: either given n lists of points; a 4DVF or the coefficient image of a spatiotemporal transform" +option "transform" t "Transform type: 0=points, 1=4DVF, 2=coeff" int no default="0" +option "points" - "0:Lists of points" string no multiple +option "input" i "1,2: 4DVF or coeff image" string no +option "interpVF" - "0,1: Interpolation: 0=NN, 1=Linear, 2=BSpline, 3=BLUT" int no default="1" +option "interpVFOrder" - "0,1: Order if BLUT or BSpline (0-5)" int no default="3" +option "interpVFSF" - "0,1: Sampling factor if BLUT" int no default="20" +option "order" - "2: Spline order" int multiple no +option "mask" m "2: Mask image filename" string no +option "spacing" - "2: Spacing of the ref image for the sampling factor" double no default="2" +option "shape" - "2: Shape of the transform: 0=egg, 1=diamond" int no default="0" diff --git a/registration/clitkPointTrajectoryGenericFilter.cxx b/registration/clitkPointTrajectoryGenericFilter.cxx new file mode 100755 index 0000000..dba4c00 --- /dev/null +++ b/registration/clitkPointTrajectoryGenericFilter.cxx @@ -0,0 +1,380 @@ +/*========================================================================= + 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 clitkPointTrajectoryGenericFilter_cxx +#define clitkPointTrajectoryGenericFilter_cxx + +/* ================================================= + * @file clitkPointTrajectoryGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkPointTrajectoryGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + PointTrajectoryGenericFilter::PointTrajectoryGenericFilter() + { + m_Verbose=false; + // m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void PointTrajectoryGenericFilter::Update() + { + // ImageTypes + const unsigned int ImageDimension=4; + const unsigned int SpaceDimension=3; + typedef itk::Vector CoefficientPixelType; + typedef itk::Vector VectorPixelType; + typedef itk::Image CoefficientImageType; + typedef itk::Image VectorFieldType; + + + // ----------------------------------------------- + // Reference Point List 3D + // ----------------------------------------------- + typedef itk::Point SpacePointType; + typedef clitk::List PointListType; + PointListType referencePointList; + if (m_Verbose) std::cout<<"Reference point list:"< TransformType; + TransformType::Pointer transform; + switch (m_ArgsInfo.transform_arg) + { + // ========================== + // List of points + // ========================== + case 0: + { + //----------------------------- + // Input point lists + //----------------------------- + typedef itk::Point PointType; + typedef clitk::List PointListType; + typedef clitk::Lists PointListsType; + PointListsType inputPointLists, sortedPointLists; + + // Read the lists + for (unsigned int i=0; i PointListTransformType; + PointListTransformType::Pointer pointListTransform=PointListTransformType::New(); + pointListTransform->SetPointLists(sortedPointLists); + + // Vector Interpolator + typedef PointListTransformType::PointListImageType PointListImageType; + typedef clitk::GenericVectorInterpolator GenericVectorInterpolatorType; + GenericVectorInterpolatorType::Pointer genericInterpolator=GenericVectorInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + typedef itk::VectorInterpolateImageFunction InterpolatorType; + InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + pointListTransform->SetInterpolator(interpolator); + transform=pointListTransform; + + break; + } + + // ========================== + // 4D vector field + // ========================== + case 1: + { + // Deformation field transform + typedef clitk::DeformationFieldTransform DeformationFieldTransformType; + DeformationFieldTransformType::Pointer deformationFieldTransform=DeformationFieldTransformType::New(); + + // The deformation field + typedef DeformationFieldTransformType::DeformationFieldType DeformationFieldType; + typedef itk::ImageFileReader InputReaderType; + InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_ArgsInfo.input_arg); + reader->Update(); + DeformationFieldType::Pointer input= reader->GetOutput(); + deformationFieldTransform->SetDeformationField(input); + + // Vector Interpolator + typedef clitk::GenericVectorInterpolator GenericVectorInterpolatorType; + GenericVectorInterpolatorType::Pointer genericInterpolator=GenericVectorInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + typedef itk::VectorInterpolateImageFunction InterpolatorType; + InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + deformationFieldTransform->SetInterpolator(interpolator); + transform=deformationFieldTransform; + + break; + } + + // ========================== + // Spatio-Temporal transform + // ========================== + case 2: + { + // S-T transform + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransform< double, ImageDimension, ImageDimension > TransformType; + TransformType::Pointer spatioTemporalTransform = TransformType::New(); + + + // Spline orders: Default is cubic splines + CoefficientImageType::RegionType::SizeType splineOrders ; + splineOrders.Fill(3); + if (m_ArgsInfo.order_given) + for(unsigned int i=0; i InputReaderType; + InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_ArgsInfo.input_arg); + reader->Update(); + CoefficientImageType::Pointer input= reader->GetOutput(); + // itk::Vector vector; + // vector.Fill(0.); + // vector[2]=100; + // input->FillBuffer(vector); + + // Mask + typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; + MaskType::Pointer spatialObjectMask=NULL; + if (m_ArgsInfo.mask_given) + { + typedef itk::Image< unsigned char, ImageDimension > ImageMaskType; + typedef itk::ImageFileReader< ImageMaskType > MaskReaderType; + MaskReaderType::Pointer maskReader = MaskReaderType::New(); + maskReader->SetFileName(m_ArgsInfo.mask_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 <<"Mask was read..." <SetImage( maskReader->GetOutput() ); + } + + // Samplingfactors + CoefficientImageType::SizeType samplingFactors; + for (unsigned int i=0; i< ImageDimension-1; i++) + { + samplingFactors[i]= (int) ( input->GetSpacing()[i]/ m_ArgsInfo.spacing_arg); + if (m_Verbose) std::cout<<"Setting sampling factor "<GetSpacing()[ImageDimension-1]/ m_ArgsInfo.phaseIncrement_arg); + if (m_Verbose) std::cout<<"Setting sampling factor "<SetTransformShape(m_ArgsInfo.shape_arg); + spatioTemporalTransform->SetSplineOrders(splineOrders); + spatioTemporalTransform->SetMask(spatialObjectMask); + spatioTemporalTransform->SetLUTSamplingFactors(samplingFactors); + spatioTemporalTransform->SetCoefficientImage(input); + transform=spatioTemporalTransform; + + break; + } + +// // ========================== +// // Spatio-Temporal transform +// // ========================== +// case 3: +// { +// // S-T transform +// typedef clitk::BSplineSpatioTemporalDeformableTransform< double, ImageDimension, ImageDimension > TransformType; +// TransformType::Pointer spatioTemporalTransform = TransformType::New(); + + +// // Spline orders: Default is cubic splines +// CoefficientImageType::RegionType::SizeType splineOrders ; +// splineOrders.Fill(3); +// if (m_ArgsInfo.order_given) +// for(unsigned int i=0; i InputReaderType; +// InputReaderType::Pointer reader = InputReaderType::New(); +// reader->SetFileName( m_ArgsInfo.input_arg); +// reader->Update(); +// CoefficientImageType::Pointer input= reader->GetOutput(); +// // itk::Vector vector; +// // vector.Fill(0.); +// // vector[2]=100; +// // input->FillBuffer(vector); + +// // Mask +// typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; +// MaskType::Pointer spatialObjectMask=NULL; +// if (m_ArgsInfo.mask_given) +// { +// typedef itk::Image< unsigned char, ImageDimension > ImageMaskType; +// typedef itk::ImageFileReader< ImageMaskType > MaskReaderType; +// MaskReaderType::Pointer maskReader = MaskReaderType::New(); +// maskReader->SetFileName(m_ArgsInfo.mask_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 <<"Mask was read..." <SetImage( maskReader->GetOutput() ); +// } + +// // Samplingfactors +// CoefficientImageType::SizeType samplingFactors; +// for (unsigned int i=0; i< ImageDimension-1; i++) +// { +// samplingFactors[i]= (int) ( input->GetSpacing()[i]/ m_ArgsInfo.spacing_arg); +// if (m_Verbose) std::cout<<"Setting sampling factor "<GetSpacing()[ImageDimension-1]/ m_ArgsInfo.phaseIncrement_arg); +// if (m_Verbose) std::cout<<"Setting sampling factor "<SetTransformShape(m_ArgsInfo.shape_arg); +// spatioTemporalTransform->SetSplineOrders(splineOrders); +// spatioTemporalTransform->SetMask(spatialObjectMask); +// spatioTemporalTransform->SetLUTSamplingFactors(samplingFactors); +// spatioTemporalTransform->SetCoefficientImage(input); +// transform=spatioTemporalTransform; + +// break; +// } + } + + + // ----------------------------------------------- + // Construct Spatio-Temporal Point lists 4D + // ----------------------------------------------- + typedef itk::Point SpaceTimePointType; + typedef clitk::Lists PointListsType; + PointListsType pointLists(referencePointList.size()); + SpaceTimePointType spaceTimePoint; + double phase; + for (unsigned int i=0; i VectorType; + typedef clitk::List VectorListType; + typedef clitk::Lists VectorListsType; + VectorListsType displacementLists(pointLists.size()); + VectorType displacement; + for (unsigned int i=0; iTransformPoint(pointLists[i][j]); + if (m_Verbose) std::cout<<"Transformed point "< filenames; + for (unsigned int i=0;i Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( PointTrajectoryGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkPointTrajectory & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + PointTrajectoryGenericFilter(); + ~PointTrajectoryGenericFilter() {}; + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkPointTrajectory m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + + +#endif // #define clitkPointTrajectoryGenericFilter_h diff --git a/registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.h b/registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.h new file mode 100644 index 0000000..a43b2ed --- /dev/null +++ b/registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.h @@ -0,0 +1,94 @@ +/*========================================================================= + 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 __clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter_h +#define __clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter_h +#include "clitkSpatioTemporalMultiResolutionPyramidImageFilter.h" +#include "vnl/vnl_matrix.h" + +namespace clitk +{ + +template < + class TInputImage, + class TOutputImage + > +class ITK_EXPORT RecursiveSpatioTemporalMultiResolutionPyramidImageFilter : + public SpatioTemporalMultiResolutionPyramidImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef RecursiveSpatioTemporalMultiResolutionPyramidImageFilter Self; + typedef SpatioTemporalMultiResolutionPyramidImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(RecursiveSpatioTemporalMultiResolutionPyramidImageFilter, + SpatioTemporalMultiResolutionPyramidImageFilter); + + /** ImageDimension enumeration. */ + itkStaticConstMacro(ImageDimension, unsigned int, + Superclass::ImageDimension); + + /** Inherit types from the superclass.. */ + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename Superclass::InputImagePointer InputImagePointer; + typedef typename Superclass::OutputImagePointer OutputImagePointer; + typedef typename Superclass::InputImageConstPointer InputImageConstPointer; + + /** Given one output whose requested region has been set, + * this method sets the requtested region for the remaining + * output images. + * The original documentation of this method is below. + * \sa ProcessObject::GenerateOutputRequestedRegion(); */ + virtual void GenerateOutputRequestedRegion(itk::DataObject *output); + + /** RecursiveSpatioTemporalMultiResolutionPyramidImageFilter requires a larger input + * requested region than the output requested regions to accomdate the + * shrinkage and smoothing operations. As such, + * SpatioTemporalMultiResolutionPyramidImageFilter needs to provide an implementation for + * GenerateInputRequestedRegion(). The original documentation of this + * method is below. \sa ProcessObject::GenerateInputRequestedRegion() */ + virtual void GenerateInputRequestedRegion(); + +protected: + RecursiveSpatioTemporalMultiResolutionPyramidImageFilter(); + ~RecursiveSpatioTemporalMultiResolutionPyramidImageFilter() {}; + void PrintSelf(std::ostream&os, itk::Indent indent) const; + + /** Generate the output data. */ + void GenerateData(); + +private: + RecursiveSpatioTemporalMultiResolutionPyramidImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.txx" +#endif + +#endif diff --git a/registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.txx b/registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.txx new file mode 100644 index 0000000..b6c2abb --- /dev/null +++ b/registration/clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.txx @@ -0,0 +1,479 @@ +/*========================================================================= + 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 __clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter_txx +#define __clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter_txx +#include "clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.h" +#include "itkShrinkImageFilter.h" +#include "itkGaussianOperator.h" +#include "itkCastImageFilter.h" +#include "itkDiscreteGaussianImageFilter.h" +#include "itkExceptionObject.h" +#include "itkResampleImageFilter.h" +#include "itkShrinkImageFilter.h" +#include "itkIdentityTransform.h" + +#include "vnl/vnl_math.h" + +namespace clitk +{ + +/** + * Constructor + */ +template +RecursiveSpatioTemporalMultiResolutionPyramidImageFilter +::RecursiveSpatioTemporalMultiResolutionPyramidImageFilter() +{ + this->Superclass::m_UseShrinkImageFilter = true; +} + +/** + * GenerateData + */ +template +void +RecursiveSpatioTemporalMultiResolutionPyramidImageFilter +::GenerateData() +{ + + if( !this->IsScheduleDownwardDivisible( this->GetSchedule() ) ) + { + // use the Superclass implemenation + this->Superclass::GenerateData(); + return; + } + + // Get the input and output pointers + InputImageConstPointer inputPtr = this->GetInput(); + + // Create caster, smoother and resampleShrink filters + typedef itk::CastImageFilter CasterType; + typedef itk::CastImageFilter CopierType; + typedef itk::DiscreteGaussianImageFilter SmootherType; + + typedef itk::ImageToImageFilter ImageToImageType; + typedef itk::ResampleImageFilter ResampleShrinkerType; + typedef itk::ShrinkImageFilter ShrinkerType; + + typename CasterType::Pointer caster = CasterType::New(); + typename CopierType::Pointer copier = CopierType::New(); + typename SmootherType::Pointer smoother = SmootherType::New(); + + + typename ImageToImageType::Pointer shrinkerFilter; + // + // only one of these pointers is going to be valid, depending on the + // value of UseShrinkImageFilter flag + typename ResampleShrinkerType::Pointer resampleShrinker; + typename ShrinkerType::Pointer shrinker; + + if(this->GetUseShrinkImageFilter()) + { + shrinker = ShrinkerType::New(); + shrinkerFilter = shrinker.GetPointer(); + } + else + { + resampleShrinker = ResampleShrinkerType::New(); + typedef itk::LinearInterpolateImageFunction< OutputImageType, double > + LinearInterpolatorType; + typename LinearInterpolatorType::Pointer interpolator = + LinearInterpolatorType::New(); + typedef itk::IdentityTransform + IdentityTransformType; + typename IdentityTransformType::Pointer identityTransform = + IdentityTransformType::New(); + resampleShrinker->SetInterpolator( interpolator ); + resampleShrinker->SetDefaultPixelValue( 0 ); + resampleShrinker->SetTransform(identityTransform); + shrinkerFilter = resampleShrinker.GetPointer(); + } + + int ilevel; + unsigned int idim; + unsigned int factors[ImageDimension]; + double variance[ImageDimension]; + + bool allOnes; + OutputImagePointer outputPtr; + OutputImagePointer swapPtr; + typename TOutputImage::RegionType LPRegion; + + smoother->SetUseImageSpacing( false ); + smoother->SetMaximumError( this->GetMaximumError() ); + shrinkerFilter->SetInput( smoother->GetOutput() ); + + + // recursively compute outputs starting from the last one + for( ilevel = this->GetNumberOfLevels() - 1; ilevel > -1; ilevel--) + { + + this->UpdateProgress( 1.0 - static_cast( 1 + ilevel ) / + static_cast( this->GetNumberOfLevels() ) ); + + // Allocate memory for each output + outputPtr = this->GetOutput( ilevel ); + outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->Allocate(); + + // cached a copy of the largest possible region + LPRegion = outputPtr->GetLargestPossibleRegion(); + + // Check shrink factors and compute variances + allOnes = true; + for( idim = 0; idim < ImageDimension; idim++ ) + { + if( ilevel == static_cast(this->GetNumberOfLevels()) - 1) + { + factors[idim] = this->GetSchedule()[ilevel][idim]; + } + else + { + factors[idim] = this->GetSchedule()[ilevel][idim] / + this->GetSchedule()[ilevel+1][idim]; + } + variance[idim] = vnl_math_sqr( 0.5 * + static_cast( factors[idim] ) ); + if( factors[idim] != 1 ) + { + allOnes = false; + } + else + { + variance[idim] = 0.0; + } + } + + + if( allOnes && ilevel == static_cast(this->GetNumberOfLevels()) - 1 ) + { + // just copy the input over + caster->SetInput( inputPtr ); + caster->GraftOutput( outputPtr ); + // ensure only the requested region is updated + caster->UpdateOutputInformation(); + caster->GetOutput()->SetRequestedRegion(outputPtr->GetRequestedRegion()); + caster->GetOutput()->PropagateRequestedRegion(); + caster->GetOutput()->UpdateOutputData(); + + swapPtr = caster->GetOutput(); + + + } + else if( allOnes ) + { + // just copy the data over + copier->SetInput( swapPtr ); + copier->GraftOutput( outputPtr ); + // ensure only the requested region is updated + copier->GetOutput()->UpdateOutputInformation(); + copier->GetOutput()->SetRequestedRegion(outputPtr->GetRequestedRegion()); + copier->GetOutput()->PropagateRequestedRegion(); + copier->GetOutput()->UpdateOutputData(); + + swapPtr = copier->GetOutput(); + + } + else + { + if( ilevel == static_cast(this->GetNumberOfLevels()) - 1 ) + { + // use caster -> smoother -> shrinker piepline + caster->SetInput( inputPtr ); + smoother->SetInput( caster->GetOutput() ); + } + else + { + // use smoother -> shrinker pipeline + smoother->SetInput( swapPtr ); + } + + smoother->SetVariance( variance ); + + // shrinker->SetShrinkFactors( factors ); + // shrinker->GraftOutput( outputPtr ); + if(!this->GetUseShrinkImageFilter()) + { + resampleShrinker->SetOutputParametersFromImage(outputPtr); + } + else + { + shrinker->SetShrinkFactors(factors); + } + shrinkerFilter->GraftOutput(outputPtr); + shrinkerFilter->Modified(); + // ensure only the requested region is updated + shrinkerFilter->GetOutput()->UpdateOutputInformation(); + shrinkerFilter->GetOutput()->SetRequestedRegion(outputPtr->GetRequestedRegion()); + shrinkerFilter->GetOutput()->PropagateRequestedRegion(); + shrinkerFilter->GetOutput()->UpdateOutputData(); + + swapPtr = shrinkerFilter->GetOutput(); + + } + + // graft pipeline output back onto this filter's output + swapPtr->SetLargestPossibleRegion( LPRegion ); + this->GraftNthOutput( ilevel, swapPtr ); + + // disconnect from pipeline to stop cycle + swapPtr->DisconnectPipeline(); + + } + +} + +/** + * PrintSelf method + */ +template +void +RecursiveSpatioTemporalMultiResolutionPyramidImageFilter +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os,indent); +} + + +/* + * GenerateOutputRequestedRegion + */ +template +void +RecursiveSpatioTemporalMultiResolutionPyramidImageFilter +::GenerateOutputRequestedRegion(itk::DataObject * ptr ) +{ + + // call the superclass's implementation of this method + Superclass::GenerateOutputRequestedRegion( ptr ); + + TOutputImage * refOutputPtr = static_cast( ptr ); + if( !refOutputPtr ) + { + itkExceptionMacro( << "Could not cast ptr to TOutputImage*." ); + } + + // find the index for this output + unsigned int refLevel; + refLevel = refOutputPtr->GetSourceOutputIndex(); + + typedef typename TOutputImage::PixelType OutputPixelType; + typedef itk::GaussianOperator OperatorType; + + OperatorType * oper = new OperatorType; + oper->SetMaximumError( this->GetMaximumError() ); + + typedef typename OutputImageType::SizeType SizeType; + typedef typename SizeType::SizeValueType SizeValueType; + typedef typename OutputImageType::IndexType IndexType; + typedef typename IndexType::IndexValueType IndexValueType; + typedef typename OutputImageType::RegionType RegionType; + + int ilevel, idim; + unsigned int factors[ImageDimension]; + + typename TInputImage::SizeType radius; + + RegionType requestedRegion; + SizeType requestedSize; + IndexType requestedIndex; + + // compute requested regions for lower levels + for( ilevel = refLevel + 1; ilevel < static_cast(this->GetNumberOfLevels()); + ilevel++ ) + { + + requestedRegion = this->GetOutput( ilevel - 1 )->GetRequestedRegion(); + requestedSize = requestedRegion.GetSize(); + requestedIndex = requestedRegion.GetIndex(); + + for( idim = 0; idim < static_cast(ImageDimension); idim++ ) + { + factors[idim] = this->GetSchedule()[ilevel-1][idim] / this->GetSchedule()[ilevel][idim]; + + // take into account shrink component + requestedSize[idim] *= static_cast(factors[idim]); + requestedIndex[idim] *= static_cast(factors[idim]); + + // take into account smoothing component + if( factors[idim] > 1 ) + { + oper->SetDirection( idim ); + oper->SetVariance( vnl_math_sqr( 0.5 * + static_cast( factors[idim] ) ) ); + oper->CreateDirectional(); + radius[idim] = oper->GetRadius()[idim]; + } + else + { + radius[idim] = 0; + } + } + + requestedRegion.SetSize( requestedSize ); + requestedRegion.SetIndex( requestedIndex ); + requestedRegion.PadByRadius( radius ); + requestedRegion.Crop( this->GetOutput(ilevel)-> + GetLargestPossibleRegion() ); + + this->GetOutput(ilevel)->SetRequestedRegion( requestedRegion ); + + } + + + // compute requested regions for higher levels + for( ilevel = refLevel - 1; ilevel > -1; ilevel-- ) + { + requestedRegion = this->GetOutput( ilevel + 1 )->GetRequestedRegion(); + requestedSize = requestedRegion.GetSize(); + requestedIndex = requestedRegion.GetIndex(); + + for( idim = 0; idim < static_cast(ImageDimension); idim++ ) + { + + factors[idim] = this->GetSchedule()[ilevel][idim] / this->GetSchedule()[ilevel+1][idim]; + + // take into account smoothing component + if( factors[idim] > 1 ) + { + oper->SetDirection( idim ); + oper->SetVariance( vnl_math_sqr( 0.5 * + static_cast( factors[idim] ) ) ); + oper->CreateDirectional(); + radius[idim] = oper->GetRadius()[idim]; + } + else + { + radius[idim] = 0; + } + + requestedSize[idim] -= static_cast( + 2 * radius[idim] ); + requestedIndex[idim] += radius[idim]; + + // take into account shrink component + requestedSize[idim] = static_cast( vcl_floor( + static_cast(requestedSize[idim]) / + static_cast(factors[idim]) ) ); + if( requestedSize[idim] < 1 ) + { + requestedSize[idim] = 1; + } + requestedIndex[idim] = static_cast( vcl_ceil( + static_cast(requestedIndex[idim]) / + static_cast(factors[idim]) ) ); + + } + + requestedRegion.SetSize( requestedSize ); + requestedRegion.SetIndex( requestedIndex ); + requestedRegion.Crop( this->GetOutput(ilevel)-> + GetLargestPossibleRegion() ); + + this->GetOutput(ilevel)->SetRequestedRegion( requestedRegion ); + + } + + // clean up + delete oper; + +} + +/** + * GenerateInputRequestedRegion + */ +template +void +RecursiveSpatioTemporalMultiResolutionPyramidImageFilter +::GenerateInputRequestedRegion() +{ + + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the input and output + InputImagePointer inputPtr = + const_cast< InputImageType *>( this->GetInput() ); + if ( !inputPtr ) + { + itkExceptionMacro( << "Input has not been set." ); + } + + // compute baseIndex and baseSize + typedef typename OutputImageType::SizeType SizeType; + typedef typename SizeType::SizeValueType SizeValueType; + typedef typename OutputImageType::IndexType IndexType; + typedef typename IndexType::IndexValueType IndexValueType; + typedef typename OutputImageType::RegionType RegionType; + + unsigned int refLevel = this->GetNumberOfLevels() - 1; + SizeType baseSize = this->GetOutput(refLevel)->GetRequestedRegion().GetSize(); + IndexType baseIndex = this->GetOutput(refLevel)->GetRequestedRegion().GetIndex(); + RegionType baseRegion; + + unsigned int idim; + for( idim = 0; idim < ImageDimension; idim++ ) + { + unsigned int factor = this->GetSchedule()[refLevel][idim]; + baseIndex[idim] *= static_cast( factor ); + baseSize[idim] *= static_cast( factor ); + } + baseRegion.SetIndex( baseIndex ); + baseRegion.SetSize( baseSize ); + + // compute requirements for the smoothing part + typedef typename TOutputImage::PixelType OutputPixelType; + typedef itk::GaussianOperator OperatorType; + + OperatorType *oper = new OperatorType; + + typename TInputImage::SizeType radius; + + RegionType inputRequestedRegion = baseRegion; + refLevel = 0; + + for( idim = 0; idim < TInputImage::ImageDimension; idim++ ) + { + oper->SetDirection(idim); + oper->SetVariance( vnl_math_sqr( 0.5 * static_cast( + this->GetSchedule()[refLevel][idim] ) ) ); + oper->SetMaximumError( this->GetMaximumError() ); + oper->CreateDirectional(); + radius[idim] = oper->GetRadius()[idim]; + if( this->GetSchedule()[refLevel][idim] <= 1 ) + { + radius[idim] = 0; + } + + } + delete oper; + + inputRequestedRegion.PadByRadius( radius ); + + // make sure the requested region is within the largest possible + inputRequestedRegion.Crop( inputPtr->GetLargestPossibleRegion() ); + + // set the input requested region + inputPtr->SetRequestedRegion( inputRequestedRegion ); + +} + + +} // namespace clitk + +#endif diff --git a/registration/clitkResampleBSplineDeformableTransform.cxx b/registration/clitkResampleBSplineDeformableTransform.cxx new file mode 100644 index 0000000..68633af --- /dev/null +++ b/registration/clitkResampleBSplineDeformableTransform.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkResampleBSplineDeformableTransform.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkResampleBSplineDeformableTransform_ggo.h" +#include "clitkIO.h" +#include "clitkResampleBSplineDeformableTransformGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkResampleBSplineDeformableTransform, args_info); + CLITK_INIT; + + // Filter + clitk::ResampleBSplineDeformableTransformGenericFilter::Pointer genericFilter=clitk::ResampleBSplineDeformableTransformGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkResampleBSplineDeformableTransform.ggo b/registration/clitkResampleBSplineDeformableTransform.ggo new file mode 100644 index 0000000..0dc6054 --- /dev/null +++ b/registration/clitkResampleBSplineDeformableTransform.ggo @@ -0,0 +1,22 @@ +#File clitkResampleBSplineDeformableTransform.ggo +Package "clitkResampleBSplineDeformableTransform" +version "1.0" +purpose "Resample the B-spline control point grid to given properties. Coefficients are resampled to values with the desired properties and reconverted to coefficients " + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "like" - "Resample output like this image" string no + + +section "Output Image Properties" + +option "origin" - "Origin for the output image" double multiple no +option "size" - "Size for the output image" int multiple no +option "spacing" - "Spacing for the output image" double multiple no + + + + diff --git a/registration/clitkResampleBSplineDeformableTransformGenericFilter.cxx b/registration/clitkResampleBSplineDeformableTransformGenericFilter.cxx new file mode 100644 index 0000000..94c2411 --- /dev/null +++ b/registration/clitkResampleBSplineDeformableTransformGenericFilter.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + 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 clitkResampleBSplineDeformableTransformGenericFilter_cxx +#define clitkResampleBSplineDeformableTransformGenericFilter_cxx + +/* ================================================= + * @file clitkResampleBSplineDeformableTransformGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkResampleBSplineDeformableTransformGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + ResampleBSplineDeformableTransformGenericFilter::ResampleBSplineDeformableTransformGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void ResampleBSplineDeformableTransformGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension, Components; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType, Components); + else if(Dimension==3) UpdateWithDim<3>(PixelType, Components); + else if (Dimension==4)UpdateWithDim<4>(PixelType, Components); + else + { + std::cout<<"Error, Only for 2,3 or 4 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( ResampleBSplineDeformableTransformGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkResampleBSplineDeformableTransform & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + ResampleBSplineDeformableTransformGenericFilter(); + ~ResampleBSplineDeformableTransformGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType, int Components); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkResampleBSplineDeformableTransform m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkResampleBSplineDeformableTransformGenericFilter.txx" +#endif + +#endif // #define clitkResampleBSplineDeformableTransformGenericFilter_h diff --git a/registration/clitkResampleBSplineDeformableTransformGenericFilter.txx b/registration/clitkResampleBSplineDeformableTransformGenericFilter.txx new file mode 100644 index 0000000..7cf8e84 --- /dev/null +++ b/registration/clitkResampleBSplineDeformableTransformGenericFilter.txx @@ -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 clitkResampleBSplineDeformableTransformGenericFilter_txx +#define clitkResampleBSplineDeformableTransformGenericFilter_txx + +/* ================================================= + * @file clitkResampleBSplineDeformableTransformGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + void + ResampleBSplineDeformableTransformGenericFilter::UpdateWithDim(std::string PixelType, int Components) + { + if (m_Verbose) std::cout << "Image was detected to be "< >(); + } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and 2D float..." << std::endl; + UpdateWithDimAndPixelType >(); + } + } + else if (Components==3) + { + if(PixelType == "double"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and 3D double..." << std::endl; + UpdateWithDimAndPixelType >(); + } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and 3D float..." << std::endl; + UpdateWithDimAndPixelType >(); + } + } + else std::cerr<<"Number of components is "< + void + ResampleBSplineDeformableTransformGenericFilter::UpdateWithDimAndPixelType() + { + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + // Filter + typedef clitk::ResampleBSplineDeformableTransformImageFilter ResampleFilterType; + typename ResampleFilterType::Pointer filter=ResampleFilterType::New(); + filter->SetInput(input); + + // Output image info + if (m_ArgsInfo.like_given) + { + typename InputReaderType::Pointer likeReader=InputReaderType::New(); + likeReader->SetFileName(m_ArgsInfo.like_arg); + likeReader->Update(); + filter->SetOutputParametersFromImage(likeReader->GetOutput()); + } + else + { + // Size + typename OutputImageType::SizeType outputSize; + if (m_ArgsInfo.size_given) + { + for(unsigned int i=0; i< Dimension; i++) + outputSize[i]=m_ArgsInfo.size_arg[i]; + } + else outputSize=input->GetLargestPossibleRegion().GetSize(); + if (m_Verbose) std::cout<<"Setting the size to "<GetSpacing(); + if (m_Verbose) std::cout<<"Setting the spacing to "<GetOrigin(); + if (m_Verbose) std::cout<<"Setting the origin to "<SetSize( outputSize ); + filter->SetOutputSpacing( outputSpacing ); + filter->SetOutputOrigin( outputOrigin ); + + } + + // Go + filter->Update(); + + // Get the output + typename OutputImageType::Pointer output=filter->GetOutput(); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(output); + writer->Update(); + + } + + +}//end clitk + +#endif //#define clitkResampleBSplineDeformableTransformGenericFilter_txx diff --git a/registration/clitkResampleBSplineDeformableTransformImageFilter.h b/registration/clitkResampleBSplineDeformableTransformImageFilter.h new file mode 100644 index 0000000..96121be --- /dev/null +++ b/registration/clitkResampleBSplineDeformableTransformImageFilter.h @@ -0,0 +1,179 @@ +/*========================================================================= + 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 clitkResampleBSplineDeformableTransformImageFilter_h +#define clitkResampleBSplineDeformableTransformImageFilter_h + +/* ================================================= + * @file clitkResampleBSplineDeformableTransformImageFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkIO.h" +#include "clitkCommon.h" +#include "clitkVectorBSplineDecompositionImageFilterWithOBD.h" +#include "clitkVectorBSplineResampleImageFunction.h" + +//itk include +#include "itkImageToImageFilter.h" +#include "itkVectorResampleImageFilter.h" +#include "itkCastImageFilter.h" + + +namespace clitk +{ + + template + class ITK_EXPORT ResampleBSplineDeformableTransformImageFilter : + public itk::ImageToImageFilter + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef ResampleBSplineDeformableTransformImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( ResampleBSplineDeformableTransformImageFilter, ImageToImageFilter ); + + /** Dimension of the domain space. */ + itkStaticConstMacro(InputImageDimension, unsigned int, Superclass::InputImageDimension); + + //---------------------------------------- + // Typedefs + //---------------------------------------- + typedef typename InputImageType::PointType InputPointType; + typedef typename InputImageType::IndexType IndexType; + + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PointType OutputPointType; + typedef typename OutputImageType::SpacingType OutputSpacingType; + typedef typename OutputImageType::DirectionType OutputDirectionType; + typedef typename OutputImageType::IndexType OutputIndexType; + typedef typename OutputImageType::SizeType OutputSizeType; + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + itkBooleanMacro(Verbose); + itkSetMacro( Verbose, bool); + itkGetConstReferenceMacro( Verbose, bool); + + // Properties of the output + itkSetMacro( Size, OutputSizeType ); + itkGetConstReferenceMacro( Size, OutputSizeType ); + itkSetMacro(OutputSpacing, OutputSpacingType); + virtual void SetOutputSpacing( const double* values); + itkGetConstReferenceMacro( OutputSpacing, OutputSpacingType ); + itkSetMacro(OutputOrigin, OutputPointType); + virtual void SetOutputOrigin( const double* values); + itkGetConstReferenceMacro( OutputOrigin, OutputPointType ); + itkSetMacro(OutputDirection, OutputDirectionType); + itkGetConstReferenceMacro(OutputDirection, OutputDirectionType); + itkSetMacro( OutputStartIndex, OutputIndexType ); + itkGetConstReferenceMacro( OutputStartIndex, OutputIndexType ); + void SetOutputParametersFromImage ( typename OutputImageType::Pointer Image ) + { + this->SetOutputOrigin ( Image->GetOrigin() ); + this->SetOutputSpacing ( Image->GetSpacing() ); + this->SetOutputDirection ( Image->GetDirection() ); + this->SetSize ( Image->GetLargestPossibleRegion().GetSize() ); + this->SetOutputStartIndex(Image->GetLargestPossibleRegion().GetIndex()); + } + + void SetOutputParametersFromConstImage ( typename OutputImageType::ConstPointer Image ) + { + this->SetOutputOrigin ( Image->GetOrigin() ); + this->SetOutputSpacing ( Image->GetSpacing() ); + this->SetOutputDirection ( Image->GetDirection() ); + this->SetSize ( Image->GetLargestPossibleRegion().GetSize() ); + this->SetOutputStartIndex(Image->GetLargestPossibleRegion().GetIndex()); + } + + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + ResampleBSplineDeformableTransformImageFilter(); + ~ResampleBSplineDeformableTransformImageFilter() {}; + + //---------------------------------------- + // Update + //---------------------------------------- + // Generate Data + void GenerateData(void); + // // Threaded Generate Data + // void BeforeThreadedGenerateData(void ); + // void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, int threadId ); + // void AfterThreadedGenerateData(void ); + // // Override defaults + // virtual void GenerateInputRequestedRegion(); + // virtual void GenerateOutputInformation (void); + // virtual void EnlargeOutputRequestedRegion(DataObject *data); + void AllocateOutputs(){}; + + //---------------------------------------- + // Data members + //---------------------------------------- + bool m_Verbose; + OutputSizeType m_Size; // Size of the output image + OutputSpacingType m_OutputSpacing; // output image spacing + OutputPointType m_OutputOrigin; // output image origin + OutputDirectionType m_OutputDirection; // output image direction cosines + OutputIndexType m_OutputStartIndex; // output image start index + OutputSizeType m_SplineOrders; + + //---------------------------------------- + // Components + //---------------------------------------- + typedef itk::VectorResampleImageFilter ResamplerType; + typedef VectorBSplineResampleImageFunction FunctionType; + typedef itk::IdentityTransform IdentityTransformType; + typedef VectorBSplineDecompositionImageFilterWithOBD DecompositionType; + typename ResamplerType::Pointer m_Resampler; + typename FunctionType::Pointer m_Function; + typename IdentityTransformType::Pointer m_Identity; + typename DecompositionType::Pointer m_Decomposition; + + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkResampleBSplineDeformableTransformImageFilter.txx" +#endif + +#endif // #define clitkResampleBSplineDeformableTransformImageFilter_h + + diff --git a/registration/clitkResampleBSplineDeformableTransformImageFilter.txx b/registration/clitkResampleBSplineDeformableTransformImageFilter.txx new file mode 100644 index 0000000..60f7fc1 --- /dev/null +++ b/registration/clitkResampleBSplineDeformableTransformImageFilter.txx @@ -0,0 +1,138 @@ +/*========================================================================= + 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 clitkResampleBSplineDeformableTransformImageFilter_txx +#define clitkResampleBSplineDeformableTransformImageFilter_txx + +/* ================================================= + * @file clitkResampleBSplineDeformableTransformImageFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the number of dimensions + //------------------------------------------------------------------- + template + ResampleBSplineDeformableTransformImageFilter::ResampleBSplineDeformableTransformImageFilter() + { + m_Verbose=false; + m_SplineOrders.Fill(3); + m_Size.Fill(0); + m_OutputSpacing.Fill(1.0); + m_OutputOrigin.Fill(-1); + m_OutputStartIndex.Fill(0); + m_OutputDirection.SetIdentity(); + + // Components + m_Resampler = ResamplerType::New(); + m_Function = FunctionType::New(); + m_Identity = IdentityTransformType::New(); + m_Decomposition = DecompositionType::New(); + + // Connect + m_Resampler->SetInterpolator( m_Function ); + m_Resampler->SetTransform( m_Identity ); + m_Decomposition->SetInput( m_Resampler->GetOutput() ); + + } + + //------------------------------------------------------------------- + // Output Info + //------------------------------------------------------------------- + template + void + ResampleBSplineDeformableTransformImageFilter::SetOutputSpacing( const double* spacing ) + { + OutputSpacingType s(spacing); + this->SetOutputSpacing( s ); + } + + //------------------------------------------------------------------- + // Output Info + //------------------------------------------------------------------- + template + void + ResampleBSplineDeformableTransformImageFilter::SetOutputOrigin( const double* origin ) + { + OutputPointType p(origin); + this->SetOutputOrigin( p ); + } + + + + //------------------------------------------------------------------- + // Update with the number of dimensions and the pixeltype + //------------------------------------------------------------------- + template + void + ResampleBSplineDeformableTransformImageFilter::GenerateData() + { + + // Resample? + bool sizeIsCorrect=true; + + if (this->GetInput()->GetSpacing() !=m_OutputSpacing) + sizeIsCorrect=false; + else if (this->GetInput()->GetLargestPossibleRegion().GetSize()!=m_Size) + sizeIsCorrect=false; + else if (this->GetInput()->GetOrigin()!=m_OutputOrigin) + sizeIsCorrect=false; + + // No resampling resquired + if (sizeIsCorrect) + { + if(m_Verbose)std::cout<<"Output properties are up to date, no resampling required!"< CastImageFilterType; + typename CastImageFilterType::Pointer caster = CastImageFilterType::New(); + caster->SetInput(this->GetInput()); + caster->Update(); + this->GraftOutput(caster->GetOutput()); + } + + // Resample + else + { + if(m_Verbose)std::cout<<"Resampling transform..."<SetInput( this->GetInput() ); + m_Resampler->SetSize( m_Size); + m_Resampler->SetOutputSpacing( m_OutputSpacing ); + m_Resampler->SetOutputOrigin( m_OutputOrigin ); + m_Resampler->SetOutputDirection( m_OutputDirection ); + m_Resampler->SetOutputStartIndex( m_OutputStartIndex ); + + // Transform the values back to Bspline coefficients + m_Decomposition->SetSplineOrders( m_SplineOrders ); + m_Decomposition->Update(); + this->GraftOutput( m_Decomposition->GetOutput() ); + } + + } + + +}//end clitk + +#endif //#define clitkResampleBSplineDeformableTransformImageFilter_txx diff --git a/registration/clitkSelectPoints.cxx b/registration/clitkSelectPoints.cxx new file mode 100755 index 0000000..6c8e40b --- /dev/null +++ b/registration/clitkSelectPoints.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkSelectPoints.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkSelectPoints_ggo.h" +#include "clitkIO.h" +#include "clitkSelectPointsGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkSelectPoints, args_info); + CLITK_INIT; + + // Filter + clitk::SelectPointsGenericFilter::Pointer genericFilter=clitk::SelectPointsGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkSelectPoints.ggo b/registration/clitkSelectPoints.ggo new file mode 100755 index 0000000..6c15fae --- /dev/null +++ b/registration/clitkSelectPoints.ggo @@ -0,0 +1,24 @@ +#File clitkSelectPoints.ggo +Package "clitkSelectPoints" +version "1.0" +purpose "Perform a selection of points on the reference and target lists of points, based on criteria applied to the reference list." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +section "Input" + +option "ref" r "List of points in reference" string yes +option "input" i "Lists of points in targets" string multiple yes + + +section "Output" + +option "sRef" - "List of points selected in reference" string yes +option "sInput" o "Lists of points selected in targets" string multiple yes + +section "Selection: Provide lower and upper coordinate bounds for as much as components as provided" + +option "component" c "Component index [0,2]" int multiple yes +option "lower" l "Lower bound" double multiple yes +option "upper" u "Upper bound" double multiple yes diff --git a/registration/clitkSelectPointsGenericFilter.cxx b/registration/clitkSelectPointsGenericFilter.cxx new file mode 100755 index 0000000..3754160 --- /dev/null +++ b/registration/clitkSelectPointsGenericFilter.cxx @@ -0,0 +1,141 @@ +/*========================================================================= + 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 clitkSelectPointsGenericFilter_cxx +#define clitkSelectPointsGenericFilter_cxx + +/* ================================================= + * @file clitkSelectPointsGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkSelectPointsGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + SelectPointsGenericFilter::SelectPointsGenericFilter() + { + m_Verbose=false; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void SelectPointsGenericFilter::Update() + { + //----------------------------- + // Typedefs + //----------------------------- + typedef double ValueType; + typedef std::vector MeasureListType; + + typedef itk::Point PointType; + typedef clitk::List PointListType; + typedef clitk::Lists PointListsType; + + + //----------------------------- + // Input point lists + //----------------------------- + PointListsType pointLists; + unsigned int numberOfPoints=0; + unsigned int numberOfLists=m_ArgsInfo.input_given; + for (unsigned int i=0; i= m_ArgsInfo.lower_arg[component]) + && (referencePointList[number][m_ArgsInfo.component_arg[component]] <= m_ArgsInfo.upper_arg[component]) ) + { + if(m_Verbose) std::cout<<"Selecting point "< filenames; + for (unsigned int i=0;i Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( SelectPointsGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkSelectPoints & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + SelectPointsGenericFilter(); + ~SelectPointsGenericFilter() {}; + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkSelectPoints m_ArgsInfo; + bool m_Verbose; + + }; + + +} // end namespace clitk + + +#endif // #define clitkSelectPointsGenericFilter_h diff --git a/registration/clitkShapedBLUTSpatioTemporalDIR.cxx b/registration/clitkShapedBLUTSpatioTemporalDIR.cxx new file mode 100755 index 0000000..2ea11fc --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDIR.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + 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 clitkShapedBLUTSpatioTemporalDIR.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkShapedBLUTSpatioTemporalDIR_ggo.h" +#include "clitkIO.h" +#include "clitkShapedBLUTSpatioTemporalDIRGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkShapedBLUTSpatioTemporalDIR, args_info); + CLITK_INIT; + + // Filter + clitk::ShapedBLUTSpatioTemporalDIRGenericFilter::Pointer genericFilter=clitk::ShapedBLUTSpatioTemporalDIRGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/registration/clitkShapedBLUTSpatioTemporalDIR.ggo b/registration/clitkShapedBLUTSpatioTemporalDIR.ggo new file mode 100755 index 0000000..43b7ea1 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDIR.ggo @@ -0,0 +1,90 @@ +#File clitkShapedBLUTSpatioTemporalDIR.ggo +#Author: Jef Vandemeulebroucke +#Date : Tue 15 Jan 2009 10.35 + +Package "clitk" +Version "Deform a volume to match a temporal sequence using a spatio-temporal deformation model. By setting the shape of the model, you modify the temporal constraints applied to the cyclic trajectory model." + +option "config" - "Config file" string no + + +section "Run Time" + +option "verbose" v "Verbose" flag off +option "threads" - "Number of threads to use (default=min(#cores,8))" int no + + +section "Input" + +option "reference" r "Input reference 3D image (float)" string yes +option "target" t "Input target 2D image (float)" 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 "vf" - "Result DVF" string yes +option "coeff" - "Result coefficient images" string no +option "padCoeff" - "Result padded coefficient images" string no +option "output" o "Deformed target image" string yes +option "before" - "Difference image before (but after rigid transform)" string no +option "after" - "Difference image after " string no +option "current" - "Write the current coefficient image every N evaluations" int no +option "intermediate" - "Write the coefficient image at resolution levels (provide N filenames)" string no multiple + + +section "Transform (Note that only one of --control, --spacing is required. The other will be adjusted to fit the region and allow exact representation. SamplingFactor will be set accordingly" + +option "shape" - "Even=4 internal CP, Odd 5 internal CP: 0,1=egg; 2,3= rabbit; 4,5=sputnik; 6,7=diamond" int no default="3" +option "initCoeff" - "Initial coefficient image (without borders)" string no +option "initPadCoeff" - "Initial padded coefficient image (with borders)" string no +option "rigid" - "Prior rigid transform matrix from reference to target space" string no +option "order" - "Spline Order FFD" int no multiple default="3" +option "control" - "Internal control points for each dimension" int no multiple +option "spacing" - "Control point spacing for each dimension (mm)" double no multiple +option "samplingFactor" - "LUT sampling factor" int no multiple + + +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 "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 off + + +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="7" +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 default="0.0" +option "upperBound" - "7: The upper bound" double no default="0.0" + + +Section "Registration" + +option "levels" - "Number of resolution levels" int no default="1" diff --git a/registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.cxx b/registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.cxx new file mode 100755 index 0000000..34cf7d3 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.cxx @@ -0,0 +1,70 @@ +/*========================================================================= + 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 clitkShapedBLUTSpatioTemporalDIRGenericFilter_cxx +#define clitkShapedBLUTSpatioTemporalDIRGenericFilter_cxx + +/* ================================================= + * @file clitkShapedBLUTSpatioTemporalDIRGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkShapedBLUTSpatioTemporalDIRGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + ShapedBLUTSpatioTemporalDIRGenericFilter::ShapedBLUTSpatioTemporalDIRGenericFilter() + { + m_Verbose=false; + m_ReferenceFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void ShapedBLUTSpatioTemporalDIRGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_ReferenceFileName, Dimension, PixelType); + + //if(Dimension==3) UpdateWithDim<3>(PixelType); + //else + if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 4 Dimensions!!!"< Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( ShapedBLUTSpatioTemporalDIRGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkShapedBLUTSpatioTemporalDIR & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_ReferenceFileName=m_ArgsInfo.reference_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + ShapedBLUTSpatioTemporalDIRGenericFilter(); + ~ShapedBLUTSpatioTemporalDIRGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithDim(std::string PixelType); + template void UpdateWithDimAndPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkShapedBLUTSpatioTemporalDIR m_ArgsInfo; + bool m_Verbose; + std::string m_ReferenceFileName; + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkShapedBLUTSpatioTemporalDIRGenericFilter.txx" +#endif + +#endif // #define clitkShapedBLUTSpatioTemporalDIRGenericFilter_h diff --git a/registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.txx b/registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.txx new file mode 100755 index 0000000..1610936 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDIRGenericFilter.txx @@ -0,0 +1,929 @@ +/*========================================================================= + 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 clitkShapedBLUTSpatioTemporalDIRGenericFilter_txx +#define clitkShapedBLUTSpatioTemporalDIRGenericFilter_txx + +/* ================================================= + * @file clitkShapedBLUTSpatioTemporalDIRGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkShapedBLUTSpatioTemporalDIRGenericFilter.h" + +namespace clitk +{ + + //============================================================================== + // Creating an observer class that allows output at each iteration + //============================================================================== + template + class CommandIterationUpdate : public itk::Command + { + public: + typedef CommandIterationUpdate Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + itkNewMacro( Self ); + + // Registration + typedef TRegistration RegistrationType; + typedef RegistrationType * RegistrationPointer; + + // Transform + typedef typename RegistrationType::FixedImageType FixedImageType; + typedef typename FixedImageType::RegionType RegionType; + itkStaticConstMacro(ImageDimension, unsigned int,FixedImageType::ImageDimension); + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransform TransformType; + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransformInitializer InitializerType; + typedef typename InitializerType::CoefficientImageType CoefficientImageType; + typedef itk::CastImageFilter CastImageFilterType; + typedef typename TransformType::ParametersType ParametersType; + typedef typename InitializerType::Pointer InitializerPointer; + + protected: + CommandIterationUpdate() { m_IterationCounter=0;} + public: + typedef clitk::GenericOptimizer OptimizerType; + typedef const OptimizerType * OptimizerPointer; + + // 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; + } + + // Output + m_Optimizer->OutputIterationInfo(); + m_IterationCounter++; + + // Write intermediate result + if (m_ArgsInfo.current_given && (m_IterationCounter> m_ArgsInfo.current_arg) ) + { + // Write && Reset + writeImage(m_Initializer->GetTransform()->GetCoefficientImage(), m_ArgsInfo.coeff_arg, m_ArgsInfo.verbose_flag ); + m_IterationCounter=0; + } + } + + // Members + void SetOptimizer(OptimizerPointer o){m_Optimizer=o;} + OptimizerPointer m_Optimizer; + + void SetInitializer(InitializerPointer i){m_Initializer=i;} + InitializerPointer m_Initializer; + + void SetArgsInfo(args_info_clitkShapedBLUTSpatioTemporalDIR a){m_ArgsInfo=a;} + args_info_clitkShapedBLUTSpatioTemporalDIR m_ArgsInfo; + + int m_IterationCounter; + }; + + + //============================================================================== + //Creating an observer class that allows us to change parameters at subsequent levels + //============================================================================== + template + class RegistrationInterfaceCommand : public itk::Command + { + public: + typedef RegistrationInterfaceCommand Self; + typedef itk::Command Superclass; + typedef itk::SmartPointer Pointer; + itkNewMacro( Self ); + protected: + RegistrationInterfaceCommand() {}; + public: + + // Registration + typedef TRegistration RegistrationType; + typedef RegistrationType * RegistrationPointer; + + // Transform + typedef typename RegistrationType::FixedImageType FixedImageType; + typedef typename FixedImageType::RegionType RegionType; + itkStaticConstMacro(ImageDimension, unsigned int,FixedImageType::ImageDimension); + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransform TransformType; + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransformInitializer InitializerType; + typedef typename InitializerType::CoefficientImageType CoefficientImageType; + typedef itk::CastImageFilter CastImageFilterType; + typedef typename TransformType::ParametersType ParametersType; + typedef typename InitializerType::Pointer InitializerPointer; + typedef typename CommandIterationUpdate< TRegistration, args_info_clitkShapedBLUTSpatioTemporalDIR>::Pointer CommandIterationUpdatePointer; + + // Optimizer + typedef clitk::GenericOptimizer GenericOptimizerType; + typedef typename GenericOptimizerType::Pointer GenericOptimizerPointer; + + // Metric + typedef typename RegistrationType::FixedImageType InternalImageType; + typedef clitk::GenericMetric GenericMetricType; + typedef typename GenericMetricType::Pointer GenericMetricPointer; + + // 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( object ); + unsigned int numberOfLevels=registration->GetNumberOfLevels(); + unsigned int currentLevel=registration->GetCurrentLevel()+1; + + // Output the levels + std::cout<1) + { + // fixed image region pyramid + typedef clitk::MultiResolutionPyramidRegionFilter FixedImageRegionPyramidType; + typename FixedImageRegionPyramidType::Pointer fixedImageRegionPyramid=FixedImageRegionPyramidType::New(); + fixedImageRegionPyramid->SetRegion(m_MetricRegion); + fixedImageRegionPyramid->SetSchedule(registration->GetFixedImagePyramid()->GetSchedule()); + + // Reinitialize the metric (!= number of samples) + m_GenericMetric= GenericMetricType::New(); + m_GenericMetric->SetArgsInfo(m_ArgsInfo); + m_GenericMetric->SetFixedImage(registration->GetFixedImagePyramid()->GetOutput(registration->GetCurrentLevel())); + if (m_ArgsInfo.referenceMask_given) m_GenericMetric->SetFixedImageMask(registration->GetMetric()->GetFixedImageMask()); + m_GenericMetric->SetFixedImageRegion(fixedImageRegionPyramid->GetOutput(registration->GetCurrentLevel())); + typedef itk::ImageToImageMetric< InternalImageType, InternalImageType > MetricType; + typename MetricType::Pointer metric=m_GenericMetric->GetMetricPointer(); + registration->SetMetric(metric); + + // Get the current coefficient image and make a COPY + typename itk::ImageDuplicator::Pointer caster=itk::ImageDuplicator::New(); + caster->SetInputImage(m_Initializer->GetTransform()->GetCoefficientImage()); + caster->Update(); + typename CoefficientImageType::Pointer currentCoefficientImage=caster->GetOutput(); + + // Write the intermediate result? + if (m_ArgsInfo.intermediate_given>=numberOfLevels) + writeImage(currentCoefficientImage, m_ArgsInfo.intermediate_arg[currentLevel-2], m_ArgsInfo.verbose_flag); + + // Set the new transform properties + m_Initializer->SetImage(registration->GetFixedImagePyramid()->GetOutput(currentLevel-1)); + if( m_Initializer->m_ControlPointSpacingIsGiven) + m_Initializer->SetControlPointSpacing(m_Initializer->m_ControlPointSpacingArray[registration->GetCurrentLevel()]); + if( m_Initializer->m_NumberOfControlPointsIsGiven) + m_Initializer->SetNumberOfControlPointsInsideTheImage(m_Initializer->m_NumberOfControlPointsInsideTheImageArray[registration->GetCurrentLevel()]); + + // Reinitialize the transform + if (m_ArgsInfo.verbose_flag) std::cout<<"Initializing transform for level "<InitializeTransform(); + ParametersType* newParameters= new typename TransformType::ParametersType(m_Initializer->GetTransform()->GetNumberOfParameters()); + + // Reinitialize an Optimizer (!= number of parameters) + m_GenericOptimizer = GenericOptimizerType::New(); + m_GenericOptimizer->SetArgsInfo(m_ArgsInfo); + m_GenericOptimizer->SetMaximize(m_Maximize); + m_GenericOptimizer->SetNumberOfParameters(m_Initializer->GetTransform()->GetNumberOfParameters()); + typedef itk::SingleValuedNonLinearOptimizer OptimizerType; + OptimizerType::Pointer optimizer = m_GenericOptimizer->GetOptimizerPointer(); + optimizer->AddObserver( itk::IterationEvent(), m_CommandIterationUpdate); + registration->SetOptimizer(optimizer); + m_CommandIterationUpdate->SetOptimizer(m_GenericOptimizer); + + // Set the previous transform parameters to the registration + // if(m_Initializer->m_Parameters!=NULL )delete m_Initializer->m_Parameters; + m_Initializer->SetInitialParameters(currentCoefficientImage,*newParameters); + registration->SetInitialTransformParametersOfNextLevel(*newParameters); + } + } + + void Execute(const itk::Object * , const itk::EventObject & ) + { return; } + + + // Members + void SetInitializer(InitializerPointer i){m_Initializer=i;} + InitializerPointer m_Initializer; + + void SetArgsInfo(args_info_clitkShapedBLUTSpatioTemporalDIR a){m_ArgsInfo=a;} + args_info_clitkShapedBLUTSpatioTemporalDIR m_ArgsInfo; + + void SetCommandIterationUpdate(CommandIterationUpdatePointer c){m_CommandIterationUpdate=c;}; + CommandIterationUpdatePointer m_CommandIterationUpdate; + + GenericOptimizerPointer m_GenericOptimizer; + void SetMaximize(bool b){m_Maximize=b;} + bool m_Maximize; + + GenericMetricPointer m_GenericMetric; + void SetMetricRegion(RegionType i){m_MetricRegion=i;} + RegionType m_MetricRegion; + + + }; + + + //============================================================================== + // Update with the number of dimensions + //============================================================================== + template + void + ShapedBLUTSpatioTemporalDIRGenericFilter::UpdateWithDim(std::string PixelType) + { + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "unsigned_char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithDimAndPixelType(); + // } + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithDimAndPixelType(); + } + } + + + //============================================================================== + // Update with the number of dimensions and pixeltype + //============================================================================== + template + void + ShapedBLUTSpatioTemporalDIRGenericFilter::UpdateWithDimAndPixelType() + { + + + //============================================================================= + //Input + //============================================================================= + bool threadsGiven=m_ArgsInfo.threads_given; + int threads=m_ArgsInfo.threads_arg; + + typedef itk::Image< PixelType, ImageDimension > FixedImageType; + typedef itk::Image< PixelType, ImageDimension > MovingImageType; + const unsigned int SpaceDimension = ImageDimension-1; + typedef double TCoordRep; + + + //======================================================= + //Input + //======================================================= + typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; + typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType; + + typename FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); + typename MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); + + fixedImageReader->SetFileName( m_ArgsInfo.reference_arg ); + movingImageReader->SetFileName( m_ArgsInfo.target_arg ); + if (m_Verbose) std::cout<<"Reading images..."<Update(); + movingImageReader->Update(); + + typename FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); + typename MovingImageType::Pointer movingImage =movingImageReader->GetOutput(); + typename FixedImageType::Pointer croppedFixedImage=fixedImage; + + + //======================================================= + // Regions + //======================================================= + + // The original input region + typename FixedImageType::RegionType fixedImageRegion = fixedImage->GetLargestPossibleRegion(); + + // The transform region with respect to the input region: + // where should the transform be DEFINED (depends on mask) + typename FixedImageType::RegionType transformRegion = fixedImage->GetLargestPossibleRegion(); + typename FixedImageType::RegionType::SizeType transformRegionSize=transformRegion.GetSize(); + typename FixedImageType::RegionType::IndexType transformRegionIndex=transformRegion.GetIndex(); + typename FixedImageType::PointType transformRegionOrigin=fixedImage->GetOrigin(); + + // The metric region with respect to the extracted transform region: + // where should the metric be CALCULATED (depends on transform) + typename FixedImageType::RegionType metricRegion = fixedImage->GetLargestPossibleRegion(); + typename FixedImageType::RegionType::SizeType metricRegionSize=metricRegion.GetSize(); + typename FixedImageType::RegionType::IndexType metricRegionIndex=metricRegion.GetIndex(); + typename FixedImageType::PointType metricRegionOrigin=fixedImage->GetOrigin(); + + //=========================================================================== + // If given, we connect a mask to reference or target + //============================================================================ + typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; + typename MaskType::Pointer fixedMask=NULL; + if (m_ArgsInfo.referenceMask_given) + { + fixedMask= MaskType::New(); + typedef itk::Image< unsigned char, ImageDimension > 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..." <SetImage( maskReader->GetOutput() ); + + // Find the bounding box of the "inside" label + typedef itk::LabelStatisticsImageFilter StatisticsImageFilterType; + typename StatisticsImageFilterType::Pointer statisticsImageFilter=StatisticsImageFilterType::New(); + statisticsImageFilter->SetInput(maskReader->GetOutput()); + statisticsImageFilter->SetLabelInput(maskReader->GetOutput()); + statisticsImageFilter->Update(); + typename StatisticsImageFilterType::BoundingBoxType boundingBox = statisticsImageFilter->GetBoundingBox(1); + + // Limit the transform region to the mask + for (unsigned int i=0; iTransformIndexToPhysicalPoint(transformRegion.GetIndex(), transformRegionOrigin); + + // Crop the fixedImage to the bounding box to facilitate multi-resolution + typedef itk::ExtractImageFilter ExtractImageFilterType; + typename ExtractImageFilterType::Pointer extractImageFilter=ExtractImageFilterType::New(); + extractImageFilter->SetInput(fixedImage); + extractImageFilter->SetExtractionRegion(transformRegion); + extractImageFilter->Update(); + croppedFixedImage=extractImageFilter->GetOutput(); + + // Update the metric region + metricRegion = croppedFixedImage->GetLargestPossibleRegion(); + metricRegionIndex=metricRegion.GetIndex(); + metricRegionSize=metricRegion.GetSize(); + croppedFixedImage->TransformIndexToPhysicalPoint(metricRegionIndex, metricRegionOrigin); + + // Set start index to zero (with respect to croppedFixedImage/transform region) + metricRegionIndex.Fill(0); + metricRegion.SetIndex(metricRegionIndex); + croppedFixedImage->SetRegions(metricRegion); + croppedFixedImage->SetOrigin(metricRegionOrigin); + + } + + typedef itk::ImageMaskSpatialObject< ImageDimension > MaskType; + typename MaskType::Pointer movingMask=NULL; + if (m_ArgsInfo.targetMask_given) + { + movingMask= MaskType::New(); + typedef itk::Image< unsigned char, ImageDimension > 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..." <SetImage( maskReader->GetOutput() ); + } + + + //======================================================= + // Output Regions + //======================================================= + + if (m_Verbose) + { + // Fixed image region + std::cout<<"The fixed image has its origin at "<GetOrigin()< FixedImagePyramidType; + typedef clitk::RecursiveSpatioTemporalMultiResolutionPyramidImageFilter< MovingImageType, MovingImageType> MovingImagePyramidType; + typename FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New(); + typename MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New(); + fixedImagePyramid->SetUseShrinkImageFilter(false); + fixedImagePyramid->SetInput(croppedFixedImage); + 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..."<Update(); + movingImagePyramid->Update(); + typedef clitk::MultiResolutionPyramidRegionFilter FixedImageRegionPyramidType; + typename FixedImageRegionPyramidType::Pointer fixedImageRegionPyramid=FixedImageRegionPyramidType::New(); + fixedImageRegionPyramid->SetRegion(metricRegion); + fixedImageRegionPyramid->SetSchedule(fixedImagePyramid->GetSchedule()); + + + + + // //======================================================= + // // Rigid Transform + // //======================================================= + // typedef itk::Euler3DTransform RigidTransformType; + // RigidTransformType::Pointer rigidTransform; + // if (m_ArgsInfo.rigid_given) + // { + // rigidTransform=RigidTransformType::New(); + // itk::Matrix rigidTransformMatrix=clitk::ReadMatrix3D(m_ArgsInfo.rigid_arg); + + // //Set the rotation + // itk::Matrix finalRotation = clitk::GetRotationalPartMatrix3D(rigidTransformMatrix); + // rigidTransform->SetMatrix(finalRotation); + + // //Set the translation + // itk::Vector finalTranslation = clitk::GetTranslationPartMatrix3D(rigidTransformMatrix); + // rigidTransform->SetTranslation(finalTranslation); + + // } + + + //======================================================= + // ShapedBSplineSpatioTemporal Transform + //======================================================= + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransform TransformType; + typename TransformType::Pointer transform= TransformType::New(); + transform->SetTransformShape(m_ArgsInfo.shape_arg); + if (fixedMask) transform->SetMask( fixedMask ); + // if (rigidTransform) transform->SetBulkTransform( rigidTransform ); + + //------------------------------------------------------------------------- + // The transform initializer + //------------------------------------------------------------------------- + typedef clitk::ShapedBLUTSpatioTemporalDeformableTransformInitializer< TransformType,FixedImageType> InitializerType; + typename InitializerType::Pointer initializer = InitializerType::New(); + initializer->SetVerbose(m_Verbose); + initializer->SetImage(fixedImagePyramid->GetOutput(0)); + initializer->SetTransform(transform); + + //------------------------------------------------------------------------- + // Order + //------------------------------------------------------------------------- + typename FixedImageType::RegionType::SizeType splineOrders ; + splineOrders.Fill(3); + if (m_ArgsInfo.order_given) + for(unsigned int i=0; iSetSplineOrders(splineOrders); + + //------------------------------------------------------------------------- + // Levels + //------------------------------------------------------------------------- + + // Spacing + if (m_ArgsInfo.spacing_given) + { + initializer->m_ControlPointSpacingArray.resize(m_ArgsInfo.levels_arg); + initializer->SetControlPointSpacing(m_ArgsInfo.spacing_arg); + initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1]=initializer->m_ControlPointSpacing; + if (m_Verbose) std::cout<<"Using a control point spacing of "<m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1] + <<" at level "<m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i]=initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-i]*2; + initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i][ImageDimension-1]=2; + if (m_Verbose) std::cout<<"Using a control point spacing of "<m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i] + <<" at level "<m_NumberOfControlPointsInsideTheImageArray.resize(m_ArgsInfo.levels_arg); + initializer->SetNumberOfControlPointsInsideTheImage(m_ArgsInfo.control_arg); + initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1]=initializer->m_NumberOfControlPointsInsideTheImage; + if (m_Verbose) std::cout<<"Using "<< initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1]<<"control points inside the image" + <<" at level "<m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i][j]=ceil ((double)initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-i][j]/2.); + // initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i]=ceil ((double)initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-i]/2.); + if (m_Verbose) std::cout<<"Using "<< initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i]<<"control points inside the image" + <<" at level "<SetControlPointSpacing( initializer->m_ControlPointSpacingArray[0]); + if (m_ArgsInfo.control_given) initializer->SetNumberOfControlPointsInsideTheImage(initializer->m_NumberOfControlPointsInsideTheImageArray[0]); + if (m_ArgsInfo.samplingFactor_given) initializer->SetSamplingFactors(m_ArgsInfo.samplingFactor_arg); + + // Initialize + initializer->InitializeTransform(); + + //------------------------------------------------------------------------- + // Initial parameters (passed by reference) + //------------------------------------------------------------------------- + typedef typename TransformType::ParametersType ParametersType; + const unsigned int numberOfParameters = transform->GetNumberOfParameters(); + ParametersType parameters(numberOfParameters); + parameters.Fill( 0.0 ); + transform->SetParameters( parameters ); + if (m_ArgsInfo.initCoeff_given) initializer->SetInitialParameters(m_ArgsInfo.initCoeff_arg, parameters); + + + //======================================================= + // Interpolator + //======================================================= + typedef clitk::GenericInterpolator GenericInterpolatorType; + typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New(); + genericInterpolator->SetArgsInfo(m_ArgsInfo); + typedef itk::InterpolateImageFunction< FixedImageType, TCoordRep > InterpolatorType; + typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer(); + + + //======================================================= + // Metric + //======================================================= + typedef clitk::GenericMetric< args_info_clitkShapedBLUTSpatioTemporalDIR, FixedImageType,MovingImageType > GenericMetricType; + typename GenericMetricType::Pointer genericMetric=GenericMetricType::New(); + genericMetric->SetArgsInfo(m_ArgsInfo); + genericMetric->SetFixedImage(fixedImagePyramid->GetOutput(0)); + if (fixedMask) genericMetric->SetFixedImageMask(fixedMask); + genericMetric->SetFixedImageRegion(fixedImageRegionPyramid->GetOutput(0)); + typedef itk::ImageToImageMetric< FixedImageType, MovingImageType > 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)..."< GenericOptimizerType; + GenericOptimizerType::Pointer genericOptimizer = GenericOptimizerType::New(); + genericOptimizer->SetArgsInfo(m_ArgsInfo); + genericOptimizer->SetMaximize(genericMetric->GetMaximize()); + genericOptimizer->SetNumberOfParameters(transform->GetNumberOfParameters()); + typedef itk::SingleValuedNonLinearOptimizer OptimizerType; + OptimizerType::Pointer optimizer = genericOptimizer->GetOptimizerPointer(); + + + //======================================================= + // Registration + //======================================================= + typedef clitk::SpatioTemporalMultiResolutionImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType; + typename RegistrationType::Pointer registration = RegistrationType::New(); + registration->SetMetric( metric ); + registration->SetOptimizer( optimizer ); + registration->SetInterpolator( interpolator ); + registration->SetTransform (transform); + if(threadsGiven) registration->SetNumberOfThreads(threads); + registration->SetFixedImage( croppedFixedImage ); + registration->SetMovingImage( movingImage ); + registration->SetFixedImageRegion( metricRegion ); + registration->SetFixedImagePyramid( fixedImagePyramid ); + registration->SetMovingImagePyramid( movingImagePyramid ); + registration->SetInitialTransformParameters( transform->GetParameters() ); + registration->SetNumberOfLevels( m_ArgsInfo.levels_arg ); + if (m_Verbose) std::cout<<"Setting the number of resolution levels to "< CommandIterationUpdateType; + typename CommandIterationUpdateType::Pointer observer = CommandIterationUpdateType::New(); + observer->SetInitializer(initializer); + observer->SetArgsInfo(m_ArgsInfo); + observer->SetOptimizer(genericOptimizer); + optimizer->AddObserver( itk::IterationEvent(), observer ); + + // Output level info + typedef RegistrationInterfaceCommand CommandType; + typename CommandType::Pointer command = CommandType::New(); + command->SetInitializer(initializer); + command->SetArgsInfo(m_ArgsInfo); + command->SetCommandIterationUpdate(observer); + command->SetMaximize(genericMetric->GetMaximize()); + command->SetMetricRegion(metricRegion); + registration->AddObserver( itk::IterationEvent(), command ); + } + + + //======================================================= + // Let's go + //======================================================= + if (m_Verbose) std::cout << std::endl << "Starting Registration" << std::endl; + + try + { + registration->StartRegistration(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught while registering!" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Get the result + //======================================================= + OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters(); + transform->SetParameters( finalParameters ); + if (m_Verbose) + { + std::cout<<"Stop condition description: " + <GetOptimizer()->GetStopConditionDescription()<GetCoefficientImage(); + typedef itk::ImageFileWriter CoeffWriterType; + typename CoeffWriterType::Pointer coeffWriter=CoeffWriterType::New(); + coeffWriter->SetInput(coefficientImage); + coeffWriter->SetFileName(m_ArgsInfo.coeff_arg); + coeffWriter->Update(); + + } + if (m_ArgsInfo.padCoeff_given) + { + typedef itk::Image, ImageDimension> CoefficientImageType; + typename CoefficientImageType::Pointer coefficientImage =transform->GetPaddedCoefficientImage(); + typedef itk::ImageFileWriter CoeffWriterType; + typename CoeffWriterType::Pointer coeffWriter=CoeffWriterType::New(); + coeffWriter->SetInput(coefficientImage); + coeffWriter->SetFileName(m_ArgsInfo.padCoeff_arg); + coeffWriter->Update(); + } + + + //======================================================= + // Generate the DVF (4D with 3 comps and 4D with 4 comps) + //======================================================= + typedef itk::Vector< float, SpaceDimension > DisplacementType; + typedef itk::Vector< float, ImageDimension > Displacement4DType; + typedef itk::Image< DisplacementType, ImageDimension > DeformationFieldType; + typedef itk::Image< Displacement4DType, ImageDimension > DeformationField4DType; + + typename DeformationFieldType::Pointer field = DeformationFieldType::New(); + typename DeformationField4DType::Pointer field4D = DeformationField4DType::New(); + field->SetRegions( fixedImageRegion ); + field->SetOrigin( fixedImage->GetOrigin() ); + field->SetSpacing( fixedImage->GetSpacing() ); + field->SetDirection( fixedImage->GetDirection() ); + field->Allocate(); + field4D->SetRegions( fixedImageRegion ); + field4D->SetOrigin( fixedImage->GetOrigin() ); + field4D->SetSpacing( fixedImage->GetSpacing() ); + field4D->SetDirection( fixedImage->GetDirection() ); + field4D->Allocate(); + + typedef itk::ImageRegionIteratorWithIndex< DeformationFieldType > FieldIterator; + typedef itk::ImageRegionIteratorWithIndex< DeformationField4DType > Field4DIterator; + FieldIterator fi( field, fixedImageRegion ); + Field4DIterator fi4D( field4D, fixedImageRegion ); + fi.GoToBegin(); + fi4D.GoToBegin(); + + typename TransformType::InputPointType fixedPoint; + typename TransformType::OutputPointType movingPoint; + typename DeformationFieldType::IndexType index; + + DisplacementType displacement; + Displacement4DType displacement4D; + displacement4D[ImageDimension-1]=0; + while( ! fi.IsAtEnd() ) + { + index = fi.GetIndex(); + field->TransformIndexToPhysicalPoint( index, fixedPoint ); + movingPoint = transform->TransformPoint( fixedPoint ); + for (unsigned int i=0; i FieldWriterType; + typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New(); + fieldWriter->SetFileName( m_ArgsInfo.vf_arg ); + fieldWriter->SetInput( field ); + try + { + fieldWriter->Update(); + } + catch( itk::ExceptionObject & excp ) + { + std::cerr << "Exception thrown writing the DVF" << std::endl; + std::cerr << excp << std::endl; + return; + } + + + //======================================================= + // Resample the moving image + //======================================================= + typedef itk::WarpImageFilter< MovingImageType, FixedImageType, DeformationField4DType > WarpFilterType; + typename WarpFilterType::Pointer warp = WarpFilterType::New(); + + warp->SetDeformationField( field4D ); + warp->SetInput( movingImageReader->GetOutput() ); + warp->SetOutputOrigin( fixedImage->GetOrigin() ); + warp->SetOutputSpacing( fixedImage->GetSpacing() ); + warp->SetOutputDirection( fixedImage->GetDirection() ); + warp->SetEdgePaddingValue( 0.0 ); + warp->Update(); + + + //======================================================= + // Write the warped image + //======================================================= + typedef itk::ImageFileWriter< FixedImageType > WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName( m_ArgsInfo.output_arg ); + writer->SetInput( warp->GetOutput() ); + + try + { + writer->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return; + } + + + //======================================================= + // Calculate the difference after the deformable transform + //======================================================= + typedef clitk::DifferenceImageFilter< FixedImageType, FixedImageType> DifferenceFilterType; + if (m_ArgsInfo.after_given) + { + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( warp->GetOutput() ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + differenceWriter->SetInput(difference->GetOutput()); + differenceWriter->SetFileName(m_ArgsInfo.after_arg); + differenceWriter->Update(); + + } + + + //======================================================= + // Calculate the difference before the deformable transform + //======================================================= + if( m_ArgsInfo.before_given ) + { + + typename FixedImageType::Pointer moving=FixedImageType::New(); + if (m_ArgsInfo.rigid_given) + { + typedef itk::ResampleImageFilter ResamplerType; + typename ResamplerType::Pointer resampler=ResamplerType::New(); + resampler->SetInput(movingImage); + resampler->SetOutputOrigin(fixedImage->GetOrigin()); + resampler->SetSize(fixedImage->GetLargestPossibleRegion().GetSize()); + resampler->SetOutputSpacing(fixedImage->GetSpacing()); + resampler->SetDefaultPixelValue( 0. ); + //resampler->SetTransform(rigidTransform); + resampler->Update(); + moving=resampler->GetOutput(); + } + else + moving=movingImage; + + typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); + difference->SetValidInput( fixedImage ); + difference->SetTestInput( moving ); + + try + { + difference->Update(); + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught calculating the difference !" << std::endl; + std::cerr << err << std::endl; + return; + } + + typename WriterType::Pointer differenceWriter=WriterType::New(); + writer->SetFileName( m_ArgsInfo.before_arg ); + writer->SetInput( difference->GetOutput() ); + writer->Update( ); + } + + return; + + } +}//end clitk + +#endif //#define clitkShapedBLUTSpatioTemporalDIRGenericFilter_txx diff --git a/registration/clitkShapedBLUTSpatioTemporalDeformableTransform.h b/registration/clitkShapedBLUTSpatioTemporalDeformableTransform.h new file mode 100755 index 0000000..2d4b9e0 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDeformableTransform.h @@ -0,0 +1,445 @@ +/*========================================================================= + 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 __clitkShapedBLUTSpatioTemporalDeformableTransform_h +#define __clitkShapedBLUTSpatioTemporalDeformableTransform_h +#include "clitkVectorBSplineResampleImageFunctionWithLUT.h" +#include "clitkExtractImageFilter.h" +#include "clitkLinearCombinationImageFilter.h" + +//itk include +#include "itkTransform.h" +#include "itkImage.h" +#include "itkImageRegion.h" +#include "itkSpatialObject.h" +#include "itkPasteImageFilter.h" +#include "itkMultiplyByConstantImageFilter.h" + +namespace clitk +{ + + template < + class TCoordRep = double, // Data type for scalars, coordinate representation,vectors + unsigned int NInputDimensions = 3, // Number of input dimensions + unsigned int NOutputDimensions = 3 > // Number of output dimensions + class ITK_EXPORT ShapedBLUTSpatioTemporalDeformableTransform : + public itk::Transform< TCoordRep, NInputDimensions, NOutputDimensions > + { + public: + + //==================================================================== + // Typedefs + //==================================================================== + typedef ShapedBLUTSpatioTemporalDeformableTransform Self; + typedef itk::Transform< TCoordRep, NInputDimensions, NOutputDimensions > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** New macro for creation of through the object factory.*/ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( ShapedBLUTSpatioTemporalDeformableTransform, Transform ); + + /** Dimension of the output space. */ + itkStaticConstMacro(OutputDimension, unsigned int, NOutputDimensions); + + /** Dimension of the input space. */ + itkStaticConstMacro(InputDimension, unsigned int, NInputDimensions); + + //JV the number of spatial dimensions + itkStaticConstMacro(SpaceDimension, unsigned int, NInputDimensions-1); + + /** Standard scalar type for this class. */ + typedef typename Superclass::ScalarType ScalarType; + + /** Standard parameters container. */ + typedef typename Superclass::ParametersType ParametersType; + + /** Standard Jacobian container. */ + typedef typename Superclass::JacobianType JacobianType; + + /** Standard vector type for this class. */ + typedef itk::Vector InputVectorType; + typedef itk::Vector OutputVectorType; + + /** Standard covariant vector type for this class. */ + typedef itk::CovariantVector InputCovariantVectorType; + typedef itk::CovariantVector OutputCovariantVectorType; + + /** Standard vnl_vector type for this class. */ + typedef vnl_vector_fixed InputVnlVectorType; + typedef vnl_vector_fixed OutputVnlVectorType; + + /** Standard coordinate point type for this class. */ + typedef itk::Point InputPointType; + typedef itk::Point OutputPointType; + + //JV Parameters as images with OutputDimension number of components per Pixel + typedef typename ParametersType::ValueType ParametersValueType; + typedef typename itk::Vector PixelType; + typedef itk::Image CoefficientImageType; + typedef typename CoefficientImageType::Pointer CoefficientImagePointer; + + + /** Typedefs for specifying the extend to the grid. */ + typedef itk::ImageRegion RegionType; + typedef typename RegionType::IndexType IndexType; + typedef typename RegionType::SizeType SizeType; + typedef typename CoefficientImageType::SpacingType SpacingType; + typedef typename CoefficientImageType::DirectionType DirectionType; + typedef typename CoefficientImageType::PointType OriginType; + typedef itk::ContinuousIndex ContinuousIndexType; + + //JV added for the BLUT interpolator + typedef itk::Vector OutputSpacingType; + + //JV m_VectorInterpolator + typedef VectorBSplineResampleImageFunctionWithLUT + VectorInterpolatorType; + typedef typename VectorInterpolatorType::CoefficientDataType CoefficientDataType; + typedef typename VectorInterpolatorType::CoefficientDataType WeightsDataType; + + /** Typedef of the bulk transform. */ + typedef itk::Transform BulkTransformType; + typedef BulkTransformType* BulkTransformPointer; + + /** Typedef of the mask */ + typedef itk::SpatialObject< InputDimension > MaskType; + typedef MaskType* MaskPointer; + + //==================================================================== + // Set et Gets + //==================================================================== + //JV added for the BLUT interpolator + void SetSplineOrder(const unsigned int & splineOrder); + void SetSplineOrders(const SizeType & splineOrders); + itkGetMacro( SplineOrders, SizeType ); + itkGetConstMacro( SplineOrders, SizeType ); + void SetLUTSamplingFactor(const int & samplingFactor); + void SetLUTSamplingFactors(const SizeType & samplingFactors); + itkGetMacro( LUTSamplingFactors, SizeType ); + itkGetConstMacro( LUTSamplingFactors,SizeType ); + + void SetParameters(const ParametersType & parameters); + + void SetFixedParameters(const ParametersType & parameters); + + void SetParametersByValue(const ParametersType & parameters); + + void SetIdentity(); + + /** Get the Transformation Parameters. */ + virtual const ParametersType& GetParameters(void) const; + + /** Get the Transformation Fixed Parameters. */ + virtual const ParametersType& GetFixedParameters(void) const; + + // The coefficientImage + virtual CoefficientImagePointer GetCoefficientImage() + { return m_CoefficientImage; } + virtual const CoefficientImagePointer GetCoefficientImage() const + { return m_CoefficientImage; } + virtual void SetCoefficientImage(CoefficientImagePointer image); + + // The padded coefficient image + virtual CoefficientImagePointer GetPaddedCoefficientImage() + { return m_PaddedCoefficientImage; } + virtual const CoefficientImagePointer GetPaddedCoefficientImage() const + { return m_PaddedCoefficientImage; } + // virtual void SetPaddedCoefficientImage(CoefficientImagePointer image); + + /** This method specifies the region over which the grid resides. */ + virtual void SetGridRegion( const RegionType& region ); + itkGetMacro( GridRegion, RegionType ); + itkGetConstMacro( GridRegion, RegionType ); + + /** This method specifies the grid spacing or resolution. */ + virtual void SetGridSpacing( const SpacingType& spacing ); + itkGetMacro( GridSpacing, SpacingType ); + itkGetConstMacro( GridSpacing, SpacingType ); + + /** This method specifies the grid directions . */ + virtual void SetGridDirection( const DirectionType & spacing ); + itkGetMacro( GridDirection, DirectionType ); + itkGetConstMacro( GridDirection, DirectionType ); + + /** This method specifies the grid origin. */ + virtual void SetGridOrigin( const OriginType& origin ); + itkGetMacro( GridOrigin, OriginType ); + itkGetConstMacro( GridOrigin, OriginType ); + + // Set the bulk transform, real pointer + // itkSetConstObjectMacro( BulkTransform, BulkTransformType ); + // itkGetConstObjectMacro( BulkTransform, BulkTransformType ); + void SetBulkTransform(BulkTransformPointer b){m_BulkTransform=b;} + BulkTransformPointer GetBulkTransform(void) {return m_BulkTransform;} + + //Set mask, inside transform applies, outside zero, real pointer + void SetMask(MaskPointer m){m_Mask=m;} + + // JV the shape + itkSetMacro( TransformShape , unsigned int ); + itkGetMacro( TransformShape , unsigned int ); + itkGetConstMacro( TransformShape, unsigned int ); + + /** Transform points by a BSpline deformable transformation. */ + OutputPointType TransformPoint(const InputPointType &point ) const; + + // JV added for just the deformable part, without bulk + OutputPointType DeformablyTransformPoint(const InputPointType &point ) const; + + /** Parameter index array type. */ + typedef itk::Array ParameterIndexArrayType; + + /** Transform points by a BSpline deformable transformation. + * On return, weights contains the interpolation weights used to compute the + * deformation and indices of the x (zeroth) dimension coefficient parameters + * in the support region used to compute the deformation. + * Parameter indices for the i-th dimension can be obtained by adding + * ( i * this->GetNumberOfParametersPerDimension() ) to the indices array. + */ + + // JV not implemented + // virtual void TransformPoint( const InputPointType & inputPoint, + // OutputPointType & outputPoint, + // WeightsType & weights, + // ParameterIndexArrayType & indices, + // bool & inside ) const; + // virtual void DeformablyTransformPoint( const InputPointType & inputPoint, + // OutputPointType & outputPoint, + // WeightsType & weights, + // ParameterIndexArrayType & indices, + // bool & inside ) const; + // virtual void GetJacobian( const InputPointType & inputPoint, + // WeightsType & weights, + // ParameterIndexArrayType & indices + // ) const; + + /** Method to transform a vector - + * not applicable for this type of transform. */ + virtual OutputVectorType TransformVector(const InputVectorType &) const + { + itkExceptionMacro(<< "Method not applicable for deformable transform." ); + return OutputVectorType(); + } + + /** Method to transform a vnl_vector - + * not applicable for this type of transform */ + virtual OutputVnlVectorType TransformVector(const InputVnlVectorType &) const + { + itkExceptionMacro(<< "Method not applicable for deformable transform. "); + return OutputVnlVectorType(); + } + + /** Method to transform a CovariantVector - + * not applicable for this type of transform */ + virtual OutputCovariantVectorType TransformCovariantVector( + const InputCovariantVectorType &) const + { + itkExceptionMacro(<< "Method not applicable for deformable transfrom. "); + return OutputCovariantVectorType(); + } + + /** Compute the Jacobian Matrix of the transformation at one point */ + virtual const JacobianType& GetJacobian(const InputPointType &point ) const; + + /** Return the number of parameters that completely define the Transfom */ + virtual unsigned int GetNumberOfParameters(void) const; + + //JV Return the padded number of parameters + virtual unsigned int GetPaddedNumberOfParameters(void) const; + + /** Return the number of parameters per dimension */ + unsigned int GetNumberOfParametersPerDimension(void) const; + + /** Return the region of the grid wholly within the support region */ + itkGetConstReferenceMacro( ValidRegion, RegionType ); + + /** Indicates that this transform is linear. That is, given two + * points P and Q, and scalar coefficients a and b, then + * + * T( a*P + b*Q ) = a * T(P) + b * T(Q) + */ + virtual bool IsLinear() const { return false; } + + //unsigned int GetNumberOfAffectedWeights() const; + + protected: + /** Print contents of an BSplineSpatioTemporalDeformableTransform. */ + void PrintSelf(std::ostream &os, itk::Indent indent) const; + + + ShapedBLUTSpatioTemporalDeformableTransform(); + virtual ~ShapedBLUTSpatioTemporalDeformableTransform(); + + /** Wrap flat array into images of coefficients. */ + void WrapAsImages(); + + // JV Pad/Extract the coefficient image + void PadCoefficientImage(void); + typename CoefficientImageType::Pointer ExtractTemporalRow(const typename CoefficientImageType::Pointer& coefficientImage, unsigned int temporalIndex); + //void ExtractCoefficientImage(void); + + /** Wrap flat array into images of coefficients. */ + inline void WrapRegion(const RegionType& support, + RegionType& first, + RegionType& second, + RegionType& third, + std::vector& bc, + std::vector& bcValues, + std::vector& bc2, + std::vector& bc2Values, + std::vector& bc3, + std::vector& bc3Values, + unsigned int& m_InitialOffset ) const; + + /** Convert an input point to a continuous index inside the BSpline grid */ + void TransformPointToContinuousIndex( const InputPointType & point, ContinuousIndexType & index ) const; + + private: + ShapedBLUTSpatioTemporalDeformableTransform(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** The bulk transform. */ + BulkTransformPointer m_BulkTransform; + MaskPointer m_Mask; + + // JV added for BLUT interpolator + SizeType m_SplineOrders; + //OutputSpacingType m_OutputSpacing; + SizeType m_LUTSamplingFactors; + + /** Variables defining the coefficient grid extend. */ + RegionType m_GridRegion; + SpacingType m_GridSpacing; + DirectionType m_GridDirection; + OriginType m_GridOrigin; + + // JV additional variables for the padded region + RegionType m_PaddedGridRegion; + OriginType m_PaddedGridOrigin; + + + DirectionType m_PointToIndex; + DirectionType m_IndexToPoint; + + RegionType m_ValidRegion; + + /** Variables defining the interpolation support region. */ + SizeType m_Offset; + itk::FixedArray m_SplineOrderOdd; + SizeType m_SupportSize; + IndexType m_ValidRegionLast; + + /** Array holding images wrapped from the flat parameters. */ + CoefficientImagePointer m_WrappedImage; + + /** Vector image representing the B-spline coefficients + * in each dimension. */ + CoefficientImagePointer m_CoefficientImage; + CoefficientImagePointer m_PaddedCoefficientImage; + + /** Jacobian as OutputDimension number of images. */ + typedef typename JacobianType::ValueType JacobianValueType; + typedef typename itk::Vector JacobianPixelType; + typedef itk::Image JacobianImageType; + typename JacobianImageType::Pointer m_JacobianImage[OutputDimension]; + typename JacobianImageType::Pointer m_PaddedJacobianImage[OutputDimension]; + typedef itk::ImageRegionIterator IteratorType; + + //JV for J calculation + IndexType m_NullIndex; + SizeType m_NullSize; + + mutable RegionType m_SupportRegion; + mutable IndexType m_SupportIndex; + mutable RegionType m_FirstRegion; + mutable RegionType m_SecondRegion; + mutable RegionType m_ThirdRegion; + mutable unsigned int m_ThirdSize; + mutable unsigned int m_InitialOffset; + + mutable std::vector m_BCIterators[SpaceDimension]; + mutable std::vector m_BCValues; + mutable std::vector m_BCRegions; + mutable unsigned int m_BCSize; + + mutable std::vector m_BC2Iterators[SpaceDimension]; + mutable std::vector m_BC2Values; + mutable std::vector m_BC2Regions; + mutable unsigned int m_BC2Size; + + mutable std::vector m_BC3Iterators[SpaceDimension]; + mutable std::vector m_BC3Values; + mutable std::vector m_BC3Regions; + mutable unsigned int m_BC3Size; + + mutable RegionType m_BCRegion; + mutable IteratorType m_FirstIterator[SpaceDimension]; + mutable IteratorType m_SecondIterator[SpaceDimension]; + mutable IteratorType m_ThirdIterator[SpaceDimension]; + mutable ContinuousIndexType m_Index; + + //JV add a padded Jacobian matrix + mutable JacobianType m_PaddedJacobian; + mutable JacobianPixelType m_ZeroVector; + + /** Keep track of last support region used in computing the Jacobian + * for fast resetting of Jacobian to zero. + */ + mutable IndexType m_LastJacobianIndex; + + /** Keep a pointer to the input parameters. */ + const ParametersType * m_InputParametersPointer; + + /** Internal parameters buffer. */ + ParametersType m_InternalParametersBuffer; + + //JV the BLUT interpolator + typename VectorInterpolatorType::Pointer m_VectorInterpolator; + + // the coefficients to apply the BC + std::vector > m_Weights; + std::vector > m_WeightRatio; + + /** Check if a continuous index is inside the valid region. */ + bool InsideValidRegion( const ContinuousIndexType& index ) const; + + // JV Shape + unsigned int m_TransformShape; + + + }; //class ShapedBLUTSpatioTemporalDeformableTransform + + +} // namespace itk + +#if ITK_TEMPLATE_TXX +# include "clitkShapedBLUTSpatioTemporalDeformableTransform.txx" +#endif + + +#endif // __clitkShapedBLUTSpatioTemporalDeformableTransform_h diff --git a/registration/clitkShapedBLUTSpatioTemporalDeformableTransform.txx b/registration/clitkShapedBLUTSpatioTemporalDeformableTransform.txx new file mode 100755 index 0000000..7600276 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDeformableTransform.txx @@ -0,0 +1,4340 @@ +/*========================================================================= + 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 __clitkShapedBLUTSpatioTemporalDeformableTransform_txx +#define __clitkShapedBLUTSpatioTemporalDeformableTransform_txx +#include "clitkShapedBLUTSpatioTemporalDeformableTransform.h" + +//itk +#include "itkContinuousIndex.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkIdentityTransform.h" + +namespace clitk +{ + + // Constructor with default arguments + template + ShapedBLUTSpatioTemporalDeformableTransform + ::ShapedBLUTSpatioTemporalDeformableTransform():Superclass(OutputDimension,0) + { + unsigned int i; + + //JV default spline order + for ( i=0;iSetLUTSamplingFactors(m_LUTSamplingFactors); + m_VectorInterpolator->SetSplineOrders(m_SplineOrders); + + // Set Bulk transform to NULL (no bulk performed) + m_BulkTransform = NULL; + + // Mask + m_Mask=NULL; + + // Shape + m_TransformShape=0; + + // Default grid size is zero + m_NullSize.Fill(0); + m_NullIndex.Fill(0); + + //JV region containing the parameters + m_GridRegion.SetSize( m_NullSize); + m_GridRegion.SetIndex( m_NullIndex ); + + //JV use second region over the images + m_PaddedGridRegion.SetSize(m_NullSize); + m_PaddedGridRegion.SetIndex(m_NullIndex); + + //JV Maintain two origins + m_GridOrigin.Fill( 0.0 ); // default origin is all zeros + m_PaddedGridOrigin.Fill( 0.0 ); // default origin is all zeros + + m_GridSpacing.Fill( 1.0 ); // default spacing is all ones + m_GridDirection.SetIdentity(); // default spacing is all ones + + m_InternalParametersBuffer = ParametersType(0); + // Make sure the parameters pointer is not NULL after construction. + m_InputParametersPointer = &m_InternalParametersBuffer; + + // Initialize coeffient images + m_WrappedImage = CoefficientImageType::New(); + m_WrappedImage->SetRegions( m_GridRegion ); + m_WrappedImage->SetOrigin( m_GridOrigin.GetDataPointer() ); + m_WrappedImage->SetSpacing( m_GridSpacing.GetDataPointer() ); + m_WrappedImage->SetDirection( m_GridDirection ); + + // JV Initialize the padded version + m_PaddedCoefficientImage = CoefficientImageType::New(); + m_PaddedCoefficientImage->SetRegions( m_PaddedGridRegion ); + m_PaddedCoefficientImage->SetOrigin( m_GridOrigin.GetDataPointer() ); + m_PaddedCoefficientImage->SetSpacing( m_GridSpacing.GetDataPointer() ); + m_PaddedCoefficientImage->SetDirection( m_GridDirection ); + + m_CoefficientImage = NULL; + + // Variables for computing interpolation + for (i=0; i SetRegions( m_GridRegion ); + m_JacobianImage[i]->SetOrigin( m_GridOrigin.GetDataPointer() ); + m_JacobianImage[i]->SetSpacing( m_GridSpacing.GetDataPointer() ); + m_JacobianImage[i]->SetDirection( m_GridDirection ); + } + + /** Fixed Parameters store the following information: + * Grid Size + * Grid Origin + * Grid Spacing + * Grid Direction */ + //JV we add the splineOrders, LUTsamplingfactor, m_Mask and m_BulkTransform + /* + Spline orders + Sampling factors + m_Mask + m_BulkTransform + The size of these is equal to the NInputDimensions + *********************************************************/ + this->m_FixedParameters.SetSize ( NInputDimensions * (NInputDimensions + 5)+3 ); + this->m_FixedParameters.Fill ( 0.0 ); + for ( i=0; im_FixedParameters[2*NInputDimensions+i] = m_GridSpacing[i]; + } + for (unsigned int di=0; dim_FixedParameters[3*NInputDimensions+(di*NInputDimensions+dj)] = m_GridDirection[di][dj]; + } + } + + //JV add splineOrders + for ( i=0; im_FixedParameters[ ( (3+NInputDimensions)*NInputDimensions)+i] = (this->GetSplineOrders())[i]; + } + + //JV add LUTsamplingFactors + for ( i=0; im_FixedParameters[( (4+NInputDimensions)*NInputDimensions)+i ] = this->GetLUTSamplingFactors()[i]; + } + + // JV add the mask pointer + this->m_FixedParameters[( (5+NInputDimensions)*NInputDimensions)]=(double)((size_t)m_Mask); + + // JV add the bulkTransform pointer + this->m_FixedParameters[( (5+NInputDimensions)*NInputDimensions) +1]=(double)((size_t)m_BulkTransform); + + // JV add the Transform shape + this->m_FixedParameters[( (5+NInputDimensions)*NInputDimensions) +2]=(double)(m_TransformShape); + + + // Calculate the PointToIndex matrices + DirectionType scale; + for( unsigned int i=0; i weights(5); + for (i=0; i<4; i++) + weights[0]=0; + // NN + weights[0]=1; + weights[1]=1./2; + weights[2]=0; + weights[3]=0; + weights[4]=0; + m_Weights[0]=weights; + + // Linear + weights[0]=1; + weights[1]=1./2; + weights[2]=0; + weights[3]=0; + weights[4]=0; + m_Weights[1]=weights; + + // quadratic + weights[0]=3./4.; + weights[1]=1./2.; + weights[2]=1./8.; + weights[3]=0; + weights[4]=0; + m_Weights[2]=weights; + + // cubic + weights[0]=2./3.; + weights[1]=23./48. ; + weights[2]=1./6.; + weights[3]=1./48.; + weights[4]=0; + m_Weights[3]=weights; + + // Update the WeightRatios + m_WeightRatio.resize(4); + for (unsigned int i=0; i<4; i++) + { + m_WeightRatio[i].resize(4); + for (unsigned int j=0; j<4; j++) + m_WeightRatio[i][j]=m_Weights[m_SplineOrders[InputDimension-1]][i]/ m_Weights[m_SplineOrders[InputDimension-1]][j]; + } + + //JV initialize some variables for jacobian calculation + m_SupportRegion.SetSize(m_SupportSize); + m_SupportIndex.Fill(0); + m_SupportRegion.SetIndex(m_SupportIndex); + for ( i = 0; i < SpaceDimension ; i++ ) + m_ZeroVector[i]=itk::NumericTraits::Zero; + + m_InitialOffset=0; + m_FirstRegion.SetSize(m_NullSize); + m_FirstRegion.SetIndex(m_NullIndex); + m_SecondRegion.SetSize(m_NullSize); + m_SecondRegion.SetIndex(m_NullIndex); + m_ThirdRegion.SetSize(m_NullSize); + m_ThirdRegion.SetIndex(m_NullIndex); + + m_BCValues.resize(0); + m_BCRegions.resize(0); + m_BCSize=0; + m_BC2Values.resize(0); + m_BC2Regions.resize(0); + m_BC2Size=0; + m_BC3Values.resize(0); + m_BC3Regions.resize(0); + m_BC3Size=0; + + + for ( i = 0; i < SpaceDimension ; i++ ) + { + m_FirstIterator[i]= IteratorType( m_JacobianImage[i], m_FirstRegion); + m_SecondIterator[i]= IteratorType( m_JacobianImage[i], m_SecondRegion); + m_ThirdIterator[i]= IteratorType( m_JacobianImage[i], m_ThirdRegion); + m_BCIterators[i].resize(0); + m_BC2Iterators[i].resize(0); + m_BC3Iterators[i].resize(0); + } + + this->Modified(); + + } + + + // Destructor + template + ShapedBLUTSpatioTemporalDeformableTransform + ::~ShapedBLUTSpatioTemporalDeformableTransform() + { + + } + + + // JV set Spline Order + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetSplineOrder(const unsigned int & splineOrder) + { + SizeType splineOrders; + for (unsigned int i=0;iSetSplineOrders(splineOrders); + } + + + // JV set Spline Orders + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetSplineOrders(const SizeType & splineOrders) + { + if(m_SplineOrders!=splineOrders) + { + m_SplineOrders=splineOrders; + + //update the interpolation function + m_VectorInterpolator->SetSplineOrders(m_SplineOrders); + + //update the varaibles for computing interpolation + for (unsigned int i=0; i Modified(); + } + } + + + // JV set sampling factor + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetLUTSamplingFactor( const int & samplingFactor) + { + SizeType samplingFactors; + for (unsigned int i=0; iSetLUTSamplingFactors(samplingFactors); + } + + + // JV set sampling factors + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetLUTSamplingFactors( const SizeType & samplingFactors) + { + if(m_LUTSamplingFactors!=samplingFactors) + { + for (unsigned int i=0; iSetLUTSamplingFactors(m_LUTSamplingFactors); + + this->Modified(); + } + } + + + // Get the number of parameters + template + unsigned int + ShapedBLUTSpatioTemporalDeformableTransform + ::GetNumberOfParameters(void) const + { + + // The number of parameters equal SpaceDimension * number of + // of pixels in the grid region. + return ( static_cast( SpaceDimension ) * + static_cast( m_GridRegion.GetNumberOfPixels() ) ); + + } + + + // Get the padded number of parameters + template + unsigned int + ShapedBLUTSpatioTemporalDeformableTransform + ::GetPaddedNumberOfParameters(void) const + { + + // The number of parameters equal SpaceDimension * number of + // of pixels in the grid region. + return ( static_cast( SpaceDimension ) * + static_cast( m_PaddedGridRegion.GetNumberOfPixels() ) ); + + } + + + + // Get the number of parameters per dimension + template + unsigned int + ShapedBLUTSpatioTemporalDeformableTransform + ::GetNumberOfParametersPerDimension(void) const + { + // The number of parameters per dimension equal number of + // of pixels in the grid region. + return ( static_cast( m_GridRegion.GetNumberOfPixels() ) ); + + } + + + // Set the grid region + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetGridRegion( const RegionType & region ) + { + if ( m_GridRegion != region ) + { + m_GridRegion = region; + m_PaddedGridRegion=region; + + // JV set the padded region + typename CoefficientImageType::RegionType::SizeType paddedSize= region.GetSize(); + + //JV size dependes on shape + switch (m_TransformShape) + { + case 0: + case 1: + paddedSize[InputDimension-1]+=4; + break; + case 2: + case 3: + paddedSize[InputDimension-1]+=4; + break; + case 4: + case 5: + paddedSize[InputDimension-1]+=3; + break; + case 6: + case 7: + paddedSize[InputDimension-1]+=2; + break; + case 8: + case 9: + paddedSize[InputDimension-1]+=3; + break; + default: + paddedSize[InputDimension-1]=+1; + } + m_PaddedGridRegion.SetSize(paddedSize); + + // Set regions for each coefficient and jacobian image + m_WrappedImage->SetRegions( m_GridRegion ); + m_PaddedCoefficientImage->SetRegions( m_PaddedGridRegion ); + m_PaddedCoefficientImage->Allocate(); + for (unsigned int j=0; j SetRegions( m_GridRegion ); + } + + // JV used the padded version for the valid region + // Set the valid region + // If the grid spans the interval [start, last]. + // The valid interval for evaluation is [start+offset, last-offset] + // when spline order is even. + // The valid interval for evaluation is [start+offset, last-offset) + // when spline order is odd. + // Where offset = vcl_floor(spline / 2 ). + // Note that the last pixel is not included in the valid region + // with odd spline orders. + typename RegionType::SizeType size = m_PaddedGridRegion.GetSize(); + typename RegionType::IndexType index = m_PaddedGridRegion.GetIndex(); + for ( unsigned int j = 0; j < NInputDimensions; j++ ) + { + index[j] += + static_cast< typename RegionType::IndexValueType >( m_Offset[j] ); + size[j] -= + static_cast< typename RegionType::SizeValueType> ( 2 * m_Offset[j] ); + m_ValidRegionLast[j] = index[j] + + static_cast< typename RegionType::IndexValueType >( size[j] ) - 1; + } + m_ValidRegion.SetSize( size ); + m_ValidRegion.SetIndex( index ); + + // If we are using the default parameters, update their size and set to identity. + // Input parameters point to internal buffer => using default parameters. + if (m_InputParametersPointer == &m_InternalParametersBuffer) + { + // Check if we need to resize the default parameter buffer. + if ( m_InternalParametersBuffer.GetSize() != this->GetNumberOfParameters() ) + { + m_InternalParametersBuffer.SetSize( this->GetNumberOfParameters() ); + // Fill with zeros for identity. + m_InternalParametersBuffer.Fill( 0 ); + } + } + + this->Modified(); + } + } + + + // Set the grid spacing + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetGridSpacing( const SpacingType & spacing ) + { + if ( m_GridSpacing != spacing ) + { + m_GridSpacing = spacing; + + // Set spacing for each coefficient and jacobian image + m_WrappedImage->SetSpacing( m_GridSpacing.GetDataPointer() ); + m_PaddedCoefficientImage->SetSpacing( m_GridSpacing.GetDataPointer() ); + for (unsigned int j=0; j SetSpacing( m_GridSpacing.GetDataPointer() ); + + // Set scale + DirectionType scale; + for( unsigned int i=0; iModified(); + } + + } + + // Set the grid direction + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetGridDirection( const DirectionType & direction ) + { + if ( m_GridDirection != direction ) + { + m_GridDirection = direction; + + // Set direction for each coefficient and jacobian image + m_WrappedImage->SetDirection( m_GridDirection ); + m_PaddedCoefficientImage->SetDirection( m_GridDirection ); + for (unsigned int j=0; j SetDirection( m_GridDirection ); + + // Set scale + DirectionType scale; + for( unsigned int i=0; iModified(); + } + + } + + + // Set the grid origin + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetGridOrigin( const OriginType& origin ) + { + if( m_GridOrigin!=origin) + { + m_GridOrigin = origin; + + // JV The origin depends on the shape + switch (m_TransformShape) + { + case 0: + case 1: + m_PaddedGridOrigin=origin; + m_PaddedGridOrigin[InputDimension-1]=origin[InputDimension-1]-2* m_GridSpacing[InputDimension-1]; + break; + case 2: + case 3: + m_PaddedGridOrigin=origin; + m_PaddedGridOrigin[InputDimension-1]=origin[InputDimension-1]-1* m_GridSpacing[InputDimension-1]; + break; + case 4: + case 5: + m_PaddedGridOrigin=origin; + m_PaddedGridOrigin[InputDimension-1]=origin[InputDimension-1]-1* m_GridSpacing[InputDimension-1]; + break; + case 6: + case 7: + m_PaddedGridOrigin=origin; + break; + case 8: + case 9: + m_PaddedGridOrigin=origin; + m_PaddedGridOrigin[InputDimension-1]=origin[InputDimension-1]-1* m_GridSpacing[InputDimension-1]; + break; + default: + m_PaddedGridOrigin=origin; + } + + // Set origin for each coefficient and jacobianimage + m_WrappedImage->SetOrigin( m_GridOrigin.GetDataPointer() ); + m_PaddedCoefficientImage->SetOrigin( m_PaddedGridOrigin.GetDataPointer() ); + for (unsigned int j=0; j SetOrigin( m_GridOrigin.GetDataPointer() ); + + this->Modified(); + } + } + + + // Set the parameters + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetIdentity() + { + if( m_InputParametersPointer ) + { + ParametersType * parameters = + const_cast( m_InputParametersPointer ); + parameters->Fill( 0.0 ); + this->Modified(); + } + else + { + itkExceptionMacro( << "Input parameters for the spline haven't been set ! " + << "Set them using the SetParameters or SetCoefficientImage method first." ); + } + } + + + // Set the parameters + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetParameters( const ParametersType & parameters ) + { + + // Check if the number of parameters match the + // Expected number of parameters + if ( parameters.Size() != this->GetNumberOfParameters() ) + { + itkExceptionMacro(<<"Mismatched between parameters size " + << parameters.size() + << " and region size " + << m_GridRegion.GetNumberOfPixels() ); + } + + // Clean up buffered parameters + m_InternalParametersBuffer = ParametersType( 0 ); + + // Keep a reference to the input parameters + m_InputParametersPointer = ¶meters; + + // Wrap flat array as images of coefficients + this->WrapAsImages(); + + //JV Set padded input to vector interpolator + m_VectorInterpolator->SetInputImage(this->GetPaddedCoefficientImage()); + + // Modified is always called since we just have a pointer to the + // parameters and cannot know if the parameters have changed. + this->Modified(); + } + + + // Set the Fixed Parameters + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetFixedParameters( const ParametersType & parameters ) + { + + // JV number should be exact, no defaults for spacing + if ( parameters.Size() != NInputDimensions * (5 + NInputDimensions)+3 ) + { + itkExceptionMacro(<< "Mismatched between parameters size " + << parameters.size() + << " and number of fixed parameters " + << NInputDimensions * (5 + NInputDimensions)+3 ); + } + /********************************************************* + Fixed Parameters store the following information: + Grid Size + Grid Origin + Grid Spacing + Grid Direction */ + // JV we add the splineOrders, LUTsamplingfactor, mask pointer and bulktransform pointer + /* + Spline orders + Sampling factors + m_Mask + m_BulkTransform + m_TransformShape + + The size of these is equal to the NInputDimensions + *********************************************************/ + + /** Set the Grid Parameters */ + SizeType gridSize; + for (unsigned int i=0; i (parameters[i]); + } + RegionType bsplineRegion; + bsplineRegion.SetSize( gridSize ); + + /** Set the Origin Parameters */ + OriginType origin; + for (unsigned int i=0; iSetSplineOrders( splineOrders ); + this->SetGridSpacing( spacing ); + this->SetGridDirection( direction ); + this->SetGridOrigin( origin ); + this->SetGridRegion( bsplineRegion ); + this->SetLUTSamplingFactors( samplingFactors ); + + } + + + // Wrap flat parameters as images + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::WrapAsImages() + { + //JV Wrap parameter array in vectorial image, changed parameter order: A1x A1y A1z, A2x .... + PixelType * dataPointer =reinterpret_cast( const_cast(m_InputParametersPointer->data_block() )) ; + unsigned int numberOfPixels = m_GridRegion.GetNumberOfPixels(); + + m_WrappedImage->GetPixelContainer()->SetImportPointer( dataPointer,numberOfPixels);//InputDimension + m_CoefficientImage = m_WrappedImage; + + //===================================== + //JV Create padded structure adding BC + //===================================== + PadCoefficientImage(); + + //===================================== + //JV Wrap jacobian into OutputDimension X Vectorial images + //===================================== + this->m_Jacobian.set_size( OutputDimension, this->GetNumberOfParameters() ); + + // Use memset to set the memory + // JV four rows of three comps of parameters + JacobianPixelType * jacobianDataPointer = reinterpret_cast(this->m_Jacobian.data_block()); + memset(jacobianDataPointer, 0, OutputDimension*numberOfPixels*sizeof(JacobianPixelType)); + + for (unsigned int j=0; jGetPixelContainer()-> + SetImportPointer( jacobianDataPointer, numberOfPixels ); + jacobianDataPointer += numberOfPixels; + } + + // Reset the J parameters + m_LastJacobianIndex = m_ValidRegion.GetIndex(); + m_FirstRegion.SetSize(m_NullSize); + m_SecondRegion.SetSize(m_NullSize); + for ( unsigned int j = 0; j < SpaceDimension ; j++ ) + { + m_FirstIterator[j]= IteratorType( m_JacobianImage[j], m_FirstRegion); + m_SecondIterator[j]= IteratorType( m_JacobianImage[j], m_SecondRegion); + } + + m_BCValues.resize(0); + m_BCRegions.resize(0); + m_BCSize=0; + m_BC2Values.resize(0); + m_BC2Regions.resize(0); + m_BC2Size=0; + m_BC3Values.resize(0); + m_BC3Regions.resize(0); + m_BC3Size=0; + + } + + + // Set the parameters by value + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetParametersByValue( const ParametersType & parameters ) + { + + // Check if the number of parameters match the + // Expected number of parameters + if ( parameters.Size() != this->GetNumberOfParameters() ) + { + itkExceptionMacro(<<"Mismatched between parameters size " + << parameters.size() + << " and region size " + << m_GridRegion.GetNumberOfPixels() ); + } + + // Copy it + m_InternalParametersBuffer = parameters; + m_InputParametersPointer = &m_InternalParametersBuffer; + + // Wrap flat array as images of coefficients + this->WrapAsImages(); + + //JV Set padded input to vector interpolator + m_VectorInterpolator->SetInputImage(this->GetPaddedCoefficientImage()); + + // Modified is always called since we just have a pointer to the + // Parameters and cannot know if the parameters have changed. + this->Modified(); + + } + + // Get the parameters + template + const + typename ShapedBLUTSpatioTemporalDeformableTransform + ::ParametersType & + ShapedBLUTSpatioTemporalDeformableTransform + ::GetParameters( void ) const + { + /** NOTE: For efficiency, this class does not keep a copy of the parameters - + * it just keeps pointer to input parameters. + */ + if (NULL == m_InputParametersPointer) + { + itkExceptionMacro( <<"Cannot GetParameters() because m_InputParametersPointer is NULL. Perhaps SetCoefficientImage() has been called causing the NULL pointer." ); + } + + return (*m_InputParametersPointer); + } + + + // Get the parameters + template + const + typename ShapedBLUTSpatioTemporalDeformableTransform + ::ParametersType & + ShapedBLUTSpatioTemporalDeformableTransform + ::GetFixedParameters( void ) const + { + RegionType resRegion = this->GetGridRegion( ); + + for (unsigned int i=0; im_FixedParameters[i] = (resRegion.GetSize())[i]; + } + for (unsigned int i=0; im_FixedParameters[NInputDimensions+i] = (this->GetGridOrigin())[i]; + } + for (unsigned int i=0; im_FixedParameters[2*NInputDimensions+i] = (this->GetGridSpacing())[i]; + } + for (unsigned int di=0; dim_FixedParameters[3*NInputDimensions+(di*NInputDimensions+dj)] = (this->GetGridDirection())[di][dj]; + } + } + + //JV add splineOrders + for (unsigned int i=0; im_FixedParameters[(3+NInputDimensions)*NInputDimensions+i] = (this->GetSplineOrders())[i]; + } + + //JV add LUTsamplingFactor + for (unsigned int i=0; im_FixedParameters[(4+NInputDimensions)*NInputDimensions+i] = (this->GetLUTSamplingFactors())[i]; + } + + //JV add the mask + this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions]=(double)((size_t) m_Mask); + + //JV add the bulktransform pointer + this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions+1]=(double)((size_t) m_BulkTransform); + + //JV add the transform shape + this->m_FixedParameters[(5+NInputDimensions)*NInputDimensions+2]=(double)( m_TransformShape); + + return (this->m_FixedParameters); + } + + + // Set the B-Spline coefficients using input images + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::SetCoefficientImage( CoefficientImagePointer image ) + { + this->SetGridSpacing( image->GetSpacing() ); + this->SetGridOrigin( image->GetOrigin() ); + this->SetGridDirection( image->GetDirection() ); + this->SetGridRegion( image->GetBufferedRegion() ); + m_CoefficientImage = image; + + //JV + // m_WrappedImage=m_CoefficientImage; + + // Update the interpolator + this->PadCoefficientImage(); + m_VectorInterpolator->SetInputImage(this->GetPaddedCoefficientImage()); + + // Clean up buffered parameters + m_InternalParametersBuffer = ParametersType( 0 ); + m_InputParametersPointer = NULL; + + } + + + // // Set the B-Spline coefficients using input images + // template + // void + // ShapedBLUTSpatioTemporalDeformableTransform + // ::SetPaddedCoefficientImage( CoefficientImagePointer image ) + // { + // //JV modify the region + // typename CoefficientImageType::RegionType region=image->GetBufferedRegion(); + // typename CoefficientImageType::RegionType::SizeType size=region.GetSize(); + // size[InputDimension-1]-=2; + // region.SetSize(size); + + // //Set properties + // this->SetGridRegion( region ); + // this->SetGridSpacing( image->GetSpacing() ); + // this->SetGridDirection( image->GetDirection() ); + // this->SetGridOrigin( image->GetOrigin() ); + // m_PaddedCoefficientImage = image; + // this->ExtractCoefficientImage(); + // m_VectorInterpolator->SetInputImage(this->GetPaddedCoefficientImage()); + + // // Clean up buffered parameters + // m_InternalParametersBuffer = ParametersType( 0 ); + // m_InputParametersPointer = NULL; + + // } + + // Set the B-Spline coefficients using input images + template + typename ShapedBLUTSpatioTemporalDeformableTransform::CoefficientImageType::Pointer + ShapedBLUTSpatioTemporalDeformableTransform + ::ExtractTemporalRow(const typename CoefficientImageType::Pointer& coefficientImage, unsigned int temporalIndex) + { + // Region + typename CoefficientImageType::RegionType sourceRegion=coefficientImage->GetLargestPossibleRegion(); + sourceRegion.SetSize(InputDimension-1, 1); + sourceRegion.SetIndex(InputDimension-1, temporalIndex); + + // Extract + typedef clitk::ExtractImageFilter ExtractImageFilterType; + typename ExtractImageFilterType::Pointer extract=ExtractImageFilterType::New(); + extract->SetInput(coefficientImage); + extract->SetExtractionRegion(sourceRegion); + extract->Update(); + typename CoefficientImageType::Pointer row= extract->GetOutput(); + + // Set index to zero + sourceRegion.SetIndex(InputDimension-1, 0); + row->SetRegions(sourceRegion); + return row; + + } + + // Set the B-Spline coefficients using input images + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::PadCoefficientImage(void) + { + + // Define paste, extract and combine filters + typedef itk::PasteImageFilter PasteImageFilterType; + typedef clitk::ExtractImageFilter ExtractImageFilterType; + typedef clitk::LinearCombinationImageFilter LinearCombinationFilterType; + typedef itk::MultiplyByConstantImageFilter MultiplicationFilterType; + + // Regions + typename CoefficientImageType::RegionType sourceRegion=m_PaddedCoefficientImage->GetLargestPossibleRegion(); + typename CoefficientImageType::RegionType destinationRegion=m_PaddedCoefficientImage->GetLargestPossibleRegion(); + typename CoefficientImageType::RegionType::SizeType sourceSize=sourceRegion.GetSize(); + typename CoefficientImageType::RegionType::SizeType destinationSize=destinationRegion.GetSize(); + typename CoefficientImageType::IndexType sourceIndex=sourceRegion.GetIndex(); + typename CoefficientImageType::IndexType destinationIndex=destinationRegion.GetIndex(); + + // JV Padding depends on the shape + switch (m_TransformShape) + { + /* The shapes are + 0: egg 4 CP 3 DOF + 1: egg 5 CP 4 DOF + 2: rabbit 4 CP 3 DOF + 3: rabbit 5 CP 4 DOF + 4: sputnik 4 CP 4 DOF + 5: sputnik 5 CP 5 DOF + 6: diamond 6 CP 5 DOF + 7: diamond 7 CP 6 DOF + */ + + case 0: + { + // ---------------------------------------------------------------------- + // The egg with 4 internal CP (starting from inhale) + // Periodic, constrained to zero at the reference + // at position 3 and + // Coeff row BC1 BC2 0 BC3 1 2 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 + // BC1= R4 + // BC2= R5 + // BC3= -weights[2]/weights[0] ( R2+R4 ) + // BC4= R2 + // --------------------------------------------------------------------- + + //--------------------------------- + // 1. First two temporal rows are identical: paste 1-2 to 0-1 + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(NInputDimensions-1,1); + sourceRegion.SetSize(NInputDimensions-1,2); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 1. Next temporal row = paste 0 to 2 + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(row0); + destinationIndex[InputDimension-1]=2; + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(row0->GetLargestPossibleRegion()); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 2 (of coeff image) + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row0); + combine1->SetInput(1,row1); + combine1->SetA(-m_WeightRatio[2][0]); + combine1->SetB(-m_WeightRatio[2][0]); + combine1->Update(); + typename CoefficientImageType::Pointer bc3Row=combine1->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc3Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc3Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next two temporal rows identical: paste 1,2 to 4,5 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(InputDimension-1,1); + sourceRegion.SetSize(InputDimension-1,2); + destinationIndex[InputDimension-1]=4; + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(sourceRegion); + + // --------------------------------- + // 4. Row at index 6=BC4= R2 + // Paste BC3 row at index 5 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(row0); + destinationIndex[InputDimension-1]=6; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(row0->GetLargestPossibleRegion()); + + // Update the chain! + paster4->Update(); + m_PaddedCoefficientImage= paster4->GetOutput(); + + break; + } + + case 1: + { + // ---------------------------------------------------------------------- + // The egg with 5 internal CP (starting from inhale) + // Periodic, constrained to zero at the reference + // at position 3 and + // Coeff row BC1 BC2 0 BC3 1 2 3 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= R5 + // BC2= R6 + // BC3= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC4= R2 + // --------------------------------------------------------------------- + //--------------------------------- + // 1. First two temporal rows are identical: paste 2-3 to 0-1 + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(NInputDimensions-1,2); + sourceRegion.SetSize(NInputDimensions-1,2); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 1. Next temporal row = paste 0 to 2 + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(row0); + destinationIndex[InputDimension-1]=2; + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(row0->GetLargestPossibleRegion()); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 2 (of coeff image) + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row0); + combine1->SetInput(1,row2); + combine1->SetA(1); + combine1->SetB(1); + // combine1->Update(); + typename LinearCombinationFilterType::Pointer combine2=LinearCombinationFilterType::New(); + combine2->SetInput(0,row1); + combine2->SetInput(1,combine1->GetOutput()); + combine2->SetA(-1.); + combine2->SetB(-m_WeightRatio[3][1]); + combine2->Update(); + typename CoefficientImageType::Pointer bc3Row=combine2->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc3Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc3Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next three temporal rows identical: paste 1,2,3 to 4,5,6 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(InputDimension-1,1); + sourceRegion.SetSize(InputDimension-1,3); + destinationIndex[InputDimension-1]=4; + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(sourceRegion); + + // --------------------------------- + // 4. Row at index 7=BC4= R2 + // Paste BC3 row at index 5 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(row0); + destinationIndex[InputDimension-1]=7; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(row0->GetLargestPossibleRegion()); + + // Update the chain! + paster4->Update(); + m_PaddedCoefficientImage= paster4->GetOutput(); + + break; + } + + +// // ---------------------------------------------------------------------- +// // The egg with 5 internal CP: +// // Periodic, C2 smooth everywhere and constrained to zero at the reference +// // Coeff row R5 BC1 0 1 2 3 BC2 R2 +// // PaddedCoeff R: 0 1 2 3 4 5 6 7 +// // BC1= -weights[2]/weights[0] ( R2+R5) +// // BC2= BC1 +// // --------------------------------------------------------------------- + +// // Extract rows with index 0 and 3 +// typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); +// typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + +// // Paste the first row +// typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); +// destinationIndex.Fill(0); +// paster1->SetDestinationIndex(destinationIndex); +// paster1->SetSourceRegion(row3->GetLargestPossibleRegion()); +// paster1->SetSourceImage(row3); +// paster1->SetDestinationImage(m_PaddedCoefficientImage); + +// // Linearly Combine rows for BC1 and BC2 +// typedef clitk::LinearCombinationImageFilter LinearCombinationFilterType; +// typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); +// combine1->SetFirstInput(row0); +// combine1->SetSecondInput(row3); +// combine1->SetA(-m_WeightRatio[2][0]); +// combine1->SetB(-m_WeightRatio[2][0]); +// combine1->Update(); +// typename CoefficientImageType::Pointer bcRow=combine1->GetOutput(); + +// // Paste the second row +// typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); +// destinationIndex[InputDimension-1]=1; +// paster2->SetDestinationIndex(destinationIndex); +// paster2->SetSourceRegion(bcRow->GetLargestPossibleRegion()); +// paster2->SetSourceImage(bcRow); +// paster2->SetDestinationImage(paster1->GetOutput()); + +// // Paste the coefficientImage +// typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); +// destinationIndex[InputDimension-1]=2; +// paster3->SetDestinationIndex(destinationIndex); +// paster3->SetSourceRegion(m_CoefficientImage->GetLargestPossibleRegion()); +// paster3->SetSourceImage(m_CoefficientImage); +// paster3->SetDestinationImage(paster2->GetOutput()); + +// // Paste the last two rows +// typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); +// destinationIndex[InputDimension-1]=6; +// paster4->SetDestinationIndex(destinationIndex); +// paster4->SetSourceRegion(bcRow->GetLargestPossibleRegion()); +// paster4->SetSourceImage(bcRow); +// paster4->SetDestinationImage(paster3->GetOutput()); + +// typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); +// destinationIndex[InputDimension-1]=7; +// paster5->SetDestinationIndex(destinationIndex); +// paster5->SetSourceRegion(row0->GetLargestPossibleRegion()); +// paster5->SetSourceImage(row0); +// paster5->SetDestinationImage(paster4->GetOutput()); + +// // Update the chain! +// paster5->Update(); +// m_PaddedCoefficientImage= paster5->GetOutput(); + +// break; +// } + + case 2: + { + // ---------------------------------------------------------------------- + // The rabbit with 4 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and the extremes fixed with anit-symm bc + // Coeff row BC1 0 1 BC2 2 BC3 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 + // BC1= 2*R1-R2 + // BC2= -weights[2]/weights[0] ( R2+R4 ) + // BC3= R1 + // BC4= 2*R1-R4 + // --------------------------------------------------------------------- + + // --------------------------------- + // 0. First Row =BC1 + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename LinearCombinationFilterType::Pointer combine0=LinearCombinationFilterType::New(); + combine0->SetInput(0,row0); + combine0->SetInput(1,row1); + combine0->SetA(2.); + combine0->SetB(-1.); + combine0->Update(); + typename CoefficientImageType::Pointer bc1Row=combine0->GetOutput(); + + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 1. Next two temporal rows are identical: paste 0-1 to 1-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(NInputDimensions-1,0); + destinationIndex[InputDimension-1]=1; + sourceRegion.SetSize(NInputDimensions-1,2); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 2 (of coeff image) + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row1); + combine1->SetInput(1,row2); + combine1->SetA(-m_WeightRatio[2][0]); + combine1->SetB(-m_WeightRatio[2][0]); + combine1->Update(); + typename CoefficientImageType::Pointer bc2Row=combine1->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next temporal row is identical: paste 2 to 4 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(row2); + destinationIndex[InputDimension-1]=4; + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(row2->GetLargestPossibleRegion()); + + // --------------------------------- + // 4. Row at index 5=BC (paddedcoeff image) R1 + // Paste BC3 row at index 5 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(row0); + destinationIndex[InputDimension-1]=5; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(row0->GetLargestPossibleRegion()); + + // --------------------------------- + // 5. Paste BC4 row at index 6 + typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + combine3->SetInput(0,row0); + combine3->SetInput(1,row2); + combine3->SetA(2.); + combine3->SetB(-1.); + combine3->Update(); + typename CoefficientImageType::Pointer bc4Row=combine3->GetOutput(); + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(bc4Row); + destinationIndex[InputDimension-1]=6; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(bc4Row->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + + case 3: + { + // ---------------------------------------------------------------------- + // The rabbit with 5 internal CP + // Periodic, constrained to zero at the reference at position 3.5 + // and the extremes fixed with anti-symmetrical BC + // Coeff row BC1 0 1 BC2 2 3 BC3 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= 2*R1-R2 + // BC2= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC3= R1 + // BC4= 2*R1-R5 + // --------------------------------------------------------------------- + + // --------------------------------- + // 0. First Row =BC1 + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename LinearCombinationFilterType::Pointer combine0=LinearCombinationFilterType::New(); + combine0->SetInput(0,row0); + combine0->SetInput(1,row1); + combine0->SetA(2.); + combine0->SetB(-1.); + combine0->Update(); + typename CoefficientImageType::Pointer bc1Row=combine0->GetOutput(); + + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 1. Next two temporal rows are identical: paste 0-1 to 1-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(InputDimension-1,0); + destinationIndex[InputDimension-1]=1; + sourceRegion.SetSize(NInputDimensions-1,2); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 3 (of coeff image) + //typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row1); + combine1->SetInput(1,row3); + combine1->SetA(1.); + combine1->SetB(1.); + combine1->Update(); + + // Extract row at index 2 (coeff image) + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + + // Combine + typename LinearCombinationFilterType::Pointer combine2=LinearCombinationFilterType::New(); + combine2->SetInput(0,combine1->GetOutput()); + combine2->SetInput(1,row2); + combine2->SetA(-m_WeightRatio[3][1]); + combine2->SetB(-1.); + combine2->Update(); + typename CoefficientImageType::Pointer bc2Row=combine2->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next two temporal rows are identical: paste 2,3 to 4,5 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(InputDimension-1,2); + destinationIndex[InputDimension-1]=4; + sourceRegion.SetSize(NInputDimensions-1,2); + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(sourceRegion); + + // --------------------------------- + // 4. Row at index 6=BC (paddedcoeff image)R1 + // Paste BC3 row at index 6 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(row0); + destinationIndex[InputDimension-1]=6; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(row0->GetLargestPossibleRegion()); + + // --------------------------------- + // 5. Paste BC4 row at index 7 + typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + combine3->SetInput(0,row0); + combine3->SetInput(1,row3); + combine3->SetA(2.); + combine3->SetB(-1.); + combine3->Update(); + typename CoefficientImageType::Pointer bc4Row=combine3->GetOutput(); + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(bc4Row); + destinationIndex[InputDimension-1]=7; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(bc4Row->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + + case 4: + { + // ---------------------------------------------------------------------- + // The sputnik with 4 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and one indepent extremes copied + // Coeff row BC1 0 1 BC2 2 BC2 3 + // PaddedCoeff R: 0 1 2 3 4 5 6 + // BC1= R6 + // BC2= -weights[2]/weights[0] ( R2+R4 ) + // BC3= weights[2]/weights[0] ( R2-R4) + R1 + // --------------------------------------------------------------------- + + //--------------------------------- + // 1. First Row is equal to last row: paste 3 row to 0 + typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(row3); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(row3->GetLargestPossibleRegion()); + + //--------------------------------- + // 1. Next two temporal rows are identical: paste 0-1 to 1-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(NInputDimensions-1,0); + destinationIndex[InputDimension-1]=1; + sourceRegion.SetSize(NInputDimensions-1,2); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 2 (of coeff image) + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row1); + combine1->SetInput(1,row2); + combine1->SetA(-m_WeightRatio[2][0]); + combine1->SetB(-m_WeightRatio[2][0]); + combine1->Update(); + typename CoefficientImageType::Pointer bc1Row=combine1->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next temporal row is identical: paste 2 to 4 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(row2); + destinationIndex[InputDimension-1]=4; + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(row2->GetLargestPossibleRegion()); + + //--------------------------------- + // 4. Final row at index 5=BC3 (paddedcoeff image)R1 R2 R4 corresponds to index in coeff image 0 1 2 + // Extract row at index 1, 2 (of coeff image)already done + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + + // Combine + typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + combine3->SetInput(0,row1); + combine3->SetInput(1,row2); + combine3->SetA(1.); + combine3->SetB(-1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine4=LinearCombinationFilterType::New(); + combine4->SetInput(0,combine3->GetOutput()); + combine4->SetInput(1,row0); + combine4->SetA(m_WeightRatio[2][0]); + combine4->SetB(1.); + combine4->Update(); + typename CoefficientImageType::Pointer bc2Row=combine4->GetOutput(); + + // Paste BC row at index 5 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=5; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + // Paste row 3 at index 6 + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(row3); + destinationIndex[InputDimension-1]=6; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(row3->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + + case 5: + { + + // ---------------------------------------------------------------------- + // The sputnik with 5 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and one indepent extreme + // Coeff row BC1 0 1 BC2 2 3 BC3 4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= R2 + R5 - R7 + // BC2= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC3= R1 + 0.5 R2 - 0.5 R7 + // ---------------------------------------------------------------------- + //--------------------------------- + // 1. First Row =BC + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + typename CoefficientImageType::Pointer row4=this->ExtractTemporalRow(m_CoefficientImage, 4); + + // Combine + typename LinearCombinationFilterType::Pointer combine0=LinearCombinationFilterType::New(); + combine0->SetInput(0,row1); + combine0->SetInput(1,row3); + combine0->SetA(1.); + combine0->SetB(1.); + //combine0->Update(); + typename LinearCombinationFilterType::Pointer combine0bis=LinearCombinationFilterType::New(); + combine0bis->SetInput(0,combine0->GetOutput()); + combine0bis->SetInput(1,row4); + combine0bis->SetA(1.); + combine0bis->SetB(-1.); + combine0bis->Update(); + typename CoefficientImageType::Pointer bc1Row=combine0bis->GetOutput(); + + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 1. Next two temporal rows are identical: paste 0-1 to 1-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(NInputDimensions-1,0); + destinationIndex[InputDimension-1]=1; + sourceRegion.SetSize(NInputDimensions-1,2); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 2 (of coeff image) + //typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row1); + combine1->SetInput(1,row3); + combine1->SetA(1.); + combine1->SetB(1.); + combine1->Update(); + + typename LinearCombinationFilterType::Pointer combine2=LinearCombinationFilterType::New(); + combine2->SetInput(0,combine1->GetOutput()); + combine2->SetInput(1,row2); + combine2->SetA(-m_WeightRatio[3][1]); + combine2->SetB(-1.); + combine2->Update(); + typename CoefficientImageType::Pointer bc2Row=combine2->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next two temporal rows are identical: paste 2,3 to 4,5 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(InputDimension-1,2); + destinationIndex[InputDimension-1]=4; + sourceRegion.SetSize(NInputDimensions-1,2); + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 4. Final row at index 6=BC3 + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + + // Combine + typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + combine3->SetInput(0,row1); + combine3->SetInput(1,row4); + combine3->SetA(1.); + combine3->SetB(-1.); + typename LinearCombinationFilterType::Pointer combine4=LinearCombinationFilterType::New(); + combine4->SetInput(0,row0); + combine4->SetInput(1,combine3->GetOutput()); + combine4->SetA(1.); + combine4->SetB(.5); + combine4->Update(); + typename CoefficientImageType::Pointer bc3Row=combine4->GetOutput(); + + // Paste BC row at index 6 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(bc3Row); + destinationIndex[InputDimension-1]=6; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(bc3Row->GetLargestPossibleRegion()); + + // Paste row 4 at index 7 + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(row4); + destinationIndex[InputDimension-1]=7; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(row4->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + + case 6: + { + // ---------------------------------------------------------------------- + // The diamond with 4 internal CP: + // Periodic, constrained to zero at the reference at position 3 + // Coeff row 0 1 2 BC1 3 BC2 4 + // PaddedCoeff R:0 1 2 3 4 5 6 + // BC1= -weights[2]/weights[0] ( R2+R4 ) + // BC2= weights[2]/weights[0] ( R0+R2-R4-R6 ) + R1 + // --------------------------------------------------------------------- + + //--------------------------------- + // 1. First Three temporal rows are identical: paste 0-2 to 0-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(m_PaddedCoefficientImage); + paster1->SetSourceImage(m_CoefficientImage); + sourceIndex.Fill(0); + destinationIndex.Fill(0); + sourceSize[NInputDimensions-1]=3; + sourceRegion.SetSize(sourceSize); + sourceRegion.SetIndex(sourceIndex); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 0, 4 (of coeff image) + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row2); + combine1->SetInput(1,row3); + combine1->SetA(-m_WeightRatio[2][0]); + combine1->SetB(-m_WeightRatio[2][0]); + combine1->Update(); + typename CoefficientImageType::Pointer bc1Row=combine1->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next row identical: paste 3 to 4 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(row3); + destinationIndex[InputDimension-1]=4; + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(row3->GetLargestPossibleRegion()); + + //--------------------------------- + // 4. Final row at index 6=BC (paddedcoeff image)R0 R2 R5 R7 R1 corresponds to index in coeff image 0 2 4 5 1 + // Extract row at index 0, 2 (of coeff image)already done + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + typename CoefficientImageType::Pointer row4=this->ExtractTemporalRow(m_CoefficientImage, 4); + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + + // Combine + typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + combine3->SetInput(0,row0); + combine3->SetInput(1,row2); + combine3->SetA(1.); + combine3->SetB(1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine4=LinearCombinationFilterType::New(); + combine4->SetInput(0,row3); + combine4->SetInput(1,row4); + combine4->SetA(1.); + combine4->SetB(1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine5=LinearCombinationFilterType::New(); + combine5->SetInput(0,combine3->GetOutput()); + combine5->SetInput(1,combine4->GetOutput()); + combine5->SetA(1.); + combine5->SetB(-1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine6=LinearCombinationFilterType::New(); + combine6->SetInput(0,combine5->GetOutput()); + combine6->SetInput(1,row1); + combine6->SetA(m_WeightRatio[2][0]); + combine6->SetB(1.); + combine6->Update(); + typename CoefficientImageType::Pointer bc2Row=combine6->GetOutput(); + + // Paste BC row at index 5 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=5; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + // Paste last row at index 6 + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(row4); + destinationIndex[InputDimension-1]=6; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(row4->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + case 7: + { + // ---------------------------------------------------------------------- + // The diamond with 5 internal CP: + // periodic, constrained to zero at the reference at position 3.5 + // Coeff row 0 1 2 BC1 3 4 BC2 5 + // PaddedCoeff R:0 1 2 3 4 5 6 7 + // BC1= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC2= weights[2]/weights[0] ( R0+R2-R5-R7 ) + R1 + // --------------------------------------------------------------------- + + //--------------------------------- + // 1. First Three temporal rows are identical: paste 0-2 to 0-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(m_PaddedCoefficientImage); + paster1->SetSourceImage(m_CoefficientImage); + sourceIndex.Fill(0); + destinationIndex.Fill(0); + sourceSize[NInputDimensions-1]=3; + sourceRegion.SetSize(sourceSize); + sourceRegion.SetIndex(sourceIndex); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 0, 4 (of coeff image) + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + typename CoefficientImageType::Pointer row4=this->ExtractTemporalRow(m_CoefficientImage, 4); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row2); + combine1->SetInput(1,row4); + combine1->SetA(1.); + combine1->SetB(1.); + combine1->Update(); + + // Extract row at index 3 (coeff image) + typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + + // Combine + typename LinearCombinationFilterType::Pointer combine2=LinearCombinationFilterType::New(); + combine2->SetInput(0,combine1->GetOutput()); + combine2->SetInput(1,row3); + combine2->SetA(-m_WeightRatio[3][1] ); + combine2->SetB(-1.); + combine2->Update(); + typename CoefficientImageType::Pointer bc1Row=combine2->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next two temporal rows are identical: paste 3,4 to 4,5 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(m_CoefficientImage); + sourceIndex[InputDimension-1]=3; + destinationIndex[InputDimension-1]=4; + sourceSize[NInputDimensions-1]=2; + sourceRegion.SetSize(sourceSize); + sourceRegion.SetIndex(sourceIndex); + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 4. Final row at index 6=BC (paddedcoeff image)R0 R2 R5 R7 R1 corresponds to index in coeff image 0 2 4 5 1 + // Extract row at index 0, 2 (of coeff image)already done + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + typename CoefficientImageType::Pointer row5=this->ExtractTemporalRow(m_CoefficientImage, 5); + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + + // Combine + typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + combine3->SetInput(0,row0); + combine3->SetInput(1,row2); + combine3->SetA(1.); + combine3->SetB(1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine4=LinearCombinationFilterType::New(); + combine4->SetInput(0,row4); + combine4->SetInput(1,row5); + combine4->SetA(1.); + combine4->SetB(1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine5=LinearCombinationFilterType::New(); + combine5->SetInput(0,combine3->GetOutput()); + combine5->SetInput(1,combine4->GetOutput()); + combine5->SetA(1.); + combine5->SetB(-1.); + + // Combine + typename LinearCombinationFilterType::Pointer combine6=LinearCombinationFilterType::New(); + combine6->SetInput(0,combine5->GetOutput()); + combine6->SetInput(1,row1); + combine6->SetA(m_WeightRatio[2][0]); + combine6->SetB(1.); + combine6->Update(); + typename CoefficientImageType::Pointer bc2Row=combine6->GetOutput(); + + // Paste BC row at index 6 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=6; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + // Paste last row at index 7 + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(row5); + destinationIndex[InputDimension-1]=7; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(row5->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + + case 9: + { + // ---------------------------------------------------------------------- + // The sputnik with 5 internal CP T''(0)=T''(10) + // Periodic, constrained to zero at the reference + // at position 3 and one indepent extreme + // Coeff row BC1 0 1 BC2 2 3 BC3 4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= -R2+R5+R7 + // BC2= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC3= R1 + // --------------------------------------------------------------------- + + //--------------------------------- + // 1. First Row =BC + typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row3=this->ExtractTemporalRow(m_CoefficientImage, 3); + typename CoefficientImageType::Pointer row4=this->ExtractTemporalRow(m_CoefficientImage, 4); + + // Combine + typename LinearCombinationFilterType::Pointer combine0=LinearCombinationFilterType::New(); + combine0->SetInput(0,row3); + combine0->SetInput(1,row4); + combine0->SetA(1.); + combine0->SetB(1.); + typename LinearCombinationFilterType::Pointer combine0bis=LinearCombinationFilterType::New(); + combine0bis->SetInput(0,combine0->GetOutput()); + combine0bis->SetInput(1,row1); + combine0bis->SetA(1.); + combine0bis->SetB(-1.); + combine0bis->Update(); + typename CoefficientImageType::Pointer bc1Row=combine0bis->GetOutput(); + + typename PasteImageFilterType::Pointer paster0=PasteImageFilterType::New(); + paster0->SetDestinationImage(m_PaddedCoefficientImage); + paster0->SetSourceImage(bc1Row); + destinationIndex[InputDimension-1]=0; + paster0->SetDestinationIndex(destinationIndex); + paster0->SetSourceRegion(bc1Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 1. Next two temporal rows are identical: paste 0-1 to 1-2 + typename PasteImageFilterType::Pointer paster1=PasteImageFilterType::New(); + paster1->SetDestinationImage(paster0->GetOutput()); + paster1->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(NInputDimensions-1,0); + destinationIndex[InputDimension-1]=1; + sourceRegion.SetSize(NInputDimensions-1,2); + paster1->SetDestinationIndex(destinationIndex); + paster1->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 2. Middle row at index 3=BC + // Extract row at index 1, 2 (of coeff image) + // typename CoefficientImageType::Pointer row1=this->ExtractTemporalRow(m_CoefficientImage, 1); + typename CoefficientImageType::Pointer row2=this->ExtractTemporalRow(m_CoefficientImage, 2); + + // Combine + typename LinearCombinationFilterType::Pointer combine1=LinearCombinationFilterType::New(); + combine1->SetInput(0,row1); + combine1->SetInput(1,row3); + combine1->SetA(1.); + combine1->SetB(1.); + combine1->Update(); + + typename LinearCombinationFilterType::Pointer combine2=LinearCombinationFilterType::New(); + combine2->SetInput(0,combine1->GetOutput()); + combine2->SetInput(1,row2); + combine2->SetA(-m_WeightRatio[3][1]); + combine2->SetB(-1.); + combine2->Update(); + typename CoefficientImageType::Pointer bc2Row=combine2->GetOutput(); + + // Paste middleRow at index 3 (padded coeff) + typename PasteImageFilterType::Pointer paster2=PasteImageFilterType::New(); + paster2->SetDestinationImage(paster1->GetOutput()); + paster2->SetSourceImage(bc2Row); + destinationIndex[InputDimension-1]=3; + paster2->SetDestinationIndex(destinationIndex); + paster2->SetSourceRegion(bc2Row->GetLargestPossibleRegion()); + + //--------------------------------- + // 3. Next two temporal rows are identical: paste 2,3 to 4,5 + typename PasteImageFilterType::Pointer paster3=PasteImageFilterType::New(); + paster3->SetDestinationImage(paster2->GetOutput()); + paster3->SetSourceImage(m_CoefficientImage); + sourceRegion.SetIndex(InputDimension-1,2); + destinationIndex[InputDimension-1]=4; + sourceRegion.SetSize(NInputDimensions-1,2); + paster3->SetDestinationIndex(destinationIndex); + paster3->SetSourceRegion(sourceRegion); + + //--------------------------------- + // 4. Final row at index 6=BC3 + typename CoefficientImageType::Pointer row0=this->ExtractTemporalRow(m_CoefficientImage, 0); + + // // Combine + // typename LinearCombinationFilterType::Pointer combine3=LinearCombinationFilterType::New(); + // combine3->SetInput(0,row0); + // combine3->SetInput(1,row1); + // combine3->SetA(1.); + // combine3->SetB(0.5); + // combine3->Update(); + // typename CoefficientImageType::Pointer bc3Row=combine3->GetOutput(); + + // Paste BC row at index 6 + typename PasteImageFilterType::Pointer paster4=PasteImageFilterType::New(); + paster4->SetDestinationImage(paster3->GetOutput()); + paster4->SetSourceImage(row0); + destinationIndex[InputDimension-1]=6; + paster4->SetDestinationIndex(destinationIndex); + paster4->SetSourceRegion(row0->GetLargestPossibleRegion()); + + // Paste row 4 at index 7 + typename PasteImageFilterType::Pointer paster5=PasteImageFilterType::New(); + paster5->SetDestinationImage(paster4->GetOutput()); + paster5->SetSourceImage(row4); + destinationIndex[InputDimension-1]=7; + paster5->SetDestinationIndex(destinationIndex); + paster5->SetSourceRegion(row4->GetLargestPossibleRegion()); + + // Update the chain! + paster5->Update(); + m_PaddedCoefficientImage= paster5->GetOutput(); + + break; + } + + default: + DD ("Shape not available"); + } + + } + + + // // Extract coefficients from padded version + // template + // void + // ShapedBLUTSpatioTemporalDeformableTransform + // ::ExtractCoefficientImage( ) + // { + // ////DD("extract coeff image"); + // typename ExtractImageFilterType::Pointer extractImageFilter = ExtractImageFilterType::New(); + // typename CoefficientImageType::RegionType extractionRegion=m_PaddedCoefficientImage->GetLargestPossibleRegion(); + // typename CoefficientImageType::RegionType::SizeType extractionSize=extractionRegion.GetSize(); + // typename CoefficientImageType::RegionType::IndexType extractionIndex = extractionRegion.GetIndex(); + // extractionSize[InputDimension-1]-=4; + // extractionIndex[InputDimension-1]=2; + // extractionRegion.SetSize(extractionSize); + // extractionRegion.SetIndex(extractionIndex); + // extractImageFilter->SetInput(m_PaddedCoefficientImage); + // extractImageFilter->SetExtractionRegion(extractionRegion); + // extractImageFilter->Update(); + // m_CoefficientImage=extractImageFilter->GetOutput(); + // } + + + // Print self + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::PrintSelf(std::ostream &os, itk::Indent indent) const + { + + this->Superclass::PrintSelf(os, indent); + + os << indent << "GridRegion: " << m_GridRegion << std::endl; + os << indent << "GridOrigin: " << m_GridOrigin << std::endl; + os << indent << "GridSpacing: " << m_GridSpacing << std::endl; + os << indent << "GridDirection: " << m_GridDirection << std::endl; + os << indent << "IndexToPoint: " << m_IndexToPoint << std::endl; + os << indent << "PointToIndex: " << m_PointToIndex << std::endl; + + os << indent << "CoefficientImage: [ "; + os << m_CoefficientImage.GetPointer() << " ]" << std::endl; + + os << indent << "WrappedImage: [ "; + os << m_WrappedImage.GetPointer() << " ]" << std::endl; + + os << indent << "InputParametersPointer: " + << m_InputParametersPointer << std::endl; + os << indent << "ValidRegion: " << m_ValidRegion << std::endl; + os << indent << "LastJacobianIndex: " << m_LastJacobianIndex << std::endl; + os << indent << "BulkTransform: "; + os << m_BulkTransform << std::endl; + + if ( m_BulkTransform ) + { + os << indent << "BulkTransformType: " + << m_BulkTransform->GetNameOfClass() << std::endl; + } + os << indent << "VectorBSplineInterpolator: "; + os << m_VectorInterpolator.GetPointer() << std::endl; + os << indent << "Mask: "; + os << m_Mask<< std::endl; + } + + + // Verify + template + bool + ShapedBLUTSpatioTemporalDeformableTransform + ::InsideValidRegion( const ContinuousIndexType& index ) const + { + bool inside = true; + + if ( !m_ValidRegion.IsInside( index ) ) + { + inside = false; + } + + // JV verify all dimensions + if ( inside) + { + typedef typename ContinuousIndexType::ValueType ValueType; + for( unsigned int j = 0; j < NInputDimensions; j++ ) + { + if (m_SplineOrderOdd[j]) + { + if ( index[j] >= static_cast( m_ValidRegionLast[j] ) ) + { + inside = false; + break; + } + } + } + } + return inside; + } + + + // Transform a point + template + typename ShapedBLUTSpatioTemporalDeformableTransform + ::OutputPointType + ShapedBLUTSpatioTemporalDeformableTransform + ::TransformPoint(const InputPointType &inputPoint) const + { + + InputPointType transformedPoint; + OutputPointType outputPoint; + + // BulkTransform + if ( m_BulkTransform ) + { + transformedPoint = m_BulkTransform->TransformPoint( inputPoint ); + } + else + { + transformedPoint = inputPoint; + } + + // Deformable transform + if ( m_PaddedCoefficientImage ) + { + // Check if inside mask + if(m_Mask && !(m_Mask->IsInside(inputPoint) ) ) + { + // Outside: no (deformable) displacement + return transformedPoint; + } + + // Check if inside valid region + bool inside = true; + ContinuousIndexType index; + this->TransformPointToContinuousIndex( inputPoint, index ); + inside = this->InsideValidRegion( index ); + if ( !inside ) + { + // Outside: no (deformable) displacement + DD("outside valid region"); + return transformedPoint; + } + + // Call the vector interpolator + itk::Vector displacement=m_VectorInterpolator->EvaluateAtContinuousIndex(index); + + // JV add for the spatial dimensions + outputPoint=transformedPoint; + for (unsigned int i=0; i + typename ShapedBLUTSpatioTemporalDeformableTransform + ::OutputPointType + ShapedBLUTSpatioTemporalDeformableTransform + ::DeformablyTransformPoint(const InputPointType &inputPoint) const + { + OutputPointType outputPoint; + if ( m_PaddedCoefficientImage ) + { + + // Check if inside mask + if(m_Mask && !(m_Mask->IsInside(inputPoint) ) ) + { + // Outside: no (deformable) displacement + return inputPoint; + } + + // Check if inside + bool inside = true; + ContinuousIndexType index; + this->TransformPointToContinuousIndex( inputPoint, index ); + inside = this->InsideValidRegion( index ); + + if ( !inside ) + { + //outside: no (deformable) displacement + outputPoint = inputPoint; + return outputPoint; + } + + // Call the vector interpolator + itk::Vector displacement=m_VectorInterpolator->EvaluateAtContinuousIndex(index); + + // JV add for the spatial dimensions + outputPoint=inputPoint; + for (unsigned int i=0; i + const + typename ShapedBLUTSpatioTemporalDeformableTransform + ::JacobianType & + ShapedBLUTSpatioTemporalDeformableTransform + ::GetJacobian( const InputPointType & point ) const + { + + //======================================================== + // Zero all components of jacobian + //======================================================== + // JV not thread safe (m_LastJacobianIndex), instantiate N transforms + // NOTE: for efficiency, we only need to zero out the coefficients + // that got fill last time this method was called. + unsigned int j=0,b=0; + + //Set the previously-set to zero + for ( j = 0; j < SpaceDimension; j++ ) + { + m_FirstIterator[j].GoToBegin(); + while ( !m_FirstIterator[j].IsAtEnd() ) + { + m_FirstIterator[j].Set( m_ZeroVector ); + ++(m_FirstIterator[j]); + } + } + + //Set the previously-set to zero + for ( j = 0; j < SpaceDimension; j++ ) + { + m_SecondIterator[j].GoToBegin(); + while ( ! (m_SecondIterator[j]).IsAtEnd() ) + { + m_SecondIterator[j].Set( m_ZeroVector ); + ++(m_SecondIterator[j]); + } + } + + //Set the previously-set to zero + if (m_ThirdSize) + for ( j = 0; j < SpaceDimension; j++ ) + { + m_ThirdIterator[j].GoToBegin(); + while ( ! (m_ThirdIterator[j]).IsAtEnd() ) + { + m_ThirdIterator[j].Set( m_ZeroVector ); + ++(m_ThirdIterator[j]); + } + } + + //Set the previously-set to zero + if (m_BCSize) + for (b=0; bIsInside(point) ) ) + { + // Outside: no (deformable) displacement + return this->m_Jacobian; + } + + // Get index + this->TransformPointToContinuousIndex( point, m_Index ); + + // NOTE: if the support region does not lie totally within the grid + // we assume zero displacement and return the input point + if ( !this->InsideValidRegion( m_Index ) ) + { + return this->m_Jacobian; + } + + // Compute interpolation weights + const WeightsDataType *weights=NULL; + m_VectorInterpolator->EvaluateWeightsAtContinuousIndex( m_Index, &weights, m_LastJacobianIndex); + + // Get support + m_SupportRegion.SetIndex( m_LastJacobianIndex ); + WrapRegion(m_SupportRegion, m_FirstRegion, m_SecondRegion, m_ThirdRegion, m_BCRegions, m_BCValues, m_BC2Regions, m_BC2Values, m_BC3Regions, m_BC3Values, m_InitialOffset); + m_ThirdSize=m_ThirdRegion.GetSize()[InputDimension-1]; + m_BCSize=m_BCRegions.size(); + m_BC2Size=m_BC2Regions.size(); + m_BC3Size=m_BC3Regions.size(); + + // Reset the iterators + for ( j = 0; j < SpaceDimension ; j++ ) + { + m_FirstIterator[j] = IteratorType( m_JacobianImage[j], m_FirstRegion); + m_SecondIterator[j] = IteratorType( m_JacobianImage[j], m_SecondRegion); + if(m_ThirdSize) m_ThirdIterator[j] = IteratorType( m_JacobianImage[j], m_ThirdRegion); + + m_BCIterators[j].resize(m_BCSize); + for (b=0; b::Zero; + if (j != SpaceDimension-1) weights-=m_FirstRegion.GetNumberOfPixels(); + } + + // Skip BC1 and go to the second region + if (m_BCSize) weights+=m_BCRegions[0].GetNumberOfPixels(); + + // For each dimension, copy the weight to the support region + //copy weight to jacobian image + for ( j = 0; j < SpaceDimension; j++ ) + { + while ( ! (m_SecondIterator[j]).IsAtEnd() ) + { + m_ZeroVector[j]=*weights; + (m_SecondIterator[j]).Set( m_ZeroVector); + ++(m_SecondIterator[j]); + weights++; + } + weights-=m_SecondRegion.GetNumberOfPixels(); + m_ZeroVector[j]=itk::NumericTraits::Zero; + } + + // Now do BC1: + if (m_BCSize) + { + // Put pointer in correct position + weights-=m_BCRegions[0].GetNumberOfPixels(); + + for ( j = 0; j < SpaceDimension; j++ ) + { + for ( b=0; b < m_BCSize; b++ ) + { + while ( ! (m_BCIterators[j][b]).IsAtEnd() ) + { + //copy weight to jacobian image + m_ZeroVector[j]=(*weights) * m_BCValues[b]; + (m_BCIterators[j][b]).Value()+= m_ZeroVector; + ++(m_BCIterators[j][b]); + weights++; + } + weights-=m_BCRegions[b].GetNumberOfPixels(); + } + m_ZeroVector[j]=itk::NumericTraits::Zero; + } + weights+=m_BCRegions[m_BCSize-1].GetNumberOfPixels(); + } + + // Add the BC2 to the weights + if (m_BC2Size) + { + // Move further in the weights pointer + weights+=m_SecondRegion.GetNumberOfPixels(); + + for ( j = 0; j < SpaceDimension; j++ ) + { + for ( b=0; b < m_BC2Size; b++ ) + { + while ( ! (m_BC2Iterators[j][b]).IsAtEnd() ) + { + //copy weight to jacobian image + m_ZeroVector[j]=(*weights) * m_BC2Values[b]; + (m_BC2Iterators[j][b]).Value()+= m_ZeroVector; + ++(m_BC2Iterators[j][b]); + weights++; + } + weights-=m_BC2Regions[b].GetNumberOfPixels(); + } + m_ZeroVector[j]=itk::NumericTraits::Zero; + } + // Move further in the weights pointer + weights+=m_BC2Regions[m_BC2Size-1].GetNumberOfPixels(); + } + + // Third Region + if(m_ThirdSize) + { + // For each dimension, copy the weight to the support region + //copy weight to jacobian image + for ( j = 0; j < SpaceDimension; j++ ) + { + while ( ! (m_ThirdIterator[j]).IsAtEnd() ) + { + m_ZeroVector[j]=*weights; + (m_ThirdIterator[j]).Value()+= m_ZeroVector; + ++(m_ThirdIterator[j]); + weights++; + } + + // Move further in the weights pointer? + if (j != SpaceDimension-1) weights-=m_ThirdRegion.GetNumberOfPixels(); + m_ZeroVector[j]=itk::NumericTraits::Zero; + } + } + + // Add the BC3 to the weights + if (m_BC3Size) + { + for ( j = 0; j < SpaceDimension; j++ ) + { + for ( b=0; b < m_BC3Size; b++ ) + { + while ( ! (m_BC3Iterators[j][b]).IsAtEnd() ) + { + //copy weight to jacobian image + m_ZeroVector[j]=(*weights) * m_BC3Values[b]; + (m_BC3Iterators[j][b]).Value()+= m_ZeroVector; + ++(m_BC3Iterators[j][b]); + weights++; + } + weights-=m_BC3Regions[b].GetNumberOfPixels(); + } + m_ZeroVector[j]=itk::NumericTraits::Zero; + } + } + + // Return the result + return this->m_Jacobian; + } + + + template + inline void + ShapedBLUTSpatioTemporalDeformableTransform + ::WrapRegion( const RegionType & m_SupportRegion, + RegionType & m_FirstRegion, + RegionType & m_SecondRegion, + RegionType & m_ThirdRegion, + std::vector& m_BCRegions,std::vector& m_BCValues, + std::vector& m_BC2Regions,std::vector& m_BC2Values, + std::vector& m_BC3Regions,std::vector& m_BC3Values, + unsigned int& m_InitialOffset ) const + { + + // Synchronize regions + m_InitialOffset=0; + m_FirstRegion=m_SupportRegion; + m_BCRegion=m_SupportRegion; + m_BCRegion.SetSize(InputDimension-1,1); + m_SecondRegion=m_SupportRegion; + m_ThirdRegion=m_SupportRegion; + m_ThirdRegion.SetSize(InputDimension-1,0); + m_BC3Regions.resize(0); + + + // BC depends on shape + switch(m_TransformShape) + { + /* The shapes are + 0: egg 4 CP 3 DOF + 1: egg 5 CP 4 DOF + 2: rabbit 4 CP 3 DOF + 3: rabbit 5 CP 4 DOF + 4: sputnik 4 CP 4 DOF + 5: sputnik 5 CP 5 DOF + 6: diamond 6 CP 5 DOF + 7: diamond 7 CP 6 DOF + */ + + case 0: + { + // ---------------------------------------------------------------------- + // The egg with 4 internal CP (starting from inhale) + // Periodic, constrained to zero at the reference + // at position 3 and + // Coeff row BC1 BC2 0 BC3 1 2 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 + // BC1= R4 + // BC2= R5 + // BC3= -weights[2]/weights[0] ( R2+R4 ) + // BC4= R2 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(0); + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC + m_BC2Regions.resize(2); + m_BC2Values.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -m_WeightRatio[2][0]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC + m_BCRegions.resize(0); + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC + m_BC2Regions.resize(2); + m_BC2Values.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -m_WeightRatio[2][0]; + + // Third Part + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,1); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,1); + + // BC2 + m_BC2Regions.resize(1); + m_BC2Values.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + + break; + } + + default: + { + DD("supportindex > 3 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } + + case 1: + { + // ---------------------------------------------------------------------- + // The egg with 5 internal CP (starting from inhale) + // Periodic, constrained to zero at the reference + // at position 3 and + // Coeff row BC1 BC2 0 BC3 1 2 3 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= R5 + // BC2= R6 + // BC3= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC4= R2 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC + m_BCRegions.resize(0); + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[3][1]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,3); + + // BC + m_BCRegions.resize(0); + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[3][1]; + + // Third Part + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,1); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,3); + m_SecondRegion.SetIndex(InputDimension-1,1); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 4: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,3); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(0); + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + + default: + { + DD("supportindex > 3 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } +// // ---------------------------------------------------------------------- +// // The egg with 5 internal CP: +// // Periodic, C2 smooth everywhere and constrained to zero at the reference +// // Coeff row R5 BC1 0 1 2 3 BC2 R2 +// // PaddedCoeff R: 0 1 2 3 4 5 6 7 +// // BC1= -weights[2]/weights[0] ( R2+R5) +// // BC2= BC1 +// // --------------------------------------------------------------------- +// switch(m_SupportRegion.GetIndex(InputDimension-1)) +// { +// case 0: +// { +// // Lower end +// m_FirstRegion.SetSize(InputDimension-1,1); +// m_FirstRegion.SetIndex(InputDimension-1,3); + +// // BC +// m_BCRegions.resize(2); +// m_BCValues.resize(2); +// m_BCRegion.SetIndex(InputDimension-1,0); +// m_BCRegions[0]=m_BCRegion; +// m_BCValues[0]=-m_WeightRatio[2][0]; +// m_BCRegion.SetIndex(InputDimension-1,3); +// m_BCRegions[1]=m_BCRegion; +// m_BCValues[1]=-m_WeightRatio[2][0]; + +// // Second part +// m_SecondRegion.SetSize(InputDimension-1,2); +// m_SecondRegion.SetIndex(InputDimension-1,0); + +// // BC2 +// m_BC2Regions.resize(0); + +// break; +// } +// case 1: +// { +// // Lower end +// m_FirstRegion.SetSize(InputDimension-1,0); + +// // BC +// m_BCRegions.resize(2); +// m_BCValues.resize(2); +// m_BCRegion.SetIndex(InputDimension-1,0); +// m_BCRegions[0]=m_BCRegion; +// m_BCValues[0]=-m_WeightRatio[2][0]; +// m_BCRegion.SetIndex(InputDimension-1,3); +// m_BCRegions[1]=m_BCRegion; +// m_BCValues[1]=-m_WeightRatio[2][0]; + +// // Second part +// m_SecondRegion.SetSize(InputDimension-1,3); +// m_SecondRegion.SetIndex(InputDimension-1,0); + +// // BC2 +// m_BC2Regions.resize(0); + +// break; +// } +// case 2: +// { +// // Lower end +// m_FirstRegion.SetSize(InputDimension-1,4); +// m_FirstRegion.SetIndex(InputDimension-1,0); + +// // BC +// m_BCRegions.resize(0); + +// // Second part +// m_SecondRegion.SetSize(InputDimension-1,0); + +// // BC2 +// m_BC2Regions.resize(0); + +// break; +// } +// case 3: +// { +// // Lower end +// m_FirstRegion.SetSize(InputDimension-1,3); +// m_FirstRegion.SetIndex(InputDimension-1,1); + +// // BC +// m_BCRegions.resize(2); +// m_BCValues.resize(2); +// m_BCRegion.SetIndex(InputDimension-1,0); +// m_BCRegions[0]=m_BCRegion; +// m_BCValues[0]=-m_WeightRatio[2][0]; +// m_BCRegion.SetIndex(InputDimension-1,3); +// m_BCRegions[1]=m_BCRegion; +// m_BCValues[1]=-m_WeightRatio[2][0]; + +// // Second part +// m_SecondRegion.SetSize(InputDimension-1,0); + +// // BC2 +// m_BC2Regions.resize(0); + +// break; +// } + +// case 4: +// { +// // Lower end +// m_FirstRegion.SetSize(InputDimension-1,2); +// m_FirstRegion.SetIndex(InputDimension-1,2); + +// // BC +// m_BCRegions.resize(2); +// m_BCValues.resize(2); +// m_BCRegion.SetIndex(InputDimension-1,0); +// m_BCRegions[0]=m_BCRegion; +// m_BCValues[0]=-m_WeightRatio[2][0]; +// m_BCRegion.SetIndex(InputDimension-1,3); +// m_BCRegions[1]=m_BCRegion; +// m_BCValues[1]=-m_WeightRatio[2][0]; + +// // Second part +// m_SecondRegion.SetSize(InputDimension-1,1); +// m_SecondRegion.SetIndex(InputDimension-1,0); + +// // BC2 +// m_BC2Regions.resize(0); + +// break; +// } + +// default: +// { +// DD("supportindex > 4 ???"); +// DD(m_SupportRegion.GetIndex(InputDimension-1)); +// DD(m_TransformShape); +// } +// }// end swith index +// break; + +// } // end case 1 shape + + case 2: + { + // ---------------------------------------------------------------------- + // The rabbit with 4 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and the extremes fixed with anit-symm bc + // Coeff row BC1 0 1 BC2 2 BC3 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 + // BC1= 2*R1-R0 + // BC2= -weights[2]/weights[0] ( R2+R4 ) + // BC3= R1 + // BC4= 2*R1-R4 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=2; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC + m_BC2Regions.resize(2); + m_BC2Values.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -m_WeightRatio[2][0]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(1); + m_BC2Values.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(1); + m_BC2Values.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + + // BC3 + m_BC3Regions.resize(2); + m_BC3Values.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC3Regions[0]=m_BCRegion; + m_BC3Values[0]=2; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC3Regions[1]=m_BCRegion; + m_BC3Values[1]= -1; + + break; + } + + default: + { + DD("supportindex > 3 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 2 shape + case 3: + { + // ---------------------------------------------------------------------- + // The rabbit with 5 internal CP + // Periodic, constrained to zero at the reference at position 3.5 + // and the extremes fixed with anti-symmetrical BC + // Coeff row BC1 0 1 BC2 2 3 BC3 BC4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= 2*R1-R2 + // BC2= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC3= R1 + // BC4= 2*R1-R5 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=2.; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1.; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[3][1]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(1); + m_BC2Values.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1.; + + break; + } + + case 4: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BCRegions.resize(1); + m_BCValues.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=1.; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(2); + m_BC2Values.resize(2); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=2; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=-1; + + break; + + } + default: + { + DD("supportindex > 4 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 3 shape + + case 4: + { + // ---------------------------------------------------------------------- + // The sputnik with 4 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and one indepent extremes copied + // Coeff row BC1 0 1 BC2 2 BC2 3 + // PaddedCoeff R: 0 1 2 3 4 5 6 + // BC1= R6 + // BC2= -weights[2]/weights[0] ( R2+R4 ) + // BC3= weights[2]/weights[0] ( R2-R4) + R1 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(1); + m_BCValues.resize(1); + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=1; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(2); + m_BC2Values.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -m_WeightRatio[2][0]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[2][0]; + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[2][0]; + + // Third part + m_ThirdRegion.SetSize(InputDimension-1,1); + m_ThirdRegion.SetIndex(InputDimension-1,3); + + break; + } + + default: + { + DD("supportindex > 3 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 4 shape + + case 5: + { + // ---------------------------------------------------------------------- + // The sputnik with 5 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and one indepent extreme + // Coeff row BC1 0 1 BC2 2 3 BC3 4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= R2 + R5 - R7 + // BC2= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC3= R1 + 0.5 R2 - 0.5 R7 + // ---------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=1.; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=1.; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-1.; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[3][1]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=0.5; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-0.5; + + break; + } + case 4: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=1; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=0.5; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-0.5; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,4); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + default: + { + DD("supportindex > 4 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 5 shape + + + + + case 6: + { + // ---------------------------------------------------------------------- + // The diamond with 4 internal CP: + // Periodic, constrained to zero at the reference at position 3 + // Coeff row 0 1 2 BC1 3 BC2 4 + // PaddedCoeff R:0 1 2 3 4 5 6 + // BC1= -weights[2]/weights[0] ( R2+R4 ) + // BC2= weights[2]/weights[0] ( R0+R2-R4-R6 ) + R1 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,3); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=-m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=-m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,3); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=-m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,3); + + // BC2 + m_BC2Regions.resize(5); + m_BC2Values.resize(5); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BC2Regions[3]=m_BCRegion; + m_BC2Values[3]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BC2Regions[4]=m_BCRegion; + m_BC2Values[4]=-m_WeightRatio[2][0]; + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(2); + m_BCValues.resize(2); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=-m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,3); + + // BC2 + m_BC2Regions.resize(5); + m_BC2Values.resize(5); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BC2Regions[3]=m_BCRegion; + m_BC2Values[3]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BC2Regions[4]=m_BCRegion; + m_BC2Values[4]=-m_WeightRatio[2][0]; + + // Third part + m_ThirdRegion.SetSize(InputDimension-1,1); + m_ThirdRegion.SetIndex(InputDimension-1,4); + + break; + } + + default: + { + DD("supportindex > 3 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 7 shape + + case 7: + { + // ---------------------------------------------------------------------- + // The diamond with 5 internal CP: + // periodic, constrained to zero at the reference at position 3.5 + // Coeff row 0 1 2 BC1 3 4 BC2 5 + // PaddedCoeff R:0 1 2 3 4 5 6 7 + // BC1= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC2= weights[2]/weights[0] ( R0+R2-R5-R7 ) + R1 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,3); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,3); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,3); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,3); + + // BC2 + m_BC2Regions.resize(5); + m_BC2Values.resize(5); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]=1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BC2Regions[3]=m_BCRegion; + m_BC2Values[3]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,5); + m_BC2Regions[4]=m_BCRegion; + m_BC2Values[4]=-m_WeightRatio[2][0]; + + break; + } + + case 4: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,3); + + // BC + m_BCRegions.resize(5); + m_BCValues.resize(5); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=1; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[3]=m_BCRegion; + m_BCValues[3]=-m_WeightRatio[2][0]; + m_BCRegion.SetIndex(InputDimension-1,5); + m_BCRegions[4]=m_BCRegion; + m_BCValues[4]=-m_WeightRatio[2][0]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,5); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + + default: + { + DD("supportindex > 4 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 7 shape + + case 9: + { + // ---------------------------------------------------------------------- + // The sputnik with 5 internal CP + // Periodic, constrained to zero at the reference + // at position 3 and one indepent extreme + // Coeff row BC1 0 1 BC2 2 3 BC3 4 + // PaddedCoeff R: 0 1 2 3 4 5 6 7 + // BC1= -R2+R5-R7 + // BC2= -weights[3]/weights[1] ( R2+R5 ) - R4 + // BC3= R1 + // --------------------------------------------------------------------- + switch(m_SupportRegion.GetIndex(InputDimension-1)) + { + case 0: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]=1; + m_BCRegion.SetIndex(InputDimension-1,4); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-1; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,0); + + // BC2 + m_BC2Regions.resize(3); + m_BC2Values.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BC2Regions[1]=m_BCRegion; + m_BC2Values[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BC2Regions[2]=m_BCRegion; + m_BC2Values[2]=-m_WeightRatio[3][1]; + + break; + } + case 1: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 2: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,1); + m_FirstRegion.SetIndex(InputDimension-1,1); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,2); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + case 3: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,0); + + // BC + m_BCRegions.resize(3); + m_BCValues.resize(3); + m_BCRegion.SetIndex(InputDimension-1,1); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=-m_WeightRatio[3][1]; + m_BCRegion.SetIndex(InputDimension-1,2); + m_BCRegions[1]=m_BCRegion; + m_BCValues[1]= -1; + m_BCRegion.SetIndex(InputDimension-1,3); + m_BCRegions[2]=m_BCRegion; + m_BCValues[2]=-m_WeightRatio[3][1]; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,2); + + // BC + m_BC2Regions.resize(1); + m_BC2Values.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BC2Regions[0]=m_BCRegion; + m_BC2Values[0]=1; + + break; + } + case 4: + { + // Lower end + m_FirstRegion.SetSize(InputDimension-1,2); + m_FirstRegion.SetIndex(InputDimension-1,2); + + // BC + m_BCRegions.resize(1); + m_BCValues.resize(1); + m_BCRegion.SetIndex(InputDimension-1,0); + m_BCRegions[0]=m_BCRegion; + m_BCValues[0]=1; + + // Second part + m_SecondRegion.SetSize(InputDimension-1,1); + m_SecondRegion.SetIndex(InputDimension-1,4); + + // BC2 + m_BC2Regions.resize(0); + + break; + } + default: + { + DD("supportindex > 4 ???"); + DD(m_SupportRegion.GetIndex(InputDimension-1)); + } + } // end switch index + + break; + } // end case 9 shape + + + default: + { + DD ("Other shapes currently not implemented"); + } + + } // end switch shape + } // end wrap region + + + + template + void + ShapedBLUTSpatioTemporalDeformableTransform + ::TransformPointToContinuousIndex( const InputPointType & point, ContinuousIndexType & index ) const + { + unsigned int j; + + itk::Vector tvector; + + for ( j = 0; j < OutputDimension; j++ ) + { + //JV find the index in the PADDED version + tvector[j] = point[j] - this->m_PaddedGridOrigin[j]; + } + + itk::Vector cvector; + + cvector = m_PointToIndex * tvector; + + for ( j = 0; j < OutputDimension; j++ ) + { + index[j] = static_cast< typename ContinuousIndexType::CoordRepType >( cvector[j] ); + } + } + + +} // namespace + +#endif + diff --git a/registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.h b/registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.h new file mode 100755 index 0000000..8c5d286 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.h @@ -0,0 +1,183 @@ +/*========================================================================= + 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 __clitkShapedBLUTSpatioTemporalDeformableTransformInitializer_h +#define __clitkShapedBLUTSpatioTemporalDeformableTransformInitializer_h +#include "clitkResampleBSplineDeformableTransformImageFilter.h" + +#include "itkObject.h" +#include "itkObjectFactory.h" +#include "itkImageFileReader.h" +#include + +namespace clitk +{ + + +template < class TTransform, class TImage > +class ITK_EXPORT ShapedBLUTSpatioTemporalDeformableTransformInitializer : public itk::Object +{ +public: + /** Standard class typedefs. */ + typedef ShapedBLUTSpatioTemporalDeformableTransformInitializer Self; + typedef itk::Object Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** New macro for creation of through a Smart Pointer. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( ShapedBLUTSpatioTemporalDeformableTransformInitializer, Object ); + + // Typedefs + typedef TTransform TransformType; + typedef typename TransformType::Pointer TransformPointer; + typedef typename TransformType::RegionType RegionType; + typedef typename TransformType::OriginType OriginType; + typedef typename TransformType::DirectionType DirectionType; + typedef typename RegionType::SizeType SizeType; + typedef typename TransformType::SpacingType SpacingType; + itkStaticConstMacro(InputDimension, unsigned int, TransformType::InputDimension); + typedef TImage ImageType; + typedef typename ImageType::ConstPointer ImagePointer; + typedef typename TransformType::CoefficientImageType CoefficientImageType; + typedef typename TransformType::ParametersType ParametersType; + + // Set and Get + itkBooleanMacro(Verbose); + itkSetMacro( Verbose, bool); + itkGetConstReferenceMacro( Verbose, bool); + itkSetObjectMacro( Transform, TransformType ); + itkGetConstObjectMacro( Transform, TransformType ); + itkSetObjectMacro( Image, ImageType ); + itkGetConstObjectMacro( Image, ImageType ); + + void SetSplineOrder(const unsigned int & splineOrder) + { + SizeType s; + s.Fill(splineOrder); + this->SetSplineOrders(s); + } + void SetSplineOrders(const SizeType & splineOrders) + { + m_SplineOrders=splineOrders; + } + void SetNumberOfControlPointsInsideTheImage( SizeType & n ) + { + m_NumberOfControlPointsInsideTheImage=n; + m_NumberOfControlPointsIsGiven=true; + this->Modified(); + } + void SetNumberOfControlPointsInsideTheImage( int * n) + { + SizeType s; + for (unsigned int i=0;iSetNumberOfControlPointsInsideTheImage( s ); + } + void SetNumberOfControlPointsInsideTheImage( unsigned int & n ) + { + SizeType s; + s.Fill( n );; + this->SetNumberOfControlPointsInsideTheImage( s ); + } + void SetControlPointSpacing( SpacingType n ) + { + m_ControlPointSpacing= n; + m_ControlPointSpacingIsGiven=true; + this->Modified(); + } + void SetControlPointSpacing( double*& n ) + { + SpacingType s( n ); + this->SetControlPointSpacing(s); + } + void SetControlPointSpacing( double n ) + { + SpacingType s; + s.Fill( n ); + this->SetControlPointSpacing(s); + } + void SetSamplingFactors( SizeType n ) + { + m_SamplingFactors=n; + m_SamplingFactorIsGiven=true; + this->Modified(); + } + void SetSamplingFactors( int *& n) + { + SizeType s; + for (unsigned int i=0;i SetSamplingFactors( s ); + } + void SetSamplingFactors( unsigned int n ) + { + SizeType s; + s.Fill( n ); + this-> SetSamplingFactors( s ); + } + virtual void InitializeTransform(); + void SetInitialParameters(const typename CoefficientImageType::Pointer coefficientImage, ParametersType& params); + void SetInitialParameters(const std::string & s, ParametersType& params); +// void SetInitialPaddedParameters(const typename CoefficientImageType::Pointer coefficientImage, ParametersType& params); +// void SetInitialPaddedParameters(const std::string & s, ParametersType& params); + + // For easy acces, declared public + std::vector m_NumberOfControlPointsInsideTheImageArray; + std::vector m_SamplingFactorsArray; + std::vector m_ControlPointSpacingArray; + + SpacingType m_ControlPointSpacing; + SizeType m_SamplingFactors; + SizeType m_SplineOrders; + SpacingType m_ChosenSpacing; + SizeType m_NumberOfControlPointsInsideTheImage; + bool m_NumberOfControlPointsIsGiven; + bool m_ControlPointSpacingIsGiven; + bool m_SamplingFactorIsGiven; + bool m_TransformRegionIsGiven; + unsigned int m_TrajectoryShape; + + typename TransformType::ParametersType* m_Parameters; + +protected: + ShapedBLUTSpatioTemporalDeformableTransformInitializer(); + ~ShapedBLUTSpatioTemporalDeformableTransformInitializer(){}; + +private: + ShapedBLUTSpatioTemporalDeformableTransformInitializer(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + bool m_Verbose; + TransformPointer m_Transform; + ImagePointer m_Image; + bool m_BC1; + bool m_BC2; + +}; //class ShapedBLUTSpatioTemporalDeformableTransformInitializer + + +} // namespace clitk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.txx" +#endif + +#endif /* __clitkShapedBLUTSpatioTemporalDeformableTransformInitializer_h */ diff --git a/registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.txx b/registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.txx new file mode 100755 index 0000000..d78fb97 --- /dev/null +++ b/registration/clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.txx @@ -0,0 +1,503 @@ +/*========================================================================= + 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 __clitkShapedBLUTSpatioTemporalDeformableTransformInitializer_txx +#define __clitkShapedBLUTSpatioTemporalDeformableTransformInitializer_txx +#include "clitkShapedBLUTSpatioTemporalDeformableTransformInitializer.h" + +namespace clitk +{ + + + template < class TTransform, class TImage > + ShapedBLUTSpatioTemporalDeformableTransformInitializer + ::ShapedBLUTSpatioTemporalDeformableTransformInitializer() + { + this->m_NumberOfControlPointsInsideTheImage.Fill( 5 ); + this->m_ControlPointSpacing.Fill(64.); + m_ControlPointSpacing[InputDimension-1]=2; + this->m_ChosenSpacing.Fill(64.); + m_ChosenSpacing[InputDimension-1]=2; + m_ControlPointSpacing[InputDimension-1]=2; + m_NumberOfControlPointsIsGiven=false; + m_ControlPointSpacingIsGiven=false; + m_TransformRegionIsGiven=false; + m_SamplingFactorIsGiven=false; + m_SplineOrders.Fill(3); + m_BC1=true; + m_BC2=true; + m_TrajectoryShape=0; + } + + template < class TTransform, class TImage > + void + ShapedBLUTSpatioTemporalDeformableTransformInitializer + ::InitializeTransform() + { + // Sanity check: + // The image is required for the region and spacing + if( ! this->m_Image ) + { + itkExceptionMacro( "Reference Image has not been set" ); + return; + } + + // A pointer to the transform is required + if( ! this->m_Transform ) + { + itkExceptionMacro( "Transform has not been set" ); + return; + } + + // If the image come from a filter, then update that filter. + if( this->m_Image->GetSource() ) + { + this->m_Image->GetSource()->Update(); + } + + + //-------------------------------------- + // Spacing & Size on image + //-------------------------------------- + SpacingType fixedImageSpacing = m_Image->GetSpacing(); + SizeType fixedImageSize=m_Image->GetLargestPossibleRegion().GetSize(); + typename RegionType::SizeType gridBorderSize; + typename RegionType::SizeType totalGridSize; + + // Only spacing given: adjust if necessary + if (m_ControlPointSpacingIsGiven && !m_NumberOfControlPointsIsGiven) + { + for(unsigned int r=0; rTransformIndexToPhysicalPoint(m_Image->GetLargestPossibleRegion().GetIndex(),fixedImageOrigin); + gridDirection = m_Image->GetDirection(); + itk::FixedArray orderShift; + + // Spacing is 2.5 : manually modify the props + if( !(m_Transform->GetTransformShape()%2) ) + { + m_ControlPointSpacing[InputDimension-1]=2.5; + m_SamplingFactors[InputDimension-1]=5; + totalGridSize[InputDimension-1]-=1; + gridRegion.SetSize(totalGridSize); + } + + + switch(m_Transform->GetTransformShape()){ + + // The egg shape + case 0: + case 1: + { + if (m_Verbose) std::cout<<"Using the egg shape..."<m_Transform->SetSplineOrders(m_SplineOrders); + this->m_Transform->SetGridSpacing( m_ControlPointSpacing ); + this->m_Transform->SetGridOrigin( gridOrigin ); + this->m_Transform->SetGridDirection( gridDirection ); + this->m_Transform->SetGridRegion( gridRegion ); + this->m_Transform->SetLUTSamplingFactors(m_SamplingFactors); + + } + + template < class TTransform, class TImage > + void + ShapedBLUTSpatioTemporalDeformableTransformInitializer + ::SetInitialParameters( const std::string& s, ParametersType& params) + { + //--------------------------------------- + // Read Initial parameters + //--------------------------------------- + typedef itk::ImageFileReader CoefficientReaderType; + typename CoefficientReaderType::Pointer coeffReader=CoefficientReaderType::New(); + coeffReader->SetFileName(s); + if(m_Verbose) std::cout<<"Reading initial coefficients from file: "<Update(); + typename CoefficientImageType::Pointer coefficientImage=coeffReader->GetOutput(); + this->SetInitialParameters(coefficientImage, params); + } + + template < class TTransform, class TImage > + void + ShapedBLUTSpatioTemporalDeformableTransformInitializer + ::SetInitialParameters(const typename CoefficientImageType::Pointer coefficientImage, ParametersType& params) + { + // Keep a reference + m_Parameters=¶ms; + + // Resample + typedef ResampleBSplineDeformableTransformImageFilter ResamplerType; + typename ResamplerType::Pointer resampler=ResamplerType::New(); + resampler->SetVerbose(m_Verbose); + resampler->SetInput(coefficientImage); + resampler->SetOutputParametersFromImage(m_Transform->GetCoefficientImage()); + if(m_Verbose) std::cout<<"Resampling initial coefficients..."<Update(); + + // Copy parameters into the existing array, I know its crappy + typedef itk::ImageRegionConstIterator Iterator; + Iterator it (resampler->GetOutput(), resampler->GetOutput()->GetLargestPossibleRegion() ); + it.GoToBegin(); + unsigned int i=0; + while(! it.IsAtEnd()) + { + for (unsigned int j=0; jm_Transform->SetParameters(params); + } + + + // template < class TTransform, class TImage > + // void + // ShapedBLUTSpatioTemporalDeformableTransformInitializer + // ::SetInitialPaddedParameters( const std::string& s, ParametersType& params) + // { + // //--------------------------------------- + // // Read Initial parameters + // //--------------------------------------- + // typedef itk::ImageFileReader CoefficientReaderType; + // typename CoefficientReaderType::Pointer coeffReader=CoefficientReaderType::New(); + // coeffReader->SetFileName(s); + // if(m_Verbose) std::cout<<"Reading initial padded coefficients from file: "<Update(); + // typename CoefficientImageType::Pointer coefficientImage=coeffReader->GetOutput(); + // this->SetInitialPaddedParameters(coefficientImage, params); + // } + + // template < class TTransform, class TImage > + // void + // ShapedBLUTSpatioTemporalDeformableTransformInitializer + // ::SetInitialPaddedParameters(const typename CoefficientImageType::Pointer coefficientImage, ParametersType& params) + // { + // // Resample + // typedef ResampleBSplineSpatioTemporalDeformableTransformImageFilter ResamplerType; + // typename ResamplerType::Pointer resampler=ResamplerType::New(); + // resampler->SetInput(coefficientImage); + // resampler->SetOutputParametersFromImage(m_Transform->GetCoefficientImage()); + // if(m_Verbose) std::cout<<"Resampling initial padded coefficients..."<Update(); + + // // Copy parameters into the existing array, I know its crappy + // typedef itk::ImageRegionConstIterator Iterator; + // Iterator it (resampler->GetOutput(), resampler->GetOutput()->GetLargestPossibleRegion() ); + // it.GoToBegin(); + // unsigned int i=0; + // while(! it.IsAtEnd()) + // { + // for (unsigned int j=0; j +class ITK_EXPORT SpatioTemporalMultiResolutionImageRegistrationMethod : public itk::ProcessObject +{ +public: + /** Standard class typedefs. */ + typedef SpatioTemporalMultiResolutionImageRegistrationMethod Self; + typedef itk::ProcessObject Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(SpatioTemporalMultiResolutionImageRegistrationMethod, ProcessObject); + + /** Type of the Fixed image. */ + typedef TFixedImage FixedImageType; + typedef typename FixedImageType::ConstPointer FixedImageConstPointer; + typedef typename FixedImageType::RegionType FixedImageRegionType; + + /** Type of the Moving image. */ + typedef TMovingImage MovingImageType; + typedef typename MovingImageType::ConstPointer MovingImageConstPointer; + + /** Type of the metric. */ + typedef itk::ImageToImageMetric< FixedImageType, + MovingImageType > MetricType; + typedef typename MetricType::Pointer MetricPointer; + + /** Type of the Transform . */ + typedef typename MetricType::TransformType TransformType; + typedef typename TransformType::Pointer TransformPointer; + + /** Type for the output: Using Decorator pattern for enabling + * the Transform to be passed in the data pipeline */ + typedef itk::DataObjectDecorator< TransformType > TransformOutputType; + typedef typename TransformOutputType::Pointer TransformOutputPointer; + typedef typename TransformOutputType::ConstPointer TransformOutputConstPointer; + + /** Type of the Interpolator. */ + typedef typename MetricType::InterpolatorType InterpolatorType; + typedef typename InterpolatorType::Pointer InterpolatorPointer; + + /** Type of the optimizer. */ + typedef itk::SingleValuedNonLinearOptimizer OptimizerType; + + //JV replace with clitk Spatio Temporal Type + /** Type of the Fixed image multiresolution pyramid. */ + typedef SpatioTemporalMultiResolutionPyramidImageFilter< FixedImageType, + FixedImageType > + FixedImagePyramidType; + typedef typename FixedImagePyramidType::Pointer FixedImagePyramidPointer; + + /** Type of pyramid schedule type */ + typedef typename FixedImagePyramidType::ScheduleType ScheduleType; + + //JV replace with clitk Spatio Temporal Type + /** Type of the moving image multiresolution pyramid. */ + typedef SpatioTemporalMultiResolutionPyramidImageFilter< MovingImageType, + MovingImageType > + MovingImagePyramidType; + typedef typename MovingImagePyramidType::Pointer MovingImagePyramidPointer; + + /** Type of the Transformation parameters This is the same type used to + * represent the search space of the optimization algorithm */ + typedef typename MetricType::TransformParametersType ParametersType; + + /** Smart Pointer type to a DataObject. */ + typedef typename itk::DataObject::Pointer DataObjectPointer; + + /** Method that initiates the registration. */ + void StartRegistration(); + + /** Method to stop the registration. */ + void StopRegistration(); + + /** Set/Get the Fixed image. */ + itkSetConstObjectMacro( FixedImage, FixedImageType ); + itkGetConstObjectMacro( FixedImage, FixedImageType ); + + /** Set/Get the Moving image. */ + itkSetConstObjectMacro( MovingImage, MovingImageType ); + itkGetConstObjectMacro( MovingImage, MovingImageType ); + + /** Set/Get the Optimizer. */ + itkSetObjectMacro( Optimizer, OptimizerType ); + itkGetObjectMacro( Optimizer, OptimizerType ); + + /** Set/Get the Metric. */ + itkSetObjectMacro( Metric, MetricType ); + itkGetObjectMacro( Metric, MetricType ); + + /** Set/Get the Metric. */ + itkSetMacro( FixedImageRegion, FixedImageRegionType ); + itkGetConstReferenceMacro( FixedImageRegion, FixedImageRegionType ); + + /** Set/Get the Transfrom. */ + itkSetObjectMacro( Transform, TransformType ); + itkGetObjectMacro( Transform, TransformType ); + + /** Set/Get the Interpolator. */ + itkSetObjectMacro( Interpolator, InterpolatorType ); + itkGetObjectMacro( Interpolator, InterpolatorType ); + + /** Set/Get the Fixed image pyramid. */ + itkSetObjectMacro( FixedImagePyramid, FixedImagePyramidType ); + itkGetObjectMacro( FixedImagePyramid, FixedImagePyramidType ); + + /** Set/Get the Moving image pyramid. */ + itkSetObjectMacro( MovingImagePyramid, MovingImagePyramidType ); + itkGetObjectMacro( MovingImagePyramid, MovingImagePyramidType ); + + /** Set/Get the schedules . */ + void SetSchedules( const ScheduleType & fixedSchedule, + const ScheduleType & movingSchedule ); + itkGetConstMacro( FixedImagePyramidSchedule, ScheduleType ); + itkGetConstMacro( MovingImagePyramidSchedule, ScheduleType ); + + /** Set/Get the number of multi-resolution levels. */ + void SetNumberOfLevels( unsigned long numberOfLevels ); + itkGetMacro( NumberOfLevels, unsigned long ); + + /** Get the current resolution level being processed. */ + itkGetMacro( CurrentLevel, unsigned long ); + + /** Set/Get the initial transformation parameters. */ + itkSetMacro( InitialTransformParameters, ParametersType ); + itkGetConstReferenceMacro( InitialTransformParameters, ParametersType ); + + /** Set/Get the initial transformation parameters of the next resolution + level to be processed. The default is the last set of parameters of + the last resolution level. */ + itkSetMacro( InitialTransformParametersOfNextLevel, ParametersType ); + itkGetConstReferenceMacro( InitialTransformParametersOfNextLevel, ParametersType ); + + /** Get the last transformation parameters visited by + * the optimizer. */ + itkGetConstReferenceMacro( LastTransformParameters, ParametersType ); + + /** Returns the transform resulting from the registration process */ + const TransformOutputType * GetOutput() const; + + /** Make a DataObject of the correct type to be used as the specified + * output. */ + virtual DataObjectPointer MakeOutput(unsigned int idx); + + /** Method to return the latest modified time of this object or + * any of its cached ivars */ + unsigned long GetMTime() const; + +protected: + SpatioTemporalMultiResolutionImageRegistrationMethod(); + virtual ~SpatioTemporalMultiResolutionImageRegistrationMethod() {}; + void PrintSelf(std::ostream& os, Indent indent) const; + + /** Method invoked by the pipeline in order to trigger the computation of + * the registration. */ + void GenerateData (); + + /** Initialize by setting the interconnects between the components. + This method is executed at every level of the pyramid with the + values corresponding to this resolution + */ + void Initialize() throw (ExceptionObject); + + /** Compute the size of the fixed region for each level of the pyramid. */ + void PreparePyramids( void ); + + /** Set the current level to be processed */ + itkSetMacro( CurrentLevel, unsigned long ); + +private: + SpatioTemporalMultiResolutionImageRegistrationMethod(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + MetricPointer m_Metric; + OptimizerType::Pointer m_Optimizer; + + MovingImageConstPointer m_MovingImage; + FixedImageConstPointer m_FixedImage; + + TransformPointer m_Transform; + InterpolatorPointer m_Interpolator; + + MovingImagePyramidPointer m_MovingImagePyramid; + FixedImagePyramidPointer m_FixedImagePyramid; + + ParametersType m_InitialTransformParameters; + ParametersType m_InitialTransformParametersOfNextLevel; + ParametersType m_LastTransformParameters; + + FixedImageRegionType m_FixedImageRegion; + std::vector m_FixedImageRegionPyramid; + + unsigned long m_NumberOfLevels; + unsigned long m_CurrentLevel; + + bool m_Stop; + + ScheduleType m_FixedImagePyramidSchedule; + ScheduleType m_MovingImagePyramidSchedule; + + bool m_ScheduleSpecified; + bool m_NumberOfLevelsSpecified; + +}; + + +} // end namespace clitk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkSpatioTemporalMultiResolutionImageRegistrationMethod.txx" +#endif + +#endif diff --git a/registration/clitkSpatioTemporalMultiResolutionImageRegistrationMethod.txx b/registration/clitkSpatioTemporalMultiResolutionImageRegistrationMethod.txx new file mode 100644 index 0000000..d93e3b3 --- /dev/null +++ b/registration/clitkSpatioTemporalMultiResolutionImageRegistrationMethod.txx @@ -0,0 +1,528 @@ +/*========================================================================= + 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 __clitkSpatioTemporalMultiResolutionImageRegistrationMethod_txx +#define __clitkSpatioTemporalMultiResolutionImageRegistrationMethod_txx +#include "clitkSpatioTemporalMultiResolutionImageRegistrationMethod.h" +#include "clitkRecursiveSpatioTemporalMultiResolutionPyramidImageFilter.h" + +namespace clitk +{ + +/** + * Constructor + */ +template < typename TFixedImage, typename TMovingImage > +SpatioTemporalMultiResolutionImageRegistrationMethod +::SpatioTemporalMultiResolutionImageRegistrationMethod() +{ + this->SetNumberOfRequiredOutputs( 1 ); // for the Transform + + m_FixedImage = 0; // has to be provided by the user. + m_MovingImage = 0; // has to be provided by the user. + m_Transform = 0; // has to be provided by the user. + m_Interpolator = 0; // has to be provided by the user. + m_Metric = 0; // has to be provided by the user. + m_Optimizer = 0; // has to be provided by the user. + + // Use SpatioTemporalMultiResolutionPyramidImageFilter as the default + // image pyramids. + m_FixedImagePyramid = FixedImagePyramidType::New(); + m_MovingImagePyramid = MovingImagePyramidType::New(); + + m_NumberOfLevels = 1; + m_CurrentLevel = 0; + + m_Stop = false; + + m_ScheduleSpecified = false; + m_NumberOfLevelsSpecified = false; + + m_InitialTransformParameters = ParametersType(1); + m_InitialTransformParametersOfNextLevel = ParametersType(1); + m_LastTransformParameters = ParametersType(1); + + m_InitialTransformParameters.Fill( 0.0f ); + m_InitialTransformParametersOfNextLevel.Fill( 0.0f ); + m_LastTransformParameters.Fill( 0.0f ); + + + TransformOutputPointer transformDecorator = + static_cast< TransformOutputType * >( + this->MakeOutput(0).GetPointer() ); + + this->ProcessObject::SetNthOutput( 0, transformDecorator.GetPointer() ); +} + + +/* + * Initialize by setting the interconnects between components. + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::Initialize() throw (ExceptionObject) +{ + + // Sanity checks + if ( !m_Metric ) + { + itkExceptionMacro(<<"Metric is not present" ); + } + + if ( !m_Optimizer ) + { + itkExceptionMacro(<<"Optimizer is not present" ); + } + + if( !m_Transform ) + { + itkExceptionMacro(<<"Transform is not present"); + } + + if( !m_Interpolator ) + { + itkExceptionMacro(<<"Interpolator is not present"); + } + + // Setup the metric + m_Metric->SetMovingImage( m_MovingImagePyramid->GetOutput(m_CurrentLevel) ); + m_Metric->SetFixedImage( m_FixedImagePyramid->GetOutput(m_CurrentLevel) ); + m_Metric->SetTransform( m_Transform ); + m_Metric->SetInterpolator( m_Interpolator ); + m_Metric->SetFixedImageRegion( m_FixedImageRegionPyramid[ m_CurrentLevel ] ); + m_Metric->Initialize(); + + // Setup the optimizer + m_Optimizer->SetCostFunction( m_Metric ); + m_Optimizer->SetInitialPosition( m_InitialTransformParametersOfNextLevel ); + + // + // Connect the transform to the Decorator. + // + TransformOutputType * transformOutput = + static_cast< TransformOutputType * >( this->ProcessObject::GetOutput(0) ); + + transformOutput->Set( m_Transform.GetPointer() ); + +} + + +/* + * Stop the Registration Process + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::StopRegistration( void ) +{ + m_Stop = true; +} + +/** + * Set the schedules for the fixed and moving image pyramid + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::SetSchedules( const ScheduleType & fixedImagePyramidSchedule, + const ScheduleType & movingImagePyramidSchedule ) +{ + if( m_NumberOfLevelsSpecified ) + { + itkExceptionMacro( "SetSchedules should not be used " + << "if numberOfLevelves are specified using SetNumberOfLevels" ); + } + m_FixedImagePyramidSchedule = fixedImagePyramidSchedule; + m_MovingImagePyramidSchedule = movingImagePyramidSchedule; + m_ScheduleSpecified = true; + + //Set the number of levels based on the pyramid schedule specified + if ( m_FixedImagePyramidSchedule.rows() != + m_MovingImagePyramidSchedule.rows()) + { + itkExceptionMacro("The specified schedules contain unequal number of levels"); + } + else + { + m_NumberOfLevels = m_FixedImagePyramidSchedule.rows(); + } + + this->Modified(); +} + +/** + * Set the number of levels + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::SetNumberOfLevels( unsigned long numberOfLevels ) +{ + if( m_ScheduleSpecified ) + { + itkExceptionMacro( "SetNumberOfLevels should not be used " + << "if schedules have been specified using SetSchedules method " ); + } + + m_NumberOfLevels = numberOfLevels; + m_NumberOfLevelsSpecified = true; + this->Modified(); +} + +/** + * Stop the Registration Process + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::PreparePyramids( void ) +{ + + if( !m_Transform ) + { + itkExceptionMacro(<<"Transform is not present"); + } + + m_InitialTransformParametersOfNextLevel = m_InitialTransformParameters; + + if ( m_InitialTransformParametersOfNextLevel.Size() != + m_Transform->GetNumberOfParameters() ) + { + itkExceptionMacro(<<"Size mismatch between initial parameter and transform"); + } + + // Sanity checks + if( !m_FixedImage ) + { + itkExceptionMacro(<<"FixedImage is not present"); + } + + if( !m_MovingImage ) + { + itkExceptionMacro(<<"MovingImage is not present"); + } + + if( !m_FixedImagePyramid ) + { + itkExceptionMacro(<<"Fixed image pyramid is not present"); + } + + if( !m_MovingImagePyramid ) + { + itkExceptionMacro(<<"Moving image pyramid is not present"); + } + + // Setup the fixed and moving image pyramid + if( m_NumberOfLevelsSpecified ) + { + m_FixedImagePyramid->SetNumberOfLevels( m_NumberOfLevels ); + m_MovingImagePyramid->SetNumberOfLevels( m_NumberOfLevels ); + } + + if( m_ScheduleSpecified ) + { + m_FixedImagePyramid->SetNumberOfLevels( m_FixedImagePyramidSchedule.rows()); + m_FixedImagePyramid->SetSchedule( m_FixedImagePyramidSchedule ); + + m_MovingImagePyramid->SetNumberOfLevels( m_MovingImagePyramidSchedule.rows()); + m_MovingImagePyramid->SetSchedule( m_MovingImagePyramidSchedule ); + } + + m_FixedImagePyramid->SetInput( m_FixedImage ); + m_FixedImagePyramid->UpdateLargestPossibleRegion(); + + // Setup the moving image pyramid + m_MovingImagePyramid->SetInput( m_MovingImage ); + m_MovingImagePyramid->UpdateLargestPossibleRegion(); + + typedef typename FixedImageRegionType::SizeType SizeType; + typedef typename FixedImageRegionType::IndexType IndexType; + + ScheduleType schedule = m_FixedImagePyramid->GetSchedule(); + std::cout << "FixedImage schedule: " << schedule << std::endl; + + ScheduleType movingschedule = m_MovingImagePyramid->GetSchedule(); + std::cout << "MovingImage schedule: " << movingschedule << std::endl; + + SizeType inputSize = m_FixedImageRegion.GetSize(); + IndexType inputStart = m_FixedImageRegion.GetIndex(); + + const unsigned long numberOfLevels = + m_FixedImagePyramid->GetNumberOfLevels(); + + m_FixedImageRegionPyramid.reserve( numberOfLevels ); + m_FixedImageRegionPyramid.resize( numberOfLevels ); + + // Compute the FixedImageRegion corresponding to each level of the + // pyramid. This uses the same algorithm of the ShrinkImageFilter + // since the regions should be compatible. + for ( unsigned int level=0; level < numberOfLevels; level++ ) + { + SizeType size; + IndexType start; + for ( unsigned int dim = 0; dim < TFixedImage::ImageDimension; dim++) + { + const float scaleFactor = static_cast( schedule[ level ][ dim ] ); + + size[ dim ] = static_cast( + vcl_floor(static_cast( inputSize[ dim ] ) / scaleFactor ) ); + if( size[ dim ] < 1 ) + { + size[ dim ] = 1; + } + + start[ dim ] = static_cast( + vcl_ceil(static_cast( inputStart[ dim ] ) / scaleFactor ) ); + } + m_FixedImageRegionPyramid[ level ].SetSize( size ); + m_FixedImageRegionPyramid[ level ].SetIndex( start ); + } + +} + +/* + * Starts the Registration Process + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::StartRegistration( void ) +{ + + // StartRegistration is an old API from before + // this egistrationMethod was a subclass of ProcessObject. + // Historically, one could call StartRegistration() instead of + // calling Update(). However, when called directly by the user, the + // inputs to the RegistrationMethod may not be up to date. This + // may cause an unexpected behavior. + // + // Since we cannot eliminate StartRegistration for backward + // compability reasons, we check whether StartRegistration was + // called directly or whether Update() (which in turn called + // StartRegistration()). + if (!m_Updating) + { + this->Update(); + } + else + { + m_Stop = false; + + this->PreparePyramids(); + + for ( m_CurrentLevel = 0; m_CurrentLevel < m_NumberOfLevels; + m_CurrentLevel++ ) + { + + // Invoke an iteration event. + // This allows a UI to reset any of the components between + // resolution level. + this->InvokeEvent( IterationEvent() ); + + // Check if there has been a stop request + if ( m_Stop ) + { + break; + } + + try + { + // initialize the interconnects between components + this->Initialize(); + } + catch( ExceptionObject& err ) + { + m_LastTransformParameters = ParametersType(1); + m_LastTransformParameters.Fill( 0.0f ); + + // pass exception to caller + throw err; + } + + try + { + // do the optimization + m_Optimizer->StartOptimization(); + } + catch( ExceptionObject& err ) + { + // An error has occurred in the optimization. + // Update the parameters + m_LastTransformParameters = m_Optimizer->GetCurrentPosition(); + + // Pass exception to caller + throw err; + } + + // get the results + m_LastTransformParameters = m_Optimizer->GetCurrentPosition(); + m_Transform->SetParameters( m_LastTransformParameters ); + + // setup the initial parameters for next level + if ( m_CurrentLevel < m_NumberOfLevels - 1 ) + { + m_InitialTransformParametersOfNextLevel = + m_LastTransformParameters; + } + } + } + +} + + +/* + * PrintSelf + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf( os, indent ); + os << indent << "Metric: " << m_Metric.GetPointer() << std::endl; + os << indent << "Optimizer: " << m_Optimizer.GetPointer() << std::endl; + os << indent << "Transform: " << m_Transform.GetPointer() << std::endl; + os << indent << "Interpolator: " << m_Interpolator.GetPointer() << std::endl; + os << indent << "FixedImage: " << m_FixedImage.GetPointer() << std::endl; + os << indent << "MovingImage: " << m_MovingImage.GetPointer() << std::endl; + os << indent << "FixedImagePyramid: "; + os << m_FixedImagePyramid.GetPointer() << std::endl; + os << indent << "MovingImagePyramid: "; + os << m_MovingImagePyramid.GetPointer() << std::endl; + + os << indent << "NumberOfLevels: "; + os << m_NumberOfLevels << std::endl; + + os << indent << "CurrentLevel: "; + os << m_CurrentLevel << std::endl; + + os << indent << "InitialTransformParameters: "; + os << m_InitialTransformParameters << std::endl; + os << indent << "InitialTransformParametersOfNextLevel: "; + os << m_InitialTransformParametersOfNextLevel << std::endl; + os << indent << "LastTransformParameters: "; + os << m_LastTransformParameters << std::endl; + os << indent << "FixedImageRegion: "; + os << m_FixedImageRegion << std::endl; + for(unsigned int level=0; level< m_FixedImageRegionPyramid.size(); level++) + { + os << indent << "FixedImageRegion at level " << level << ": "; + os << m_FixedImageRegionPyramid[level] << std::endl; + } + os << indent << "FixedImagePyramidSchedule : " << std::endl; + os << m_FixedImagePyramidSchedule << std::endl; + os << indent << "MovingImagePyramidSchedule : " << std::endl; + os << m_MovingImagePyramidSchedule << std::endl; + +} + + +/* + * Generate Data + */ +template < typename TFixedImage, typename TMovingImage > +void +SpatioTemporalMultiResolutionImageRegistrationMethod +::GenerateData() +{ + this->StartRegistration(); +} + +template < typename TFixedImage, typename TMovingImage > +unsigned long +SpatioTemporalMultiResolutionImageRegistrationMethod +::GetMTime() const +{ + unsigned long mtime = Superclass::GetMTime(); + unsigned long m; + + + // Some of the following should be removed once ivars are put in the + // input and output lists + + if (m_Transform) + { + m = m_Transform->GetMTime(); + mtime = (m > mtime ? m : mtime); + } + + if (m_Interpolator) + { + m = m_Interpolator->GetMTime(); + mtime = (m > mtime ? m : mtime); + } + + if (m_Metric) + { + m = m_Metric->GetMTime(); + mtime = (m > mtime ? m : mtime); + } + + if (m_Optimizer) + { + m = m_Optimizer->GetMTime(); + mtime = (m > mtime ? m : mtime); + } + + if (m_FixedImage) + { + m = m_FixedImage->GetMTime(); + mtime = (m > mtime ? m : mtime); + } + + if (m_MovingImage) + { + m = m_MovingImage->GetMTime(); + mtime = (m > mtime ? m : mtime); + } + + return mtime; + +} + +/* + * Get Output + */ +template < typename TFixedImage, typename TMovingImage > +const typename SpatioTemporalMultiResolutionImageRegistrationMethod::TransformOutputType * +SpatioTemporalMultiResolutionImageRegistrationMethod +::GetOutput() const +{ + return static_cast< const TransformOutputType * >( this->ProcessObject::GetOutput(0) ); +} + +template < typename TFixedImage, typename TMovingImage > +DataObject::Pointer +SpatioTemporalMultiResolutionImageRegistrationMethod +::MakeOutput(unsigned int output) +{ + switch (output) + { + case 0: + return static_cast(TransformOutputType::New().GetPointer()); + break; + default: + itkExceptionMacro("MakeOutput request for an output number larger than the expected number of outputs"); + return 0; + } +} + +} // end namespace clitk + + +#endif diff --git a/registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.h b/registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.h new file mode 100644 index 0000000..ca4a001 --- /dev/null +++ b/registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.h @@ -0,0 +1,162 @@ +/*========================================================================= + 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 __clitkSpatioTemporalMultiResolutionPyramidImageFilter_h +#define __clitkSpatioTemporalMultiResolutionPyramidImageFilter_h +#include "itkImageToImageFilter.h" +#include "itkArray2D.h" + +namespace clitk +{ + +template < class TInputImage, class TOutputImage > +class ITK_EXPORT SpatioTemporalMultiResolutionPyramidImageFilter : + public itk::ImageToImageFilter< TInputImage, TOutputImage > +{ + +public: + /** Standard class typedefs. */ + typedef SpatioTemporalMultiResolutionPyramidImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(SpatioTemporalMultiResolutionPyramidImageFilter, ImageToImageFilter); + + /** ScheduleType typedef support. */ + typedef itk::Array2D ScheduleType; + + /** ImageDimension enumeration. */ + itkStaticConstMacro(ImageDimension, unsigned int, + TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, + TOutputImage::ImageDimension); + + /** Inherit types from Superclass. */ + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename Superclass::InputImagePointer InputImagePointer; + typedef typename Superclass::OutputImagePointer OutputImagePointer; + typedef typename Superclass::InputImageConstPointer InputImageConstPointer; + + /** Set the number of multi-resolution levels. The matrix containing the + * schedule will be resized accordingly. The schedule is populated with + * default values. At the coarset (0) level, the shrink factors are set + * 2^(nlevel - 1) for all dimension. These shrink factors are halved for + * subsequent levels. The number of levels is clamped to a minimum value + * of 1. All shrink factors are also clamped to a minimum value of 1. */ + virtual void SetNumberOfLevels(unsigned int num); + + /** Get the number of multi-resolution levels. */ + itkGetConstMacro(NumberOfLevels, unsigned int); + + /** Set a multi-resolution schedule. The input schedule must have only + * ImageDimension number of columns and NumberOfLevels number of rows. For + * each dimension, the shrink factor must be non-increasing with respect to + * subsequent levels. This function will clamp shrink factors to satisify + * this condition. All shrink factors less than one will also be clamped + * to the value of 1. */ + virtual void SetSchedule( const ScheduleType& schedule ); + + /** Get the multi-resolution schedule. */ + itkGetConstReferenceMacro(Schedule, ScheduleType); + + /** Set the starting shrink factor for the coarset (0) resolution + * level. The schedule is then populated with defaults values obtained by + * halving the factors at the previous level. All shrink factors are + * clamped to a minimum value of 1. */ + virtual void SetStartingShrinkFactors( unsigned int factor ); + virtual void SetStartingShrinkFactors( unsigned int* factors ); + + /** Get the starting shrink factors */ + const unsigned int * GetStartingShrinkFactors() const; + + /** Test if the schedule is downward divisible. This method returns true if + * at every level, the shrink factors are divisble by the shrink factors at + * the next level. */ + static bool IsScheduleDownwardDivisible( const ScheduleType& schedule ); + + /** MultiResolutionPyramidImageFilter produces images which are of + * different resolution and different pixel spacing than its input image. + * As such, MultiResolutionPyramidImageFilter needs to provide an + * implementation for GenerateOutputInformation() in order to inform the + * pipeline execution model. The original documentation of this method is + * below. \sa ProcessObject::GenerateOutputInformaton() */ + virtual void GenerateOutputInformation(); + + /** Given one output whose requested region has been set, this method sets + * the requested region for the remaining output images. The original + * documentation of this method is below. \sa + * ProcessObject::GenerateOutputRequestedRegion(); */ + virtual void GenerateOutputRequestedRegion(itk::DataObject *output); + + /** MultiResolutionPyramidImageFilter requires a larger input requested + * region than the output requested regions to accomdate the shrinkage and + * smoothing operations. As such, MultiResolutionPyramidImageFilter needs + * to provide an implementation for GenerateInputRequestedRegion(). The + * original documentation of this method is below. \sa + * ProcessObject::GenerateInputRequestedRegion() */ + virtual void GenerateInputRequestedRegion(); + + itkSetMacro(MaximumError,double); + itkGetConstReferenceMacro(MaximumError,double); + + itkSetMacro(UseShrinkImageFilter,bool); + itkGetConstMacro(UseShrinkImageFilter,bool); + itkBooleanMacro(UseShrinkImageFilter); + + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(SameDimensionCheck, + (itk::Concept::SameDimension)); + itkConceptMacro(OutputHasNumericTraitsCheck, + (itk::Concept::HasNumericTraits)); + /** End concept checking */ +#endif + +protected: + SpatioTemporalMultiResolutionPyramidImageFilter(); + ~SpatioTemporalMultiResolutionPyramidImageFilter() {}; + void PrintSelf(std::ostream&os, itk::Indent indent) const; + + /** Generate the output data. */ + void GenerateData(); + + double m_MaximumError; + unsigned int m_NumberOfLevels; + ScheduleType m_Schedule; + bool m_UseShrinkImageFilter; + +private: + SpatioTemporalMultiResolutionPyramidImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + + +} // namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkSpatioTemporalMultiResolutionPyramidImageFilter.txx" +#endif + +#endif diff --git a/registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.txx b/registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.txx new file mode 100644 index 0000000..55e599c --- /dev/null +++ b/registration/clitkSpatioTemporalMultiResolutionPyramidImageFilter.txx @@ -0,0 +1,629 @@ +/*========================================================================= + 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 __clitkSpatioTemporalMultiResolutionPyramidImageFilter_txx +#define __clitkSpatioTemporalMultiResolutionPyramidImageFilter_txx +#include "clitkSpatioTemporalMultiResolutionPyramidImageFilter.h" +#include "itkGaussianOperator.h" +#include "itkCastImageFilter.h" +#include "itkDiscreteGaussianImageFilter.h" +#include "itkExceptionObject.h" +#include "itkResampleImageFilter.h" +#include "itkShrinkImageFilter.h" +#include "itkIdentityTransform.h" + +#include "vnl/vnl_math.h" + +namespace clitk +{ + +/** + * Constructor + */ +template +SpatioTemporalMultiResolutionPyramidImageFilter +::SpatioTemporalMultiResolutionPyramidImageFilter() +{ + m_NumberOfLevels = 0; + this->SetNumberOfLevels( 2 ); + m_MaximumError = 0.1; + m_UseShrinkImageFilter = false; +} + + +/** + * Set the number of computation levels + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::SetNumberOfLevels( + unsigned int num ) +{ + if( m_NumberOfLevels == num ) + { + return; + } + + this->Modified(); + + // clamp value to be at least one + m_NumberOfLevels = num; + if( m_NumberOfLevels < 1 ) m_NumberOfLevels = 1; + + // resize the schedules + ScheduleType temp( m_NumberOfLevels, ImageDimension ); + temp.Fill( 0 ); + m_Schedule = temp; + + // determine initial shrink factor + unsigned int startfactor = 1; + startfactor = startfactor << ( m_NumberOfLevels - 1 ); + + // set the starting shrink factors + this->SetStartingShrinkFactors( startfactor ); + + // set the required number of outputs + this->SetNumberOfRequiredOutputs( m_NumberOfLevels ); + + unsigned int numOutputs = static_cast( this->GetNumberOfOutputs() ); + unsigned int idx; + if( numOutputs < m_NumberOfLevels ) + { + // add extra outputs + for( idx = numOutputs; idx < m_NumberOfLevels; idx++ ) + { + typename itk::DataObject::Pointer output = + this->MakeOutput( idx ); + this->SetNthOutput( idx, output.GetPointer() ); + } + + } + else if( numOutputs > m_NumberOfLevels ) + { + // remove extra outputs + for( idx = m_NumberOfLevels; idx < numOutputs; idx++ ) + { + typename itk::DataObject::Pointer output = + this->GetOutputs()[idx]; + this->RemoveOutput( output ); + } + } + +} + + +/* + * Set the starting shrink factors + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::SetStartingShrinkFactors( + unsigned int factor ) +{ + + unsigned int array[ImageDimension]; + //JV temporal dimension always 1 + for( unsigned int dim = 0; dim < ImageDimension-1; ++dim ) + { + array[dim] = factor; + } + array[ImageDimension-1]=1; + + this->SetStartingShrinkFactors( array ); + +} + + +/** + * Set the starting shrink factors + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::SetStartingShrinkFactors( + unsigned int * factors ) +{ + + for( unsigned int dim = 0; dim < ImageDimension-1; ++dim ) + { + m_Schedule[0][dim] = factors[dim]; + if( m_Schedule[0][dim] == 0 ) + { + m_Schedule[0][dim] = 1; + } + } + //JV temporal dimension always 1 + m_Schedule[0][ImageDimension-1]=1; + + for( unsigned int level = 1; level < m_NumberOfLevels; ++level ) + { + //JV temporal dimension always 1 + for( unsigned int dim = 0; dim < ImageDimension-1; ++dim ) + { + m_Schedule[level][dim] = m_Schedule[level-1][dim] / 2; + if( m_Schedule[level][dim] == 0 ) + { + m_Schedule[level][dim] = 1; + } + } + m_Schedule[level][ImageDimension-1]=1; + } + + this->Modified(); + +} + + +/* + * Get the starting shrink factors + */ +template +const unsigned int * +SpatioTemporalMultiResolutionPyramidImageFilter +::GetStartingShrinkFactors() const +{ + return ( m_Schedule.data_block() ); +} + + +/* + * Set the multi-resolution schedule + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::SetSchedule( + const ScheduleType& schedule ) +{ + + if( schedule.rows() != m_NumberOfLevels || + schedule.columns() != ImageDimension ) + { + itkDebugMacro(<< "Schedule has wrong dimensions" ); + return; + } + + if( schedule == m_Schedule ) + { + return; + } + + this->Modified(); + unsigned int level, dim; + for( level = 0; level < m_NumberOfLevels; level++ ) + { + //JV temporal dimension always 1 + for( dim = 0; dim < ImageDimension-1; dim++ ) + { + + m_Schedule[level][dim] = schedule[level][dim]; + + // set schedule to max( 1, min(schedule[level], + // schedule[level-1] ); + if( level > 0 ) + { + m_Schedule[level][dim] = vnl_math_min( m_Schedule[level][dim], m_Schedule[level-1][dim] ); + } + + if( m_Schedule[level][dim] < 1 ) + { + m_Schedule[level][dim] = 1; + } + } + m_Schedule[level][ImageDimension-1]=1; + } +} + + +/* + * Is the schedule downward divisible ? + */ +template +bool +SpatioTemporalMultiResolutionPyramidImageFilter +::IsScheduleDownwardDivisible( const ScheduleType& schedule ) +{ + + unsigned int ilevel, idim; + for( ilevel = 0; ilevel < schedule.rows() - 1; ilevel++ ) + { + for( idim = 0; idim < schedule.columns(); idim++ ) + { + if( schedule[ilevel][idim] == 0 ) + { + return false; + } + if( ( schedule[ilevel][idim] % schedule[ilevel+1][idim] ) > 0 ) + { + return false; + } + } + } + + return true; +} + +/* + * GenerateData for non downward divisible schedules + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::GenerateData() +{ + // Get the input and output pointers + InputImageConstPointer inputPtr = this->GetInput(); + + // Create caster, smoother and resampleShrinker filters + typedef itk::CastImageFilter CasterType; + typedef itk::DiscreteGaussianImageFilter SmootherType; + + typedef itk::ImageToImageFilter ImageToImageType; + typedef itk::ResampleImageFilter ResampleShrinkerType; + typedef itk::ShrinkImageFilter ShrinkerType; + + typename CasterType::Pointer caster = CasterType::New(); + typename SmootherType::Pointer smoother = SmootherType::New(); + + typename ImageToImageType::Pointer shrinkerFilter; + // + // only one of these pointers is going to be valid, depending on the + // value of UseShrinkImageFilter flag + typename ResampleShrinkerType::Pointer resampleShrinker; + typename ShrinkerType::Pointer shrinker; + + if(this->GetUseShrinkImageFilter()) + { + shrinker = ShrinkerType::New(); + shrinkerFilter = shrinker.GetPointer(); + } + else + { + resampleShrinker = ResampleShrinkerType::New(); + typedef itk::LinearInterpolateImageFunction< OutputImageType, double > + LinearInterpolatorType; + typename LinearInterpolatorType::Pointer interpolator = + LinearInterpolatorType::New(); + resampleShrinker->SetInterpolator( interpolator ); + resampleShrinker->SetDefaultPixelValue( 0 ); + shrinkerFilter = resampleShrinker.GetPointer(); + } + // Setup the filters + caster->SetInput( inputPtr ); + + smoother->SetUseImageSpacing( false ); + smoother->SetInput( caster->GetOutput() ); + smoother->SetMaximumError( m_MaximumError ); + + shrinkerFilter->SetInput( smoother->GetOutput() ); + + unsigned int ilevel, idim; + unsigned int factors[ImageDimension]; + double variance[ImageDimension]; + + for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ ) + { + this->UpdateProgress( static_cast( ilevel ) / + static_cast( m_NumberOfLevels ) ); + + // Allocate memory for each output + OutputImagePointer outputPtr = this->GetOutput( ilevel ); + outputPtr->SetBufferedRegion( outputPtr->GetRequestedRegion() ); + outputPtr->Allocate(); + + // compute shrink factors and variances + for( idim = 0; idim < ImageDimension; idim++ ) + { + factors[idim] = m_Schedule[ilevel][idim]; + variance[idim] = vnl_math_sqr( 0.5 * + static_cast( factors[idim] ) ); + } + + if(!this->GetUseShrinkImageFilter()) + { + typedef itk::IdentityTransform + IdentityTransformType; + typename IdentityTransformType::Pointer identityTransform = + IdentityTransformType::New(); + resampleShrinker->SetOutputParametersFromImage( outputPtr ); + resampleShrinker->SetTransform(identityTransform); + } + else + { + shrinker->SetShrinkFactors(factors); + } + // use mini-pipeline to compute output + smoother->SetVariance( variance ); + + shrinkerFilter->GraftOutput( outputPtr ); + + // force to always update in case shrink factors are the same + shrinkerFilter->Modified(); + shrinkerFilter->UpdateLargestPossibleRegion(); + this->GraftNthOutput( ilevel, shrinkerFilter->GetOutput() ); + } +} + +/** + * PrintSelf method + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os,indent); + + os << indent << "MaximumError: " << m_MaximumError << std::endl; + os << indent << "No. levels: " << m_NumberOfLevels << std::endl; + os << indent << "Schedule: " << std::endl; + os << m_Schedule << std::endl; + os << "Use ShrinkImageFilter= " << m_UseShrinkImageFilter << std::endl; +} + + +/* + * GenerateOutputInformation + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::GenerateOutputInformation() +{ + + // call the superclass's implementation of this method + Superclass::GenerateOutputInformation(); + + // get pointers to the input and output + InputImageConstPointer inputPtr = this->GetInput(); + + if ( !inputPtr ) + { + itkExceptionMacro( << "Input has not been set" ); + } + + const typename InputImageType::PointType& + inputOrigin = inputPtr->GetOrigin(); + const typename InputImageType::SpacingType& + inputSpacing = inputPtr->GetSpacing(); + const typename InputImageType::DirectionType& + inputDirection = inputPtr->GetDirection(); + const typename InputImageType::SizeType& inputSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + const typename InputImageType::IndexType& inputStartIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + + typedef typename OutputImageType::SizeType SizeType; + typedef typename SizeType::SizeValueType SizeValueType; + typedef typename OutputImageType::IndexType IndexType; + typedef typename IndexType::IndexValueType IndexValueType; + + OutputImagePointer outputPtr; + typename OutputImageType::PointType outputOrigin; + typename OutputImageType::SpacingType outputSpacing; + SizeType outputSize; + IndexType outputStartIndex; + + // we need to compute the output spacing, the output image size, + // and the output image start index + for(unsigned int ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ ) + { + outputPtr = this->GetOutput( ilevel ); + if( !outputPtr ) { continue; } + + for(unsigned int idim = 0; idim < OutputImageType::ImageDimension; idim++ ) + { + const double shrinkFactor = static_cast( m_Schedule[ilevel][idim] ); + outputSpacing[idim] = inputSpacing[idim] * shrinkFactor; + + outputSize[idim] = static_cast( + vcl_floor(static_cast(inputSize[idim]) / shrinkFactor ) ); + if( outputSize[idim] < 1 ) { outputSize[idim] = 1; } + + outputStartIndex[idim] = static_cast( + vcl_ceil(static_cast(inputStartIndex[idim]) / shrinkFactor ) ); + } + //Now compute the new shifted origin for the updated levels; + const typename OutputImageType::PointType::VectorType outputOriginOffset + =(inputDirection*(outputSpacing-inputSpacing))*0.5; + for(unsigned int idim = 0; idim < OutputImageType::ImageDimension; idim++ ) + { + outputOrigin[idim]=inputOrigin[idim]+outputOriginOffset[idim]; + } + + typename OutputImageType::RegionType outputLargestPossibleRegion; + outputLargestPossibleRegion.SetSize( outputSize ); + outputLargestPossibleRegion.SetIndex( outputStartIndex ); + + outputPtr->SetLargestPossibleRegion( outputLargestPossibleRegion ); + outputPtr->SetOrigin ( outputOrigin ); + outputPtr->SetSpacing( outputSpacing ); + outputPtr->SetDirection( inputDirection );//Output Direction should be same as input. + } +} + + +/* + * GenerateOutputRequestedRegion + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::GenerateOutputRequestedRegion(itk::DataObject * refOutput ) +{ + // call the superclass's implementation of this method + Superclass::GenerateOutputRequestedRegion( refOutput ); + + // find the index for this output + unsigned int refLevel = refOutput->GetSourceOutputIndex(); + + // compute baseIndex and baseSize + typedef typename OutputImageType::SizeType SizeType; + typedef typename SizeType::SizeValueType SizeValueType; + typedef typename OutputImageType::IndexType IndexType; + typedef typename IndexType::IndexValueType IndexValueType; + typedef typename OutputImageType::RegionType RegionType; + + TOutputImage * ptr = static_cast( refOutput ); + if( !ptr ) + { + itkExceptionMacro( << "Could not cast refOutput to TOutputImage*." ); + } + + unsigned int ilevel, idim; + + if ( ptr->GetRequestedRegion() == ptr->GetLargestPossibleRegion() ) + { + // set the requested regions for the other outputs to their + // requested region + + for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ ) + { + if( ilevel == refLevel ) { continue; } + if( !this->GetOutput(ilevel) ) { continue; } + this->GetOutput(ilevel)->SetRequestedRegionToLargestPossibleRegion(); + } + } + else + { + // compute requested regions for the other outputs based on + // the requested region of the reference output + IndexType outputIndex; + SizeType outputSize; + RegionType outputRegion; + IndexType baseIndex = ptr->GetRequestedRegion().GetIndex(); + SizeType baseSize = ptr->GetRequestedRegion().GetSize(); + + for( idim = 0; idim < TOutputImage::ImageDimension; idim++ ) + { + unsigned int factor = m_Schedule[refLevel][idim]; + baseIndex[idim] *= static_cast( factor ); + baseSize[idim] *= static_cast( factor ); + } + + for( ilevel = 0; ilevel < m_NumberOfLevels; ilevel++ ) + { + if( ilevel == refLevel ) { continue; } + if( !this->GetOutput(ilevel) ) { continue; } + + for( idim = 0; idim < TOutputImage::ImageDimension; idim++ ) + { + + double factor = static_cast( m_Schedule[ilevel][idim] ); + + outputSize[idim] = static_cast( + vcl_floor(static_cast(baseSize[idim]) / factor ) ); + if( outputSize[idim] < 1 ) { outputSize[idim] = 1; } + + outputIndex[idim] = static_cast( + vcl_ceil(static_cast(baseIndex[idim]) / factor ) ); + + } + + outputRegion.SetIndex( outputIndex ); + outputRegion.SetSize( outputSize ); + + // make sure the region is within the largest possible region + outputRegion.Crop( this->GetOutput( ilevel )-> + GetLargestPossibleRegion() ); + // set the requested region + this->GetOutput( ilevel )->SetRequestedRegion( outputRegion ); + } + + } +} + + +/** + * GenerateInputRequestedRegion + */ +template +void +SpatioTemporalMultiResolutionPyramidImageFilter +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the input and output + InputImagePointer inputPtr = + const_cast< InputImageType * >( this->GetInput() ); + if ( !inputPtr ) + { + itkExceptionMacro( << "Input has not been set." ); + } + + // compute baseIndex and baseSize + typedef typename OutputImageType::SizeType SizeType; + typedef typename SizeType::SizeValueType SizeValueType; + typedef typename OutputImageType::IndexType IndexType; + typedef typename IndexType::IndexValueType IndexValueType; + typedef typename OutputImageType::RegionType RegionType; + + unsigned int refLevel = m_NumberOfLevels - 1; + SizeType baseSize = this->GetOutput(refLevel)->GetRequestedRegion().GetSize(); + IndexType baseIndex = this->GetOutput(refLevel)->GetRequestedRegion().GetIndex(); + RegionType baseRegion; + + unsigned int idim; + for( idim = 0; idim < ImageDimension; idim++ ) + { + unsigned int factor = m_Schedule[refLevel][idim]; + baseIndex[idim] *= static_cast( factor ); + baseSize[idim] *= static_cast( factor ); + } + baseRegion.SetIndex( baseIndex ); + baseRegion.SetSize( baseSize ); + + // compute requirements for the smoothing part + typedef typename TOutputImage::PixelType OutputPixelType; + typedef typename itk::GaussianOperator OperatorType; + + OperatorType *oper = new OperatorType; + + typename TInputImage::SizeType radius; + + RegionType inputRequestedRegion = baseRegion; + refLevel = 0; + + for( idim = 0; idim < TInputImage::ImageDimension; idim++ ) + { + oper->SetDirection(idim); + oper->SetVariance( vnl_math_sqr( 0.5 * static_cast( + m_Schedule[refLevel][idim] ) ) ); + oper->SetMaximumError( m_MaximumError ); + oper->CreateDirectional(); + radius[idim] = oper->GetRadius()[idim]; + } + delete oper; + + inputRequestedRegion.PadByRadius( radius ); + + // make sure the requested region is within the largest possible + inputRequestedRegion.Crop( inputPtr->GetLargestPossibleRegion() ); + + // set the input requested region + inputPtr->SetRequestedRegion( inputRequestedRegion ); + +} + + +} // namespace clitk + +#endif diff --git a/registration/clitkTransformToDeformationFieldSource.h b/registration/clitkTransformToDeformationFieldSource.h new file mode 100644 index 0000000..2e0a101 --- /dev/null +++ b/registration/clitkTransformToDeformationFieldSource.h @@ -0,0 +1,223 @@ +/*========================================================================= + 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 __clitkTransformToDeformationFieldSource_h +#define __clitkTransformToDeformationFieldSource_h +#include "itkTransform.h" +#include "itkImageSource.h" + +namespace clitk +{ + +/** \class TransformToDeformationFieldSource + * \brief Generate a deformation field from a coordinate transform + * + * This class was inspired on an the itkDeformationFieldImageFilter class. + * + * Output information (spacing, size and direction) for the output + * image should be set. This information has the normal defaults of + * unit spacing, zero origin and identity direction. Optionally, the + * output information can be obtained from a reference image. If the + * reference image is provided and UseReferenceImage is On, then the + * spacing, origin and direction of the reference image will be used. + * + * Since this filter produces an image which is a different size than + * its input, it needs to override several of the methods defined + * in ProcessObject in order to properly manage the pipeline execution model. + * In particular, this filter overrides + * ProcessObject::GenerateInputRequestedRegion() and + * ProcessObject::GenerateOutputInformation(). + * + * This filter is implemented as a multithreaded filter. It provides a + * ThreadedGenerateData() method for its implementation. + * + * \author Marius Staring, Leiden University Medical Center, The Netherlands. + * + * This class was taken from the Insight Journal paper: + * http://hdl.handle.net/1926/1387 + * + * + * \ingroup GeometricTransforms + */ +template +class ITK_EXPORT TransformToDeformationFieldSource: + public itk::ImageSource +{ +public: + /** Standard class typedefs. */ + typedef TransformToDeformationFieldSource Self; + typedef itk::ImageSource Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::Pointer OutputImagePointer; + typedef typename OutputImageType::ConstPointer OutputImageConstPointer; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( TransformToDeformationFieldSource, ImageSource ); + + /** Number of dimensions. */ + itkStaticConstMacro( ImageDimension, unsigned int, + TOutputImage::ImageDimension ); + + /** Typedefs for transform. */ + typedef itk::Transform TransformType; + typedef typename TransformType::ConstPointer TransformPointerType; + + /** Typedefs for output image. */ + typedef typename OutputImageType::PixelType PixelType; + // JV + itkStaticConstMacro(SpaceDimension, unsigned int,PixelType::Dimension); + typedef typename PixelType::ValueType PixelValueType; + typedef typename OutputImageType::RegionType RegionType; + typedef typename RegionType::SizeType SizeType; + typedef typename OutputImageType::IndexType IndexType; + typedef typename OutputImageType::PointType PointType; + typedef typename OutputImageType::SpacingType SpacingType; + typedef typename OutputImageType::PointType OriginType; + typedef typename OutputImageType::DirectionType DirectionType; + + /** Typedefs for base image. */ + typedef itk::ImageBase< itkGetStaticConstMacro( ImageDimension ) > ImageBaseType; + + /** Set the coordinate transformation. + * Set the coordinate transform to use for resampling. Note that this must + * be in physical coordinates and it is the output-to-input transform, NOT + * the input-to-output transform that you might naively expect. By default + * the filter uses an Identity transform. You must provide a different + * transform here, before attempting to run the filter, if you do not want to + * use the default Identity transform. */ + itkSetConstObjectMacro( Transform, TransformType ); + + /** Get a pointer to the coordinate transform. */ + itkGetConstObjectMacro( Transform, TransformType ); + + /** Set the size of the output image. */ + virtual void SetOutputSize( const SizeType & size ); + + /** Get the size of the output image. */ + virtual const SizeType & GetOutputSize(); + + /** Set the start index of the output largest possible region. + * The default is an index of all zeros. */ + virtual void SetOutputIndex( const IndexType & index ); + + /** Get the start index of the output largest possible region. */ + virtual const IndexType & GetOutputIndex(); + + /** Set the region of the output image. */ + itkSetMacro( OutputRegion, OutputImageRegionType ); + + /** Get the region of the output image. */ + itkGetConstReferenceMacro( OutputRegion, OutputImageRegionType ); + + /** Set the output image spacing. */ + itkSetMacro( OutputSpacing, SpacingType ); + virtual void SetOutputSpacing( const double* values ); + + /** Get the output image spacing. */ + itkGetConstReferenceMacro( OutputSpacing, SpacingType ); + + /** Set the output image origin. */ + itkSetMacro( OutputOrigin, OriginType ); + virtual void SetOutputOrigin( const double* values); + + /** Get the output image origin. */ + itkGetConstReferenceMacro( OutputOrigin, OriginType ); + + /** Set the output direction cosine matrix. */ + itkSetMacro( OutputDirection, DirectionType ); + itkGetConstReferenceMacro( OutputDirection, DirectionType ); + + /** Helper method to set the output parameters based on this image */ + void SetOutputParametersFromImage( const ImageBaseType * image ); + + /** DeformationFieldImageFilter produces a vector image. */ + virtual void GenerateOutputInformation( void ); + + /** Just checking if transform is set. */ + virtual void BeforeThreadedGenerateData( void ); + + /** Compute the Modified Time based on changes to the components. */ + unsigned long GetMTime( void ) const; + + // JV To allow 4D DVF conversion +// #ifdef ITK_USE_CONCEPT_CHECKING +// /** Begin concept checking */ +// itkStaticConstMacro(PixelDimension, unsigned int, +// PixelType::Dimension ); +// itkConceptMacro(SameDimensionCheck, +// (Concept::SameDimension)); +// /** End concept checking */ +// #endif + +protected: + TransformToDeformationFieldSource( ); + ~TransformToDeformationFieldSource( ) {}; + + void PrintSelf( std::ostream& os, itk::Indent indent ) const; + + /** TransformToDeformationFieldSource can be implemented as a multithreaded + * filter. + */ + void ThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread, + int threadId ); + + /** Default implementation for resampling that works for any + * transformation type. + */ + void NonlinearThreadedGenerateData( + const OutputImageRegionType& outputRegionForThread, + int threadId ); + + /** Faster implementation for resampling that works for with linear + * transformation types. + */ + void LinearThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread, + int threadId ); + +private: + + TransformToDeformationFieldSource( const Self& ); //purposely not implemented + void operator=( const Self& ); //purposely not implemented + + /** Member variables. */ + RegionType m_OutputRegion; // region of the output image + TransformPointerType m_Transform; // Coordinate transform to use + SpacingType m_OutputSpacing; // output image spacing + OriginType m_OutputOrigin; // output image origin + DirectionType m_OutputDirection; // output image direction cosines + +}; // end class TransformToDeformationFieldSource + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkTransformToDeformationFieldSource.txx" +#endif + +#endif // end #ifndef __clitkTransformToDeformationFieldSource_h diff --git a/registration/clitkTransformToDeformationFieldSource.txx b/registration/clitkTransformToDeformationFieldSource.txx new file mode 100644 index 0000000..a509304 --- /dev/null +++ b/registration/clitkTransformToDeformationFieldSource.txx @@ -0,0 +1,380 @@ +/*========================================================================= + 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 __clitkTransformToDeformationFieldSource_txx +#define __clitkTransformToDeformationFieldSource_txx +#include "clitkTransformToDeformationFieldSource.h" + +#include "itkIdentityTransform.h" +#include "itkProgressReporter.h" +#include "itkImageRegionIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" + +namespace clitk +{ +/** + * Constructor + */ + template + TransformToDeformationFieldSource::TransformToDeformationFieldSource() +{ + this->m_OutputSpacing.Fill(1.0); + this->m_OutputOrigin.Fill(0.0); + this->m_OutputDirection.SetIdentity(); + + SizeType size; + size.Fill( 0 ); + this->m_OutputRegion.SetSize( size ); + + IndexType index; + index.Fill( 0 ); + this->m_OutputRegion.SetIndex( index ); + + this->m_Transform + = itk::IdentityTransform::New(); +} // end Constructor + +/** + * Print out a description of self + * + * \todo Add details about this class + */ +template +void +TransformToDeformationFieldSource +::PrintSelf( std::ostream & os, itk::Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "OutputRegion: " << this->m_OutputRegion << std::endl; + os << indent << "OutputSpacing: " << this->m_OutputSpacing << std::endl; + os << indent << "OutputOrigin: " << this->m_OutputOrigin << std::endl; + os << indent << "OutputDirection: " << this->m_OutputDirection << std::endl; + os << indent << "Transform: " << this->m_Transform.GetPointer() << std::endl; +} // end PrintSelf() + +/** + * Set the output image size. + */ +template +void +TransformToDeformationFieldSource + ::SetOutputSize( const SizeType & size ) +{ + this->m_OutputRegion.SetSize( size ); +} + +/** + * Get the output image size. + */ +template +const typename TransformToDeformationFieldSource + ::SizeType & +TransformToDeformationFieldSource + ::GetOutputSize() +{ + return this->m_OutputRegion.GetSize(); +} + +/** + * Set the output image index. + */ +template +void +TransformToDeformationFieldSource + ::SetOutputIndex( const IndexType & index ) +{ + this->m_OutputRegion.SetIndex( index ); +} + +/** + * Get the output image index. + */ +template +const typename TransformToDeformationFieldSource + ::IndexType & +TransformToDeformationFieldSource + ::GetOutputIndex() +{ + return this->m_OutputRegion.GetIndex(); +} + +/** + * Set the output image spacing. + */ +template +void +TransformToDeformationFieldSource + ::SetOutputSpacing( const double *spacing ) +{ + SpacingType s( spacing ); + + this->SetOutputSpacing( s ); +} // end SetOutputSpacing() + +/** + * Set the output image origin. + */ +template +void +TransformToDeformationFieldSource + ::SetOutputOrigin( const double *origin ) +{ + OriginType p( origin ); + + this->SetOutputOrigin( p ); +} + +/** Helper method to set the output parameters based on this image */ +template +void +TransformToDeformationFieldSource + ::SetOutputParametersFromImage ( const ImageBaseType *image ) +{ + if ( !image ) + { + itkExceptionMacro(<< "Cannot use a null image reference"); + } + + this->SetOutputOrigin( image->GetOrigin() ); + this->SetOutputSpacing( image->GetSpacing() ); + this->SetOutputDirection( image->GetDirection() ); + this->SetOutputRegion( image->GetLargestPossibleRegion() ); +} // end SetOutputParametersFromImage() + +/** + * Set up state of filter before multi-threading. + * InterpolatorType::SetInputImage is not thread-safe and hence + * has to be set up before ThreadedGenerateData + */ +template +void +TransformToDeformationFieldSource + ::BeforeThreadedGenerateData( void ) +{ + if ( !this->m_Transform ) + { + itkExceptionMacro(<< "Transform not set"); + } +} // end BeforeThreadedGenerateData() + +/** + * ThreadedGenerateData + */ +template +void +TransformToDeformationFieldSource + ::ThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread, + int threadId ) +{ + // Check whether we can use a fast path for resampling. Fast path + // can be used if the transformation is linear. Transform respond + // to the IsLinear() call. + if ( this->m_Transform->IsLinear() ) + { + this->LinearThreadedGenerateData( outputRegionForThread, threadId ); + return; + } + + // Otherwise, we use the normal method where the transform is called + // for computing the transformation of every point. + this->NonlinearThreadedGenerateData( outputRegionForThread, threadId ); +} // end ThreadedGenerateData() + +template +void +TransformToDeformationFieldSource + ::NonlinearThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread, + int threadId ) +{ + // Get the output pointer + OutputImagePointer outputPtr = this->GetOutput(); + + // Create an iterator that will walk the output region for this thread. + typedef itk::ImageRegionIteratorWithIndex OutputIteratorType; + OutputIteratorType outIt( outputPtr, outputRegionForThread ); + + // Define a few variables that will be used to translate from an input pixel + // to an output pixel + PointType outputPoint; // Coordinates of output pixel + PointType transformedPoint; // Coordinates of transformed pixel + PixelType deformation; // the difference + + // Support for progress methods/callbacks + itk::ProgressReporter progress( this, threadId, + outputRegionForThread.GetNumberOfPixels() ); + + // Walk the output region + outIt.GoToBegin(); + while ( !outIt.IsAtEnd() ) + { + // Determine the index of the current output pixel + outputPtr->TransformIndexToPhysicalPoint( outIt.GetIndex(), outputPoint ); + + // Compute corresponding input pixel position + transformedPoint = this->m_Transform->TransformPoint( outputPoint ); + + // Compute the deformation + for ( unsigned int i = 0; i < SpaceDimension; ++i ) + { + deformation[i] = static_cast( + transformedPoint[i] - outputPoint[i] ); + } + + // Set it + outIt.Set( deformation ); + + // Update progress and iterator + progress.CompletedPixel(); + ++outIt; + } +} // end NonlinearThreadedGenerateData() + +template +void +TransformToDeformationFieldSource + ::LinearThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread, + int threadId ) +{ + // Get the output pointer + OutputImagePointer outputPtr = this->GetOutput(); + + // Create an iterator that will walk the output region for this thread. + typedef itk::ImageLinearIteratorWithIndex OutputIteratorType; + OutputIteratorType outIt( outputPtr, outputRegionForThread ); + + outIt.SetDirection( 0 ); + + // Define a few indices that will be used to translate from an input pixel + // to an output pixel + PointType outputPoint; // Coordinates of current output pixel + PointType transformedPoint; // Coordinates of transformed pixel + PixelType deformation; // the difference + + IndexType index; + + // Support for progress methods/callbacks + itk::ProgressReporter progress( this, threadId, + outputRegionForThread.GetNumberOfPixels() ); + + // Determine the position of the first pixel in the scanline + outIt.GoToBegin(); + index = outIt.GetIndex(); + outputPtr->TransformIndexToPhysicalPoint( index, outputPoint ); + + // Compute corresponding transformed pixel position + transformedPoint = this->m_Transform->TransformPoint( outputPoint ); + + // Compare with the ResampleImageFilter + + // Compute delta + PointType outputPointNeighbour; + PointType transformedPointNeighbour; + typedef typename PointType::VectorType VectorType; + VectorType delta; + ++index[0]; + outputPtr->TransformIndexToPhysicalPoint( index, outputPointNeighbour ); + transformedPointNeighbour = this->m_Transform->TransformPoint( + outputPointNeighbour ); + delta = transformedPointNeighbour - transformedPoint + - ( outputPointNeighbour - outputPoint ); + + // loop over the vector image + while ( !outIt.IsAtEnd() ) + { + // Get current point + index = outIt.GetIndex(); + outputPtr->TransformIndexToPhysicalPoint( index, outputPoint ); + + // Compute transformed point + transformedPoint = this->m_Transform->TransformPoint( outputPoint ); + + while ( !outIt.IsAtEndOfLine() ) + { + // Compute the deformation + for ( unsigned int i = 0; i < SpaceDimension; ++i ) + { + deformation[i] = static_cast( + transformedPoint[i] - outputPoint[i] ); + } + + // Set it + outIt.Set( deformation ); + + // Update stuff + progress.CompletedPixel(); + ++outIt; + transformedPoint += delta; + } + + outIt.NextLine(); + } +} // end LinearThreadedGenerateData() + +/** + * Inform pipeline of required output region + */ +template +void +TransformToDeformationFieldSource + ::GenerateOutputInformation( void ) +{ + // call the superclass' implementation of this method + Superclass::GenerateOutputInformation(); + + // get pointer to the output + OutputImagePointer outputPtr = this->GetOutput(); + if ( !outputPtr ) + { + return; + } + + outputPtr->SetLargestPossibleRegion( m_OutputRegion ); + + outputPtr->SetSpacing( m_OutputSpacing ); + outputPtr->SetOrigin( m_OutputOrigin ); + outputPtr->SetDirection( m_OutputDirection ); +} // end GenerateOutputInformation() + +/** + * Verify if any of the components has been modified. + */ +template +unsigned long +TransformToDeformationFieldSource + ::GetMTime( void ) const +{ + unsigned long latestTime = itk::Object::GetMTime(); + + if ( this->m_Transform ) + { + if ( latestTime < this->m_Transform->GetMTime() ) + { + latestTime = this->m_Transform->GetMTime(); + } + } + + return latestTime; +} // end GetMTime() +} // end namespace clitk + +#endif // end #ifndef _clitkTransformToDeformationFieldSource_txx -- 2.47.1