本文档说明
使用 OpenCV 内置的 Haar 级联分类器,实现 USB 摄像头实时人脸检测与框选,并进行性能调优。
前置准备
bash
source ~/opencv-env/bin/activate1
Haar 级联分类器简介
OpenCV 内置了多种预训练的 Haar 级联分类器模型,无需额外下载:
| 模型文件 | 检测目标 |
|---|---|
haarcascade_frontalface_default.xml | 正面人脸 |
haarcascade_eye.xml | 眼睛 |
haarcascade_smile.xml | 微笑 |
haarcascade_upperbody.xml | 上半身 |
模型文件位于 OpenCV 安装目录中,可通过代码自动获取路径。
基础人脸检测
python
import cv2
import os
os.environ.setdefault('DISPLAY', ':0')
DEVICE_INDEX = 73
def main():
# 加载人脸检测模型
cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
face_cascade = cv2.CascadeClassifier(cascade_path)
cap = cv2.VideoCapture(DEVICE_INDEX)
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)
if not cap.isOpened():
print("Error: Cannot open camera")
return
win = "Face Detection"
cv2.namedWindow(win, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(win, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
print("Press 'q' to quit")
import time
frame_count = 0
start_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
break
frame_count += 1
# 转灰度(Haar 检测需要灰度图)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.3,
minNeighbors=5,
minSize=(30, 30)
)
# 画框
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(frame, "Face", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
# 显示 FPS 和人脸数量
elapsed = time.time() - start_time
fps = frame_count / elapsed if elapsed > 0 else 0
cv2.putText(frame, f"FPS: {fps:.1f} | Faces: {len(faces)}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
cv2.imshow(win, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
print(f"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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
运行:
bash
DISPLAY=:0 ~/opencv-env/bin/python3 face_detect.py1
性能调优
detectMultiScale 参数说明
| 参数 | 作用 | 调优建议 |
|---|---|---|
scaleFactor | 图像缩放比例 | 越大越快但可能漏检,推荐 1.2~1.5 |
minNeighbors | 最少邻居数 | 越大误检越少,推荐 4~6 |
minSize | 最小检测尺寸 | 过滤太小的误检,推荐 (30,30) |
优化版:缩小检测图 + 跳帧
python
import cv2
import time
import os
os.environ.setdefault('DISPLAY', ':0')
DEVICE_INDEX = 73
DETECT_SCALE = 0.5 # 缩小到 50% 做检测
SKIP_FRAMES = 2 # 每 N 帧检测一次
def main():
cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
face_cascade = cv2.CascadeClassifier(cascade_path)
cap = cv2.VideoCapture(DEVICE_INDEX)
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)
if not cap.isOpened():
print("Error: Cannot open camera")
return
win = "Face Detection (Optimized)"
cv2.namedWindow(win, cv2.WINDOW_NORMAL)
cv2.setWindowProperty(win, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
frame_count = 0
start_time = time.time()
faces = []
while True:
ret, frame = cap.read()
if not ret:
break
frame_count += 1
# 每 N 帧检测一次,其余帧复用上次结果
if frame_count % SKIP_FRAMES == 0:
small = cv2.resize(frame, None, fx=DETECT_SCALE, fy=DETECT_SCALE)
gray = cv2.cvtColor(small, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5, minSize=(20, 20))
# 画框(坐标需要还原)
for (x, y, w, h) in faces:
sx = int(x / DETECT_SCALE)
sy = int(y / DETECT_SCALE)
sw = int(w / DETECT_SCALE)
sh = int(h / DETECT_SCALE)
cv2.rectangle(frame, (sx, sy), (sx + sw, sy + sh), (0, 255, 0), 2)
elapsed = time.time() - start_time
fps = frame_count / elapsed if elapsed > 0 else 0
cv2.putText(frame, f"FPS: {fps:.1f} | Faces: {len(faces)}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
cv2.imshow(win, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
print(f"Optimized 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
59
60
61
62
63
64
65
66
67
68
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
性能对比
| 方案 | 分辨率 | 帧率 |
|---|---|---|
| 基础版(每帧检测) | 1280×720 | 13.1fps |
| 优化版(缩小+跳帧) | 640×480 | 19.3fps |
进一步加速
如需更高性能的人脸检测/识别,可以使用 RK3576 的 NPU(RKNN)进行 AI 推理加速,推理速度可达 4.4ms/帧。