python的opencv操作记录(九)——图像清晰度计算

文章目录

  • 图像清晰度计算的一般思路
    • 图像梯度
    • 图像梯度绝对值与梯度角度
  • 基于梯度的方式
      • 计算梯度算子1——Sobel算子
      • 计算梯度算子2——Laplacian算子
    • 梯度统计评分
      • 平均梯度
      • 梯度总和
  • Demo

图像清晰度计算的一般思路

定义图像清晰度是一个比较定制化,或者说比较偏业务属性的,就是说要根据需要来定义图像的清晰度。
但是一般来说,还是有个一般过程。

  • 一般来说,清晰的图像的另外一个含义就是轮廓清晰,物体之间的边缘明显。从图像频域的角度来看,就是图像的高频分量较多。
  • 通过图像求导的来得到图像的梯度,梯度越大,说明像素变化越大,物体之间的边缘也就越清晰。

图像的频域之前的文章说过了,这里说一下图像的梯度问题。

图像梯度

图像梯度的定义分为两个维度:

  • X方向上的梯度:当前像素右侧的像素值减去当前像素左侧像素的像素值
  • Y方向上的梯度:当前像素下方的像素值减去当前像素上方像素的像素值

用一个向量来表示的话就是:
∇ 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(x1,y)f(x,y+1)f(x,y1)]

在图像计算领域中,最经典的计算方式就是掩码方式,或者说是卷积的方式。
上面一个公式在图像领域就可以用一个掩码来表示:

  • X方向的掩码:
    [ − 1 , 0 , 1 ] \begin{bmatrix} -1, 0, 1 \end{bmatrix} [1,0,1]
  • Y方向的掩码:
    [ − 1 , 0 , 1 ] \begin{bmatrix} -1, \\ 0, \\ 1 \end{bmatrix} 1,0,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)

基于梯度的方式

基于梯度的计算方式一般分成两步:

  • 计算梯度
  • 针对梯度进行统计评分

计算梯度算子1——Sobel算子

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} 121000121

      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(x1,y1)+f(x+1,y1)2f(x1,y)+2f(x+1,y)f(x1,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} 101202101

      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(x1,y1)2f(x+1,y1)f(x1,y)+2f(x+1,y)f(x1,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的,我的理解也是这个矩阵的各个数字在某种程度上是服从高斯分布的。
不知道正不正确,如果有哪位朋友清楚,请指教,谢谢。

计算梯度算子2——Laplacian算子

拉普拉斯算子和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)

Demo

我从网上找了两张图,一张是对焦不那么清楚的,一张是对焦相对比较清楚的,我们用上述的方式进行一个简单的实验:

python的opencv操作记录(九)——图像清晰度计算_第1张图片
python的opencv操作记录(九)——图像清晰度计算_第2张图片

代码如下:

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)

从结果可以看出,通过拉普拉斯算子是可以计算出图像的清晰度来的。
当然,有一种情况,在光学相机拍摄的图像里面,有些是会突出前景而虚化背景的,这种情况下就需要先提取一下感兴趣区域之后再对感兴趣区域进行计算了。

你可能感兴趣的:(python,opencv,图像清晰度,图像梯度)