Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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