00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef __itkCannyEdgeDetectionImageFilter_h
00018 #define __itkCannyEdgeDetectionImageFilter_h
00019
00020 #include "itkImageToImageFilter.h"
00021 #include "itkImage.h"
00022 #include "itkFixedArray.h"
00023 #include "itkConstNeighborhoodIterator.h"
00024 #include "itkDiscreteGaussianImageFilter.h"
00025 #include "itkMultiplyImageFilter.h"
00026 #include "itkZeroFluxNeumannBoundaryCondition.h"
00027 #include "itkMultiThreader.h"
00028 #include "itkDerivativeOperator.h"
00029 #include "itkSparseFieldLayer.h"
00030 #include "itkObjectStore.h"
00031
00032
00033 namespace itk
00034 {
00035
00036
00037 template <class TValueType>
00038 class ListNode
00039 {
00040 public:
00041 TValueType m_Value;
00042
00043 ListNode *Next;
00044 ListNode *Previous;
00045 };
00046
00047
00089 template<class TInputImage, class TOutputImage>
00090 class ITK_EXPORT CannyEdgeDetectionImageFilter
00091 : public ImageToImageFilter<TInputImage, TOutputImage>
00092 {
00093 public:
00095 typedef CannyEdgeDetectionImageFilter Self;
00096 typedef ImageToImageFilter<TInputImage, TOutputImage> Superclass;
00097
00099 typedef TInputImage InputImageType;
00100 typedef TOutputImage OutputImageType;
00101
00103 typedef SmartPointer<Self> Pointer;
00104 typedef SmartPointer<const Self> ConstPointer;
00105
00107 typedef typename TInputImage::PixelType InputImagePixelType;
00108 typedef typename TOutputImage::PixelType OutputImagePixelType;
00109 typedef typename TInputImage::IndexType IndexType;
00110
00113 typedef ZeroFluxNeumannBoundaryCondition<OutputImageType>
00114 DefaultBoundaryConditionType;
00115
00119 typedef ConstNeighborhoodIterator<OutputImageType,
00120 DefaultBoundaryConditionType> NeighborhoodType;
00121
00122 typedef ListNode<IndexType> ListNodeType;
00123 typedef ObjectStore<ListNodeType> ListNodeStorageType;
00124 typedef SparseFieldLayer<ListNodeType> ListType;
00125 typedef typename ListType::Pointer ListPointerType;
00126
00128 itkNewMacro(Self);
00129
00131 typedef typename TOutputImage::RegionType OutputImageRegionType;
00132 typedef typename TInputImage::RegionType InputImageRegionType;
00133
00135 itkTypeMacro(CannyEdgeDetectionImageFilter, ImageToImageFilter);
00136
00138 itkStaticConstMacro(ImageDimension, unsigned int,
00139 TInputImage::ImageDimension);
00140 itkStaticConstMacro(OutputImageDimension, unsigned int,
00141 TOutputImage::ImageDimension);
00143
00145 typedef FixedArray<double, itkGetStaticConstMacro(ImageDimension)> ArrayType;
00146
00148 itkSetMacro(Variance, ArrayType);
00149 itkGetConstMacro(Variance, const ArrayType);
00150 itkSetMacro(MaximumError, ArrayType);
00151 itkGetConstMacro(MaximumError, const ArrayType);
00153
00156 void SetVariance(const typename ArrayType::ValueType v)
00157 {
00158 for (unsigned int i=0; i < TInputImage::ImageDimension; i++)
00159 {
00160 if (m_Variance[i] != v)
00161 {
00162 m_Variance.Fill(v);
00163 this->Modified();
00164 break;
00165 }
00166 }
00167 }
00169
00172 void SetMaximumError(const typename ArrayType::ValueType v)
00173 {
00174 for (unsigned int i=0; i < TInputImage::ImageDimension; i++)
00175 {
00176 if (m_MaximumError[i] != v)
00177 {
00178 m_MaximumError.Fill(v);
00179 this->Modified();
00180 break;
00181 }
00182 }
00183 }
00185
00186
00187 void SetThreshold(const OutputImagePixelType th)
00188 {
00189 this->m_Threshold = th;
00190 this->m_UpperThreshold = m_Threshold;
00191 this->m_LowerThreshold = m_Threshold/2.0;
00192 itkLegacyReplaceBodyMacro(SetThreshold, 2.2, SetUpperThreshold);
00193 }
00194
00195 OutputImagePixelType GetThreshold(OutputImagePixelType th)
00196 {
00197 itkLegacyReplaceBodyMacro(GetThreshold, 2.2, GetUpperThreshold);
00198 return this->m_Threshold;
00199 }
00200
00202 itkSetMacro(UpperThreshold, OutputImagePixelType );
00203 itkGetConstMacro(UpperThreshold, OutputImagePixelType);
00204
00205 itkSetMacro(LowerThreshold, OutputImagePixelType );
00206 itkGetConstMacro(LowerThreshold, OutputImagePixelType);
00207
00208
00209 itkSetMacro(OutsideValue, OutputImagePixelType);
00210 itkGetConstMacro(OutsideValue, OutputImagePixelType);
00211
00212 OutputImageType * GetNonMaximumSuppressionImage()
00213 {
00214 return this->m_MultiplyImageFilter->GetOutput();
00215 }
00216
00224 virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError);
00225
00226 #ifdef ITK_USE_CONCEPT_CHECKING
00227
00228 itkConceptMacro(InputHasNumericTraitsCheck,
00229 (Concept::HasNumericTraits<InputImagePixelType>));
00230 itkConceptMacro(OutputHasNumericTraitsCheck,
00231 (Concept::HasNumericTraits<OutputImagePixelType>));
00232 itkConceptMacro(SameDimensionCheck,
00233 (Concept::SameDimension<ImageDimension, OutputImageDimension>));
00234 itkConceptMacro(InputIsFloatingPointCheck,
00235 (Concept::IsFloatingPoint<InputImagePixelType>));
00236 itkConceptMacro(OutputIsFloatingPointCheck,
00237 (Concept::IsFloatingPoint<OutputImagePixelType>));
00238
00240 #endif
00241
00242 protected:
00243 CannyEdgeDetectionImageFilter();
00244 CannyEdgeDetectionImageFilter(const Self&) {}
00245 void PrintSelf(std::ostream& os, Indent indent) const;
00246
00247 void GenerateData();
00248
00249 typedef DiscreteGaussianImageFilter<InputImageType, OutputImageType>
00250 GaussianImageFilterType;
00251 typedef MultiplyImageFilter< OutputImageType,
00252 OutputImageType, OutputImageType> MultiplyImageFilterType;
00253
00254 private:
00255 virtual ~CannyEdgeDetectionImageFilter(){};
00256
00258 struct CannyThreadStruct
00259 {
00260 CannyEdgeDetectionImageFilter *Filter;
00261 };
00262
00264 void AllocateUpdateBuffer();
00265
00267 void HysteresisThresholding();
00268
00270 void FollowEdge(IndexType index);
00271
00272
00276 void Compute2ndDerivative();
00277
00286
00287
00288
00294 void ThreadedCompute2ndDerivative(const OutputImageRegionType&
00295 outputRegionForThread, int threadId);
00296
00300 static ITK_THREAD_RETURN_TYPE
00301 Compute2ndDerivativeThreaderCallback( void * arg );
00302
00306 OutputImagePixelType ComputeCannyEdge(const NeighborhoodType &it,
00307 void *globalData );
00308
00313 void Compute2ndDerivativePos();
00314
00320 void ThreadedCompute2ndDerivativePos(const OutputImageRegionType&
00321 outputRegionForThread, int threadId);
00322
00326 static ITK_THREAD_RETURN_TYPE
00327 Compute2ndDerivativePosThreaderCallback( void *arg );
00328
00330 ArrayType m_Variance;
00331
00334 ArrayType m_MaximumError;
00335
00337 OutputImagePixelType m_UpperThreshold;
00338
00340 OutputImagePixelType m_LowerThreshold;
00341
00343 OutputImagePixelType m_Threshold;
00344
00346 OutputImagePixelType m_OutsideValue;
00347
00349 typename OutputImageType::Pointer m_UpdateBuffer1;
00350
00352 typename GaussianImageFilterType::Pointer m_GaussianFilter;
00353
00356 typename MultiplyImageFilterType::Pointer m_MultiplyImageFilter;
00357
00360 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00361 m_ComputeCannyEdge1stDerivativeOper;
00362 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00363 m_ComputeCannyEdge2ndDerivativeOper;
00365
00366 std::slice m_ComputeCannyEdgeSlice[ImageDimension];
00367
00368 unsigned long m_Stride[ImageDimension];
00369 unsigned long m_Center;
00370
00371 typename ListNodeStorageType::Pointer m_NodeStore;
00372 ListPointerType m_NodeList;
00373
00374 };
00375
00376 }
00377
00378 #ifndef ITK_MANUAL_INSTANTIATION
00379 #include "itkCannyEdgeDetectionImageFilter.txx"
00380 #endif
00381
00382 #endif
00383