18 #ifndef __itkLiveWireImageFunction_txx
19 #define __itkLiveWireImageFunction_txx
21 #include "itkLiveWireImageFunction.h"
23 #include "itkCastImageFilter.h"
24 #include "itkConstNeighborhoodIterator.h"
25 #include "itkNeighborhood.h"
26 #include "itkRescaleIntensityImageFilter.h"
27 #include "itkZeroCrossingBasedEdgeDetectionImageFilter.h"
29 #include "vnl/vnl_math.h"
35 template<
class TInputImage>
36 LiveWireImageFunction<TInputImage>
37 ::LiveWireImageFunction()
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;
45 this->m_ZeroCrossingImage =
nullptr;
46 this->m_MaskImage =
nullptr;
48 this->m_InsidePixelValue = NumericTraits<MaskPixelType>::One;
50 this->m_AnchorSeed.Fill( 0 );
54 template<
class TInputImage>
55 LiveWireImageFunction<TInputImage>
56 ::~LiveWireImageFunction()
63 template <
class TInputImage>
68 Superclass::SetInputImage( ptr );
73 typedef CastImageFilter<InputImageType, RealImageType> CasterType;
74 typename CasterType::Pointer caster = CasterType::New();
75 caster->SetInput( this->GetInputImage() );
78 typename GradientFilterType::Pointer gradient = GradientFilterType::New();
79 gradient->SetInput( this->GetInputImage() );
80 gradient->SetUseImageSpacing( this->m_UseImageSpacing );
82 this->m_GradientImage = gradient->GetOutput();
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();
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 )
99 ItM.Set( ( ItG.Get() ).GetNorm() );
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 );
108 this->m_RescaledGradientMagnitudeImage = rescaler->GetOutput();
110 if ( !this->m_ZeroCrossingImage )
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();
123 this->GeneratePathDirectionImage();
126 template <
class TInputImage>
131 if ( !this->IsInsideBuffer( this->m_AnchorSeed ) )
133 itkExceptionMacro(
"m_AnchorSeed is not inside buffer." );
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 );
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();
154 typename ConstNeighborhoodIterator<InputImageType>::RadiusType radius;
156 ConstNeighborhoodIterator<BooleanImageType> It( radius, expanded,
157 expanded->GetRequestedRegion() );
158 unsigned int numberOfNeighbors = 1;
159 for (
unsigned int d = 0; d < ImageDimension; d++ )
161 numberOfNeighbors *= ( 2*radius[d] + 1 );
163 Neighborhood<RealType, ImageDimension> scaleFactors;
164 scaleFactors.SetRadius( radius );
165 for (
unsigned int n = 0; n < numberOfNeighbors; n++ )
168 if ( n == static_cast<unsigned int>( 0.5 * numberOfNeighbors ) )
172 typename Neighborhood<RealType, ImageDimension>::OffsetType offset
173 = scaleFactors.GetOffset( n );
175 bool isFaceConnected =
true;
176 unsigned int sumOffset = 0;
177 for (
unsigned int d = 0; d < ImageDimension; d++ )
179 sumOffset += vnl_math_abs( offset[d] );
180 if ( this->m_UseImageSpacing )
182 scaleFactors[n] += (
static_cast<RealType
>( offset[d] * offset[d] )
183 * this->GetInputImage()->GetSpacing()[d]
184 * this->GetInputImage()->GetSpacing()[d] );
188 scaleFactors[n] +=
static_cast<RealType
>( offset[d] * offset[d] );
190 if ( sumOffset > 1 && this->m_UseFaceConnectedness )
192 isFaceConnected =
false;
196 if ( !isFaceConnected )
200 if ( scaleFactors[n] > 0 )
202 scaleFactors[n] = vcl_sqrt( scaleFactors[n] );
210 PriorityQueueElementType anchorElement( this->m_AnchorSeed, 0.0 );
212 if ( this->m_MaskImage &&
213 this->m_MaskImage->GetPixel( this->m_AnchorSeed )
214 != this->m_InsidePixelValue )
216 itkWarningMacro(
"The anchor seed is outside the user-defined mask region." );
220 typename PriorityQueueType::Pointer Q = PriorityQueueType::New();
222 Q->Push( anchorElement );
224 while ( !Q->Empty() )
226 PriorityQueueElementType centerElement = Q->Peek();
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 );
235 typename GradientImageType::PixelType centerGradient
236 = this->m_GradientImage->GetPixel( centerElement.m_Element );
238 = this->m_GradientMagnitudeImage->GetPixel( centerElement.m_Element );
240 for (
unsigned int n = 0; n < numberOfNeighbors; n++ )
242 if ( scaleFactors[n] == 0 )
247 bool isExpanded = It.GetPixel( n, inBounds );
248 if ( isExpanded || !inBounds )
253 IndexType neighborIndex = It.GetIndex( n );
255 if ( this->m_MaskImage && this->m_MaskImage->GetPixel(
256 neighborIndex ) != this->m_InsidePixelValue )
261 typename GradientImageType::PixelType neighborGradient
262 = this->m_GradientImage->GetPixel( neighborIndex );
263 RealType neighborNorm
264 = this->m_GradientMagnitudeImage->GetPixel( neighborIndex );
270 if ( this->m_ZeroCrossingWeight > 0 && this->m_ZeroCrossingImage )
272 fz = 1.0 - this->m_ZeroCrossingImage->GetPixel( neighborIndex );
275 if ( this->m_GradientMagnitudeWeight > 0.0 )
278 this->m_RescaledGradientMagnitudeImage->GetPixel( neighborIndex );
280 if ( this->m_GradientDirectionWeight > 0.0
281 && neighborNorm > 0 && centerNorm > 0 )
283 PointType neighborPoint;
284 this->GetInputImage()->TransformIndexToPhysicalPoint(
285 neighborIndex, neighborPoint );
286 typename PointType::VectorType vector
287 = neighborPoint - centerPoint;
288 RealType vectorNorm = vector.GetNorm();
290 RealType centerMin = vnl_math_min( centerGradient * vector,
291 centerGradient * -vector );
292 RealType neighborMin = vnl_math_min( neighborGradient * vector,
293 neighborGradient * -vector );
295 fd = 1.0 - ( vcl_acos( centerMin / ( centerNorm * vectorNorm ) ) +
296 vcl_acos( neighborMin / ( neighborNorm * vectorNorm ) ) )
300 RealType neighborCost
301 = centerElement.m_Priority + scaleFactors[n] *
302 ( fg * this->m_GradientMagnitudeWeight
303 + fz * this->m_ZeroCrossingWeight
304 + fd * this->m_GradientDirectionWeight );
306 PriorityQueueElementType neighborElement( neighborIndex, neighborCost );
308 Q->Push( neighborElement );
310 this->m_PathDirectionImage->SetPixel( neighborIndex,
311 centerElement.m_Element - neighborElement.m_Element );
313 PriorityQueueElementType element = Q->Peek();
314 while ( expanded->GetPixel( element.m_Element ) )
323 template <
class TInputImage>
324 typename LiveWireImageFunction<TInputImage>::OutputType::Pointer
328 if ( !this->IsInsideBuffer( index ) )
330 itkWarningMacro(
"Requested index is not inside buffer." );
334 if ( this->m_MaskImage &&
335 this->m_MaskImage->GetPixel( index )
336 != this->m_InsidePixelValue )
338 itkWarningMacro(
"The index is outside the user-defined mask region." );
342 typename OutputType::Pointer output = OutputType::New();
343 output->Initialize();
345 IndexType currentIndex = index;
346 while ( currentIndex != this->m_AnchorSeed )
348 output->AddVertex( VertexType( currentIndex ) );
349 currentIndex += this->m_PathDirectionImage->GetPixel( currentIndex );
351 output->AddVertex( VertexType( currentIndex ) );
359 template <
class TInputImage>
364 Superclass::PrintSelf( os, indent );
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;
379 os << indent <<
"MaskImage"
380 << this->m_MaskImage << std::endl;
381 os << indent <<
"InsidePixelValue"
382 << this->m_InsidePixelValue << std::endl;
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