Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkDiffImageApplier.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 "mitkDiffImageApplier.h"
18 
20 #include "mitkImageAccessByItk.h"
21 #include "mitkImageCast.h"
22 #include "mitkImageTimeSelector.h"
23 #include "mitkRenderingManager.h"
25 
26 #include <itkImageRegionConstIterator.h>
27 #include <itkImageSliceIteratorWithIndex.h>
28 
30 {
31 }
32 
34 {
35 }
36 
38 {
39  ApplyDiffImageOperation *imageOperation = dynamic_cast<ApplyDiffImageOperation *>(operation);
40  if (imageOperation // we actually have the kind of operation that we can handle
41  &&
42  imageOperation->IsImageStillValid()) // AND the image is not yet deleted
43  {
44  m_Image = imageOperation->GetImage();
45  Image::Pointer image3D = m_Image; // will be changed later in case of 3D+t
46 
47  m_SliceDifferenceImage = imageOperation->GetDiffImage();
48  m_TimeStep = imageOperation->GetTimeStep();
49 
50  m_Factor = imageOperation->GetFactor();
51 
52  if (m_SliceDifferenceImage->GetDimension() == 2)
53  {
54  m_SliceIndex = imageOperation->GetSliceIndex();
55  m_SliceDimension = imageOperation->GetSliceDimension();
56  switch (m_SliceDimension)
57  {
58  default:
59  case 2:
60  m_Dimension0 = 0;
61  m_Dimension1 = 1;
62  break;
63  case 1:
64  m_Dimension0 = 0;
65  m_Dimension1 = 2;
66  break;
67  case 0:
68  m_Dimension0 = 1;
69  m_Dimension1 = 2;
70  break;
71  }
72 
73  if (m_SliceDifferenceImage->GetDimension() != 2 || (m_Image->GetDimension() < 3 || m_Image->GetDimension() > 4) ||
74  m_SliceDifferenceImage->GetDimension(0) != m_Image->GetDimension(m_Dimension0) ||
75  m_SliceDifferenceImage->GetDimension(1) != m_Image->GetDimension(m_Dimension1) ||
76  m_SliceIndex >= m_Image->GetDimension(m_SliceDimension))
77  {
78  itkExceptionMacro(
79  "Slice and image dimensions differ or slice index is too large. Sorry, cannot work like this.");
80  return;
81  }
82 
83  if (m_Image->GetDimension() == 4)
84  {
86  timeSelector->SetInput(m_Image);
87  timeSelector->SetTimeNr(m_TimeStep);
88  timeSelector->UpdateLargestPossibleRegion();
89  image3D = timeSelector->GetOutput();
90  }
91 
92  // this will do a long long if/else to find out both pixel types
93  AccessFixedDimensionByItk(image3D, ItkImageSwitch2DDiff, 3);
94 
95  if (m_Factor == 1 || m_Factor == -1)
96  {
97  if (m_Factor == -1)
98  {
99  // multiply diff pixels by factor and then send this diff slice
100  AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 2);
101  }
102 
103  // just send the diff to SegmentationInterpolationController
106  if (interpolator)
107  {
108  interpolator->BlockModified(true);
109  interpolator->SetChangedSlice(m_SliceDifferenceImage, m_SliceDimension, m_SliceIndex, m_TimeStep);
110  }
111 
112  m_Image->Modified();
113 
114  if (interpolator)
115  {
116  interpolator->BlockModified(false);
117  }
118 
119  if (m_Factor == -1) // return to normal values
120  {
121  AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 2);
122  }
123  }
124  else // no trivial case, too lazy to do something else
125  {
126  m_Image->Modified(); // check if interpolation is called. prefer to send diff directly
127  }
128 
130  }
131  else if (m_SliceDifferenceImage->GetDimension() == 3)
132  {
133  // ...
134  if (m_SliceDifferenceImage->GetDimension(0) != m_Image->GetDimension(0) ||
135  m_SliceDifferenceImage->GetDimension(1) != m_Image->GetDimension(1) ||
136  m_SliceDifferenceImage->GetDimension(2) != m_Image->GetDimension(2) || m_TimeStep >= m_Image->GetDimension(3))
137  {
138  itkExceptionMacro("Diff image size differs from original image size. Sorry, cannot work like this.");
139  return;
140  }
141 
142  if (m_Image->GetDimension() == 4)
143  {
145  timeSelector->SetInput(m_Image);
146  timeSelector->SetTimeNr(m_TimeStep);
147  timeSelector->UpdateLargestPossibleRegion();
148  image3D = timeSelector->GetOutput();
149  }
150 
151  // this will do a long long if/else to find out both pixel types
152  AccessFixedDimensionByItk(image3D, ItkImageSwitch3DDiff, 3);
153 
154  if (m_Factor == 1 || m_Factor == -1)
155  {
156  if (m_Factor == -1)
157  {
158  // multiply diff pixels by factor and then send this diff slice
159  AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 3);
160  }
161 
162  // just send the diff to SegmentationInterpolationController
165  if (interpolator)
166  {
167  interpolator->BlockModified(true);
168  interpolator->SetChangedVolume(m_SliceDifferenceImage, m_TimeStep);
169  }
170 
171  m_Image->Modified();
172 
173  if (interpolator)
174  {
175  interpolator->BlockModified(false);
176  }
177 
178  if (m_Factor == -1) // return to normal values
179  {
180  AccessFixedDimensionByItk(m_SliceDifferenceImage, ItkInvertPixelValues, 3);
181  }
182  }
183  else // no trivial case, too lazy to do something else
184  {
185  m_Image->Modified(); // check if interpolation is called. prefer to send diff directly
186  }
187 
189  }
190  else
191  {
192  itkExceptionMacro("Diff image must be 2D or 3D. Sorry, cannot work like this.");
193  return;
194  }
195  }
196 
197  m_Image = nullptr;
198  m_SliceDifferenceImage = nullptr;
199 }
200 
202 {
203  static DiffImageApplier::Pointer s_Instance = DiffImageApplier::New();
204 
205  return s_Instance;
206 }
207 
208 // basically copied from mitk/Core/Algorithms/mitkImageAccessByItk.h
209 #define myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, pixeltype, dimension, itkimage2) \
210  if (typeId == MapPixelComponentType<pixeltype>::value) \
211  \
212 { \
213  typedef itk::Image<pixeltype, dimension> ImageType; \
214  typedef mitk::ImageToItk<ImageType> ImageToItkType; \
215  itk::SmartPointer<ImageToItkType> imagetoitk = ImageToItkType::New(); \
216  const mitk::Image *constImage = mitkImage; \
217  mitk::Image *nonConstImage = const_cast<mitk::Image *>(constImage); \
218  nonConstImage->Update(); \
219  imagetoitk->SetInput(nonConstImage); \
220  imagetoitk->Update(); \
221  itkImageTypeFunction(imagetoitk->GetOutput(), itkimage2); \
222  \
223 }
224 
225 #define myMITKDiffImageApplierFilterAccessAllTypesByItk(mitkImage, itkImageTypeFunction, dimension, itkimage2) \
226  \
227 { \
228  myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, double, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk( \
229  mitkImage, \
230  itkImageTypeFunction, \
231  float, \
232  dimension, \
233  itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, int, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, \
234  itkImageTypeFunction, \
235  unsigned int, \
236  dimension, \
237  itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, short, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned short, dimension, itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, \
238  itkImageTypeFunction, \
239  char, \
240  dimension, \
241  itkimage2) else myMITKDiffImageApplierFilterAccessByItk(mitkImage, \
242  itkImageTypeFunction, \
243  unsigned char, \
244  dimension, \
245  itkimage2) \
246  \
247 }
248 
249 template <typename TPixel, unsigned int VImageDimension>
250 void mitk::DiffImageApplier::ItkImageSwitch2DDiff(itk::Image<TPixel, VImageDimension> *itkImage)
251 {
252  const int typeId = m_SliceDifferenceImage->GetPixelType().GetComponentType();
253 
254  myMITKDiffImageApplierFilterAccessAllTypesByItk(m_SliceDifferenceImage, ItkImageProcessing2DDiff, 2, itkImage);
255 }
256 
257 template <typename TPixel, unsigned int VImageDimension>
258 void mitk::DiffImageApplier::ItkImageSwitch3DDiff(itk::Image<TPixel, VImageDimension> *itkImage)
259 {
260  const int typeId = m_SliceDifferenceImage->GetPixelType().GetComponentType();
261 
262  myMITKDiffImageApplierFilterAccessAllTypesByItk(m_SliceDifferenceImage, ItkImageProcessing3DDiff, 3, itkImage);
263 }
264 
265 template <typename TPixel1, unsigned int VImageDimension1, typename TPixel2, unsigned int VImageDimension2>
266 void mitk::DiffImageApplier::ItkImageProcessing2DDiff(itk::Image<TPixel1, VImageDimension1> *diffImage,
267  itk::Image<TPixel2, VImageDimension2> *outputImage)
268 {
269  typedef itk::Image<TPixel1, VImageDimension1> DiffImageType;
270  typedef itk::Image<TPixel2, VImageDimension2> VolumeImageType;
271 
272  typedef itk::ImageSliceIteratorWithIndex<VolumeImageType> OutputSliceIteratorType;
273  typedef itk::ImageRegionConstIterator<DiffImageType> DiffSliceIteratorType;
274 
275  typename VolumeImageType::RegionType sliceInVolumeRegion;
276 
277  sliceInVolumeRegion = outputImage->GetLargestPossibleRegion();
278  sliceInVolumeRegion.SetSize(m_SliceDimension, 1); // just one slice
279  sliceInVolumeRegion.SetIndex(m_SliceDimension, m_SliceIndex); // exactly this slice, please
280 
281  OutputSliceIteratorType outputIterator(outputImage, sliceInVolumeRegion);
282  outputIterator.SetFirstDirection(m_Dimension0);
283  outputIterator.SetSecondDirection(m_Dimension1);
284 
285  DiffSliceIteratorType diffIterator(diffImage, diffImage->GetLargestPossibleRegion());
286 
287  // iterate over output slice (and over input slice simultaneously)
288  outputIterator.GoToBegin();
289  diffIterator.GoToBegin();
290  while (!outputIterator.IsAtEnd())
291  {
292  while (!outputIterator.IsAtEndOfSlice())
293  {
294  while (!outputIterator.IsAtEndOfLine())
295  {
296  TPixel2 newValue = outputIterator.Get() + (TPixel2)((double)diffIterator.Get() * m_Factor);
297  outputIterator.Set(newValue);
298  ++outputIterator;
299  ++diffIterator;
300  }
301  outputIterator.NextLine();
302  }
303  outputIterator.NextSlice();
304  }
305 }
306 
307 template <typename TPixel1, unsigned int VImageDimension1, typename TPixel2, unsigned int VImageDimension2>
308 void mitk::DiffImageApplier::ItkImageProcessing3DDiff(itk::Image<TPixel1, VImageDimension1> *diffImage,
309  itk::Image<TPixel2, VImageDimension2> *outputImage)
310 {
311  typedef itk::Image<TPixel1, VImageDimension1> DiffImageType;
312  typedef itk::Image<TPixel2, VImageDimension2> VolumeImageType;
313 
314  typedef itk::ImageRegionIterator<VolumeImageType> OutputSliceIteratorType;
315  typedef itk::ImageRegionConstIterator<DiffImageType> DiffSliceIteratorType;
316 
317  OutputSliceIteratorType outputIterator(outputImage, outputImage->GetLargestPossibleRegion());
318  DiffSliceIteratorType diffIterator(diffImage, diffImage->GetLargestPossibleRegion());
319 
320  // iterate over output slice (and over input slice simultaneously)
321  outputIterator.GoToBegin();
322  diffIterator.GoToBegin();
323  while (!outputIterator.IsAtEnd())
324  {
325  TPixel2 newValue = outputIterator.Get() + (TPixel2)((double)diffIterator.Get() * m_Factor);
326  outputIterator.Set(newValue);
327  ++outputIterator;
328  ++diffIterator;
329  }
330 }
331 
332 template <typename TPixel, unsigned int VImageDimension>
333 void mitk::DiffImageApplier::ItkInvertPixelValues(itk::Image<TPixel, VImageDimension> *itkImage)
334 {
335  typedef itk::ImageRegionIterator<itk::Image<TPixel, VImageDimension>> IteratorType;
336  IteratorType iter(itkImage, itkImage->GetLargestPossibleRegion());
337 
338  iter.GoToBegin();
339  while (!iter.IsAtEnd())
340  {
341  iter.Set(-(iter.Get()));
342  ++iter;
343  }
344 }
Operation, that holds information about some image difference.
void ItkImageProcessing2DDiff(itk::Image< TPixel1, VImageDimension1 > *itkImage1, itk::Image< TPixel2, VImageDimension2 > *itkImage2)
itk::SmartPointer< Self > Pointer
#define AccessFixedDimensionByItk(mitkImage, itkImageTypeFunction, dimension)
Access a mitk-image with known dimension by an itk-image.
Base class of all Operation-classes.
Definition: mitkOperation.h:33
static Pointer New()
void ItkImageSwitch3DDiff(itk::Image< TPixel, VImageDimension > *image)
void SetChangedSlice(const Image *sliceDiff, unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep)
Update after changing a single slice.
void ItkImageSwitch2DDiff(itk::Image< TPixel, VImageDimension > *image)
Applies difference images to 3D images.
void ItkImageProcessing3DDiff(itk::Image< TPixel1, VImageDimension1 > *itkImage1, itk::Image< TPixel2, VImageDimension2 > *itkImage2)
void BlockModified(bool)
Block reaction to an images Modified() events.
static DiffImageApplier * GetInstanceForUndo()
void SetChangedVolume(const Image *sliceDiff, unsigned int timeStep)
static RenderingManager * GetInstance()
static SegmentationInterpolationController * InterpolatorForImage(const Image *)
Find interpolator for a given image.
virtual void ExecuteOperation(Operation *operation) override
#define myMITKDiffImageApplierFilterAccessAllTypesByItk(mitkImage, itkImageTypeFunction, dimension, itkimage2)
void ItkInvertPixelValues(itk::Image< TPixel, VImageDimension > *itkImage)
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
static Pointer New()