检测哪张图片更清晰

33

我正在寻找一种方法来检测两张相似图片的哪一张更加清晰。

我认为可以使用某种整体锐度的度量方式,并生成得分(假设例子:image1的锐度得分为9,image2的锐度得分为7,则image1更清晰)。

我已经搜索了一些关于锐度检测/评分算法的内容,但只找到了一些能够增强图像锐度的算法。

是否有人做过类似的事情,或者有任何有用的资源/线索?

我将在Web应用程序的上下文中使用此功能,因此首选PHP或C/C++。


2
它们是同一物体/距离的两张图像,但其中一张更清晰吗? - Assaf Lavie
3
有趣的论文:http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?tp=&arnumber=4697259 (使用特征值进行图像清晰度测量) - Assaf Lavie
@gigantt,谢谢,我会去看看的。我想大部分图片会基本相似。也许距离略微变化可能会导致主题大小的小变化,或具有狭窄景深的情况下可能会导致不同部分进出焦点。 - econstantin
5个回答

23

如在这个Matlab Central页面中所示,可以通过平均梯度幅值来估计清晰度。

我在Python中使用了以下代码:

from PIL import Image
import numpy as np

im = Image.open(filename).convert('L') # to grayscale
array = np.asarray(im, dtype=np.int32)

gy, gx = np.gradient(array)
gnorm = np.sqrt(gx**2 + gy**2)
sharpness = np.average(gnorm)

可以使用更简单的numpy.diff计算出类似的数字,而不是使用numpy.gradient。 需要调整结果数组的大小:

dx = np.diff(array)[1:,:] # remove the first row
dy = np.diff(array, axis=0)[:,1:] # remove the first column
dnorm = np.sqrt(dx**2 + dy**2)
sharpness = np.average(dnorm)

1
是的,更少的锐度意味着更多的模糊。 - Robert Pollak
这需要在灰度图像上完成,就像Matlab代码中一样吗?还是它也可以在彩色图像上工作?(我假设array = list(img.getdata()),这正确吗?) - faerubin
@faerubin,我的代码是针对灰度图像的。我现在已经扩展了片段以显示这一点。然而,类似的方法也可以用于彩色图像数据。 - Robert Pollak

16

简单的方法是测量对比度-像素值之间差异最大的图像最为清晰。例如,可以计算像素值的方差(或标准偏差),较大的数值胜出。这种方法寻找整体对比度最大的图像,但可能不是您想要的--特别是,它倾向于偏好具有最大景深的图片。

根据您的需求,您可能更喜欢使用类似FFT的方法,以查看哪个显示了最高频率内容。这使您可以优先选择某些部分极其清晰的图片(但其他部分则不那么清晰)而不是具有更多景深的图片,因此更多的图像区域是相对清晰的,但最大清晰度较低(由于较小光圈的衍射通常会发生这种情况)。


关于FFT方法,有趣的方法!您是指比较FFT转换图像某些部分的亮度吗?更高的频率会位于图像的中心还是边缘? - ellockie
1
@ellockie:在FFT之后,您拥有的是描述图像的数据,但不再是实际图像。更高的频率取决于图像的内容,而不是图像中的位置(即可以出现在任何地方--其想法是它会发生在最锐利的部分)。 - Jerry Coffin
在FFT变换图像中,您可以说距离中心更远的像素代表与更详细特征相关的更高频率吗?感谢您的解释。 - ellockie

6

一个简单实用的方法是使用边缘检测(边缘越多==图像更清晰)。

使用PHP GD快速而不失效率地实现。

function getBlurAmount($image) {
    $size = getimagesize($image);
    $image = imagecreatefromjpeg($image);
    imagefilter($image, IMG_FILTER_EDGEDETECT);    
    $blur = 0;
    for ($x = 0; $x < $size[0]; $x++) {
        for ($y = 0; $y < $size[1]; $y++) {
            $blur += imagecolorat($image, $x, $y) & 0xFF;
        }
    }
    return $blur;
}

$e1 = getBlurAmount('http://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Jonquil_flowers_at_f32.jpg/800px-Jonquil_flowers_at_f32.jpg');
$e2 = getBlurAmount('http://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Jonquil_flowers_at_f5.jpg/800px-Jonquil_flowers_at_f5.jpg');

echo "Relative blur amount: first image " . $e1 / min($e1, $e2) . ", second image " . $e2 / min($e1, $e2);

(图像模糊较少则更清晰) 更高效的方法是在您的代码中检测边缘,使用Sobel算子PHP示例(我想重写为C ++应该会大大提高性能)。


imagecolorat() 返回的最后一个字节包含蓝色组件。如果要考虑红色和绿色,请在使用之前使用 imagefilter($image,IMG_FILTER_GRAYSCALE) 进行过滤处理。 - hermannk
imagefilter($image, IMG_FILTER_EDGEDETECT) 返回大约为 127 的值。如果图片中存在更多对比度,则这些值与该值相比会更加不同。然而,平均值始终接近于 127。要解决此问题:计算灰度值的方差。 - hermannk

3

这篇论文描述了一种使用DWT计算模糊因子的方法。看起来很直接,但是它不是检测清晰度,而是检测模糊度。似乎它首先检测边缘(简单卷积),然后使用DWT累积和评分。


2

检查对比度传递函数(CTF)

这里有一个实现
这里有一个解释


1
据我所见,这篇论文和实现适用于电子显微镜。推广到普通摄影似乎并不直接。我投了反对票,因为我非常想知道在这里如何使用CTF,如果你编辑和完善你的答案,我会撤销我的投票。谢谢! - Dr. belisarius
2
链接已经失效 :( - Alessandro Mariani
你应该将它们都发布出来,而不是提供一个可能会更改的链接。 - Innat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接