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