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
00210 OutputImageType * GetNonMaximumSuppressionImage()
00211 {
00212 return this->m_MultiplyImageFilter->GetOutput();
00213 }
00214
00222 virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError);
00223
00224 #ifdef ITK_USE_CONCEPT_CHECKING
00225
00226 itkConceptMacro(InputHasNumericTraitsCheck,
00227 (Concept::HasNumericTraits<InputImagePixelType>));
00228 itkConceptMacro(OutputHasNumericTraitsCheck,
00229 (Concept::HasNumericTraits<OutputImagePixelType>));
00230 itkConceptMacro(SameDimensionCheck,
00231 (Concept::SameDimension<ImageDimension, OutputImageDimension>));
00232 itkConceptMacro(InputIsFloatingPointCheck,
00233 (Concept::IsFloatingPoint<InputImagePixelType>));
00234 itkConceptMacro(OutputIsFloatingPointCheck,
00235 (Concept::IsFloatingPoint<OutputImagePixelType>));
00236
00238 #endif
00239
00240 protected:
00241 CannyEdgeDetectionImageFilter();
00242 CannyEdgeDetectionImageFilter(const Self&) {}
00243 void PrintSelf(std::ostream& os, Indent indent) const;
00244
00245 void GenerateData();
00246
00247 typedef DiscreteGaussianImageFilter<InputImageType, OutputImageType>
00248 GaussianImageFilterType;
00249 typedef MultiplyImageFilter< OutputImageType,
00250 OutputImageType, OutputImageType> MultiplyImageFilterType;
00251
00252 private:
00253 virtual ~CannyEdgeDetectionImageFilter(){};
00254
00256 struct CannyThreadStruct
00257 {
00258 CannyEdgeDetectionImageFilter *Filter;
00259 };
00260
00262 void AllocateUpdateBuffer();
00263
00265 void HysteresisThresholding();
00266
00268 void FollowEdge(IndexType index);
00269
00271 bool InBounds(IndexType index);
00272
00273
00277 void Compute2ndDerivative();
00278
00287
00288
00289
00295 void ThreadedCompute2ndDerivative(const OutputImageRegionType&
00296 outputRegionForThread, int threadId);
00297
00301 static ITK_THREAD_RETURN_TYPE
00302 Compute2ndDerivativeThreaderCallback( void * arg );
00303
00307 OutputImagePixelType ComputeCannyEdge(const NeighborhoodType &it,
00308 void *globalData );
00309
00314 void Compute2ndDerivativePos();
00315
00321 void ThreadedCompute2ndDerivativePos(const OutputImageRegionType&
00322 outputRegionForThread, int threadId);
00323
00327 static ITK_THREAD_RETURN_TYPE
00328 Compute2ndDerivativePosThreaderCallback( void *arg );
00329
00331 ArrayType m_Variance;
00332
00335 ArrayType m_MaximumError;
00336
00338 OutputImagePixelType m_UpperThreshold;
00339
00341 OutputImagePixelType m_LowerThreshold;
00342
00344 OutputImagePixelType m_Threshold;
00345
00347 OutputImagePixelType m_OutsideValue;
00348
00350 typename OutputImageType::Pointer m_UpdateBuffer1;
00351
00353 typename GaussianImageFilterType::Pointer m_GaussianFilter;
00354
00357 typename MultiplyImageFilterType::Pointer m_MultiplyImageFilter;
00358
00361 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00362 m_ComputeCannyEdge1stDerivativeOper;
00363 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00364 m_ComputeCannyEdge2ndDerivativeOper;
00366
00367 std::slice m_ComputeCannyEdgeSlice[ImageDimension];
00368
00369 unsigned long m_Stride[ImageDimension];
00370 unsigned long m_Center;
00371
00372 typename ListNodeStorageType::Pointer m_NodeStore;
00373 ListPointerType m_NodeList;
00374
00375 };
00376
00377 }
00378
00379 #ifndef ITK_MANUAL_INSTANTIATION
00380 #include "itkCannyEdgeDetectionImageFilter.txx"
00381 #endif
00382
00383 #endif
00384
00385