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
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.