Python 作图片清晰度识别

在一般状况下,图片是否清晰是个感性认识,同一个图,有可能你以为还过得去,而别人会以为不清晰,缺少一个统一的标准。然而有一些算法能够去量化图片的清晰度,作到有章可循。python

原理

若是以前了解过信号处理,就会知道最直接的方法是计算图片的快速傅里叶变换,而后查看高低频分布。若是图片有少许的高频成分,那么该图片就能够被认为是模糊的。然而,区分高频量多少的具体阈值倒是十分困难的,不恰当的阈值将会致使极差的结果。git

咱们指望的是一个单一的浮点数就能够表示图片的清晰度。 Pech-Pacheco 在 2000 年模式识别国际会议提出将图片中某一通道(通常用灰度值)经过拉普拉斯掩模作卷积运算,而后计算标准差,出来的值就能够表明图片清晰度。程序员

这种方法凑效的缘由就在于拉普拉斯算子定义自己。它被用来测量图片的二阶导数,突出图片中强度快速变化的区域,和 Sobel 以及 Scharr 算子十分类似。而且,和以上算子同样,拉普拉斯算子也常常用于边缘检测。此外,此算法基于如下假设:若是图片具备较高方差,那么它就有较广的频响范围,表明着正常,聚焦准确的图片。可是若是图片具备有较小方差,那么它就有较窄的频响范围,意味着图片中的边缘数量不多。正如咱们所知道的,图片越模糊,其边缘就越少。github

有了表明清晰度的值,剩下的工做就是设定相应的阀值,若是某图片方差低于预先定义的阈值,那么该图片就能够被认为是模糊的,高于阈值,就不是模糊的。算法

实操

原理看起来比较复杂,涉及到不少信号啊图片处理的相关知识,下面咱们来实操一下,直观感觉下。json

因为人生苦短,以及我我的是朋友圈第一 Python 吹子,我选择使用 Python 来实现,核心代码简单到使人发指:微信

import cv2

def getImageVar(imgPath):
	image = cv2.imread(imgPath);
	img2gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
	imageVar = cv2.Laplacian(img2gray, cv2.CV_64F).var()

	return imageVar
复制代码

真是人生苦短啊,核心代码就三行,简单解释下。markdown

import cv2 使用了一个著名的图像处理库 OpenCV,关于 OpenCV 的安装这里很少赘述,须要注意的是它依赖 numpy。oop

image = cv2.imread(imgPath) 使用 OpenCV 提供的方法读取图片。 img2gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 转化为灰度图。以下图:spa

原图是这样的:

cv2.Laplacian(img2gray, cv2.CV_64F) 对图片用 3x3 拉普拉斯算子作卷积,这里的 cv2.CV_64F 就是拉普拉斯算子。

原理部分说过,拉普拉斯算子常常用于边缘检测,因此这里通过拉普拉斯算子以后,留下的都是检测到的边缘。上图通过这步处理以后是这样的:

能够看到这里图片人物大体仍是比较清晰的。

cv2.Laplacian(img2gray, cv2.CV_64F).var() 计算出方差,并最后返回。

上面那张图按这个计算出来时 3170 多,这个就是最后咱们用来判断清晰度的值。

能够再找一张看看:

原图:

作灰度和通过拉普拉斯算子以后,能够看到人物部分已经不是很清晰了。

最后算出来的方差只有 530

剩下的工做就是根据总体图片质量肯定阀值了。

局限性

经过上面的实操,咱们知道这个算法的技巧在于设置合适的阀值,阈值过低会致使正常图片被误断为模糊图片,阈值过高会致使模糊图片被误判为正常图片。阀值依赖于你实际应用的业务场景,须要根据使用场景的不一样作不一样的定制。

真正的银弹并不存在。除了须要定个阀值外,有些图片可能会故意作个背景模糊或者背景虚化,这种图片很容易被误杀。

好比:

计算出来是这样的,后面一大片都是黑的。

这个图前景其实看着还行,可是背景有大片的虚化和模糊,这种状况下比较容易被误杀。

因此最好仍是在了解原理以后,根据实际场景来使用。


最后写了个简单的脚本,对传入的图片路径的图片进行计算,而后返回一个 json 字符串。

用法 python getRank.py --imgs=./1.jpg,./2.jpg

源码:github.com/bob-chen/de…

碎碎念

记录一些所思所想,写写科技与人文,写写生活状态,写写读书心得,主要是扯淡和感悟。 欢迎关注,交流。

微信公众号:程序员的诗和远方

公众号ID : MonkeyCoder-Life

程序员的诗和远方
相关文章
相关标签/搜索