Title: Zero-parameter, automatic Canny edge detection with Python and OpenCV - PyImageSearch

URL Source: https://pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/

Published Time: 2015-04-06T14:00:37+00:00

Markdown Content:
Today I’ve got a little trick for you, straight out of the PyImageSearch vault.

[![Image 1: Figure 2: Applying automatic Canny edge detection to a picture of a camera. Left: Wide Canny edge threshold. Center: Tight Canny edge threshold. Right: Automatic Canny edge threshold.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20970%20546'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/01/auto_canny_camerapng.png)

This trick is really awesome — and in many cases, it **_completely_ _alleviates_** the need to tune the parameters to your Canny edge detectors. But before we get into that, let’s discuss the Canny edge detector a bit.

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

**OpenCV and Python versions:**  
This example will run on **Python 2.7/Python 3.4+** and **OpenCV 2.4.X/OpenCV 3.0+**.

The Canny Edge Detector
-----------------------

In previous posts we’ve used the Canny edge detector a fair amount of times. We’ve used it to build a [kick-ass mobile document scanner](https://pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/) and we’ve used to [find a Game Boy screen in a photo](https://pyimagesearch.com/2014/04/21/building-pokedex-python-finding-game-boy-screen-step-4-6/), just two name a couple instances.

The Canny edge detector was developed way back in 1986 by John F. Canny. And it’s still widely used today was one of the default edge detectors in image processing.

The Canny edge detection algorithm can be broken down into 5 steps:

*   **Step 1:** Smooth the image using a Gaussian filter to remove high frequency noise.
*   **Step 2:** Compute the gradient intensity representations of the image.
*   **Step 3:** Apply non-maximum suppression to remove “false” responses to to edge detection.
*   **Step 4:** Apply thresholding using a lower and upper boundary on the gradient values.
*   **Step 5:** Track edges using hysteresis by suppressing weak edges that are not connected to strong edges.

If you’re familiar with the OpenCV implementation of the Canny edge detector you’ll know that the function signature looks like this:

**cv2.canny(image, lower, upper)**

Where `image` is the image that we want to detect edges in; and `lower` and `upper` are our integer thresholds for Step 4, respectively.

**The problem becomes determining these lower and upper thresholds.**

What is the optimal value for the thresholds?

This question is especially important when you are processing multiple images with different contents captured under varying lighting conditions.

In the remainder of this blog post I’ll show you a little trick that relies on **_basic statistics_** that you can apply to remove the manual tuning of the thresholds to Canny edge detection.

This trick will save you time parameter tuning — and you’ll still get a nice Canny edge map after applying the function.

To learn more about this zero-parameter, automatic Canny edge detection trick, read on.

Let’s go ahead and get started. Open up a new file in your favorite code editor, name it `auto_canny.py` , and let’s get started:

\# import the necessary packages
import numpy as np
import argparse
import glob
import cv2

def auto\_canny(image, sigma=0.33):
	# compute the median of the single channel pixel intensities
	v = np.median(image)

	# apply automatic Canny edge detection using the computed median
	lower = int(max(0, (1.0 - sigma) \* v))
	upper = int(min(255, (1.0 + sigma) \* v))
	edged = cv2.Canny(image, lower, upper)

	# return the edged image
	return edged

The first thing we’ll do is import our necessary packages. We’ll use NumPy to for numerical operations, `argparse` to parse command line arguments, `glob` to grab the paths to our images from disk, and `cv2` for our OpenCV bindings.

We then define `auto_canny` , our automatic Canny edge detection function on **Line 7**. This function requires a single argument, `image` , which is the single-channel image that we want to detect images in. An optional argument, `sigma` can be used to vary the percentage thresholds that are determined based on simple statistics.

**Line 9** handles computing the median of the pixel intensities in the image.

We then take this median value and construct two thresholds, `lower` and `upper` on **Lines 12 and 13**. These thresholds are constructed based on the +/- percentages controlled by the `sigma` argument.

A lower value of `sigma` indicates a tighter threshold, whereas a larger value of `sigma` gives a wider threshold. In general, you will not have to change this `sigma` value often. Simply select a single, default `sigma` value and apply it to your entire dataset of images.

_**Note:** In practice, `sigma=0.33` tends to give good results on most of the dataset I’m working with, so I choose to supply 33% as the default sigma value._

Now that we have our lower and upper thresholds, we then apply the Canny edge detector on **Line 14** and return it to the calling function on **Line 17**.

Let’s keep moving with this example and see how we can apply it to our images:

\# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--images", required=True,
	help="path to input dataset of images")
args = vars(ap.parse\_args())

# loop over the images
for imagePath in glob.glob(args\["images"\] + "/\*.jpg"):
	# load the image, convert it to grayscale, and blur it slightly
	image = cv2.imread(imagePath)
	gray = cv2.cvtColor(image, cv2.COLOR\_BGR2GRAY)
	blurred = cv2.GaussianBlur(gray, (3, 3), 0)

	# apply Canny edge detection using a wide threshold, tight
	# threshold, and automatically determined threshold
	wide = cv2.Canny(blurred, 10, 200)
	tight = cv2.Canny(blurred, 225, 250)
	auto = auto\_canny(blurred)

	# show the images
	cv2.imshow("Original", image)
	cv2.imshow("Edges", np.hstack(\[wide, tight, auto\]))
	cv2.waitKey(0)

We parse our command line arguments on **Lines 20-23**. We only need a single switch here, `--images` , which is the path to the directory containing the images we want to process.

We then loop over the images in our directory on **Line 26**, load the image from disk on **Line 28**, convert the image to grayscale on **Line 29**, and apply a Gaussian blur with a _3 x 3_ kernel to help remove high frequency noise on **Line 30**.

**Lines 34-36** then apply Canny edge detection using three methods:

1.  A _wide_ threshold.
2.  A _tight_ threshold.
3.  A threshold determined _automatically_ using our `auto_canny` function.

Finally, our resulting images are displayed to us on **Lines 39-41**.

The auto\_canny function in action
----------------------------------

Alright, enough talk about code. Let’s see our `auto_canny` function in action.

Open up a terminal and execute the following command:

$ python auto\_canny.py --images images

You should then see the following output:

[![Image 3: Figure 1: Applying automatic Canny edge detection. Left: Wide Canny edge threshold. Center: Tight Canny edge threshold. Right: Automatic Canny edge threshold.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20272'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/01/auto_canny_dolphin.png)

**Figure 1:** Applying automatic Canny edge detection. _Left:_ Wide Canny edge threshold. _Center:_ Tight Canny edge threshold. _Right:_ Automatic Canny edge threshold.

As you can see, the _wide_ Canny edge threshold not only detects the dolphin, but also many of the clouds in the image. The _tight_ threshold does not detect the clouds, but misses out on the dolphin tail. Finally, the _automatic_ method is able to find all of the dolphin, while removing many of the cloud edges.

Let’s try another image:

[![Image 4: Figure 2: Applying automatic Canny edge detection to a picture of a camera. Left: Wide Canny edge threshold. Center: Tight Canny edge threshold. Right: Automatic Canny edge threshold.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20338'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/01/auto_canny_camerapng.png)

**Figure 2:** Applying automatic Canny edge detection to a picture of a camera. _Left:_ Wide Canny edge threshold. _Center:_ Tight Canny edge threshold. _Right:_ Automatic Canny edge threshold.

The wide Canny threshold on the _left_ includes high frequency noise based on the reflection of the light on the brushed metal of the camera, whereas the tight threshold in the _center_ misses out on many of the structural edges on the camera. Finally, the automatic method on the _right_ is able to find many of the structural edges while not including the high frequency noise.

One more example:

[![Image 5: Figure 3: Applying automatic Canny edge detection to a picture of a cup. Left: Wide Canny edge threshold. Center: Tight Canny edge threshold. Right: Automatic Canny edge threshold.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20382'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/01/auto_canny_cup.png)

**Figure 3:** Applying automatic Canny edge detection to a picture of a cup. _Left:_ Wide Canny edge threshold. _Center:_ Tight Canny edge threshold. _Right:_ Automatic Canny edge threshold.

The results here are fairly dramatic. While both the wide _(left)_ and the automatic _(right)_ Canny edge detection methods perform similarly, the tight threshold _(center)_ misses out on almost all of the structural edges of the cup.

Given the examples above, it’s clear that the automatic, zero-parameter version of the Canny edge detection obtains the **best results** with the **least effort**.

_**Note:** The three example images were taken from the CALTECH-101 dataset._

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

Summary
-------

In this blog post I showed you a simple trick to (reliably) automatically detect edges in images using the Canny edge detector, **_without providing thresholds to the function_**_._

This trick simply takes the median of the image, and then constructs upper and lower thresholds based on a percentage of this median. In practice, `sigma=0.33` tends to obtain good results.

In general, you’ll find that the automatic, zero-parameter version of the Canny edge detection is able to obtain fairly decent results with little-to-no effort on your part.

With this in mind, why not download the source code to this post and give it a shot on your own images? I would be curious to hear about your results!

![Image 6](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and a **FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.** Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!