OpenCV 是计算机视觉领域超实用的开源库。它能帮你实现图像、视频处理,像实时检测人脸、跟踪目标、处理图像。无论是安防监控、自动驾驶,还是趣味手势识别,OpenCV 都能大显身手!
目录
一、背景
二、OpenCV 环境搭建
2.1 安装 Python
2.2 安装 OpenCV 库
三、OpenCV 基本操作
3.1 图像读取与显示
3.2 视频捕获与显示
四、实时目标检测
4.1 Haar 级联分类器
4.2 YOLO(You Only Look Once)
五、实时目标跟踪
5.1 KCF(Kernelized Correlation Filters)跟踪器
六、实时图像处理
6.1 图像滤波
6.2 边缘检测
七、实时应用案例
7.1 智能安防监控系统
7.2 手势识别系统
八、小结
一、背景
OpenCV 作为计算机视觉领域的开源库,凭借其丰富的算法和高效的性能,在实时应用开发中占据重要地位。实时应用要求系统能够在短时间内对输入数据进行处理并给出反馈,OpenCV 的多种功能正好满足了这些需求,如安防监控需快速检测目标,自动驾驶要实时识别道路信息等。
二、OpenCV 环境搭建
2.1 安装 Python
Python 是使用 OpenCV 的常用语言,其安装步骤如下:
步骤 |
操作内容 |
说明 |
1 |
访问 Python 官方网站(Download Python | Python.org) |
可根据操作系统选择合适的 Python 版本,建议使用 Python 3.9 及以上版本 |
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 图像读取与显示
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 视频捕获与显示
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 级联分类器
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)
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)跟踪器
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 图像滤波
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 边缘检测
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 智能安防监控系统
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 手势识别系统
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 快速实现各种实时应用。在实际开发中,可根据具体需求选择合适的算法和技术,并不断优化以提高应用性能。