As suggested above, the Matlab Canny edge detector calculates the gradient using a "derivative of a Gaussian filter" (as stated in the documentation). In other words, Matlab does a Gaussian blur of the image and then finds the gradient of that smoothed image... all using a single fancy filter. [If you want to know the details, just type in
edit edge as Andrey suggested, and then scroll down to the
The blurring operation significantly reduces the amount of noise present in the image, eliminating many spurious edges and leaving behind the good stuff.
Unfortunately, the OpenCV Canny function doesn't let you change the filter kernel it uses via the function parameters. However. You can generate the same results by first blurring the input image, and then passing this blurred image into the Canny function.
This significantly cleans up the resulting edge map. To blur the input image, I personally use OpenCV's
GaussianBlur() function with
sigmaX=2. This mimics the default sigma in Matlab. The best blurring kernel size can vary from case to case, but in Matlab it is calculated using
filterLength = 8*ceil(sigma);, so for a sigma of 2 that would mean a kernel size of
Since both the Gaussian Blur and Sobel filters are linear, passing a blurred input image to the OpenCV
Canny() function is mathematically equivalent to what Matlab does because of the principle of superposition, as demonstrated in this pseudocode (note:
* is the convolution operator):
// The Matlab method: the sobel and blur operations are combined into
// a single filter, and that filter is then convolved with the image
matlabFancyFilter = (sobel * blur);
gradient = matlabFancyFilter * image;
// Equivalent method: image is first convolved with the blur filter, and
// then convolved with the sobel filter.
gradient = sobel * (blur * image); // image is filtered twice
There is an OpenCV Canny tutorial here that demonstrates how to do this using C++. I'm a python guy, so here is what I do:
smoothedInput = cv2.GaussianBlur(image, (7,7), 2);
edges = cv2.Canny(smoothedInput, 25, 50);