人脸识别项目实战(一):人脸检测模块实现
人脸检测是人脸识别系统的基础,负责从图像或视频中准确定位人脸区域。本模块基于 LFW 数据集和 YOLOv8 模型,实现高效的人脸检测功能,为后续的人脸识别识别流程提供支持。准备 LFW 人脸数据集并进行预处理使用 LabelImg 工具进行人脸区域标注基于 YOLOv8 模型进行训练与优化实现图片与视频流的人脸检测功能技术栈:Python 3.12+、OpenCV、YOLOv8、LabelImg
人脸识别项目实战(一):人脸检测模块实现
一、项目结构

二、模块概述
人脸检测是人脸识别系统的基础,负责从图像或视频中准确定位人脸区域。本模块基于 LFW 数据集和 YOLOv8 模型,实现高效的人脸检测功能,为后续的人脸识别识别流程提供支持。
人脸检测模块主要完成以下任务:
- 准备 LFW 人脸数据集并进行预处理
- 使用 LabelImg 工具进行人脸区域标注
- 基于 YOLOv8 模型进行训练与优化
- 实现图片与视频流的人脸检测功能
技术栈:Python 3.10+、OpenCV、YOLOv8、LabelImg、LFW 数据集
(建议建立一个虚拟环境,后续人脸识别模块可能会出现依赖库版本冲突的问题(如numpy版本被降级),使用虚拟环境可以有效隔离项目依赖,避免影响系统全局环境)
三、数据集准备
1. LFW 数据集下载
LFW(Labeled Faces in the Wild)是常用的人脸数据集,包含数千张真实场景下的人脸图片。
🛠️ 方法一:国内镜像下载(速度快)
🛠️ 方法二:官网直接下载
🛠️ 方法三:使用 scikit-learn 自动下载
安装sklearn-learn库
pip install scikit-learn==1.3.2
下载LFW数据集
from sklearn.datasets import fetch_lfw_people
# 自动下载并加载数据集
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
2. 数据整理与筛选
LFW 数据集原始结构为按人物分目录存储,我们需要将图片集中整理并筛选部分样本用于标注
(1)将lfw原始图片整合到data中
import os
import shutil
# lfw 目录
source_dir = os.path.join(os.getcwd(), 'lfw')
# data目录
target_dir = os.path.join(os.getcwd(), 'data')
# 支持的图像文件扩展名列表
image_extension = ('.jpg', '.jpeg', '.png')
# 统计迁移的图像数量
count = 0
# 遍历lfw目录
for root, dirs, files in os.walk(source_dir):
# print(files)
for file in files:
if file.lower().endswith(image_extension):
src_path = os.path.join(root, file)
dst_path = os.path.join(target_dir, file)
# 处理可能存在的文件名冲突(自动重命名)
if os.path.exists(dst_path):
base, ext = os.path.splitext(file)
i = 1
new_path = dst_path
while os.path.exists(dst_path):
new_name = base + '_' + str(i) + ext
new_path = os.path.join(target_dir, new_name)
i += 1
dst_path = new_path
shutil.copy(src_path, dst_path) # 保留原始数据,避免操作失误导致数据丢失
count += 1
print(f"移动完成!共迁移 {count} 张图片到 {target_dir} 目录")
(2)数据清洗
data文件夹中包含1w多张图片,筛选一些图片来标记即可,再使用缩放模糊增强数据
import os
import random
import shutil
import cv2
import numpy as np
src_path = 'data/'
dst_path = 'sift_img/'
# 支持的图像文件扩展名列表
image_extension = ('.jpg', '.jpeg', '.png')
# 存放所有图片的相对路径
img_files = []
# 获取所有图片的相对路径
for root, dirs, files in os.walk(src_path):
for filename in files:
if filename.endswith(image_extension):
img_files.append(os.path.join(root, filename))
# 设置选取图片的总数量
total = min(200, len(img_files))
# 随机选择 total 张图片的路径
sift_path = random.sample(img_files, total)
# print(sift_path)
for image_path in sift_path:
shutil.copy(image_path, dst_path) # 保留原始数据,避免操作失误导致数据丢失
# 当前数据只能处理近距离的人脸识别,离远点效果就变差了
# 所以再选择一些图片,处理图像,增强数据
deal_size = min(30, len(img_files))
deal_path = random.sample(img_files, deal_size)
for img_path in deal_path:
img = cv2.imread(img_path)
# 当路径中包含中文、空格或特殊字符等等,可能会导致图像无法读取
if img is None:
print(f"无法读取图片: {img_path}")
continue
# 获取文件名
filename = os.path.basename(img_path)
# 创建不同缩放比例的版本 (模拟不同距离)
for scale_factor in [0.3, 0.5, 0.7]: # 30%, 50%, 70% 缩放
# 缩放人脸
face_width = int(img.shape[1] * scale_factor)
face_height = int(img.shape[0] * scale_factor)
scaled_face = cv2.resize(img, (face_width, face_height), interpolation=cv2.INTER_AREA)
# 创建大背景 (原始尺寸的1.5倍)
bg_width = int(img.shape[1] * 1.5)
bg_height = int(img.shape[0] * 1.5)
new_img = np.zeros((bg_height, bg_width, 3), dtype=np.uint8)
# 随机位置放置缩放后的人脸
x = random.randint(0, bg_width - face_width)
y = random.randint(0, bg_height - face_height)
new_img[y:y + face_height, x:x + face_width] = scaled_face
# 添加模糊 (模拟远距离模糊效果)
if scale_factor == 0.3:
blur_level = 3
elif scale_factor == 0.5:
blur_level = 3
else:
blur_level = 1
new_img = cv2.GaussianBlur(new_img, (blur_level, blur_level), 0)
new_img_name = f"enhanced_{scale_factor}_{blur_level}_{filename}"
cv2.imwrite(os.path.join(dst_path, new_img_name), new_img)
print(f"处理完成!图片保存在: {dst_path}")
当然,你也可以有其他的图像增强方式,比如旋转、曝光、翻转、裁剪等等,来提高模型的鲁棒性和泛化能力
3. 数据标注(LabelImg)
使用 LabelImg 工具对筛选出的图片进行人脸区域标注,生成 YOLO 格式的标签文件:
(1)安装 LabelImg:
🛠️ 方法一:从源码安装(推荐)
-
克隆仓库
git clone https://github.com/HumanSignal/labelImg.git或者访问 GitHub 仓库:https://github.com/HumanSignal/labelImg 直接下载 ZIP 安装
解压后,在命令控制行中打开labelImg再进行后续操作

-
安装依赖
pip install pyqt5 lxml -
编译资源文件
pyrcc5 -o libs/resources.py resources.qrc -
创建初始化文件
echo.> libs\__init__.py -
运行 LabelImg
python labelImg.py
🛠️ 方法二:使用 pip 安装
安装最新稳定版
pip install labelImg
运行
labelImg
不建议,程序会崩溃
(2)使用labelImg
在 labelImg-master\data\predefined_classes.txt 中修改标签


修改好标签后就可以打开labelImg进行标记


这里只是一些简单的操作,想要深入了解的,自行查找
4.数据集划分
将标注好的数据集划分为训练集(85%)和验证集(15%),符合 YOLO 训练要求的目录结构:
创建 YOLO 配置文件./dataset/mydata.yaml:
# peach
train: E:/python/FaceRecognition/FaceDetection/dataset/train
val: E:/python/FaceRecognition/FaceDetection/dataset/valid
# Classes
names:
0: face
# 这样数量要和你标记时使用的标签数量一致,否则后续会出错
将做好标记的图片划分为训练集和验证集
import os
import random
import shutil
src_path = 'sift_img/'
target_path = 'dataset/'
# 训练集比例
train_ratio = 0.85
# 验证集比例
val_ratio = 0.15
# 创建目标文件夹及其子文件夹
train_dir = os.path.join(target_path, 'train')
os.makedirs(train_dir, exist_ok=True)
val_dir = os.path.join(target_path, 'val')
os.makedirs(val_dir, exist_ok=True)
# 创建images和labels
for dir in [train_dir, val_dir]:
os.makedirs(os.path.join(dir, 'images'), exist_ok=True)
os.makedirs(os.path.join(dir, 'labels'), exist_ok=True)
# 支持的图像文件扩展名列表
image_extension = ('.jpg', '.jpeg', '.png')
# 获取所有文件列表
files_list = os.listdir(src_path)
img_list = [i for i in files_list if i.endswith(image_extension)]
# 随机打乱
random.shuffle(img_list)
# 计算训练集和验证集的大小
train_size = int(len(img_list) * train_ratio)
# val_size = len(img_list) - train_size
# 划分数据
for i, file in enumerate(img_list):
file_name = os.path.splitext(os.path.basename(file))[0]
if i < train_size:
save_path = train_dir
else:
save_path = val_dir
image_path = os.path.join(save_path, 'images')
label_path = os.path.join(save_path, 'labels')
shutil.copy(os.path.join(src_path, file), image_path) # 保留原始数据,避免操作失误导致数据丢失
shutil.copy(os.path.join(src_path, file_name + '.txt'), label_path)
print('处理完毕!')
四、YOLOv8 模型训练
使用 Ultralytics 库的 YOLOv8n 预训练模型进行微调,实现人脸检测
安装Ultralytics官方库 (我这使用的是 8.2.0 版本)
pip install ultralytics==8.1.46
from ultralytics import YOLO
# 当前目录下有yolov8n.pt会自动加载, 没有会自动下载
model = YOLO("yolov8n.pt")
if __name__ == "__main__":
# 使用模型
# data指定数据集配置文件的路径
# epochs指定训练的轮数
# workers指定用于数据加载的子进程数,0表示使用主进程
# mixup指定是否使用mixup数据增强,0.5表示50%的概率使用
# mosaic指定是否使用mosaic数据增强,0.5表示50%的概率使用
# device指定训练使用的设备,0表示使用第一个GPU
model.train(data="./dataset/mydata.yaml", epochs=100, workers=0, mixup=0.5, mosaic=0.5, device="cuda") # GPU训练
# model.train(data="./dataset/mydata.yaml", epochs=100, workers=0, mixup=0.5, mosaic=0.5, device="cpu") # 改用cpu训练
# 在验证集上评估模型性能
metrics = model.val()
# 将模型导出为 ONNX 格式
# 作用:ONNX 是一种开放格式,用于表示深度学习模型。它旨在提供一种标准格式,使得不同框架之间可以互相转换模型。
# opset指定ONNX的opset版本
# 返回导出是否成功
success = model.export(format="onnx", opset=12)
# 对指定图像进行预测
results = model("./dataset/valid/images/Elena_Bereznaya_0001.jpg") # 返回一个结果列表,每个元素是一个Prediction对象
for result in results:
# 获取边界框输出
boxes = result.boxes
# 获取分割掩码输出
masks = result.masks
# 获取姿态关键点输出
keypoints = result.keypoints
# 获取分类概率输出
probs = result.probs
# 显示预测结果到屏幕
result.show()

五、人脸检测功能测试
1. 图片检测
import cv2
from ultralytics import YOLO
# 加载YOLOv8模型
model = YOLO("runs/detect/train/weights/best.pt")
# 测试:图片检测
img = cv2.imread("Amber_Tamblyn_0002.jpg")
# 在图片运行YOLOv8推理
results = model(img)
# 在图片可视化推理结果
annotated_frame = results[0].plot()
# 显示标注后的图片
cv2.imshow("result", annotated_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

2. 视频流检测
使用爱给网(CC 协议,免费商用)下载的视频进行测试
import cv2
from ultralytics import YOLO
# 加载YOLOv8模型
model = YOLO("runs/detect/train/weights/best.pt")
# 测试:视频检测
cap = cv2.VideoCapture('video_example.mp4')
# 打开自己的摄像头
# cap = cv2.VideoCapture(0)
# 遍历视频帧
while cap.isOpened():
# 从视频中读取一帧
success, frame = cap.read()
if success:
# 在帧上运行YOLOv8推理
results = model(frame)
# 在帧上可视化推理结果
annotated_frame = results[0].plot()
# 显示标注后的帧
cv2.imshow("result", annotated_frame)
# 如果按下'Esc'键则退出循环
if cv2.waitKey(1) & 0xFF == 27:
break
else:
# 如果视频播放完毕,则退出循环
break
# 释放视频捕获对象并关闭显示窗口
cap.release()
cv2.destroyAllWindows()

本模块完成了从数据集准备到模型部署的完整人脸检测流程,基于 LFW 数据集和 YOLOv8 模型实现了高效的人脸区域定位,使用LFW数据集对亚洲人脸的识别效果不佳,但用来简单的检测还是可以的。
本项目及相关代码仅用于学习和研究目的,不保证其在任何场景下的准确性、完整性和可靠性。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)