Slicer  4.10
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 http://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 http://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==ITK_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==ITK_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==ITK_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==ITK_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==ITK_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()!=ITK_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==ITK_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!=ITK_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=ITK_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==ITK_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==ITK_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==ITK_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==ITK_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 ITK_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 = ITK_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==ITK_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==ITK_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()!=ITK_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==ITK_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 ITK_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==ITK_NULLPTR)
1197  {
1198  vtkErrorWithObjectMacro(loggerObject, "Cannot set ITK thin-plate spline transform from VTK: the intput 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!=ITK_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!=ITK_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  std::cout << "CreateVTKTransformFromITK - SetVTKLinearTransformFromITK conversionSuccess:" << conversionSuccess << std::endl;
1281  if (conversionSuccess)
1282  {
1283  vtkNew<vtkTransform> linearTransformVtk;
1284  linearTransformVtk->SetMatrix(transformMatrixVtk.GetPointer());
1285  linearTransformVtk->Register(ITK_NULLPTR);
1286  return linearTransformVtk.GetPointer();
1287  }
1288  // Grid
1289  vtkNew<vtkOrientedGridTransform> gridTransformVtk;
1290  conversionSuccess = SetVTKOrientedGridTransformFromITK<T>(loggerObject, gridTransformVtk.GetPointer(), transformItk);
1291  if (conversionSuccess)
1292  {
1293  gridTransformVtk->Register(ITK_NULLPTR);
1294  return gridTransformVtk.GetPointer();
1295  }
1296  // BSpline
1297  vtkNew<vtkOrientedBSplineTransform> bsplineTransformVtk;
1298  conversionSuccess = SetVTKBSplineFromITKv4Generic<T>(loggerObject, bsplineTransformVtk.GetPointer(), transformItk);
1299  if (conversionSuccess)
1300  {
1301  bsplineTransformVtk->Register(ITK_NULLPTR);
1302  return bsplineTransformVtk.GetPointer();
1303  }
1304  // ThinPlateSpline
1305  vtkNew<vtkThinPlateSplineTransform> tpsTransformVtk;
1306  conversionSuccess = SetVTKThinPlateSplineTransformFromITK<T>(loggerObject, tpsTransformVtk.GetPointer(), transformItk);
1307  if (conversionSuccess)
1308  {
1309  tpsTransformVtk->Register(ITK_NULLPTR);
1310  return tpsTransformVtk.GetPointer();
1311  }
1312 
1313  return ITK_NULLPTR;
1314 }
1315 
1316 //----------------------------------------------------------------------------
1317 itk::Object::Pointer vtkITKTransformConverter::CreateITKTransformFromVTK(vtkObject* loggerObject,
1318  vtkAbstractTransform* transformVtk, itk::Object::Pointer& secondaryTransformItk, int preferITKv3CompatibleTransforms, bool initialize /*= true*/)
1319 {
1320  typedef itk::CompositeTransform< double > CompositeTransformType;
1321 
1322  if (transformVtk==ITK_NULLPTR)
1323  {
1324  vtkErrorWithObjectMacro(loggerObject, "CreateITKTransformFromVTK failed: invalid VTK transform");
1325  return ITK_NULLPTR;
1326  }
1327  vtkNew<vtkCollection> transformList;
1328  vtkMRMLTransformNode::FlattenGeneralTransform(transformList.GetPointer(), transformVtk);
1329  if (transformList->GetNumberOfItems()==0)
1330  {
1331  // no transformation means identity transform
1332  vtkNew<vtkTransform> identity;
1333  transformList->AddItem(identity.GetPointer());
1334  }
1335 
1336  itk::Object::Pointer primaryTransformItk;
1337  if (transformList->GetNumberOfItems()==1)
1338  {
1339  // Simple, non-composite transform (one item in the input transform)
1340  vtkObject* singleTransformVtk = transformList->GetItemAsObject(0);
1341  // Linear
1342  if (vtkHomogeneousTransform::SafeDownCast(singleTransformVtk))
1343  {
1344  vtkHomogeneousTransform* linearTransformVtk = vtkHomogeneousTransform::SafeDownCast(singleTransformVtk);
1345  vtkMatrix4x4* transformMatrix = linearTransformVtk->GetMatrix();
1346  if (!SetITKLinearTransformFromVTK(loggerObject, primaryTransformItk, transformMatrix))
1347  {
1348  // conversion failed
1349  return ITK_NULLPTR;
1350  }
1351  return primaryTransformItk;
1352  }
1353  // BSpline
1354  else if (vtkOrientedBSplineTransform::SafeDownCast(singleTransformVtk))
1355  {
1356  vtkOrientedBSplineTransform* bsplineTransformVtk = vtkOrientedBSplineTransform::SafeDownCast(singleTransformVtk);
1357  vtkMatrix4x4* bulkMatrix = bsplineTransformVtk->GetBulkTransformMatrix(); // non-zero for ITKv3 bspline transform only
1358  if (preferITKv3CompatibleTransforms || (bulkMatrix!=ITK_NULLPTR && !IsIdentityMatrix(bulkMatrix)))
1359  {
1360  if (!SetITKv3BSplineFromVTK(loggerObject, primaryTransformItk, secondaryTransformItk, bsplineTransformVtk, preferITKv3CompatibleTransforms))
1361  {
1362  // conversion failed
1363  return ITK_NULLPTR;
1364  }
1365  return primaryTransformItk;
1366  }
1367  else
1368  {
1369  if (!SetITKv4BSplineFromVTK(loggerObject, primaryTransformItk, bsplineTransformVtk))
1370  {
1371  // conversion failed
1372  return ITK_NULLPTR;
1373  }
1374  return primaryTransformItk;
1375  }
1376  }
1377  // Grid
1378  else if (vtkOrientedGridTransform::SafeDownCast(singleTransformVtk))
1379  {
1380  vtkOrientedGridTransform* gridTransformVtk = vtkOrientedGridTransform::SafeDownCast(singleTransformVtk);
1381  if (!SetITKOrientedGridTransformFromVTK(loggerObject, primaryTransformItk, gridTransformVtk))
1382  {
1383  // conversion failed
1384  return ITK_NULLPTR;
1385  }
1386  return primaryTransformItk;
1387  }
1388  // ThinPlateSpline
1389  else if (vtkThinPlateSplineTransform::SafeDownCast(singleTransformVtk))
1390  {
1391  vtkThinPlateSplineTransform* tpsTransformVtk = vtkThinPlateSplineTransform::SafeDownCast(singleTransformVtk);
1392  if (!SetITKThinPlateSplineTransformFromVTK(loggerObject, primaryTransformItk, tpsTransformVtk, initialize))
1393  {
1394  // conversion failed
1395  return ITK_NULLPTR;
1396  }
1397  return primaryTransformItk;
1398  }
1399  else
1400  {
1401  if (singleTransformVtk==ITK_NULLPTR)
1402  {
1403  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: invalid input transform");
1404  return ITK_NULLPTR;
1405  }
1406  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: conversion of transform type "<<singleTransformVtk->GetClassName()<<" is not supported");
1407  return ITK_NULLPTR;
1408  }
1409  }
1410  else
1411  {
1412  // Composite transform (more than one items in the input transform)
1413  // Create an ITK composite transform from the VTK general transform
1414  CompositeTransformType::Pointer compositeTransformItk = CompositeTransformType::New();
1415  primaryTransformItk = compositeTransformItk;
1416  // We need to iterate through the list in reverse order, as ITK CompositeTransform can only append transform on one side
1417  for (int transformIndex = transformList->GetNumberOfItems()-1; transformIndex>=0; --transformIndex)
1418  {
1419  vtkAbstractTransform* singleTransformVtk = vtkAbstractTransform::SafeDownCast(transformList->GetItemAsObject(transformIndex));
1420  itk::Object::Pointer secondaryTransformItk;
1421  // We use ITKv4 format (PreferITKv3Transform format is set to false), because
1422  // legacy ITKv3 code does not know how to interpret composite transforms,
1423  // and also ITKv3 bspline transform with bulk component cannot be saved in a composite transform
1424  itk::Object::Pointer singleTransformItk = CreateITKTransformFromVTK(loggerObject, singleTransformVtk, secondaryTransformItk, false );
1425  if (secondaryTransformItk.IsNotNull())
1426  {
1427  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.");
1428  return ITK_NULLPTR;
1429  }
1430 
1431  if (singleTransformItk.IsNull()
1432  || std::string(singleTransformItk->GetNameOfClass()).find("Transform") == std::string::npos)
1433  {
1434  vtkErrorWithObjectMacro(loggerObject, "vtkITKTransformConverter::CreateITKTransformFromVTK failed: invalid element found while trying to create a composite transform");
1435  return ITK_NULLPTR;
1436  }
1437  CompositeTransformType::TransformType::Pointer singleTransformItkTypeChecked = static_cast< CompositeTransformType::TransformType* >( singleTransformItk.GetPointer() );
1438  compositeTransformItk->AddTransform(singleTransformItkTypeChecked.GetPointer());
1439  }
1440  return primaryTransformItk;
1441  }
1442  return ITK_NULLPTR;
1443 }
1444 
1445 #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)
virtual void SetBulkTransformMatrix(vtkMatrix4x4 *)
static bool SetITKv4BSplineFromVTKGeneric(vtkObject *loggerObject, typename itk::Transform< T, VTKDimension, VTKDimension >::Pointer &warpTransformItk, vtkOrientedBSplineTransform *bsplineVtk)
static vtkOrientedBSplineTransform * SafeDownCast(vtkObject *o)
static bool SetITKBSplineParametersFromVTKGeneric(vtkObject *loggerObject, typename itk::Transform< typename BSplineTransformType::ScalarType, VTKDimension, VTKDimension >::Pointer &warpTransformItk, vtkOrientedBSplineTransform *bsplineVtk)
virtual vtkMatrix4x4 * GetBulkTransformMatrix()
itk::ThinPlateSplineKernelTransform< double, 3 > ThinPlateSplineTransformDoubleType
static bool SetITKLinearTransformFromVTK(vtkObject *loggerObject, itk::Object::Pointer &transformItk_LPS, vtkMatrix4x4 *transformVtk_RAS)
vtkOrientedBSplineTransform - arbitrarily oriented cubic b-spline deformation transformation.
static bool SetVTKLinearTransformFromITK(vtkObject *loggerObject, vtkMatrix4x4 *transformVtk_RAS, typename itk::TransformBaseTemplate< T >::Pointer transformItk_LPS)
static vtkOrientedGridTransform * SafeDownCast(vtkObject *o)
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)
virtual vtkMatrix4x4 * GetGridDirectionMatrix()
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
virtual void SetGridDirectionMatrix(vtkMatrix4x4 *)
static bool SetITKOrientedGridTransformFromVTK(vtkObject *loggerObject, itk::Object::Pointer &transformItk_LPS, vtkOrientedGridTransform *transformVtk_RAS)
virtual vtkMatrix4x4 * GetGridDirectionMatrix()
itk::AffineTransform< TransformRealType, 3 > AffineTransformType
Definition: dtitypes.h:64
static void FlattenGeneralTransform(vtkCollection *outputTransformList, vtkAbstractTransform *inputTransform)
vtkOrientedGridTransform - arbitrarily oriented displacement field deformation transformation.
virtual void SetGridDirectionMatrix(vtkMatrix4x4 *)
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)