'Canny edge detection does not detect 100% horizontal/un-rotated lines
Is the Canny edge detection supposed to not detect pure, non-rotated horizontal lines?
These are the input images:
Left: 100% horizontal (non-rotated) non-blurry lines
Right: the same image 1° rotated
The corresponding output "edges" images:
(Images scaled here 2x with no smoothing for better judging.)
The images were processed with thresholds low=250x0.66 and high=250x1.33 and kernel size k=3.
While the ladder image generated quiet satisfying results, the former image does not.
The images were not further pre-processed at the moment, what you see is what's going into Canny.
I created the first image as test data. It might be a constructed case, although such lines might occur in real world scenarios.
MCVE:
public class q58884116 {
public static void main(String[] args) throws Exception {
System.load(new File(Paths.get("target", "classes", "libopencv_java412.so").toString()).getAbsolutePath());
File inFile = new File(args[0]);
File outFile = new File(args[1]);
Mat imageColor = Imgcodecs.imread(inFile.getAbsolutePath(), Imgcodecs.IMREAD_COLOR);
Mat patternProbeImage = new Mat();
Imgproc.cvtColor(imageColor, patternProbeImage, Imgproc.COLOR_BGR2GRAY);
Mat edges = new Mat();
// Value determined from histogram in Gimp.
Imgproc.Canny(patternProbeImage, edges, 250 * 0.66, 250 * 1.33, 3, true);
Imgcodecs.imwrite(outFile.getAbsolutePath(), edges);
}
}
The input image (unscaled): input.png
- Compiled from Git
- OpenCV 4.1.2
- cmake 3.7.2
- gcc 6.3.0
- openjdk 1.8.0_232
- Using the Java library.
The build steps:
$ git clone https://github.com/opencv/opencv.git
$ cd opencv/
$ git checkout 4.1.2
$ cd cmake/
$ cmake -DCMAKE_INSTALL_PREFIX="/opt/opencv" ..
$ make -j4
$ make install
I must admit, I'm not familiar with the theories behind Canny or even computer vision in general. I'm just getting started with it. Although I can imagine this might be caused by the row of zeros of the Gy matrix used by the Sobel function (which was mentioned in Canny function articles).
If this is indeed a limitation of Canny, what are usual approaches to handle such scenarios (in short)?
I approached this empirically: I've created a white to black gradient image with a black grating pattern on top of it. The grating shall represent the lines of the original test image on top of different backgrounds.
This is our input image:
(Cropped and resized for prettier post, download original.)
The MCVE is extended to generate edges for a variety of threshold ranges (not every possible combination there is, but a fair amount):
for (int i = 0; i < 255 - 50; i++) {
Mat edges = new Mat();
Imgproc.Canny(patternProbeImage, edges, i, i + 50, 3, true);
Imgcodecs.imwrite(getOutputFile(outFile, "lb-0-" + String.format("%03d", i)).getAbsolutePath(), edges);
}
We can then inspect the generated edges.
With this one liner a mosaic (sprite) of all images was generated for easier inspection:
$ convert gradient-grating.out.lb-0-*.png +append gradient-grating.out.lb.png
This is the result:
As one can see, Canny was unable to detect more and more edges on the minimum value side (top) with increasing lower thresholds. I expected this. Though on the maximum value side, Canny was never able to detect edges, no matter what thresholds were given.
Solution 1:[1]
Try saving the image and then opening the image file directly. It may simply be an issue with how the plotter is rendering the image.
I had the same issue myself, but solved it. I was viewing my edge image through a jupyter notebook, using matplotlib. The 100% horizontal edges would not render when displayed inside the notebook. But when I saved it to png and opened the image file directly, the horizontal edges were in fact there.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | funky-phyllo |






