In this tutorial you will learn how to:
Filter out any noise. The Gaussian filter is used for this purpose. An example of a Gaussian kernel of that might be used is shown below:
Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel:
Apply a pair of convolution masks (in and
directions:
Find the gradient strength and direction with:
The direction is rounded to one of four possible angles (namely 0, 45, 90 or 135)
Non-maximum suppression is applied. This removes pixels that are not considered to be part of an edge. Hence, only thin lines (candidate edges) will remain.
Hysteresis: The final step. Canny does use two thresholds (upper and lower):
Canny recommended aupper:lower ratio between 2:1 and 3:1.
For more details, you can always consult your favorite Computer Vision book.
#include"opencv2/imgproc/imgproc.hpp"#include"opencv2/highgui/highgui.hpp"#include<stdlib.h>#include<stdio.h>usingnamespacecv;/// Global variablesMatsrc,src_gray;Matdst,detected_edges;intedgeThresh=1;intlowThreshold;intconstmax_lowThreshold=100;intratio=3;intkernel_size=3;char*window_name="Edge Map";/** * @function CannyThreshold * @brief Trackbar callback - Canny thresholds input with a ratio 1:3 */voidCannyThreshold(int,void*){/// Reduce noise with a kernel 3x3blur(src_gray,detected_edges,Size(3,3));/// Canny detectorCanny(detected_edges,detected_edges,lowThreshold,lowThreshold*ratio,kernel_size);/// Using Canny's output as a mask, we display our resultdst=Scalar::all(0);src.copyTo(dst,detected_edges);imshow(window_name,dst);}/** @function main */intmain(intargc,char**argv){/// Load an imagesrc=imread(argv[1]);if(!src.data){return-1;}/// Create a matrix of the same type and size as src (for dst)dst.create(src.size(),src.type());/// Convert the image to grayscalecvtColor(src,src_gray,CV_BGR2GRAY);/// Create a windownamedWindow(window_name,CV_WINDOW_AUTOSIZE);/// Create a Trackbar for user to enter thresholdcreateTrackbar("Min Threshold:",window_name,&lowThreshold,max_lowThreshold,CannyThreshold);/// Show the imageCannyThreshold(0,0);/// Wait until user exit program by pressing a keywaitKey(0);return0;}
Create some needed variables:
Mat src, src_gray; Mat dst, detected_edges; int edgeThresh = 1; int lowThreshold; int const max_lowThreshold = 100; int ratio = 3; int kernel_size = 3; char* window_name = "Edge Map";Note the following:a. We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*)b. We set the kernel size of :math:`3` (for the Sobel operations to be performed internally by the Canny function)c. We set a maximum value for the lower Threshold of :math:`100`.
Loads the source image:
/// Load an imagesrc=imread(argv[1]);if(!src.data){return-1;}
Create a matrix of the same type and size ofsrc (to bedst)
dst.create(src.size(),src.type());
Convert the image to grayscale (using the functioncvtColor:
cvtColor(src,src_gray,CV_BGR2GRAY);
Create a window to display the results
namedWindow(window_name,CV_WINDOW_AUTOSIZE);
Create a Trackbar for the user to enter the lower threshold for our Canny detector:
createTrackbar("Min Threshold:",window_name,&lowThreshold,max_lowThreshold,CannyThreshold);
Observe the following:
Let’s check theCannyThreshold function, step by step:
First, we blur the image with a filter of kernel size 3:
blur(src_gray,detected_edges,Size(3,3));
Second, we apply the OpenCV functionCanny:
Canny(detected_edges,detected_edges,lowThreshold,lowThreshold*ratio,kernel_size);
where the arguments are:
We fill adst image with zeros (meaning the image is completely black).
dst=Scalar::all(0);
Finally, we will use the functioncopyTo to map only the areas of the image that are identified as edges (on a black background).
src.copyTo(dst,detected_edges);
copyTo copy thesrc image ontodst. However, it will only copy the pixels in the locations where they have non-zero values. Since the output of the Canny detector is the edge contours on a black background, the resultingdst will be black in all the area but the detected edges.
We display our result:
imshow(window_name,dst);
After compiling the code above, we can run it giving as argument the path to an image. For example, using as an input the following image:
Moving the slider, trying different threshold, we obtain the following result:
Notice how the image is superposed to the black background on the edge regions.