Medical Imaging Interaction Toolkit  2018.4.99-a28b433c
Medical Imaging Interaction Toolkit
mitkImageToItk.txx
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #ifndef IMAGETOITK_TXX_INCLUDED_C1C2FCD2
14 #define IMAGETOITK_TXX_INCLUDED_C1C2FCD2
15 
16 #include "itkImportMitkImageContainer.h"
17 #include "mitkBaseProcess.h"
18 #include "mitkException.h"
19 #include "mitkImageReadAccessor.h"
20 #include "mitkImageToItk.h"
21 #include "mitkImageWriteAccessor.h"
22 
23 #include <memory>
24 
25 template <typename TImageType>
26 struct SetLengthHelper
27 {
28  SetLengthHelper(TImageType *in) { m_Image = in; }
29 private:
30  TImageType *m_Image;
31 };
32 
33 template <typename T, unsigned int VDimension>
34 struct SetLengthHelper<itk::Image<T, VDimension>>
35 {
36  typedef itk::Image<T, VDimension> TImageType;
37 
38  SetLengthHelper(TImageType *in) { m_Image = in; }
39  void SetVectorLength(size_t) {}
40 private:
41  TImageType *m_Image;
42 };
43 
44 template <typename T, unsigned int VDimension>
45 struct SetLengthHelper<itk::VectorImage<T, VDimension>>
46 {
47  typedef itk::VectorImage<T, VDimension> TImageType;
48 
49  SetLengthHelper(TImageType *in) { m_Image = in; }
50  void SetVectorLength(size_t len) { m_Image->SetVectorLength(len); }
51 private:
52  TImageType *m_Image;
53 };
54 
55 template <class TOutputImage>
56 void mitk::ImageToItk<TOutputImage>::SetInput(mitk::Image *input)
57 {
58  this->SetInput(static_cast<const Image *>(input));
59  m_ConstInput = false;
60 }
61 
62 template <class TOutputImage>
63 void mitk::ImageToItk<TOutputImage>::SetInput(const mitk::Image *input)
64 {
65  this->CheckInput(input);
66  // Process object is not const-correct so the const_cast is required here
67  itk::ProcessObject::PushFrontInput(input);
68  m_ConstInput = true;
69 }
70 
71 template <class TOutputImage>
72 mitk::Image *mitk::ImageToItk<TOutputImage>::GetInput(void)
73 {
74  if (this->GetNumberOfInputs() < 1)
75  {
76  return nullptr;
77  }
78 
79  return static_cast<mitk::Image *>(itk::ProcessObject::GetInput(0));
80 }
81 
82 template <class TOutputImage>
83 const mitk::Image *mitk::ImageToItk<TOutputImage>::GetInput() const
84 {
85  if (this->GetNumberOfInputs() < 1)
86  {
87  return nullptr;
88  }
89 
90  return static_cast<const mitk::Image *>(itk::ProcessObject::GetInput(0));
91 }
92 
93 template <class TOutputImage>
94 void mitk::ImageToItk<TOutputImage>::GenerateData()
95 {
96  // Allocate output
97  mitk::Image::Pointer input = this->GetInput();
98  typename Superclass::OutputImageType::Pointer output = this->GetOutput();
99 
100  unsigned long noBytes = input->GetDimension(0);
101  for (unsigned int i = 1; i < TOutputImage::GetImageDimension(); ++i)
102  {
103  noBytes = noBytes * input->GetDimension(i);
104  }
105  const mitk::PixelType pixelType = input->GetPixelType();
106  if (pixelType.GetPixelType() == itk::ImageIOBase::VECTOR)
107  {
108  noBytes *= pixelType.GetNumberOfComponents();
109  SetLengthHelper<typename Superclass::OutputImageType> helper(output.GetPointer());
110  helper.SetVectorLength(pixelType.GetNumberOfComponents());
111  }
112 
113  std::unique_ptr<mitk::ImageAccessorBase> imageAccess;
114  if (m_ConstInput)
115  {
116  imageAccess.reset(new mitk::ImageReadAccessor(input, nullptr, m_Options));
117  }
118  else
119  {
120  imageAccess.reset(new mitk::ImageWriteAccessor(input, nullptr, m_Options));
121  }
122 
123  // hier wird momentan wohl nur der erste Channel verwendet??!!
124  if (imageAccess->GetData() == nullptr)
125  {
126  itkWarningMacro(<< "no image data to import in ITK image");
127 
128  RegionType bufferedRegion;
129  output->SetBufferedRegion(bufferedRegion);
130  return;
131  }
132 
133  if (m_CopyMemFlag)
134  {
135  itkDebugMacro("copyMem ...");
136 
137  output->Allocate();
138 
139  memcpy(output->GetBufferPointer(), imageAccess->GetData(), sizeof(InternalPixelType) * noBytes);
140  }
141  else
142  {
143  itkDebugMacro("do not copyMem ...");
144  typedef itk::ImportMitkImageContainer<itk::SizeValueType, InternalPixelType> ImportContainerType;
145  typename ImportContainerType::Pointer import;
146 
147  import = ImportContainerType::New();
148  import->Initialize();
149 
150  itkDebugMacro(<< "size of container = " << import->Size());
151  // import->SetImageDataItem(m_ImageDataItem);
152  import->SetImageAccessor(imageAccess.release(), sizeof(InternalPixelType) * noBytes);
153 
154  output->SetPixelContainer(import);
155  itkDebugMacro(<< "size of container = " << import->Size());
156  }
157 }
158 
159 template <class TOutputImage>
160 void mitk::ImageToItk<TOutputImage>::UpdateOutputInformation()
161 {
162  mitk::Image::Pointer input = this->GetInput();
163  if (input.IsNotNull() && (input->GetSource().IsNotNull()) && input->GetSource()->Updating())
164  {
165  typename Superclass::OutputImageType::Pointer output = this->GetOutput();
166  unsigned long t1 = input->GetUpdateMTime() + 1;
167  if (t1 > this->m_OutputInformationMTime.GetMTime())
168  {
169  output->SetPipelineMTime(t1);
170 
171  this->GenerateOutputInformation();
172 
173  this->m_OutputInformationMTime.Modified();
174  }
175  return;
176  }
177  Superclass::UpdateOutputInformation();
178 }
179 
180 template <class TOutputImage>
181 void mitk::ImageToItk<TOutputImage>::GenerateOutputInformation()
182 {
183  mitk::Image::ConstPointer input = this->GetInput();
184  typename Superclass::OutputImageType::Pointer output = this->GetOutput();
185 
186  // allocate size, origin, spacing, direction in types of output image
187  SizeType size;
188  const unsigned int itkDimMin3 = (TOutputImage::ImageDimension > 3 ? TOutputImage::ImageDimension : 3);
189  const unsigned int itkDimMax3 = (TOutputImage::ImageDimension < 3 ? TOutputImage::ImageDimension : 3);
190  typename Superclass::OutputImageType::PointType::ValueType origin[itkDimMin3];
191  typename Superclass::OutputImageType::SpacingType::ComponentType spacing[itkDimMin3];
192  typename Superclass::OutputImageType::DirectionType direction;
193 
194  // copy as much information as possible into size and spacing
195  unsigned int i;
196  for (i = 0; i < itkDimMax3; ++i)
197  {
198  size[i] = input->GetDimension(i);
199  spacing[i] = input->GetGeometry()->GetSpacing()[i];
200  }
201  for (; i < TOutputImage::ImageDimension; ++i)
202  {
203  origin[i] = 0.0;
204  size[i] = input->GetDimension(i);
205  spacing[i] = 1.0;
206  }
207 
208  // build region from size
209  IndexType start;
210  start.Fill(0);
211  RegionType region;
212  region.SetIndex(start);
213  region.SetSize(size);
214 
215  // copy as much information as possible into origin
216  const mitk::Point3D &mitkorigin = input->GetGeometry()->GetOrigin();
217  itk2vtk(mitkorigin, origin);
218 
219  // copy as much information as possible into direction
220  direction.SetIdentity();
221  unsigned int j;
222  const AffineTransform3D::MatrixType &matrix = input->GetGeometry()->GetIndexToWorldTransform()->GetMatrix();
223 
224  /// \warning 2D MITK images could have a 3D rotation, since they have a 3x3 geometry matrix.
225  /// If it is only a rotation around the axial plane normal, it can be express with a 2x2 matrix.
226  /// In this case, the ITK image conservs this information and is identical to the MITK image!
227  /// If the MITK image contains any other rotation, the ITK image will have no rotation at all.
228  /// Spacing is of course conserved in both cases.
229 
230  // the following loop devides by spacing now to normalize columns.
231  // counterpart of InitializeByItk in mitkImage.h line 372 of revision 15092.
232 
233  // Check if information is lost
234  if (TOutputImage::ImageDimension <= 2)
235  {
236  if ((TOutputImage::ImageDimension == 2) && ((matrix[0][2] != 0) || (matrix[1][2] != 0) || (matrix[2][0] != 0) ||
237  (matrix[2][1] != 0) || ((matrix[2][2] != 1) && (matrix[2][2] != -1))))
238  {
239  // The 2D MITK image contains 3D rotation information.
240  // This cannot be expressed in a 2D ITK image, so the ITK image will have no rotation
241  }
242  else
243  {
244  // The 2D MITK image can be converted to an 2D ITK image without information loss!
245  for (i = 0; i < itkDimMax3; ++i)
246  for (j = 0; j < itkDimMax3; ++j)
247  direction[i][j] = matrix[i][j] / spacing[j];
248  }
249  }
250  else
251  {
252  // Normal 3D image. Conversion possible without problem!
253  for (i = 0; i < itkDimMax3; ++i)
254  for (j = 0; j < itkDimMax3; ++j)
255  direction[i][j] = matrix[i][j] / spacing[j];
256  }
257 
258  // set information into output image
259  output->SetRegions(region);
260  output->SetOrigin(origin);
261  output->SetSpacing(spacing);
262  output->SetDirection(direction);
263 }
264 
265 template <class TOutputImage>
266 void mitk::ImageToItk<TOutputImage>::CheckInput(const mitk::Image *input) const
267 {
268  if (input == nullptr)
269  {
270  itkExceptionMacro(<< "image is null");
271  }
272  if (input->GetDimension() != TOutputImage::GetImageDimension())
273  {
274  itkExceptionMacro(<< "image has dimension " << input->GetDimension() << " instead of "
275  << TOutputImage::GetImageDimension());
276  }
277 
278  if (!(input->GetPixelType() == mitk::MakePixelType<TOutputImage>(input->GetPixelType().GetNumberOfComponents())))
279  {
280  itkExceptionMacro(<< "image has wrong pixel type ");
281  }
282 }
283 
284 template <class TOutputImage>
285 void mitk::ImageToItk<TOutputImage>::PrintSelf(std::ostream &os, itk::Indent indent) const
286 {
287  Superclass::PrintSelf(os, indent);
288 }
289 
290 #endif // IMAGETOITK_TXX_INCLUDED_C1C2FCD2