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
mitkSliceBasedInterpolationController.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 
18 
19 #include "mitkExtractSliceFilter.h"
20 #include "mitkImageAccessByItk.h"
21 #include "mitkImageCast.h"
22 #include "mitkImageReadAccessor.h"
23 #include "mitkImageTimeSelector.h"
24 
26 
27 #include <itkCommand.h>
28 #include <itkImage.h>
29 #include <itkImageSliceConstIteratorWithIndex.h>
30 
33 
35  const Image *image)
36 {
37  InterpolatorMapType::iterator iter = s_InterpolatorForImage.find(image);
38  if (iter != s_InterpolatorForImage.end())
39  {
40  return iter->second;
41  }
42  else
43  {
44  return NULL;
45  }
46 }
47 
49  : m_WorkingImage(NULL), m_ReferenceImage(NULL)
50 {
51 }
52 
54 {
55  // remove this from the list of interpolators
56  for (InterpolatorMapType::iterator iter = s_InterpolatorForImage.begin(); iter != s_InterpolatorForImage.end();
57  ++iter)
58  {
59  if (iter->second == this)
60  {
61  s_InterpolatorForImage.erase(iter);
62  break;
63  }
64  }
65 }
66 
68 {
69  m_LabelCountInSlice.clear();
70  int numberOfLabels = m_WorkingImage->GetNumberOfLabels();
71  m_LabelCountInSlice.resize(m_WorkingImage->GetTimeSteps());
72 
73  for (unsigned int timeStep = 0; timeStep < m_WorkingImage->GetTimeSteps(); ++timeStep)
74  {
75  m_LabelCountInSlice[timeStep].resize(3);
76  for (unsigned int dim = 0; dim < 3; ++dim)
77  {
78  m_LabelCountInSlice[timeStep][dim].clear();
79  m_LabelCountInSlice[timeStep][dim].resize(m_WorkingImage->GetDimension(dim));
80  for (unsigned int slice = 0; slice < m_WorkingImage->GetDimension(dim); ++slice)
81  {
82  m_LabelCountInSlice[timeStep][dim][slice].clear();
83  m_LabelCountInSlice[timeStep][dim][slice].resize(numberOfLabels);
84  m_LabelCountInSlice[timeStep][dim][slice].assign(numberOfLabels, 0);
85  }
86  }
87  }
88 }
89 
91 {
92  if (m_WorkingImage != newImage)
93  {
94  // delete the current working image from the list of interpolators
95  InterpolatorMapType::iterator iter = s_InterpolatorForImage.find(m_WorkingImage);
96  if (iter != s_InterpolatorForImage.end())
97  {
98  s_InterpolatorForImage.erase(iter);
99  }
100 
101  m_WorkingImage = newImage;
102 
103  s_InterpolatorForImage.insert(std::make_pair(m_WorkingImage, this));
104  }
105 
106  this->ResetLabelCount();
107 
108  AccessFixedDimensionByItk_1(m_WorkingImage, ScanImageITKProcessing, 3, 0);
109 
110  // for all timesteps, scan whole image: TODO: enable this again for 3D+time
111  /*
112  for (unsigned int timeStep = 0; timeStep < m_WorkingImage->GetTimeSteps(); ++timeStep)
113  {
114  ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
115  timeSelector->SetInput( m_WorkingImage );
116  timeSelector->SetTimeNr( timeStep );
117  timeSelector->UpdateLargestPossibleRegion();
118  Image::Pointer segmentation3D = timeSelector->GetOutput();
119  this->SetChangedVolume( segmentation3D.GetPointer(), timeStep );
120  }
121  */
122  // this->Modified();
123 }
124 
126 {
127  if (!newImage)
128  return;
129 
130  m_ReferenceImage = newImage;
131 
132  // ensure the reference image has the same dimensionality and extents as the segmentation image
133  if (m_WorkingImage.IsNull() || m_ReferenceImage->GetDimension() != m_WorkingImage->GetDimension() ||
134  m_ReferenceImage->GetPixelType().GetNumberOfComponents() != 1 ||
135  m_WorkingImage->GetPixelType().GetNumberOfComponents() != 1)
136  {
137  MITK_WARN << "Segmentation image has different image characteristics than reference image." << std::endl;
138  m_ReferenceImage = NULL;
139  return;
140  }
141 
142  for (unsigned int dim = 0; dim < m_WorkingImage->GetDimension(); ++dim)
143  {
144  if (m_ReferenceImage->GetDimension(dim) != m_WorkingImage->GetDimension(dim))
145  {
146  MITK_WARN << "original patient image does not match segmentation (different extent in dimension " << dim
147  << "), ignoring patient image" << std::endl;
148  m_ReferenceImage = NULL;
149  return;
150  }
151  }
152 }
153 
155  unsigned int sliceDimension,
156  unsigned int sliceIndex,
157  unsigned int timeStep)
158 {
159  if (!slice)
160  return;
161  if (slice->GetDimension() != 2)
162  return;
163  if (sliceDimension > 2)
164  return;
165  if (m_WorkingImage.IsNull())
166  return;
167 
168  // check if the number of labels has changed
169  int numberOfLabels = m_WorkingImage->GetNumberOfLabels();
170  if (m_LabelCountInSlice[0][0][0].size() != numberOfLabels)
171  return;
172 
173  unsigned int dim0(0);
174  unsigned int dim1(1);
175 
176  // determine the other two dimensions
177  switch (sliceDimension)
178  {
179  default:
180  case 2:
181  dim0 = 0;
182  dim1 = 1;
183  break;
184  case 1:
185  dim0 = 0;
186  dim1 = 2;
187  break;
188  case 0:
189  dim0 = 1;
190  dim1 = 2;
191  break;
192  }
193 
195  slice, ScanSliceITKProcessing, 2, SetChangedSliceOptions(sliceDimension, sliceIndex, dim0, dim1, timeStep));
196 
197  // this->Modified();
198 }
199 
200 template <typename PixelType>
201 void mitk::SliceBasedInterpolationController::ScanSliceITKProcessing(const itk::Image<PixelType, 2> *input,
202  const SetChangedSliceOptions &options)
203 {
204  unsigned int timeStep = options.timeStep;
205  unsigned int sliceDimension = options.sliceDimension;
206  unsigned int sliceIndex = options.sliceIndex;
207 
208  if (sliceDimension > 2)
209  return;
210  if (sliceIndex >= m_LabelCountInSlice[timeStep][sliceDimension].size())
211  return;
212 
213  unsigned int dim0(options.dim0);
214  unsigned int dim1(options.dim1);
215 
216  std::vector<int> numberOfPixels; // number of pixels in the current slice that are equal to the active label
217  int numberOfLabels = m_WorkingImage->GetNumberOfLabels();
218  numberOfPixels.resize(numberOfLabels);
219 
220  typedef itk::Image<PixelType, 2> ImageType;
221  typedef itk::ImageRegionConstIteratorWithIndex<ImageType> IteratorType;
222 
223  IteratorType iter(input, input->GetLargestPossibleRegion());
224  iter.GoToBegin();
225 
226  typename IteratorType::IndexType index;
227 
228  while (!iter.IsAtEnd())
229  {
230  index = iter.GetIndex();
231  int value = static_cast<int>(iter.Get());
232  ++m_LabelCountInSlice[timeStep][dim0][index[0]][value];
233  ++m_LabelCountInSlice[timeStep][dim1][index[1]][value];
234  ++numberOfPixels[value];
235  ++iter;
236  }
237 
238  for (unsigned int label = 0; label < numberOfLabels; ++label)
239  {
240  m_LabelCountInSlice[timeStep][sliceDimension][sliceIndex][label] = numberOfPixels[label];
241  }
242 }
243 
244 template <typename TPixel, unsigned int VImageDimension>
245 void mitk::SliceBasedInterpolationController::ScanImageITKProcessing(itk::Image<TPixel, VImageDimension> *input,
246  unsigned int timeStep)
247 {
248  typedef itk::ImageSliceConstIteratorWithIndex<itk::Image<TPixel, VImageDimension>> IteratorType;
249 
250  IteratorType iter(input, input->GetLargestPossibleRegion());
251  iter.SetFirstDirection(0);
252  iter.SetSecondDirection(1);
253 
254  typename IteratorType::IndexType index;
255  unsigned int x = 0;
256  unsigned int y = 0;
257  unsigned int z = 0;
258 
259  std::vector<int> numberOfPixels; // number of pixels per slice that are equal to the active label
260  int numberOfLabels = m_WorkingImage->GetNumberOfLabels();
261  numberOfPixels.resize(numberOfLabels);
262 
263  iter.GoToBegin();
264  while (!iter.IsAtEnd())
265  {
266  while (!iter.IsAtEndOfSlice())
267  {
268  while (!iter.IsAtEndOfLine())
269  {
270  index = iter.GetIndex();
271  x = index[0];
272  y = index[1];
273  z = index[2];
274 
275  int value = static_cast<unsigned int>(iter.Get());
276  ++m_LabelCountInSlice[timeStep][0][x][value];
277  ++m_LabelCountInSlice[timeStep][1][y][value];
278  ++numberOfPixels[value];
279 
280  ++iter;
281  }
282  iter.NextLine();
283  }
284 
285  for (unsigned int label = 0; label < numberOfLabels; ++label)
286  m_LabelCountInSlice[timeStep][2][z][label] += numberOfPixels[label];
287 
288  // clear label counter
289  numberOfPixels.assign(numberOfLabels, 0);
290  iter.NextSlice();
291  }
292 }
293 
295  unsigned int sliceIndex,
296  const mitk::PlaneGeometry *currentPlane,
297  unsigned int timeStep)
298 {
299  if (m_WorkingImage.IsNull())
300  return NULL;
301  if (!currentPlane)
302  return NULL;
303  if (timeStep >= m_LabelCountInSlice.size())
304  return NULL;
305  if (sliceDimension > 2)
306  return NULL;
307  int upperLimit = m_LabelCountInSlice[timeStep][sliceDimension].size();
308  if (sliceIndex >= upperLimit - 1)
309  return NULL; // can't interpolate first and last slice
310  if (sliceIndex < 1)
311  return NULL;
312 
313  int pixelValue = m_WorkingImage->GetActiveLabel()->GetValue();
314 
315  // slice contains a segmentation, won't interpolate anything then
316  if (m_LabelCountInSlice[timeStep][sliceDimension][sliceIndex][pixelValue] > 0)
317  return NULL;
318 
319  int lowerBound(0);
320  int upperBound(0);
321  bool bounds(false);
322 
323  for (lowerBound = sliceIndex - 1; /*lowerBound >= 0*/; --lowerBound)
324  {
325  if (m_LabelCountInSlice[timeStep][sliceDimension][lowerBound][pixelValue] > 0)
326  {
327  bounds = true;
328  break;
329  }
330 
331  if (lowerBound == 0)
332  break;
333  }
334 
335  if (!bounds)
336  return NULL;
337 
338  bounds = false;
339  for (upperBound = sliceIndex + 1; upperBound < upperLimit; ++upperBound)
340  {
341  if (m_LabelCountInSlice[timeStep][sliceDimension][upperBound][pixelValue] > 0)
342  {
343  bounds = true;
344  break;
345  }
346  }
347 
348  if (!bounds)
349  return NULL;
350 
351  // ok, we have found two neighboring slices with the active label
352  // (and we made sure that the current slice does NOT contain the active label
353  // Setting up the ExtractSliceFilter
355  extractor->SetInput(m_WorkingImage);
356  extractor->SetTimeStep(timeStep);
357  extractor->SetResliceTransformByGeometry(m_WorkingImage->GetTimeGeometry()->GetGeometryForTimeStep(timeStep));
358  extractor->SetVtkOutputRequest(false);
359 
360  // Reslicing the current plane
361  extractor->SetWorldGeometry(currentPlane);
362  extractor->Modified();
363 
364  try
365  {
366  extractor->Update();
367  }
368  catch (const std::exception &e)
369  {
370  MITK_ERROR << "Error in 2D interpolation: " << e.what();
371  return NULL;
372  }
373 
374  mitk::Image::Pointer resultImage = extractor->GetOutput();
375  resultImage->DisconnectPipeline();
376 
377  // Creating PlaneGeometry for lower slice
378  mitk::PlaneGeometry::Pointer reslicePlane = currentPlane->Clone();
379 
380  // Transforming the current origin so that it matches the lower slice
381  mitk::Point3D origin = currentPlane->GetOrigin();
382  m_WorkingImage->GetSlicedGeometry()->WorldToIndex(origin, origin);
383  origin[sliceDimension] = lowerBound;
384  m_WorkingImage->GetSlicedGeometry()->IndexToWorld(origin, origin);
385  reslicePlane->SetOrigin(origin);
386 
387  // Extract the lower slice
388  extractor->SetWorldGeometry(reslicePlane);
389  extractor->Modified();
390 
391  try
392  {
393  extractor->Update();
394  }
395  catch (const std::exception &e)
396  {
397  MITK_ERROR << "Error in 2D interpolation: " << e.what();
398  return NULL;
399  }
400 
401  mitk::Image::Pointer lowerMITKSlice = extractor->GetOutput();
402  lowerMITKSlice->DisconnectPipeline();
403 
404  // Transforming the current origin so that it matches the upper slice
405  m_WorkingImage->GetSlicedGeometry()->WorldToIndex(origin, origin);
406  origin[sliceDimension] = upperBound;
407  m_WorkingImage->GetSlicedGeometry()->IndexToWorld(origin, origin);
408  reslicePlane->SetOrigin(origin);
409 
410  // Extract the upper slice
411  extractor->SetWorldGeometry(reslicePlane);
412  extractor->Modified();
413 
414  try
415  {
416  extractor->Update();
417  }
418  catch (const std::exception &e)
419  {
420  MITK_ERROR << "Error in 2D interpolation: " << e.what();
421  return NULL;
422  }
423 
424  mitk::Image::Pointer upperMITKSlice = extractor->GetOutput();
425  upperMITKSlice->DisconnectPipeline();
426 
427  if (lowerMITKSlice.IsNull() || upperMITKSlice.IsNull())
428  return NULL;
429 
430  // interpolation algorithm gets some inputs
431  // two segmentations (guaranteed to be of the same data type, but no special data type guaranteed)
432  // orientation (sliceDimension) of the segmentations
433  // position of the two slices (sliceIndices)
434  // one volume image (original patient image)
435  //
436  // interpolation algorithm can use e.g. itk::ImageSliceConstIteratorWithIndex to
437  // inspect the original patient image at appropriate positions
438 
441 
442  algorithm->Interpolate(
443  lowerMITKSlice.GetPointer(), lowerBound, upperMITKSlice.GetPointer(), upperBound, sliceIndex, 0, resultImage);
444 
445  return resultImage;
446 }
const Point3D GetOrigin() const
Get the origin, e.g. the upper-left corner of the plane.
void ResetLabelCount()
Initializes the internal container with the number of voxels per label.
void SetWorkingImage(LabelSetImage *image)
Initialize with a whole volume.
itk::SmartPointer< Self > Pointer
Image::Pointer Interpolate(unsigned int sliceDimension, unsigned int sliceIndex, const mitk::PlaneGeometry *currentPlane, unsigned int timeStep)
Update after changing the whole working image.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
static SliceBasedInterpolationController * InterpolatorForImage(const Image *)
Find interpolator for a given image.
void SetChangedSlice(const Image *image, unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep)
Update after changing a single slice in the working image.
static Pointer New()
Pointer Clone() const
std::map< const Image *, SliceBasedInterpolationController * > InterpolatorMapType
map::core::discrete::Elements< 3 >::InternalImageType ImageType
#define MITK_WARN
Definition: mitkLogMacros.h:23
Image class for storing images.
Definition: mitkImage.h:76
void ScanImageITKProcessing(itk::Image< TPixel, VImageDimension > *, unsigned int timeStep)
internal scan of the whole image
void ScanSliceITKProcessing(const itk::Image< PixelType, 2 > *, const SetChangedSliceOptions &options)
internal scan of a single slice
#define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1)
LabelSetImage class for handling labels and layers in a segmentation session.
Describes a two-dimensional, rectangular plane.
unsigned int GetDimension() const
Get dimension of the image.
Definition: mitkImage.cpp:110
void SetReferenceImage(Image *image)
Set a reference image (original patient image) - optional.
Protected class of mitk::SliceBasedInterpolationController. Don't use (you shouldn't be able to do so...