Seg3D  2.4
Seg3D is a free volume segmentation and processing tool developed by the NIH Center for Integrative Biomedical Computing at the University of Utah Scientific Computing and Imaging (SCI) Institute.
All Classes Namespaces Functions Variables Typedefs Enumerator Friends
itkLiveWireImageFunction.hxx
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkLiveWireImageFunction.txx,v $
5  Language: C++
6  Date: $Date: $
7  Version: $Revision: $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 
18 #ifndef __itkLiveWireImageFunction_txx
19 #define __itkLiveWireImageFunction_txx
20 
21 #include "itkLiveWireImageFunction.h"
22 
23 #include "itkCastImageFilter.h"
24 #include "itkConstNeighborhoodIterator.h"
25 #include "itkNeighborhood.h"
26 #include "itkRescaleIntensityImageFilter.h"
27 #include "itkZeroCrossingBasedEdgeDetectionImageFilter.h"
28 
29 #include "vnl/vnl_math.h"
30 
31 namespace itk
32 {
33 
34 // Constructor
35 template<class TInputImage>
36 LiveWireImageFunction<TInputImage>
37 ::LiveWireImageFunction()
38 {
39  this->m_GradientMagnitudeWeight = 0.43;
40  this->m_ZeroCrossingWeight = 0.43;
41  this->m_GradientDirectionWeight = 0.14;
42  this->m_UseFaceConnectedness = true;
43  this->m_UseImageSpacing = true;
44 
45  this->m_ZeroCrossingImage = nullptr;
46  this->m_MaskImage = nullptr;
47 
48  this->m_InsidePixelValue = NumericTraits<MaskPixelType>::One;
49 
50  this->m_AnchorSeed.Fill( 0 );
51 }
52 
53 // Destructor
54 template<class TInputImage>
55 LiveWireImageFunction<TInputImage>
56 ::~LiveWireImageFunction()
57 {
58 }
59 
63 template <class TInputImage>
64 void
67 {
68  Superclass::SetInputImage( ptr );
69 
73  typedef CastImageFilter<InputImageType, RealImageType> CasterType;
74  typename CasterType::Pointer caster = CasterType::New();
75  caster->SetInput( this->GetInputImage() );
76  caster->Update();
77 
78  typename GradientFilterType::Pointer gradient = GradientFilterType::New();
79  gradient->SetInput( this->GetInputImage() );
80  gradient->SetUseImageSpacing( this->m_UseImageSpacing );
81  gradient->Update();
82  this->m_GradientImage = gradient->GetOutput();
83 
84  this->m_GradientMagnitudeImage = RealImageType::New();
85  this->m_GradientMagnitudeImage->SetOrigin(
86  this->GetInputImage()->GetOrigin() );
87  this->m_GradientMagnitudeImage->SetSpacing(
88  this->GetInputImage()->GetSpacing() );
89  this->m_GradientMagnitudeImage->SetRegions(
90  this->GetInputImage()->GetRequestedRegion() );
91  this->m_GradientMagnitudeImage->Allocate();
92 
93  ImageRegionIterator<GradientImageType> ItG( this->m_GradientImage,
94  this->m_GradientImage->GetRequestedRegion() );
95  ImageRegionIterator<RealImageType> ItM( this->m_GradientMagnitudeImage,
96  this->m_GradientMagnitudeImage->GetRequestedRegion() );
97  for ( ItG.GoToBegin(), ItM.GoToBegin(); !ItG.IsAtEnd(); ++ItG, ++ItM )
98  {
99  ItM.Set( ( ItG.Get() ).GetNorm() );
100  }
101 
102  typedef RescaleIntensityImageFilter<RealImageType, RealImageType> RescalerType;
103  typename RescalerType::Pointer rescaler = RescalerType::New();
104  rescaler->SetInput( this->m_GradientMagnitudeImage );
105  rescaler->SetOutputMinimum( NumericTraits<RealType>::Zero );
106  rescaler->SetOutputMaximum( NumericTraits<RealType>::One );
107  rescaler->Update();
108  this->m_RescaledGradientMagnitudeImage = rescaler->GetOutput();
109 
110  if ( !this->m_ZeroCrossingImage )
111  {
112  typedef ZeroCrossingBasedEdgeDetectionImageFilter<RealImageType, RealImageType>
113  ZeroCrossingFilterType;
114  typename ZeroCrossingFilterType::Pointer
115  zeroCrossing = ZeroCrossingFilterType::New();
116  zeroCrossing->SetInput( caster->GetOutput() );
117  zeroCrossing->SetForegroundValue( NumericTraits<RealType>::One );
118  zeroCrossing->SetBackgroundValue( NumericTraits<RealType>::Zero );
119  zeroCrossing->Update();
120  this->m_ZeroCrossingImage = zeroCrossing->GetOutput();
121  }
122 
123  this->GeneratePathDirectionImage();
124 }
125 
126 template <class TInputImage>
127 void
130 {
131  if ( !this->IsInsideBuffer( this->m_AnchorSeed ) )
132  {
133  itkExceptionMacro( "m_AnchorSeed is not inside buffer." );
134  }
135 
139  typedef Image<bool, ImageDimension> BooleanImageType;
140  typename BooleanImageType::Pointer expanded = BooleanImageType::New();
141  expanded->SetOrigin( this->GetInputImage()->GetOrigin() );
142  expanded->SetSpacing( this->GetInputImage()->GetSpacing() );
143  expanded->SetRegions( this->GetInputImage()->GetRequestedRegion() );
144  expanded->Allocate();
145  expanded->FillBuffer( false );
146  expanded->SetPixel( this->m_AnchorSeed, true );
147 
148  this->m_PathDirectionImage = OffsetImageType::New();
149  this->m_PathDirectionImage->SetOrigin( this->GetInputImage()->GetOrigin() );
150  this->m_PathDirectionImage->SetSpacing( this->GetInputImage()->GetSpacing() );
151  this->m_PathDirectionImage->SetRegions( this->GetInputImage()->GetRequestedRegion() );
152  this->m_PathDirectionImage->Allocate();
153 
154  typename ConstNeighborhoodIterator<InputImageType>::RadiusType radius;
155  radius.Fill( 1 );
156  ConstNeighborhoodIterator<BooleanImageType> It( radius, expanded,
157  expanded->GetRequestedRegion() );
158  unsigned int numberOfNeighbors = 1;
159  for ( unsigned int d = 0; d < ImageDimension; d++ )
160  {
161  numberOfNeighbors *= ( 2*radius[d] + 1 );
162  }
163  Neighborhood<RealType, ImageDimension> scaleFactors;
164  scaleFactors.SetRadius( radius );
165  for ( unsigned int n = 0; n < numberOfNeighbors; n++ )
166  {
167  scaleFactors[n] = 0;
168  if ( n == static_cast<unsigned int>( 0.5 * numberOfNeighbors ) )
169  {
170  continue;
171  }
172  typename Neighborhood<RealType, ImageDimension>::OffsetType offset
173  = scaleFactors.GetOffset( n );
174 
175  bool isFaceConnected = true;
176  unsigned int sumOffset = 0;
177  for ( unsigned int d = 0; d < ImageDimension; d++ )
178  {
179  sumOffset += vnl_math_abs( offset[d] );
180  if ( this->m_UseImageSpacing )
181  {
182  scaleFactors[n] += ( static_cast<RealType>( offset[d] * offset[d] )
183  * this->GetInputImage()->GetSpacing()[d]
184  * this->GetInputImage()->GetSpacing()[d] );
185  }
186  else
187  {
188  scaleFactors[n] += static_cast<RealType>( offset[d] * offset[d] );
189  }
190  if ( sumOffset > 1 && this->m_UseFaceConnectedness )
191  {
192  isFaceConnected = false;
193  break;
194  }
195  }
196  if ( !isFaceConnected )
197  {
198  scaleFactors[n] = 0;
199  }
200  if ( scaleFactors[n] > 0 )
201  {
202  scaleFactors[n] = vcl_sqrt( scaleFactors[n] );
203  }
204  }
205 
210  PriorityQueueElementType anchorElement( this->m_AnchorSeed, 0.0 );
211 
212  if ( this->m_MaskImage &&
213  this->m_MaskImage->GetPixel( this->m_AnchorSeed )
214  != this->m_InsidePixelValue )
215  {
216  itkWarningMacro( "The anchor seed is outside the user-defined mask region." );
217  return;
218  }
219 
220  typename PriorityQueueType::Pointer Q = PriorityQueueType::New();
221  Q->Initialize();
222  Q->Push( anchorElement );
223 
224  while ( !Q->Empty() )
225  {
226  PriorityQueueElementType centerElement = Q->Peek();
227  Q->Pop();
228 
229  expanded->SetPixel( centerElement.m_Element, true );
230  It.SetLocation( centerElement.m_Element );
231  PointType centerPoint;
232  this->GetInputImage()->TransformIndexToPhysicalPoint(
233  centerElement.m_Element, centerPoint );
234 
235  typename GradientImageType::PixelType centerGradient
236  = this->m_GradientImage->GetPixel( centerElement.m_Element );
237  RealType centerNorm
238  = this->m_GradientMagnitudeImage->GetPixel( centerElement.m_Element );
239 
240  for ( unsigned int n = 0; n < numberOfNeighbors; n++ )
241  {
242  if ( scaleFactors[n] == 0 )
243  {
244  continue;
245  }
246  bool inBounds;
247  bool isExpanded = It.GetPixel( n, inBounds );
248  if ( isExpanded || !inBounds )
249  {
250  continue;
251  }
252 
253  IndexType neighborIndex = It.GetIndex( n );
254 
255  if ( this->m_MaskImage && this->m_MaskImage->GetPixel(
256  neighborIndex ) != this->m_InsidePixelValue )
257  {
258  continue;
259  }
260 
261  typename GradientImageType::PixelType neighborGradient
262  = this->m_GradientImage->GetPixel( neighborIndex );
263  RealType neighborNorm
264  = this->m_GradientMagnitudeImage->GetPixel( neighborIndex );
265 
266  RealType fz = 0.0;
267  RealType fg = 0.0;
268  RealType fd = 0.0;
269 
270  if ( this->m_ZeroCrossingWeight > 0 && this->m_ZeroCrossingImage )
271  {
272  fz = 1.0 - this->m_ZeroCrossingImage->GetPixel( neighborIndex );
273  }
274 
275  if ( this->m_GradientMagnitudeWeight > 0.0 )
276  {
277  fg = 1.0 -
278  this->m_RescaledGradientMagnitudeImage->GetPixel( neighborIndex );
279  }
280  if ( this->m_GradientDirectionWeight > 0.0
281  && neighborNorm > 0 && centerNorm > 0 )
282  {
283  PointType neighborPoint;
284  this->GetInputImage()->TransformIndexToPhysicalPoint(
285  neighborIndex, neighborPoint );
286  typename PointType::VectorType vector
287  = neighborPoint - centerPoint;
288  RealType vectorNorm = vector.GetNorm();
289 
290  RealType centerMin = vnl_math_min( centerGradient * vector,
291  centerGradient * -vector );
292  RealType neighborMin = vnl_math_min( neighborGradient * vector,
293  neighborGradient * -vector );
294 
295  fd = 1.0 - ( vcl_acos( centerMin / ( centerNorm * vectorNorm ) ) +
296  vcl_acos( neighborMin / ( neighborNorm * vectorNorm ) ) )
297  / vnl_math::pi;
298  }
299 
300  RealType neighborCost
301  = centerElement.m_Priority + scaleFactors[n] *
302  ( fg * this->m_GradientMagnitudeWeight
303  + fz * this->m_ZeroCrossingWeight
304  + fd * this->m_GradientDirectionWeight );
305 
306  PriorityQueueElementType neighborElement( neighborIndex, neighborCost );
307 
308  Q->Push( neighborElement );
309 
310  this->m_PathDirectionImage->SetPixel( neighborIndex,
311  centerElement.m_Element - neighborElement.m_Element );
312 
313  PriorityQueueElementType element = Q->Peek();
314  while ( expanded->GetPixel( element.m_Element ) )
315  {
316  Q->Pop();
317  element = Q->Peek();
318  }
319  }
320  }
321 }
322 
323 template <class TInputImage>
324 typename LiveWireImageFunction<TInputImage>::OutputType::Pointer
326 ::EvaluateAtIndex( const IndexType &index ) const
327 {
328  if ( !this->IsInsideBuffer( index ) )
329  {
330  itkWarningMacro( "Requested index is not inside buffer." );
331  return nullptr;
332  }
333 
334  if ( this->m_MaskImage &&
335  this->m_MaskImage->GetPixel( index )
336  != this->m_InsidePixelValue )
337  {
338  itkWarningMacro( "The index is outside the user-defined mask region." );
339  return nullptr;
340  }
341 
342  typename OutputType::Pointer output = OutputType::New();
343  output->Initialize();
344 
345  IndexType currentIndex = index;
346  while ( currentIndex != this->m_AnchorSeed )
347  {
348  output->AddVertex( VertexType( currentIndex ) );
349  currentIndex += this->m_PathDirectionImage->GetPixel( currentIndex );
350  }
351  output->AddVertex( VertexType( currentIndex ) );
352 
353  return output;
354 }
355 
359 template <class TInputImage>
360 void
362 ::PrintSelf(std::ostream& os, Indent indent) const
363 {
364  Superclass::PrintSelf( os, indent );
365 
366  os << indent << "AnchorSeed: "
367  << this->m_AnchorSeed << std::endl;
368  os << indent << "GradientMagnitudeWeight: "
369  << this->m_GradientMagnitudeWeight << std::endl;
370  os << indent << "GradientDirectionWeight: "
371  << this->m_GradientDirectionWeight << std::endl;
372  os << indent << "ZeroCrossingWeight: "
373  << this->m_ZeroCrossingWeight << std::endl;
374  os << indent << "UseImageSpacing: "
375  << this->m_UseImageSpacing << std::endl;
376  os << indent << "UseFaceConnectedness: "
377  << this->m_UseFaceConnectedness << std::endl;
378 
379  os << indent << "MaskImage"
380  << this->m_MaskImage << std::endl;
381  os << indent << "InsidePixelValue"
382  << this->m_InsidePixelValue << std::endl;
383 
384 }
385 
386 } // end namespace itk
387 
388 #endif
Implements livewire image segmentation of Barret and Mortensen.
Definition: itkLiveWireImageFunction.h:46
TInputImage InputImageType
Definition: itkLiveWireImageFunction.h:72
Definition: itkNormalizeImageFilterWithMask.h:48
virtual OutputType::Pointer EvaluateAtIndex(const IndexType &index) const
Definition: itkLiveWireImageFunction.hxx:326
virtual void SetInputImage(const InputImageType *ptr)
Definition: itkLiveWireImageFunction.hxx:66
void PrintSelf(std::ostream &os, Indent indent) const
Definition: itkLiveWireImageFunction.hxx:362