检查图像位图是否模糊的简单方法

8

我正在寻找一种“非常”简单的方法来检查图像位图是否模糊。我不需要精确和复杂的算法,比如fft、小波等。只要一个非常简单的想法,即使它不准确。

我考虑计算像素(x,y)和像素(x+1,y)之间的RGB分量的平均欧几里得距离,然后使用阈值,但效果很差。还有其他想法吗?


1
你可以使用滑动窗口的平均方差来大致了解高频内容的数量。首先将其转换为灰度。这个问题的答案有更多的选项。 - Roger Rowland
可能是如何检测图像是否模糊?的重复问题。 - jtlz2
我尝试了这个,它有效。https://medium.com/better-programming/blur-detection-via-metal-on-ios-16dd02cb1558 - Hope
3个回答

18
不要计算相邻像素之间的平均差异。
即使照片完全对焦,它仍然可能包含大面积的均匀颜色,比如天空。这些会降低平均差异并掩盖您感兴趣的细节。您真正想找到的是最大差异值。
此外,为了加快速度,我不会检查图像中的每个像素。通过检查相距10个像素的水平和垂直线网格,您应该能够获得合理的结果。
以下是使用PHP的GD图形函数对来自Wikimedia Commons(Bokeh_Ipomea.jpg)的图像进行测试的结果。Sharpness值只是255的最大像素差异值的百分比(我只查看了绿色通道;您应该先转换成灰度)。下面的数字显示处理图像所需的时间。

close-up of Ipomea flower, sharpness calculated as 71.0%

same image with slight blurring, sharpness is reduced to 36.1%

same image with severe blurring; sharpness is now 17.6%

如果你需要它们,这里是我使用的源图片:

更新:

这个算法存在一个问题,即它依赖于图像具有相当高的对比度以及锐利的边缘。可以通过找到最大像素差(maxdiff),并在以该位置为中心的小区域内找到像素值的整体范围(range)来改进它。然后按照以下方式计算清晰度:

sharpness = (maxdiff / (offset + range)) * (1.0 + offset / 255) * 100%

其中,offset是一个参数,它减少了非常小的边缘的影响,以使背景噪声不会对结果产生显著影响。(我使用了15的值。)

这会产生相当不错的结果。任何清晰度低于40%的东西可能都是模糊的。以下是一些示例(最大像素差和9×9本地搜索区域的位置也显示出来,供参考):

"纯麻" by mystuart @ Flickr (来源)

"模糊的美丽" by Ilya @ Flickr (来源)

"模糊的市区" by Andy Arthur @ Flickr (来源)

"模糊的火山土丘" by matt Dombrowski @ Flickr (来源)

然而,结果仍然不完美。本质上模糊的主题始终会导致较低的清晰度值:

"Clouds and sky" by William Warby @ Flickr (来源)

Bokeh效果可以从光的点源产生锐利的边缘,即使它们完全失焦:

"The Side" by HD41117 @ Flickr (来源)

您提到希望能够拒绝用户提交的失焦照片。由于这种技术并不完美,我建议您在图像模糊时通知用户,而不是完全拒绝它。


感谢@squeamish-ossifrage的回复,但您能否提供我更多细节?我想实现您的方法,但我不清楚它的工作原理。您是为每个像素计算其与邻居之间的颜色距离,然后选择最大值吗?如果是这样,假设您的图像包含两个相邻的像素,一个白色和一个黑色。这将给出255的最大距离和100%的锐度。这正确吗? - user2923045
这肯定有效,而且就像要求的那样简单。唯一的问题是时间。为了获得快速结果,请选择稀疏网格。 - sepdek
它的功能很好,但不幸的是,它只适用于当你有多个相同图片实例时,并且想要确定哪一个是最好的(就锐度而言)。我的问题则不同。事实上,我只有一张图片实例,我想要确定它的质量(就锐度而言),如果它模糊的话就将其拒绝。 - user2923045
1
如果你指的是灰度图像,那么它应该可以正常工作。如果你的图像只是黑白的(即每个像素1比特),那么它将无法正常工作。我建议你自己试试。 - r3mainer
1
@floriankrueger 对不起,我没有解释清楚。当$maxv-$minv==0时,该值被选择为输出0.0的值,当$maxv-$minv==255时,该值被选择为输出100.0的值。 - r3mainer
显示剩余8条评论

3
我认为从哲学上讲,所有自然图像都是模糊的...模糊程度取决于您的应用。广义上讲,图像的模糊或清晰可以用各种方法来衡量。首先,您可以尝试检查图像的能量,该能量定义为平方像素值的归一化求和:
     1     2
E = --- Σ I,其中I为图像,N为像素数(在灰度下定义)
     N

首先,您可以应用高斯拉普拉斯算子(LoG)滤波器来检测图像的“能量”区域,然后检查能量。模糊图像应显示出明显较低的能量。

在MATLAB中查看一个使用典型灰度lena图像的示例:
这是原始图像 This is the original image 这是模糊的图像,带有高斯噪声 This is the blurry image, blurred with gaussian noise 这是原始图像的LoG图像 This is the LoG image of the original 这是模糊图像的LoG图像 This is the LoG image of the blurry image

如果您只计算这两个LoG图像的能量,则会得到:

E  = 1265       E  = 88
 or              bl

这是巨大的差异...
然后,您只需要选择一个阈值来判断哪个能量适合您的应用...


原始图像存在许多颗粒噪声,这些噪声被您的高斯滤波器消除了。即使照片对焦不正确,真实照片仍将包含相同数量的噪声。 - r3mainer
@squeamishossifrage,我强烈不同意你的看法。在我看来,如果图像模糊(或对焦不正确),那就没有可能保留足够的细节以获得高能量... - sepdek
让我试着解释一下。看看原始图像的背景,在帽子上方的区域。即使它已经失焦,图像在这里显然很嘈杂。这反映了拍摄这张照片的胶片的颗粒度。另一方面,用数码相机拍摄的照片会受到暗电流和热噪声的影响。在这两种情况下,这种噪声将对图像的平均能量产生重要影响。 - r3mainer
@squeamishossifrage 我能理解这个,但我的观点是这种“粒度”不会对能源的增加做出重大贡献。我已经用各种图像测试了我提出的方法,包括你的例子中的图像,我的方法仍然有效。 - sepdek
@squeamishossifrage ...继续... 我也在MATLAB中实现了您的方法,这样做更容易,并尝试使用整个图像而不仅仅是网格上的采样。两种方法得到的结果是一致的。但是,显然,我的方法会比你的方法慢,因为它使用更复杂的操作,如果您的网格变得更稀疏(足以表示图像),那么它肯定可以变得更快。 - sepdek
我尝试了sepdek的方法,但成果有限。主要问题在于“只需选择一个阈值”。而为此选择阈值需要将问题绑定得更紧,通常比较困难。 - don_q

1
计算相邻像素的平均L1距离:
N1=1/(2*N_pixel) * sum( abs(p(x,y)-p(x-1,y)) + abs(p(x,y)-p(x,y-1)) )

然后计算平均 L2 距离:
N2= 1/(2*N_pixel) * sum( (p(x,y)-p(x-1,y))^2 + (p(x,y)-p(x,y-1))^2  )

然后比率 N2 / (N1*N1) 是模糊度的一种度量。这适用于灰度图像,对于彩色图像,需要分别针对每个通道进行计算。


谢谢@pentadecagon。您建议将图像转换为灰度还是针对每个通道重复上述任务,然后以某种方式聚合结果? - user2923045
你好 @pentadecagon,能否提供模糊图像的确切代码?非常感谢。 - Amit Thakur

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