Python计算机视觉 第10章-OpenCV
OpenCV 是一个C++ 库,用于(实时)处理计算视觉问题。实时处理计算机视觉的 C++ 库,最初由英特尔公司开发,现由 Willow Garage 维护。OpenCV 是在 BSD 许可下发布的开源库,这意味着它对于学术研究和商业应用是免费的。
10.1 OpenCV的Python接口
OpenCV(Open Source Computer Vision Library)是一个开源计算机视觉库,提供了大量的图像和视频处理功能。其 Python 接口使得用户能够方便地在 Python 中使用 OpenCV 的功能。OpenCV Python 接口通过 cv2
模块提供了对各种计算机视觉算法和工具的访问,包括图像处理、视频分析、机器学习等。
使用
#直接pip没法安装下来
pip install cv2#需要按照如下命令安装才会成功
pip install opencv-python
如果安装速度太慢可以使用清华源:
pip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple
10.2 OpenCV基础知识
主要功能:
-
图像读取和显示
- 读取图像:
cv2.imread()
- 显示图像:
cv2.imshow()
- 保存图像:
cv2.imwrite()
- 读取图像:
-
图像处理
- 图像转换:
cv2.cvtColor()
- 图像平滑:
cv2.GaussianBlur()
,cv2.medianBlur()
- 边缘检测:
cv2.Canny()
- 图像转换:
-
几何变换
- 图像缩放:
cv2.resize()
- 旋转和仿射变换:
cv2.warpAffine()
- 透视变换:
cv2.warpPerspective()
- 图像缩放:
-
特征检测与描述
- 角点检测:
cv2.cornerHarris()
- 特征匹配:
cv2.BFMatcher()
,cv2.FlannBasedMatcher()
- 角点检测:
-
视频处理
- 捕捉视频:
cv2.VideoCapture()
- 播放视频:
cv2.imshow()
(与图像处理相同)
- 捕捉视频:
-
机器学习与深度学习
- 加载预训练模型:
cv2.dnn.readNet()
- 进行推理:
cv2.dnn.forward()
- 加载预训练模型:
示例代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图像
image = cv2.imread('test.jpg')# 显示原图
cv2.imshow('Original Image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()# 转换为灰度图
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 图像平滑
smoothed_image = cv2.GaussianBlur(gray_image, (5, 5), 0)# 边缘检测
edges = cv2.Canny(smoothed_image, 100, 200)# 显示处理结果
fig, axs = plt.subplots(1, 3, figsize=(15, 5))
axs[0].imshow(cv2.cvtColor(gray_image, cv2.COLOR_BGR2RGB), cmap='gray')
axs[0].set_title('Gray Image')
axs[0].axis('off')axs[1].imshow(cv2.cvtColor(smoothed_image, cv2.COLOR_BGR2RGB), cmap='gray')
axs[1].set_title('Smoothed Image')
axs[1].axis('off')axs[2].imshow(cv2.cvtColor(edges, cv2.COLOR_BGR2RGB), cmap='gray')
axs[2].set_title('Edges')
axs[2].axis('off')plt.show()
处理结果如下:
实验图1 示例代码处理结果
其中:
-
读取图像:
cv2.imread('test.jpg)
-
转换为灰度图:
cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
-
图像平滑:
cv2.GaussianBlur(gray_image, (5, 5), 0)
-
边缘检测:
cv2.Canny(smoothed_image, 100, 200)
-
显示结果:使用
matplotlib
展示灰度图、平滑图像和边缘检测结果
10.3 处理视频
OpenCV 提供了全面的视频处理功能,主要包括以下几个方面:
-
读取视频:
- 打开视频文件或摄像头进行视频流读取。
- 使用
cv2.VideoCapture()
进行视频捕捉。
-
显示视频:
- 显示视频帧或视频流。
- 使用
cv2.imshow()
显示每一帧图像。
-
处理视频:
- 对视频帧进行各种图像处理操作,如颜色转换、滤镜应用、对象检测等。
-
写入视频:
- 将处理后的视频保存到文件中。
- 使用
cv2.VideoWriter()
进行视频编写和保存。
-
视频属性获取:
- 获取视频的帧率、分辨率、总帧数等信息。
- 通过
cv2.CAP_PROP_FPS
、cv2.CAP_PROP_FRAME_WIDTH
、cv2.CAP_PROP_FRAME_HEIGHT
获取视频属性。
-
逐帧处理:
- 对每一帧进行个性化处理,例如去噪、边缘检测、特效添加等。
-
视频流处理:
- 实时处理来自摄像头的视频流,包括实时特效应用和流媒体处理。
这些功能使得 OpenCV 能够实现丰富的视频分析和处理任务,如视频编辑、运动跟踪、实时监控等。
10.4 跟踪
视频跟踪是计算机视觉中的一项重要任务,用于在视频序列中持续追踪特定的对象。OpenCV 提供了多种跟踪算法,可以用于实现目标跟踪功能。
主要功能:
-
初始化跟踪器:
- 使用预定义的跟踪器算法(如 KLT、MOSSE、CSRT 等)来初始化跟踪器。
-
目标检测:
- 在视频的第一帧中检测并确定要跟踪的目标区域。
-
跟踪目标:
- 在后续帧中持续追踪目标,更新目标的位置。
-
更新跟踪器:
- 根据每帧中的目标位置更新跟踪器。
-
可视化跟踪结果:
- 在视频帧上绘制跟踪结果,例如矩形框或轨迹。
常见跟踪器:
-
KLT(Kanade-Lucas-Tomasi):
- 基于特征点跟踪的方法,适用于处理局部特征的目标。
-
MOSSE(Minimum Output Sum of Squared Error):
- 基于相关滤波器的跟踪方法,速度快且适用于低分辨率目标。
-
CSRT(Discriminative Correlation Filter with Channel and Spatial Reliability):
- 结合了通道和空间可靠性的跟踪方法,适用于处理尺度变化和遮挡情况。
-
MedianFlow:
- 基于光流的方法,适用于处理稳定的目标跟踪。
应用场景
- 实时监控:跟踪视频监控中的运动目标。
- 视频分析:分析运动对象的轨迹和行为。
- 人机交互:在增强现实和虚拟现实中跟踪用户的动作。
通过这些跟踪功能,OpenCV 能够帮助实现高效的目标跟踪,广泛应用于安防、自动驾驶、运动分析等领域。
10.4.2 Lucas-Kanade 算法
Lucas-Kanade 算法 是一种经典的光流法,用于在视频序列中估计每一帧图像中像素的运动。它基于局部区域的假设,通过求解局部区域内光流的速度来实现目标的跟踪和运动估计。
核心思想
-
局部光流假设:
- 假设目标在连续帧之间的运动是局部一致的,即在小区域内所有像素的运动是相同的。
-
光流约束方程:
- 基于光流约束方程: I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0
其中, I x I_x Ix 和 I y I_y Iy 分别是图像在 x x x 和 y y y 方向上的梯度, I t I_t It 是时间梯度(图像亮度随时间的变化), u u u 和 v v v 是光流的水平和垂直分量。
- 基于光流约束方程: I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0
-
局部光流求解:
- 使用局部窗口内的像素梯度信息,通过最小二乘法来估计光流的速度。通常,采用 3 × 3 3 \times 3 3×3 的窗口进行光流的计算。
-
光流计算:
- 通过求解以下线性方程组得到光流速度:
[ ∑ I x 2 ∑ I x I y ∑ I x I y ∑ I y 2 ] [ u v ] = − [ ∑ I x I t ∑ I y I t ] \begin{bmatrix} \sum I_x^2 & \sum I_x I_y \\ \sum I_x I_y & \sum I_y^2 \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} = - \begin{bmatrix} \sum I_x I_t \\ \sum I_y I_t \end{bmatrix} [∑Ix2∑IxIy∑IxIy∑Iy2][uv]=−[∑IxIt∑IyIt]
其中, ∑ \sum ∑ 表示在局部窗口内的积分。
- 通过求解以下线性方程组得到光流速度:
优点
- 准确性:在平滑和一致的区域内能够提供较高的准确性。
- 实现简单:相对简单的数学模型,易于实现。
缺点
- 对大位移敏感:在目标快速移动或存在较大位移的情况下,光流计算的准确性可能降低。
- 需要平滑区域:算法在具有纹理的区域效果较好,对于平坦区域或重复纹理区域可能不够准确。
应用场景
- 运动检测:估计视频序列中物体的运动。
- 目标跟踪:在视频流中追踪特定目标的运动。
- 光流估计:用于图像对齐、稳定化和动作分析等。
Lucas-Kanade 算法因其简单有效的特性,广泛应用于各种计算机视觉任务中,是视频处理和目标跟踪中的基础算法之一。
如图10-6所示:
图 10-6:通过 LKTrack 类利用 Lucas-Kanade 算法进行跟踪
10.5 更多实例
10.5.1 图像修复
图像修复是指对图像中丢失或损坏的部分进行重建的过程。这个过程不仅包括用于恢复丢失数据或损坏部分的算法,还包括在照片编辑应用程序中去除不需要的元素,如红眼或物体。图像修复旨在填补图像中的缺失区域,使其恢复到尽可能完整和自然的状态。
主要步骤:
-
标记损坏区域:
- 确定图像中需要修复的区域,通常通过掩模图像标记这些区域。掩模图像中的标记区域会指示需要修复的部分。
-
选择修复算法:
- 选择适当的图像修复算法。例如,均值填补(Inpainting)方法使用周围像素的信息来填补损坏区域。Navier-Stokes 算法和纹理合成等方法也可用于不同类型的图像修复。
-
应用修复算法:
- 利用所选的算法对损坏区域进行修复。算法会根据周围区域的图像数据来填补缺失部分。
-
处理结果:
- 对修复后的图像进行后处理,以确保修复区域与周围区域自然融合。检查和调整修复效果,以实现更好的视觉效果。
应用场景:
- 图像恢复:修复老旧或损坏的照片,使其恢复到原始状态。
- 去除红眼:在照片编辑中去除红眼效果。
- 物体去除:在照片中去除不需要的物体或标记,填补被去除部分的图像信息。
- 遮挡修复:处理由于遮挡或图像损坏导致的缺失区域。
图像修复技术可以有效地恢复图像的完整性和视觉质量,广泛应用于图像编辑、数字修复以及计算机视觉等领域。
如图10-8所示:
图 10-8:用 OpenCV 进行图像修复的示例。左图显示了由用户标记的“破损”区域。右图显示了经过图像修复后的结果
10.5.2 利用霍夫变换检测直线
霍夫变换 是一种经典的图像处理技术,用于检测图像中的直线或其他形状。霍夫变换通过将图像空间的直线检测转换为参数空间的峰值检测,从而实现直线的检测。
核心思想
-
直线方程:
- 在笛卡尔坐标系中,直线方程为 y = m x + c y = mx + c y=mx+c,其中 m m m 是斜率, c c c 是截距。
- 在霍夫变换中,通常使用极坐标系表示直线: ρ = x cos θ + y sin θ \rho = x \cos \theta + y \sin \theta ρ=xcosθ+ysinθ
其中, ρ \rho ρ 是直线到原点的距离, θ \theta θ 是直线的角度。
-
参数空间:
- 通过将每个图像中的点转换为参数空间中的直线表示,所有的直线将映射到参数空间中的一条曲线。
-
累加器:
- 在参数空间中,对每条曲线进行累加,形成一个累加器数组。直线的峰值对应于参数空间中的高响应值。
-
峰值检测:
- 在累加器中寻找峰值,这些峰值对应于图像中真实存在的直线。
霍夫变换步骤
-
边缘检测:
- 使用边缘检测算法(如 Canny 边缘检测)检测图像中的边缘点。
-
霍夫变换:
- 将每个边缘点转换为参数空间中的曲线,并在累加器中进行累加。
-
峰值检测:
- 在累加器中检测峰值,找到参数空间中的直线。
-
绘制直线:
- 根据检测到的直线参数,在原图像上绘制直线。
应用场景
- 车道检测:用于自动驾驶系统中检测车道标线。
- 建筑物结构分析:分析建筑物中的直线结构。
- 图像校正:校正图像中的直线变形。
霍夫变换通过将图像空间中的问题转换到参数空间,能够有效检测直线,并广泛应用于各种计算机视觉任务中。
示例代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图像
image = cv2.imread('img_1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 边缘检测
edges = cv2.Canny(gray, 50, 150)# 霍夫变换检测直线
lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)# 在图像上绘制直线
if lines is not None:for line in lines:rho, theta = line[0]a = np.cos(theta)b = np.sin(theta)x0 = a * rhoy0 = b * rhox1 = int(x0 + 1000 * (-b))y1 = int(y0 + 1000 * (a))x2 = int(x0 - 1000 * (-b))y2 = int(y0 - 1000 * (a))cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)# 显示结果
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Detected Lines')
plt.axis('off')
plt.show()
处理结果如下:
实验图2 直线检测结果