Basic Edge Detection in Python

December 5th, 2007

Detecting edges in images is being actively researched for many different applications. The most notable of these applications is computer vision. The reason I began studying edge detection algorithms, aside from them being really cool, is that I’ve been noticing that I can use edge detection as part of my toolbox for optical character recognition.

So, how do we define edges in any given image? Edges are really just areas where the pixels intensities contrast. Basically where you have a bunch of light pixels touching a bunch of dark pixels. There are a couple different methods used for detecting edges: gradient and Laplacian. I’m going to be covering a basic gradient edge detection technique and will cover Laplacian techniques in future posts.

Gradient edge detection approximates the first derivative of the image, looking for minimum and maximum intensities in the magnitude of the gradient. Locating edge pixels can be done by setting a threshold of some value and testing if the gradient is greater than that threshold.

The gradient of the image function I is given by the vector:

ߜ I = [∂I / ∂x, ∂I / ∂y]

To approximate the first derivative of the image, we use convolution masks. The method I’m going to present is the Prewitt method. It uses two masks to approximate ∂I / ∂x and ∂I / ∂y, giving us a gradient of the image’s pixels. ∂I / ∂x and ∂I / ∂y detect vertical and horizontal edges, respectively. The masks that define ∂I / ∂x and ∂I / ∂y for the Prewitt operator are:

∂I / ∂x:
[-1, 0, 1]
[-1, 0, 1]
[-1, 0, 1]

∂I / ∂y:
[1, 1, 1]
[0, 0, 0]
[-1, -1, -1]

The resulting outputs of convolving the image with these masks are then added to get the magnitude of the gradient. The magnitude of the gradient is given by:

|G| = sqrt(Gx2 + Gy2)


To approximate the magnitude of the gradient, we use:

|G| = |Gx| + |Gy|

After getting the magnitude of the gradient, we want to check if it’s larger than our threshold. All the methods I’ve seen use a threshold of 255. What this means is that when the magnitude of the gradient is larger than 255, we’ve found an edge. We cap the magnitude to 255 if it’s larger than 255 and mark the pixel in the output image as a 0, which is black. This is done implicitly by setting the pixel value to 255 - magnitude, meaning if the magnitude is 255, the pixel value is black. Magnitudes of 0 will set the pixel to 255 - 0, which is white. The magnitudes can be any value between 0 and 255, inclusive.

The Prewitt masks in Python are given by the function get_prewitt_masks():

Now on to the meat of the entire operation. The prewitt() function takes a 1-d array of pixels and the width and height of the input image. It returns a greyscale edge map image.

You can store this code all in one file so when you run it, you can pass the program arguments for the input and output image filenames on the command line. To do so, add this code to the Python file with the edge detection code from earlier:

I called my file prewitt.py, so with all that code in the same file, you can call it from the command line:

$ python prewitt.py input_image.gif output_image.gif

Note that it will work for pretty much any image type you give it. Here are some results of me running the code above:

I suppose that concludes this article on basic edge detection using the Prewitt method. Hope you enjoyed reading it as much as I enjoyed writing it!

8 Responses to “Basic Edge Detection in Python”

  1. Peter Says:

    very cool code !!

    If you run it with psyco you would be amazed by the performance gain.
    (install psyco and insert two lines in your code at the top
    import psyco
    psyco.full())

    If you would replace ‘magnitude’ with ’sum’ you would be amazed by the funcionality ;-)

    For non-programmers : replace the word “magnitude” with the word “sum” throuhgout the code or is does nothing.

    still Very Cool Code !

  2. David Reynolds Says:

    Thanks for the comment. I’ve been meaning to look into psyco for awhile now. Will have to run some tests with it when I get more time.

  3. Dinu Gherman Says:

    Cool code, but it has a tiny bug. If you replace this:

    magnitude = abs(sumX) + abs(sumY)

    with:

    sum = abs(sumX) + abs(sumY)

    then it works as expected. BTW, it would be nice to provide a real file, so people don’t need to copy and paste, which is error-prone…

    Dinu

  4. David Reynolds Says:

    Editing code in wordpress is a pain in the ass. I changed all the sum references to magnitude since sum is a python function. I’ll hopefully get some files uploaded so people can download them. Thanks for the suggestion.

  5. nate Says:

    “∂I / ∂x and ∂I / ∂y detect vertical and horizontal edges, respectively.”

    I do not follow how these partials detect vertical and horizontal edges. Can you elaborate on this or point me to some more details. I am new to image processing and I am trying to detect only horizontal or vertical straight lines in an image.

  6. David Reynolds Says:

    nate: it’s been awhile since I’ve done any kind of image processing stuff, but this is one site I got a ton of information from: http://www.pages.drexel.edu/~weg22/edge.html

    I hope that helps. Feel free to email me if you need more help.

  7. 0x666 Says:

    nate:
    Edge - is zone where color intensity suddenly drops or raises. In mathematical terms - there is intensity extremum. Extremums in functions are found by differentiating these functions. In this case -> dI/dx = 0 or dI/dy = 0. This is because at intensity maximum (or minimum) intensity changes is minimal (or zero).

  8. Amutha pandian Says:

    sir
    this is also very nice im dong my pg project shape recognation its very useful to me

Leave a Reply