I'm confused by this line of code:
src.copyTo( dst, detected_edges);
What you are doing is writing into dst
, at the location of the detected edges, the pixel value of the original input image src
.
By definition, the location of the edge is somewhere half-way the transition between two more or less uniformly colored regions. Half-way you should see a color half-way between the colors of those two regions. Why is this color interesting enough to preserve in your output? What if at the location of the transition the pixel value happens to be 0?
The purpose of the Canny edge detector is to detect the location of edges. It returns a binary image where the pixels at edges are set. These locations are found by using hysteresis thresholding (a two-threshold process) of an image where the pixel values were the edge strength. That is, there is an intermediate image where the intensity of the pixel is related to the contrast at the edge. Maybe you want to recover that image? If so, you'd have to copy-paste the code inside the Canny function, and leave out the last step, the thresholding.
This line:
blur( src_gray, detected_edges, Size(3,3) );
is not necessary. You should be able to get the same effect by increasing the apertureSize
parameter to cv::Canny
. Also, a box filter is the worst type of blur filter you can apply. Here I wrote up a bit explaining what is so bad about the box filter. One of the consequences of using a box filter before detecting edges is that you might find false edges.
For best precision you'd use a Gaussian filter, and then set the apertureSize
parameter to 1 to avoid further smoothing inside the cv::Canny
function.
You also get better results if you set the L2gradient
input parameter to true
. This makes the function use the correct definition of norm, which leads to a more rotationally-invariant filter (this means that you will get more similar results if you rotate your image by 45 degrees, apply the filter, and then rotate the result back).
Combining the previous point and this point, you'd end up doing:
GaussianBlur( src_gray, detected_edges, Size(0,0), 2 )
Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, 1, true );
Regarding style:
Try to be consistent with spacing and so on. It makes it easier to read code. For example these three consecutive lines:
dst = Scalar::all(0);
src.copyTo( dst, detected_edges);
imshow( window_name, dst );
The first line has no spaces inside the parentheses, the second one only after the opening parenthesis, and the third one inside both.
A similar thing happens with the closing brackets: each one in your bit of code is on a different column.
Finally, I would suggest that you don't do
using namespace cv;
and instead explicitly write cv::
in front of each OpenCV function call. This makes it explicit where the function that you're calling comes from. This is a small program, and you only call one function that is not from OpenCV, but as your program grows, you'll have more self-written functions and maybe also call functions from a second library. Using explicit namespaces will make reading your code a lot easier.
Regarding "detecting all the edges correctly":
This depends on your definition of edge. The Canny edge detector detects all the edges correctly, using its definition of edge.
If you define "edges" as the edges of all objects in the image, then it is not possible to detect them all. You can only detect edges if the contrast between the object and the background is large enough. A black object on a black background will not have any "edges" (edges according to Canny's definition) along its "edges" (the actual object's edges). If you are interested in detecting these type of edges, I recommend that you closely follow the latest research publications in the field, maybe one day someone will discover how to do this. :)