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 ListNode *Next;
00043 ListNode *Previous;
00044 };
00045
00046
00088 template<class TInputImage, class TOutputImage>
00089 class ITK_EXPORT CannyEdgeDetectionImageFilter
00090 : public ImageToImageFilter<TInputImage, TOutputImage>
00091 {
00092 public:
00094 typedef CannyEdgeDetectionImageFilter Self;
00095 typedef ImageToImageFilter<TInputImage, TOutputImage> Superclass;
00096
00098 typedef TInputImage InputImageType;
00099 typedef TOutputImage OutputImageType;
00100
00102 typedef SmartPointer<Self> Pointer;
00103 typedef SmartPointer<const Self> ConstPointer;
00104
00106 typedef typename TInputImage::PixelType InputImagePixelType;
00107 typedef typename TOutputImage::PixelType OutputImagePixelType;
00108 typedef typename TInputImage::IndexType IndexType;
00109
00112 typedef ZeroFluxNeumannBoundaryCondition<OutputImageType>
00113 DefaultBoundaryConditionType;
00114
00118 typedef ConstNeighborhoodIterator<OutputImageType,
00119 DefaultBoundaryConditionType> NeighborhoodType;
00120
00121 typedef ListNode<IndexType> ListNodeType;
00122 typedef ObjectStore<ListNodeType> ListNodeStorageType;
00123 typedef SparseFieldLayer<ListNodeType> ListType;
00124 typedef typename ListType::Pointer ListPointerType;
00125
00127 itkNewMacro(Self);
00128
00130 typedef typename TOutputImage::RegionType OutputImageRegionType;
00131
00133 itkTypeMacro(CannyEdgeDetectionImageFilter, ImageToImageFilter);
00134
00136 itkStaticConstMacro(ImageDimension, unsigned int,
00137 TInputImage::ImageDimension);
00138 itkStaticConstMacro(OutputImageDimension, unsigned int,
00139 TOutputImage::ImageDimension);
00141
00143 typedef FixedArray<double, itkGetStaticConstMacro(ImageDimension)> ArrayType;
00144
00146 itkSetMacro(Variance, ArrayType);
00147 itkGetMacro(Variance, const ArrayType);
00148 itkSetMacro(MaximumError, ArrayType);
00149 itkGetMacro(MaximumError, const ArrayType);
00151
00154 void SetVariance(const typename ArrayType::ValueType v)
00155 {
00156 for (unsigned int i=0; i < TInputImage::ImageDimension; i++)
00157 {
00158 if (m_Variance[i] != v)
00159 {
00160 m_Variance.Fill(v);
00161 this->Modified();
00162 break;
00163 }
00164 }
00165 }
00167
00170 void SetMaximumError(const typename ArrayType::ValueType v)
00171 {
00172 for (unsigned int i=0; i < TInputImage::ImageDimension; i++)
00173 {
00174 if (m_Variance[i] != v)
00175 {
00176 m_MaximumError.Fill(v);
00177 this->Modified();
00178 break;
00179 }
00180 }
00181 }
00183
00184
00185 void SetThreshold(const OutputImagePixelType th)
00186 {
00187 this->m_Threshold = th;
00188 this->m_UpperThreshold = m_Threshold;
00189 this->m_LowerThreshold = m_Threshold/2.0;
00190 itkLegacyReplaceBody(SetThreshold, 2.2, SetUpperThreshold);
00191 }
00192
00193 OutputImagePixelType GetThreshold(OutputImagePixelType th)
00194 {
00195 itkLegacyReplaceBody(GetThreshold, 2.2, GetUpperThreshold);
00196 return this->m_Threshold;
00197 }
00198
00200 itkSetMacro(UpperThreshold, OutputImagePixelType );
00201 itkGetMacro(UpperThreshold, OutputImagePixelType);
00202
00203 itkSetMacro(LowerThreshold, OutputImagePixelType );
00204 itkGetMacro(LowerThreshold, OutputImagePixelType);
00205
00206
00207 itkSetMacro(OutsideValue, OutputImagePixelType);
00208 itkGetMacro(OutsideValue, OutputImagePixelType);
00209
00217 virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError);
00218
00219 #ifdef ITK_USE_CONCEPT_CHECKING
00220
00221 itkConceptMacro(InputHasNumericTraitsCheck,
00222 (Concept::HasNumericTraits<InputImagePixelType>));
00223 itkConceptMacro(OutputHasNumericTraitsCheck,
00224 (Concept::HasNumericTraits<OutputImagePixelType>));
00225 itkConceptMacro(SameDimensionCheck,
00226 (Concept::SameDimension<ImageDimension, OutputImageDimension>));
00227 itkConceptMacro(InputIsFloatingPointCheck,
00228 (Concept::IsFloatingPoint<InputImagePixelType>));
00229 itkConceptMacro(OutputIsFloatingPointCheck,
00230 (Concept::IsFloatingPoint<OutputImagePixelType>));
00231
00233 #endif
00234
00235 protected:
00236 CannyEdgeDetectionImageFilter();
00237 CannyEdgeDetectionImageFilter(const Self&) {}
00238 void PrintSelf(std::ostream& os, Indent indent) const;
00239
00240 void GenerateData();
00241
00242 typedef DiscreteGaussianImageFilter<InputImageType, OutputImageType>
00243 GaussianImageFilterType;
00244 typedef MultiplyImageFilter< OutputImageType,
00245 OutputImageType, OutputImageType> MultiplyImageFilterType;
00246
00247 private:
00248 virtual ~CannyEdgeDetectionImageFilter(){};
00249
00251 struct CannyThreadStruct
00252 {
00253 CannyEdgeDetectionImageFilter *Filter;
00254 };
00255
00257 void AllocateUpdateBuffer();
00258
00260 void HysteresisThresholding();
00261
00263 void FollowEdge(IndexType index);
00264
00266 bool InBounds(IndexType index);
00267
00268
00272 void Compute2ndDerivative();
00273
00282
00283
00284
00290 void ThreadedCompute2ndDerivative(const OutputImageRegionType&
00291 outputRegionForThread, int threadId);
00292
00296 static ITK_THREAD_RETURN_TYPE
00297 Compute2ndDerivativeThreaderCallback( void * arg );
00298
00302 OutputImagePixelType ComputeCannyEdge(const NeighborhoodType &it,
00303 void *globalData );
00304
00309 void Compute2ndDerivativePos();
00310
00316 void ThreadedCompute2ndDerivativePos(const OutputImageRegionType&
00317 outputRegionForThread, int threadId);
00318
00322 static ITK_THREAD_RETURN_TYPE
00323 Compute2ndDerivativePosThreaderCallback( void *arg );
00324
00326 ArrayType m_Variance;
00327
00330 ArrayType m_MaximumError;
00331
00333 OutputImagePixelType m_UpperThreshold;
00334
00336 OutputImagePixelType m_LowerThreshold;
00337
00339 OutputImagePixelType m_Threshold;
00340
00342 OutputImagePixelType m_OutsideValue;
00343
00345 typename OutputImageType::Pointer m_UpdateBuffer1;
00346
00348 typename GaussianImageFilterType::Pointer m_GaussianFilter;
00349
00352 typename MultiplyImageFilterType::Pointer m_MultiplyImageFilter;
00353
00356 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00357 m_ComputeCannyEdge1stDerivativeOper;
00358 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00359 m_ComputeCannyEdge2ndDerivativeOper;
00361
00362 std::slice m_ComputeCannyEdgeSlice[ImageDimension];
00363
00364 unsigned long m_Stride[ImageDimension];
00365 unsigned long m_Center;
00366
00367 typename ListNodeStorageType::Pointer m_NodeStore;
00368 ListPointerType m_NodeList;
00369
00370 };
00371
00372 }
00373
00374 #ifndef ITK_MANUAL_INSTANTIATION
00375 #include "itkCannyEdgeDetectionImageFilter.txx"
00376 #endif
00377
00378 #endif
00379
00380