文章目录
1.背景介绍
- 因为所做的项目中,需要对一些图像的模糊度进行评价,所以开始了一些模糊度方面的学习探索
- 图像模糊会造成高频信息缺损或对比度下降
图像模糊度评价属于是图像质量评价(Image Quality Assessment,IQA),一般分为三种:无参考(No Reference,NR)、全参考(Full Reference,FR)、半参考(Reduced Reference,RR)。
- 首先手头上有三个数据集,暂时命名为pcm2,real,pred,目前的目标是选取一个简单明了的模糊度评价函数,使得前两者与后者尽可能差距大,编写以下函数对三个数据集进行评价
import cv2,os
import numpy as np
from tqdm import trange
def fun_blur(img_gray):
#
pass
def calAllBlurValue(pngPath,fun_blur):
pnglist = os.listdir(pngPath)
blurs = []
for i in trange(len(pnglist)):
img = cv2.imread(os.path.join(pngPath,pnglist[i]))
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
blurs.append(fun_blur(img_gray))
return blurs
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
funName = u"算法"
fun_blur = fun_blur
pcm2Path = r""
pcm2Blurs = np.array(calAllBlurValue(pcm2Path,fun_blur))
realPath = r""
realBlurs = np.array(calAllBlurValue(realPath,fun_blur))
predPath = r""
predBlurs = np.array(calAllBlurValue(predPath,fun_blur))
df = pd.DataFrame({'pcm2':pcm2Blurs,'real':realBlurs})
plt.figure(figsize=(8,5))
plt.subplot(1,2,1)
# plt.ylim(0, 900)
sns.boxplot(data=df,width=0.8) #左图
plt.subplot(1,2,2)
# plt.ylim(0, 900)
sns.boxplot(data=pd.DataFrame({'pred':predBlurs}),width=0.4,color='g') #右图
plt.suptitle(funName)
plt.savefig(r""+funName+".png",dpi=300)
- 在实际使用时只需要在函数部分填入即可
2.评价方法
- 由于场景限制以及重点不在这里,就不采用复杂度较高的算法,而只是采用一些经典且是基于图像本身的统计信息进行评价的方法,主要是参考文献[3]中2.6.2 用于“自动聚焦”领域的算法中的模糊度评价算法
2.1 灰度方差算法
g ˉ = 1 N x × N y ∑ f ( x , y ) s = 1 N x × N y ∑ ( f ( x , y ) − g ˉ ) 2 \bar{g}=\frac{1}{N_x\times N_y}\sum{f(x,y)} \\ s=\frac{1}{N_x\times N_y}\sum{(f(x,y)-\bar{g})^2} gˉ=Nx×Ny1∑f(x,y)s=Nx×Ny1∑(f(x,y)−gˉ)2
- 将图像转换为灰度图后,计算灰度图的方差,以方差值的大小评价图像模糊度,表征了图像变化的平均程度
def fun_blur1(img):
# 1、灰度方差算法
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
# return np.power(img_gray-img_gray.mean(),2).mean()
return img_gray.var()
- 绘制的箱线图如下:
它表征了图像灰度变化的平均程度,灰度变化的平均程度越大,图像越清晰,灰度变化平均程度越小,图像越模糊。
- 但是根据实际来看,从人肉眼上看清晰程度是pcm2>real>pred,再做研究
2.2 灰度差分绝对值之和算法
s = ∑ ∑ { ∣ f ( x + 1 , y ) − f ( x , y ) ∣ + ∣ f ( x , y + 1 ) − f ( x , y ) ∣ } s=\sum{\sum{\{|{f(x+1,y)-f(x,y)}|+|{f(x,y+1)-f(x,y)}|\}}} s=∑∑{∣f(x+1,y)−f(x,y)∣+∣f(x,y+1)−f(x,y)∣}
- 因为n×m的图像经过上述操作后会出现n-1×m的矩阵与n×m-1的矩阵做加运算(或者在每个横竖运算后都填充一行未操作的原数据),所以这里的公式我稍微修改了一下,不知道是否还能具有正确的特征
s = ∑ { ∣ f ( x + 1 , y ) − f ( x , y ) ∣ } + ∑ { ∣ f ( x , y + 1 ) − f ( x , y ) ∣ } s=\sum{\{|{f(x+1,y)-f(x,y)}|\}+\sum{\{|{f(x,y+1)-f(x,y)}|\}}} s=∑{∣f(x+1,y)−f(x,y)∣}+∑{∣f(x,y+1)−f(x,y)∣}
def fun_blur2(img):
# 2、灰度差分绝对值之和方差算法
# x方向,Y方向图像差分绝对值的和作为度量标准:
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
delat_y = np.abs(img_gray[1:,:]-img_gray[:-1,:])
delat_x = np.abs(img_gray[:,1:]-img_gray[:,:-1])
return delat_x.sum()+delat_y.sum()
- 虽然差距倒是挺大的,但是为了方便和原数据相对比,我尝试了将求和改成了求平均值,公式如下:
s = 1 ( N x − 1 ) × N y ∑ { ∣ f ( x + 1 , y ) − f ( x , y ) ∣ } + 1 N x × ( N y − 1 ) ∑ { ∣ f ( x , y + 1 ) − f ( x , y ) ∣ } s=\frac{1}{(N_x-1)\times N_y}\sum{\{|{f(x+1,y)-f(x,y)}|\}+\frac{1}{N_x\times (N_y-1)}\sum{\{|{f(x,y+1)-f(x,y)}|\}}} s=(Nx−1)×Ny1∑{∣f(x+1,y)−f(x,y)∣}+Nx×(Ny−1)1∑{∣f(x,y+1)−f(x,y)∣}
def fun_blur2(img):
# 2、灰度差分绝对值之和方差算法
# x方向,Y方向图像差分绝对值的和作为度量标准:
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
delat_y = np.abs(img_gray[1:,:]-img_gray[:-1,:])
delat_x = np.abs(img_gray[:,1:]-img_gray[:,:-1])
return delat_x.mean()+delat_y.mean()
2.3 灰度差分平方和算法
- 与2.2相比是将绝对值修改为平方项,突出大的微分项的影响
s = ∑ ∑ { ( f ( x + 1 , y ) − f ( x , y ) ) 2 + ( f ( x , y + 1 ) − f ( x , y ) ) 2 } s=\sum{\sum{\{({f(x+1,y)-f(x,y)})^2+({f(x,y+1)-f(x,y)})^2\}}} s=∑∑{(f(x+1,y)−f(x,y))2+(f(x,y+1)−f(x,y))2}
- 同样基于2.2的考虑,将公式修改为:
s = 1 ( N x − 1 ) × N y ∑ { ( f ( x + 1 , y ) − f ( x , y ) ) 2 } + 1 N x × ( N y − 1 ) ∑ { ( f ( x , y + 1 ) − f ( x , y ) ) 2 } s=\frac{1}{(N_x-1)\times N_y}\sum{\{({f(x+1,y)-f(x,y)})^2\}+\frac{1}{N_x\times (N_y-1)}\sum{\{({f(x,y+1)-f(x,y)})^2\}}} s=(Nx−1)×Ny1∑{(f(x+1,y)−f(x,y))2}+Nx×(Ny−1)1∑{(f(x,y+1)−f(x,y))2}
def fun_blur3(img):
# 3、灰度差分平方和方差算法
# x方向,Y方向图像差分平方值的和作为度量标准,突出微分值的影响,提高信噪比数值
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
delat_y = np.power(img_gray[1:,:]-img_gray[:-1,:],2)
delat_x = np.power(img_gray[:,1:]-img_gray[:,:-1],2)
return delat_x.mean()+delat_y.mean()
- 不知道是因为自己修改了的原因,还是因为我的数据确实不适应这种算法,数据集pred模糊程度平均值介于pcm2和real之间,暂不考虑
2.4 Brenner函数
- Brenner梯度函数简单计算相邻两个像素灰度差的平方
s = ∑ ∑ ( f ( x + 2 , y ) − f ( x , y ) ) 2 s=\sum\sum(f(x+2,y)-f(x,y))^2 s=∑∑(f(x+2,y)−f(x,y))2
def fun_blur4(img):
# Brenner梯度函数是最简单的梯度评价函数,它只是简单的计算相邻两个像素灰度差的平方
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
delat_x = np.power(img_gray[:,2:]-img_gray[:,:-2],2)
return delat_x.sum()
2.5 Roberts梯度和
s = ∑ ∑ { ∣ f ( x , y ) − f ( x + 1 , y + 1 ) ∣ + ∥ f ( x + 1 , y ) − f ( x , y + 1 ) ∣ } s=\sum{\sum{\{|{f(x,y)-f(x+1,y+ 1)|}+\|{f(x+1,y)-f(x,y+1)}|\}}} s=∑∑{∣f(x,y)−f(x+1,y+1)∣+∥f(x+1,y)−f(x,y+1)∣}
def fun_blur5(img):
# 5、Roberts梯度和
# 定义为相邻四个像素对角线像素灰度值差的绝对值之和
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
delta11 = np.abs(img_gray[:-1,:-1]-img_gray[1:,1:])
delta10 = np.abs(img_gray[1:,:-1]-img_gray[:-1,1:])
return (delta11+delta10).sum()
- 这个比较符合预期,数据集间几乎没有相交的地方,但是还是要加个均值比较直观
2.6 拉普拉斯梯度和 1
- 所谓梯度和1是指用拉普拉斯模板1获得每个像素的拉普拉斯梯度,然后求和,模板1如下
m = [ 0 1 0 1 − 4 1 0 1 0 ] m=\left[ \begin{matrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{matrix} \right] m=⎣⎡0101−41010⎦⎤
s = ∑ ∑ { ∣ f ( x + 1 , y ) + f ( x , y + 1 ) + f ( x − 1 , y ) + f ( x , y − 1 ) − 4 f ( x , y 1 ) ∣ } s=\sum{\sum{\{|{f(x+1,y)+f(x,y+1)+f(x-1,y)+f(x,y-1)-4f(x,y 1)}|\}}} s=∑∑{∣f(x+1,y)+f(x,y+1)+f(x−1,y)+f(x,y−1)−4f(x,y1)∣}
def fun_blur6(img):
#拉普拉斯模板1
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
s = img_gray[1:-1,:-2]+img_gray[1:-1,2:]+img_gray[:-2,1:-1]+img_gray[2:,1:-1]-4*img_gray[1:-1,1:-1]
return np.abs(s).mean()
2.7 拉普拉斯梯度和 2
m = [ 1 1 1 1 − 8 1 1 1 1 ] m=\left[ \begin{matrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \end{matrix} \right] m=⎣⎡1111−81111⎦⎤
def fun_blur7(img):
#拉普拉斯模板2
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
s = img_gray[1:-1,:-2]+img_gray[1:-1,2:]+img_gray[:-2,1:-1]+img_gray[2:,1:-1]+img_gray[2:,2:]+img_gray[:-2,:-2]+img_gray[2:,:-2]+img_gray[:-2,2:]-8*img_gray[1:-1,1:-1]
return np.abs(s).mean()
- 同理差距更大了些
2.8 Tenengrad函数
- 定义模板算子:
K x = [ 0 − 1 0 0 2 0 0 − 1 0 ] , K y = [ 0 0 0 − 1 2 − 1 0 0 0 ] K_x=\left[ \begin{matrix} 0 & -1 & 0 \\ 0 & 2 & 0 \\ 0 & -1 & 0 \end{matrix} \right] , K_y=\left[ \begin{matrix} 0 & 0 & 0 \\ -1 & 2 & -1 \\ 0 & 0 & 0 \end{matrix} \right] Kx=⎣⎡000−12−1000⎦⎤,Ky=⎣⎡0−100200−10⎦⎤
- 进行卷积操作,并计算模糊度:
f x ( x , y ) = f ( x , y ) ∗ K x , f y ( x , y ) = f ( x , y ) ∗ K y f_x(x,y)=f(x,y)*K_x,\ f_y(x,y)=f(x,y)*K_y fx(x,y)=f(x,y)∗Kx, fy(x,y)=f(x,y)∗Ky
s = f x 2 ( x , y ) + f y 2 ( x , y ) s = \sqrt{f_x^2(x,y)+f_y^2(x,y)} s=fx2(x,y)+fy2(x,y)
def fun_blur8(img):
#Tenengrad函数
img_gray =cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
fx = np.power(img_gray[:,1:-1]*2 - img_gray[:,:-2] - img_gray[:,2:],2)
fy = np.power(img_gray[1:-1,:]*2 - img_gray[:-2,:] - img_gray[:-2,:],2)
return np.sqrt(fx.mean()+fy.mean())
3.总结
- 以上实现了8种经典的统计学信息的参考模糊度评价方法,其中有很多细节我为了编程实现方便进行了一定的变形,可能会导致一些致命错误,望知者指正
- 其中不只是基于灰度,也可以基于RGB的图片,但是这里没有一一列举,只需要简单修改一下代码即可实现
- 依照结果而言,我预计选择拉普拉斯梯度和 2方法进行进一步调研,去研究他评价低的图片和人肉眼的差异,并且确定他的评价是否合适,是否有更有用的变形
4.参考文献
[1] 梅嘉祥,刘展宁,张志佳,等. 图像模糊度评价及其应用综述[J]. 软件工程. 2018, 21(04): 23-26.
[2] 王志明. 无参考图像质量评价综述[J]. 自动化学报. 2015, 41(06): 1062-1079.
[3] 庞胜利. 图像模糊度评价研究[D]. 西安电子科技大学, 2010.