一、项目结构

在这里插入图片描述

二、模块概述

人脸检测是人脸识别系统的基础,负责从图像或视频中准确定位人脸区域。本模块基于 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

🛠️ 方法一:从源码安装(推荐)

  1. 克隆仓库

    git clone https://github.com/HumanSignal/labelImg.git
    

    或者访问 GitHub 仓库:https://github.com/HumanSignal/labelImg 直接下载 ZIP 安装

    解压后,在命令控制行中打开labelImg再进行后续操作

    在这里插入图片描述

  2. 安装依赖

    pip install pyqt5 lxml
    
  3. 编译资源文件

    pyrcc5 -o libs/resources.py resources.qrc
    
  4. 创建初始化文件

    echo.> libs\__init__.py
    
  5. 运行 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数据集对亚洲人脸的识别效果不佳,但用来简单的检测还是可以的。

人脸识别项目实战(二):人脸识别模块实现

本项目及相关代码仅用于学习和研究目的,不保证其在任何场景下的准确性、完整性和可靠性。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐