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
00140 typedef FixedArray<double, itkGetStaticConstMacro(ImageDimension)> ArrayType;
00141
00143 itkSetMacro(Variance, ArrayType);
00144 itkGetMacro(Variance, const ArrayType);
00145 itkSetMacro(MaximumError, ArrayType);
00146 itkGetMacro(MaximumError, const ArrayType);
00147
00150 void SetVariance(const typename ArrayType::ValueType v)
00151 {
00152 for (unsigned int i=0; i < TInputImage::ImageDimension; i++)
00153 {
00154 if (m_Variance[i] != v)
00155 {
00156 m_Variance.Fill(v);
00157 this->Modified();
00158 break;
00159 }
00160 }
00161 }
00162
00165 void SetMaximumError(const typename ArrayType::ValueType v)
00166 {
00167 for (unsigned int i=0; i < TInputImage::ImageDimension; i++)
00168 {
00169 if (m_Variance[i] != v)
00170 {
00171 m_MaximumError.Fill(v);
00172 this->Modified();
00173 break;
00174 }
00175 }
00176 }
00177
00178
00179 void SetThreshold(const OutputImagePixelType th)
00180 {
00181 this->m_Threshold = th;
00182 this->m_UpperThreshold = m_Threshold;
00183 this->m_LowerThreshold = m_Threshold/2.0;
00184 itkLegacyReplaceBody(SetThreshold, 2.2, SetUpperThreshold);
00185 }
00186
00187 OutputImagePixelType GetThreshold(OutputImagePixelType th)
00188 {
00189 itkLegacyReplaceBody(GetThreshold, 2.2, GetUpperThreshold);
00190 return this->m_Threshold;
00191 }
00192
00194 itkSetMacro(UpperThreshold, OutputImagePixelType );
00195 itkGetMacro(UpperThreshold, OutputImagePixelType);
00196
00197 itkSetMacro(LowerThreshold, OutputImagePixelType );
00198 itkGetMacro(LowerThreshold, OutputImagePixelType);
00199
00200
00201 itkSetMacro(OutsideValue, OutputImagePixelType);
00202 itkGetMacro(OutsideValue, OutputImagePixelType);
00203
00211 virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError);
00212
00213 protected:
00214 CannyEdgeDetectionImageFilter();
00215 CannyEdgeDetectionImageFilter(const Self&) {}
00216 void PrintSelf(std::ostream& os, Indent indent) const;
00217
00218 void GenerateData();
00219
00220 typedef DiscreteGaussianImageFilter<InputImageType, OutputImageType>
00221 GaussianImageFilterType;
00222 typedef MultiplyImageFilter< OutputImageType,
00223 OutputImageType, OutputImageType> MultiplyImageFilterType;
00224
00225 private:
00226 virtual ~CannyEdgeDetectionImageFilter(){};
00227
00229 struct CannyThreadStruct
00230 {
00231 CannyEdgeDetectionImageFilter *Filter;
00232 };
00233
00235 void AllocateUpdateBuffer();
00236
00238 void HysteresisThresholding();
00239
00241 void FollowEdge(IndexType index);
00242
00244 bool InBounds(IndexType index);
00245
00246
00250 void Compute2ndDerivative();
00251
00260
00261
00262
00268 void ThreadedCompute2ndDerivative(const OutputImageRegionType&
00269 outputRegionForThread, int threadId);
00270
00274 static ITK_THREAD_RETURN_TYPE
00275 Compute2ndDerivativeThreaderCallback( void * arg );
00276
00280 OutputImagePixelType ComputeCannyEdge(const NeighborhoodType &it,
00281 void *globalData );
00282
00287 void Compute2ndDerivativePos();
00288
00294 void ThreadedCompute2ndDerivativePos(const OutputImageRegionType&
00295 outputRegionForThread, int threadId);
00296
00300 static ITK_THREAD_RETURN_TYPE
00301 Compute2ndDerivativePosThreaderCallback( void *arg );
00302
00304 ArrayType m_Variance;
00305
00308 ArrayType m_MaximumError;
00309
00311 OutputImagePixelType m_UpperThreshold;
00312
00314 OutputImagePixelType m_LowerThreshold;
00315
00317 OutputImagePixelType m_Threshold;
00318
00320 OutputImagePixelType m_OutsideValue;
00321
00323 typename OutputImageType::Pointer m_UpdateBuffer1;
00324
00326 typename GaussianImageFilterType::Pointer m_GaussianFilter;
00327
00330 typename MultiplyImageFilterType::Pointer m_MultiplyImageFilter;
00331
00334 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00335 m_ComputeCannyEdge1stDerivativeOper;
00336 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00337 m_ComputeCannyEdge2ndDerivativeOper;
00338
00339 std::slice m_ComputeCannyEdgeSlice[ImageDimension];
00340
00341 unsigned long m_Stride[ImageDimension];
00342 unsigned long m_Center;
00343
00344 typename ListNodeStorageType::Pointer m_NodeStore;
00345 ListPointerType m_NodeList;
00346
00347 };
00348
00349 }
00350
00351 #ifndef ITK_MANUAL_INSTANTIATION
00352 #include "itkCannyEdgeDetectionImageFilter.txx"
00353 #endif
00354
00355 #endif
00356