Slicer 5.8
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:
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