1 /*============================================================================
3 The Medical Imaging Interaction Toolkit (MITK)
5 Copyright (c) German Cancer Research Center (DKFZ)
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
11 ============================================================================*/
13 #ifndef __itkShortestPathCostFunctionLiveWire_txx
14 #define __itkShortestPathCostFunctionLiveWire_txx
16 #include "itkShortestPathCostFunctionLiveWire.h"
20 #include <itkCannyEdgeDetectionImageFilter.h>
21 #include <itkCastImageFilter.h>
22 #include <itkGradientImageFilter.h>
23 #include <itkGradientMagnitudeImageFilter.h>
24 #include <itkLaplacianImageFilter.h>
25 #include <itkStatisticsImageFilter.h>
26 #include <itkZeroCrossingImageFilter.h>
31 template <class TInputImageType>
32 ShortestPathCostFunctionLiveWire<TInputImageType>::ShortestPathCostFunctionLiveWire(): m_MinCosts(0.0), m_UseRepulsivePoints(false), m_GradientMax(0.0), m_Initialized(false), m_UseCostMap(false), m_MaxMapCosts(-1.0)
36 template <class TInputImageType>
37 void ShortestPathCostFunctionLiveWire<TInputImageType>::AddRepulsivePoint(const IndexType &index)
39 this->m_MaskImage->SetPixel(index, 255);
40 m_UseRepulsivePoints = true;
43 template <class TInputImageType>
44 void ShortestPathCostFunctionLiveWire<TInputImageType>::RemoveRepulsivePoint(const IndexType &index)
46 this->m_MaskImage->SetPixel(index, 0);
49 template <class TInputImageType>
50 void ShortestPathCostFunctionLiveWire<TInputImageType>::SetImage(const TInputImageType *_arg)
52 if (this->m_Image != _arg)
56 // initialize mask image
57 this->m_MaskImage = UnsignedCharImageType::New();
58 this->m_MaskImage->SetRegions(this->m_Image->GetLargestPossibleRegion());
59 this->m_MaskImage->SetOrigin(this->m_Image->GetOrigin());
60 this->m_MaskImage->SetSpacing(this->m_Image->GetSpacing());
61 this->m_MaskImage->SetDirection(this->m_Image->GetDirection());
62 this->m_MaskImage->Allocate();
63 this->m_MaskImage->FillBuffer(0);
66 this->m_Initialized = false;
70 template <class TInputImageType>
71 void ShortestPathCostFunctionLiveWire<TInputImageType>::ClearRepulsivePoints()
73 m_UseRepulsivePoints = false;
74 this->m_MaskImage->FillBuffer(0);
77 template <class TInputImageType>
78 double ShortestPathCostFunctionLiveWire<TInputImageType>::GetCost(IndexType p1, IndexType p2)
80 // local component costs
87 // if we are on the mask, return asap
88 if (m_UseRepulsivePoints)
90 if ((this->m_MaskImage->GetPixel(p1) != 0) || (this->m_MaskImage->GetPixel(p2) != 0))
94 double gradientX, gradientY;
95 gradientX = gradientY = 0.0;
99 double gradientMagnitude;
101 // Gradient Magnitude costs
102 gradientMagnitude = this->m_GradientMagnitudeImage->GetPixel(p2);
103 gradientX = m_GradientImage->GetPixel(p2)[0];
104 gradientY = m_GradientImage->GetPixel(p2)[1];
106 if (m_UseCostMap && !m_CostMap.empty())
108 std::map<int, int>::iterator end = m_CostMap.end();
109 std::map<int, int>::iterator last = --(m_CostMap.end());
112 std::map<int, int>::iterator x;
113 // std::map< int, int >::key_type keyOfX = static_cast<std::map< int, int >::key_type>(gradientMagnitude * 1000);
114 int keyOfX = static_cast<int>(gradientMagnitude /* ShortestPathCostFunctionLiveWire::MAPSCALEFACTOR*/);
115 x = m_CostMap.find(keyOfX);
117 std::map<int, int>::iterator left2;
118 std::map<int, int>::iterator left1;
119 std::map<int, int>::iterator right1;
120 std::map<int, int>::iterator right2;
123 { // x can also be == end if the key is not in the map but between two other keys
124 // search next key within map from x upwards
125 right1 = m_CostMap.lower_bound(keyOfX);
132 if (right1 == end || right1 == last)
136 else //( right1 != (end-1) )
139 right2 = ++right1; // rght1 + 1
143 if (right1 == m_CostMap.begin())
148 else if (right1 == (++(m_CostMap.begin())))
151 left1 = --right1; // rght1 - 1
158 left1 = --right1; // rght1 - 1
159 left2 = --right1; // rght1 - 2
163 double partRight1, partRight2, partLeft1, partLeft2;
164 partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0;
167 f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 )
169 gaussian approximation
172 v(bin) is the value in the map
178 partLeft2 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, left2->first, left2->second);
183 partLeft1 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, left1->first, left1->second);
188 partRight1 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, right1->first, right1->second);
193 partRight2 = ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(keyOfX, right2->first, right2->second);
196 if (m_MaxMapCosts > 0.0)
198 gradientCost = 1.0 - ((partRight1 + partRight2 + partLeft1 + partLeft2) / m_MaxMapCosts);
201 { // use linear mapping
202 gradientCost = 1.0 - (gradientMagnitude / m_GradientMax);
206 { // use linear mapping
207 // value between 0 (good) and 1 (bad)
208 gradientCost = 1.0 - (gradientMagnitude / m_GradientMax);
211 // Laplacian zero crossing costs
212 // f(p) = 0; if I(p)=0
214 double laplacianCost;
215 typename Superclass::PixelType laplaceImageValue;
217 laplaceImageValue = m_EdgeImage->GetPixel(p2);
219 if (laplaceImageValue < 0 || laplaceImageValue > 0)
228 // gradient vector at p1
229 double nGradientAtP1[2];
230 nGradientAtP1[0] = gradientX; // previously computed for gradient magnitude
231 nGradientAtP1[1] = gradientY;
233 // gradient direction unit vector of p1
234 nGradientAtP1[0] /= gradientMagnitude;
235 nGradientAtP1[1] /= gradientMagnitude;
238 // gradient vector at p1
239 double nGradientAtP2[2];
241 nGradientAtP2[0] = m_GradientImage->GetPixel(p2)[0];
242 nGradientAtP2[1] = m_GradientImage->GetPixel(p2)[1];
244 nGradientAtP2[0] /= m_GradientMagnitudeImage->GetPixel(p2);
245 nGradientAtP2[1] /= m_GradientMagnitudeImage->GetPixel(p2);
247 double scalarProduct = (nGradientAtP1[0] * nGradientAtP2[0]) + (nGradientAtP1[1] * nGradientAtP2[1]);
248 if (std::abs(scalarProduct) >= 1.0)
250 // this should probably not happen; make sure the input for acos is valid
251 scalarProduct = 0.999999999;
254 double gradientDirectionCost = acos(scalarProduct) / 3.14159265;
256 if (this->m_UseCostMap)
268 costs = w1 * laplacianCost + w2 * gradientCost + w3 * gradientDirectionCost;
270 // scale by euclidian distance
272 if (p1[0] == p2[0] || p1[1] == p2[1])
274 // horizontal or vertical neighbor
280 costScale = sqrt(2.0);
288 template <class TInputImageType>
289 double ShortestPathCostFunctionLiveWire<TInputImageType>::GetMinCost()
294 template <class TInputImageType>
295 void ShortestPathCostFunctionLiveWire<TInputImageType>::Initialize()
299 typedef itk::CastImageFilter<TInputImageType, FloatImageType> CastFilterType;
300 typename CastFilterType::Pointer castFilter = CastFilterType::New();
301 castFilter->SetInput(this->m_Image);
303 // init gradient magnitude image
304 typedef itk::GradientMagnitudeImageFilter<FloatImageType, FloatImageType> GradientMagnitudeFilterType;
305 typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New();
306 gradientFilter->SetInput(castFilter->GetOutput());
307 // gradientFilter->SetNumberOfThreads(4);
308 // gradientFilter->GetOutput()->SetRequestedRegion(m_RequestedRegion);
310 gradientFilter->Update();
311 this->m_GradientMagnitudeImage = gradientFilter->GetOutput();
313 typedef itk::StatisticsImageFilter<FloatImageType> StatisticsImageFilterType;
314 typename StatisticsImageFilterType::Pointer statisticsImageFilter = StatisticsImageFilterType::New();
315 statisticsImageFilter->SetInput(this->m_GradientMagnitudeImage);
316 statisticsImageFilter->Update();
318 m_GradientMax = statisticsImageFilter->GetMaximum();
320 typedef itk::GradientImageFilter<FloatImageType> GradientFilterType;
322 typename GradientFilterType::Pointer filter = GradientFilterType::New();
323 // sigma is specified in millimeters
324 // filter->SetSigma( 1.5 );
325 filter->SetInput(castFilter->GetOutput());
328 m_GradientImage = filter->GetOutput();
330 // init zero crossings
331 // typedef itk::ZeroCrossingImageFilter< TInputImageType, UnsignedCharImageType > ZeroCrossingImageFilterType;
332 // ZeroCrossingImageFilterType::Pointer zeroCrossingImageFilter = ZeroCrossingImageFilterType::New();
333 // zeroCrossingImageFilter->SetInput(this->m_Image);
334 // zeroCrossingImageFilter->SetBackgroundValue(1);
335 // zeroCrossingImageFilter->SetForegroundValue(0);
336 // zeroCrossingImageFilter->SetNumberOfThreads(4);
337 // zeroCrossingImageFilter->Update();
339 // m_EdgeImage = zeroCrossingImageFilter->GetOutput();
341 // cast image to float to apply canny edge dection filter
342 /*typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType;
343 CastFilterType::Pointer castFilter = CastFilterType::New();
344 castFilter->SetInput(this->m_Image);*/
346 // typedef itk::LaplacianImageFilter<FloatImageType, FloatImageType > filterType;
347 // filterType::Pointer laplacianFilter = filterType::New();
348 // laplacianFilter->SetInput( castFilter->GetOutput() ); // NOTE: input image type must be double or float
349 // laplacianFilter->Update();
351 // m_EdgeImage = laplacianFilter->GetOutput();
353 // init canny edge detection
354 typedef itk::CannyEdgeDetectionImageFilter<FloatImageType, FloatImageType> CannyEdgeDetectionImageFilterType;
355 typename CannyEdgeDetectionImageFilterType::Pointer cannyEdgeDetectionfilter =
356 CannyEdgeDetectionImageFilterType::New();
357 cannyEdgeDetectionfilter->SetInput(castFilter->GetOutput());
358 cannyEdgeDetectionfilter->SetUpperThreshold(30);
359 cannyEdgeDetectionfilter->SetLowerThreshold(15);
360 cannyEdgeDetectionfilter->SetVariance(4);
361 cannyEdgeDetectionfilter->SetMaximumError(.01f);
363 cannyEdgeDetectionfilter->Update();
364 m_EdgeImage = cannyEdgeDetectionfilter->GetOutput();
367 m_MinCosts = 0.0; // The lower, the more thouroughly! 0 = dijkstra. If estimate costs are lower than actual costs
368 // everything is fine. If estimation is higher than actual costs, you might not get the shortest
369 // but a different path.
371 m_Initialized = true;
374 // check start/end point value
375 startValue = this->m_Image->GetPixel(this->m_StartIndex);
376 endValue = this->m_Image->GetPixel(this->m_EndIndex);
379 template <class TInputImageType>
380 double ShortestPathCostFunctionLiveWire<TInputImageType>::SigmoidFunction(
381 double I, double max, double min, double alpha, double beta)
383 // Using the SIgmoid formula from ITK Software Guide 6.3.2 Non Linear Mappings
384 double Exponent = -1 * ((I - beta) / alpha);
385 double Factor = 1 / (1 + exp(Exponent));
386 double newI = (max - min) * Factor + min;
391 template <class TInputImageType>
392 double ShortestPathCostFunctionLiveWire<TInputImageType>::Gaussian(double x, double xOfGaussian, double yOfGaussian)
394 return yOfGaussian * exp(-0.5 * pow((x - xOfGaussian), 2));
397 } // end namespace itk
399 #endif // __itkShortestPathCostFunctionLiveWire_txx