Edge detection is an essential image analysis technique when someone is interested in recognizing objects by their outlines, and is also considered an essential step in recovering information from images.
For instance, important features like lines and curves can be extracted using edge detection, which are then normally used by higher-level computer vision or image processing algorithms. A good edge detection algorithm would highlight the locations of major edges in an image, while at the same time ignoring any false edges caused by noise.
But what are edges anyway? Edges are image features that can be used in estimating and analyzing the structure of objects in an image. They represent significant local changes that happened in the image intensity (i.e. pixel value). Edges normally occur on the boundary between two different regions in the image.
In this tutorial, I’m going to describe the Canny edge detector algorithm, and how we can implement it in Python.
Canny Edge Detector
The Canny edge detector algorithm is named after its inventor, John F. Canny, who invented the algorithm in 1986. The Canny edge detector normally takes a grayscale image as input and produces an image showing the location of intensity discontinuities as output (i.e. edges).
I don’t want to go mathematical here, but I will describe what’s going on behind the scenes in the Canny edge detector algorithm from a high-level viewpoint.
The first thing the Canny edge detector does is that it uses Gaussian convolution to smooth the input image and remove noise. A first derivative operator is then applied to the smoothed image in order to highlight those regions of the image with high first spatial derivatives.
The algorithm then finds both the gradient magnitude and direction by calculating the x-derivative and the y-derivative, especially since knowing the direction of the gradient actually enables us to find the direction of the edges.
The algorithm then performs what’s called non-maximal suppression, where it tracks along the top of the ridges that rise from the edges, and sets those pixels that are not on the ridge top to zero, eventually producing a thin line in the result.
In other words, we check if the gradient calculated in the previous step is considered the maximum among the neighboring points lying in both the positive and negative directions of the gradient. If the gradient was the maximum, it is considered to be part of the edge, and vice versa.
The tracking process above is controlled by two thresholds, t1
and t2
, such that t1>t2
, referred to as hysteresis thresholding. Tracking begins at a point on the ridge higher than t1
, and then continues in both of the directions out of that point until the height of the ridge becomes less than t2
.
So, basically, what happens here is that we select all the edge points that are above the upper threshold t1
, and then investigate if there are neighbors of these points which are considered below the upper threshold t1
and above the lower threshold t2
. In this case, such neighbors would be part of the edge.
Thus, the width of the Gaussian kernel used for smoothing the input image, and the t1 (upper) and t2 (lower) thresholds used by the tracker, are the parameters that determine the effect of the canny edge detector.
Python Implementation
In this section, I will describe two ways in which we can implement the Canny edge detector. One way uses the scikit-image
library, and the other uses the OpenCV
library.
Canny Edge Detector Using scikit-image
If you don’t have scikit-image
already installed on your machine, go ahead and install it by following the instructions shown on the installing scikit-image page.
As I’m using an Ubuntu
machine, I simply had to run the following command in my Terminal to get the library up and running:
sudo apt-get install python-skimage
The scikit-image
library has a canny()
function which we can use to apply the Canny edge detector on our image. Notice that the function is part of the feature
module.
Before moving forward, let’s use a toy image to experiment with. You can use any image though. I’m going to use the boat.png image shown below (click on the link to download the image):
Without further ado, let’s see how we can detect the edges in the above image (i.e. boat) using the Canny edge detector. Remember that our image needs to be grayscale. Since our image is already grayscale, we don’t need to do anything at this point, such as converting the image from color to grayscale. The script for the Canny edge detector looks as follows:
from skimage import io from skimage import feature im = io.imread('boat.png') edges = feature.canny(im) io.imshow(edges) io.show()
So, as you can see, we first read our image, boat.png
. After that, we apply the canny()
function on the image (I didn’t pass any custom parameters, except our image, and left it at the function’s defaults). Finally, we display our result that shows the detected edges. The result of the above script looks as follows:
You can play around with the parameters to get different results on how edges are detected. But the result looks nice with those detected edges, doesn’t it?!
Canny Edge Detector Using OpenCV
In this section, we are going to see how we can use OpenCV
to apply the Canny edge detector on our boat image. If you don’t have OpenCV installed yet, go ahead and install it. You can check the following articles on how you can install OpenCV
on your machine. I have included different articles for different operating systems:
- Ubuntu 16.04: How to install OpenCV
- Install OpenCV-Python in Windows
- Install OpenCV 3 on macOS
As with the scikit-image
library, OpenCV
also has a function called canny()
to apply the Canny edge detector algorithm on the image. The following script shows how we can use OpenCV
to find the edges in our image:
import cv2 import matplotlib.pyplot as plt im = cv2.imread('boat.png') edges = cv2.Canny(im,25,255,L2gradient=False) plt.imshow(edges,cmap='gray') plt.show()
Notice that I have passed the following as arguments to the Canny()
function:
-
im
: image name -
lower threshold
: 25 -
upper threshold
: 255 -
L2gradient=False
: this means that the L1-norm is used. If set toTrue
, the L2-norm will be used.
The matplotlib
library has then been used to plot the results. To learn more about this library, check my tutorial: Introducing Python’s Matplotlib Library.
The result of the above script is as follows:
Conclusion
In this tutorial, we have learned about the Canny edge detector and seen how the scikit-image
and OpenCV
libraries enable us to easily implement this detector with a few lines of code.
Powered by WPeMatico