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 "itkConstNeighborhoodIterator.h"
00023
#include "itkZeroFluxNeumannBoundaryCondition.h"
00024
#include "itkMultiThreader.h"
00025
#include "itkDerivativeOperator.h"
00026
#include "itkSparseFieldLayer.h"
00027
#include "itkObjectStore.h"
00028
00029
00030
namespace itk
00031 {
00032
00033
00034
template <
class TValueType>
00035 class ListNode
00036 {
00037
public:
00038 TValueType
m_Value;
00039 ListNode *
Next;
00040 ListNode *
Previous;
00041 };
00042
00043
00085
template<
class TInputImage,
class TOutputImage>
00086 class ITK_EXPORT CannyEdgeDetectionImageFilter
00087 :
public ImageToImageFilter<TInputImage, TOutputImage>
00088 {
00089
public:
00091 typedef CannyEdgeDetectionImageFilter
Self;
00092 typedef ImageToImageFilter<TInputImage, TOutputImage> Superclass;
00093
00095 typedef TInputImage
InputImageType;
00096 typedef TOutputImage
OutputImageType;
00097
00099 typedef SmartPointer<Self> Pointer;
00100 typedef SmartPointer<const Self> ConstPointer;
00101
00103 typedef typename TInputImage::PixelType
InputImagePixelType;
00104 typedef typename TOutputImage::PixelType
OutputImagePixelType;
00105 typedef typename TInputImage::IndexType
IndexType;
00106
00109
typedef ZeroFluxNeumannBoundaryCondition<OutputImageType>
00110 DefaultBoundaryConditionType;
00111
00115
typedef ConstNeighborhoodIterator<
OutputImageType,
00116 DefaultBoundaryConditionType>
NeighborhoodType;
00117
00118 typedef ListNode<IndexType> ListNodeType;
00119 typedef ObjectStore<ListNodeType> ListNodeStorageType;
00120 typedef SparseFieldLayer<ListNodeType> ListType;
00121 typedef typename ListType::Pointer
ListPointerType;
00122
00124
itkNewMacro(
Self);
00125
00127 typedef typename TOutputImage::RegionType
OutputImageRegionType;
00128
00130
itkTypeMacro(CannyEdgeDetectionImageFilter,
ImageToImageFilter);
00131
00133
itkStaticConstMacro(ImageDimension,
unsigned int,
00134 TInputImage::ImageDimension);
00135
00137
itkSetVectorMacro(Variance,
double, ImageDimension);
00138
itkGetVectorMacro(Variance,
const double, ImageDimension);
00139
itkSetVectorMacro(MaximumError,
double, ImageDimension);
00140
itkGetVectorMacro(MaximumError,
const double, ImageDimension);
00141
00144
void SetVariance(
const double v)
00145 {
00146
double vArray[ImageDimension];
00147
for (
unsigned int i = 0; i<ImageDimension; ++i) { vArray[i] = v; }
00148 this->SetVariance(vArray);
00149 }
00150
00153
void SetMaximumError(
const double v)
00154 {
00155 double vArray[ImageDimension];
00156
for (
unsigned int i = 0; i<ImageDimension; ++i) { vArray[i] = v; }
00157 this->SetMaximumError(vArray);
00158 }
00159
00160
00161
itkSetMacro(Threshold, OutputImagePixelType );
00162
itkGetMacro(Threshold, OutputImagePixelType);
00163
00165
00166
00167
00168
00169
00170
00171
00172
itkSetMacro(OutsideValue, OutputImagePixelType);
00173
itkGetMacro(OutsideValue, OutputImagePixelType);
00174
00182
virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError);
00183
00184 protected:
00185 CannyEdgeDetectionImageFilter();
00186 CannyEdgeDetectionImageFilter(const Self&) {}
00187
void PrintSelf(std::ostream& os, Indent indent)
const;
00188
00189 void GenerateData();
00190
00191
private:
00192
virtual ~CannyEdgeDetectionImageFilter(){};
00193
00195
struct CannyThreadStruct
00196 {
00197 CannyEdgeDetectionImageFilter *Filter;
00198 };
00199
00201
void AllocateUpdateBuffer();
00202
00204
void HysteresisThresholding();
00205
00207
void FollowEdge(IndexType index);
00208
00210
bool InBounds(IndexType index);
00211
00212
00216
void Compute2ndDerivative();
00217
00226
00227
00228
00234
void ThreadedCompute2ndDerivative(
const OutputImageRegionType&
00235 outputRegionForThread,
int threadId);
00236
00240
static ITK_THREAD_RETURN_TYPE
00241 Compute2ndDerivativeThreaderCallback(
void * arg );
00242
00246 OutputImagePixelType ComputeCannyEdge(
const NeighborhoodType &it,
00247
void *globalData );
00248
00253
void Compute2ndDerivativePos();
00254
00260
void ThreadedCompute2ndDerivativePos(
const OutputImageRegionType&
00261 outputRegionForThread,
int threadId);
00262
00266
static ITK_THREAD_RETURN_TYPE
00267 Compute2ndDerivativePosThreaderCallback(
void *arg );
00268
00270
double m_Variance[ImageDimension];
00271
00274
double m_MaximumError[ImageDimension];
00275
00277 OutputImagePixelType m_UpperThreshold;
00278
00280 OutputImagePixelType m_LowerThreshold;
00281
00283 OutputImagePixelType m_Threshold;
00284
00286 OutputImagePixelType m_OutsideValue;
00287
00289
typename OutputImageType::Pointer m_UpdateBuffer;
00290
typename OutputImageType::Pointer m_UpdateBuffer1;
00291
00294 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00295 m_ComputeCannyEdge1stDerivativeOper;
00296 DerivativeOperator<OutputImagePixelType,itkGetStaticConstMacro(ImageDimension)>
00297 m_ComputeCannyEdge2ndDerivativeOper;
00298
00299 std::slice m_ComputeCannyEdgeSlice[ImageDimension];
00300
00301
unsigned long m_Stride[ImageDimension];
00302
unsigned long m_Center;
00303
00304
typename ListNodeStorageType::Pointer m_NodeStore;
00305 ListPointerType m_NodeList;
00306
00307 };
00308
00309 }
00310
00311
#ifndef ITK_MANUAL_INSTANTIATION
00312
#include "itkCannyEdgeDetectionImageFilter.txx"
00313
#endif
00314
00315
#endif
00316