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