Title: Blur detection with OpenCV - PyImageSearch

URL Source: https://pyimagesearch.com/2015/09/07/blur-detection-with-opencv/

Published Time: 2015-09-07T14:00:46+00:00

Markdown Content:
[![Image 1: detecting_blur_header](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20392'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_header.jpg)

Between myself and my father, Jemma, the super-sweet, hyper-active, extra-loving family beagle may be the most photographed dog of all time. Since we got her as a 8-week old puppy, to now, just under three years later, we have accumulated over _**6,000+ photos**_ of the dog.

Excessive?

Perhaps. But I love dogs. A lot. Especially beagles. So it should come as no surprise that as a dog owner, I spend a lot of time playing tug-of-war with Jemma’s favorite toys, rolling around on the kitchen floor with her as we roughhouse, and yes, _snapping tons of photos of her with my iPhone._

Over this past weekend I sat down and tried to organize the massive amount of photos in iPhoto. Not only was it a huge undertaking, I started to notice a pattern fairly quickly — **_there were lots of photos with excessive amounts of blurring_**.

Whether due to sub-par photography skills, trying to keep up with super-active Jemma as she ran around the room, or her spazzing out right as I was about to take the _perfect shot_, many photos contained a decent amount of blurring.

Now, for the average person I suppose they would have just deleted these blurry photos (or at least moved them to a separate folder) — but as a computer vision scientist, that wasn’t going to happen.

Instead, I opened up an editor and coded up a quick Python script to **perform blur detection with OpenCV**.

In the rest of this blog post, I’ll show you how to compute the amount of blur in an image using OpenCV, Python, and the Laplacian operator. By the end of this post, you’ll be able to apply the _variance of the Laplacian_ _method_ to your own photos to detect the amount of blurring.

![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)

Variance of the Laplacian
-------------------------

[![Image 3: Figure 2: Convolving the input image with the Laplacian operator.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20368%20450'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_convolution.jpg)

**Figure 1:** Convolving the input image with the Laplacian operator.

My first stop when figuring out how to detect the amount of blur in an image was to read through the excellent survey work, _[Analysis of focus measure operators for shape-from-focus](https://pdfs.semanticscholar.org/8c67/5bf5b542b98bf81dcf70bd869ab52ab8aae9.pdf)_ \[2013 Pertuz et al\]. Inside their paper, Pertuz et al. reviews nearly _36 different methods_ to estimate the focus measure of an image.

If you have any background in signal processing, the first method to consider would be computing the [Fast Fourier Transform](https://en.wikipedia.org/wiki/Fast_Fourier_transform) of the image and then examining the distribution of low and high frequencies — if there are a low amount of high frequencies, then the image can be considered blurry. However, defining what is a _low_ number of high frequencies and what is a _high_ number of high frequencies can be quite problematic, often leading to sub-par results.

Instead, wouldn’t it be nice if we could just compute a _single floating point value_ to represent how _blurry_ a given image is?

Pertuz et al. reviews many methods to compute this “blurryness metric”, some of them simple and straightforward using just basic grayscale pixel intensity statistics, others more advanced and feature-based, evaluating the Local Binary Patterns of an image.

After a quick scan of the paper, I came to the implementation that I was looking for: **variation of the Laplacian** by Pech-Pacheco et al. in their 2000 ICPR paper, _[Diatom autofocusing in brightfield microscopy: a comparative study](http://optica.csic.es/papers/icpr2k.pdf)_.

The method is simple. Straightforward. Has sound reasoning. And can be implemented in _**only a single line of code**_:

cv2.Laplacian(image, cv2.CV\_64F).var()

You simply take a single channel of an image (presumably grayscale) and convolve it with the following _3 x 3_ kernel:

[![Image 4: Figure 2: The Laplacian kernel.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2086%2067'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_laplacian.png)

**Figure 2:** The Laplacian kernel.

And then take the variance (i.e. standard deviation squared) of the response.

If the variance falls below a pre-defined threshold, then the image is considered _blurry_; otherwise, the image is _not blurry_.

The reason this method works is due to the definition of the Laplacian operator itself, which is used to measure the 2nd derivative of an image. The Laplacian highlights regions of an image containing rapid intensity changes, much like the Sobel and Scharr operators. And, just like these operators, the Laplacian is often used for edge detection. The assumption here is that if an image contains _high variance_ then there is a wide spread of responses, both edge-like and non-edge like, representative of a normal, in-focus image. But if there is _very low variance_, then there is a tiny spread of responses, indicating there are very little edges in the image. As we know, the more an image is blurred, _the less edges there are_.

Obviously the trick here is setting the correct threshold which can be quite domain dependent. Too low of a threshold and you’ll incorrectly mark images as blurry when they are not. Too high of a threshold then images that are actually blurry will not be marked as blurry. This method tends to work best in environments where you can compute an acceptable focus measure range and then detect outliers.

Detecting the amount of blur in an image
----------------------------------------

So now that we’ve reviewed the the method we are going to use to compute a single metric to represent how “blurry” a given image is, let’s take a look at our dataset of the following 12 images:

[![Image 5: Figure 3: Our dataset of images. Some are blurry, some are not. Our goal is to perform blur detection with OpenCV and mark the images as such.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20592'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_dataset.png)

**Figure 3:** Our dataset of images. Some are blurry, some are not. Our goal is to perform blur detection with OpenCV and mark the images as such.

As you can see, some images are blurry, some images are not. Our goal here is to _correctly_ mark each image as _blurry_ or _non-blurry_.

With that said, open up a new file, name it `detect_blur.py` , and let’s get coding:

\# import the necessary packages
from imutils import paths
import argparse
import cv2

def variance\_of\_laplacian(image):
	# compute the Laplacian of the image and then return the focus
	# measure, which is simply the variance of the Laplacian
	return cv2.Laplacian(image, cv2.CV\_64F).var()

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--images", required=True,
	help="path to input directory of images")
ap.add\_argument("-t", "--threshold", type=float, default=100.0,
	help="focus measures that fall below this value will be considered 'blurry'")
args = vars(ap.parse\_args())

We start off by importing our necessary packages on **Lines 2-4**. If you don’t already have my [imutils](https://github.com/jrosebr1/imutils) package on your machine, you’ll want to install it now:

$ pip install imutils

From there, we’ll define our `variance_of_laplacian` function on **Line 6**. This method will take only a single argument the `image` (presumed to be a single channel, such as a grayscale image) that we want to compute the focus measure for. From there, **Line 9** simply convolves the `image` with the _3 x 3_ Laplacian operator and returns the variance.

**Lines 12-17** handle parsing our command line arguments. The first switch we’ll need is `--images` , the path to the directory containing our dataset of images we want to test for blurryness.

We’ll also define an optional argument `--thresh` , which is the threshold we’ll use for the blurry test. If the focus measure for a given image falls below this threshold, we’ll mark the image as _blurry_. It’s important to note that you’ll likely have to tune this value for your own dataset of images. A value of `100` seemed to work well for my dataset, but this value is quite subjective to the contents of the image(s), so you’ll need to play with this value yourself to obtain optimal results.

Believe it or not, the hard part is done! We just need to write a bit of code to load the image from disk, compute the variance of the Laplacian, and then mark the image as blurry or non-blurry:

\# loop over the input images
for imagePath in paths.list\_images(args\["images"\]):
	# load the image, convert it to grayscale, and compute the
	# focus measure of the image using the Variance of Laplacian
	# method
	image = cv2.imread(imagePath)
	gray = cv2.cvtColor(image, cv2.COLOR\_BGR2GRAY)
	fm = variance\_of\_laplacian(gray)
	text = "Not Blurry"

	# if the focus measure is less than the supplied threshold,
	# then the image should be considered "blurry"
	if fm < args\["threshold"\]:
		text = "Blurry"

	# show the image
	cv2.putText(image, "{}: {:.2f}".format(text, fm), (10, 30),
		cv2.FONT\_HERSHEY\_SIMPLEX, 0.8, (0, 0, 255), 3)
	cv2.imshow("Image", image)
	key = cv2.waitKey(0)

We start looping over our directory of images on **Line 20**. For each of these images we’ll load it from disk, convert it to grayscale, and then apply blur detection using OpenCV (**Lines 24-27**).

In the case that the focus measure exceeds the threshold supplied a command line argument, we’ll mark the image as _“blurry”_.

Finally, **Lines 35-38** write the `text` and computed focus measure to the image and display the result to our screen.

Now that we have `detect_blur.py` script coded up, let’s give it a shot. Open up a shell and issue the following command:

$ python detect\_blur.py --images images

[![Image 6: Figure 4: Correctly marking the image as "blurry".](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_001.jpg)

**Figure 4:** Correctly marking the image as “blurry”.

The focus measure of this image is _83.17_, falling below our threshold of _100_; thus, we correctly mark this image as blurry.

[![Image 7: Figure 5: Performing blur detection with OpenCV. This image is marked as "blurry".](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_002.jpg)

**Figure 5:** Performing blur detection with OpenCV. This image is marked as “blurry”.

This image has a focus measure of _64.25_, also causing us to mark it as “blurry”.

[![Image 8: Figure 6: Marking an image as "non-blurry".](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_003.jpg)

**Figure 6:** Marking an image as “non-blurry”.

**Figure 6** has a very high focus measure score at _1004.14_ — orders of magnitude higher than the previous two figures. This image is clearly non-blurry and in-focus.

[![Image 9: Figure 7: Applying blur detection with OpenCV and Python.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_004.jpg)

**Figure 7:** Applying blur detection with OpenCV and Python.

The only amount of blur in this image comes from Jemma wagging her tail.

[![Image 10: Figure 8: Basic blur detection with OpenCV and Python.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_005.jpg)

**Figure 8:** Basic blur detection with OpenCV and Python.

The reported focus measure is lower than **Figure 7**, but we are still able to correctly classify the image as “non-blurry”.

[![Image 11: Figure 9: Computing the focus measure of an image.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_006.jpg)

**Figure 9:** Computing the focus measure of an image.

However, we can clearly see the above image is blurred.

[![Image 12: Figure 10: An example of computing the amount of blur in an image.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_007.jpg)

**Figure 10:** An example of computing the amount of blur in an image.

The large focus measure score indicates that the image is non-blurry.

[![Image 13: Figure 11: The subsequent image in the dataset is marked as "blurry".](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_008.jpg)

**Figure 11:** The subsequent image in the dataset is marked as “blurry”.

However, this image contains dramatic amounts of blur.

[![Image 14: Detecting the amount of blur in an image using the variance of Laplacian.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_009.jpg)

**Figure 12:** Detecting the amount of blur in an image using the variance of Laplacian.

[![Image 15: Figure 13: Compared to Figure 12 above, the amount of blur in this image is substantially reduced.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_010.jpg)

**Figure 13:** Compared to Figure 12 above, the amount of blur in this image is substantially reduced.

[![Image 16: Figure 14: Again, this image is correctly marked as not being "blurred".](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_011.jpg)

**Figure 14:** Again, this image is correctly marked as not being “blurred”.

[![Image 17: Figure 15: Lastly, we end our example by using blur detection in OpenCV to mark this image as "blurry".](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20460%20600'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2015/09/detecting_blur_result_012.jpg)

**Figure 15:** Lastly, we end our example by using blur detection in OpenCV to mark this image as “blurry”.

### 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 we learned how to perform blur detection using OpenCV and Python.

We implemented the _variance of Laplacian_ method to give us a single floating point value to represent the “blurryness” of an image. This method is fast, simple, and easy to apply — we simply convolve our input image with the Laplacian operator and compute the variance. If the variance falls below a predefined threshold, we mark the image as “blurry”.

It’s important to note that threshold is a critical parameter to tune correctly and you’ll often need to tune it on a per-dataset basis. Too small of a value, and you’ll accidentally mark images as blurry when they are not. With too large of a threshold, you’ll mark images as non-blurry when in fact they are.

Be sure to download the code using the form at the bottom of this post and give it a try!

![Image 18](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!