OpenCV 是计算机视觉领域超实用的开源库。它能帮你实现图像、视频处理,像实时检测人脸、跟踪目标、处理图像。无论是安防监控、自动驾驶,还是趣味手势识别,OpenCV 都能大显身手!
目录
[二、OpenCV 环境搭建](#二、OpenCV 环境搭建)
[2.1 安装 Python](#2.1 安装 Python)
[2.2 安装 OpenCV 库](#2.2 安装 OpenCV 库)
[三、OpenCV 基本操作](#三、OpenCV 基本操作)
[3.1 图像读取与显示](#3.1 图像读取与显示)
[3.2 视频捕获与显示](#3.2 视频捕获与显示)
[4.1 Haar 级联分类器](#4.1 Haar 级联分类器)
[4.2 YOLO(You Only Look Once)](#4.2 YOLO(You Only Look Once))
[5.1 KCF(Kernelized Correlation Filters)跟踪器](#5.1 KCF(Kernelized Correlation Filters)跟踪器)
[6.1 图像滤波](#6.1 图像滤波)
[6.2 边缘检测](#6.2 边缘检测)
[7.1 智能安防监控系统](#7.1 智能安防监控系统)
[7.2 手势识别系统](#7.2 手势识别系统)
一、背景
OpenCV 作为计算机视觉领域的开源库,凭借其丰富的算法和高效的性能,在实时应用开发中占据重要地位。实时应用要求系统能够在短时间内对输入数据进行处理并给出反馈,OpenCV 的多种功能正好满足了这些需求,如安防监控需快速检测目标,自动驾驶要实时识别道路信息等。
二、OpenCV 环境搭建
2.1 安装 Python
Python 是使用 OpenCV 的常用语言,其安装步骤如下:
步骤 | 操作内容 | 说明 |
---|---|---|
1 | 访问 Python 官方网站([Download Python | Python.org](https://www.python.org/downloads/ "Download Python | Python.org")) |
2 | 下载对应操作系统的安装包 | 如 Windows 选择.exe 文件,Linux 选择源码包或使用包管理器安装 |
3 | 运行安装程序 | 安装过程中勾选 "Add Python to PATH",方便后续使用 |
2.2 安装 OpenCV 库
安装 OpenCV 库可通过 pip 命令完成,具体如下:
库名称 | 安装命令 | 用途 |
---|---|---|
opencv - python | pip install opencv - python |
基础的 OpenCV 库,包含核心功能 |
opencv - contrib - python | pip install opencv - contrib - python |
包含额外的贡献模块,如一些实验性算法和功能 |
三、OpenCV 基本操作
3.1 图像读取与显示
cpp
import cv2
# 读取图像
image = cv2.imread('test.jpg')
# 显示图像
cv2.imshow('Image', image)
# 等待按键事件
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
函数 | 作用 | 参数说明 |
---|---|---|
cv2.imread() |
读取图像文件 | 第一个参数为图像文件路径,第二个参数可指定读取模式(如灰度模式等) |
cv2.imshow() |
显示图像 | 第一个参数为窗口名称,第二个参数为要显示的图像数据 |
cv2.waitKey() |
等待按键事件 | 参数为等待时间(毫秒),0 表示无限等待 |
cv2.destroyAllWindows() |
关闭所有打开的窗口 | 无参数 |
3.2 视频捕获与显示
cpp
import cv2
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
# 读取一帧视频
ret, frame = cap.read()
if not ret:
break
# 显示帧
cv2.imshow('Video', frame)
# 按 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
函数 | 作用 | 参数说明 |
---|---|---|
cv2.VideoCapture() |
打开视频捕获设备 | 参数可以是摄像头编号(如 0 表示默认摄像头)或视频文件路径 |
cap.read() |
读取一帧视频 | 返回两个值,ret 表示是否成功读取,frame 为读取的帧数据 |
cap.release() |
释放视频捕获设备 | 无参数 |
四、实时目标检测
4.1 Haar 级联分类器
cpp
import cv2
# 加载人脸分类器
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 转换为灰度图像
gray = 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), (255, 0, 0), 2)
# 显示帧
cv2.imshow('Face Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
步骤 | 操作 | 说明 |
---|---|---|
1 | 加载分类器 | 使用 cv2.CascadeClassifier() 加载预训练的分类器文件 |
2 | 读取视频帧 | 利用 cv2.VideoCapture() 和 cap.read() 读取摄像头视频帧 |
3 | 转换为灰度图像 | 使用 cv2.cvtColor() 将彩色图像转换为灰度图像,提高检测效率 |
4 | 目标检测 | 调用 detectMultiScale() 方法进行目标检测,返回检测到的目标矩形框信息 |
5 | 绘制矩形框 | 使用 cv2.rectangle() 在检测到的目标周围绘制矩形框 |
4.2 YOLO(You Only Look Once)
cpp
import cv2
import numpy as np
# 加载模型配置和权重文件
net = cv2.dnn.readNet('yolov3.weights', 'yolov3.cfg')
# 加载类别名称
classes = []
with open('coco.names', 'r') as f:
classes = [line.strip() for line in f.readlines()]
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
height, width, _ = frame.shape
# 准备输入图像
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
# 获取输出层名称
output_layer_names = net.getUnconnectedOutLayersNames()
# 前向传播
outputs = net.forward(output_layer_names)
boxes = []
confidences = []
class_ids = []
# 处理输出结果
for output in outputs:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
# 非极大值抑制
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
# 绘制检测结果
font = cv2.FONT_HERSHEY_PLAIN
colors = np.random.uniform(0, 255, size=(len(classes), 3))
if len(indexes) > 0:
for i in indexes.flatten():
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
confidence = str(round(confidences[i], 2))
color = colors[class_ids[i]]
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
cv2.putText(frame, label + " " + confidence, (x, y + 20), font, 2, color, 2)
# 显示帧
cv2.imshow('YOLO Object Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
步骤 | 操作 | 说明 |
---|---|---|
1 | 加载模型和类别 | 用 cv2.dnn.readNet() 加载模型配置和权重文件,读取类别名称文件 |
2 | 读取视频帧 | 同 Haar 级联分类器 |
3 | 准备输入图像 | 使用 cv2.dnn.blobFromImage() 对图像进行预处理 |
4 | 前向传播 | 调用 net.forward() 进行推理,得到输出结果 |
5 | 处理输出结果 | 筛选出置信度高于阈值的检测结果,记录矩形框、置信度和类别信息 |
6 | 非极大值抑制 | 使用 cv2.dnn.NMSBoxes() 去除重叠的检测框 |
7 | 绘制检测结果 | 在图像上绘制矩形框和类别标签 |
五、实时目标跟踪
5.1 KCF(Kernelized Correlation Filters)跟踪器
cpp
import cv2
# 打开摄像头
cap = cv2.VideoCapture(0)
# 读取第一帧
ret, frame = cap.read()
# 选择跟踪区域
bbox = cv2.selectROI(frame, False)
# 创建 KCF 跟踪器
tracker = cv2.TrackerKCF_create()
# 初始化跟踪器
tracker.init(frame, bbox)
while True:
ret, frame = cap.read()
if not ret:
break
# 更新跟踪器
success, bbox = tracker.update(frame)
# 绘制跟踪结果
if success:
(x, y, w, h) = [int(v) for v in bbox]
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
else:
cv2.putText(frame, "Tracking failed", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
# 显示帧
cv2.imshow('KCF Tracking', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
步骤 | 操作 | 说明 |
---|---|---|
1 | 打开摄像头并读取第一帧 | 同前面视频处理操作 |
2 | 选择跟踪区域 | 使用 cv2.selectROI() 让用户手动选择要跟踪的目标区域 |
3 | 创建并初始化跟踪器 | 使用 cv2.TrackerKCF_create() 创建 KCF 跟踪器,并使用第一帧和选择的区域进行初始化 |
4 | 跟踪目标 | 在后续帧中调用 tracker.update() 更新跟踪器状态,获取新的跟踪区域 |
5 | 绘制跟踪结果 | 根据跟踪结果在图像上绘制矩形框或显示跟踪失败信息 |
六、实时图像处理
6.1 图像滤波
cpp
import cv2
import numpy as np
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 均值滤波
blurred = cv2.blur(frame, (5, 5))
# 高斯滤波
gaussian_blurred = cv2.GaussianBlur(frame, (5, 5), 0)
# 显示原始图像和滤波后的图像
cv2.imshow('Original', frame)
cv2.imshow('Blurred', blurred)
cv2.imshow('Gaussian Blurred', gaussian_blurred)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
滤波类型 | 函数 | 作用 | 参数说明 |
---|---|---|---|
均值滤波 | cv2.blur() |
平滑图像,去除噪声 | 第一个参数为输入图像,第二个参数为滤波核大小 |
高斯滤波 | cv2.GaussianBlur() |
更有效地去除高斯噪声 | 第一个参数为输入图像,第二个参数为滤波核大小,第三个参数为高斯核标准差 |
6.2 边缘检测
cpp
import cv2
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Canny 边缘检测
edges = cv2.Canny(gray, 100, 200)
# 显示原始图像和边缘检测结果
cv2.imshow('Original', frame)
cv2.imshow('Edges', edges)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
步骤 | 操作 | 说明 |
---|---|---|
1 | 读取视频帧 | 同前面视频处理操作 |
2 | 转换为灰度图像 | 减少计算量,便于边缘检测 |
3 | 边缘检测 | 使用 cv2.Canny() 进行边缘检测,两个阈值参数用于控制边缘的检测灵敏度 |
4 | 显示结果 | 显示原始图像和边缘检测后的图像 |
七、实时应用案例
7.1 智能安防监控系统
cpp
import cv2
import time
# 加载人脸分类器
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 打开摄像头
cap = cv2.VideoCapture(0)
# 初始化视频写入器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = None
while True:
ret, frame = cap.read()
if not ret:
break
# 转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = face_cascade.detectMultiScale(gray, 1.1, 4)
if len(faces) > 0:
if out is None:
# 开始录制视频
out = cv2.VideoWriter('alert_video.avi', fourcc, 20.0, (frame.shape[1], frame.shape[0]))
start_time = time.time()
# 在检测到的人脸周围绘制矩形
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 写入视频帧
out.write(frame)
# 录制时间超过 10 秒,停止录制
if time.time() - start_time > 10:
out.release()
out = None
else:
if out is not None:
out.release()
out = None
# 显示帧
cv2.imshow('Smart Surveillance', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
if out is not None:
out.release()
cv2.destroyAllWindows()
步骤 | 操作 | 说明 |
---|---|---|
1 | 加载分类器和打开摄像头 | 同 Haar 级联分类器部分 |
2 | 初始化视频写入器 | 使用 cv2.VideoWriter_fourcc() 和 cv2.VideoWriter() 初始化视频写入器 |
3 | 检测人脸 | 利用 Haar 级联分类器检测人脸 |
4 | 录制视频 | 当检测到人脸时开始录制视频,录制时间超过 10 秒停止录制 |
5 | 显示帧 | 实时显示视频帧 |
7.2 手势识别系统
cpp
import cv2
import numpy as np
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# 定义手势区域
roi = frame[100:300, 100:300]
# 转换为灰度图像
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
# 高斯滤波
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 阈值处理
_, thresh = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY_INV)
# 查找轮廓
contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) > 0:
# 找到最大的轮廓
cnt = max(contours, key=cv2.contourArea)
# 计算凸包
hull = cv2.convexHull(cnt)
# 绘制轮廓和凸包
cv2.drawContours(roi, [cnt], 0, (0, 255, 0), 2)
cv2.drawContours(roi, [hull], 0, (0, 0, 255), 2)
# 计算凸包缺陷
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)
if defects is not None:
count_defects = 0
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
# 计算三角形的边长
a = np.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)
b = np.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)
c = np.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)
# 计算角度
angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) * 180 / np.pi
if angle <= 90:
count_defects += 1
cv2.circle(roi, far, 5, (0, 0, 255), -1)
# 根据缺陷数量判断手势
if count_defects == 0:
cv2.putText(frame, "Closed Fist", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
elif count_defects == 1:
cv2.putText(frame, "One Finger", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
elif count_defects == 2:
cv2.putText(frame, "Two Fingers", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
elif count_defects == 3:
cv2.putText(frame, "Three Fingers", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
elif count_defects == 4:
cv2.putText(frame, "Four Fingers", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
else:
cv2.putText(frame, "Open Hand", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 显示帧
cv2.imshow('Gesture Recognition', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
步骤 | 操作 | 说明 |
---|---|---|
1 | 打开摄像头并读取帧 | 同前面视频处理操作 |
2 | 定义手势区域 | 从视频帧中选取特定区域进行手势识别 |
3 | 图像预处理 | 转换为灰度图像、高斯滤波、阈值处理 |
4 | 查找轮廓和凸包 | 使用 cv2.findContours() 查找轮廓,cv2.convexHull() 计算凸包 |
5 | 计算凸包缺陷 | 通过 cv2.convexityDefects() 计算凸包缺陷,根据缺陷数量判断手势 |
6 | 显示结果 | 在图像上显示识别出的手势信息 |
八、小结
OpenCV 在实时应用开发中具有强大的功能和广泛的应用场景。通过本文介绍的环境搭建、基本操作、目标检测、跟踪、图像处理以及应用案例等内容,开发者可以利用 OpenCV 快速实现各种实时应用。在实际开发中,可根据具体需求选择合适的算法和技术,并不断优化以提高应用性能。