As promised in my previous post and in response to a comment , here is a step by step explanation of the Canny Edge Detector. I have some images from a previous post available here.
Firstly we need to apply a Gaussian Point Spread Function (PSF) to our image. This will make the image seem slightly blurry. Increasing the width of the filter will of course increase the blurriness of the image. A wider filter tends to cause the Canny Edge detector to detect longer smoother lines while a narrow filter allows it to find shorter lines.
I almost always use a Gaussian filter of 5x5 with a sigma of 1.4 which gives a matrix of:
2 4 5 4 2
4 9 12 9 4
5 12 15 12 5
4 9 12 9 4
2 4 5 4 2
I find it gives generally nice results and finds enough detail for my purposes. If you looking for more regular / longer features its worth trying a wider filter.
Don't forget to multiple your result by the reciprocal of the sum of the entries in your matrix. For this one its 1/159. And remember to NOT write the result back to your source image while you are still busy calculating.
The Canny edge detector is quite sensitive to noise in an image so the above stage of making the image blurry does help in this regard.
Next step is to actual find some edges. The sobel edge detector is probably the most commonly used one but you can use others.
The sobel matrix (kernel) for calculating an approximate to the derivative in the y direction is:
1 2 1
0 0 0
-1 -2 -1
after we convolve with the image (essentially mutiply with the source image and then add together and store the result) we call this Gy.
Do the same in the x direction using the following kernel:
1 0 -1
2 0 -2
1 0 -1
(notice it is the same as the y kernel but is sensitive to changes in x direction) We call this Gy.
Basically we have estimated the rate of change of values in the underlying image (derivative) to get the edges which are areas where values change rapidly. This implies higher values in the result indicate regions of more rapid change.
So we now have a estimate of the first derivative for the x and y directions for each point, using this we can calculate the angle at the point using:
theta = arctan (Gy/Gx)
And the gradient strength or magnitude (G) by:
G = sqrt ( Gx^2 + Gy^2) ie the distance from 0 in both directions
Generally theta is rounded to the vertical, horizontal and diagonal directions but you dont need to do this if you are trying to make something more senstive to different angles.
Non maximal suppression can now be applied to the image to get rid of any additional "angle" noise. We do this by checking if the gradient magnitude is a local maximum in the gradient direction. Do this by passing a nxn window (typically 3x3) over the results from the previous stage. This last step serves to make the edges more defined.
I hope this more in depth explanation helps explain the process a bit better. I have left out implementation / optimization as they are quite dependant on your underlying architecture. A good article for optimizing a "blur" filter on a CUDA capable GPU is here.
Remember you can use any PSF (blur function) and any edge detector function. I have only shown the most common (Gaussian and Sobel) here.