课程实现由三个脚本组成:采集人脸、训练 LBPH 模型、实时识别。完整代码与 Haar 分类器保存在七项课程设计资料中,提取码:3ezu

返回项目 005 · 硬件组装与镜像烧录 · 环境搭建与相机测试

1、目录结构

1
2
3
4
5
6
7
OpenCV_Facial_Recognition/
├── 01_face_dataset.py
├── 02_face_training.py
├── 03_face_recognition.py
├── haarcascade_frontalface_default.xml
├── dataset/
└── trainer/

先创建输出目录:

1
mkdir -p dataset trainer

2、采集人脸样本

01_face_dataset.py 使用摄像头读取画面,Haar 分类器定位人脸,将灰度人脸区域保存为:

1
dataset/User.<person_id>.<sample_id>.jpg

课程源码中的采集流程:

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
cam = cv2.VideoCapture(0)
cam.set(3, 640)
cam.set(4, 480)

face_detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
face_id = input("\n 请输入用户ID,然后按 <回车> 键 ==> ")
count = 0

while True:
ret, img = cam.read()
img = cv2.flip(img, -1)
img = cv2.flip(img, 0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(gray, 1.3, 5)

for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
count += 1
cv2.imwrite(
"dataset/User." + str(face_id) + "." + str(count) + ".jpg",
gray[y:y + h, x:x + w],
)
cv2.imshow("image", img)

k = cv2.waitKey(100) & 0xff
if k == 27 or count >= 30:
break

cam.release()
cv2.destroyAllWindows()

课程版本为每个人采集约 30 张样本。采集时应缓慢改变角度和表情,并避免所有照片几乎完全相同。

运行:

1
python3 01_face_dataset.py

3、训练 LBPH 模型

02_face_training.py 读取文件名中的人员 ID,将灰度图像转换为 NumPy 数组,再训练 LBPH 识别器。课程源码中的核心函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")

def getImagesAndLabels(path):
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
faceSamples = []
ids = []

for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert("L")
img_numpy = np.array(PIL_img, "uint8")
id = int(os.path.split(imagePath)[-1].split(".")[1])
faces = detector.detectMultiScale(img_numpy)

for (x, y, w, h) in faces:
faceSamples.append(img_numpy[y:y + h, x:x + w])
ids.append(id)

return faceSamples, ids

faces, ids = getImagesAndLabels("dataset")
recognizer.train(faces, np.array(ids))
recognizer.write("trainer/trainer.yml")

运行:

1
python3 02_face_training.py

训练完成后应确认 trainer/trainer.yml 已生成,并记录实际参与训练的人员数量和样本数量。

4、实时识别

03_face_recognition.py 加载 trainer.yml,对摄像头中的每个人脸执行预测:

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
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read("trainer/trainer.yml")

faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
names = ["None", "Marcelo", "Paula", "Ilza", "Z", "W"]

faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(int(minW), int(minH)),
)

for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
id, confidence = recognizer.predict(gray[y:y + h, x:x + w])

if confidence < 100:
id = names[id]
confidence = " {0}%".format(round(100 - confidence))
else:
id = "unknown"
confidence = " {0}%".format(round(100 - confidence))

cv2.putText(img, str(id), (x + 5, y - 5), font, 1,
(255, 255, 255), 2)
cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1,
(255, 255, 0), 1)

LBPH 返回的值更接近“距离”,数值越小通常表示越相似。课程代码把它转换成便于展示的百分比,但这个百分比不是经过严格校准的真实概率。

运行:

1
python3 03_face_recognition.py

人员 ID 与姓名通过脚本中的列表映射。应保证列表索引与采集时输入的数字 ID 一致。

5、完整运行顺序

1
2
3
4
cd OpenCV_Facial_Recognition
python3 01_face_dataset.py
python3 02_face_training.py
python3 03_face_recognition.py

重新采集或新增人员后,需要再次运行训练脚本,生成新的 trainer.yml

6、测试建议

测试 目的
同一人、相似光照 验证基本识别链路
同一人、不同角度 观察姿态变化影响
同一人、不同光照 观察光照鲁棒性
未登记人员 检查未知人员阈值
多人同时出现 检查检测和显示逻辑
遮挡或远距离 记录失败边界

不要只用训练时同一位置、同一光照下的画面测试,否则结果会显得很好,却不能说明模型具有泛化能力。

7、实现边界与改进

  • 当前实现是 Haar + LBPH 的轻量课程方案。
  • 没有经过独立测试集、交叉验证或标准数据集评估。
  • 没有活体检测,照片或屏幕攻击可能绕过识别。
  • 没有数据库、身份权限和隐私数据管理。

后续可在电脑端比较深度特征模型、SVM、PCA 或人脸反欺骗方法,但应把扩展实验与树莓派上的实际可复现版本分开记录。