本文档说明
掌握多摄像头管理、分辨率切换等进阶技巧,以及常见报错的排查方法。
多摄像头管理
如果接入了多个 USB 摄像头,可以同时打开:
python
import cv2
import os
os.environ.setdefault('DISPLAY', ':0')
# 假设两个摄像头分别是 /dev/video73 和 /dev/video75
cap1 = cv2.VideoCapture(73)
cap2 = cv2.VideoCapture(75)
while True:
ret1, frame1 = cap1.read()
ret2, frame2 = cap2.read()
if ret1:
cv2.imshow("Camera 1", frame1)
if ret2:
cv2.imshow("Camera 2", frame2)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap1.release()
cap2.release()
cv2.destroyAllWindows()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
WARNING
同一个摄像头不能被两个进程同时打开。如果报错 VIDIOC_STREAMON: Device or resource busy,说明摄像头已被其他程序占用。
分辨率动态切换
python
import cv2
DEVICE_INDEX = 73
cap = cv2.VideoCapture(DEVICE_INDEX)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
# 常用分辨率
resolutions = {
'480p': (640, 480),
'720p': (1280, 720),
'1080p': (1920, 1080),
}
def set_resolution(cap, name):
w, h = resolutions[name]
cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"Set {name}: requested {w}x{h}, actual {actual_w}x{actual_h}")
set_resolution(cap, '720p')
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
TIP
cap.set() 设置的参数不一定生效,取决于摄像头硬件支持。设置后务必用 cap.get() 确认实际值。
脚本模板
推荐的脚本开头模板,处理了 DISPLAY 和设备号自动检测:
python
#!/usr/bin/env python3
import cv2
import os
import subprocess
# 自动设置 DISPLAY(ADB/SSH 场景)
os.environ.setdefault('DISPLAY', ':0')
def find_usb_camera():
"""自动检测 USB 摄像头设备号"""
try:
result = subprocess.run(['v4l2-ctl', '--list-devices'],
capture_output=True, text=True, timeout=5)
lines = result.stdout.split('\n')
for i, line in enumerate(lines):
if 'usb' in line.lower():
for j in range(i + 1, len(lines)):
dl = lines[j].strip()
if dl.startswith('/dev/video'):
return int(dl.replace('/dev/video', ''))
if dl == '':
break
except Exception:
pass
return None
# 自动获取设备号
DEVICE = find_usb_camera()
if DEVICE is None:
print("No USB camera found!")
exit(1)
print(f"Using camera: /dev/video{DEVICE}")
# --- 你的代码从这里开始 ---
cap = cv2.VideoCapture(DEVICE)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
# ...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
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
常见问题排查
cv2.error: Cannot connect to X server
原因:没有设置 DISPLAY 环境变量。
解决:在脚本开头加:
python
import os
os.environ.setdefault('DISPLAY', ':0')1
2
2
或运行时加前缀:
bash
DISPLAY=:0 ~/opencv-env/bin/python3 your_script.py1
VIDIOC_STREAMON: Device or resource busy
原因:摄像头已被其他程序占用。
解决:
bash
# 查看谁在使用摄像头
fuser /dev/video73
# 杀掉占用进程
fuser -k /dev/video731
2
3
4
2
3
4
帧率很低(只有 5~10fps)
可能原因:
- 使用了 YUYV 格式而非 MJPG
- 分辨率设置过高
- 处理逻辑太重
解决:
python
# 确保使用 MJPG
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
# 降低分辨率
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)1
2
3
4
5
2
3
4
5
imshow 窗口无响应 / 卡死
原因:循环中没有调用 cv2.waitKey()。
waitKey() 不仅检测按键,还负责处理窗口事件。不调用则窗口卡死。
ModuleNotFoundError: No module named 'cv2'
原因:没有激活虚拟环境。
解决:
bash
source ~/opencv-env/bin/activate
# 或直接用虚拟环境的 python
~/opencv-env/bin/python3 your_script.py1
2
3
2
3
摄像头拔插后设备号变了
USB 摄像头的设备号不是固定的,拔插后可能变化。使用自动检测脚本获取当前设备号:
bash
v4l2-ctl --list-devices | grep -A1 usb | grep /dev/video | head -11
或在代码中使用上方的 find_usb_camera() 函数自动检测。