OpenCV-Python实践之图像梯度算子

图像梯度算子简介

  相信只要是懂些图像处理的知识,都知道图像梯度的含义。不知道是否考虑过为什么图像梯度如此广泛认知与使用?为什么不使用图像纹理、图像色彩、图像相位等等,在这里我并不是说上述除了图像梯度之外,其它的图像信息不重要,我只是想说图像梯度最为广泛的被研究与使用。下面我们来看一幅图像:

  从上图坐标为灰度图像,右边为Laplacian算子提取的图像梯度图;现在我们来看一下左边图片中的A、B、C、D、E、F区域,你可以通过这些子区域发现处于图像中的哪个位置吗?通过人眼观察可以轻易得出结果:E、F最容易分辨,C、D能够确定更小的范围区域,A、B最难分辨在哪个范围。OK,让我们来看右边的梯度算子,可以发现:E、F小区域在梯度图像上较为完整的保留下来,C、D保留边缘曲线,A、B已经完全发现不出什么明显的特征。

  通过上述一个简单的观察,你会发现:E、F是角点区域(梯度各个方向变化最为明显),C、D为边缘区域(梯度垂直于边缘方向最为明显)、A、B为平坦区域(梯度各个方向变化都不明显)。这不就是后面做特征点检测的信息丰富度准则,角点最为稳定、边缘检测等特征。图像梯度提取最为简单直接,能够有效的描述图像的原始状态,因此发展一系列的图像梯度算子:Roberts、Prewitt、Sobel、Laplacian、Scharr等。下面介绍一下比较经常使用的梯度提取算子卷积核函数:

Sobel算子:

Wsobelx=[w00w01w02w10w11w12w20w21w22]=[−10+1−20+2−10+1]W_{sobelx}=
\left[
\begin{matrix}
w_{00} & w_{01} & w_{02} \\
w_{10} & w_{11} & w_{12} \\
w_{20} & w_{21} & w_{22}
\end{matrix}
\right] =
\left[
\begin{matrix}
-1 & 0 & +1 \\
-2 & 0 & +2 \\
-1 & 0 & +1
\end{matrix}
\right]

Wsobely=[w00w01w02w10w11w12w20w21w22]=[−1−2−1000+1+2+1]W_{sobely}=
\left[
\begin{matrix}
w_{00} & w_{01} & w_{02} \\
w_{10} & w_{11} & w_{12} \\
w_{20} & w_{21} & w_{22}
\end{matrix}
\right] =
\left[
\begin{matrix}
-1 & -2 & -1 \\
0 & 0 & 0 \\
+1 & +2 & +1
\end{matrix}
\right]

分别为Sobel算子针对XXYY方向提取的图像,然后对梯度图像:
(1)Gimage=Gx2+Gy2G_{image}=\sqrt{G^{2}_x+G^{2}_y}\tag{1}

  参数解释:GimageG_{image}为Sobel算子提取的梯度图像,GxG_xWsobelxW_{sobelx}卷积核与原始图像卷积提取X方向的结果,GyG_yWsobelyW_{sobely}卷积核与原始图像卷积提取YY方向的结果。

Scharr算子:

Wscharrx=[w00w01w02w10w11w12w20w21w22]=[−30+3−100+10−30+3]W_{scharrx}=
\left[
\begin{matrix}
w_{00} & w_{01} & w_{02} \\
w_{10} & w_{11} & w_{12} \\
w_{20} & w_{21} & w_{22}
\end{matrix}
\right] =
\left[
\begin{matrix}
-3 & 0 & +3 \\
-10 & 0 & +10 \\
-3 & 0 & +3
\end{matrix}
\right]

Wscharry=[w00w01w02w10w11w12w20w21w22]=[−3−10−3000+3+10+3]W_{scharry}=
\left[
\begin{matrix}
w_{00} & w_{01} & w_{02} \\
w_{10} & w_{11} & w_{12} \\
w_{20} & w_{21} & w_{22}
\end{matrix}
\right] =
\left[
\begin{matrix}
-3 & -10 & -3 \\
0 & 0 & 0 \\
+3 & +10 & +3
\end{matrix}
\right]

Scharr算子与Sobel算子原理一致,只是改进版,效果要比Sobel好些。

Laplacian算子:

  拉普拉斯算子是最广为人知的算子,完全的尺度不变性,依赖二阶导数能够提取稳定的特征点,著名的差分高斯近似加速等等。其提取图像特征的核函数为:

Wlaplacian=[w00w01w02w10w11w12w20w21w22]=[0101−41010]W_{laplacian}=
\left[
\begin{matrix}
w_{00} & w_{01} & w_{02} \\
w_{10} & w_{11} & w_{12} \\
w_{20} & w_{21} & w_{22}
\end{matrix}
\right] =
\left[
\begin{matrix}
0 & 1 & 0 \\
1 & -4 & 1 \\
0 & 1 & 0
\end{matrix}
\right]

  利用卷积核与图像进行卷积运算,以此来提取图像梯度。关于卷积操作具体解释可以参考图像滤波算法系列实战总结之一博文开头卷积示例图片,抱歉暂无找到引用何处,发现后会添加上。

OpenCV-Python代码实践
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('./data/feature_building.jpg', 0)

laplacian = cv2.Laplacian(img, cv2.CV_64F)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)

sobelxy = np.sqrt(sobelx*sobelx + sobely*sobely)

scharrx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=-1)
scharry = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=-1)

scharrxy = np.sqrt(scharrx*scharrx + scharry*scharry)


plt.subplot(2, 4, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 2), plt.imshow(laplacian, cmap='gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 3), plt.imshow(sobelx, cmap='gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 4), plt.imshow(sobely, cmap='gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 5), plt.imshow(scharrx, cmap='gray')
plt.title('Scharr X'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 6), plt.imshow(scharry, cmap='gray')
plt.title('Scharr Y'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 7), plt.imshow(sobelxy, cmap='gray')
plt.title('Sobel XY'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 4, 8), plt.imshow(scharrxy, cmap='gray')
plt.title('Scharr XY'), plt.xticks([]), plt.yticks([])

plt.show()
实验结果
参考

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_gradients/py_gradients.html

相关推荐:

如何在 Tkinter 中实现无闪烁的图像缩放动画

本文详解Tkinter图像缩放动画中闪烁问题的根本原因(重复创建canvas图像项+未控制帧率),并提供基于canvas.itemconfig()更新图像和after()驱动定时帧循环的专业解决方案,附完整可运行类封装示例。 本文详解tkinter图像缩放动画中闪烁问题的根本原因(重复创建canva...

Tkinter 图像缩放动画无闪烁实现指南

本文详解如何在Tkinter中实现平滑、无闪烁的图像缩放动画,核心在于避免重复创建canvas图像项、使用itemconfig动态更新图像,并通过after()实现可控帧率与事件循环协同。 本文详解如何在tkinter中实现平滑、无闪烁的图像缩放动画,核心在于避免重复创建canvas图像项、使用`i...

为什么特征降维后的梯度下降反而更慢?——解析 NumPy 循环开销与向量化优化

本文揭示了在使用svd降维后梯度下降运行时间不降反升的根本原因:原始实现中嵌套python循环和动态列表操作主导了耗时,而非矩阵运算本身;通过向量化重写(消除外层学习率循环、预分配数组、批量更新参数),可使小规模特征集真正发挥计算优势。 本文揭示了在使用svd降维后梯度下降运行时间不降反升的根本原因...

Plotly 图像导出在 Windows 11 上卡死的解决方案

在Windows11中使用Plotly的write_image()导出PNG时进程无响应,根本原因是Kaleido依赖版本存在兼容性问题;降级至kaleido==0.1.0.post1可稳定解决该问题。 在windows11中使用plotly的`write_image()`导出png时进程无响应,根...

PyAutoGUI 中 locateAllOnScreen 异常捕获的正确实践

locateAllOnScreen在未找到图像时会抛出pyscreeze.ImageNotFoundException,而直接exceptImageNotFoundException:无法捕获——必须显式导入并指定完整异常路径,否则异常将中断程序。本文详解标准捕获方式、安全遍历策略及实用规避技巧。 ...