本文档说明
使用 Python + OpenCV 打开 USB 摄像头,实现实时画面全屏显示、FPS 叠加和按键截图功能。
前置准备
确保已完成 环境搭建 和 USB摄像头识别与验证。
bash
source ~/opencv-env/bin/activate1
WARNING
本章代码中的 DEVICE_INDEX = 73 需要替换为你实际的设备号。
打开摄像头
OpenCV 使用 cv2.VideoCapture 来操作摄像头,传入设备索引号(/dev/videoX 中的 X):
python
import cv2
DEVICE_INDEX = 73
cap = cv2.VideoCapture(DEVICE_INDEX)
if not cap.isOpened():
print("Error: Cannot open camera")
exit()
print("Camera opened successfully")
cap.release()1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
设置摄像头参数
python
import cv2
DEVICE_INDEX = 73
cap = cv2.VideoCapture(DEVICE_INDEX)
# 设置 MJPG 格式(低带宽,高帧率)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
# 设置分辨率
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
# 设置帧率
cap.set(cv2.CAP_PROP_FPS, 25)
# 确认实际参数(不一定和设置值一致,取决于硬件支持)
print(f"Resolution: {int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))}x{int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))}")
print(f"FPS: {cap.get(cv2.CAP_PROP_FPS)}")
cap.release()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
核心 API 说明
cap.read() 返回值
ret, frame = cap.read() 返回两个值:
ret(bool):读取是否成功,必须检查frame(numpy.ndarray):图像数据,形状(height, width, 3),通道顺序 BGR
waitKey 说明
cv2.waitKey(1) & 0xFF 是固定写法:
waitKey(1):等待 1ms,让 OpenCV 刷新窗口。传 0 则无限等待& 0xFF:取低 8 位,确保按键判断在 64 位系统上正确
实时全屏显示
将摄像头画面实时全屏显示在屏幕上,叠加 FPS 信息:
python
import cv2
import time
import os
os.environ.setdefault('DISPLAY', ':0')
DEVICE_INDEX = 73
def main():
cap = cv2.VideoCapture(DEVICE_INDEX)
if not cap.isOpened():
print("Error: Cannot open camera")
return
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
cap.set(cv2.CAP_PROP_FPS, 25)
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"Camera: {w}x{h} | Press 'q' to quit")
# 全屏窗口
win = "USB Camera"
cv2.namedWindow(win, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(win, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
frame_count = 0
start_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
print("Frame read failed")
break
frame_count += 1
elapsed = time.time() - start_time
fps = frame_count / elapsed if elapsed > 0 else 0
# 叠加 FPS
cv2.putText(frame, f"FPS: {fps:.1f}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, f"{w}x{h}", (w - 160, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
cv2.imshow(win, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
print(f"Total: {frame_count} frames, Avg FPS: {fps:.1f}")
if __name__ == "__main__":
main()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
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
保存为 ~/opencv-test/camera_preview.py,运行:
bash
# 桌面终端直接运行
python3 ~/opencv-test/camera_preview.py
# ADB/SSH 远程运行
DISPLAY=:0 ~/opencv-env/bin/python3 ~/opencv-test/camera_preview.py1
2
3
4
5
2
3
4
5
按键截图功能
在实时预览基础上,按 s 键保存截图:
python
import cv2
import time
import os
os.environ.setdefault('DISPLAY', ':0')
DEVICE_INDEX = 73
def main():
cap = cv2.VideoCapture(DEVICE_INDEX)
if not cap.isOpened():
print("Error: Cannot open camera")
return
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
win = "Camera - Press 's' to save, 'q' to quit"
cv2.namedWindow(win, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(win, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
print("Press 's' to save screenshot, 'q' to quit")
while True:
ret, frame = cap.read()
if not ret:
break
cv2.imshow(win, frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('s'):
filename = f"capture_{int(time.time())}.jpg"
cv2.imwrite(filename, frame)
print(f"Saved: {filename}")
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()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
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
截图保存位置
文件保存在运行脚本时的当前目录。支持 .jpg(有损压缩)、.png(无损)、.bmp(无压缩)格式。
API 速查
| 函数 | 作用 | 示例 |
|---|---|---|
cv2.VideoCapture(index) | 打开摄像头 | cap = cv2.VideoCapture(73) |
cap.isOpened() | 检查是否打开成功 | if not cap.isOpened(): ... |
cap.set(prop, value) | 设置参数 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) |
cap.get(prop) | 获取参数 | w = cap.get(cv2.CAP_PROP_FRAME_WIDTH) |
cap.read() | 读取一帧 | ret, frame = cap.read() |
cap.release() | 释放摄像头 | cap.release() |
cv2.imshow(name, img) | 显示图像 | cv2.imshow("Camera", frame) |
cv2.waitKey(ms) | 等待按键 | key = cv2.waitKey(1) & 0xFF |
cv2.imwrite(path, img) | 保存图像 | cv2.imwrite("photo.jpg", frame) |
cv2.destroyAllWindows() | 关闭所有窗口 | cv2.destroyAllWindows() |
常见问题
运行时报错 "cannot open display"
通过 ADB/SSH 运行时需要指定 DISPLAY。在脚本开头加:
python
import os
os.environ.setdefault('DISPLAY', ':0')1
2
2
画面延迟很大
- 确认使用了 MJPG 格式(而非 YUYV)
- 降低分辨率到 640×480
- 去掉不必要的处理逻辑
报错 "Cannot open camera"
设备号不对。运行 v4l2-ctl --list-devices | grep -A1 usb 确认实际设备号。