定义图像清晰度是一个比较定制化,或者说比较偏业务属性的,就是说要根据需要来定义图像的清晰度。
但是一般来说,还是有个一般过程。
图像的频域之前的文章说过了,这里说一下图像的梯度问题。
图像梯度的定义分为两个维度:
用一个向量来表示的话就是:
∇ f ( x , y ) = [ g x g y ] = [ f ( x + 1 , y ) − f ( x − 1 , y ) f ( x , y + 1 ) − f ( x , y − 1 ) ] \nabla f(x,y) = \begin{bmatrix} g_x \\ g_y \end{bmatrix} = \begin{bmatrix} f(x+1, y) - f(x-1, y) \\ f(x, y+1) - f(x, y-1) \end{bmatrix} ∇f(x,y)=[gxgy]=[f(x+1,y)−f(x−1,y)f(x,y+1)−f(x,y−1)]
在图像计算领域中,最经典的计算方式就是掩码方式,或者说是卷积的方式。
上面一个公式在图像领域就可以用一个掩码来表示:
如果减出来的数字小于0,是没有意义的,所以有一个梯度绝对值的计算方法:
g x 2 + g y 2 \sqrt{g_x^2 + g_y^2} gx2+gy2
梯度角度定义为:
a r c t a n ( g x g y ) arctan(\frac{g_x}{g_y}) arctan(gygx)
基于梯度的计算方式一般分成两步:
Sobel算子的一般过程:
利用下面的两个掩码对图像进行计算,一个是X方向上的,一个是Y方向上的:
X方向上的掩码
[ − 1 0 1 − 2 0 2 − 1 0 1 ] \begin{bmatrix} -1 & 0 & 1\\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} ⎣⎡−1−2−1000121⎦⎤
g ( x ) = − f ( x − 1 , y − 1 ) + f ( x + 1 , y − 1 ) − 2 f ( x − 1 , y ) + 2 f ( x + 1 , y ) − f ( x − 1 , y + 1 ) + f ( x + 1 , y + 1 ) g(x) = -f(x-1, y-1) + f(x+1, y-1) -2f(x-1,y) \\+2f(x+1, y) - f(x-1, y+1) + f(x+1,y+1) g(x)=−f(x−1,y−1)+f(x+1,y−1)−2f(x−1,y)+2f(x+1,y)−f(x−1,y+1)+f(x+1,y+1)
Y方向上的掩码
[ − 1 − 2 − 1 0 0 0 1 2 1 ] \begin{bmatrix} -1 & -2 & -1\\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} ⎣⎡−101−202−101⎦⎤
g ( y ) = − f ( x − 1 , y − 1 ) − 2 f ( x + 1 , y − 1 ) − f ( x − 1 , y ) + 2 f ( x + 1 , y ) − f ( x − 1 , y + 1 ) + f ( x + 1 , y + 1 ) g(y) = -f(x-1, y-1) - 2f(x+1, y-1) -f(x-1,y) \\+2f(x+1, y) - f(x-1, y+1) + f(x+1,y+1) g(y)=−f(x−1,y−1)−2f(x+1,y−1)−f(x−1,y)+2f(x+1,y)−f(x−1,y+1)+f(x+1,y+1)
直接通过掩膜计算就可以得到sobel算子计算后的图像。
我使用的是opencv,具体的可以参考官网的说明文档:
https://docs.opencv.org/4.6.0/d4/d86/group__imgproc__filter.html#gacea54f142e81b6758cb6f375ce782c8d
这里有一个问题,就是在求梯度的过程中,是个1 * 3或者3 * 1的向量,这里是一个矩阵,虽然看上去和上面的很类似,而且官网文档上有这么一句:
The Sobel operators combine Gaussian smoothing and differentiation,就是说综合和求梯度和高斯模糊两种操作。
我的理解如下:X和Y上的梯度就和第一部分描述的一样,就是按照梯度的定义来计算的,而 3 * 3矩阵中的中间部分[-2, 0, 2]加上两边的[-1, 0, 1]组成的矩阵是服从高斯分布的,参考:https://blog.csdn.net/Quincuntial/article/details/50625389。
而且在opencv的sobel算子中,这个矩阵还可以是5 * 5和7 * 7的,我的理解也是这个矩阵的各个数字在某种程度上是服从高斯分布的。
不知道正不正确,如果有哪位朋友清楚,请指教,谢谢。
拉普拉斯算子和sobel很类似,实际上就是x方向上做两次sobel算子计算,然后在y方向上也做两次sobel算子计算,然后再把两者相加。
如果ksize=1的话,就使用一个特殊的掩膜进行计算,可以参考opencv官方文档:
https://docs.opencv.org/4.6.0/d4/d86/group__imgproc__filter.html#gad78703e4c8fe703d479c1860d76429e6
官网上写的是:
d s t = Δ s r c = ∇ 2 f ( x ) + ∇ 2 f ( y ) dst=\Delta src=\nabla ^2f(x) + \nabla ^2f(y) dst=Δsrc=∇2f(x)+∇2f(y)
得到梯度图像后,对整个梯度图像进行统计,一般来说可以用梯度平均值来代表原始图像的梯度分布:
调用cv2中的mean函数计算梯度:
score = cv2.mean(img_lap)
调用cv2中的sumElems函数计算梯度图中所有点之和
score = cv2.sumElems(img_lap)
我从网上找了两张图,一张是对焦不那么清楚的,一张是对焦相对比较清楚的,我们用上述的方式进行一个简单的实验:
代码如下:
img_blur = cv2.imread("/Users/zoulei/files/personal/images/1.jpg", 0)
img_blur_lap = cv2.Laplacian(img_blur, cv2.CV_8UC1, ksize=3)
score_blur = cv2.sumElems(img_blur_lap)
print(score_blur)
mean_value_blur_laplacian = cv2.mean(img_blur_lap)
print(mean_value_blur_laplacian)
img_clear = cv2.imread("/Users/zoulei/files/personal/images/2.jpg", 0)
img_clear_lap = cv2.Laplacian(img_clear, cv2.CV_8UC1, ksize=3)
score_clear = cv2.sumElems(img_clear_lap)
print(score_clear)
mean_value_clear_laplacian = cv2.mean(img_clear_lap)
print(mean_value_clear_laplacian)
输出结果:
score_blur:(411391.0, 0.0, 0.0, 0.0)
mean_value_blur_laplacian:(10.624767561983472, 0.0, 0.0, 0.0)
score_clear:(635569.0, 0.0, 0.0, 0.0)
mean_value_clear_laplacian:(16.11238148354713, 0.0, 0.0, 0.0)
从结果可以看出,通过拉普拉斯算子是可以计算出图像的清晰度来的。
当然,有一种情况,在光学相机拍摄的图像里面,有些是会突出前景而虚化背景的,这种情况下就需要先提取一下感兴趣区域之后再对感兴趣区域进行计算了。