实用技巧 | 使用OpenCV进行模糊检测

2021-12-08 18:37:05 浏览数 (1)

作者:Adrian Rosebrock 来源:计算机视觉与机器学习

编者荐语

可能这就是所谓的举一反三吧,其实相机自动对焦的一种较为简单的实现就是,相对于目标物体,前后移动相机并检测当前图像的清晰(模糊)度,选择一个最清晰的位置。废话不多说了,看看文章是如何实现的吧。

链接丨https://www.pyimagesearch.com/2015/09/07/blur-detection-with-opencv/

这只超可爱、超活跃家养小猎犬可能是有史以来拍照次数最多的狗。从8周大我们得到它的时候,到现在,不到3年的时间,我们已经收集了6000多张狗狗的照片。

在刚刚过去的这个周末,我坐下来,试图整理手机里大量的照片。这是一项艰巨的任务,而且我很快就注意到一个问题——有很多照片模糊程度过高。

现在,对于一般人来说,我认为他们会删除这些模糊的照片(或者至少将它们移到一个单独的文件夹中)——但作为一个计算机视觉科学家,这是不可能发生的。

相反,我编写了一个快速的Python脚本,用OpenCV执行模糊检测。

接下来,我将向你展示如何使用OpenCV、Python和Laplacian算子计算图像中的模糊量。在这篇文章的结尾,你将能够应用Laplacian方法到你自己的照片来检测模糊的程度。

拉普拉斯变换的方差

图1:用Laplacian算子卷积输入图像

在研究如何检测图像中的模糊程度时,我的第一步是阅读优秀的综述论文,即【形状-聚焦测量算子分析[2013 Pertuz等]】。在Pertuz等人的论文中,回顾了近36种估计图像焦距程度的不同方法。

代码语言:javascript复制
https://www.semanticscholar.org/paper/Analysis-of-focus-measure-operators-for-Pertuz-Puig/8c675bf5b542b98bf81dcf70bd869ab52ab8aae9?p2df

如果你有信号处理方面的背景,首先要考虑的方法是计算图像的快速傅里叶变换,然后检查低频和高频的分布:如果图像只有有少量的高频,那么图像就会被认为是模糊的。然而,定义什么算低数量的高频或者什么是高数量的高频是相当困难的。

相反,如果我们可以计算一个单一的浮点值来表示一个给定图像的模糊程度,不是很好吗? Pertuz等人回顾了许多计算这种“模糊度度量”的方法,其中一些方法简单而直接,仅使用基本的灰度像素强度统计,另一些更先进和基于特征的方法,评估图像的局部二值模式。

快速浏览完这篇论文后,我找到了我一直在寻找的理想算法:pecch - pacheco等人在他们2000年ICPR论文《亮场显微镜中的硅藻自动聚焦:比较研究》中提出的Laplacian的变化。

方法很简单。简单。有良好的推理。并且只需要一行代码就可以实现:

代码语言:javascript复制
cv2.Laplacian(image, cv2.CV_64F).var()

你只需采取一个图像的单一通道(大概灰度)和卷积它与以下3 x 3的内核:

然后取响应的方差(即标准差的平方)。 如果方差低于预先定义的阈值,则认为图像模糊;否则,图像不会模糊。

这种方法有效的原因是由于Laplacian算子本身的定义,它用于测量图像的二阶导数。拉普拉斯算子突出显示图像中包含快速梯度变化的区域,很像Sobel和Scharr算子。和这些算子一样,Laplacian也经常用于边缘检测。这里的假设是,如果一幅图像的方差较高,那么就说明图像有广泛的响应,包括类边和非类边,这是一幅正常的聚焦图像的代表。但如果方差很低,那么就会有很小的响应扩散,这表明图像中几乎没有边缘。而图像越模糊,边缘就越少。所以可以用来检测是否模糊。

显然,这里的关键是设置正确的阈值,而阈值的设置与应用到的图像集相关。如果阈值过低,你就会错误地将原本不模糊的图像标记为模糊。如果阈值过高,那么实际上模糊的图像将不会被标记为模糊。这种方法只有在非常稳定的图像集(同一类型)中应用良好。

检测图像中模糊的数量

所以现在我们已经明确了将要使用的方法:计算一个单一的度量来表示一个给定的图像是多么“模糊”,让我们看看我们的数据集以下12张图像:

图3:我们的图像集。有些模糊,有些则不然。我们的目标是使用OpenCV进行模糊检测并将图像标记为模糊。

正如你所看到的,有些图像是模糊的,有些则不是。我们的目标是正确地标记每个图像模糊或非模糊。 有了这些,打开一个新文件,命名为detect_blur.py,让我们打开代码:

代码语言:javascript复制
# 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())

我们从在第2-4行上导入必要的包开始。如果你还没有我的imutils包在你的机器上,你会想现在安装:

代码语言:javascript复制
$ pip install imutils

从这里开始,我们将在第6行定义variance_of_laplacian函数。这个方法将我们想要计算焦距的图像(假设为单个通道,例如灰度图像)作为参数。第9行简单地用3 x 3 Laplacian运算符对图像进行卷积,并返回方差。

第12-17行解析命令行参数。我们需要的第一个命令是——images,它是指向包含我们想要测试是否模糊的图像数据集的目录的路径。

我们还将定义一个可选参数——thresh,它是我们将用于模糊测试的阈值。如果一个给定图像的焦距测量低于这个阈值,我们将标记图像为模糊。需要注意的是,您可能需要为自己的图像数据集调优这个值。100的值对于我的数据集似乎工作得很好,但是这个值对于图像的内容是非常主观的,所以您需要自己使用这个值来获得最优结果。

不管你信不信,最难的部分已经完成了!我们只需要写一点代码从磁盘加载图像,计算Laplacian的方差,然后将图像标记为模糊或非模糊:

代码语言:javascript复制
# 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)

我们从第2行开始对图像目录进行循环。对于这些图像,我们将从磁盘加载,将其转换为灰度,然后使用OpenCV应用模糊检测(第6-9行)。 在焦点测量超过命令行参数提供的阈值的情况下,我们将把图像标记为“模糊”。 最后,第3517-20行将文本和计算结果写到图像上,并将结果显示在我们的屏幕上。

使用OpenCV进行模糊检测

现在我们已经编写了detect_blur.py脚本,让我们尝试一下。打开一个shell并发出以下命令:

代码语言:javascript复制
$ python detect_blur.py --images images

这张照片的计算值是83.17,低于我们的阈值100;因此,我们正确地将该图像标记为模糊。

这幅图像的计算值为64.25,这也使得我们将其标记为“模糊”。

图6的计算值很高,为1004.14—比前两幅图高了几个数量级。这幅图像显然是非常清晰的。

总结

在这篇博文中,我们学习了如何使用OpenCV和Python执行模糊检测。

我们实现了计算Laplacian方法的方差,得到一个浮点值来表示图像的“模糊”程度。这种方法快速、简单、易于应用——我们只需用Laplacian算子对输入图像进行卷积并计算方差。如果方差低于预先定义的阈值,我们将图像标记为“模糊”。 需要注意的是,阈值是正确调优的一个关键参数,您经常需要根据每个数据集对其进行调优。

0 人点赞