1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18 #ifndef clitkBLUTDIRGenericFilter_cxx
19 #define clitkBLUTDIRGenericFilter_cxx
21 /* =================================================
22 * @file clitkBLUTDIRGenericFilter.cxx
28 ===================================================*/
30 #include "clitkBLUTDIRGenericFilter.h"
31 #include "clitkBLUTDIRCommandIterationUpdateDVF.h"
32 #include "itkCenteredTransformInitializer.h"
33 #if (ITK_VERSION_MAJOR == 4) && (ITK_VERSION_MINOR < 6)
34 # include "itkTransformToDisplacementFieldSource.h"
36 # include "itkTransformToDisplacementFieldFilter.h"
42 //==============================================================================
43 // Creating an observer class that allows output at each iteration
44 //==============================================================================
45 class CommandIterationUpdate : public itk::Command
48 typedef CommandIterationUpdate Self;
49 typedef itk::Command Superclass;
50 typedef itk::SmartPointer<Self> Pointer;
53 CommandIterationUpdate() {};
55 typedef clitk::GenericOptimizer<args_info_clitkBLUTDIR> OptimizerType;
56 typedef const OptimizerType * OptimizerPointer;
58 // Set the generic optimizer
59 void SetOptimizer(OptimizerPointer o){m_Optimizer=o;}
62 void Execute(itk::Object *caller, const itk::EventObject & event)
64 Execute( (const itk::Object *)caller, event);
67 void Execute(const itk::Object * object, const itk::EventObject & event)
69 if( !(itk::IterationEvent().CheckEvent( &event )) )
74 m_Optimizer->OutputIterationInfo();
77 OptimizerPointer m_Optimizer;
80 //===========================================================================//
82 //==========================================================================//
83 BLUTDIRGenericFilter::BLUTDIRGenericFilter():
84 ImageToImageGenericFilter<Self>("Register DIR")
86 InitializeImageType<2>();
87 InitializeImageType<3>();
91 //=========================================================================//
93 //==========================================================================//
94 void BLUTDIRGenericFilter::SetArgsInfo(const args_info_clitkBLUTDIR & a){
96 if (m_ArgsInfo.reference_given) AddInputFilename(m_ArgsInfo.reference_arg);
98 if (m_ArgsInfo.target_given) {
99 AddInputFilename(m_ArgsInfo.target_arg);
102 if (m_ArgsInfo.output_given) SetOutputFilename(m_ArgsInfo.output_arg);
104 if (m_ArgsInfo.verbose_given) m_Verbose=true;
107 //=========================================================================//
108 //===========================================================================//
109 template<unsigned int Dim>
110 void BLUTDIRGenericFilter::InitializeImageType()
112 ADD_DEFAULT_IMAGE_TYPES(3);
114 //--------------------------------------------------------------------
116 //==============================================================================
117 //Creating an observer class that allows us to change parameters at subsequent levels
118 //==============================================================================
119 template <typename TRegistration,class args_info_clitkBLUTDIR>
120 class RegistrationInterfaceCommand : public itk::Command
123 typedef RegistrationInterfaceCommand Self;
124 typedef itk::Command Superclass;
125 typedef itk::SmartPointer<Self> Pointer;
128 RegistrationInterfaceCommand() { };
132 typedef TRegistration RegistrationType;
133 typedef RegistrationType * RegistrationPointer;
136 typedef typename RegistrationType::FixedImageType FixedImageType;
137 typedef typename FixedImageType::RegionType RegionType;
138 itkStaticConstMacro(ImageDimension, unsigned int,FixedImageType::ImageDimension);
139 typedef clitk::MultipleBSplineDeformableTransform<double, ImageDimension, ImageDimension> TransformType;
140 typedef clitk::MultipleBSplineDeformableTransformInitializer<TransformType, FixedImageType> InitializerType;
141 typedef typename InitializerType::CoefficientImageType CoefficientImageType;
142 typedef itk::CastImageFilter<CoefficientImageType, CoefficientImageType> CastImageFilterType;
143 typedef typename TransformType::ParametersType ParametersType;
144 typedef typename InitializerType::Pointer InitializerPointer;
145 typedef CommandIterationUpdate::Pointer CommandIterationUpdatePointer;
148 typedef clitk::GenericOptimizer<args_info_clitkBLUTDIR> GenericOptimizerType;
149 typedef typename GenericOptimizerType::Pointer GenericOptimizerPointer;
152 typedef typename RegistrationType::FixedImageType InternalImageType;
153 typedef clitk::GenericMetric<args_info_clitkBLUTDIR, InternalImageType, InternalImageType> GenericMetricType;
154 typedef typename GenericMetricType::Pointer GenericMetricPointer;
156 // Two arguments are passed to the Execute() method: the first
157 // is the pointer to the object which invoked the event and the
158 // second is the event that was invoked.
159 void Execute(itk::Object * object, const itk::EventObject & event)
161 if( !(itk::IterationEvent().CheckEvent( &event )) )
167 RegistrationPointer registration = dynamic_cast<RegistrationPointer>( object );
168 unsigned int numberOfLevels=registration->GetNumberOfLevels();
169 unsigned int currentLevel=registration->GetCurrentLevel()+1;
172 std::cout<<std::endl;
173 std::cout<<"========================================"<<std::endl;
174 std::cout<<"Starting resolution level "<<currentLevel<<" of "<<numberOfLevels<<"..."<<std::endl;
175 std::cout<<"========================================"<<std::endl;
176 std::cout<<std::endl;
181 // fixed image region pyramid
182 typedef clitk::MultiResolutionPyramidRegionFilter<InternalImageType> FixedImageRegionPyramidType;
183 typename FixedImageRegionPyramidType::Pointer fixedImageRegionPyramid=FixedImageRegionPyramidType::New();
184 fixedImageRegionPyramid->SetRegion(m_MetricRegion);
185 fixedImageRegionPyramid->SetSchedule(registration->GetFixedImagePyramid()->GetSchedule());
187 // Reinitialize the metric (!= number of samples)
188 m_GenericMetric= GenericMetricType::New();
189 m_GenericMetric->SetArgsInfo(m_ArgsInfo);
190 m_GenericMetric->SetFixedImage(registration->GetFixedImagePyramid()->GetOutput(registration->GetCurrentLevel()));
191 if (m_ArgsInfo.referenceMask_given) m_GenericMetric->SetFixedImageMask(registration->GetMetric()->GetFixedImageMask());
192 m_GenericMetric->SetFixedImageRegion(fixedImageRegionPyramid->GetOutput(registration->GetCurrentLevel()));
193 typedef itk::ImageToImageMetric< InternalImageType, InternalImageType > MetricType;
194 typename MetricType::Pointer metric=m_GenericMetric->GetMetricPointer();
195 registration->SetMetric(metric);
197 // Get the current coefficient image and make a COPY
198 typename itk::ImageDuplicator<CoefficientImageType>::Pointer caster = itk::ImageDuplicator<CoefficientImageType>::New();
199 std::vector<typename CoefficientImageType::Pointer> currentCoefficientImages = m_Initializer->GetTransform()->GetCoefficientImages();
200 for (unsigned i = 0; i < currentCoefficientImages.size(); ++i)
202 caster->SetInputImage(currentCoefficientImages[i]);
204 currentCoefficientImages[i] = caster->GetOutput();
208 // Write the intermediate result?
209 if (m_ArgsInfo.intermediate_given>=numberOfLevels)
210 writeImage<CoefficientImageType>(currentCoefficientImage, m_ArgsInfo.intermediate_arg[currentLevel-2], m_ArgsInfo.verbose_flag);
213 // Set the new transform properties
214 m_Initializer->SetImage(registration->GetFixedImagePyramid()->GetOutput(currentLevel-1));
215 if( m_Initializer->m_ControlPointSpacingIsGiven)
216 m_Initializer->SetControlPointSpacing(m_Initializer->m_ControlPointSpacingArray[registration->GetCurrentLevel()]);
217 if( m_Initializer->m_NumberOfControlPointsIsGiven)
218 m_Initializer->SetNumberOfControlPointsInsideTheImage(m_Initializer->m_NumberOfControlPointsInsideTheImageArray[registration->GetCurrentLevel()]);
220 // Reinitialize the transform
221 if (m_ArgsInfo.verbose_flag) std::cout<<"Initializing transform for level "<<currentLevel<<" of "<<numberOfLevels<<"..."<<std::endl;
222 m_Initializer->InitializeTransform();
223 ParametersType* newParameters= new typename TransformType::ParametersType(m_Initializer->GetTransform()->GetNumberOfParameters());
225 // DS : if we want to skip the last pyramid level, force to only 1 iteration
226 DD(m_ArgsInfo.skipLastPyramidLevel_flag);
227 if ((currentLevel == numberOfLevels) && (m_ArgsInfo.skipLastPyramidLevel_flag)) {
228 DD(m_ArgsInfo.maxIt_arg);
229 std::cout << "I skip the last pyramid level : set max iteration to 0" << std::endl;
230 m_ArgsInfo.maxIt_arg = 0;
231 DD(m_ArgsInfo.maxIt_arg);
234 // Reinitialize an Optimizer (!= number of parameters)
235 m_GenericOptimizer = GenericOptimizerType::New();
236 m_GenericOptimizer->SetArgsInfo(m_ArgsInfo);
237 m_GenericOptimizer->SetMaximize(m_Maximize);
238 m_GenericOptimizer->SetNumberOfParameters(m_Initializer->GetTransform()->GetNumberOfParameters());
241 typedef itk::SingleValuedNonLinearOptimizer OptimizerType;
242 OptimizerType::Pointer optimizer = m_GenericOptimizer->GetOptimizerPointer();
243 optimizer->AddObserver( itk::IterationEvent(), m_CommandIterationUpdate);
244 registration->SetOptimizer(optimizer);
245 m_CommandIterationUpdate->SetOptimizer(m_GenericOptimizer);
247 // Set the previous transform parameters to the registration
248 // if(m_Initializer->m_Parameters!=NULL )delete m_Initializer->m_Parameters;
249 m_Initializer->SetInitialParameters(currentCoefficientImages, *newParameters);
250 registration->SetInitialTransformParametersOfNextLevel(*newParameters);
254 void Execute(const itk::Object * , const itk::EventObject & )
259 void SetInitializer(InitializerPointer i){m_Initializer=i;}
260 InitializerPointer m_Initializer;
262 void SetArgsInfo(args_info_clitkBLUTDIR a){m_ArgsInfo=a;}
263 args_info_clitkBLUTDIR m_ArgsInfo;
265 void SetCommandIterationUpdate(CommandIterationUpdatePointer c){m_CommandIterationUpdate=c;};
266 CommandIterationUpdatePointer m_CommandIterationUpdate;
268 GenericOptimizerPointer m_GenericOptimizer;
269 void SetMaximize(bool b){m_Maximize=b;}
272 GenericMetricPointer m_GenericMetric;
273 void SetMetricRegion(RegionType i){m_MetricRegion=i;}
274 RegionType m_MetricRegion;
279 //==============================================================================
280 // Update with the number of dimensions and pixeltype
281 //==============================================================================
282 template<class InputImageType>
283 void BLUTDIRGenericFilter::UpdateWithInputImageType()
285 if (m_Verbose) std::cout << "BLUTDIRGenericFilter::UpdateWithInputImageType()" << std::endl;
287 //=============================================================================
289 //=============================================================================
290 bool threadsGiven=m_ArgsInfo.threads_given;
291 int threads=m_ArgsInfo.threads_arg;
292 typedef typename InputImageType::PixelType PixelType;
294 typedef double TCoordRep;
296 typename InputImageType::Pointer fixedImage = this->template GetInput<InputImageType>(0);
298 typename InputImageType::Pointer inputFixedImage = this->template GetInput<InputImageType>(0);
301 typename InputImageType::Pointer movingImage = this->template GetInput<InputImageType>(1);
303 typename InputImageType::Pointer inputMovingImage = this->template GetInput<InputImageType>(1);
305 typedef itk::Image< PixelType,InputImageType::ImageDimension > FixedImageType;
306 typedef itk::Image< PixelType, InputImageType::ImageDimension> MovingImageType;
307 const unsigned int SpaceDimension = InputImageType::ImageDimension;
308 //Whatever the pixel type, internally we work with an image represented in float
309 //Reading reference image
310 if (m_Verbose) std::cout<<"Reading images..."<<std::endl;
311 //=======================================================
313 //=======================================================
314 typename FixedImageType::Pointer croppedFixedImage=fixedImage;
315 //=======================================================
317 //=======================================================
318 // The original input region
319 typename FixedImageType::RegionType fixedImageRegion = fixedImage->GetLargestPossibleRegion();
321 // The transform region with respect to the input region:
322 // where should the transform be DEFINED (depends on mask)
323 typename FixedImageType::RegionType transformRegion = fixedImage->GetLargestPossibleRegion();
324 typename FixedImageType::RegionType::SizeType transformRegionSize=transformRegion.GetSize();
325 typename FixedImageType::RegionType::IndexType transformRegionIndex=transformRegion.GetIndex();
326 typename FixedImageType::PointType transformRegionOrigin=fixedImage->GetOrigin();
328 // The metric region with respect to the extracted transform region:
329 // where should the metric be CALCULATED (depends on transform)
330 typename FixedImageType::RegionType metricRegion = fixedImage->GetLargestPossibleRegion();
331 typename FixedImageType::RegionType::IndexType metricRegionIndex=metricRegion.GetIndex();
332 typename FixedImageType::PointType metricRegionOrigin=fixedImage->GetOrigin();
335 //===========================================================================
336 // If given, we connect a mask to reference or target
337 //============================================================================
338 typedef itk::ImageMaskSpatialObject< InputImageType::ImageDimension > MaskType;
339 typedef itk::Image< unsigned char, InputImageType::ImageDimension > ImageLabelType;
340 typename MaskType::Pointer fixedMask = NULL;
341 typename ImageLabelType::Pointer labels = NULL;
342 if (m_ArgsInfo.referenceMask_given)
344 fixedMask = MaskType::New();
345 labels = ImageLabelType::New();
346 typedef itk::ImageFileReader< ImageLabelType > LabelReaderType;
347 typename LabelReaderType::Pointer labelReader = LabelReaderType::New();
348 labelReader->SetFileName(m_ArgsInfo.referenceMask_arg);
351 labelReader->Update();
353 catch( itk::ExceptionObject & err )
355 std::cerr << "ExceptionObject caught while reading mask or labels !" << std::endl;
356 std::cerr << err << std::endl;
359 if (m_Verbose)std::cout <<"Reference image mask was read..." <<std::endl;
362 typedef itk::ResampleImageFilter<ImageLabelType, ImageLabelType> ResamplerType;
363 typename ResamplerType::Pointer resampler = ResamplerType::New();
364 typedef itk::NearestNeighborInterpolateImageFunction<ImageLabelType, TCoordRep> InterpolatorType;
365 typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
366 resampler->SetOutputParametersFromImage(fixedImage);
367 resampler->SetInterpolator(interpolator);
368 resampler->SetInput(labelReader->GetOutput());
370 labels = resampler->GetOutput();
372 // Set the image to the spatialObject
373 fixedMask->SetImage(labels);
375 // Find the bounding box of the "inside" label
376 typedef itk::LabelGeometryImageFilter<ImageLabelType> GeometryImageFilterType;
377 typename GeometryImageFilterType::Pointer geometryImageFilter=GeometryImageFilterType::New();
378 geometryImageFilter->SetInput(labels);
379 geometryImageFilter->Update();
380 typename GeometryImageFilterType::BoundingBoxType boundingBox = geometryImageFilter->GetBoundingBox(1);
382 // Limit the transform region to the mask
383 for (unsigned int i=0; i<InputImageType::ImageDimension; i++)
385 transformRegionIndex[i]=boundingBox[2*i];
386 transformRegionSize[i]=boundingBox[2*i+1]-boundingBox[2*i]+1;
388 transformRegion.SetSize(transformRegionSize);
389 transformRegion.SetIndex(transformRegionIndex);
390 fixedImage->TransformIndexToPhysicalPoint(transformRegion.GetIndex(), transformRegionOrigin);
392 // Crop the fixedImage to the bounding box to facilitate multi-resolution
393 typedef itk::ExtractImageFilter<FixedImageType,FixedImageType> ExtractImageFilterType;
394 typename ExtractImageFilterType::Pointer extractImageFilter=ExtractImageFilterType::New();
395 extractImageFilter->SetDirectionCollapseToSubmatrix();
396 extractImageFilter->SetInput(fixedImage);
397 extractImageFilter->SetExtractionRegion(transformRegion);
398 extractImageFilter->Update();
399 croppedFixedImage=extractImageFilter->GetOutput();
401 // Update the metric region
402 metricRegion = croppedFixedImage->GetLargestPossibleRegion();
403 metricRegionIndex=metricRegion.GetIndex();
404 croppedFixedImage->TransformIndexToPhysicalPoint(metricRegionIndex, metricRegionOrigin);
406 // Set start index to zero (with respect to croppedFixedImage/transform region)
407 metricRegionIndex.Fill(0);
408 metricRegion.SetIndex(metricRegionIndex);
409 croppedFixedImage->SetRegions(metricRegion);
410 croppedFixedImage->SetOrigin(metricRegionOrigin);
413 typedef itk::ImageMaskSpatialObject< InputImageType::ImageDimension > MaskType;
414 typename MaskType::Pointer movingMask=NULL;
415 if (m_ArgsInfo.targetMask_given)
417 movingMask= MaskType::New();
418 typedef itk::Image< unsigned char, InputImageType::ImageDimension > ImageMaskType;
419 typedef itk::ImageFileReader< ImageMaskType > MaskReaderType;
420 typename MaskReaderType::Pointer maskReader = MaskReaderType::New();
421 maskReader->SetFileName(m_ArgsInfo.targetMask_arg);
424 maskReader->Update();
426 catch( itk::ExceptionObject & err )
428 std::cerr << "ExceptionObject caught !" << std::endl;
429 std::cerr << err << std::endl;
431 if (m_Verbose)std::cout <<"Target image mask was read..." <<std::endl;
433 movingMask->SetImage( maskReader->GetOutput() );
437 //=======================================================
439 //=======================================================
443 // Fixed image region
444 std::cout<<"The fixed image has its origin at "<<fixedImage->GetOrigin()<<std::endl
445 <<"The fixed image region starts at index "<<fixedImageRegion.GetIndex()<<std::endl
446 <<"The fixed image region has size "<< fixedImageRegion.GetSize()<<std::endl;
449 std::cout<<"The transform has its origin at "<<transformRegionOrigin<<std::endl
450 <<"The transform region will start at index "<<transformRegion.GetIndex()<<std::endl
451 <<"The transform region has size "<< transformRegion.GetSize()<<std::endl;
454 std::cout<<"The metric region has its origin at "<<metricRegionOrigin<<std::endl
455 <<"The metric region will start at index "<<metricRegion.GetIndex()<<std::endl
456 <<"The metric region has size "<< metricRegion.GetSize()<<std::endl;
461 //=======================================================
462 // Pyramids (update them for transform initializer)
463 //=======================================================
464 typedef itk::RecursiveMultiResolutionPyramidImageFilter< FixedImageType, FixedImageType> FixedImagePyramidType;
465 typedef itk::RecursiveMultiResolutionPyramidImageFilter< MovingImageType, MovingImageType> MovingImagePyramidType;
466 typename FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New();
467 typename MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New();
468 fixedImagePyramid->SetUseShrinkImageFilter(false);
469 fixedImagePyramid->SetInput(croppedFixedImage);
470 fixedImagePyramid->SetNumberOfLevels(m_ArgsInfo.levels_arg);
471 movingImagePyramid->SetUseShrinkImageFilter(false);
472 movingImagePyramid->SetInput(movingImage);
473 movingImagePyramid->SetNumberOfLevels(m_ArgsInfo.levels_arg);
474 if (m_Verbose) std::cout<<"Creating the image pyramid..."<<std::endl;
475 fixedImagePyramid->Update();
476 movingImagePyramid->Update();
477 typedef clitk::MultiResolutionPyramidRegionFilter<FixedImageType> FixedImageRegionPyramidType;
478 typename FixedImageRegionPyramidType::Pointer fixedImageRegionPyramid=FixedImageRegionPyramidType::New();
479 fixedImageRegionPyramid->SetRegion(metricRegion);
480 fixedImageRegionPyramid->SetSchedule(fixedImagePyramid->GetSchedule());
483 //=======================================================
484 // Rigid or Affine Transform
485 //=======================================================
486 typedef itk::AffineTransform <double,3> RigidTransformType;
487 RigidTransformType::Pointer rigidTransform=NULL;
488 if (m_ArgsInfo.initMatrix_given)
490 if(m_Verbose) std::cout<<"Reading the prior transform matrix "<< m_ArgsInfo.initMatrix_arg<<"..."<<std::endl;
491 rigidTransform=RigidTransformType::New();
492 itk::Matrix<double,4,4> rigidTransformMatrix=clitk::ReadMatrix3D(m_ArgsInfo.initMatrix_arg);
495 itk::Matrix<double,3,3> finalRotation = clitk::GetRotationalPartMatrix3D(rigidTransformMatrix);
496 rigidTransform->SetMatrix(finalRotation);
498 //Set the translation
499 itk::Vector<double,3> finalTranslation = clitk::GetTranslationPartMatrix3D(rigidTransformMatrix);
500 rigidTransform->SetTranslation(finalTranslation);
502 else if (m_ArgsInfo.centre_flag)
504 if(m_Verbose) std::cout<<"No itinial matrix given and \"centre\" flag switched on. Centering all images..."<<std::endl;
506 rigidTransform=RigidTransformType::New();
508 typedef itk::CenteredTransformInitializer<RigidTransformType, FixedImageType, MovingImageType > TransformInitializerType;
509 typename TransformInitializerType::Pointer initializer = TransformInitializerType::New();
510 initializer->SetTransform( rigidTransform );
511 initializer->SetFixedImage( fixedImage );
512 initializer->SetMovingImage( movingImage );
513 initializer->GeometryOn();
514 initializer->InitializeTransform();
518 //=======================================================
519 // B-LUT FFD Transform
520 //=======================================================
521 typedef clitk::MultipleBSplineDeformableTransform<TCoordRep,InputImageType::ImageDimension, SpaceDimension > TransformType;
522 typename TransformType::Pointer transform = TransformType::New();
523 if (labels) transform->SetLabels(labels);
524 if (rigidTransform) transform->SetBulkTransform(rigidTransform);
526 //-------------------------------------------------------------------------
527 // The transform initializer
528 //-------------------------------------------------------------------------
529 typedef clitk::MultipleBSplineDeformableTransformInitializer< TransformType,FixedImageType> InitializerType;
530 typename InitializerType::Pointer initializer = InitializerType::New();
531 initializer->SetVerbose(m_Verbose);
532 initializer->SetImage(fixedImagePyramid->GetOutput(0));
533 initializer->SetTransform(transform);
535 //-------------------------------------------------------------------------
537 //-------------------------------------------------------------------------
538 typename FixedImageType::RegionType::SizeType splineOrders ;
539 splineOrders.Fill(3);
540 if (m_ArgsInfo.order_given)
541 for(unsigned int i=0; i<InputImageType::ImageDimension;i++)
542 splineOrders[i]=m_ArgsInfo.order_arg[i];
543 if (m_Verbose) std::cout<<"Setting the spline orders to "<<splineOrders<<"..."<<std::endl;
544 initializer->SetSplineOrders(splineOrders);
546 //-------------------------------------------------------------------------
548 //-------------------------------------------------------------------------
551 if (m_ArgsInfo.spacing_given)
553 initializer->m_ControlPointSpacingArray.resize(m_ArgsInfo.levels_arg);
554 initializer->SetControlPointSpacing(m_ArgsInfo.spacing_arg);
555 initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1]=initializer->m_ControlPointSpacing;
556 if (m_Verbose) std::cout<<"Using a control point spacing of "<<initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1]
557 <<" at level "<<m_ArgsInfo.levels_arg<<" of "<<m_ArgsInfo.levels_arg<<"..."<<std::endl;
559 for (int i=1; i<m_ArgsInfo.levels_arg; i++ )
561 initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i]=initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-i]*2;
562 if (m_Verbose) std::cout<<"Using a control point spacing of "<<initializer->m_ControlPointSpacingArray[m_ArgsInfo.levels_arg-1-i]
563 <<" at level "<<m_ArgsInfo.levels_arg-i<<" of "<<m_ArgsInfo.levels_arg<<"..."<<std::endl;
569 if (m_ArgsInfo.control_given)
571 initializer->m_NumberOfControlPointsInsideTheImageArray.resize(m_ArgsInfo.levels_arg);
572 initializer->SetNumberOfControlPointsInsideTheImage(m_ArgsInfo.control_arg);
573 initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1]=initializer->m_NumberOfControlPointsInsideTheImage;
574 if (m_Verbose) std::cout<<"Using "<< initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1]<<"control points inside the image"
575 <<" at level "<<m_ArgsInfo.levels_arg<<" of "<<m_ArgsInfo.levels_arg<<"..."<<std::endl;
577 for (int i=1; i<m_ArgsInfo.levels_arg; i++ )
579 for(unsigned int j=0;j<InputImageType::ImageDimension;j++)
580 initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i][j]=ceil ((double)initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-i][j]/2.);
581 // initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i]=ceil ((double)initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-i]/2.);
582 if (m_Verbose) std::cout<<"Using "<< initializer->m_NumberOfControlPointsInsideTheImageArray[m_ArgsInfo.levels_arg-1-i]<<"control points inside the image"
583 <<" at level "<<m_ArgsInfo.levels_arg<<" of "<<m_ArgsInfo.levels_arg<<"..."<<std::endl;
588 // Inialize on the first level
589 if (m_ArgsInfo.verbose_flag) std::cout<<"Initializing transform for level 1 of "<<m_ArgsInfo.levels_arg<<"..."<<std::endl;
590 if (m_ArgsInfo.spacing_given) initializer->SetControlPointSpacing( initializer->m_ControlPointSpacingArray[0]);
591 if (m_ArgsInfo.control_given) initializer->SetNumberOfControlPointsInsideTheImage(initializer->m_NumberOfControlPointsInsideTheImageArray[0]);
592 if (m_ArgsInfo.samplingFactor_given) initializer->SetSamplingFactors(m_ArgsInfo.samplingFactor_arg);
595 initializer->InitializeTransform();
597 //-------------------------------------------------------------------------
598 // Initial parameters (passed by reference)
599 //-------------------------------------------------------------------------
600 typedef typename TransformType::ParametersType ParametersType;
601 const unsigned int numberOfParameters = transform->GetNumberOfParameters();
602 ParametersType parameters(numberOfParameters);
603 parameters.Fill( 0.0 );
604 transform->SetParameters( parameters );
605 if (m_ArgsInfo.initCoeff_given) initializer->SetInitialParameters(m_ArgsInfo.initCoeff_arg, parameters);
607 //-------------------------------------------------------------------------
608 // DEBUG: use an itk BSpline instead of multilabel BLUTs
609 //-------------------------------------------------------------------------
610 typedef itk::Transform< TCoordRep, 3, 3 > RegistrationTransformType;
611 RegistrationTransformType::Pointer regTransform(transform);
612 typedef itk::BSplineDeformableTransform<TCoordRep,SpaceDimension, 3> SingleBSplineTransformType;
613 typename SingleBSplineTransformType::Pointer sTransform;
614 if(m_ArgsInfo.itkbspline_flag) {
615 if( transform->GetTransforms().size()>1)
616 itkExceptionMacro(<< "invalid --itkbspline option if there is more than 1 label")
617 sTransform = SingleBSplineTransformType::New();
618 sTransform->SetBulkTransform( transform->GetTransforms()[0]->GetBulkTransform() );
619 sTransform->SetGridSpacing( transform->GetTransforms()[0]->GetGridSpacing() );
620 sTransform->SetGridOrigin( transform->GetTransforms()[0]->GetGridOrigin() );
621 sTransform->SetGridRegion( transform->GetTransforms()[0]->GetGridRegion() );
622 sTransform->SetParameters( transform->GetTransforms()[0]->GetParameters() );
623 regTransform = sTransform;
624 transform = NULL; // free memory
627 //=======================================================
629 //=======================================================
630 typedef clitk::GenericInterpolator<args_info_clitkBLUTDIR, FixedImageType, TCoordRep > GenericInterpolatorType;
631 typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
632 genericInterpolator->SetArgsInfo(m_ArgsInfo);
633 typedef itk::InterpolateImageFunction< FixedImageType, TCoordRep > InterpolatorType;
634 typename InterpolatorType::Pointer interpolator=genericInterpolator->GetInterpolatorPointer();
637 //=======================================================
639 //=======================================================
640 typedef clitk::GenericMetric<args_info_clitkBLUTDIR, FixedImageType,MovingImageType > GenericMetricType;
641 typename GenericMetricType::Pointer genericMetric=GenericMetricType::New();
642 genericMetric->SetArgsInfo(m_ArgsInfo);
643 genericMetric->SetFixedImage(fixedImagePyramid->GetOutput(0));
644 if (fixedMask) genericMetric->SetFixedImageMask(fixedMask);
645 genericMetric->SetFixedImageRegion(fixedImageRegionPyramid->GetOutput(0));
646 typedef itk::ImageToImageMetric< FixedImageType, MovingImageType > MetricType;
647 typename MetricType::Pointer metric=genericMetric->GetMetricPointer();
648 if (movingMask) metric->SetMovingImageMask(movingMask);
650 metric->SetNumberOfThreads( threads );
651 if (m_Verbose) std::cout<< "Using " << threads << " threads." << std::endl;
654 //=======================================================
656 //=======================================================
657 typedef clitk::GenericOptimizer<args_info_clitkBLUTDIR> GenericOptimizerType;
658 GenericOptimizerType::Pointer genericOptimizer = GenericOptimizerType::New();
659 genericOptimizer->SetArgsInfo(m_ArgsInfo);
660 genericOptimizer->SetMaximize(genericMetric->GetMaximize());
661 genericOptimizer->SetNumberOfParameters(regTransform->GetNumberOfParameters());
662 typedef itk::SingleValuedNonLinearOptimizer OptimizerType;
663 OptimizerType::Pointer optimizer = genericOptimizer->GetOptimizerPointer();
666 //=======================================================
668 //=======================================================
669 typedef itk::MultiResolutionImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType;
670 typename RegistrationType::Pointer registration = RegistrationType::New();
671 registration->SetMetric( metric );
672 registration->SetOptimizer( optimizer );
673 registration->SetInterpolator( interpolator );
674 registration->SetTransform (regTransform );
676 registration->SetNumberOfThreads(threads);
677 if (m_Verbose) std::cout<< "Using " << threads << " threads." << std::endl;
679 registration->SetFixedImage( croppedFixedImage );
680 registration->SetMovingImage( movingImage );
681 registration->SetFixedImageRegion( metricRegion );
682 registration->SetFixedImagePyramid( fixedImagePyramid );
683 registration->SetMovingImagePyramid( movingImagePyramid );
684 registration->SetInitialTransformParameters( regTransform->GetParameters() );
685 registration->SetNumberOfLevels( m_ArgsInfo.levels_arg );
686 if (m_Verbose) std::cout<<"Setting the number of resolution levels to "<<m_ArgsInfo.levels_arg<<"..."<<std::endl;
689 //================================================================================================
691 //================================================================================================
694 // Output iteration info
695 CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
696 observer->SetOptimizer(genericOptimizer);
697 optimizer->AddObserver( itk::IterationEvent(), observer );
700 typedef RegistrationInterfaceCommand<RegistrationType,args_info_clitkBLUTDIR> CommandType;
701 typename CommandType::Pointer command = CommandType::New();
702 command->SetInitializer(initializer);
703 command->SetArgsInfo(m_ArgsInfo);
704 command->SetCommandIterationUpdate(observer);
705 command->SetMaximize(genericMetric->GetMaximize());
706 command->SetMetricRegion(metricRegion);
707 registration->AddObserver( itk::IterationEvent(), command );
709 if (m_ArgsInfo.coeff_given)
711 if(m_ArgsInfo.itkbspline_flag) {
712 itkExceptionMacro("--coeff and --itkbpline are incompatible");
715 std::cout << std::endl << "Output coefficient images every " << m_ArgsInfo.coeffEveryN_arg << " iterations." << std::endl;
716 typedef CommandIterationUpdateDVF<FixedImageType, OptimizerType, TransformType> DVFCommandType;
717 typename DVFCommandType::Pointer observerdvf = DVFCommandType::New();
718 observerdvf->SetFixedImage(fixedImage);
719 observerdvf->SetTransform(transform);
720 observerdvf->SetArgsInfo(m_ArgsInfo);
721 optimizer->AddObserver( itk::IterationEvent(), observerdvf );
726 //=======================================================
728 //=======================================================
729 if (m_Verbose) std::cout << std::endl << "Starting Registration" << std::endl;
733 registration->Update();
735 catch( itk::ExceptionObject & err )
737 std::cerr << "ExceptionObject caught while registering!" << std::endl;
738 std::cerr << err << std::endl;
743 //=======================================================
745 //=======================================================
746 OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters();
747 regTransform->SetParameters( finalParameters );
750 std::cout<<"Stop condition description: "
751 <<registration->GetOptimizer()->GetStopConditionDescription()<<std::endl;
755 //=======================================================
756 // Get the BSpline coefficient images and write them
757 //=======================================================
758 if (m_ArgsInfo.coeff_given)
760 typedef typename TransformType::CoefficientImageType CoefficientImageType;
761 std::vector<typename CoefficientImageType::Pointer> coefficientImages = transform->GetCoefficientImages();
762 typedef itk::ImageFileWriter<CoefficientImageType> CoeffWriterType;
763 typename CoeffWriterType::Pointer coeffWriter = CoeffWriterType::New();
764 unsigned nLabels = transform->GetnLabels();
766 std::string fname(m_ArgsInfo.coeff_arg);
767 int dotpos = fname.length() - 1;
768 while (dotpos >= 0 && fname[dotpos] != '.')
771 for (unsigned i = 0; i < nLabels; ++i)
773 std::ostringstream osfname;
774 osfname << fname.substr(0, dotpos) << '_' << i << fname.substr(dotpos);
775 coeffWriter->SetInput(coefficientImages[i]);
776 coeffWriter->SetFileName(osfname.str());
777 coeffWriter->Update();
783 //=======================================================
784 // Compute the DVF (only deformable transform)
785 //=======================================================
786 typedef itk::Vector< float, SpaceDimension > DisplacementType;
787 typedef itk::Image< DisplacementType, InputImageType::ImageDimension > DisplacementFieldType;
788 #if (ITK_VERSION_MAJOR == 4) && (ITK_VERSION_MINOR < 6)
789 typedef itk::TransformToDisplacementFieldSource<DisplacementFieldType, double> ConvertorType;
791 typedef itk::TransformToDisplacementFieldFilter<DisplacementFieldType, double> ConvertorType;
793 typename ConvertorType::Pointer filter= ConvertorType::New();
794 filter->SetNumberOfThreads(1);
795 if(m_ArgsInfo.itkbspline_flag)
796 sTransform->SetBulkTransform(NULL);
798 transform->SetBulkTransform(NULL);
799 filter->SetTransform(regTransform);
800 #if ITK_VERSION_MAJOR > 4 || (ITK_VERSION_MAJOR == 4 && ITK_VERSION_MINOR >= 6)
801 filter->SetReferenceImage(fixedImage);
803 filter->SetOutputParametersFromImage(fixedImage);
806 typename DisplacementFieldType::Pointer field = filter->GetOutput();
809 //=======================================================
811 //=======================================================
812 typedef itk::ImageFileWriter< DisplacementFieldType > FieldWriterType;
813 typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New();
814 fieldWriter->SetFileName( m_ArgsInfo.vf_arg );
815 fieldWriter->SetInput( field );
818 fieldWriter->Update();
820 catch( itk::ExceptionObject & excp )
822 std::cerr << "Exception thrown writing the DVF" << std::endl;
823 std::cerr << excp << std::endl;
828 //=======================================================
829 // Resample the moving image
830 //=======================================================
831 typedef itk::ResampleImageFilter< MovingImageType, FixedImageType > ResampleFilterType;
832 typename ResampleFilterType::Pointer resampler = ResampleFilterType::New();
833 if (rigidTransform) {
834 if(m_ArgsInfo.itkbspline_flag)
835 sTransform->SetBulkTransform(rigidTransform);
837 transform->SetBulkTransform(rigidTransform);
839 resampler->SetTransform( regTransform );
840 resampler->SetInput( movingImage);
841 resampler->SetOutputParametersFromImage(fixedImage);
843 typename FixedImageType::Pointer result=resampler->GetOutput();
845 // typedef itk::WarpImageFilter< MovingImageType, FixedImageType, DeformationFieldType > WarpFilterType;
846 // typename WarpFilterType::Pointer warp = WarpFilterType::New();
848 // warp->SetDeformationField( field );
849 // warp->SetInput( movingImageReader->GetOutput() );
850 // warp->SetOutputOrigin( fixedImage->GetOrigin() );
851 // warp->SetOutputSpacing( fixedImage->GetSpacing() );
852 // warp->SetOutputDirection( fixedImage->GetDirection() );
853 // warp->SetEdgePaddingValue( 0.0 );
857 //=======================================================
858 // Write the warped image
859 //=======================================================
860 typedef itk::ImageFileWriter< FixedImageType > WriterType;
861 typename WriterType::Pointer writer = WriterType::New();
862 writer->SetFileName( m_ArgsInfo.output_arg );
863 writer->SetInput( result );
869 catch( itk::ExceptionObject & err )
871 std::cerr << "ExceptionObject caught !" << std::endl;
872 std::cerr << err << std::endl;
877 //=======================================================
878 // Calculate the difference after the deformable transform
879 //=======================================================
880 typedef clitk::DifferenceImageFilter< FixedImageType, FixedImageType> DifferenceFilterType;
881 if (m_ArgsInfo.after_given)
883 typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New();
884 difference->SetValidInput( fixedImage );
885 difference->SetTestInput( result );
889 difference->Update();
891 catch( itk::ExceptionObject & err )
893 std::cerr << "ExceptionObject caught calculating the difference !" << std::endl;
894 std::cerr << err << std::endl;
898 typename WriterType::Pointer differenceWriter=WriterType::New();
899 differenceWriter->SetInput(difference->GetOutput());
900 differenceWriter->SetFileName(m_ArgsInfo.after_arg);
901 differenceWriter->Update();
906 //=======================================================
907 // Calculate the difference before the deformable transform
908 //=======================================================
909 if( m_ArgsInfo.before_given )
912 typename FixedImageType::Pointer moving=FixedImageType::New();
913 if (m_ArgsInfo.initMatrix_given)
915 typedef itk::ResampleImageFilter<MovingImageType, FixedImageType> ResamplerType;
916 typename ResamplerType::Pointer resampler=ResamplerType::New();
917 resampler->SetInput(movingImage);
918 resampler->SetOutputOrigin(fixedImage->GetOrigin());
919 resampler->SetSize(fixedImage->GetLargestPossibleRegion().GetSize());
920 resampler->SetOutputSpacing(fixedImage->GetSpacing());
921 resampler->SetDefaultPixelValue( 0. );
922 if (rigidTransform ) resampler->SetTransform(rigidTransform);
924 moving=resampler->GetOutput();
929 typename DifferenceFilterType::Pointer difference = DifferenceFilterType::New();
930 difference->SetValidInput( fixedImage );
931 difference->SetTestInput( moving );
935 difference->Update();
937 catch( itk::ExceptionObject & err )
939 std::cerr << "ExceptionObject caught calculating the difference !" << std::endl;
940 std::cerr << err << std::endl;
944 typename WriterType::Pointer differenceWriter=WriterType::New();
945 writer->SetFileName( m_ArgsInfo.before_arg );
946 writer->SetInput( difference->GetOutput() );
955 #endif // #define clitkBLUTDIRGenericFilter_txx