00001 #ifndef gevd_fold_h_ 00002 #define gevd_fold_h_ 00003 //: 00004 // \file 00005 // \brief detection of fold profiles in the intensity image 00006 // 00007 // Operator to implement Canny edge detector which finds elongated 00008 // fold/roof contours with ddG. Then junctions are found by extending 00009 // from end points of dangling contours. 00010 // 00011 // The recipe is: 00012 // - Convolution with Gaussian with sigma typically = 1, 00013 // to well-condition the surface before taking second derivative. 00014 // Result is a smoothed image. 00015 // 00016 // - Convolution with Laplacian, or second difference. 00017 // Result is a gradient image. Canny proves that first-derivative 00018 // of the Gaussian is the optimum filter to detect elongated 00019 // step profiles. 00020 // 00021 // - Optionally estimate sensor/texture sigma, if given noise 00022 // sigma is a negative interpolation factor -k in range -[0 1]. 00023 // noise_sigma = (1-k)*sensor_sigma + k*texture_sigma. 00024 // Sensor and texture sigmas are estimated from the histogram 00025 // of weak step edges, detected in an ROI centered on gradient image. 00026 // (see Step constructor documentation in Step.C - JLM) 00027 // 00028 // - Non Maximum suppression in the direction of local Hessian, 00029 // to detect pixels with maximum local curvature, above a priori 00030 // noise response. Result is connected contours, width < 2, 00031 // broken only at junctions with weaker chains. 00032 // Also obtain subpixel accuracy normal to the contour. 00033 // 00034 // - Optionally extend from end points of contours to search for 00035 // maximum curvature in the direction normal to the dangling contours, 00036 // above some factor of the noise response. 00037 // Result is a simple detection of all strong junctions. 00038 // 00039 // Input: Intensity image, smoothing sigma, sensor/texture noise sigma 00040 // and threshold factors for detecting contour/junction edge elements. 00041 // 00042 // Output: Magnitude, direction, location of fold pixels, forming 00043 // a connected network of contours. 00044 // 00045 // Complexity: O(|pixels|) time and space for convolutions. 00046 // O(|edgels|) time for iterative extension to recover junctions. 00047 // 00048 // \verbatim 00049 // Authors 00050 // John Canny (1986) SM Thesis 00051 // Chris Connolly (1987) use directional 1st-difference 00052 // Van-Duc Nguyen (1989) add subpixel location, extension to find junctions 00053 // Arron Heller (1992) translate from CLOS to C++ 00054 // Van-Duc Nguyen (1995) add noise estimation, use FloatOperators. 00055 // Joe Mundy (1997) Added strength and direction arrays for transfer to 00056 // edgel chains. The flag "transfer" controls the 00057 // setting of these arrays. Note difference with 00058 // gevd_step.h.. Didn't want to affect global use of 00059 // DetectEdgels. 00060 // \endverbatim 00061 //----------------------------------------------------------------------------- 00062 00063 #include <vcl_iosfwd.h> 00064 class gevd_bufferxy; 00065 00066 class gevd_fold 00067 { 00068 public: 00069 //: Save parameters and create workspace for detecting fold profiles. 00070 // High frequency features are smoothed away by smooth_sigma. 00071 // Texture or white noise less than noise_sigma are not detected. 00072 // smooth_sigma = 0.5-2.0, 1.0 insures separation of independent folds >= 2. 00073 // noise_sigma = is standard deviation of intensity, in a uniform region. 00074 // Optionally estimate sensor/texture sigma, if given noise sigma 00075 // is a negative factor -k between -[0 1]. In this case, 00076 // noise_sigma = (1-k)*sensor_sigma + k*texture_sigma. 00077 // Response of white noise to the filter ddG is computed, and 00078 // then multiplied by contour_factor/junction_factor to obtain 00079 // thresholds for detecting contour/junction edges. 00080 // 00081 gevd_fold(float smooth_sigma=1, //!< spatial smoothing [0.5 2.0] 00082 float noise_sigma=-0.5, //!< sensor/texture intensity noise -[0 1] 00083 float contour_factor=1.0, //!< threshold factor for contour edgels 00084 float junction_factor=1.5); //!< threshold factor for junction edgels 00085 00086 //: Free space allocated for detecting fold profiles. Does nothing. 00087 ~gevd_fold() {} 00088 00089 static gevd_bufferxy* null_bufferxy; 00090 00091 //: Detect fold profiles with ddG edge detector. 00092 // The image is convolved with a Gaussian to smooth away 00093 // high frequency noise, and insure separation of fold responses. 00094 // Then the largest absolute eigenvalue, and corresponding eigenvector 00095 // of the local Hessian are computed 00096 // using second difference [+1 -2 +1]. 00097 // Optionally estimate sensor/texture sigma and set threshold. 00098 // Finally, non maximum suppression is done to find strict 00099 // local maxima of curvature. 00100 // The edge detector finds elongated contours only. 00101 // These contours are typically broken at junctions because non 00102 // maximum suppression is done along only the strongest direction. 00103 // Return contour (float), direction (byte), location (float) images. 00104 // Return true if no exception. 00105 // J. Canny, A Computational Approach to Edge Detection, 00106 // IEEE Trans on PAMI, vol 8, no 6, Nov 1986. 00107 bool DetectEdgels(const gevd_bufferxy& image, //!< float image 00108 gevd_bufferxy*& edgels, //!< strength = dG * I 00109 gevd_bufferxy*& direction, //!< direction % PI/4 00110 gevd_bufferxy*& locationx, //!< subpixel loc 00111 gevd_bufferxy*& locationy, 00112 bool peaks_only = false, 00113 bool valleys_only = false, 00114 bool transfer = false, //if true, fill mag and angle arrays 00115 gevd_bufferxy*& mag = null_bufferxy, // d2G magnitude 00116 gevd_bufferxy*& angle = null_bufferxy); //Gradient orientation 00117 00118 //: 00119 // Find junctions by searching for extensions of contours from 00120 // their dangling end points. Non maximum suppression insures that 00121 // contours have width < 2, and so we can find the left/right neighbors, 00122 // and deduce end points. By using a minimally smoothed image, 00123 // we find fold profiles up to joining with a stronger contour, thus 00124 // recovering the missing junction caused by NMS along only 1 direction. 00125 // The junctions are returned but are not set in the contour image, 00126 // to prevent incorrect tracing of stronger contours first. 00127 int RecoverJunctions(const gevd_bufferxy& image, //!< iterative extension 00128 gevd_bufferxy& edgels, //!< from end points of contours 00129 gevd_bufferxy& direction, 00130 gevd_bufferxy& locationx, gevd_bufferxy& locationy, 00131 int*& junctionx, int*& junctiony); 00132 00133 //: query stored/estimated noise sigma 00134 // Return the standard deviation of raw noise, in the original image, 00135 // either estimated or given by the user. If the noise has not been 00136 // estimated, return 0. 00137 float NoiseSigma() const; 00138 00139 //: response of noise sigma to filter ddG 00140 // Compute response of white noise through the filter ddG, or 00141 // second-derivative of the Gaussian. Using a threshold of 3 times 00142 // this noise response would eliminate 99% of the noise edges. 00143 float NoiseResponse() const; 00144 00145 //: elongated/directional? 00146 // Return threshold for detecting contour or junction, 00147 // which is response of white gaussian noise, noise_sigma, 00148 // to fold edge detector, i.e. second-order derivative of Gaussian, 00149 // smooth_sigma. 00150 // noise_sigma can be estimated by finding the standard deviation 00151 // in a region of constant intensity, and no texture patterns. 00152 // Use short_factor*noise_sigma and smooth_sigma/2, when detecting 00153 // junctions, to account for multiple responses to fold edge detector. 00154 float NoiseThreshold(bool shortp=false) const; 00155 00156 //: 00157 // Compute response of white noise through the filter ddG, or 00158 // second-derivative of the Gaussian. Using a threshold of 3 times 00159 // this noise response would eliminate 99% of the noise edges. 00160 static float NoiseResponseToFilter(float noiseSigma, 00161 float smoothSigma, 00162 float filterFactor); 00163 00164 friend vcl_ostream& operator<<(vcl_ostream& os, const gevd_fold& st); 00165 friend vcl_ostream& operator<<(vcl_ostream& os, gevd_fold& st); 00166 00167 protected: 00168 float smoothSigma; //!< spatial smoothing 00169 float noiseSigma; //!< sensor/texture noise 00170 float contourFactor, junctionFactor; //!< threshold factor for edgels 00171 float filterFactor; //!< factor in convolution filter 00172 }; 00173 00174 #endif // gevd_fold_h_