Canny Edge Detection
1 july 2007, Simon Strandgaard
WARNING: this is a work in progress. This is NOT a reference of how canny is supposed to work, because I havn't gotten it right yet. Please take a look at the non-maximum suppression step and tell me what wrong with it. If you have image-data of how its supposed to look, then I am terrible interessed.
I have roughly followed this document (except 1/115 had to be 1/159):
http://www.pages.drexel.edu/~weg22/can_tut.html.
Found a better text about canny:
http://idlastro.gsfc.nasa.gov/idl_html_help/CANNY.html.
article that describes non-maximum suppression:
http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MARBLE/low/edges/canny.htm.
here is images of each step, so we can check if we are doing it right:
http://robotics.eecs.berkeley.edu/~mayi/imgproc/cademo.html
http://cs.nyu.edu/~cil217/Vision/vision_edge_detector.htm
interactive canny filter
http://matlabserver.cs.rug.nl/cgi-bin/matweb.exe.
STEP1: gaussian blur
Converted to grayscale by adding red + green + blue. Then applied a 5x5 filter.
STEP2: deltax
Measure horizontal changes by applying a 3x3 filter to the output from step1.
STEP3: deltay
Measure vertical changes by applying a 3x3 filter to the output from step1.
STEP4: gradient
Measure length of deltax and deltay using pythagoras.
STEP5: direction
Find the direction of deltax and deltay. Remap from degrees into the range 0 to 4.
if the gradient is zero then use a value of 0
0 .. 22.5 is remapped into 1
22.5 .. 67.5 is remapped into 2
67.5 .. 112.5 is remapped into 3
112.5 .. 157.5 is remapped into 4
157.5 .. 180 is remapped into 1
AFAIK directions is only used when doing nonmaximum suppression. Is this correct?
STEP6: nonmaximum suppression
I need more info about how this step is supposed to work. My understanding is that one needs to identify possible-edge-pixels.
How is output supposed to look in this step?
for(int y=1; y<height-1; ++y)
for(int x=1; x<width-1; ++x) {
int dir = _step5_direction[y * width + x];
if(!dir) continue;
// choose 2 neighbour pixels depending on
// our own orientation.
int i = 0;
int j = 0;
switch(dir) {
case DIRECTION_0: i = 1; j = 0; break;
case DIRECTION_45: i = 1; j = 1; break;
case DIRECTION_90: i = 0; j = 1; break;
case DIRECTION_135: i = -1; j = 1; break;
}
int a = _step4_gradient[(y + j) * width + x + i];
int b = _step4_gradient[(y - j) * width + x - i];
int center = _step4_gradient[y * width + x];
/*
we got an edge if the centerpixel has the greatest magnitude.
example: 0, 2, 4 in this case the magnitude
is increasing. so the centerpixel is not an edge.
example: 5, 8, 3 in this case we got an edge.
*/
if((center >= a) && (center >= b)) {
_step6_max[y * width + x] = 1;
}
}
STEP7: thresholding
Start tracking when a gradient pixel is greater than upper threshold.
Stop tracking when a gradient pixel is below the lower threshold.
Tracking is a recursive operation where you look at the 8 neighbour pixels. If the conditions is satisfied for a pixel then tracking is repeated with that pixel in the center.
I'm looking for something more sensitive to color changes. I wonder if there is a good RGB edge detection algorithm.