显示图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import cv2

# 1.读取图像
img = cv2.imread("../images/leijun/3.jpg") # 参数为图像路径,不可包含中文

# 2.检查图像是否成功读取
if img is None:
print("错误:无法加载图像,请检查路径是否正确!")
exit()

# 3.显示图像
cv2.imshow("Display", img) # 第一个参数为窗口名,第二个参数为要显示的图像对象

while True:
# 4.等待用户按键
# 参数0表示无限等待,直到用户按下任意键
key = cv2.waitKey(0)

# 5.根据用户按键执行操作
# print(key) # 发现打印结果为按键的ASCII码
if key & 0xFF == ord('s'):
cv2.imwrite('saved.jpg', img)
print('图片已保存')
elif key & 0xFF == ord('q'):
break
else:
print('您按下了{}键'.format(chr(key)))

# 6.关闭窗口
cv2.destroyWindow("Display") # 关闭名为Display的窗口
cv2.destroyAllWindows() # 关闭所有窗口

读取图片报错

1
2
3
4
5
[ WARN:0@0.025] global loadsave.cpp:268 cv::findDecoder imread_('../images/雷军/1.jpg'): can't open/read file: check file path/integrity
Traceback (most recent call last):
File "F:\repo\Python\opencv-leaning\chapter1\BaseOperation.py", line 5, in <module>
cv2.imshow("雷军", img)
cv2.error: OpenCV(4.11.0) D:\a\opencv-python\opencv-python\opencv\modules\highgui\src\window.cpp:973: error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'cv::imshow'
含中文路径的图片

猜测是中文路径问题,将文件夹重命名为leijun即可

image-20250427210458763

图片可显示,但是图片分辨率太高,我的显示器显示不全

可以使用cv2.resize(src, dsize, fx, fy, interpolation)方法

  • src
    • 输入图像(通常是 NumPy 数组)。
    • 示例:src = cv2.imread("image.jpg")
  • dsize
    • 输出图像的尺寸,格式为 (width, height)
    • 如果指定了 dsize,则忽略 fxfy
    • 示例:(300, 200) 表示输出图像宽度为 300 像素,高度为 200 像素。
  • fx
    • 水平方向的缩放比例(宽度方向)。
    • 默认值为 0,表示不使用此参数。
    • 示例:fx=0.5 表示水平方向缩小到原来的 50%。
  • fy
    • 垂直方向的缩放比例(高度方向)。
    • 默认值为 0,表示不使用此参数。
    • 示例:fy=2.0 表示垂直方向放大到原来的 2 倍。
  • interpolation
    • 插值方法,用于决定如何调整像素值。
    • 常见的插值方法及其适用场景如下:
      • cv2.INTER_NEAREST:最近邻插值(速度最快,但质量较差,适用于对质量要求不高的场景)。
      • cv2.INTER_LINEAR:双线性插值(默认值,适用于缩小或放大)。
      • cv2.INTER_CUBIC:三次插值(质量更高,但速度较慢,适用于对质量要求较高的场景)。
      • cv2.INTER_AREA:区域插值(适用于缩小图像,效果较好)。
      • cv2.INTER_LANCZOS4:Lanczos 插值(高质量插值,但计算成本高,适用于对质量要求极高的场景)。

显示视频

视频的显示是通过imshow方法逐帧显示每一帧的画面组合起来从而形成的视频效果

1.捕获视频

捕获本机摄像头

1
cap = cv2.VideoCapture(0)

参数0为默认摄像头,1/2/...为本机其他摄像头(如有)

捕获本地视频文件

1
cap = cv2.VideoCapture('video.mp4')

捕获网络视频流

1
cap = cv2.VideoCapture('https://vjs.zencdn.net/v/oceans.mp4')

设置属性

使用 set() 方法来设置摄像头或视频捕获的各种属性,例如分辨率、帧率等。

1
2
3
4
5
6
7
8
cap = cv2.VideoCapture(0)

# 设置视频分辨率为 1280x720
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

# 设置帧率为 30 FPS
cap.set(cv2.CAP_PROP_FPS, 30)

获取属性

使用 get() 方法可以获取当前视频捕获的各种属性,比如宽度、高度、帧率等。

1
2
3
4
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS)
print(f"Width: {width}, Height: {height}, FPS: {fps}")

可操作的属性列表如下

参数名称 说明 读/写
CV.CAP_PROP_POS_MSEC 0 当前视频文件的时间位置(返回毫秒)或视频捕获时间戳 Y/N
CV.CAP_PROP_POS_FRAMES 1 从0开始的解码/捕获时间帧 Y/N
CV.CAP_PROP_POS_AVI_RATIO 2 返回视频文件的相关位置:0,视频开始。1,视频结束 Y/N
CV.CAP_PROP_FRAME_WIDTH 3 视频流中的帧宽 Y/Y
CV.CAP_PROP_FRAME_HEIGHT 4 视频流中的帧高 Y/Y
CV.CAP_PROP_FPS 5 帧率 Y/Y
CV.CAP_PROP_FOURCC 6 返回解码方式中的四字符 Y/Y
CV.CAP_PROP_FRAME_COUNT 7 视频文件的总帧数 Y/N
CV.CAP_PROP_FORMAT 8 由retrieve()函数返回的矩阵对象的格式 Y/N
CV.CAP_PROP_MODE 9 用于预测当前捕获模式的后端专用值 Y/N
CV.CAP_PROP_BRIGHTNESS 10 图像的亮度(仅用于摄像头) Y/Y
CV.CAP_PROP_CONTRAST 11 图像的对比度(仅用于摄像头) Y/Y
CV.CAP_PROP_SATURATION 12 图像的饱和度(仅用于摄像头) Y/Y
CV.CAP_PROP_HUE 13 图像的色调(仅用于摄像头) Y/Y
CV.CAP_PROP_GAIN 14 图像增益(仅用于摄像头) Y/Y
CV.CAP_PROP_EXPOSURE 15 曝光度(仅用于摄像头) Y/Y
CV.CAP_PROP_CONVERT_RGB 16 用于预测图像是否应该被转换为RGB的布尔位 Y/N
CV.CAP_PROP_WHITE_BALANCE 17 白平衡(当前不支持) Y/N
CV.CAP_PROP_RECTIFICATION 18 立体相机的纠正位 Y/N

检查是否成功打开视频源

使用cap.isOpened()方法检查是否成功打开视频源

1
2
if not cap.isOpened():
print("无法打开摄像头")

2.逐帧读取视频

使用 read() 方法逐帧读取视频。

1
2
3
4
5
6
7
8
9
while cap.isOpened():
ret, frame = cap.read() # 返回一个元组,第一个元素为布尔值,第二个元素为实际读取到的图像帧(是一个 NumPy 数组)
if not ret:
break
# 显示帧
cv2.imshow("Frame", frame)
# 等待1毫秒的获取按键的 ASCII 值的低 8 位
if cv2.waitKey(1) & 0xFF == ord('q'):
break

waitKey(1)非常容易忽略,会看到一个空白或冻结的窗口,即使程序正在运行。

waitKey(0)表示无限等待,直到用户按下任意键。 显示图像后,程序会暂停,画面保持不动。直到你按下任意键(比如空格、q、回车等),程序才会继续往下执行。适合逐帧手动播放视频。

3.释放视频捕获对象

用完视频捕获对象后,应该调用 cap.release() 来释放资源。

含有视频保存的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import cv2

# 打开摄像头(设备索引号根据你的设备调整,默认是 0)
cap = cv2.VideoCapture(0)

# 获取帧的宽度和高度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 定义编码格式,创建 VideoWriter 对象
fourcc = cv2.VideoWriter_fourcc(*'XVID') # 编码格式(常见:XVID, MJPG, DIVX 等)
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (frame_width, frame_height))

print("开始录制... 按 'q' 键停止并保存视频")

while cap.isOpened():
ret, frame = cap.read()
if not ret:
break

# 写入帧到视频文件
out.write(frame)

# 显示画面(可选)
cv2.imshow('Recording...', frame)

# 按 q 键停止录制
if cv2.waitKey(1) & 0xFF == ord('q'):
break

# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()

print("视频已保存为 output.avi")

📝 VideoWriter()参数说明

参数 含义
'output.avi' 输出视频文件名
fourcc 视频编码器,决定视频格式和压缩方式
20.0 帧率(每秒帧数),通常设为 20~30
(width, height) 帧的分辨率,必须与输入帧一致

🎞️ 支持的编码格式(FourCC)

你可以使用不同的 FourCC 编码来生成不同格式的视频文件:

编码 文件格式 备注
'XVID' .avi 最常用,兼容性好
'MP4V' .mp4 MP4 格式,清晰度高
'MJPG' .avi 不压缩,体积大但速度快
'DIVX' .avi 老版本编码器

例如:

1
2
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('output.mp4', fourcc, 20.0, (640, 480))

⚠️ 注意事项

  • 视频尺寸必须匹配输入帧大小,否则会写入失败。
  • 不要在没有写完所有帧时就调用 release(),否则可能损坏视频文件。
  • 某些编码格式在某些系统上不支持,可以尝试更换 FourCC。

Core模块

功能: 提供 OpenCV 的核心功能,包括基本数据结构、矩阵操作、绘图函数等。

主要类和函数:

  • Mat: OpenCV 中用于存储图像和矩阵的基本数据结构。
  • Scalar: 用于表示颜色或像素值。
  • Point、Size、Rect: 用于表示点、尺寸和矩形。
  • 基本绘图函数: cv.line()cv.circle()cv.rectangle()cv.putText() 等。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import cv2
import numpy as np

# 创建一个空白图像 (500x500 像素,3 通道 BGR)
image = np.zeros((500, 500, 3), dtype=np.uint8)

# 修改(450,450-499,499)处的像素值
image[450,450:499] = [255,255,0]

# 绘制一条直线
cv2.line(image, (50, 50), (400, 400), (0, 0, 255), thickness=2)
cv2.line(image,(300,400),(400,300),(255,0,255),thickness=8)
# 绘制一个圆
cv2.circle(image, (250, 250), 100, (255, 0, 0), thickness=3)
cv2.circle(image,(100,100),100,(100,200,300),8)
# 绘制一个矩形
cv2.rectangle(image, (100, 100), (300, 300), (0, 255, 0), thickness=5)
cv2.rectangle(image,(300,400),(400,300),(255,255,0),8)
# 添加文本
cv2.putText(image, "OpenCV Drawing", (50, 450), cv2.FONT_HERSHEY_COMPLEX,1, (255, 255, 255), thickness=2)
# 显示图像
cv2.imshow("Drawing Example", image)


# 等待按键并关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

图像在计算机中是以三维数组进行存储的,比如(300,300,3)表示宽为300,高为300,通道数为3的一张图像,一张标量图可以看作三张二维数组的叠加态,具体自行了解吧。

方法参数记忆

cv2.line()

线段的绘制首先需要给出在哪张图像(img)上进行绘制,然后再给出待绘制线段的起点(pt1)与终点(pt2)坐标,再给出线段的颜色(color),以及线段的粗细(thickness)

cv2.circle()

圆形的绘制首先需要确定在哪张图像(img)上进行绘制,然后给出圆心坐标(center)与半径(radius),再给出颜色(color)和线的粗细(thickness)

cv2.rectangle()

矩形的绘制首先需要确定在哪张图像(img)上进行绘制,然后给出两个对角的坐标(pt1、pt2),再给出线的颜色(color)和粗细(thickness)

cv2.putText()

添加文字首先需要确定在哪张图像上进行绘制,然后给出文字内容,再给出文字起始点左下角坐标(org)和字体类型(fontFace),再给出字体大小缩放因子(fontScale)、字体颜色(color)、字体粗细(thickness)

综上来说,先确定图像、然后所绘制图形的属性,主要内容在前,位置在后,最后是图形颜色与粗细。

Imgproc 模块

功能: 提供图像处理功能,包括图像滤波、几何变换、颜色空间转换等。

主要类和函数:

  • 图像滤波: cv.blur()cv.GaussianBlur()cv.medianBlur() 等。
  • 几何变换: cv.resize()cv.warpAffine()cv.warpPerspective() 等。
  • 颜色空间转换: cv.cvtColor()(如 BGR 转灰度、BGR 转 HSV)。
  • 阈值处理: cv.threshold()cv.adaptiveThreshold()
  • 边缘检测: cv.Canny()cv.Sobel()cv.Laplacian()

应用场景:

  • 图像平滑、锐化、边缘检测。
  • 图像缩放、旋转、仿射变换。
  • 图像二值化、颜色空间转换。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import cv2
import numpy as np

# =================== 1. 读取图像 ===================
image = cv2.imread('../images/lena.png') # 读取图像文件
if image is None:
print("❌ 错误:图像未找到,请检查路径是否正确!")
exit() # 如果图像为空,退出程序

# =================== 2. 图像滤波(去噪)===================
# 高斯模糊:使用 11x11 的核进行平滑处理,σ=0 表示自动计算标准差
blurred = cv2.GaussianBlur(image, (11, 11), 0)

# 中值滤波:用于去除椒盐噪声,5x5 核大小
median_blurred = cv2.medianBlur(image, 5)

# =================== 3. 几何变换(缩放、旋转)===================
# 缩放图像:缩小为原来的一半,使用线性插值
resized = cv2.resize(image, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)

# 顺时针旋转90度:仅支持 90 度倍数旋转
rotated = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)

# =================== 4. 颜色空间转换 ===================
# BGR 转灰度图:单通道图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# BGR 转 HSV:色调(Hue)、饱和度(Saturation)、明度(Value)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# 灰度图转BGR:将单通道图像复制为三通道
gray2bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)

# HSV 转 BGR:还原为原始颜色空间
hsv2bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

# HSV 转 RGB:常用于显示或深度学习模型输入
hsv2rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)

# RGB 转 BGR:OpenCV默认是BGR格式
rgb2bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)

# BGR 转 RGB:用于兼容Matplotlib等库
bgr2rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# =================== 5. 阈值处理(二值化)===================
# 固定阈值处理:大于128设为255(白色),否则为0(黑色)
_, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)

# 自适应阈值处理:基于局部区域均值,窗口大小11x11,C=2
adaptive_binary = cv2.adaptiveThreshold(
gray, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY,
11, 2
)

# =================== 6. 边缘检测 ===================
# Canny边缘检测:低阈值50,高阈值150
edges_canny = cv2.Canny(gray, 50, 150)

# Sobel算子:X方向边缘检测,ksize=5
edges_sobel = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=5)

# Laplacian算子:所有方向边缘检测
edges_laplacian = cv2.Laplacian(gray, cv2.CV_64F)

# =================== 7. 显示图像 ===================
# 所有处理结果都会在一个个窗口中显示出来

cv2.imshow("Original", image)
cv2.imshow("Gaussian Blur", blurred)
cv2.imshow("Median Blur", median_blurred)
cv2.imshow("Resized", resized)
cv2.imshow("Rotated", rotated)
cv2.imshow("Gray", gray)
cv2.imshow("HSV", hsv)
cv2.imshow("Binary Threshold", binary)
cv2.imshow("Adaptive Threshold", adaptive_binary)
cv2.imshow("Canny Edges", edges_canny)
cv2.imshow("Sobel Edges", edges_sobel)
cv2.imshow("Laplacian Edges", edges_laplacian)
cv2.imshow("Gray2BGR", gray2bgr)
cv2.imshow("Hsv2BGR", hsv2bgr)
cv2.imshow("Hsv2RGB", hsv2rgb)
cv2.imshow("BGR2RGB", bgr2rgb)
cv2.imshow("RGB2BGR", rgb2bgr)

# =================== 8. 等待按键并关闭窗口 ===================
print("✅ 程序已启动,请按任意键关闭所有窗口...")

# 等待任意按键按下
cv2.waitKey(0)

# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()

HighGUI 模块

功能: 提供高层 GUI 和媒体 I/O 功能,用于图像的显示和交互。

主要类和函数:

  • 图像显示: cv.imshow()cv.waitKey()cv.destroyAllWindows()
  • 视频捕获: cv.VideoCapture()cv.VideoWriter()
  • 鼠标和键盘事件: cv.setMouseCallback()

应用场景:

  • 显示图像和视频。
  • 捕获摄像头或视频文件。
  • 处理用户交互(如鼠标点击、键盘输入)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import cv2  # 导入OpenCV库

# =================== 功能一:图像显示 ===================
def display_image():
"""
功能描述:
- 读取一张图片并显示在一个窗口中。
- 按下 'q' 键关闭窗口。
"""

# 读取图像文件
image = cv2.imread('../images/lena.png') # 替换为你自己的路径

# 判断是否成功读取图像
if image is None:
print("Error: Image not found!")
return

# 创建一个名为 "Image Window" 的窗口并显示图像
cv2.imshow("Image Window", image)

# 等待键盘输入(0 表示无限等待)
key = cv2.waitKey(0)

# 如果按下的是 'q' 键,输出提示信息
if key == ord('q'):
print("Quit")

# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()


# =================== 功能二:视频捕获和保存 ===================
def capture_and_save_video():
"""
功能描述:
- 打开默认摄像头(通常是0号设备)进行实时视频采集。
- 将每一帧写入输出视频文件 output.avi。
- 按下 'q' 键退出录制。
"""

# 打开摄像头(参数 0 表示默认摄像头)
cap = cv2.VideoCapture(0)

# 判断是否成功打开摄像头
if not cap.isOpened():
print("Error: Could not open camera!")
return

# 设置视频编码格式(这里使用 XVID 编码)
fourcc = cv2.VideoWriter_fourcc(*'XVID')

# 创建 VideoWriter 对象,用于写入视频
# 参数说明:
# - 文件名:output.avi
# - 编码器:fourcc
# - 帧率:20.0 FPS
# - 分辨率:640x480
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))

# 循环读取每一帧
while True:
# 读取当前帧
ret, frame = cap.read()

# 如果读取失败(如摄像头断开),退出循环
if not ret:
print("Error: Could not read frame!")
break

# 显示当前帧
cv2.imshow("Video Capture", frame)

# 写入当前帧到输出文件
out.write(frame)

# 检测是否按下 'q' 键,是则退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break

# 释放摄像头资源
cap.release()

# 释放视频写入资源
out.release()

# 关闭所有OpenCV窗口
cv2.destroyAllWindows()


# =================== 功能三:鼠标事件处理 ===================
def handle_mouse_events():
"""
功能描述:
- 在图像窗口中监听鼠标事件。
- 当用户左键或右键点击时,在控制台打印坐标信息。
"""

# 自定义鼠标回调函数
def mouse_callback(event, x, y, flags, param):
"""
参数说明:
event: 事件类型(如单击、移动等)
x, y: 发生事件时的坐标
flags: 特殊按键状态(如Shift、Ctrl等)
param: 用户自定义传参(本例未使用)
"""
# 左键单击
if event == cv2.EVENT_LBUTTONDOWN:
print(f"Left button clicked at ({x}, {y})")
# 右键单击
elif event == cv2.EVENT_RBUTTONDOWN:
print(f"Right button clicked at ({x}, {y})")
# 鼠标移动(可选)
# elif event == cv2.EVENT_MOUSEMOVE:
# print(f"Move by {x},{y}")

# 加载图像
image = cv2.imread('../images/lena.png') # 替换为你自己的路径

# 判断是否成功读取图像
if image is None:
print("Error: Image not found!")
return

# 创建一个窗口,并绑定鼠标事件回调函数
cv2.namedWindow("Mouse Events") # 创建一个名为 "Mouse Events" 的窗口
cv2.setMouseCallback("Mouse Events", mouse_callback) # 绑定回调函数

# 主循环:持续显示图像,直到按下 'q'
while True:
cv2.imshow("Mouse Events", image) # 显示图像
if cv2.waitKey(0) == ord('q'): # 按下 'q' 键退出
break

# 关闭所有OpenCV窗口
cv2.destroyAllWindows()


# =================== 主程序入口 ===================
if __name__ == "__main__":
"""
主程序逻辑:
- 提供一个简单的文本菜单,让用户选择要执行的功能
- 支持:
1. 显示图像
2. 捕获并保存视频
3. 处理鼠标事件
"""

# 打印功能菜单
print("Choose an option:")
print("1. Display Image")
print("2. Capture and Save Video")
print("3. Handle Mouse Events")

# 获取用户输入
choice = input("Enter your choice (1/2/3): ")

# 根据选择调用对应函数
if choice == '1':
display_image()
elif choice == '2':
capture_and_save_video()
elif choice == '3':
handle_mouse_events()
else:
print("Invalid choice!")

Video模块

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import cv2

# =================== 功能一:背景减除 ===================
def background_subtraction():
"""
功能描述:
- 使用摄像头实时获取视频流。
- 利用 OpenCV 提供的 MOG2 背景建模算法进行背景减除。
- 输出当前帧的前景掩膜图像。
"""

# 打开默认摄像头(设备索引号为0)
cap = cv2.VideoCapture(0)

# 检查摄像头是否成功打开
if not cap.isOpened():
print("Error: Could not open camera!")
return

# 创建背景减除器(MOG2算法)
subtractor = cv2.createBackgroundSubtractorMOG2(
history=500, # 历史帧数,用于构建背景模型
varThreshold=16, # 方差阈值,用于判断是否为前景
detectShadows=True # 是否检测阴影
)

while True:
# 读取当前帧
ret, frame = cap.read()

# 如果读取失败,跳出循环
if not ret:
break

# 应用背景减除器,得到前景掩膜
mask = subtractor.apply(frame)

# 显示原始帧和前景掩膜
cv2.imshow("Original", frame)
cv2.imshow("Background Subtraction", mask)

# 按下 'q' 键退出循环
if cv2.waitKey(30) & 0xFF == ord('q'):
break

# 释放摄像头资源
cap.release()
# 关闭所有OpenCV窗口
cv2.destroyAllWindows()


# =================== 功能二:光流法(Lucas-Kanade)===================
def optical_flow():
"""
功能描述:
- 使用 Lucas-Kanade 光流法追踪特征点运动轨迹。
- 在视频中绘制跟踪点的移动路径。
"""

# 打开默认摄像头
cap = cv2.VideoCapture(0)

# 检查摄像头是否成功打开
if not cap.isOpened():
print("Error: Could not open camera!")
return

# 读取第一帧
ret, prev_frame = cap.read()
if not ret:
return

# 将第一帧转为灰度图,用于后续处理
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)

# 检测初始特征点(最多检测100个)
prev_points = cv2.goodFeaturesToTrack(prev_gray, maxCorners=100, qualityLevel=0.01, minDistance=10)

while True:
# 读取下一帧
ret, frame = cap.read()
if not ret:
break

# 转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# 计算光流,找到当前帧中特征点的位置
next_points, status, _ = cv2.calcOpticalFlowPyrLK(prev_gray, gray, prev_points, None)

# 只保留状态为1(成功跟踪)的点
good_prev = prev_points[status == 1]
good_next = next_points[status == 1]

# 绘制光流轨迹
for i, (p, n) in enumerate(zip(good_prev, good_next)):
x1, y1 = p.ravel() # 上一帧点坐标
x2, y2 = n.ravel() # 当前帧点坐标
cv2.line(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)

# 显示结果
cv2.imshow("Optical Flow", frame)

# 更新上一帧和特征点
prev_gray = gray.copy()
prev_points = good_next.reshape(-1, 1, 2)

# 按下 'q' 键退出
if cv2.waitKey(30) & 0xFF == ord('q'):
break

# 释放资源
cap.release()
cv2.destroyAllWindows()


# =================== 功能三:目标跟踪(KCF)===================
def object_tracking():
"""
功能描述:
- 使用 KCF 目标跟踪器实现手动选择目标并持续跟踪。
- 用户通过鼠标框选目标区域后开始跟踪。
"""

# 打开默认摄像头
cap = cv2.VideoCapture(0)

# 检查摄像头是否成功打开
if not cap.isOpened():
print("Error: Could not open camera!")
return

# 读取第一帧
ret, frame = cap.read()
if not ret:
return

# 弹出窗口让用户选择跟踪目标区域(ROI)
bbox = cv2.selectROI("Select ROI", frame, fromCenter=False)
cv2.destroyAllWindows()

# 初始化 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 failure detected", (100, 80),
cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)

# 显示跟踪结果
cv2.imshow("Object Tracking", frame)

# 按下 'q' 键退出
if cv2.waitKey(30) & 0xFF == ord('q'):
break

# 释放资源
cap.release()
cv2.destroyAllWindows()


# =================== 主程序入口 ===================
if __name__ == "__main__":
"""
主程序逻辑:
- 提供一个简单的文本菜单,让用户选择要执行的功能
- 支持:
1. 背景减除
2. 光流法
3. 目标跟踪
"""

# 打印功能菜单
print("Choose an option:")
print("1. Background Subtraction")
print("2. Optical Flow")
print("3. Object Tracking")

# 获取用户输入
choice = input("Enter your choice (1/2/3): ")

# 根据选择调用对应函数
if choice == '1':
background_subtraction()
elif choice == '2':
optical_flow()
elif choice == '3':
object_tracking()
else:
print("Invalid choice!")

使用opencv自带的目标跟踪准确率非常低,以下是使用yolo的目标检测代码:

YOLOv8目标检测(CPU)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from ultralytics import YOLO
import cv2

# 加载预训练模型(可选:yolov8n.pt, yolov8s.pt, yolov8m.pt...)
model = YOLO('yolov8s.pt')

# 打开摄像头
cap = cv2.VideoCapture(0)

while cap.isOpened():
ret, frame = cap.read()
if not ret:
break

# 使用YOLO进行推理
results = model(frame)

# 可视化结果
annotated_frame = results[0].plot()

cv2.imshow("YOLOv8 Detection", annotated_frame)

if cv2.waitKey(1) & 0xFF == ord('q'):
break

cap.release()
cv2.destroyAllWindows()

YOLOv8目标检测(GPU)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from ultralytics import YOLO
import cv2
import time

# ================== 1. 加载预训练模型 ==================
# 支持 yolov8n.pt / yolov8s.pt / yolov8m.pt / yolov8l.pt / yolov8x.pt
model = YOLO('yolov8s.pt') # 加载模型,会自动从网络下载到本地缓存目录

# 强制使用 GPU(如果可用)
device = 'cuda' if model.device.type == 'cuda' else 'cpu'
print(f"当前使用的设备: {device}")

# ================== 2. 打开摄像头 ==================
cap = cv2.VideoCapture(0) # 打开默认摄像头(索引号为0)

if not cap.isOpened():
print("错误:无法打开摄像头")
exit()

# 设置摄像头分辨率(可选)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# ================== 3. 实时检测循环 ==================
print("开始检测,请查看摄像头窗口... 按 q 键退出")

prev_time = time.time() # 用于计算帧率

while True:
ret, frame = cap.read()
if not ret:
print("读取帧失败,退出...")
break

# 使用 GPU 进行推理
results = model(frame, device=device)

# 绘制检测结果
annotated_frame = results[0].plot() # 自动绘制边界框和标签

# 计算帧率
current_time = time.time()
fps = 1 / (current_time - prev_time)
prev_time = current_time

# 在图像上显示帧率
cv2.putText(annotated_frame, f"FPS: {int(fps)}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

# 显示结果
cv2.imshow("YOLOv8 实时目标检测", annotated_frame)

# 按下 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
print("用户已按下 q 键,退出检测...")
break

# ================== 4. 释放资源 ==================
cap.release()
cv2.destroyAllWindows()

注意:如果你是笔记本电脑自带的 Intel 集成显卡或 AMD 显卡,目前无法使用 CUDA 加速 YOLOv8

常用总结

类别 方法 示例
图像读取 cv2.imread, cv2.imwrite image = cv2.imread('lena.png')
视频处理 cv2.VideoCapture, cv2.VideoWriter cap = cv2.VideoCapture(0)
几何变换 cv2.resize, cv2.rotate resized = cv2.resize(image, None, fx=0.5, fy=0.5)
颜色空间 cv2.cvtColor gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
滤波去噪 cv2.GaussianBlur, cv2.medianBlur blurred = cv2.GaussianBlur(image, (11, 11), 0)
边缘检测 cv2.Canny, cv2.Sobel edges = cv2.Canny(gray, 50, 150)
阈值处理 cv2.threshold, cv2.adaptiveThreshold _, binary = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)
目标跟踪 cv2.TrackerKCF_create tracker = cv2.TrackerKCF_create()
绘制图形 cv2.putText, cv2.rectangle cv2.rectangle(image, (100, 100), (200, 200), (0, 255, 0), 2)

补充:

opencv中图像坐标的原点 (0, 0) 在 左上角

一般来说,在深度学习中,NCHWNHWC 是两种常见的数据格式,用于表示图像数据的存储方式。它们分别代表不同的维度排列顺序。

  • NCHW:N 表示批量大小(Batch),C 表示通道数(Channel),H 表示高度(Height),W 表示宽度(Width)。
  • NHWC:N 表示批量大小(Batch),H 表示高度(Height),W 表示宽度(Width),C 表示通道数(Channel)。

性能差异:在 GPU 上,NCHW 格式更适合,因为它可以利用 GPU 的并行性,计算卷积时比 NHWC 要快约 2.5 倍。在 CPU 上,NHWC 格式更适合,因为它可以利用 SSE 或 AVX 优化,沿着最后一维(即 C 维)计算会更快

不同的深度学习框架对 NCHW 和 NHWC 格式的支持情况如下:

  • TensorFlow:默认使用 NHWC 格式,GPU 也支持 NCHW。
  • Caffe:使用 NCHW 格式。
  • PyTorch:使用 NCHW 格式