Search code examples
opencvcanny-operator

Can I eliminate these 'jaggies' from Canny edge detection?


In my application of a Canny edge detector (from OpenCV), I've run into an annoyance where I get slight jagged edges where I would prefer straight ones. Below is an example based on a simple distillation of the situation. My actual application includes lines at other angles than 0/90/180/270 degrees, but the effect is quite similar whenever lines are nearly parallel to the X/Y axes.

My input images often have a slight gradient in the direction orthogonal to the straight line, and I think this the basic source of the problem. I did some digging through code and debugging in OpenCV and have mostly convinced myself that the problem is inherent to the way that the Canny algorithm works, rather than OpenCV's particular implementation of it, but I still haven't completely given up on Canny.

I have tried Arrayfire's Canny implementation and got similar-but-worse results, and I've tried applying a blur to the edge output to make the effect less pronounced, but the results are still not ideal.

from PIL import Image, ImageDraw
import numpy as np
import cv2 as cv

cross_img = Image.new('L', (500, 500))
d = ImageDraw.Draw(cross_img)
for i in range(500):
    c = 60 + i / 10
    d.line(((240, i), (260, i)), int(c))
    d.line(((i, 240), (i, 260)), int(c))
npimg = np.asarray(cross_img)
cannpimg = np.zeros_like(npimg)
cv.Canny(npimg, 200, 400, cannpimg)
canimg = Image.fromarray(cannpimg)

cross_img.save('/tmp/cross.png')
canimg.save('/tmp/can.png')

Input image Canny output


Solution

  • You're right, the jaggies are due to the way Canny Edge detection handles this case of an edge defined by a gradient which is in a different direction than said edge. You can run a gray level transform on the image before running canny, which squashes all gradient values to white and black values remain black.