OpenCV--从零构建个人人脸识别系统

📅 2026/7/14 10:19:45
OpenCV--从零构建个人人脸识别系统
1. 人脸识别系统基础准备想要从零构建个人人脸识别系统首先需要理解几个核心概念。人脸识别本质上分为两个步骤人脸检测和人脸识别。人脸检测负责在图像中找到人脸的位置就像在人群中先找到每个人的脸人脸识别则是判断这张脸属于谁就像认出老朋友的面孔。OpenCV作为计算机视觉领域的瑞士军刀提供了完整的工具链。我推荐使用Python语言进行开发因为它的语法简单社区资源丰富。安装OpenCV只需要一行命令pip install opencv-python opencv-contrib-python硬件方面普通笔记本电脑就足够运行基础的人脸识别系统。如果追求更好的实时性能可以考虑配备独立显卡的机器。我用过的一款性价比很高的配置是Intel i5处理器16GB内存NVIDIA GTX 1650显卡可以流畅运行多个人脸识别模型。2. 数据集采集与处理2.1 公开数据集获取ORL人脸数据库是个不错的起点包含40个人每人10张不同角度和表情的照片。下载后建议按照以下目录结构组织dataset/ s1/ s1_1.bmp s1_2.bmp ... s2/ s2_1.bmp ...我处理这个数据集时发现图片尺寸统一为92×112像素这为后续处理提供了便利。可以用以下代码批量检查图片尺寸import cv2 import os for root, dirs, files in os.walk(dataset): for file in files: img cv2.imread(os.path.join(root, file)) print(f{file} 尺寸: {img.shape})2.2 个人数据采集搭建自己的数据集需要一些技巧。我建议在不同光照条件下自然光、室内光采集包含不同表情微笑、严肃和角度正面、轻微侧脸。使用OpenCV的摄像头采集代码如下import cv2 cap cv2.VideoCapture(0) count 0 while True: ret, frame cap.read() cv2.imshow(Capture, frame) key cv2.waitKey(1) if key ord(p): # 按p键拍照 cv2.imwrite(fmy_face_{count}.jpg, frame) count 1 elif key 27: # ESC键退出 break cap.release() cv2.destroyAllWindows()我通常会采集20-30张自己的照片覆盖各种场景。曾经因为只采集了5张照片导致识别率很低后来增加了样本数量才改善。2.3 数据预处理采集的照片需要统一处理为92×112的灰度图。这个步骤很关键我遇到过因为尺寸不一致导致训练失败的情况。预处理代码如下face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml) def preprocess_image(img_path): img cv2.imread(img_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: face_roi gray[y:yh, x:xw] resized cv2.resize(face_roi, (92, 112)) return resized return None处理完成后建议将个人照片放入dataset/s41目录假设ORL数据集有40个人保持数据结构一致。3. 数据标注与CSV文件生成3.1 手动标注的痛点早期项目我手动创建CSV文件400张图片花了大半天时间还容易出错。后来发现可以用Python脚本自动生成效率提升十倍不止。3.2 自动化CSV生成以下脚本可以自动创建包含图片路径和标签的CSV文件import os import csv with open(faces.csv, w, newline) as csvfile: writer csv.writer(csvfile, delimiter;) for root, dirs, files in os.walk(dataset): for file in files: if file.endswith(.bmp): label os.path.basename(root)[1:] # 获取s1中的1 path os.path.join(root, file) writer.writerow([path, label])这个脚本会生成如下格式的CSVdataset/s1/s1_1.bmp;1 dataset/s1/s1_2.bmp;1 ... dataset/s41/s41_1.bmp;41我建议在生成后手动检查几行确保路径和标签对应正确。曾经因为路径中的反斜杠问题导致训练时读取失败后来统一改用正斜杠解决了。4. 模型训练与算法选择4.1 OpenCV提供的三种算法OpenCV提供了三种传统人脸识别算法各有特点Eigenfaces基于PCA降维计算人脸的主成分Fisherfaces考虑类别信息的LDA降维LBPH局部二值模式直方图对光照变化更鲁棒在我的测试中LBPH在光照变化大的场景表现最好Eigenfaces训练速度最快。以下是三种模型的训练代码import cv2 import numpy as np def load_dataset(csv_path): images [] labels [] with open(csv_path, r) as f: for line in f: path, label line.strip().split(;) images.append(cv2.imread(path, cv2.IMREAD_GRAYSCALE)) labels.append(int(label)) return images, labels images, labels load_dataset(faces.csv) # Eigenfaces model_eigen cv2.face.EigenFaceRecognizer_create() model_eigen.train(images, np.array(labels)) model_eigen.save(model_eigen.yml) # Fisherfaces model_fisher cv2.face.FisherFaceRecognizer_create() model_fisher.train(images, np.array(labels)) model_fisher.save(model_fisher.yml) # LBPH model_lbph cv2.face.LBPHFaceRecognizer_create() model_lbph.train(images, np.array(labels)) model_lbph.save(model_lbph.yml)训练时间取决于数据集大小ORL个人数据约450张图在我的笔记本上大约需要2分钟。4.2 模型参数调优每个算法都有可调参数以LBPH为例model_lbph cv2.face.LBPHFaceRecognizer_create( radius1, # LBP半径 neighbors8, # 采样点数量 grid_x8, # 水平分块数 grid_y8, # 垂直分块数 threshold100.0 # 识别阈值 )我通过实验发现grid分块太多如16×16会导致过拟合太少如4×4则识别率下降。8×8是个不错的平衡点。5. 实时人脸识别实现5.1 基础识别流程将训练好的模型应用到摄像头视频流的完整代码cap cv2.VideoCapture(0) face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml) model cv2.face.LBPHFaceRecognizer_create() model.read(model_lbph.yml) while True: ret, frame cap.read() gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: face_roi gray[y:yh, x:xw] resized cv2.resize(face_roi, (92, 112)) label, confidence model.predict(resized) if label 41 and confidence 70: # 假设个人标签是41 cv2.putText(frame, Me, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2) cv2.rectangle(frame, (x,y), (xw,yh), (0,255,0), 2) else: cv2.rectangle(frame, (x,y), (xw,yh), (0,0,255), 2) cv2.imshow(Face Recognition, frame) if cv2.waitKey(1) 27: break cap.release() cv2.destroyAllWindows()5.2 性能优化技巧在实际使用中我发现几个提升体验的技巧降低检测频率每3帧检测一次人脸其余帧只做识别多帧投票连续5帧识别为同一个人才确认结果动态阈值根据光照条件自动调整识别阈值优化后的检测部分代码frame_count 0 last_labels [] while True: ret, frame cap.read() frame_count 1 if frame_count % 3 0: # 每3帧检测一次人脸 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: # ...识别代码同前... last_labels.append(label) if len(last_labels) 5: last_labels.pop(0) # 取最近5帧中最常见的标签 final_label max(set(last_labels), keylast_labels.count)6. 系统部署与优化6.1 常见问题解决在项目实践中我遇到过几个典型问题误识别解决方法是在不同光照条件下采集更多训练数据侧脸识别差可以增加侧脸训练样本或使用多角度检测模型实时性差减少检测频率或改用更轻量的模型6.2 扩展功能基础系统完成后可以考虑添加以下功能人脸注册功能通过GUI界面添加新用户活体检测防止照片攻击表情识别同时识别面部表情一个简单的人脸注册功能实现import tkinter as tk from tkinter import simpledialog def register_new_face(): name simpledialog.askstring(Input, Enter your name:) if name: cap cv2.VideoCapture(0) count 0 while count 20: # 采集20张照片 ret, frame cap.read() gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: cv2.imwrite(fdataset/{name}/{name}_{count}.jpg, gray[y:yh, x:xw]) count 1 cv2.imshow(Registering, frame) cv2.waitKey(100) cap.release() cv2.destroyAllWindows() update_model() # 重新训练模型 root tk.Tk() btn tk.Button(root, textRegister New Face, commandregister_new_face) btn.pack() root.mainloop()这个项目最让我有成就感的是看到系统准确识别出自己的那一刻。从数据采集到模型训练再到最后的实时识别每个环节都有需要解决的挑战。建议初学者可以先复现基础版本再逐步添加自己的改进。