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