Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkCorrectorAlgorithm.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 (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 #include "mitkCorrectorAlgorithm.h"
14 #include "mitkContourUtils.h"
15 #include "mitkITKImageImport.h"
16 #include "mitkImageAccessByItk.h"
17 #include "mitkImageCast.h"
18 #include "mitkImageDataItem.h"
19 
20 #include <mitkContourModelUtils.h>
21 
22 #include "itkCastImageFilter.h"
23 #include "itkImageDuplicator.h"
24 #include "itkImageRegionIterator.h"
25 
27 {
28 }
29 
31 {
32 }
33 
34 template <typename TPixel, unsigned int VDimensions>
36  itk::Image<TPixel, VDimensions> *,
37  mitk::Image::Pointer target,
38  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer segmentationPixelTypeImage)
39 {
40  typedef itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2> InputImageType;
41  typedef itk::Image<TPixel, 2> OutputImageType;
42  typedef itk::CastImageFilter<InputImageType, OutputImageType> CastImageFilterType;
43 
44  typename CastImageFilterType::Pointer castImageFilter = CastImageFilterType::New();
45  castImageFilter->SetInput(segmentationPixelTypeImage);
46  castImageFilter->Update();
47  typename OutputImageType::Pointer tempItkImage = castImageFilter->GetOutput();
48  tempItkImage->DisconnectPipeline();
49  mitk::CastToMitkImage(tempItkImage, target);
50 }
51 
53 {
55 
56  if (inputImage.IsNull() || inputImage->GetDimension() != 2)
57  {
58  itkExceptionMacro("CorrectorAlgorithm needs a 2D image as input.");
59  }
60 
61  if (m_Contour.IsNull())
62  {
63  itkExceptionMacro("CorrectorAlgorithm needs a Contour object as input.");
64  }
65 
66  // copy the input (since m_WorkingImage will be changed later)
67  m_WorkingImage = inputImage;
68 
69  TimeGeometry::Pointer originalGeometry = nullptr;
70 
71  if (inputImage->GetTimeGeometry())
72  {
73  originalGeometry = inputImage->GetTimeGeometry()->Clone();
74  m_WorkingImage->SetTimeGeometry(originalGeometry);
75  }
76  else
77  {
78  itkExceptionMacro("Original image does not have a 'Time sliced geometry'! Cannot copy.");
79  }
80 
81  Image::Pointer temporarySlice;
82 
83  // Convert to DefaultSegmentationDataType (because TobiasHeimannCorrectionAlgorithm relys on that data type)
84  {
85  itk::Image<DefaultSegmentationDataType, 2>::Pointer correctPixelTypeImage;
86  CastToItkImage(m_WorkingImage, correctPixelTypeImage);
87  assert(correctPixelTypeImage.IsNotNull());
88 
89  // possible bug in CastToItkImage ?
90  // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in
91  // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479:
92  // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0
93  // && aSpacing[2]>0' failed
94  // solution here: we overwrite it with an unity matrix
95  itk::Image<DefaultSegmentationDataType, 2>::DirectionType imageDirection;
96 
97  imageDirection.SetIdentity();
98  // correctPixelTypeImage->SetDirection(imageDirection);
99 
100  temporarySlice = this->GetOutput();
101  // temporarySlice = ImportItkImage( correctPixelTypeImage );
102  // m_FillColor = 1;
103  m_EraseColor = 0;
104 
105  ImprovedHeimannCorrectionAlgorithm(correctPixelTypeImage);
106 
107  // this is suboptimal, needs to be kept synchronous to DefaultSegmentationDataType
108  if (inputImage->GetChannelDescriptor().GetPixelType().GetComponentType() == itk::ImageIOBase::USHORT)
109  { // the cast at the beginning did not copy the data
110  CastToMitkImage(correctPixelTypeImage, temporarySlice);
111  }
112  else
113  { // it did copy the data and cast the pixel type
114  AccessByItk_n(m_WorkingImage, ConvertBackToCorrectPixelType, (temporarySlice, correctPixelTypeImage));
115  }
116  }
117  temporarySlice->SetTimeGeometry(originalGeometry);
118 }
119 
120 template <typename ScalarType>
121 itk::Index<2> mitk::CorrectorAlgorithm::ensureIndexInImage(ScalarType i0, ScalarType i1)
122 {
123  itk::Index<2> toReturn;
124 
125  itk::Size<5> size = m_WorkingImage->GetLargestPossibleRegion().GetSize();
126 
127  toReturn[0] = std::min((ScalarType)(size[0] - 1), std::max((ScalarType)0.0, i0));
128  toReturn[1] = std::min((ScalarType)(size[1] - 1), std::max((ScalarType)0.0, i1));
129 
130  return toReturn;
131 }
132 
134  itk::Image<DefaultSegmentationDataType, 2>::Pointer pic)
135 {
162  ContourModel::Pointer projectedContour =
164 
165  if (projectedContour.IsNull() || projectedContour->GetNumberOfVertices() < 2)
166  return false;
167 
168  // Read the first point of the contour
169  auto contourIter = projectedContour->Begin();
170  if (contourIter == projectedContour->End())
171  return false;
172  itk::Index<2> previousIndex;
173 
174  previousIndex = ensureIndexInImage((*contourIter)->Coordinates[0], (*contourIter)->Coordinates[1]);
175  ++contourIter;
176 
177  int currentColor = (pic->GetPixel(previousIndex) == m_FillColor);
178  TSegData currentSegment;
179  int countOfSegments = 1;
180 
181  bool firstSegment = true;
182  auto contourEnd = projectedContour->End();
183  for (; contourIter != contourEnd; ++contourIter)
184  {
185  // Get current point
186  itk::Index<2> currentIndex;
187  currentIndex = ensureIndexInImage((*contourIter)->Coordinates[0] + 0.5, (*contourIter)->Coordinates[1] + 0.5);
188 
189  // Calculate length and slope
190  double slopeX = currentIndex[0] - previousIndex[0];
191  double slopeY = currentIndex[1] - previousIndex[1];
192  double length = std::sqrt(slopeX * slopeX + slopeY * slopeY);
193  double deltaX = slopeX / length;
194  double deltaY = slopeY / length;
195 
196  for (double i = 0; i <= length && length > 0; i += 1)
197  {
198  itk::Index<2> temporaryIndex;
199  temporaryIndex = ensureIndexInImage(previousIndex[0] + deltaX * i, previousIndex[1] + deltaY * i);
200 
201  if (!pic->GetLargestPossibleRegion().IsInside(temporaryIndex))
202  continue;
203  if ((pic->GetPixel(temporaryIndex) == m_FillColor) != currentColor)
204  {
205  currentSegment.points.push_back(temporaryIndex);
206  if (!firstSegment)
207  {
208  ModifySegment(currentSegment, pic);
209  }
210  else
211  {
212  firstSegment = false;
213  }
214  currentSegment = TSegData();
215  ++countOfSegments;
216  currentColor = (pic->GetPixel(temporaryIndex) == m_FillColor);
217  }
218  currentSegment.points.push_back(temporaryIndex);
219  }
220  previousIndex = currentIndex;
221  }
222 
223  return true;
224 }
225 
226 void mitk::CorrectorAlgorithm::ColorSegment(
227  const mitk::CorrectorAlgorithm::TSegData &segment,
228  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer pic)
229 {
230  int colorMode = (pic->GetPixel(segment.points[0]) == m_FillColor);
231  int color = 0;
232  if (colorMode)
233  color = m_EraseColor;
234  else
235  color = m_FillColor;
236 
237  std::vector<itk::Index<2>>::const_iterator indexIterator;
238  std::vector<itk::Index<2>>::const_iterator indexEnd;
239 
240  indexIterator = segment.points.begin();
241  indexEnd = segment.points.end();
242 
243  for (; indexIterator != indexEnd; ++indexIterator)
244  {
245  pic->SetPixel(*indexIterator, color);
246  }
247 }
248 
249 itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer mitk::CorrectorAlgorithm::CloneImage(
250  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer pic)
251 {
252  typedef itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2> ItkImageType;
253  typedef itk::ImageDuplicator<ItkImageType> DuplicatorType;
254  DuplicatorType::Pointer duplicator = DuplicatorType::New();
255  duplicator->SetInputImage(pic);
256  duplicator->Update();
257 
258  return duplicator->GetOutput();
259 }
260 
261 itk::Index<2> mitk::CorrectorAlgorithm::GetFirstPoint(
262  const mitk::CorrectorAlgorithm::TSegData &segment,
263  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer pic)
264 {
265  int colorMode = (pic->GetPixel(segment.points[0]) == m_FillColor);
266 
267  std::vector<itk::Index<2>>::const_iterator indexIterator;
268  std::vector<itk::Index<2>>::const_iterator indexEnd;
269 
270  indexIterator = segment.points.begin();
271  indexEnd = segment.points.end();
272 
273  itk::Index<2> index;
274 
275  for (; indexIterator != indexEnd; ++indexIterator)
276  {
277  for (int xOffset = -1; xOffset < 2; ++xOffset)
278  {
279  for (int yOffset = -1; yOffset < 2; ++yOffset)
280  {
281  index = ensureIndexInImage((*indexIterator)[0] - xOffset, (*indexIterator)[1] - yOffset);
282 
283  if ((pic->GetPixel(index) == m_FillColor) != colorMode)
284  {
285  return index;
286  }
287  }
288  }
289  }
290  mitkThrow() << "No Starting point is found next to the curve.";
291 }
292 
293 std::vector<itk::Index<2>> mitk::CorrectorAlgorithm::FindSeedPoints(
294  const mitk::CorrectorAlgorithm::TSegData &segment,
295  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer pic)
296 {
297  typedef itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer ItkImagePointerType;
298 
299  std::vector<itk::Index<2>> seedPoints;
300 
301  try
302  {
303  itk::Index<2> firstPoint = GetFirstPoint(segment, pic);
304  seedPoints.push_back(firstPoint);
305  }
306  catch (const mitk::Exception&)
307  {
308  return seedPoints;
309  }
310 
311  if (segment.points.size() < 4)
312  return seedPoints;
313 
314  std::vector<itk::Index<2>>::const_iterator indexIterator;
315  std::vector<itk::Index<2>>::const_iterator indexEnd;
316 
317  indexIterator = segment.points.begin();
318  indexEnd = segment.points.end();
319 
320  ItkImagePointerType listOfPoints = CloneImage(pic);
321  listOfPoints->FillBuffer(0);
322  listOfPoints->SetPixel(seedPoints[0], 1);
323  for (; indexIterator != indexEnd; ++indexIterator)
324  {
325  listOfPoints->SetPixel(*indexIterator, 2);
326  }
327  indexIterator = segment.points.begin();
328  indexIterator++;
329  indexIterator++;
330  indexEnd--;
331  indexEnd--;
332  for (; indexIterator != indexEnd; ++indexIterator)
333  {
334  bool pointFound = true;
335  while (pointFound)
336  {
337  pointFound = false;
338  itk::Index<2> index;
339  itk::Index<2> index2;
340  for (int xOffset = -1; xOffset < 2; ++xOffset)
341  {
342  for (int yOffset = -1; yOffset < 2; ++yOffset)
343  {
344  index = ensureIndexInImage((*indexIterator)[0] - xOffset, (*indexIterator)[1] - yOffset);
345  index2 = index;
346 
347  if (listOfPoints->GetPixel(index2) > 0)
348  continue;
349 
350  index[0] = index[0] - 1;
351  index = ensureIndexInImage(index[0], index[1]);
352  if (listOfPoints->GetPixel(index) == 1)
353  {
354  pointFound = true;
355  seedPoints.push_back(index2);
356  listOfPoints->SetPixel(index2, 1);
357  continue;
358  }
359 
360  index[0] = index[0] + 2;
361  index = ensureIndexInImage(index[0], index[1]);
362  if (listOfPoints->GetPixel(index) == 1)
363  {
364  pointFound = true;
365  seedPoints.push_back(index2);
366  listOfPoints->SetPixel(index2, 1);
367  continue;
368  }
369 
370  index[0] = index[0] - 1;
371  index[1] = index[1] - 1;
372  index = ensureIndexInImage(index[0], index[1]);
373  if (listOfPoints->GetPixel(index) == 1)
374  {
375  pointFound = true;
376  seedPoints.push_back(index2);
377  listOfPoints->SetPixel(index2, 1);
378  continue;
379  }
380 
381  index[1] = index[1] + 2;
382  index = ensureIndexInImage(index[0], index[1]);
383  if (listOfPoints->GetPixel(index) == 1)
384  {
385  pointFound = true;
386  seedPoints.push_back(index2);
387  listOfPoints->SetPixel(index2, 1);
388  continue;
389  }
390  }
391  }
392  }
393  }
394  return seedPoints;
395 }
396 
397 int mitk::CorrectorAlgorithm::FillRegion(
398  const std::vector<itk::Index<2>> &seedPoints,
399  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer pic)
400 {
401  int numberOfPixel = 0;
402  int mode = (pic->GetPixel(seedPoints[0]) == m_FillColor);
403  int drawColor = m_FillColor;
404  if (mode)
405  {
406  drawColor = m_EraseColor;
407  }
408 
409  std::vector<itk::Index<2>> workPoints;
410  workPoints = seedPoints;
411  // workPoints.push_back(seedPoints[0]);
412  while (workPoints.size() > 0)
413  {
414  itk::Index<2> currentIndex = workPoints.back();
415  workPoints.pop_back();
416  if ((pic->GetPixel(currentIndex) == m_FillColor) == mode)
417  ++numberOfPixel;
418  pic->SetPixel(currentIndex, drawColor);
419 
420  currentIndex = ensureIndexInImage(currentIndex[0] - 1, currentIndex[1]);
421  if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode)
422  workPoints.push_back(currentIndex);
423 
424  currentIndex = ensureIndexInImage(currentIndex[0] + 2, currentIndex[1]);
425  if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode)
426  workPoints.push_back(currentIndex);
427 
428  currentIndex = ensureIndexInImage(currentIndex[0] - 1, currentIndex[1] - 1);
429 
430  if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode)
431  workPoints.push_back(currentIndex);
432 
433  currentIndex = ensureIndexInImage(currentIndex[0], currentIndex[1] + 2);
434  if (pic->GetLargestPossibleRegion().IsInside(currentIndex) && (pic->GetPixel(currentIndex) == m_FillColor) == mode)
435  workPoints.push_back(currentIndex);
436  }
437 
438  return numberOfPixel;
439 }
440 
441 void mitk::CorrectorAlgorithm::OverwriteImage(
442  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer source,
443  itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2>::Pointer target)
444 {
445  typedef itk::Image<mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2> ItkImageType;
446  typedef itk::ImageRegionIterator<ItkImageType> ImageIteratorType;
447 
448  ImageIteratorType sourceIter(source, source->GetLargestPossibleRegion());
449  ImageIteratorType targetIter(target, target->GetLargestPossibleRegion());
450  while (!sourceIter.IsAtEnd())
451  {
452  targetIter.Set(sourceIter.Get());
453  ++sourceIter;
454  ++targetIter;
455  }
456 }
457 
459  itk::Image<DefaultSegmentationDataType, 2>::Pointer pic)
460 {
461  typedef itk::Image<DefaultSegmentationDataType, 2>::Pointer ItkImagePointerType;
462 
463  ItkImagePointerType firstSideImage = CloneImage(pic);
464  ColorSegment(segment, firstSideImage);
465  ItkImagePointerType secondSideImage = CloneImage(firstSideImage);
466 
467  std::vector<itk::Index<2>> seedPoints = FindSeedPoints(segment, firstSideImage);
468  if (seedPoints.size() < 1)
469  return false;
470  int firstSidePixel = FillRegion(seedPoints, firstSideImage);
471 
472  std::vector<itk::Index<2>> secondSeedPoints = FindSeedPoints(segment, firstSideImage);
473  if (secondSeedPoints.size() < 1)
474  return false;
475  int secondSidePixel = FillRegion(secondSeedPoints, secondSideImage);
476 
477  if (firstSidePixel < secondSidePixel)
478  {
479  OverwriteImage(firstSideImage, pic);
480  }
481  else
482  {
483  OverwriteImage(secondSideImage, pic);
484  }
485  return true;
486 }
double ScalarType
void ConvertBackToCorrectPixelType(itk::Image< TPixel, VDimensions > *, mitk::Image::Pointer target, itk::Image< mitk::CorrectorAlgorithm::DefaultSegmentationDataType, 2 >::Pointer segmentationPixelTypeImage)
itk::SmartPointer< Self > Pointer
Definition: mitkImage.h:84
float yOffset
Definition: MitkMCxyz.cpp:622
#define AccessByItk_n(mitkImage, itkImageTypeFunction, va_tuple)
Access a MITK image by an ITK image with one or more parameters.
bool ModifySegment(const TSegData &segment, itk::Image< DefaultSegmentationDataType, 2 >::Pointer pic)
bool ImprovedHeimannCorrectionAlgorithm(itk::Image< DefaultSegmentationDataType, 2 >::Pointer pic)
ContourModel::Pointer m_Contour
An object of this class represents an exception of MITK. Please don&#39;t instantiate exceptions manually...
Definition: mitkException.h:45
Calculated difference image.
#define mitkThrow()
static ContourModel::Pointer ProjectContourTo2DSlice(Image *slice, ContourModel *contourIn3D, bool correctionForIpSegmentation, bool constrainToInside)
Projects a contour onto an image point by point. Converts from world to index coordinates.
mitk::Image OutputImageType
Some convenient typedefs.
static T max(T x, T y)
Definition: svm.cpp:56
Superclass of all classes having one or more Images as input and generating Images as output...
static T min(T x, T y)
Definition: svm.cpp:53
InputImageType * GetInput(void)
void CastToMitkImage(const itk::SmartPointer< ItkOutputImageType > &itkimage, itk::SmartPointer< mitk::Image > &mitkoutputimage)
Cast an itk::Image (with a specific type) to an mitk::Image.
Definition: mitkImageCast.h:74
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
std::vector< itk::Index< 2 > > points
OutputType * GetOutput()
Get the output data of this image source object.