当前位置: 首页 > news >正文

深度学习之opencv篇

引言:为什么选择 OpenCV?

在当今数字化时代,图像处理和计算机视觉技术已渗透到我们生活的方方面面 —— 从手机拍照的美颜功能到自动驾驶的环境感知,从医学影像分析到安防监控系统,背后都离不开高效的视觉处理算法。而OpenCV(Open Source Computer Vision Library) 作为这一领域最受欢迎的开源库,自 2000 年首次发布以来,已成为百万开发者的首选工具。

OpenCV 由英特尔公司发起并主导开发,如今由非盈利组织 OpenCV.org 维护。它支持多种编程语言(C++、Python、Java 等),可在 Windows、Linux、macOS、Android、iOS 等多平台运行,更重要的是,它提供了超过 2500 个优化过的算法,涵盖从基础图像处理到高级计算机视觉的全领域应用。

本文将带您全面探索 OpenCV 的核心功能,通过大量实战代码示例,从基础操作到高级应用,逐步掌握这一强大工具的使用技巧。无论您是图像处理新手,还是希望提升技能的开发者,本文都能为您提供系统的指导。

一、OpenCV 环境搭建

在开始之前,我们需要先搭建 OpenCV 开发环境。本节将详细介绍不同操作系统下的安装方法,以 Python 为例(因其简洁易学,适合快速验证算法)。

1.1 Windows 系统安装

  1. 安装 Python:前往 Python 官网 下载最新版本,勾选 "Add Python to PATH",按提示完成安装。
  2. 安装 OpenCV:打开命令提示符(CMD),输入以下命令:

    bash

    pip install opencv-python  # 基础包
    pip install opencv-contrib-python  # 扩展包(包含专利算法)
    
  3. 验证安装

    python

    运行

    import cv2
    print(cv2.__version__)  # 输出版本号即表示安装成功
    

1.2 Linux/macOS 系统安装

  1. 安装 Python
    • Linux:多数系统预装 Python,可通过 sudo apt install python3 安装
    • macOS:使用 Homebrew:brew install python3
  2. 安装 OpenCV

    bash

    pip3 install opencv-python
    pip3 install opencv-contrib-python
    
  3. 验证安装:同 Windows 步骤。

二、OpenCV 核心概念与基础操作

2.1 图像的表示方式

在计算机中,图像本质上是由像素点组成的矩阵:

  • 灰度图:单通道矩阵,每个像素值范围为 [0, 255](0 表示黑色,255 表示白色)
  • 彩色图:多通道矩阵,OpenCV 默认使用 BGR 格式(与 RGB 相反),每个通道像素值范围同样为 [0, 255]

例如,一张 480×640 的彩色图在 OpenCV 中会被表示为一个形状为 (480, 640, 3) 的 NumPy 数组(行 × 列 × 通道)。

2.2 图像的读取、显示与保存

这是 OpenCV 最基础的操作,也是所有后续处理的起点。

python

运行

import cv2
import numpy as np# 1. 读取图像
# 参数1:图像路径(中文路径需注意编码问题)
# 参数2:读取模式(cv2.IMREAD_COLOR:彩色图,默认值;cv2.IMREAD_GRAYSCALE:灰度图;cv2.IMREAD_UNCHANGED:包含Alpha通道)
img = cv2.imread('test.jpg', cv2.IMREAD_COLOR)# 检查图像是否读取成功
if img is None:print("无法读取图像,请检查路径是否正确")
else:# 2. 显示图像# 参数1:窗口名称(字符串)# 参数2:要显示的图像cv2.imshow('Original Image', img)# 等待用户按键(0表示无限等待,单位为毫秒)cv2.waitKey(0)# 3. 保存图像# 参数1:保存路径及文件名# 参数2:要保存的图像cv2.imwrite('saved_image.jpg', img)# 关闭所有OpenCV窗口cv2.destroyAllWindows()

注意事项

  • 若图像路径包含中文,直接使用 cv2.imread 可能失败,需通过 NumPy 读取:

    python

    运行

    import numpy as np
    img = cv2.imdecode(np.fromfile('中文路径.jpg', dtype=np.uint8), cv2.IMREAD_COLOR)
    
  • cv2.waitKey() 是必不可少的,否则窗口会一闪而过。

2.3 图像属性与通道操作

获取图像的基本信息(尺寸、通道数等),并对通道进行拆分与合并:

python

运行

import cv2img = cv2.imread('test.jpg')# 获取图像属性
height, width, channels = img.shape  # 彩色图
# 灰度图的shape为(height, width),可通过len(img.shape)判断:1表示灰度图,3表示彩色图
print(f"图像尺寸:{height}×{width},通道数:{channels}")
print(f"数据类型:{img.dtype}")  # 通常为uint8# 拆分通道
b, g, r = cv2.split(img)  # 拆分B、G、R通道(注意顺序)# 合并通道
merged_img = cv2.merge([b, g, r])  # 需按BGR顺序合并# 单独显示某个通道(以蓝色通道为例)
# 方法1:将其他通道设为0
blue_img = np.zeros_like(img)
blue_img[:, :, 0] = b  # 仅保留蓝色通道# 方法2:创建单通道图像后扩展为3通道(便于显示)
blue_gray = cv2.cvtColor(blue_img, cv2.COLOR_BGR2GRAY)
blue_3ch = cv2.cvtColor(blue_gray, cv2.COLOR_GRAY2BGR)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Blue Channel', blue_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

扩展知识:通道拆分也可通过数组切片实现(效率更高):

python

运行

b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]

三、图像几何变换

图像几何变换是调整图像尺寸、角度或位置的基础操作,广泛应用于图像对齐、缩放适配等场景。

3.1 图像缩放

python

运行

import cv2img = cv2.imread('test.jpg')# 方法1:指定目标尺寸(width, height)
resized1 = cv2.resize(img, (600, 400))# 方法2:指定缩放比例
scale = 0.5  # 缩小为原来的50%
resized2 = cv2.resize(img, None, fx=scale, fy=scale)# 选择插值方法(不同场景适用不同方法)
# - cv2.INTER_NEAREST:最近邻插值(速度快,质量低)
# - cv2.INTER_LINEAR:双线性插值(默认值,平衡速度和质量)
# - cv2.INTER_CUBIC:双三次插值(质量高,速度慢,适合放大图像)
# - cv2.INTER_AREA:区域插值(适合缩小图像,可避免摩尔纹)
resized_high_quality = cv2.resize(img, (1200, 800), interpolation=cv2.INTER_CUBIC)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Resized (600x400)', resized1)
cv2.imshow('Resized (50%)', resized2)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2 图像旋转

python

运行

import cv2
import numpy as npimg = cv2.imread('test.jpg')
height, width = img.shape[:2]# 1. 获取旋转矩阵
# 参数1:旋转中心(这里设为图像中心)
# 参数2:旋转角度(正值表示逆时针旋转)
# 参数3:缩放比例
M = cv2.getRotationMatrix2D((width/2, height/2), 45, 1)# 2. 执行旋转
# 参数3:输出图像尺寸(width, height)
rotated = cv2.warpAffine(img, M, (width, height))# 扩展:旋转后避免裁剪(计算新尺寸)
angle = 45
radians = np.radians(angle)
new_width = int(width * np.abs(np.cos(radians)) + height * np.abs(np.sin(radians)))
new_height = int(width * np.abs(np.sin(radians)) + height * np.abs(np.cos(radians)))# 调整旋转矩阵(使旋转中心适配新尺寸)
M[0, 2] += (new_width / 2) - (width / 2)
M[1, 2] += (new_height / 2) - (height / 2)rotated_full = cv2.warpAffine(img, M, (new_width, new_height))# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Rotated (45 degrees)', rotated)
cv2.imshow('Rotated (no crop)', rotated_full)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.3 图像平移与翻转

python

运行

import cv2
import numpy as npimg = cv2.imread('test.jpg')
height, width = img.shape[:2]# 1. 图像平移
# 平移矩阵:[[1,0,dx], [0,1,dy]],dx为水平偏移(正值右移),dy为垂直偏移(正值下移)
dx, dy = 100, 50
M = np.float32([[1, 0, dx], [0, 1, dy]])
translated = cv2.warpAffine(img, M, (width, height))# 2. 图像翻转
# 参数2:翻转方式(0:垂直翻转;1:水平翻转;-1:同时垂直和水平翻转)
flip_vertical = cv2.flip(img, 0)
flip_horizontal = cv2.flip(img, 1)
flip_both = cv2.flip(img, -1)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Translated', translated)
cv2.imshow('Flip Vertical', flip_vertical)
cv2.imshow('Flip Horizontal', flip_horizontal)
cv2.imshow('Flip Both', flip_both)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、色彩空间转换

色彩空间是描述颜色的数学模型,不同场景需要不同的色彩空间。OpenCV 支持多种色彩空间转换,以下是最常用的几种。

4.1 常用色彩空间简介

色彩空间特点与应用场景
BGROpenCV 默认格式,适合显示和存储
RGB多数图像库(如 PIL)使用的格式,与 BGR 仅通道顺序不同
GRAY灰度图,单通道,简化计算,常用于预处理
HSV分离亮度(V)和色彩(H、S),适合颜色检测
YCrCb用于 JPEG 压缩,Y 通道为亮度,适合肤色检测

4.2 色彩空间转换代码示例

python

运行

import cv2img = cv2.imread('test.jpg')# 1. BGR 转 RGB(用于与其他库交互)
rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 2. BGR 转灰度图
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 3. BGR 转 HSV
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)# 4. BGR 转 YCrCb
ycrcb_img = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)# 显示结果
cv2.imshow('BGR', img)
cv2.imshow('RGB', rgb_img)  # 注意:OpenCV显示RGB图会偏色,因其默认按BGR解析
cv2.imshow('GRAY', gray_img)
cv2.imshow('HSV', hsv_img)
cv2.imshow('YCrCb', ycrcb_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

4.3 实战:基于 HSV 的颜色检测

HSV 色彩空间对光照变化不敏感,是颜色检测的理想选择。以下示例实现检测图像中的红色物体:

python

运行

import cv2
import numpy as npimg = cv2.imread('red_object.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)# 定义红色的HSV范围(红色在HSV中有两个区间)
lower_red1 = np.array([0, 120, 70])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 120, 70])
upper_red2 = np.array([180, 255, 255])# 创建掩码(符合范围的像素设为255,否则为0)
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = mask1 | mask2  # 合并两个掩码# 对原图和掩码执行位运算,提取红色区域
result = cv2.bitwise_and(img, img, mask=mask)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Mask', mask)
cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

技巧:如何确定颜色的 HSV 范围?

  1. 用绘图工具取目标颜色的 BGR 值
  2. 转换为 HSV 后,上下浮动一定范围作为阈值:

    python

    运行

    bgr_color = np.uint8([[[0, 0, 255]]])  # 红色的BGR值
    hsv_color = cv2.cvtColor(bgr_color, cv2.COLOR_BGR2HSV)
    print(hsv_color)  # 输出HSV值,以此为中心设置范围
    

五、图像阈值处理

阈值处理是将灰度图转换为二值图的过程,通过设定阈值将像素分为两类(黑 / 白),常用于图像分割和特征提取。

5.1 简单阈值处理

python

运行

import cv2
import numpy as np# 读取灰度图
img = cv2.imread('text_image.jpg', cv2.IMREAD_GRAYSCALE)# 简单阈值处理
# 参数1:输入图像(必须为单通道)
# 参数2:阈值
# 参数3:最大值(超过阈值的像素设为此值)
# 参数4:阈值类型
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)  # 超过阈值为最大值,否则为0
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)  # 与THRESH_BINARY相反
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)  # 超过阈值的像素设为阈值,否则不变
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)  # 超过阈值的像素不变,否则为0
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)  # 与THRESH_TOZERO相反# 显示结果
titles = ['Original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]for i in range(6):cv2.imshow(titles[i], images[i])cv2.waitKey(0)
cv2.destroyAllWindows()

5.2 自适应阈值处理

简单阈值使用全局阈值,当图像光照不均匀时效果较差。自适应阈值会根据像素周围的区域动态调整阈值:

python

运行

import cv2img = cv2.imread('text_image.jpg', cv2.IMREAD_GRAYSCALE)
# 去除噪声(自适应阈值对噪声敏感)
img = cv2.GaussianBlur(img, (5, 5), 0)# 简单阈值(对比用)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 自适应阈值
# 参数2:最大值
# 参数3:自适应方法(ADAPTIVE_THRESH_MEAN_C:均值;ADAPTIVE_THRESH_GAUSSIAN_C:高斯加权均值)
# 参数4:阈值类型
# 参数5:块大小(计算阈值的区域大小,必须为奇数)
# 参数6:常数(从均值/加权均值中减去的值)
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)# 显示结果
titles = ['Original', 'Global Threshold (127)', 'Adaptive Mean', 'Adaptive Gaussian']
images = [img, th1, th2, th3]for i in range(4):cv2.imshow(titles[i], images[i])cv2.waitKey(0)
cv2.destroyAllWindows()

5.3 Otsu 阈值法

Otsu 算法会自动计算最优阈值,适用于双峰直方图的图像(像素值集中在两个区域):

python

运行

import cv2
import matplotlib.pyplot as pltimg = cv2.imread('noisy_image.jpg', cv2.IMREAD_GRAYSCALE)# 简单阈值(手动设置阈值)
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)# Otsu 阈值(自动计算阈值)
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 先高斯滤波再Otsu阈值(处理噪声)
blur = cv2.GaussianBlur(img, (5, 5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 绘制直方图对比
images = [img, 0, th1,img, 0, th2,blur, 0, th3]
titles = ['Original', 'Histogram', 'Global (v=100)','Original', 'Histogram', "Otsu's (v={})".format(ret2),'Gaussian Blur', 'Histogram', "Otsu's (v={})".format(ret3)]for i in range(3):plt.subplot(3, 3, i*3+1), plt.imshow(images[i*3], 'gray')plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])plt.subplot(3, 3, i*3+2), plt.hist(images[i*3].ravel(), 256)plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])plt.subplot(3, 3, i*3+3), plt.imshow(images[i*3+2], 'gray')plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])plt.show()

六、图像滤波与平滑

图像滤波用于去除噪声或提取特征,是图像处理中的关键步骤。OpenCV 提供了多种滤波方法,适用于不同类型的噪声。

6.1 均值滤波

均值滤波将每个像素替换为其邻域内像素的平均值,适用于去除高斯噪声,但会使图像模糊。

python

运行

import cv2img = cv2.imread('noisy_image.jpg')# 均值滤波
# 参数:卷积核大小(必须为奇数)
blur = cv2.blur(img, (5, 5))# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Mean Blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.2 高斯滤波

高斯滤波使用高斯核进行加权平均,相比均值滤波,对边缘的模糊程度更低。

python

运行

import cv2img = cv2.imread('noisy_image.jpg')# 高斯滤波
# 参数1:卷积核大小(必须为奇数)
# 参数2:x方向标准差(0表示自动计算)
# 参数3:y方向标准差(0表示自动计算)
gaussian_blur = cv2.GaussianBlur(img, (5, 5), 0)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Gaussian Blur', gaussian_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.3 中值滤波

中值滤波将每个像素替换为其邻域内像素的中值,特别适合去除椒盐噪声(随机出现的黑白点)。

python

运行

import cv2img = cv2.imread('salt_pepper_noise.jpg')# 中值滤波
# 参数:卷积核大小(必须为奇数)
median_blur = cv2.medianBlur(img, 5)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Median Blur', median_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.4 双边滤波

双边滤波在平滑图像的同时保留边缘,结合了空间高斯权重和灰度值相似性权重。

python

运行

import cv2img = cv2.imread('texture_image.jpg')# 双边滤波
# 参数1:直径(像素邻域大小)
# 参数2:颜色空间标准差(越大,允许更多颜色参与滤波)
# 参数3:坐标空间标准差(越大,更远的像素也会影响结果)
bilateral = cv2.bilateralFilter(img, 9, 75, 75)# 高斯滤波对比(边缘会模糊)
gaussian = cv2.GaussianBlur(img, (9, 9), 0)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Bilateral Filter', bilateral)
cv2.imshow('Gaussian Blur', gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

七、边缘检测

边缘是图像中灰度变化剧烈的区域,包含了物体的重要特征。边缘检测是目标识别、图像分割的基础。

7.1 Canny 边缘检测

Canny 边缘检测是一种多阶段算法,具有良好的抗噪声能力和边缘定位精度,是最常用的边缘检测方法。

python

运行

import cv2img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)# 步骤1:降噪(Canny对噪声敏感)
blur = cv2.GaussianBlur(img, (3, 3), 0)# 步骤2:Canny边缘检测
# 参数1:输入图像
# 参数2:低阈值
# 参数3:高阈值(通常为低阈值的2-3倍)
# 参数4:Sobel算子大小(默认3)
# 参数5:L2梯度(True表示使用L2范数,False表示使用L1范数)
edges = cv2.Canny(blur, 50, 150, apertureSize=3, L2gradient=True)# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

Canny 算法原理

  1. 高斯滤波去除噪声
  2. 计算梯度强度和方向(使用 Sobel 算子)
  3. 非极大值抑制(保留局部最大值,细化边缘)
  4. 双阈值检测(确定强边缘和弱边缘)
  5. 边缘连接(弱边缘若与强边缘相连则保留)

7.2 Sobel 算子与 Laplacian 算子

python

运行

import cv2
import numpy as npimg = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
img = cv2.GaussianBlur(img, (3, 3), 0)  # 降噪# Sobel算子(计算x和y方向的梯度)
# 参数2:输出图像深度(-1表示与输入相同)
# 参数3:x方向导数阶数
# 参数4:y方向导数阶数
# 参数5:算子大小
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)# 转换为uint8(Sobel可能输出负值,需取绝对值)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)# 合并x和y方向梯度
sobel_combined = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)# Laplacian算子(二阶导数,对噪声更敏感)
laplacian = cv2.Laplacian(img, cv2.CV_64F, ksize=3)
laplacian = cv2.convertScaleAbs(laplacian)# 显示结果
titles = ['Original', 'Sobel X', 'Sobel Y', 'Sobel Combined', 'Laplacian']
images = [img, sobelx, sobely, sobel_combined, laplacian]for i in range(5):cv2.imshow(titles[i], images[i])cv2.waitKey(0)
cv2.destroyAllWindows()

八、特征检测与描述

特征是图像中具有独特性和稳定性的区域(如角点、边缘、斑点等),特征检测与描述是目标匹配、图像拼接等高级应用的基础。

8.1 Harris 角点检测

角点是图像中两个边缘的交点,Harris 算法通过检测灰度变化剧烈的区域来识别角点。

python

运行

import cv2
import numpy as npimg = cv2.imread('chessboard.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)# Harris角点检测
# 参数1:输入图像(单通道,float32)
# 参数2:角点检测的邻域大小
# 参数3:Sobel算子孔径大小
# 参数4:Harris检测自由参数
dst = cv2.cornerHarris(gray, 2, 3, 0.04)# 膨胀角点(便于显示)
dst = cv2.dilate(dst, None)# 标记角点(阈值为最大值的0.01)
img[dst > 0.01 * dst.max()] = [0, 0, 255]  # 红色标记cv2.imshow('Harris Corners', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

8.2 SIFT 特征检测(尺度不变特征变换)

SIFT 特征具有尺度不变性和旋转不变性,即使图像缩放、旋转后仍能稳定识别。

python

运行

import cv2# 注意:SIFT算法受专利保护,需安装opencv-contrib-python
img = cv2.imread('lena.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 创建SIFT对象
sift = cv2.SIFT_create()# 检测关键点并计算描述符
kp, des = sift.detectAndCompute(gray, None)# 在图像上绘制关键点
# 参数3:标记点的颜色(BGR)
# 参数4:标记点的大小
img_with_kp = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)cv2.imshow('SIFT Keypoints', img_with_kp)
cv2.waitKey(0)
cv2.destroyAllWindows()

8.3 ORB 特征检测(替代 SIFT 的免费方案)

ORB 是 SIFT 和 SURF 的替代方案,具有更快的速度,且不受专利限制。

python

运行

import cv2img = cv2.imread('lena.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 创建ORB对象
orb = cv2.ORB_create()# 检测关键点并计算描述符
kp, des = orb.detectAndCompute(gray, None)# 绘制关键点
img_with_kp = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)cv2.imshow('ORB Keypoints', img_with_kp)
cv2.waitKey(0)
cv2.destroyAllWindows()

8.4 特征匹配

使用 ORB 特征实现两幅图像的匹配:

python

运行

import cv2
import numpy as np# 读取两幅图像
img1 = cv2.imread('object.jpg', 0)  # 目标图像
img2 = cv2.imread('scene.jpg', 0)   # 场景图像# 初始化ORB
orb = cv2.ORB_create()# 检测特征点并计算描述符
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)# 创建暴力匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)# 匹配描述符
matches = bf.match(des1, des2)# 按距离排序(保留最佳匹配)
matches = sorted(matches, key=lambda x: x.distance)# 绘制前10个匹配点
img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)cv2.imshow('Matches', img_matches)
cv2.waitKey(0)
cv2.destroyAllWindows()

九、视频处理基础

OpenCV 不仅能处理图像,还能读取、处理和保存视频,支持从文件或摄像头获取视频流。

9.1 读取与显示视频文件

python

运行

import cv2# 打开视频文件(参数也可以是摄像头索引,0表示默认摄像头)
cap = cv2.VideoCapture('test_video.mp4')# 检查视频是否成功打开
if not cap.isOpened():print("无法打开视频文件")exit()# 循环读取视频帧
while cap.isOpened():# 读取一帧(ret为布尔值,表示是否成功读取;frame为帧图像)ret, frame = cap.read()if not ret:print("已到达视频末尾")break# 显示帧(可在此处添加帧处理代码)cv2.imshow('Video Frame', frame)# 按下 'q' 键退出if cv2.waitKey(25) & 0xFF == ord('q'):break# 释放资源
cap.release()
cv2.destroyAllWindows()

9.2 视频属性与控制

python

运行

import cv2cap = cv2.VideoCapture('test_video.mp4')# 获取视频属性
fps = cap.get(cv2.CAP_PROP_FPS)  # 帧率
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # 高度
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))  # 总帧数
duration = frame_count / fps  # 视频时长(秒)print(f"帧率:{fps:.2f}")
print(f"尺寸:{width}×{height}")
print(f"总帧数:{frame_count}")
print(f"时长:{duration:.2f}秒")# 设置视频属性(并非所有属性都可修改)
cap.set(cv2.CAP_PROP_POS_FRAMES, 100)  # 跳转到第100帧# 读取并显示指定帧
ret, frame = cap.read()
if ret:cv2.imshow('Frame 100', frame)cv2.waitKey(0)cap.release()
cv2.destroyAllWindows()

9.3 保存视频

python

运行

import cv2cap = cv2.VideoCapture(0)  # 打开摄像头# 定义编码器(不同平台支持的编码器不同)
# Windows:DIVX;Linux:XVID;macOS:avc1
fourcc = cv2.VideoWriter_fourcc(*'XVID')# 创建VideoWriter对象
# 参数1:输出文件名
# 参数2:编码器
# 参数3:帧率
# 参数4:视频尺寸
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))while cap.isOpened():ret, frame = cap.read()if not ret:break# 可在此处添加帧处理(如灰度化、边缘检测等)# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)  # 保存灰度视频需转回3通道# 写入帧out.write(frame)cv2.imshow('Frame', frame)if cv2.waitKey(1) & 0xFF == ord('q'):break# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()

十、背景减除与运动检测

背景减除是从视频中提取运动物体的常用技术,通过构建背景模型并与当前帧对比,检测出前景(运动物体)。

python

运行

import cv2
import numpy as np# 打开摄像头或视频文件
cap = cv2.VideoCapture(0)# 创建背景减除器(三种常用算法)
# 1. MOG2:基于高斯混合模型
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, detectShadows=True)
# 2. KNN:基于K近邻
# fgbg = cv2.createBackgroundSubtractorKNN(history=500, detectShadows=True)
# 3. GMG:结合静态背景估计和贝叶斯分割(对噪声敏感,需预处理)
# kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# fgbg = cv2.createBackgroundSubtractorGMG()while True:ret, frame = cap.read()if not ret:break# 应用背景减除fgmask = fgbg.apply(frame)# 对MOG2和KNN,阴影会被标记为灰色(值为127),可将其设为0if isinstance(fgbg, cv2.BackgroundSubtractorMOG2) or isinstance(fgbg, cv2.BackgroundSubtractorKNN):fgmask[fgmask == 127] = 0# 形态学操作去除噪声kernel = np.ones((3, 3), np.uint8)fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)# 找到轮廓(检测运动物体)contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 绘制轮廓for c in contours:# 过滤小轮廓(排除噪声)if cv2.contourArea(c) < 500:continuex, y, w, h = cv2.boundingRect(c)cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)# 显示结果cv2.imshow('Frame', frame)cv2.imshow('FG Mask', fgmask)if cv2.waitKey(30) & 0xFF == ord('q'):breakcap.release()
cv2.destroyAllWindows()

十一、综合案例:人脸检测与识别

结合上述知识,我们实现一个基于 Haar 级联分类器的人脸检测系统。

11.1 人脸检测基础

python

运行

import cv2# 加载Haar级联分类器(OpenCV自带)
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')# 读取图像并转换为灰度图
img = cv2.imread('people.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 检测人脸
# 参数1:灰度图
# 参数2:缩放因子(1.1表示每次缩小10%)
# 参数3:最小邻居数(越高检测越严格)
faces = face_cascade.detectMultiScale(gray, 1.1, 4)# 在人脸周围绘制矩形,并检测眼睛
for (x, y, w, h) in faces:cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)# 人脸区域roi_gray = gray[y:y+h, x:x+w]roi_color = img[y:y+h, x:x+w]# 在人脸区域检测眼睛eyes = eye_cascade.detectMultiScale(roi_gray)for (ex, ey, ew, eh) in eyes:cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)cv2.imshow('Face Detection', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

11.2 实时人脸检测(摄像头)

python

运行

import cv2face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()if not ret:breakgray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)faces = face_cascade.detectMultiScale(gray, 1.1, 4)for (x, y, w, h) in faces:cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)# 添加文字标签cv2.putText(frame, 'Face', (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)cv2.imshow('Real-time Face Detection', frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()
cv2.destroyAllWindows()

结语:OpenCV 的进阶之路

本文涵盖了 OpenCV 的核心功能,从基础的图像读写到高级的特征检测和视频处理,通过大量代码示例帮助您快速上手。但 OpenCV 的能力远不止于此,以下是值得深入学习的进阶方向:

  1. 深度学习与 OpenCV:OpenCV 支持加载 TensorFlow、PyTorch 等框架训练的模型,实现更精准的目标检测(如 YOLO、SSD)、人脸识别等。
  2. 3D 计算机视觉:利用 OpenCV 处理立体图像,计算深度信息,实现三维重建。
  3. 性能优化:通过 OpenCV 的 GPU 加速模块(cv2.cuda)提升处理速度,满足实时应用需求。
  4. 行业应用:结合具体领域(如医学影像、自动驾驶、机器人视觉)深入研究解决方案。

OpenCV 官网(https://opencv.org/)和官方文档是学习的最佳资源,建议结合实际项目实践,不断提升技能。

希望本文能成为您探索计算机视觉世界的起点,祝您在 OpenCV 的学习之路上取得进步!

http://www.dtcms.com/a/318889.html

相关文章:

  • HashMap寻址算法
  • QT项目 -仿QQ音乐的音乐播放器(第五节)
  • 《算法导论》第 10 章 - 基本数据结构
  • 深入剖析Java线程:从基础到实战(上)
  • ubuntu cloud init 20.04LTS升级到22.04LTS
  • vue3接收SSE流数据进行实时渲染日志
  • Web开发模式 前端渲染 后端渲染 身份认证
  • 第三章:【springboot】框架介绍MyBatis
  • Spring AOP动态代理核心原理深度解析 - 图解+实战揭秘Java代理设计模式
  • 前端百分比展示导致后端 BigDecimal 转换异常的排查与解决
  • 多账号管理方案:解析一款免Root的App分身工具
  • 【RabbitMQ面试精讲 Day 13】HAProxy与负载均衡配置
  • HTTP 协议升级(HTTP Upgrade)机制
  • winform中的listbox实现拖拽功能
  • 基于ubuntu搭建gitlab
  • KDE Connect
  • 一篇文章入门TCP与UDP(保姆级别)
  • 02电气设计-安全继电器电路设计(让电路等级达到P4的安全等级)
  • C语言strncmp函数详解:安全比较字符串的实用工具
  • 合约收款方式,转账与问题安全
  • 怎么进行专项分析项目?
  • 上证50期权持仓明细在哪里查询?
  • C语言(08)——整数浮点数在内存中的存储
  • LINUX-批量文件管理及vim文件编辑器
  • 浅析 Berachain v2 ,对原有 PoL 机制进行了哪些升级?
  • AutoMQ-Kafka的替代方案实战
  • JAVA第六学:数组的使用
  • 【C++】哈希表原理与实现详解
  • 基于langchain的两个实际应用:[MCP多服务器聊天系统]和[解析PDF文档的RAG问答]
  • 智能制造的中枢神经工控机在自动化产线中的关键角色