Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkImageMappingHelper.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include <itkInterpolateImageFunction.h>
18 #include <itkNearestNeighborInterpolateImageFunction.h>
19 #include <itkLinearInterpolateImageFunction.h>
20 #include <itkBSplineInterpolateImageFunction.h>
21 #include <itkWindowedSincInterpolateImageFunction.h>
22 
23 #include <mitkImageAccessByItk.h>
24 #include <mitkImageCast.h>
25 #include <mitkGeometry3D.h>
26 #include <mitkImageToItk.h>
27 #include <mitkImageTimeSelector.h>
28 
29 #include "mapRegistration.h"
30 
31 #include "mitkImageMappingHelper.h"
32 #include "mitkRegistrationHelper.h"
33 
34 template <typename TImage >
36 {
37  typedef ::itk::InterpolateImageFunction< TImage > BaseInterpolatorType;
38  typename BaseInterpolatorType::Pointer result;
39 
40  switch (interpolatorType)
41  {
43  {
45  break;
46  }
48  {
50  spInterpolator->SetSplineOrder(3);
51  result = spInterpolator;
52  break;
53  }
55  {
57  break;
58  }
60  {
61  result = ::itk::WindowedSincInterpolateImageFunction<TImage,4,::itk::Function::WelchWindowFunction<4> >::New();
62  break;
63  }
64  default:
65  {
67  break;
68  }
69 
70  }
71 
72  return result;
73 };
74 
75 template <typename TPixelType, unsigned int VImageDimension >
76 void doMITKMap(const ::itk::Image<TPixelType,VImageDimension>* input, mitk::ImageMappingHelper::ResultImageType::Pointer& result, const mitk::ImageMappingHelper::RegistrationType*& registration,
77  bool throwOnOutOfInputAreaError, const double& paddingValue, const mitk::ImageMappingHelper::ResultImageGeometryType*& resultGeometry,
78  bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
79 {
80  typedef ::map::core::Registration<VImageDimension,VImageDimension> ConcreteRegistrationType;
81  typedef ::map::core::ImageMappingTask<ConcreteRegistrationType, ::itk::Image<TPixelType,VImageDimension>, ::itk::Image<TPixelType,VImageDimension> > MappingTaskType;
83 
84  typedef typename MappingTaskType::ResultImageDescriptorType ResultImageDescriptorType;
85  typename ResultImageDescriptorType::Pointer resultDescriptor;
86 
87  //check if image and result geometry fits the passed registration
89  if (registration->getMovingDimensions()!=VImageDimension)
90  {
91  map::core::OStringStream str;
92  str << "Dimension of MITK image ("<<VImageDimension<<") does not equal the moving dimension of the registration object ("<<registration->getMovingDimensions()<<").";
93  throw mitk::AccessByItkException(str.str());
94  }
95 
96  if (registration->getTargetDimensions()!=VImageDimension)
97  {
98  map::core::OStringStream str;
99  str << "Dimension of MITK image ("<<VImageDimension<<") does not equal the target dimension of the registration object ("<<registration->getTargetDimensions()<<").";
100  throw mitk::AccessByItkException(str.str());
101  }
102 
103  const ConcreteRegistrationType* castedReg = dynamic_cast<const ConcreteRegistrationType*>(registration);
104 
105  if (registration->getTargetDimensions()==2 && resultGeometry)
106  {
108 
109  if (bounds[4]!=0 || bounds[5]!=0)
110  {
111  //array "bounds" is constructed as [min Dim1, max Dim1, min Dim2, max Dim2, min Dim3, max Dim3]
112  //therfore [4] and [5] must be 0
113 
114  map::core::OStringStream str;
115  str << "Dimension of defined result geometry does not equal the target dimension of the registration object ("<<registration->getTargetDimensions()<<").";
116  throw mitk::AccessByItkException(str.str());
117  }
118  }
119 
120  //check/create resultDescriptor
122  if (resultGeometry)
123  {
124  resultDescriptor = ResultImageDescriptorType::New();
125 
126  typename ResultImageDescriptorType::PointType origin;
127  typename ResultImageDescriptorType::SizeType size;
128  typename ResultImageDescriptorType::SpacingType fieldSpacing;
129  typename ResultImageDescriptorType::DirectionType matrix;
130 
132  mitk::Vector3D geoSpacing = resultGeometry->GetSpacing();
133  mitk::Point3D geoOrigin = resultGeometry->GetOrigin();
134  mitk::AffineTransform3D::MatrixType geoMatrix = resultGeometry->GetIndexToWorldTransform()->GetMatrix();
135 
136  for (unsigned int i = 0; i<VImageDimension; ++i)
137  {
138  origin[i] = static_cast<typename ResultImageDescriptorType::PointType::ValueType>(geoOrigin[i]);
139  fieldSpacing[i] = static_cast<typename ResultImageDescriptorType::SpacingType::ValueType>(geoSpacing[i]);
140  size[i] = static_cast<typename ResultImageDescriptorType::SizeType::SizeValueType>(geoBounds[(2*i)+1]-geoBounds[2*i])*fieldSpacing[i];
141  }
142 
143  //Matrix extraction
144  matrix.SetIdentity();
145  unsigned int i;
146  unsigned int j;
147 
153 
154  // the following loop devides by spacing now to normalize columns.
155  // counterpart of InitializeByItk in mitkImage.h line 372 of revision 15092.
156 
157  // Check if information is lost
158  if ( VImageDimension == 2)
159  {
160  if ( ( geoMatrix[0][2] != 0) ||
161  ( geoMatrix[1][2] != 0) ||
162  ( geoMatrix[2][0] != 0) ||
163  ( geoMatrix[2][1] != 0) ||
164  (( geoMatrix[2][2] != 1) && ( geoMatrix[2][2] != -1) ))
165  {
166  // The 2D MITK image contains 3D rotation information.
167  // This cannot be expressed in a 2D ITK image, so the ITK image will have no rotation
168  }
169  else
170  {
171  // The 2D MITK image can be converted to an 2D ITK image without information loss!
172  for ( i=0; i < 2; ++i)
173  {
174  for( j=0; j < 2; ++j )
175  {
176  matrix[i][j] = geoMatrix[i][j]/fieldSpacing[j];
177  }
178  }
179  }
180  }
181  else if (VImageDimension == 3)
182  {
183  // Normal 3D image. Conversion possible without problem!
184  for ( i=0; i < 3; ++i)
185  {
186  for( j=0; j < 3; ++j )
187  {
188  matrix[i][j] = geoMatrix[i][j]/fieldSpacing[j];
189  }
190  }
191  }
192  else
193  {
194  assert(0);
195  throw mitk::AccessByItkException("Usage of resultGeometry for 2D images is not yet implemented.");
199  }
200 
201  resultDescriptor->setOrigin(origin);
202  resultDescriptor->setSize(size);
203  resultDescriptor->setSpacing(fieldSpacing);
204  resultDescriptor->setDirection(matrix);
205  }
206 
207  //do the mapping
209  typedef ::itk::InterpolateImageFunction< ::itk::Image<TPixelType,VImageDimension> > BaseInterpolatorType;
210  typename BaseInterpolatorType::Pointer interpolator = generateInterpolator< ::itk::Image<TPixelType,VImageDimension> >(interpolatorType);
211  assert(interpolator.IsNotNull());
212  spTask->setImageInterpolator(interpolator);
213  spTask->setInputImage(input);
214  spTask->setRegistration(castedReg);
215  spTask->setResultImageDescriptor(resultDescriptor);
216  spTask->setThrowOnMappingError(throwOnMappingError);
217  spTask->setErrorValue(errorValue);
218  spTask->setThrowOnPaddingError(throwOnOutOfInputAreaError);
219  spTask->setPaddingValue(paddingValue);
220 
221  spTask->execute();
222  mitk::CastToMitkImage<>(spTask->getResultImage(),result);
223 }
224 
227  bool throwOnOutOfInputAreaError, const double& paddingValue, const ResultImageGeometryType* resultGeometry,
228  bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
229 {
230  if (!registration)
231  {
232  mitkThrow() << "Cannot map image. Passed registration wrapper pointer is NULL.";
233  }
234  if (!input)
235  {
236  mitkThrow() << "Cannot map image. Passed image pointer is NULL.";
237  }
238 
240 
241  if(input->GetTimeSteps()==1)
242  { //map the image and done
243  AccessByItk_n(input, doMITKMap, (result, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType));
244  }
245  else
246  { //map every time step and compose
247 
248  mitk::TimeGeometry::ConstPointer timeGeometry = input->GetTimeGeometry();
249  mitk::TimeGeometry::Pointer mappedTimeGeometry = timeGeometry->Clone();
250 
251  for (unsigned int i = 0; i<input->GetTimeSteps(); ++i)
252  {
253  ResultImageGeometryType::Pointer mappedGeometry = resultGeometry->Clone();
254  mappedTimeGeometry->SetTimeStepGeometry(mappedGeometry,i);
255  }
256 
257  result = mitk::Image::New();
258  result->Initialize(input->GetPixelType(),*mappedTimeGeometry, 1, input->GetTimeSteps());
259 
260  for (unsigned int i = 0; i<input->GetTimeSteps(); ++i)
261  {
263  imageTimeSelector->SetInput(input);
264  imageTimeSelector->SetTimeNr(i);
265  imageTimeSelector->UpdateLargestPossibleRegion();
266 
267  InputImageType::Pointer timeStepInput = imageTimeSelector->GetOutput();
268  ResultImageType::Pointer timeStepResult;
269  AccessByItk_n(timeStepInput, doMITKMap, (timeStepResult, registration, throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue, interpolatorType));
270  result->SetVolume(timeStepResult->GetVolumeData()->GetData(),i);
271  }
272  }
273 
274  return result;
275 }
276 
279  bool throwOnOutOfInputAreaError, const double& paddingValue, const ResultImageGeometryType* resultGeometry,
280  bool throwOnMappingError, const double& errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
281 {
282  if (!registration)
283  {
284  mitkThrow() << "Cannot map image. Passed registration wrapper pointer is NULL.";
285  }
286  if (!registration->GetRegistration())
287  {
288  mitkThrow() << "Cannot map image. Passed registration wrapper containes no registration.";
289  }
290  if (!input)
291  {
292  mitkThrow() << "Cannot map image. Passed image pointer is NULL.";
293  }
294 
295  ResultImageType::Pointer result = map(input, registration->GetRegistration(), throwOnOutOfInputAreaError, paddingValue, resultGeometry, throwOnMappingError, errorValue);
296  return result;
297 }
298 
299 
302  refineGeometry(const InputImageType* input, const RegistrationType* registration,
303  bool throwOnError)
304 {
306 
307  if (!registration)
308  {
309  mitkThrow() << "Cannot refine image geometry. Passed registration pointer is NULL.";
310  }
311  if (!input)
312  {
313  mitkThrow() << "Cannot refine image geometry. Passed image pointer is NULL.";
314  }
315 
317  if(spTransform.IsNull() && throwOnError)
318  {
319  mitkThrow() << "Cannot refine image geometry. Registration does not contain a suitable direct mapping kernel (3D affine transformation or compatible required).";
320  }
321 
322  if(spTransform.IsNotNull())
323  {
324  //copy input image
325  result = input->Clone();
326 
327  //refine geometries
328  for(unsigned int i = 0; i < result->GetTimeSteps(); ++i)
329  { //refine every time step
330  result->GetGeometry(i)->Compose(spTransform);
331  }
332  result->GetTimeGeometry()->Update();
333  }
334 
335  return result;
336 }
337 
340  refineGeometry(const InputImageType* input, const MITKRegistrationType* registration,
341  bool throwOnError)
342 {
343  if (!registration)
344  {
345  mitkThrow() << "Cannot refine image geometry. Passed registration wrapper pointer is NULL.";
346  }
347  if (!registration->GetRegistration())
348  {
349  mitkThrow() << "Cannot refine image geometry. Passed registration wrapper containes no registration.";
350  }
351  if (!input)
352  {
353  mitkThrow() << "Cannot refine image geometry. Passed image pointer is NULL.";
354  }
355 
356  ResultImageType::Pointer result = refineGeometry(input, registration->GetRegistration(), throwOnError);
357  return result;
358 }
359 
360 bool
363 {
364  bool result = true;
365 
366  if (!registration)
367  {
368  mitkThrow() << "Cannot check refine capability of registration. Passed registration pointer is NULL.";
369  }
370 
371  //if the helper does not return null, we can refine the geometry.
372  result = mitk::MITKRegistrationHelper::getAffineMatrix(registration,false).IsNotNull();
373 
374  return result;
375 }
376 
377 bool
380 {
381  if (!registration)
382  {
383  mitkThrow() << "Cannot check refine capability of registration. Passed registration wrapper pointer is NULL.";
384  }
385  if (!registration->GetRegistration())
386  {
387  mitkThrow() << "Cannot check refine capability of registration. Passed registration wrapper containes no registration.";
388  }
389 
390  return canRefineGeometry(registration->GetRegistration());
391 }
392 
const Point3D GetOrigin() const
Get the origin, e.g. the upper-left corner of the plane.
static Affine3DTransformType::Pointer getAffineMatrix(const mitk::MAPRegistrationWrapper *wrapper, bool inverseKernel)
mitk::Point3D PointType
itk::SmartPointer< Self > Pointer
BoundingBoxType::BoundsArrayType BoundsArrayType
const mitk::Vector3D GetSpacing() const
Get the spacing (size of a pixel).
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
Definition: mitkBaseData.h:52
MAPRegistrationWrapper Wrapper class to allow the handling of MatchPoint registration objects as mitk...
unsigned int GetTimeSteps() const
Get the number of time steps from the TimeGeometry As the base data has not a data vector given by it...
Definition: mitkBaseData.h:346
#define AccessByItk_n(mitkImage, itkImageTypeFunction, va_tuple)
Access a MITK image by an ITK image with one or more parameters.
const BoundsArrayType GetBounds() const
map::core::RegistrationBase * GetRegistration()
MITKMATCHPOINTREGISTRATION_EXPORT bool canRefineGeometry(const RegistrationType *registration)
ValueType
Type of the value held by a Value object.
Definition: jsoncpp.h:345
#define mitkThrow()
Image class for storing images.
Definition: mitkImage.h:76
MITKMATCHPOINTREGISTRATION_EXPORT ResultImageType::Pointer refineGeometry(const InputImageType *input, const RegistrationType *registration, bool throwOnError=true)
const mitk::PixelType GetPixelType(int n=0) const
Returns the PixelType of channel n.
Definition: mitkImage.cpp:105
void doMITKMap(const ::itk::Image< TPixelType, VImageDimension > *input, mitk::ImageMappingHelper::ResultImageType::Pointer &result, const mitk::ImageMappingHelper::RegistrationType *&registration, bool throwOnOutOfInputAreaError, const double &paddingValue, const mitk::ImageMappingHelper::ResultImageGeometryType *&resultGeometry, bool throwOnMappingError, const double &errorValue, mitk::ImageMappingInterpolator::Type interpolatorType)
static Pointer New()
Exception class thrown in AccessByItk macros.
MITKMATCHPOINTREGISTRATION_EXPORT ResultImageType::Pointer map(const InputImageType *input, const RegistrationType *registration, bool throwOnOutOfInputAreaError=false, const double &paddingValue=0, const ResultImageGeometryType *resultGeometry=NULL, bool throwOnMappingError=true, const double &errorValue=0, mitk::ImageMappingInterpolator::Type interpolatorType=mitk::ImageMappingInterpolator::Linear)
typename::itk::InterpolateImageFunction< TImage >::Pointer generateInterpolator(mitk::ImageMappingInterpolator::Type interpolatorType)
::map::core::RegistrationBase RegistrationType
Pointer Clone() const
BaseGeometry Describes the geometry of a data object.
static Pointer New()
mitk::AffineTransform3D * GetIndexToWorldTransform()
Get the transformation used to convert from index to world coordinates.
Pointer Clone() const
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.