Slicer  5.1
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
vtkITKTransformConverter.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Visualization Toolkit
4  Module: $RCSfile: vtkITKTransformConverter.h,v $
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or https://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #ifndef __vtkITKTransformConverter_h
17 #define __vtkITKTransformConverter_h
18 
19 #include "vtkMRMLTransformNode.h"
20 
21 // VTK includes
22 #include <vtkImageData.h>
23 #include <vtkPoints.h>
24 #include <vtkThinPlateSplineTransform.h>
25 #include <vtkTransform.h>
26 
27 // ITK includes
28 #include <itkAffineTransform.h>
29 #include <itkBSplineDeformableTransform.h> // ITKv3 style
30 #include <itkBSplineTransform.h> // ITKv4 style
31 #include <itkCompositeTransform.h>
32 #include <itkCompositeTransformIOHelper.h>
33 #include <itkDisplacementFieldTransform.h>
34 #include <itkIdentityTransform.h>
35 #include <itkTransformFileWriter.h>
36 #include <itkTransformFileReader.h>
37 #include <itkImageFileReader.h>
38 #include <itkImageFileWriter.h>
39 #include <itkTranslationTransform.h>
40 #include <itkScaleTransform.h>
41 #include <itkTransformFactory.h>
42 #include <itkThinPlateSplineKernelTransform.h>
43 
44 // Constants and typedefs
45 
46 static const unsigned int VTKDimension = 3;
47 
48 static const int BSPLINE_TRANSFORM_ORDER = 3;
49 
50 typedef itk::TransformFileWriter TransformWriterType;
51 
52 typedef itk::DisplacementFieldTransform< double, 3 > DisplacementFieldTransformDoubleType;
53 typedef DisplacementFieldTransformDoubleType::DisplacementFieldType GridImageDoubleType;
54 
55 typedef itk::ThinPlateSplineKernelTransform<double,3> ThinPlateSplineTransformDoubleType;
56 
57 #include "vtkITKTransformInverse.h"
58 
60 {
61 public:
62 
63  static void RegisterInverseTransformTypes();
64 
65  template<typename T>
66  static vtkAbstractTransform* CreateVTKTransformFromITK(vtkObject* loggerObject, typename itk::TransformBaseTemplate<T>::Pointer transformItk);
67 
77  static itk::Object::Pointer CreateITKTransformFromVTK(vtkObject* loggerObject, vtkAbstractTransform* transformVtk,
78  itk::Object::Pointer& secondaryTransformItk, int preferITKv3CompatibleTransforms, bool initialize = true);
79 
80  template <typename T> static bool SetVTKBSplineFromITKv3Generic(vtkObject* loggerObject, vtkOrientedBSplineTransform* bsplineVtk, typename itk::TransformBaseTemplate<T>::Pointer warpTransformItk, typename itk::TransformBaseTemplate<T>::Pointer bulkTransformItk);
81 
82  template<typename T>
83  static bool SetVTKOrientedGridTransformFromITKImage(vtkObject* loggerObject, vtkOrientedGridTransform* grid_Ras, typename itk::DisplacementFieldTransform< T, 3 >::DisplacementFieldType::Pointer gridImage_Lps);
84  static bool SetITKImageFromVTKOrientedGridTransform(vtkObject* loggerObject, GridImageDoubleType::Pointer &gridImage_Lps, vtkOrientedGridTransform* grid_Ras);
85 
86 protected:
87 
88  template<typename T>
89  static bool SetVTKLinearTransformFromITK(vtkObject* loggerObject, vtkMatrix4x4* transformVtk_RAS, typename itk::TransformBaseTemplate<T>::Pointer transformItk_LPS);
90  static bool SetITKLinearTransformFromVTK(vtkObject* loggerObject, itk::Object::Pointer& transformItk_LPS, vtkMatrix4x4* transformVtk_RAS);
91 
92  template<typename T>
93  static bool SetVTKOrientedGridTransformFromITK(vtkObject* loggerObject, vtkOrientedGridTransform* transformVtk_RAS, typename itk::TransformBaseTemplate<T>::Pointer transformItk_LPS);
94  static bool SetITKOrientedGridTransformFromVTK(vtkObject* loggerObject, itk::Object::Pointer& transformItk_LPS, vtkOrientedGridTransform* transformVtk_RAS);
95 
96  static bool SetITKv3BSplineFromVTK(vtkObject* loggerObject, itk::Object::Pointer& warpTransformItk, itk::Object::Pointer& bulkTransformItk, vtkOrientedBSplineTransform* bsplineVtk, bool alwaysAddBulkTransform);
97  static bool SetITKv4BSplineFromVTK(vtkObject* loggerObject, itk::Object::Pointer& warpTransformItk, vtkOrientedBSplineTransform* bsplineVtk);
98 
99  template<typename T>
100  static bool SetVTKThinPlateSplineTransformFromITK(vtkObject* loggerObject, vtkThinPlateSplineTransform* transformVtk_RAS, typename itk::TransformBaseTemplate<T>::Pointer transformItk_LPS);
101  static bool SetITKThinPlateSplineTransformFromVTK(vtkObject* loggerObject, itk::Object::Pointer& transformItk_LPS,
102  vtkThinPlateSplineTransform* transformVtk_RAS, bool initialize = true);
103 
104  static bool IsIdentityMatrix(vtkMatrix4x4 *matrix);
105 
106  template <typename BSplineTransformType> static bool SetVTKBSplineParametersFromITKGeneric(vtkObject* loggerObject, vtkOrientedBSplineTransform* bsplineVtk, typename itk::TransformBaseTemplate<typename BSplineTransformType::ScalarType>::Pointer warpTransformItk);
107  template <typename T> static bool SetVTKBSplineFromITKv4Generic(vtkObject* loggerObject, vtkOrientedBSplineTransform* bsplineVtk, typename itk::TransformBaseTemplate<T>::Pointer warpTransformItk);
108 
109  template <typename BSplineTransformType> static bool SetITKBSplineParametersFromVTKGeneric(vtkObject* loggerObject, typename itk::Transform< typename BSplineTransformType::ScalarType,VTKDimension,VTKDimension>::Pointer& warpTransformItk, vtkOrientedBSplineTransform* bsplineVtk);
110  template <typename T> static bool SetITKv3BSplineFromVTKGeneric(vtkObject* loggerObject, typename itk::Transform<T,VTKDimension,VTKDimension>::Pointer& warpTransformItk, typename itk::Transform<T,VTKDimension,VTKDimension>::Pointer& bulkTransformItk, vtkOrientedBSplineTransform* bsplineVtk, bool alwaysAddBulkTransform);
111  template <typename T> static bool SetITKv4BSplineFromVTKGeneric(vtkObject* loggerObject, typename itk::Transform<T,VTKDimension,VTKDimension>::Pointer& warpTransformItk, vtkOrientedBSplineTransform* bsplineVtk);
112 
113 };
114 
115 //----------------------------------------------------------------------------
117 {
118  itk::TransformFactory<InverseDisplacementFieldTransformFloatType>::RegisterTransform();
119  itk::TransformFactory<InverseDisplacementFieldTransformDoubleType>::RegisterTransform();
120 
121  itk::TransformFactory<InverseBSplineTransformFloatITKv3Type>::RegisterTransform();
122  itk::TransformFactory<InverseBSplineTransformFloatITKv4Type>::RegisterTransform();
123  itk::TransformFactory<InverseBSplineTransformDoubleITKv3Type>::RegisterTransform();
124  itk::TransformFactory<InverseBSplineTransformDoubleITKv4Type>::RegisterTransform();
125 
126  itk::TransformFactory<InverseThinPlateSplineTransformFloatType>::RegisterTransform();
127  itk::TransformFactory<InverseThinPlateSplineTransformDoubleType>::RegisterTransform();
128 
129  typedef itk::ThinPlateSplineKernelTransform<float,3> ThinPlateSplineTransformFloatType;
130  typedef itk::ThinPlateSplineKernelTransform<double,3> ThinPlateSplineTransformDoubleType;
131 
132  // by default they are not registered
133  itk::TransformFactory<ThinPlateSplineTransformFloatType>::RegisterTransform();
134  itk::TransformFactory<ThinPlateSplineTransformDoubleType>::RegisterTransform();
135 }
136 
137 //----------------------------------------------------------------------------
138 template<typename T>
140  vtkObject* /*loggerObject*/,
141  vtkMatrix4x4* transformVtk_RAS,
142  typename itk::TransformBaseTemplate<T>::Pointer transformItk_LPS)
143 {
144  static const unsigned int D = VTKDimension;
145  typedef itk::MatrixOffsetTransformBase<T,D,D> LinearTransformType;
146  typedef itk::ScaleTransform<T, D> ScaleTransformType;
147  typedef itk::TranslationTransform<T, D> TranslateTransformType;
148 
149  vtkSmartPointer<vtkMatrix4x4> transformVtk_LPS = vtkSmartPointer<vtkMatrix4x4>::New();
150 
151  bool convertedToVtkMatrix=false;
152 
153  std::string itkTransformClassName = transformItk_LPS->GetNameOfClass();
154 
155  // Linear transform of doubles or floats, dimension 3
156 
157  // ITKIO transform libraries are build as shared and dynamic_cast
158  // can NOT be used with templated classes that are
159  // instantiated in a translation unit different than the one where they are
160  // defined. It will work only if the classes are explicitly instantiated
161  // and exported.
162  // To workaround the issue, instead of using dynamic_cast:
163  // (1) to ensure the objects are of the right type string comparison is done
164  // (2) static_cast is used instead of dynamic_cast.
165  // See InsightSoftwareConsortium/ITK@d1e9fe2
166  // and see https://stackoverflow.com/questions/8024010/why-do-template-class-functions-have-to-be-declared-in-the-same-translation-unit
167  //
168  // The disadvantage of this approach is that each supported class name has to be explicitly listed here and if the class hierarchy changes in ITK
169  // then the static cast may produce invalid results. Also, even if the transform class name is matching,
170  // we may cast the transform to a wrong type due to mismatch in dimensions (not 3) or data type (not double or float).
171 
172  if (itkTransformClassName.find( "AffineTransform" ) != std::string::npos ||
173  itkTransformClassName == "MatrixOffsetTransformBase" ||
174  itkTransformClassName == "Rigid3DTransform" ||
175  itkTransformClassName == "Euler3DTransform" ||
176  itkTransformClassName == "CenteredEuler3DTransform" ||
177  itkTransformClassName == "QuaternionRigidTransform" ||
178  itkTransformClassName == "VersorTransform" ||
179  itkTransformClassName == "VersorRigid3DTransform" ||
180  itkTransformClassName == "ScaleSkewVersor3DTransform" ||
181  itkTransformClassName == "ScaleVersor3DTransform" ||
182  itkTransformClassName == "Similarity3DTransform" ||
183  itkTransformClassName == "ScaleTransform" ||
184  itkTransformClassName == "ScaleLogarithmicTransform")
185  {
186  typename LinearTransformType::Pointer dlt
187  = static_cast<LinearTransformType*>( transformItk_LPS.GetPointer() );
188  convertedToVtkMatrix=true;
189  for (unsigned int i=0; i < D; i++)
190  {
191  for (unsigned int j=0; j < D; j++)
192  {
193  transformVtk_LPS->SetElement(i, j, dlt->GetMatrix()[i][j]);
194  }
195  transformVtk_LPS->SetElement(i, D, dlt->GetOffset()[i]);
196  }
197  }
198 
199  // Identity transform of doubles or floats, dimension 3
200  if (itkTransformClassName == "IdentityTransform")
201  {
202  // nothing to do, matrix is already the identity
203  convertedToVtkMatrix=true;
204  }
205 
206  // Scale transform of doubles or floats, dimension 3
207  if (itkTransformClassName == "ScaleTransform")
208  {
209  typename ScaleTransformType::Pointer dst
210  = static_cast<ScaleTransformType*>( transformItk_LPS.GetPointer() );
211  convertedToVtkMatrix=true;
212  for (unsigned int i=0; i < D; i++)
213  {
214  transformVtk_LPS->SetElement(i, i, dst->GetScale()[i]);
215  }
216  }
217 
218  // Translate transform of doubles or floats, dimension 3
219  if (itkTransformClassName == "TranslationTransform")
220  {
221  typename TranslateTransformType::Pointer dtt
222  = static_cast<TranslateTransformType*>( transformItk_LPS.GetPointer());
223  convertedToVtkMatrix=true;
224  for (unsigned int i=0; i < D; i++)
225  {
226  transformVtk_LPS->SetElement(i, D, dtt->GetOffset()[i]);
227  }
228  }
229 
230  // Convert from LPS (ITK) to RAS (Slicer)
231  //
232  // Tras = lps2ras * Tlps * ras2lps
233  //
234 
235  vtkSmartPointer<vtkMatrix4x4> lps2ras = vtkSmartPointer<vtkMatrix4x4>::New();
236  lps2ras->SetElement(0,0,-1);
237  lps2ras->SetElement(1,1,-1);
238  vtkMatrix4x4* ras2lps = lps2ras; // lps2ras is diagonal therefore the inverse is identical
239 
240  vtkMatrix4x4::Multiply4x4(lps2ras, transformVtk_LPS, transformVtk_LPS);
241  vtkMatrix4x4::Multiply4x4(transformVtk_LPS, ras2lps, transformVtk_RAS);
242 
243  return convertedToVtkMatrix;
244 }
245 
246 //----------------------------------------------------------------------------
247 bool vtkITKTransformConverter::SetITKLinearTransformFromVTK(vtkObject* loggerObject, itk::Object::Pointer& transformItk_LPS, vtkMatrix4x4* transformVtk_RAS)
248 {
249  typedef itk::AffineTransform<double, VTKDimension> AffineTransformType;
250 
251  if (transformVtk_RAS==nullptr)
252  {
253  vtkErrorWithObjectMacro(loggerObject,"vtkITKTransformConverter::SetITKLinearTransformFromVTK failed: invalid input transform");
254  return false;
255  }
256 
257  vtkSmartPointer<vtkMatrix4x4> lps2ras = vtkSmartPointer<vtkMatrix4x4>::New();
258  lps2ras->SetElement(0,0,-1);
259  lps2ras->SetElement(1,1,-1);
260  vtkMatrix4x4* ras2lps = lps2ras; // lps2ras is diagonal therefore the inverse is identical
261 
262  // Convert from RAS (Slicer) to LPS (ITK)
263  //
264  // Tlps = ras2lps * Tras * lps2ras
265  //
266  vtkSmartPointer<vtkMatrix4x4> vtkmat = vtkSmartPointer<vtkMatrix4x4>::New();
267 
268  vtkMatrix4x4::Multiply4x4(ras2lps, transformVtk_RAS, vtkmat);
269  vtkMatrix4x4::Multiply4x4(vtkmat, lps2ras, vtkmat);
270 
271  typedef AffineTransformType::MatrixType MatrixType;
272  typedef AffineTransformType::OutputVectorType OffsetType;
273 
274  MatrixType itkmat;
275  OffsetType itkoffset;
276 
277  for (unsigned int i=0; i < VTKDimension; i++)
278  {
279  for (unsigned int j=0; j < VTKDimension; j++)
280  {
281  itkmat[i][j] = vtkmat->GetElement(i, j);
282  }
283  itkoffset[i] = vtkmat->GetElement(i, VTKDimension);
284  }
285 
286  AffineTransformType::Pointer affine = AffineTransformType::New();
287  affine->SetMatrix(itkmat);
288  affine->SetOffset(itkoffset);
289 
290  transformItk_LPS = affine;
291  return true;
292 }
293 
294 //----------------------------------------------------------------------------
296 {
297  static double identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
298  int i,j;
299 
300  for (i = 0; i < 4; i++)
301  {
302  for (j = 0; j < 4; j++)
303  {
304  if (matrix->GetElement(i,j) != identity[4*i+j])
305  {
306  return false;
307  }
308  }
309  }
310  return true;
311 }
312 
313 //----------------------------------------------------------------------------
314 template <typename BSplineTransformType>
316  vtkObject* loggerObject,
317  vtkOrientedBSplineTransform* bsplineVtk,
318  typename itk::TransformBaseTemplate<typename BSplineTransformType::ScalarType>::Pointer warpTransformItk)
319 {
320  //
321  // this version uses the itk::BSplineTransform not the itk::BSplineDeformableTransform
322  //
323  typedef typename BSplineTransformType::ScalarType T;
324  if (bsplineVtk==nullptr)
325  {
326  vtkErrorWithObjectMacro(loggerObject, "vtkMRMLTransformStorageNode::SetVTKBSplineFromITKv4 failed: bsplineVtk is invalid");
327  return false;
328  }
329  bool isDoublePrecisionInput=true;
330  if (sizeof(T)==sizeof(float))
331  {
332  isDoublePrecisionInput=false;
333  }
334  else if (sizeof(T)==sizeof(double))
335  {
336  isDoublePrecisionInput=true;
337  }
338  else
339  {
340  vtkErrorWithObjectMacro(loggerObject,"Unsupported scalar type in BSpline transform file (only float and double are supported)");
341  return false;
342  }
343 
344  typename BSplineTransformType::Pointer bsplineItk = BSplineTransformType::New();
345  std::string warpTransformItkName = warpTransformItk->GetNameOfClass();
346  std::string requestedWarpTransformItkName = bsplineItk->GetNameOfClass();
347  if (warpTransformItkName != requestedWarpTransformItkName)
348  {
349  return false;
350  }
351  if (warpTransformItk->GetOutputSpaceDimension() != VTKDimension)
352  {
353  vtkErrorWithObjectMacro(loggerObject, "Unsupported number of dimensions in BSpline transform file (expected = "
354  << VTKDimension << ", actual = " << warpTransformItk->GetOutputSpaceDimension() << ")");
355  return false;
356  }
357  bsplineItk = static_cast< BSplineTransformType* >( warpTransformItk.GetPointer() );
358 
359  // now get the fixed parameters and map them to the vtk analogs
360 
361  // it turns out that for a BSplineTransform, the TransformDomain information
362  // is not populated when reading from a file, so instead we access these
363  // fields from one of the coefficient images (they are assumed to be
364  // identical)
365  const typename BSplineTransformType::CoefficientImageArray coefficientImages =
366  bsplineItk->GetCoefficientImages();
367 
368  // * mesh size X, Y, Z (including the BSPLINE_TRANSFORM_ORDER=3 boundary nodes,
369  // 1 before and 2 after the grid)
370  typename BSplineTransformType::MeshSizeType meshSize =
371  coefficientImages[0]->GetLargestPossibleRegion().GetSize();
372 
373  // * mesh origin X, Y, Z (position of the boundary node before the grid)
374  typename BSplineTransformType::OriginType origin =
375  coefficientImages[0]->GetOrigin();
376 
377  // * mesh spacing X, Y, Z
378  typename BSplineTransformType::SpacingType spacing =
379  coefficientImages[0]->GetSpacing();
380 
381  // * mesh direction 3x3 matrix (first row, second row, third row)
382  typename BSplineTransformType::DirectionType direction =
383  coefficientImages[0]->GetDirection();
384 
385  vtkNew<vtkMatrix4x4> gridDirectionMatrix_LPS;
386  for (unsigned int row=0; row<VTKDimension; row++)
387  {
388  for (unsigned int column=0; column<VTKDimension; column++)
389  {
390  gridDirectionMatrix_LPS->SetElement(row,column,direction[row][column]);
391  }
392  }
393 
394  // Set bspline grid and coefficients
395  bsplineVtk->SetBorderModeToZero();
396 
397  vtkNew<vtkImageData> bsplineCoefficients;
398 
399  bsplineCoefficients->SetExtent(0, meshSize[0]-1, 0, meshSize[1]-1, 0, meshSize[2]-1);
400  bsplineCoefficients->SetSpacing(spacing[0], spacing[1], spacing[2]);
401 
402  // convert the direction matrix from LPS (itk) to RAS (slicer)
403  vtkNew<vtkMatrix4x4> lpsToRas;
404  lpsToRas->SetElement(0,0,-1);
405  lpsToRas->SetElement(1,1,-1);
406 
407  vtkNew<vtkMatrix4x4> rasToLps;
408  rasToLps->SetElement(0,0,-1);
409  rasToLps->SetElement(1,1,-1);
410 
411  vtkNew<vtkMatrix4x4> gridDirectionMatrix_RAS;
412  vtkMatrix4x4::Multiply4x4(
413  lpsToRas.GetPointer(),
414  gridDirectionMatrix_LPS.GetPointer(),
415  gridDirectionMatrix_RAS.GetPointer());
416  bsplineVtk->SetGridDirectionMatrix(gridDirectionMatrix_RAS.GetPointer());
417 
418  // convert the origin from LPS (itk) to RAS (slicer)
419  double gridOrigin_RAS[3]={-origin[0], -origin[1], origin[2]};
420  bsplineCoefficients->SetOrigin(gridOrigin_RAS);
421 
422  int bsplineCoefficientsScalarType=VTK_FLOAT;
423  if (isDoublePrecisionInput)
424  {
425  bsplineCoefficientsScalarType=VTK_DOUBLE;
426  }
427 
428  bsplineCoefficients->AllocateScalars(bsplineCoefficientsScalarType, 3);
429 
430  const unsigned int expectedNumberOfVectors = meshSize[0]*meshSize[1]*meshSize[2];
431  const unsigned int expectedNumberOfParameters = expectedNumberOfVectors*VTKDimension;
432  const unsigned int actualNumberOfParameters = bsplineItk->GetNumberOfParameters();
433 
434  if( actualNumberOfParameters != expectedNumberOfParameters )
435  {
436  vtkErrorWithObjectMacro(loggerObject,"Mismatch in number of BSpline parameters in the transform file and the MRML node");
437  return false;
438  }
439  const T* itkBSplineParams_LPS = static_cast<const T*>(bsplineItk->GetParameters().data_block());
440  T* vtkBSplineParams_RAS=static_cast<T*>(bsplineCoefficients->GetScalarPointer());
441  for (unsigned int i=0; i<expectedNumberOfVectors; i++)
442  {
443  *(vtkBSplineParams_RAS++) = - (*(itkBSplineParams_LPS ));
444  *(vtkBSplineParams_RAS++) = - (*(itkBSplineParams_LPS+expectedNumberOfVectors ));
445  *(vtkBSplineParams_RAS++) = (*(itkBSplineParams_LPS+expectedNumberOfVectors*2));
446  itkBSplineParams_LPS++;
447  }
448  bsplineVtk->SetCoefficientData(bsplineCoefficients.GetPointer());
449 
450  // Success
451  return true;
452 }
453 
454 //----------------------------------------------------------------------------
455 template <typename T> bool vtkITKTransformConverter::SetVTKBSplineFromITKv3Generic(vtkObject* loggerObject,
456  vtkOrientedBSplineTransform* bsplineVtk,
457  typename itk::TransformBaseTemplate<T>::Pointer warpTransformItk, typename itk::TransformBaseTemplate<T>::Pointer bulkTransformItk)
458 {
459  if (bsplineVtk==nullptr)
460  {
461  vtkErrorWithObjectMacro(loggerObject, "vtkMRMLTransformStorageNode::SetVTKBSplineFromITK failed: bsplineVtk is invalid");
462  return false;
463  }
464 
465  bool inverse = false;
466  // inverse class is derived from forward class, so it has to be checked first
468  {
469  inverse = true;
470  }
471  else if (SetVTKBSplineParametersFromITKGeneric< itk::BSplineDeformableTransform< T, VTKDimension, VTKDimension > >(loggerObject, bsplineVtk, warpTransformItk))
472  {
473  inverse = false;
474  }
475  else
476  {
477  vtkDebugWithObjectMacro(loggerObject, "Not an ITKv3 BSpline transform");
478  return false;
479  }
480 
481  // Set the bulk transform
482  if( bulkTransformItk )
483  {
484  std::string bulkTransformItkTransformName = bulkTransformItk->GetNameOfClass();
485 
486  typedef itk::AffineTransform<T,3> BulkTransformType;
487 
488  if (bulkTransformItkTransformName == "AffineTransform")
489  {
490  BulkTransformType* bulkItkAffine = static_cast<BulkTransformType*> (bulkTransformItk.GetPointer());
491  vtkNew<vtkMatrix4x4> bulkMatrix_LPS;
492  for (unsigned int i=0; i < VTKDimension; i++)
493  {
494  for (unsigned int j=0; j < VTKDimension; j++)
495  {
496  bulkMatrix_LPS->SetElement(i,j, bulkItkAffine->GetMatrix()[i][j]);
497  }
498  bulkMatrix_LPS->SetElement(i,VTKDimension, bulkItkAffine->GetOffset()[i]);
499  }
500  vtkNew<vtkMatrix4x4> lpsToRas;
501  lpsToRas->SetElement(0,0,-1);
502  lpsToRas->SetElement(1,1,-1);
503  vtkNew<vtkMatrix4x4> rasToLps;
504  rasToLps->SetElement(0,0,-1);
505  rasToLps->SetElement(1,1,-1);
506  vtkNew<vtkMatrix4x4> bulkMatrix_RAS; // bulk_RAS = lpsToRas * bulk_LPS * rasToLps
507  vtkMatrix4x4::Multiply4x4(lpsToRas.GetPointer(), bulkMatrix_LPS.GetPointer(), bulkMatrix_RAS.GetPointer());
508  vtkMatrix4x4::Multiply4x4(bulkMatrix_RAS.GetPointer(), rasToLps.GetPointer(), bulkMatrix_RAS.GetPointer());
509  bsplineVtk->SetBulkTransformMatrix(bulkMatrix_RAS.GetPointer());
510  }
511  else if (bulkTransformItkTransformName == "IdentityTransform")
512  {
513  // bulk transform is identity, which is equivalent to no bulk transform
514  }
515  else
516  {
517  vtkErrorWithObjectMacro(loggerObject,"Cannot read the 2nd transform in BSplineTransform (expected AffineTransform_double_3_3 or IdentityTransform)" );
518  return false;
519  }
520  }
521 
522  if (inverse)
523  {
524  bsplineVtk->Inverse();
525  }
526 
527  // Success
528  return true;
529 }
530 
531 //----------------------------------------------------------------------------
532 template <typename T> bool vtkITKTransformConverter::SetVTKBSplineFromITKv4Generic(vtkObject* loggerObject,
533  vtkOrientedBSplineTransform* bsplineVtk, typename itk::TransformBaseTemplate<T>::Pointer warpTransformItk)
534 {
535  bool inverse = false;
536  // inverse class is derived from forward class, so it has to be checked first
538  {
539  inverse = true;
540  }
541  else if (SetVTKBSplineParametersFromITKGeneric< itk::BSplineTransform< T, VTKDimension, VTKDimension > >(loggerObject, bsplineVtk, warpTransformItk))
542  {
543  inverse = false;
544  }
545  else
546  {
547  vtkDebugWithObjectMacro(loggerObject, "Not an ITKv4 BSpline transform");
548  return false;
549  }
550  if (inverse)
551  {
552  bsplineVtk->Inverse();
553  }
554  return true;
555 }
556 
557 //----------------------------------------------------------------------------
558 template <typename BSplineTransformType> bool vtkITKTransformConverter::SetITKBSplineParametersFromVTKGeneric(vtkObject* loggerObject,
559  typename itk::Transform< typename BSplineTransformType::ScalarType,VTKDimension,VTKDimension>::Pointer& warpTransformItk, vtkOrientedBSplineTransform* bsplineVtk)
560 {
561  typedef typename BSplineTransformType::ScalarType T;
562  if (bsplineVtk==nullptr)
563  {
564  vtkErrorWithObjectMacro(loggerObject, "vtkMRMLTransformStorageNode::SetITKBSplineFromVTK failed: bsplineVtk is invalid");
565  return false;
566  }
567  vtkImageData* bsplineCoefficients_RAS=bsplineVtk->GetCoefficientData();
568  if (bsplineCoefficients_RAS==nullptr)
569  {
570  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file: coefficients are not specified");
571  return false;
572  }
573 
574  typename BSplineTransformType::Pointer bsplineItk = BSplineTransformType::New();
575  warpTransformItk = bsplineItk;
576 
577  // Fixed parameters:
578  // * mesh size X, Y, Z (including the BSPLINE_TRANSFORM_ORDER=3 boundary nodes, 1 before and 2 after the grid)
579  // * mesh origin X, Y, Z (position of the boundary node before the grid)
580  // * mesh spacing X, Y, Z
581  // * mesh direction 3x3 matrix (first row, second row, third row)
582  typename BSplineTransformType::FixedParametersType transformFixedParamsItk;
583  const unsigned int numberOfFixedParameters=VTKDimension*(VTKDimension+3);
584  transformFixedParamsItk.SetSize(numberOfFixedParameters);
585 
586  int *gridExtent=bsplineCoefficients_RAS->GetExtent();
587  int gridSize[3]={gridExtent[1]-gridExtent[0]+1, gridExtent[3]-gridExtent[2]+1, gridExtent[5]-gridExtent[4]+1};
588  transformFixedParamsItk[0]=gridSize[0];
589  transformFixedParamsItk[1]=gridSize[1];
590  transformFixedParamsItk[2]=gridSize[2];
591 
592  double* gridOrigin_RAS=bsplineCoefficients_RAS->GetOrigin();
593  double gridOrigin_LPS[3]={-gridOrigin_RAS[0], -gridOrigin_RAS[1], gridOrigin_RAS[2]};
594  transformFixedParamsItk[3]=gridOrigin_LPS[0];
595  transformFixedParamsItk[4]=gridOrigin_LPS[1];
596  transformFixedParamsItk[5]=gridOrigin_LPS[2];
597 
598  double* gridSpacing=bsplineCoefficients_RAS->GetSpacing();
599  transformFixedParamsItk[6]=gridSpacing[0];
600  transformFixedParamsItk[7]=gridSpacing[1];
601  transformFixedParamsItk[8]=gridSpacing[2];
602 
603  vtkNew<vtkMatrix4x4> gridDirectionMatrix_RAS;
604  if (bsplineVtk->GetGridDirectionMatrix()!=nullptr)
605  {
606  gridDirectionMatrix_RAS->DeepCopy(bsplineVtk->GetGridDirectionMatrix());
607  }
608  vtkNew<vtkMatrix4x4> lpsToRas;
609  lpsToRas->SetElement(0,0,-1);
610  lpsToRas->SetElement(1,1,-1);
611  vtkNew<vtkMatrix4x4> rasToLps;
612  rasToLps->SetElement(0,0,-1);
613  rasToLps->SetElement(1,1,-1);
614  vtkNew<vtkMatrix4x4> gridDirectionMatrix_LPS;
615  vtkMatrix4x4::Multiply4x4(rasToLps.GetPointer(), gridDirectionMatrix_RAS.GetPointer(), gridDirectionMatrix_LPS.GetPointer());
616  int fpIndex=9;
617  for (unsigned int row=0; row<VTKDimension; row++)
618  {
619  for (unsigned int column=0; column<VTKDimension; column++)
620  {
621  transformFixedParamsItk[fpIndex++]=gridDirectionMatrix_LPS->GetElement(row,column);
622  }
623  }
624 
625  bsplineItk->SetFixedParameters(transformFixedParamsItk);
626 
627  // BSpline coefficients
628 
629  const unsigned int expectedNumberOfVectors = gridSize[0]*gridSize[1]*gridSize[2];
630  const unsigned int expectedNumberOfParameters = expectedNumberOfVectors*VTKDimension;
631  if( bsplineItk->GetNumberOfParameters() != expectedNumberOfParameters )
632  {
633  vtkErrorWithObjectMacro(loggerObject,"Mismatch in number of BSpline parameters in the ITK transform and the VTK transform");
634  return false;
635  }
636 
637  typename BSplineTransformType::ParametersType transformParamsItk(expectedNumberOfParameters);
638  T* itkBSplineParams_LPS = static_cast<T*>(transformParamsItk.data_block());
639  T* vtkBSplineParams_RAS=static_cast<T*>(bsplineCoefficients_RAS->GetScalarPointer());
640  double coefficientScale = bsplineVtk->GetDisplacementScale();
641  for (unsigned int i=0; i<expectedNumberOfVectors; i++)
642  {
643  *(itkBSplineParams_LPS ) = -coefficientScale * (*(vtkBSplineParams_RAS++));
644  *(itkBSplineParams_LPS+expectedNumberOfVectors ) = -coefficientScale * (*(vtkBSplineParams_RAS++));
645  *(itkBSplineParams_LPS+expectedNumberOfVectors*2) = coefficientScale * (*(vtkBSplineParams_RAS++));
646  itkBSplineParams_LPS++;
647  }
648 
649  bsplineItk->SetParameters(transformParamsItk);
650  return true;
651 }
652 
653 //----------------------------------------------------------------------------
654 template <typename T> bool vtkITKTransformConverter::SetITKv3BSplineFromVTKGeneric(vtkObject* loggerObject,
655  typename itk::Transform<T,VTKDimension,VTKDimension>::Pointer& warpTransformItk,
656  typename itk::Transform<T,VTKDimension,VTKDimension>::Pointer& bulkTransformItk,
657  vtkOrientedBSplineTransform* bsplineVtk, bool alwaysAddBulkTransform)
658 {
659  if (bsplineVtk==nullptr)
660  {
661  vtkErrorWithObjectMacro(loggerObject, "vtkMRMLTransformStorageNode::SetITKBSplineFromVTK failed: bsplineVtk is invalid");
662  return false;
663  }
664  // Update is needed because it refreshes the inverse flag (the flag may be out-of-date if the transform depends on its inverse)
665  bsplineVtk->Update();
666  bool itkTransformSetSuccessfully = false;
667  if (bsplineVtk->GetInverseFlag())
668  {
669  itkTransformSetSuccessfully = SetITKBSplineParametersFromVTKGeneric< itk::InverseBSplineDeformableTransform< T, VTKDimension, VTKDimension > >(loggerObject, warpTransformItk, bsplineVtk);
670  }
671  else
672  {
673  itkTransformSetSuccessfully = SetITKBSplineParametersFromVTKGeneric< itk::BSplineDeformableTransform< T, VTKDimension, VTKDimension > >(loggerObject, warpTransformItk, bsplineVtk);
674  }
675  if (!itkTransformSetSuccessfully)
676  {
677  vtkErrorWithObjectMacro(loggerObject, "vtkMRMLTransformStorageNode::SetITKBSplineFromVTK failed: cannot determine BSpline parameters");
678  return false;
679  }
680 
681  vtkMatrix4x4* bulkMatrix_RAS=bsplineVtk->GetBulkTransformMatrix();
682  if (bulkMatrix_RAS || alwaysAddBulkTransform)
683  {
684  vtkNew<vtkMatrix4x4> lpsToRas;
685  lpsToRas->SetElement(0,0,-1);
686  lpsToRas->SetElement(1,1,-1);
687  vtkNew<vtkMatrix4x4> rasToLps;
688  rasToLps->SetElement(0,0,-1);
689  rasToLps->SetElement(1,1,-1);
690  vtkNew<vtkMatrix4x4> bulkMatrix_LPS; // bulk_LPS = rasToLps * bulk_RAS * lpsToRas
691  // If bulk transform is available then use it, otherwise just write an identity matrix (we just write it because
692  // alwaysAddBulkTransform was requested, due to backward compatibility reasons)
693  if (bulkMatrix_RAS!=nullptr)
694  {
695  vtkMatrix4x4::Multiply4x4(rasToLps.GetPointer(), bulkMatrix_RAS, bulkMatrix_LPS.GetPointer());
696  vtkMatrix4x4::Multiply4x4(bulkMatrix_LPS.GetPointer(), lpsToRas.GetPointer(), bulkMatrix_LPS.GetPointer());
697  }
698  typedef itk::AffineTransform<T,VTKDimension> BulkTransformType;
699  typename BulkTransformType::Pointer affineItk = BulkTransformType::New();
700  bulkTransformItk = affineItk;
701 
702  typename BulkTransformType::MatrixType affineMatrix;
703  typename BulkTransformType::OffsetType affineOffset;
704  for (unsigned int i=0; i < VTKDimension; i++)
705  {
706  for (unsigned int j=0; j < VTKDimension; j++)
707  {
708  affineMatrix[i][j]=bulkMatrix_LPS->GetElement(i,j);
709  }
710  affineOffset[i]=bulkMatrix_LPS->GetElement(i,VTKDimension);
711  }
712 
713  affineItk->SetMatrix(affineMatrix);
714  affineItk->SetOffset(affineOffset);
715  }
716  else
717  {
718  bulkTransformItk=nullptr;
719  }
720 
721  return true;
722 }
723 
724 //----------------------------------------------------------------------------
725 template <typename T> bool vtkITKTransformConverter::SetITKv4BSplineFromVTKGeneric(vtkObject* loggerObject,
726  typename itk::Transform<T,VTKDimension,VTKDimension>::Pointer& warpTransformItk,
727  vtkOrientedBSplineTransform* bsplineVtk)
728 {
729  // Update is needed because it refreshes the inverse flag (the flag may be out-of-date if the transform depends on its inverse)
730  bsplineVtk->Update();
731  bool itkTransformSetSuccessfully = false;
732  if (bsplineVtk->GetInverseFlag())
733  {
734  itkTransformSetSuccessfully = SetITKBSplineParametersFromVTKGeneric< itk::InverseBSplineTransform< T, VTKDimension, VTKDimension > >(loggerObject, warpTransformItk, bsplineVtk);
735  }
736  else
737  {
738  itkTransformSetSuccessfully = SetITKBSplineParametersFromVTKGeneric< itk::BSplineTransform< T, VTKDimension, VTKDimension > >(loggerObject, warpTransformItk, bsplineVtk);
739  }
740  if (!itkTransformSetSuccessfully)
741  {
742  vtkErrorWithObjectMacro(loggerObject, "vtkMRMLTransformStorageNode::SetITKv4BSplineFromVTKGeneric failed: cannot determine BSpline parameters");
743  return false;
744  }
745  return true;
746 }
747 
748 //----------------------------------------------------------------------------
749 bool vtkITKTransformConverter::SetITKv3BSplineFromVTK(vtkObject* loggerObject, itk::Object::Pointer& warpTransformItk,
750  itk::Object::Pointer& bulkTransformItk, vtkOrientedBSplineTransform* bsplineVtk, bool alwaysAddBulkTransform)
751 {
752  if (bsplineVtk==nullptr)
753  {
754  vtkErrorWithObjectMacro(loggerObject, "Cannot retrieve BSpline transform from node");
755  return false;
756  }
757 
758  vtkImageData* bsplineCoefficients=bsplineVtk->GetCoefficientData();
759 
760  if (bsplineCoefficients==nullptr)
761  {
762  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file: coefficients are not specified");
763  return false;
764  }
765 
766  if (bsplineCoefficients->GetScalarType()==VTK_FLOAT)
767  {
768  typedef itk::Transform<float, VTKDimension, VTKDimension > ITKTransformType;
769  ITKTransformType::Pointer floatWarpTransformItk;
770  ITKTransformType::Pointer floatBulkTransformItk;
771  if (!SetITKv3BSplineFromVTKGeneric<float>(loggerObject, floatWarpTransformItk, floatBulkTransformItk, bsplineVtk, alwaysAddBulkTransform))
772  {
773  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file");
774  return false;
775  }
776  warpTransformItk = floatWarpTransformItk.GetPointer();
777  bulkTransformItk = floatBulkTransformItk.GetPointer();
778  }
779  else if (bsplineCoefficients->GetScalarType()==VTK_DOUBLE)
780  {
781  typedef itk::Transform<double, VTKDimension, VTKDimension > ITKTransformType;
782  ITKTransformType::Pointer doubleWarpTransformItk;
783  ITKTransformType::Pointer doubleBulkTransformItk;
784  if (!SetITKv3BSplineFromVTKGeneric<double>(loggerObject, doubleWarpTransformItk, doubleBulkTransformItk, bsplineVtk, alwaysAddBulkTransform))
785  {
786  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file");
787  return false;
788  }
789  warpTransformItk = doubleWarpTransformItk;
790  bulkTransformItk = doubleBulkTransformItk;
791  }
792  else
793  {
794  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file: only float and double coefficient types are supported");
795  return false;
796  }
797 
798  return true;
799 }
800 
801 //----------------------------------------------------------------------------
802 bool vtkITKTransformConverter::SetITKv4BSplineFromVTK(vtkObject* loggerObject, itk::Object::Pointer& warpTransformItk, vtkOrientedBSplineTransform* bsplineVtk)
803 {
804  if (bsplineVtk==nullptr)
805  {
806  vtkErrorWithObjectMacro(loggerObject, "Cannot retrieve BSpline transform from node");
807  return false;
808  }
809 
810  vtkImageData* bsplineCoefficients=bsplineVtk->GetCoefficientData();
811 
812  if (bsplineCoefficients==nullptr)
813  {
814  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file: coefficients are not specified");
815  return false;
816  }
817 
818  if (bsplineCoefficients->GetScalarType()==VTK_FLOAT)
819  {
820  typedef itk::Transform<float, VTKDimension, VTKDimension > ITKTransformType;
821  ITKTransformType::Pointer floatWarpTransformItk;
822  if (!SetITKv4BSplineFromVTKGeneric<float>(loggerObject, floatWarpTransformItk, bsplineVtk))
823  {
824  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file");
825  return false;
826  }
827  warpTransformItk = floatWarpTransformItk.GetPointer();
828  }
829  else if (bsplineCoefficients->GetScalarType()==VTK_DOUBLE)
830  {
831  typedef itk::Transform<double, VTKDimension, VTKDimension > ITKTransformType;
832  ITKTransformType::Pointer doubleWarpTransformItk;
833  if (!SetITKv4BSplineFromVTKGeneric<double>(loggerObject, doubleWarpTransformItk, bsplineVtk))
834  {
835  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file");
836  return false;
837  }
838  warpTransformItk = doubleWarpTransformItk;
839  }
840  else
841  {
842  vtkErrorWithObjectMacro(loggerObject, "Cannot write BSpline transform to file: only float and double coefficient types are supported");
843  return false;
844  }
845 
846  return true;
847 }
848 
849 //----------------------------------------------------------------------------
850 template<typename T>
851 bool vtkITKTransformConverter::SetVTKOrientedGridTransformFromITK(vtkObject* loggerObject, vtkOrientedGridTransform* transformVtk_RAS, typename itk::TransformBaseTemplate<T>::Pointer transformItk_LPS)
852 {
853  typedef itk::DisplacementFieldTransform< T, 3 > DisplacementFieldTransformType;
854  typedef itk::InverseDisplacementFieldTransform< T, 3 > InverseDisplacementFieldTransformType;
855 
856  if (!transformItk_LPS)
857  {
858  vtkErrorWithObjectMacro(loggerObject, "Cannot set VTK oriented grid transform from ITK: the input transform is nullptr");
859  return false;
860  }
861  if (transformItk_LPS->GetOutputSpaceDimension() != VTKDimension)
862  {
863  vtkErrorWithObjectMacro(loggerObject, "Unsupported number of dimensions in oriented grid transform file (expected = "
864  << VTKDimension << ", actual = " << transformItk_LPS->GetOutputSpaceDimension() << ")");
865  return false;
866  }
867 
868  std::string transformItkClassName = transformItk_LPS->GetNameOfClass();
869 
870  bool inverse = false;
871  typename DisplacementFieldTransformType::DisplacementFieldType* gridImageItk_Lps = nullptr;
872  if (transformItkClassName == "InverseDisplacementFieldTransform") // inverse class is derived from forward class, so it has to be checked first
873  {
874  DisplacementFieldTransformType* inverseDisplacementFieldTransform = static_cast<InverseDisplacementFieldTransformType*>( transformItk_LPS.GetPointer() );
875  inverse = true;
876  gridImageItk_Lps = inverseDisplacementFieldTransform->GetDisplacementField();
877  }
878  else if (transformItkClassName == "DisplacementFieldTransform")
879  {
880  DisplacementFieldTransformType* displacementFieldTransform = static_cast<DisplacementFieldTransformType*>( transformItk_LPS.GetPointer() );
881  inverse = false;
882  gridImageItk_Lps = displacementFieldTransform->GetDisplacementField();
883  }
884  else
885  {
886  vtkDebugWithObjectMacro(loggerObject, "Not a grid transform");
887  return false;
888  }
889  if (!SetVTKOrientedGridTransformFromITKImage<T>(loggerObject, transformVtk_RAS, gridImageItk_Lps))
890  {
891  return false;
892  }
893  if (inverse)
894  {
895  transformVtk_RAS->Inverse();
896  }
897  return true;
898 }
899 
900 //----------------------------------------------------------------------------
901 bool vtkITKTransformConverter::SetITKOrientedGridTransformFromVTK(vtkObject* loggerObject, itk::Object::Pointer& transformItk_LPS, vtkOrientedGridTransform* transformVtk_RAS)
902 {
903  GridImageDoubleType::Pointer gridImageItk_Lps;
904  if (!SetITKImageFromVTKOrientedGridTransform(loggerObject, gridImageItk_Lps, transformVtk_RAS))
905  {
906  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::SetITKOrientedGridTransformFromVTK failed: input transform is invalid");
907  return false;
908  }
909  // Update is needed because it refreshes the inverse flag (the flag may be out-of-date if the transform depends on its inverse)
910  transformVtk_RAS->Update();
911  if (transformVtk_RAS->GetInverseFlag())
912  {
913  InverseDisplacementFieldTransformDoubleType::Pointer gridTransformItk = InverseDisplacementFieldTransformDoubleType::New();
914  gridTransformItk->SetDisplacementField(gridImageItk_Lps);
915  transformItk_LPS = gridTransformItk;
916  }
917  else
918  {
919  DisplacementFieldTransformDoubleType::Pointer gridTransformItk = DisplacementFieldTransformDoubleType::New();
920  gridTransformItk->SetDisplacementField(gridImageItk_Lps);
921  transformItk_LPS = gridTransformItk;
922  }
923  return true;
924 }
925 
926 //----------------------------------------------------------------------------
927 template<typename T>
928 bool vtkITKTransformConverter::SetVTKOrientedGridTransformFromITKImage(vtkObject* loggerObject, vtkOrientedGridTransform* grid_Ras, typename itk::DisplacementFieldTransform< T, 3 >::DisplacementFieldType::Pointer gridImage_Lps)
929 {
930  typedef itk::DisplacementFieldTransform< T, 3 > DisplacementFieldTransformType;
931  typedef typename DisplacementFieldTransformType::DisplacementFieldType GridImageType;
932 
933  vtkNew<vtkImageData> gridImage_Ras;
934 
935  // Origin
936  gridImage_Ras->SetOrigin( -gridImage_Lps->GetOrigin()[0], -gridImage_Lps->GetOrigin()[1], gridImage_Lps->GetOrigin()[2] );
937 
938  // Spacing
939  gridImage_Ras->SetSpacing( gridImage_Lps->GetSpacing()[0], gridImage_Lps->GetSpacing()[1], gridImage_Lps->GetSpacing()[2] );
940 
941  // Direction
942  vtkNew<vtkMatrix4x4> gridDirectionMatrix_LPS;
943  for (unsigned int row=0; row<VTKDimension; row++)
944  {
945  for (unsigned int column=0; column<VTKDimension; column++)
946  {
947  gridDirectionMatrix_LPS->SetElement(row,column,gridImage_Lps->GetDirection()(row,column));
948  }
949  }
950  vtkNew<vtkMatrix4x4> lpsToRas;
951  lpsToRas->SetElement(0,0,-1);
952  lpsToRas->SetElement(1,1,-1);
953  vtkNew<vtkMatrix4x4> gridDirectionMatrix_RAS;
954  vtkMatrix4x4::Multiply4x4(lpsToRas.GetPointer(), gridDirectionMatrix_LPS.GetPointer(), gridDirectionMatrix_RAS.GetPointer());
955  grid_Ras->SetGridDirectionMatrix(gridDirectionMatrix_RAS.GetPointer());
956 
957  // Vectors
958  typename GridImageType::SizeType size = gridImage_Lps->GetBufferedRegion().GetSize();
959  gridImage_Ras->SetDimensions( size[0], size[1], size[2] );
960  unsigned int numberOfScalarComponents = GridImageType::PixelType::Dimension;
961  if (numberOfScalarComponents!=VTKDimension)
962  {
963  vtkErrorWithObjectMacro(loggerObject, "Cannot load grid transform: the input displacement field expected to contain "
964  << VTKDimension << " components but it actually contains " << numberOfScalarComponents );
965  return false;
966  }
967  gridImage_Ras->AllocateScalars(VTK_DOUBLE, 3);
968 
969  double* displacementVectors_Ras = reinterpret_cast<double*>(gridImage_Ras->GetScalarPointer());
970  itk::ImageRegionConstIterator<GridImageType> inputIt(gridImage_Lps, gridImage_Lps->GetRequestedRegion());
971  inputIt.GoToBegin();
972  while( !inputIt.IsAtEnd() )
973  {
974  typename GridImageType::PixelType displacementVectorLps=inputIt.Get();
975  *(displacementVectors_Ras++) = -displacementVectorLps[0];
976  *(displacementVectors_Ras++) = -displacementVectorLps[1];
977  *(displacementVectors_Ras++) = displacementVectorLps[2];
978  ++inputIt;
979  }
980 
981  grid_Ras->SetDisplacementGridData( gridImage_Ras.GetPointer() );
982 
983  // Set the interpolation to cubic to have smooth derivatives
984  grid_Ras->SetInterpolationModeToCubic();
985 
986  return true;
987 }
988 
989 //----------------------------------------------------------------------------
990 bool vtkITKTransformConverter::SetITKImageFromVTKOrientedGridTransform(vtkObject* loggerObject, GridImageDoubleType::Pointer &gridImage_Lps, vtkOrientedGridTransform* grid_Ras)
991 {
992  if (grid_Ras==nullptr)
993  {
994  vtkErrorWithObjectMacro(loggerObject, "Cannot save grid transform: the input vtkOrientedGridTransform is invalid");
995  return false;
996  }
997 
998  // Update is needed because DisplacementGrid may be out-of-date if the transform depends on its inverse
999  grid_Ras->Update();
1000 
1001  vtkImageData* gridImage_Ras = grid_Ras->GetDisplacementGrid();
1002  if (gridImage_Ras==nullptr)
1003  {
1004  vtkErrorWithObjectMacro(loggerObject, "Cannot save grid transform: the input vtkOrientedGridTransform does not contain a valid displacement grid");
1005  return false;
1006  }
1007  if (gridImage_Ras->GetNumberOfScalarComponents() != static_cast<int>(VTKDimension))
1008  {
1009  vtkErrorWithObjectMacro(loggerObject, "Cannot save grid transform: the input vtkOrientedGridTransform expected to contain "
1010  << VTKDimension << " components but it actually contains " << gridImage_Ras->GetNumberOfScalarComponents() );
1011  return false;
1012  }
1013 
1014  gridImage_Lps = GridImageDoubleType::New();
1015 
1016  // Origin
1017  double* origin_Ras = gridImage_Ras->GetOrigin();
1018  double origin_Lps[3] = { -origin_Ras[0], -origin_Ras[1], origin_Ras[2] };
1019  gridImage_Lps->SetOrigin( origin_Lps );
1020 
1021  // Spacing
1022  double* spacing = gridImage_Ras->GetSpacing();
1023  //GridType::SpacingType spacing( spacing );
1024  gridImage_Lps->SetSpacing( spacing );
1025 
1026  // Direction
1027  vtkNew<vtkMatrix4x4> gridDirectionMatrix_Ras;
1028  if (grid_Ras->GetGridDirectionMatrix()!=nullptr)
1029  {
1030  gridDirectionMatrix_Ras->DeepCopy(grid_Ras->GetGridDirectionMatrix());
1031  }
1032  vtkNew<vtkMatrix4x4> rasToLps;
1033  rasToLps->SetElement(0,0,-1);
1034  rasToLps->SetElement(1,1,-1);
1035  vtkNew<vtkMatrix4x4> gridDirectionMatrix_Lps;
1036  vtkMatrix4x4::Multiply4x4(rasToLps.GetPointer(), gridDirectionMatrix_Ras.GetPointer(), gridDirectionMatrix_Lps.GetPointer());
1037  GridImageDoubleType::DirectionType gridDirectionMatrixItk_Lps;
1038  for (unsigned int row=0; row<VTKDimension; row++)
1039  {
1040  for (unsigned int column=0; column<VTKDimension; column++)
1041  {
1042  gridDirectionMatrixItk_Lps(row,column) = gridDirectionMatrix_Lps->GetElement(row,column);
1043  }
1044  }
1045  gridImage_Lps->SetDirection(gridDirectionMatrixItk_Lps);
1046 
1047  // Vectors
1048  GridImageDoubleType::IndexType start;
1049  start[0] = start[1] = start[2] = 0;
1050  int* Nijk = gridImage_Ras->GetDimensions();
1051  GridImageDoubleType::SizeType size;
1052  size[0] = Nijk[0]; size[1] = Nijk[1]; size[2] = Nijk[2];
1053  GridImageDoubleType::RegionType region;
1054  region.SetSize( size );
1055  region.SetIndex( start );
1056  gridImage_Lps->SetRegions( region );
1057  gridImage_Lps->Allocate();
1058  itk::ImageRegionIterator<GridImageDoubleType> gridImageIt_Lps(gridImage_Lps, region);
1059  gridImageIt_Lps.GoToBegin();
1060  GridImageDoubleType::PixelType displacementVectorLps;
1061  double displacementScale = grid_Ras->GetDisplacementScale();
1062  double displacementShift = grid_Ras->GetDisplacementShift();
1063 
1064  if (gridImage_Ras->GetScalarType()==VTK_DOUBLE)
1065  {
1066  double* displacementVectors_Ras = reinterpret_cast<double*>(gridImage_Ras->GetScalarPointer());
1067  while( !gridImageIt_Lps.IsAtEnd() )
1068  {
1069  displacementVectorLps[0] = -( displacementScale * (*(displacementVectors_Ras++)) + displacementShift );
1070  displacementVectorLps[1] = -( displacementScale * (*(displacementVectors_Ras++)) + displacementShift );
1071  displacementVectorLps[2] = ( displacementScale * (*(displacementVectors_Ras++)) + displacementShift );
1072  gridImageIt_Lps.Set(displacementVectorLps);
1073  ++gridImageIt_Lps;
1074  }
1075  }
1076  else if (gridImage_Ras->GetScalarType()==VTK_FLOAT)
1077  {
1078  float* displacementVectors_Ras = reinterpret_cast<float*>(gridImage_Ras->GetScalarPointer());
1079  while( !gridImageIt_Lps.IsAtEnd() )
1080  {
1081  displacementVectorLps[0] = -( displacementScale * (*(displacementVectors_Ras++)) + displacementShift );
1082  displacementVectorLps[1] = -( displacementScale * (*(displacementVectors_Ras++)) + displacementShift );
1083  displacementVectorLps[2] = ( displacementScale * (*(displacementVectors_Ras++)) + displacementShift );
1084  gridImageIt_Lps.Set(displacementVectorLps);
1085  ++gridImageIt_Lps;
1086  }
1087  }
1088  else
1089  {
1090  vtkErrorWithObjectMacro(loggerObject, "Cannot save grid transform: only float and double scalar types are supported");
1091  return false;
1092  }
1093  return true;
1094 }
1095 
1096 //----------------------------------------------------------------------------
1097 template<typename T>
1098 bool vtkITKTransformConverter::SetVTKThinPlateSplineTransformFromITK(vtkObject* loggerObject, vtkThinPlateSplineTransform* transformVtk_RAS, typename itk::TransformBaseTemplate<T>::Pointer transformItk_LPS)
1099 {
1100  typedef itk::ThinPlateSplineKernelTransform<T,3> ThinPlateSplineTransformType;
1101  typedef itk::InverseThinPlateSplineKernelTransform< T, 3 > InverseThinPlateSplineTransformType;
1102 
1103  if (transformVtk_RAS==nullptr)
1104  {
1105  vtkErrorWithObjectMacro(loggerObject, "Cannot set VTK thin-plate spline transform from ITK: the output vtkThinPlateSplineTransform is invalid");
1106  return false;
1107  }
1108 
1109  if (!transformItk_LPS)
1110  {
1111  vtkErrorWithObjectMacro(loggerObject, "Cannot set VTK thin-plate spline transform from ITK: the input transform is nullptr");
1112  return false;
1113  }
1114 
1115  if (transformItk_LPS->GetOutputSpaceDimension() != VTKDimension)
1116  {
1117  vtkErrorWithObjectMacro(loggerObject, "Unsupported number of dimensions in thin-plate spline transform file (expected = "
1118  << VTKDimension << ", actual = " << transformItk_LPS->GetOutputSpaceDimension() << ")");
1119  return false;
1120  }
1121 
1122  std::string transformItkClassName = transformItk_LPS->GetNameOfClass();
1123 
1124  bool inverse = false;
1125  typename ThinPlateSplineTransformType::PointSetType::Pointer sourceLandmarksItk_Lps;
1126  typename ThinPlateSplineTransformType::PointSetType::Pointer targetLandmarksItk_Lps;
1127  if (transformItkClassName == "InverseThinPlateSplineKernelTransform") // inverse class is derived from forward class, so it has to be checked first
1128  {
1129  ThinPlateSplineTransformType* inverseTpsTransform = static_cast<InverseThinPlateSplineTransformType*>( transformItk_LPS.GetPointer() );
1130  inverse = true;
1131  sourceLandmarksItk_Lps = inverseTpsTransform->GetSourceLandmarks();
1132  targetLandmarksItk_Lps = inverseTpsTransform->GetTargetLandmarks();
1133  }
1134  else if (transformItkClassName == "ThinPlateSplineKernelTransform")
1135  {
1136  ThinPlateSplineTransformType* tpsTransform = static_cast<ThinPlateSplineTransformType*>( transformItk_LPS.GetPointer() );
1137  inverse = false;
1138  sourceLandmarksItk_Lps = tpsTransform->GetSourceLandmarks();
1139  targetLandmarksItk_Lps = tpsTransform->GetTargetLandmarks();
1140  }
1141  else
1142  {
1143  vtkDebugWithObjectMacro(loggerObject, "Not a ThinPlateSpline transform");
1144  return false;
1145  }
1146 
1147  vtkNew<vtkPoints> sourceLandmarksVtk_Ras;
1148  unsigned int numberOfSourceLandmarks = sourceLandmarksItk_Lps->GetNumberOfPoints();
1149  for(unsigned int i = 0; i < numberOfSourceLandmarks; i++)
1150  {
1151  typename ThinPlateSplineTransformType::InputPointType pointItk_Lps;
1152  bool pointExists = sourceLandmarksItk_Lps->GetPoint(i, &pointItk_Lps);
1153  if (!pointExists)
1154  {
1155  continue;
1156  }
1157  double pointVtk_Ras[3]={0};
1158  pointVtk_Ras[0] = -pointItk_Lps[0];
1159  pointVtk_Ras[1] = -pointItk_Lps[1];
1160  pointVtk_Ras[2] = pointItk_Lps[2];
1161  sourceLandmarksVtk_Ras->InsertNextPoint(pointVtk_Ras);
1162  }
1163 
1164  vtkNew<vtkPoints> targetLandmarksVtk_Ras;
1165  unsigned int numberOfTargetLandmarks = targetLandmarksItk_Lps->GetNumberOfPoints();
1166  for(unsigned int i = 0; i < numberOfTargetLandmarks; i++)
1167  {
1168  typename ThinPlateSplineTransformType::InputPointType pointItk_Lps;
1169  bool pointExists = targetLandmarksItk_Lps->GetPoint(i, &pointItk_Lps);
1170  if (!pointExists)
1171  {
1172  continue;
1173  }
1174  double pointVtk_Ras[3]={0};
1175  pointVtk_Ras[0] = -pointItk_Lps[0];
1176  pointVtk_Ras[1] = -pointItk_Lps[1];
1177  pointVtk_Ras[2] = pointItk_Lps[2];
1178  targetLandmarksVtk_Ras->InsertNextPoint(pointVtk_Ras);
1179  }
1180 
1181  transformVtk_RAS->SetBasisToR(); // need to set this because data is 3D
1182  transformVtk_RAS->SetSourceLandmarks(sourceLandmarksVtk_Ras.GetPointer());
1183  transformVtk_RAS->SetTargetLandmarks(targetLandmarksVtk_Ras.GetPointer());
1184 
1185  if (inverse)
1186  {
1187  transformVtk_RAS->Inverse();
1188  }
1189  return true;
1190 }
1191 
1192 //----------------------------------------------------------------------------
1194  itk::Object::Pointer& transformItk_LPS, vtkThinPlateSplineTransform* transformVtk_RAS, bool initialize /*= true*/)
1195 {
1196  if (transformVtk_RAS==nullptr)
1197  {
1198  vtkErrorWithObjectMacro(loggerObject, "Cannot set ITK thin-plate spline transform from VTK: the input vtkThinPlateSplineTransform is invalid");
1199  return false;
1200  }
1201 
1202  // Update is needed because the Basis value and Inverse flag may be out-of-date if the transform depends on its inverse
1203  transformVtk_RAS->Update();
1204 
1205  if (transformVtk_RAS->GetBasis()!=VTK_RBF_R)
1206  {
1207  vtkErrorWithObjectMacro(loggerObject, "Cannot set ITK thin-plate spline transform from VTK: basis function must be R."
1208  " Call SetBasisToR() method of the vtkThinPlateSplineTransform object before attempting to write it to file.");
1209  return false;
1210  }
1211 
1212  ThinPlateSplineTransformDoubleType::PointSetType::Pointer sourceLandmarksItk_Lps = ThinPlateSplineTransformDoubleType::PointSetType::New();
1213  vtkPoints* sourceLandmarksVtk_Ras=transformVtk_RAS->GetSourceLandmarks();
1214  if (sourceLandmarksVtk_Ras!=nullptr)
1215  {
1216  for (int i=0; i<sourceLandmarksVtk_Ras->GetNumberOfPoints(); i++)
1217  {
1218  double posVtk_Ras[3]={0};
1219  sourceLandmarksVtk_Ras->GetPoint(i, posVtk_Ras);
1220  ThinPlateSplineTransformDoubleType::InputPointType posItk_Lps;
1221  posItk_Lps[0] = -posVtk_Ras[0];
1222  posItk_Lps[1] = -posVtk_Ras[1];
1223  posItk_Lps[2] = posVtk_Ras[2];
1224  sourceLandmarksItk_Lps->GetPoints()->InsertElement(i,posItk_Lps);
1225  }
1226  }
1227  ThinPlateSplineTransformDoubleType::PointSetType::Pointer targetLandmarksItk_Lps = ThinPlateSplineTransformDoubleType::PointSetType::New();
1228  vtkPoints* targetLandmarksVtk_Ras=transformVtk_RAS->GetTargetLandmarks();
1229  if (targetLandmarksVtk_Ras!=nullptr)
1230  {
1231  for (int i=0; i<targetLandmarksVtk_Ras->GetNumberOfPoints(); i++)
1232  {
1233  double posVtk_Ras[3]={0};
1234  targetLandmarksVtk_Ras->GetPoint(i, posVtk_Ras);
1235  ThinPlateSplineTransformDoubleType::InputPointType posItk_Lps;
1236  posItk_Lps[0] = -posVtk_Ras[0];
1237  posItk_Lps[1] = -posVtk_Ras[1];
1238  posItk_Lps[2] = posVtk_Ras[2];
1239  targetLandmarksItk_Lps->GetPoints()->InsertElement(i,posItk_Lps);
1240  }
1241  }
1242 
1243  if (transformVtk_RAS->GetInverseFlag())
1244  {
1245  InverseThinPlateSplineTransformDoubleType::Pointer tpsTransformItk = InverseThinPlateSplineTransformDoubleType::New();
1246  tpsTransformItk->SetSourceLandmarks(sourceLandmarksItk_Lps);
1247  tpsTransformItk->SetTargetLandmarks(targetLandmarksItk_Lps);
1248  if (initialize)
1249  {
1250  tpsTransformItk->ComputeWMatrix();
1251  }
1252  transformItk_LPS = tpsTransformItk;
1253  }
1254  else
1255  {
1256  ThinPlateSplineTransformDoubleType::Pointer tpsTransformItk = ThinPlateSplineTransformDoubleType::New();
1257  tpsTransformItk->SetSourceLandmarks(sourceLandmarksItk_Lps);
1258  tpsTransformItk->SetTargetLandmarks(targetLandmarksItk_Lps);
1259  if (initialize)
1260  {
1261  tpsTransformItk->ComputeWMatrix();
1262  }
1263  transformItk_LPS = tpsTransformItk;
1264  }
1265  return true;
1266 }
1267 
1268 
1269 //----------------------------------------------------------------------------
1270 template <typename T>
1272  vtkObject* loggerObject,
1273  typename itk::TransformBaseTemplate<T>::Pointer transformItk)
1274 {
1275  bool conversionSuccess = false;
1276 
1277  // Linear
1278  vtkNew<vtkMatrix4x4> transformMatrixVtk;
1279  conversionSuccess = SetVTKLinearTransformFromITK<T>(loggerObject, transformMatrixVtk.GetPointer(), transformItk);
1280  if (conversionSuccess)
1281  {
1282  vtkNew<vtkTransform> linearTransformVtk;
1283  linearTransformVtk->SetMatrix(transformMatrixVtk.GetPointer());
1284  linearTransformVtk->Register(nullptr);
1285  return linearTransformVtk.GetPointer();
1286  }
1287  // Grid
1288  vtkNew<vtkOrientedGridTransform> gridTransformVtk;
1289  conversionSuccess = SetVTKOrientedGridTransformFromITK<T>(loggerObject, gridTransformVtk.GetPointer(), transformItk);
1290  if (conversionSuccess)
1291  {
1292  gridTransformVtk->Register(nullptr);
1293  return gridTransformVtk.GetPointer();
1294  }
1295  // BSpline
1296  vtkNew<vtkOrientedBSplineTransform> bsplineTransformVtk;
1297  conversionSuccess = SetVTKBSplineFromITKv4Generic<T>(loggerObject, bsplineTransformVtk.GetPointer(), transformItk);
1298  if (conversionSuccess)
1299  {
1300  bsplineTransformVtk->Register(nullptr);
1301  return bsplineTransformVtk.GetPointer();
1302  }
1303  // ThinPlateSpline
1304  vtkNew<vtkThinPlateSplineTransform> tpsTransformVtk;
1305  conversionSuccess = SetVTKThinPlateSplineTransformFromITK<T>(loggerObject, tpsTransformVtk.GetPointer(), transformItk);
1306  if (conversionSuccess)
1307  {
1308  tpsTransformVtk->Register(nullptr);
1309  return tpsTransformVtk.GetPointer();
1310  }
1311 
1312  return nullptr;
1313 }
1314 
1315 //----------------------------------------------------------------------------
1316 itk::Object::Pointer vtkITKTransformConverter::CreateITKTransformFromVTK(vtkObject* loggerObject,
1317  vtkAbstractTransform* transformVtk, itk::Object::Pointer& secondaryTransformItk, int preferITKv3CompatibleTransforms, bool initialize /*= true*/)
1318 {
1319  typedef itk::CompositeTransform< double > CompositeTransformType;
1320 
1321  if (transformVtk==nullptr)
1322  {
1323  vtkErrorWithObjectMacro(loggerObject, "CreateITKTransformFromVTK failed: invalid VTK transform");
1324  return nullptr;
1325  }
1326  vtkNew<vtkCollection> transformList;
1327  vtkMRMLTransformNode::FlattenGeneralTransform(transformList.GetPointer(), transformVtk);
1328  if (transformList->GetNumberOfItems()==0)
1329  {
1330  // no transformation means identity transform
1331  vtkNew<vtkTransform> identity;
1332  transformList->AddItem(identity.GetPointer());
1333  }
1334 
1335  itk::Object::Pointer primaryTransformItk;
1336  if (transformList->GetNumberOfItems()==1)
1337  {
1338  // Simple, non-composite transform (one item in the input transform)
1339  vtkObject* singleTransformVtk = transformList->GetItemAsObject(0);
1340  // Linear
1341  if (vtkHomogeneousTransform::SafeDownCast(singleTransformVtk))
1342  {
1343  vtkHomogeneousTransform* linearTransformVtk = vtkHomogeneousTransform::SafeDownCast(singleTransformVtk);
1344  vtkMatrix4x4* transformMatrix = linearTransformVtk->GetMatrix();
1345  if (!SetITKLinearTransformFromVTK(loggerObject, primaryTransformItk, transformMatrix))
1346  {
1347  // conversion failed
1348  return nullptr;
1349  }
1350  return primaryTransformItk;
1351  }
1352  // BSpline
1353  else if (vtkOrientedBSplineTransform::SafeDownCast(singleTransformVtk))
1354  {
1355  vtkOrientedBSplineTransform* bsplineTransformVtk = vtkOrientedBSplineTransform::SafeDownCast(singleTransformVtk);
1356  vtkMatrix4x4* bulkMatrix = bsplineTransformVtk->GetBulkTransformMatrix(); // non-zero for ITKv3 bspline transform only
1357  if (preferITKv3CompatibleTransforms || (bulkMatrix!=nullptr && !IsIdentityMatrix(bulkMatrix)))
1358  {
1359  if (!SetITKv3BSplineFromVTK(loggerObject, primaryTransformItk, secondaryTransformItk, bsplineTransformVtk, preferITKv3CompatibleTransforms))
1360  {
1361  // conversion failed
1362  return nullptr;
1363  }
1364  return primaryTransformItk;
1365  }
1366  else
1367  {
1368  if (!SetITKv4BSplineFromVTK(loggerObject, primaryTransformItk, bsplineTransformVtk))
1369  {
1370  // conversion failed
1371  return nullptr;
1372  }
1373  return primaryTransformItk;
1374  }
1375  }
1376  // Grid
1377  else if (vtkOrientedGridTransform::SafeDownCast(singleTransformVtk))
1378  {
1379  vtkOrientedGridTransform* gridTransformVtk = vtkOrientedGridTransform::SafeDownCast(singleTransformVtk);
1380  if (!SetITKOrientedGridTransformFromVTK(loggerObject, primaryTransformItk, gridTransformVtk))
1381  {
1382  // conversion failed
1383  return nullptr;
1384  }
1385  return primaryTransformItk;
1386  }
1387  // ThinPlateSpline
1388  else if (vtkThinPlateSplineTransform::SafeDownCast(singleTransformVtk))
1389  {
1390  vtkThinPlateSplineTransform* tpsTransformVtk = vtkThinPlateSplineTransform::SafeDownCast(singleTransformVtk);
1391  if (!SetITKThinPlateSplineTransformFromVTK(loggerObject, primaryTransformItk, tpsTransformVtk, initialize))
1392  {
1393  // conversion failed
1394  return nullptr;
1395  }
1396  return primaryTransformItk;
1397  }
1398  else
1399  {
1400  if (singleTransformVtk==nullptr)
1401  {
1402  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: invalid input transform");
1403  return nullptr;
1404  }
1405  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: conversion of transform type "<<singleTransformVtk->GetClassName()<<" is not supported");
1406  return nullptr;
1407  }
1408  }
1409  else
1410  {
1411  // Composite transform (more than one items in the input transform)
1412  // Create an ITK composite transform from the VTK general transform
1413  CompositeTransformType::Pointer compositeTransformItk = CompositeTransformType::New();
1414  primaryTransformItk = compositeTransformItk;
1415  // We need to iterate through the list in reverse order, as ITK CompositeTransform can only append transform on one side
1416  for (int transformIndex = transformList->GetNumberOfItems()-1; transformIndex>=0; --transformIndex)
1417  {
1418  vtkAbstractTransform* singleTransformVtk = vtkAbstractTransform::SafeDownCast(transformList->GetItemAsObject(transformIndex));
1419  itk::Object::Pointer secondaryTransformItkTmp;
1420  // We use ITKv4 format (PreferITKv3Transform format is set to false), because
1421  // legacy ITKv3 code does not know how to interpret composite transforms,
1422  // and also ITKv3 bspline transform with bulk component cannot be saved in a composite transform
1423  itk::Object::Pointer singleTransformItk = CreateITKTransformFromVTK(loggerObject, singleTransformVtk, secondaryTransformItkTmp, false );
1424  if (secondaryTransformItkTmp.IsNotNull())
1425  {
1426  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: composite transforms cannot contain legacy transforms (that contains secondary transforms). Do not harden transforms on legacy ITK transforms to avoid this error.");
1427  return nullptr;
1428  }
1429 
1430  if (singleTransformItk.IsNull()
1431  || std::string(singleTransformItk->GetNameOfClass()).find("Transform") == std::string::npos)
1432  {
1433  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: invalid element found while trying to create a composite transform");
1434  return nullptr;
1435  }
1436  CompositeTransformType::TransformType::Pointer singleTransformItkTypeChecked = static_cast< CompositeTransformType::TransformType* >( singleTransformItk.GetPointer() );
1437  compositeTransformItk->AddTransform(singleTransformItkTypeChecked.GetPointer());
1438  }
1439  return primaryTransformItk;
1440  }
1441  return nullptr;
1442 }
1443 
1444 #endif // __vtkITKTransformConverter_h
itk::DisplacementFieldTransform< double, 3 > DisplacementFieldTransformDoubleType
static bool SetVTKBSplineFromITKv3Generic(vtkObject *loggerObject, vtkOrientedBSplineTransform *bsplineVtk, typename itk::TransformBaseTemplate< T >::Pointer warpTransformItk, typename itk::TransformBaseTemplate< T >::Pointer bulkTransformItk)
static bool SetITKv4BSplineFromVTKGeneric(vtkObject *loggerObject, typename itk::Transform< T, VTKDimension, VTKDimension >::Pointer &warpTransformItk, vtkOrientedBSplineTransform *bsplineVtk)
static bool SetITKBSplineParametersFromVTKGeneric(vtkObject *loggerObject, typename itk::Transform< typename BSplineTransformType::ScalarType, VTKDimension, VTKDimension >::Pointer &warpTransformItk, vtkOrientedBSplineTransform *bsplineVtk)
itk::ThinPlateSplineKernelTransform< double, 3 > ThinPlateSplineTransformDoubleType
static bool SetITKLinearTransformFromVTK(vtkObject *loggerObject, itk::Object::Pointer &transformItk_LPS, vtkMatrix4x4 *transformVtk_RAS)
static bool SetVTKLinearTransformFromITK(vtkObject *loggerObject, vtkMatrix4x4 *transformVtk_RAS, typename itk::TransformBaseTemplate< T >::Pointer transformItk_LPS)
static bool SetVTKThinPlateSplineTransformFromITK(vtkObject *loggerObject, vtkThinPlateSplineTransform *transformVtk_RAS, typename itk::TransformBaseTemplate< T >::Pointer transformItk_LPS)
static bool SetITKv3BSplineFromVTKGeneric(vtkObject *loggerObject, typename itk::Transform< T, VTKDimension, VTKDimension >::Pointer &warpTransformItk, typename itk::Transform< T, VTKDimension, VTKDimension >::Pointer &bulkTransformItk, vtkOrientedBSplineTransform *bsplineVtk, bool alwaysAddBulkTransform)
static bool SetVTKBSplineFromITKv4Generic(vtkObject *loggerObject, vtkOrientedBSplineTransform *bsplineVtk, typename itk::TransformBaseTemplate< T >::Pointer warpTransformItk)
itk::TransformFileWriter TransformWriterType
static bool SetVTKOrientedGridTransformFromITKImage(vtkObject *loggerObject, vtkOrientedGridTransform *grid_Ras, typename itk::DisplacementFieldTransform< T, 3 >::DisplacementFieldType::Pointer gridImage_Lps)
static bool SetITKv4BSplineFromVTK(vtkObject *loggerObject, itk::Object::Pointer &warpTransformItk, vtkOrientedBSplineTransform *bsplineVtk)
static bool IsIdentityMatrix(vtkMatrix4x4 *matrix)
static bool SetITKv3BSplineFromVTK(vtkObject *loggerObject, itk::Object::Pointer &warpTransformItk, itk::Object::Pointer &bulkTransformItk, vtkOrientedBSplineTransform *bsplineVtk, bool alwaysAddBulkTransform)
static const unsigned int VTKDimension
static bool SetITKOrientedGridTransformFromVTK(vtkObject *loggerObject, itk::Object::Pointer &transformItk_LPS, vtkOrientedGridTransform *transformVtk_RAS)
itk::AffineTransform< TransformRealType, 3 > AffineTransformType
Definition: dtitypes.h:64
static void FlattenGeneralTransform(vtkCollection *outputTransformList, vtkAbstractTransform *inputTransform)
static vtkAbstractTransform * CreateVTKTransformFromITK(vtkObject *loggerObject, typename itk::TransformBaseTemplate< T >::Pointer transformItk)
DisplacementFieldTransformDoubleType::DisplacementFieldType GridImageDoubleType
static itk::Object::Pointer CreateITKTransformFromVTK(vtkObject *loggerObject, vtkAbstractTransform *transformVtk, itk::Object::Pointer &secondaryTransformItk, int preferITKv3CompatibleTransforms, bool initialize=true)
static bool SetVTKBSplineParametersFromITKGeneric(vtkObject *loggerObject, vtkOrientedBSplineTransform *bsplineVtk, typename itk::TransformBaseTemplate< typename BSplineTransformType::ScalarType >::Pointer warpTransformItk)
static bool SetVTKOrientedGridTransformFromITK(vtkObject *loggerObject, vtkOrientedGridTransform *transformVtk_RAS, typename itk::TransformBaseTemplate< T >::Pointer transformItk_LPS)
static bool SetITKImageFromVTKOrientedGridTransform(vtkObject *loggerObject, GridImageDoubleType::Pointer &gridImage_Lps, vtkOrientedGridTransform *grid_Ras)
static const int BSPLINE_TRANSFORM_ORDER
static bool SetITKThinPlateSplineTransformFromVTK(vtkObject *loggerObject, itk::Object::Pointer &transformItk_LPS, vtkThinPlateSplineTransform *transformVtk_RAS, bool initialize=true)