Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkImageLiveWireContourModelFilter.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 <itkCastImageFilter.h>
20 #include <itkGradientMagnitudeImageFilter.h>
21 #include <itkImageRegionIterator.h>
22 
23 #include "mitkIOUtil.h"
24 
26 {
27  OutputType::Pointer output = dynamic_cast<OutputType *>(this->MakeOutput(0).GetPointer());
28  this->SetNumberOfRequiredInputs(1);
29  this->SetNumberOfIndexedOutputs(1);
30  this->SetNthOutput(0, output.GetPointer());
33  m_ShortestPathFilter->SetCostFunction(m_CostFunction);
34  m_UseDynamicCostMap = false;
35  m_TimeStep = 0;
36 }
37 
39 {
40 }
41 
43 {
44  return Superclass::GetOutput();
45 }
46 
48 {
49  this->SetInput(0, input);
50 }
51 
54 {
55  if (idx + 1 > this->GetNumberOfInputs())
56  {
57  this->SetNumberOfRequiredInputs(idx + 1);
58  }
59  if (input != static_cast<InputType *>(this->ProcessObject::GetInput(idx)))
60  {
61  this->ProcessObject::SetNthInput(idx, const_cast<InputType *>(input));
62  this->Modified();
63 
64  AccessFixedDimensionByItk(input, ItkPreProcessImage, 2);
65  }
66 }
67 
69 {
70  if (this->GetNumberOfInputs() < 1)
71  return NULL;
72  return static_cast<const mitk::ImageLiveWireContourModelFilter::InputType *>(this->ProcessObject::GetInput(0));
73 }
74 
76  unsigned int idx)
77 {
78  if (this->GetNumberOfInputs() < 1)
79  return NULL;
80  return static_cast<const mitk::ImageLiveWireContourModelFilter::InputType *>(this->ProcessObject::GetInput(idx));
81 }
82 
84 {
85  mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput());
86 
87  if (!input)
88  {
89  MITK_ERROR << "No input available.";
90  itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!");
91  return;
92  }
93 
94  if (input->GetDimension() != 2)
95  {
96  MITK_ERROR << "Filter is only working on 2D images.";
97  itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that "
98  "the input is 2D!");
99  return;
100  }
101 
102  input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex);
103  input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex);
104 
105  // only start calculating if both indices are inside image geometry
106  if (input->GetGeometry()->IsIndexInside(this->m_StartPointInIndex) &&
107  input->GetGeometry()->IsIndexInside(this->m_EndPointInIndex))
108  {
109  try
110  {
111  this->UpdateLiveWire();
112  }
113  catch (itk::ExceptionObject &e)
114  {
115  MITK_INFO << "Exception caught during live wiring calculation: " << e;
116  return;
117  }
118  }
119 }
120 
121 template <typename TPixel, unsigned int VImageDimension>
122 void mitk::ImageLiveWireContourModelFilter::ItkPreProcessImage(const itk::Image<TPixel, VImageDimension> *inputImage)
123 {
124  typedef itk::Image<TPixel, VImageDimension> InputImageType;
125  typedef itk::CastImageFilter<InputImageType, InternalImageType> CastFilterType;
126 
127  typename CastFilterType::Pointer castFilter = CastFilterType::New();
128  castFilter->SetInput(inputImage);
129  castFilter->Update();
130  m_InternalImage = castFilter->GetOutput();
131  m_CostFunction->SetImage(m_InternalImage);
132  m_ShortestPathFilter->SetInput(m_InternalImage);
133 }
134 
136 {
137  m_CostFunction->ClearRepulsivePoints();
138 }
139 
141 {
142  m_CostFunction->AddRepulsivePoint(idx);
143 }
144 
146 {
148  mask->InitializeByItk(this->m_CostFunction->GetMaskImage());
149  mask->SetVolume(this->m_CostFunction->GetMaskImage()->GetBufferPointer());
150  mitk::IOUtil::Save(mask, "G:\\Data\\mask.nrrd");
151 }
152 
154 {
155  m_CostFunction->RemoveRepulsivePoint(idx);
156 }
157 
159 {
160  m_CostFunction->ClearRepulsivePoints();
161 
162  ShortestPathType::const_iterator iter = points.begin();
163  for (; iter != points.end(); iter++)
164  {
165  m_CostFunction->AddRepulsivePoint((*iter));
166  }
167 }
168 
170 {
171  // compute the requested region for itk filters
172  InternalImageType::IndexType startPoint, endPoint;
173 
174  startPoint[0] = m_StartPointInIndex[0];
175  startPoint[1] = m_StartPointInIndex[1];
176 
177  endPoint[0] = m_EndPointInIndex[0];
178  endPoint[1] = m_EndPointInIndex[1];
179 
180  // minimum value in each direction for startRegion
181  InternalImageType::IndexType startRegion;
182  startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0];
183  startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1];
184 
185  // maximum value in each direction for size
186  InternalImageType::SizeType size;
187  size[0] = abs(startPoint[0] - endPoint[0]) + 1;
188  size[1] = abs(startPoint[1] - endPoint[1]) + 1;
189 
191  region.SetSize(size);
192  region.SetIndex(startRegion);
193 
194  // inputImage->SetRequestedRegion(region);
195 
196  // extracts features from image and calculates costs
197  // m_CostFunction->SetImage(m_InternalImage);
198  m_CostFunction->SetStartIndex(startPoint);
199  m_CostFunction->SetEndIndex(endPoint);
200  m_CostFunction->SetRequestedRegion(region);
201  m_CostFunction->SetUseCostMap(m_UseDynamicCostMap);
202 
203  // calculate shortest path between start and end point
204  m_ShortestPathFilter->SetFullNeighborsMode(true);
205  // m_ShortestPathFilter->SetInput( m_CostFunction->SetImage(m_InternalImage) );
206  m_ShortestPathFilter->SetMakeOutputImage(false);
207 
208  // m_ShortestPathFilter->SetCalcAllDistances(true);
209  m_ShortestPathFilter->SetStartIndex(startPoint);
210  m_ShortestPathFilter->SetEndIndex(endPoint);
211 
212  m_ShortestPathFilter->Update();
213 
214  // construct contour from path image
215  // get the shortest path as vector
216  ShortestPathType shortestPath = m_ShortestPathFilter->GetVectorPath();
217 
218  // fill the output contour with control points from the path
219  OutputType::Pointer output = dynamic_cast<OutputType *>(this->MakeOutput(0).GetPointer());
220  this->SetNthOutput(0, output.GetPointer());
221 
222  // OutputType::Pointer output = dynamic_cast<OutputType*> ( this->GetOutput() );
223  output->Expand(m_TimeStep + 1);
224 
225  // output->Clear();
226 
227  mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput());
228 
229  ShortestPathType::const_iterator pathIterator = shortestPath.begin();
230 
231  while (pathIterator != shortestPath.end())
232  {
233  mitk::Point3D currentPoint;
234  currentPoint[0] = static_cast<mitk::ScalarType>((*pathIterator)[0]);
235  currentPoint[1] = static_cast<mitk::ScalarType>((*pathIterator)[1]);
236  currentPoint[2] = 0.0;
237 
238  input->GetGeometry()->IndexToWorld(currentPoint, currentPoint);
239  output->AddVertex(currentPoint, false, m_TimeStep);
240 
241  pathIterator++;
242  }
243 }
244 
246 {
247  mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput());
248  if (!input)
249  return false;
250 
251  try
252  {
253  AccessFixedDimensionByItk_1(input, CreateDynamicCostMapByITK, 2, path);
254  }
255  catch (itk::ExceptionObject &e)
256  {
257  MITK_INFO << "Exception caught during dynamic cost map alculation: " << e;
258  return false;
259  }
260 
261  return true;
262 }
263 
264 template <typename TPixel, unsigned int VImageDimension>
266  const itk::Image<TPixel, VImageDimension> *inputImage, mitk::ContourModel *path)
267 {
268  /*++++++++++ create dynamic cost transfer map ++++++++++*/
269 
270  /* Compute the costs of the gradient magnitude dynamically.
271  * using a map of the histogram of gradient magnitude image.
272  * Use the histogram gradient map to interpolate the costs
273  * with gaussing function including next two bins right and left
274  * to current position x. With the histogram gradient costs are interpolated
275  * with a gaussing function summation of next two bins right and left
276  * to current position x.
277  */
278  std::vector<itk::Index<VImageDimension>> shortestPath;
279 
280  mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput());
281  if (path == NULL)
282  {
283  OutputType::Pointer output = this->GetOutput();
284  mitk::ContourModel::VertexIterator it = output->IteratorBegin();
285  while (it != output->IteratorEnd())
286  {
288  mitk::Point3D c = (*it)->Coordinates;
289  input->GetGeometry()->WorldToIndex(c, c);
290  cur[0] = c[0];
291  cur[1] = c[1];
292 
293  shortestPath.push_back(cur);
294  it++;
295  }
296  }
297  else
298  {
300  while (it != path->IteratorEnd())
301  {
303  mitk::Point3D c = (*it)->Coordinates;
304  input->GetGeometry()->WorldToIndex(c, c);
305  cur[0] = c[0];
306  cur[1] = c[1];
307 
308  shortestPath.push_back(cur);
309  it++;
310  }
311  }
312 
313  // filter image gradient magnitude
314  typedef itk::GradientMagnitudeImageFilter<itk::Image<TPixel, VImageDimension>, itk::Image<TPixel, VImageDimension>>
315  GradientMagnitudeFilterType;
317  gradientFilter->SetInput(inputImage);
318  gradientFilter->Update();
319  typename itk::Image<TPixel, VImageDimension>::Pointer gradientMagnImage = gradientFilter->GetOutput();
320 
321  // get the path
322 
323  // iterator of path
324  typename std::vector<itk::Index<VImageDimension>>::iterator pathIterator = shortestPath.begin();
325 
326  std::map<int, int> histogram;
327 
328  // create histogram within path
329  while (pathIterator != shortestPath.end())
330  {
331  // count pixel values
332  // use scale factor to avoid mapping gradients between 0.0 and 1.0 to same bin
333  histogram[static_cast<int>(gradientMagnImage->GetPixel((*pathIterator)) *
335 
336  pathIterator++;
337  }
338 
339  double max = 1.0;
340 
341  if (!histogram.empty())
342  {
343  std::map<int, int>::iterator itMAX;
344 
345  // get max of histogramm
346  int currentMaxValue = 0;
347  std::map<int, int>::iterator it = histogram.begin();
348  while (it != histogram.end())
349  {
350  if ((*it).second > currentMaxValue)
351  {
352  itMAX = it;
353  currentMaxValue = (*it).second;
354  }
355  it++;
356  }
357 
358  std::map<int, int>::key_type keyOfMax = itMAX->first;
359 
360  // compute the to max of gaussian summation
361  std::map<int, int>::iterator end = histogram.end();
362  std::map<int, int>::iterator last = --(histogram.end());
363 
364  std::map<int, int>::iterator left2;
365  std::map<int, int>::iterator left1;
366  std::map<int, int>::iterator right1;
367  std::map<int, int>::iterator right2;
368 
369  right1 = itMAX;
370 
371  if (right1 == end || right1 == last)
372  {
373  right2 = end;
374  }
375  else //( right1 <= last )
376  {
377  std::map<int, int>::iterator temp = right1;
378  right2 = ++right1; // rght1 + 1
379  right1 = temp;
380  }
381 
382  if (right1 == histogram.begin())
383  {
384  left1 = end;
385  left2 = end;
386  }
387  else if (right1 == (++(histogram.begin())))
388  {
389  std::map<int, int>::iterator temp = right1;
390  left1 = --right1; // rght1 - 1
391  right1 = temp;
392  left2 = end;
393  }
394  else
395  {
396  std::map<int, int>::iterator temp = right1;
397  left1 = --right1; // rght1 - 1
398  left2 = --right1; // rght1 - 2
399  right1 = temp;
400  }
401 
402  double partRight1, partRight2, partLeft1, partLeft2;
403  partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0;
404 
405  /*
406  f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 )
407 
408  gaussian approximation
409 
410  where
411  v(bin) is the value in the map
412  k(bin) is the key
413  */
414 
415  if (left2 != end)
416  {
417  partLeft2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left2->first, left2->second);
418  }
419 
420  if (left1 != end)
421  {
422  partLeft1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left1->first, left1->second);
423  }
424 
425  if (right1 != end)
426  {
427  partRight1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right1->first, right1->second);
428  }
429 
430  if (right2 != end)
431  {
432  partRight2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right2->first, right2->second);
433  }
434 
435  max = (partRight1 + partRight2 + partLeft1 + partLeft2);
436  }
437 
438  this->m_CostFunction->SetDynamicCostMap(histogram);
439  this->m_CostFunction->SetCostMapMaximum(max);
440 }
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are store...
itk::SmartPointer< Self > Pointer
#define MITK_INFO
Definition: mitkLogMacros.h:22
void ClearRepulsivePoints()
Clear all repulsive points used in the cost function.
#define AccessFixedDimensionByItk(mitkImage, itkImageTypeFunction, dimension)
Access a mitk-image with known dimension by an itk-image.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
double ScalarType
CostFunctionType::Pointer m_CostFunction
The cost function to compute costs between two pixels.
void CreateDynamicCostMapByITK(const itk::Image< TPixel, VImageDimension > *inputImage, mitk::ContourModel *path=NULL)
mitk::ContourElement::VertexIterator VertexIterator
void AddRepulsivePoint(const itk::Index< 2 > &idx)
Add a single repulsive point to the cost function.
void SetRepulsivePoints(const ShortestPathType &points)
Set a vector with repulsive points to use in the cost function.
VertexIterator IteratorBegin(int timestep=0) const
Returns a const VertexIterator at the start element of the contour.
static double Gaussian(double x, double xOfGaussian, double yOfGaussian)
Returns the y value of gaussian with given offset and amplitude.
bool CreateDynamicCostMap(mitk::ContourModel *path=NULL)
Create dynamic cost tranfer map - on the fly training.
virtual mitkBaseDataSourceGetOutputDeclarations itk::DataObject::Pointer MakeOutput(DataObjectPointerArraySizeType idx) override
itk::Image< double, 3 > InputImageType
ShortestPathImageFilterType::Pointer m_ShortestPathFilter
Shortest path filter according to cost function m_CostFunction.
Image class for storing images.
Definition: mitkImage.h:76
static T max(T x, T y)
Definition: svm.cpp:70
static Pointer New()
bool m_UseDynamicCostMap
Flag to use a dynmic cost map or not.
#define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1)
void ItkPreProcessImage(const itk::Image< TPixel, VImageDimension > *inputImage)
VertexIterator IteratorEnd(int timestep=0) const
Returns a const VertexIterator at the end element of the contour.
void RemoveRepulsivePoint(const itk::Index< 2 > &idx)
Remove a single repulsive point from the cost function.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.