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