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