news 2026/9/16 6:26:18

基于YOLOv5的人脸检测与人脸计数复现指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv5的人脸检测与人脸计数复现指南

简介:资源是一套基于YOLOv5的人脸检测与人脸计数完整复现项目,适合深度学习初学者、目标检测方向研究者以及希望快速上手YOLO实战流程的开发者阅读使用。内容涵盖训练数据集、模型配置、测试脚本与详细过程记录,可帮助读者从数据预处理、模型训练、验证测试到结果可视化,完整理解并跑通人脸检测与计数任务。包体共1264个文件,以json标注、png/bmp/jpg图像、yaml模型配置、py训练脚本、log日志、pt权重等为主,压缩包大小约340.72MB。目前已有1455人学习。资源内附人脸训练数据集、yolov5-master工程、训练日志与权重文件,并配有《基于YOLO的人脸检测和人脸计数复现代码过程.docx》说明文档,方便对照复盘;同时提供测试图像与mp4视频,便于验证模型在不同场景下的检测效果。对于锚框调整、损失函数修改、检测结果后处理和人脸计数思路,也有实际代码与日志可供参考。

1. 复现前先问自己:这份YOLOv5人脸计数代码改了什么

很多人下载到“基于YOLO的人脸检测和人脸计数复现”资源包后,第一反应是解压、装环境、直接跑train.py,然后卡在“训练几分钟loss不降”上。实际上,这个包里并没有现成的权重文件,而是给了一堆000 (7).bmp这类测试图、一个events.out.tfevents.*训练日志,以及yolov5-master的完整框架。复现的关键不是跑通官方demo,而是把默认的COCO 80类检测改成单类人脸检测,同时把针对通用目标设计的锚框替换成人脸这种小目标适用的尺度,否则效果根本没法看。下面按数据准备、结构修改、训练调参、推理计数、工程落地五个阶段展开。

2. 数据准备与标注:把BMP图像变成YOLOv5能吃的txt标签

2.1 训练集目录结构:images与labels一一对应

YOLOv5读取数据时并不关心图片是jpg还是bmp,它要求每个标注文件与图片同属一个文件名、后缀不同:图片是000 (7).bmp,标注就是000 (7).txt,并且放在对应的images/labels/目录下。典型的目录组织方式如下:

data/ ├── images/ │ ├── train/ │ │ ├── 000 (7).bmp │ │ └── ... │ └── val/ │ └── ... ├── labels/ │ ├── train/ │ │ ├── 000 (7).txt │ │ └── ... │ └── val/ │ └── ...

train.py只认识 images 路径,会按后缀自动去 labels 目录找同名txt。最容易犯的错是把标注文件命名为000 (7).txt.txt,或者train和val的图片混放。检查方式很简单:用下面命令统计没有标注的图片数。

for f in data/images/train/*.bmp; do name=$(basename "$f" .bmp) [ ! -f "data/labels/train/${name}.txt" ] && echo "$name" done

这个循环的作用是遍历train目录下所有bmp,取出不带扩展名的文件名,再检查labels目录里是否存在同名txt,没有就打印出来。如果有输出,说明有遗漏标注,YOLOv5的训练会把这些图当作背景图,导致模型被喂入大量负样本,最终表现为“什么都检不出来”或“对所有区域都输出低置信度框”。

2.2 无标注怎么办:用dlib或MTCNN生成初始框

资源包里只给了原始bmp图片,并没有配套的标签。常见做法是先跑一遍现成的人脸检测器生成粗框,再人工修正。以dlib为例,dlib.get_frontal_face_detector()虽然只有HOG+线性分类器,但对正脸、光线正常的照片效果足够,适合偷懒做初稿。

import dlib, cv2, os, glob detector = dlib.get_frontal_face_detector() def bmp_to_yolo(img_path, out_path): img = cv2.imread(img_path) h, w = img.shape[:2] faces = detector(img, 1) if len(faces) == 0: return with open(out_path, 'w') as f: for face in faces: x, y, r, b = face.left(), face.top(), face.right(), face.bottom() # 越界保护,防止坐标超出图像范围 x, y = max(x, 0), max(y, 0) r, b = min(r, w), min(b, h) cx = (x + r) / 2 / w cy = (y + b) / 2 / h fw = (r - x) / w fh = (b - y) / h f.write(f"0 {cx:.6f} {cy:.6f} {fw:.6f} {fh:.6f}\n") for bmp in glob.glob("data/images/train/*.bmp"): base = os.path.splitext(os.path.basename(bmp))[0] bmp_to_yolo(bmp, f"data/labels/train/{base}.txt")

这段代码把dlib返回的人脸框坐标从像素值转成YOLO要求的归一化中心点坐标和宽高:cx = (x+r)/2/wfw = (r-x)/w,所有值都在0到1之间。原始人脸框如果越界会被max/min裁掉,避免训练时边界框为负或超过1。detector(img, 1)中第二个参数表示上采样次数,值越大越容易检出小人脸,但速度也成倍增加。

提示:dlib生成的是矩形框,有时会把脖子、肩膀框进去,而YOLOv5训练时根据正样本坐标回归,并不会把矩形中的背景区域当成有效特征。所以只要矩形中心点落在人脸主体内,最终模型也能学到近似矩形框。

2.3 数据划分:按人员分组比随机划分更合理

训练集和验证集如果随机打散,同一个人不同角度的图片会同时进入左右两边,验证结果虚高。对人脸计数项目,我一般先按文件名前缀或文件夹把人分组,再按80/20比例划分。

import os, random, shutil from collections import defaultdict imgs = glob.glob("cut_faces_raw/*.bmp") # 替换成你的原图目录 group = defaultdict(list) for p in imgs: key = os.path.basename(p).split('_')[0] # 按前缀分人 group[key].append(p) for g, paths in group.items(): random.shuffle(paths) sp = int(len(paths) * 0.8) for p in paths[:sp]: shutil.copy(p, "data/images/train/") for p in paths[sp:]: shutil.copy(p, "data/images/val/")

这里的key = basename(p).split('_')[0]假设你的图片命名是“人名_序号.bmp”,如果不满足就需要手动改分组逻辑。划分的目的是防止同一个人重复出现在训练和验证集,否则模型其实只是记住了这张脸,泛化性测试就没了意义。数据准备好后,下一步是改YOLOv5的网络配置。

3. 改网络结构与人脸训练参数:从yolov5s.yaml到face.yaml

3.1 nc=1与锚框重算:单类检测的形态变化

YOLOv5的检测头输出通道数是3 * (5 + nc),3表示每个特征层预设的3个锚框,5是坐标四值加一个objectness,nc是类别数。COCO的nc=80,所以yolov5s.yaml里把nc改成1后,模型参数量会明显下降,但更重要的是锚框要变。

默认锚框是COCO统计出来的:

anchors: - [10,13, 16,30, 33,23] - [30,61, 62,45, 59,119] - [116,90, 156,198, 373,326]

第一行最小的10x13对于人脸来说还是太大。人脸在640x640输入下,常见宽度只有20~60像素,长宽比接近1:1。所以直接把anchors换成更密集的小框:

anchors: - [5,5, 8,9, 15,15] - [21,21, 30,30, 46,46] - [65,65, 95,95, 140,140]

这里第一行对应80x80的浅层特征图,负责捕捉20像素以下的人脸;第二行对应40x40中层;第三行对应20x20深层,负责大脸。锚框的作用是给回归提供先验,所以不必和真实框完全一致,只要数量级对即可。如果你懒得手算,YOLOv5在训练时会启用autoanchor重新聚类,命令加--noautoanchor可以关闭,但建议先让它自己算一轮,然后看runs/train/exp/anchors.png里的聚类结果再调整。

3.2 数据配置face.yaml:路径、类别和超参

data/下新建face.yaml

train: data/images/train val: data/images/val nc: 1 names: ['face']

这是最精简版。如果服务器内存充足,可以在训练命令中加--cache让图片全部缓存进内存,减少磁盘IO等待。更多超参数不写在这个文件里,而是放在data/hyps/hyp.scratch-low.yaml,训练时用--hyp指定。对人脸这类单类、小目标任务,我通常调大hsv_hhsv_s来增强肤色变化:

hsv_h: 0.015 # 色调增强幅度 hsv_s: 0.7 # 饱和度增强,越大越不容易过拟合 fliplr: 0.5 # 水平翻转概率

这三个值控制的是颜色扰动和翻转。人脸检测对光照敏感,适度增大hsv_s能让模型学会在不同光线下找人脸;但hsv_h调太大会出现彩色人脸,反而破坏特征。所以0.015左右是经验值。

3.3 训练命令与关键参数表

启动训练的命令如下:

python train.py --img 640 --batch 16 --epochs 100 --data face.yaml \ --weights yolov5s.pt --hyp data/hyps/hyp.scratch-low.yaml --cache

--weights yolov5s.pt的意义是从COCO预训练权重开始迁移学习。虽然类别不同,但浅层卷积提取的纹理、边缘特征仍然有用,从零训练100轮很难收敛到同样精度。如果你是在AMD显卡上跑,PyTorch需要换成ROCm版本,命令本身不用变,只是依赖安装方式不同。

参数作用人脸任务推荐值
--img训练输入分辨率640,小脸多可上768
--batch批次大小16(8G显存用8)
--epochs训练轮数100起步,看loss决定
--weights初始权重或预训练权重yolov5s.pt
--hyp数据增强与损失超参hyp.scratch-low.yaml
--cache预加载图像到内存加快训练

注意batch和学习率的关系:YOLOv5默认学习率是按batch=64标定的,如果你改成16,建议把--lr0从默认的0.01调低到0.005左右;如果发现loss震荡,再继续减半。训练过程中观察命令行输出的boxobjcls三个损失。对人脸检测,cls损失会快速降到接近0,因为只有一个类;这时你就知道模型已经分清了“脸/非脸”,剩下就看boxobj是否还在波动。

3.4 用tensorboard监控训练:tfevents不是摆设

资源包里的events.out.tfevents.1624361803.kele.11844.0就是训练过程保存的日志文件。YOLOv5用PyTorch的torch.utils.tensorboard写tensorboard事件,查看方式:

tensorboard --logdir runs/train

浏览器打开http://localhost:6006,能看到train/box_losstrain/obj_lossval/mAP_0.5等曲线。注意事件文件名里的1624361803是Unix时间戳,对应2021年6月;kele是机器名。这个信息在判断训练日志归属、对齐代码版本时很有用——很多复现失败是因为拿另一个时间点训练的日志去对比当前权重。

4. 推理、评估与人脸计数:把检测结果变成人数

4.1 使用detect.py输出检测框和置信度

训练完成后,对单张测试图推理最简单的是用官方detect.py

python detect.py --source "../test" --weights runs/train/exp/weights/best.pt \ --conf-thres 0.5 --iou-thres 0.45 --save-txt --save-conf

--save-txt会把每个检测框写入runs/detect/exp/labels/000 (7).txt,内容格式是class conf x_center y_center w h--save-conf让置信度一并保存。--conf-thres表示置信度阈值。人脸检测建议设在0.4~0.6之间,不要用默认0.25;因为人脸误检率在低置信度区间很高,头发、手掌、水杯都容易触发。--iou-thres是NMS的IoU阈值,0.45是常见值,越小人脸重合越高时越容易只保留一个框,适合拥挤场景。

4.2 统计单张图片人脸数:读取txt逐行计数

一个快速计数脚本,直接复用detect.py生成的txt:

for f in runs/detect/exp/labels/*.txt; do echo "$(basename "$f") $(wc -l < "$f")" done

wc -l < "$f"统计行数,每行一个人脸框,行数就是该图的人脸数。如果用Python实时输出,可以这样:

import torch import cv2 model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt') img = cv2.imread('test/000 (7).bmp')[..., ::-1] results = model(img, size=640) boxes = results.pandas().xyxy[0] count = len(boxes[boxes['confidence'] > 0.5]) print('face count:', count)

results.pandas().xyxy[0]是DataFrame,包含xmin,ymin,xmax,ymax,confidence,class,name。这里我们用>0.5过滤低置信度框,与上面的--conf-thres语义一致。如果想要可视化,可以把坐标取整后传给cv2.rectangle画框。

4.3 视频或连续帧计数:先做帧间去重

如果统计视频,逐帧把框数加起来没有意义,同一个人会被重复计数。常见做法是用中心点最近邻做帧间匹配,给每个检测框一个临时ID。下面是一个简化版本:

import numpy as np last_centers = [] track_id = 0 max_id = 0 for frame in video_frames: centers = get_face_centers(frame) # 内部调模型,返回所有框中心点 if not last_centers: last_centers = centers continue for c in centers: if last_centers: dists = np.linalg.norm(np.array(last_centers) - c, axis=1) j = np.argmin(dists) if dists[j] < 30: # 像素阈值,按实际分辨率调整 track_id = j else: track_id += 1 max_id = max(max_id, track_id) last_centers = centers

这段逻辑很粗糙,只做了一帧的最近邻匹配,没有处理消失和重现,所以更适合“走廊人流量统计”这类短时场景。严谨的做法是接入DeepSORT或ByteTrack,但复现这个项目时能解释清楚“为什么不能直接累加框数”,已经比照抄代码的人强。真正的工程实现还需要卡尔曼滤波预测轨迹,这里不展开。

4.4 验证模型精度:val.py与结果指标

训练过程中跑验证集看mAP是常规操作,但很多人在人脸任务上纠结于mAP@0.5:0.95的数字偏低。实际上人脸检测常用mAP@0.5作为主要指标,因为密集人脸区域存在大量相近框,IoU稍微一高就被判负例,mAP@0.5:0.95数值天然难看。

python val.py --data face.yaml --weights runs/train/exp/weights/best.pt --task val

结束后在runs/val/exp/里能看到results.csv,竖向是类别,中间几列是precision、recall、mAP@0.5、mAP@0.5:0.95。评判一个模型是否可用,先看recall:人脸计数最怕漏检,recall低于0.85,后面提升confthres会损失大量真脸;再看precision:高误检会导致把背景人数算多。两个指标要结合你的计数场景——人流密度统计更看重recall,安防抓拍更看重precision。

5. 工程落地:实时摄像头计数与小脸加速技巧

5.1 摄像头实时人脸计数

把detect.py的--source改成0就能跑摄像头,但实际延迟很高。更快的方案是强制半精度推理,并降低输入尺寸:

python detect.py --source 0 --weights best.pt --img 416 --half --conf 0.5

输入降到416后速度能提升约40%,但人脸框的最小可检尺寸也会下降。如果摄像头安装位置较高、人脸普遍小于30像素,还是建议保留640,不要为了帧率牺牲小脸检出。

5.2 用切片推理处理超小小脸

摄像头如果是1080p,人脸区域可能只有15x15像素。YOLOv5在640输入下会把原图等比缩放,小人脸在特征图上只剩1~2个像素,难以产生有效响应。常见做法是对原图做切片推理:把图像分割成若干重叠块,每块独立推理,再拼接结果。Sahi库就是专门做这个的,命令类似:

sahi predict --source test/ --model_path best.pt --model_type yolov5 \ --slice_height 320 --slice_width 320 --overlap_height_ratio 0.2

切片尺寸设成320可以保留更多细节,重叠率20%是为了让边缘人脸至少有一半完整出现在某一块中。合并检测结果时注意去重——同一张脸可能被两个切片都检到,NMS会在最终合并时处理掉,但不同切片的置信度尺度略有差异,所以--conf可以压到0.3再合并。

5.3 监控loss稳定后提前停训

人脸单类任务收敛很快,不一定需要硬跑100轮。当val/obj_loss连续10个epoch不再下降,可以直接停掉,然后复制best.pt去推理。用脚本自动判断比较省事:

import csv with open('runs/train/exp/results.csv') as f: rows = list(csv.reader(f)) val_losses = [float(r[4]) for r in rows[1:]] # 假设第5列是val/obj_loss if len(val_losses) > 10 and val_losses[-1] >= val_losses[-11]: print("early stop: val/obj_loss no longer decreasing")

这是一个很基础的解析。实际应该取当前和10个epoch前的差值,而不是简单比较大小。重点是:人脸检测的loss曲线里,cls先降、obj随后降、box最后降,如果你看到box还在缓慢下降但val mAP已经不动,说明模型容量不够,加数据比加epoch管用。复现这套项目时,建议先拿yolov5s.pt做一次完整流程,确认每一个环节的输出都正常后,再换上你自己的场景数据,把--img调成你的摄像头分辨率,重新训练一轮——这才是这套代码真正开始干活的时候。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 6:25:57

网站代码需要注意什么问题图解步骤避坑指南

网站代码需要注意什么问题图解步骤避坑指南 找建站公司最怕什么?不是功能少,而是报价单上那些看不懂的名词,最后变成你口袋里的真金白银。很多老板拿着“企业官网”四个字去问价,从五千到五万都有,心里直打鼓:这差价到底差在哪?是不是被坑了?别急,今天咱们不聊虚的,直接拆解 网站代码需要注意什么问题…

作者头像 李华
网站建设 2026/9/16 6:25:49

小样本气动力预测:LSTM迁移学习实战指南

简介&#xff1a;本资源面向航空航天工程、智能控制及深度学习领域的研究者与高年级本科生&#xff0c;提供一套基于迁移学习与LSTM神经网络的气动力建模完整实现方案&#xff0c;旨在解决传统风洞试验与CFD仿真成本高、周期长的问题&#xff0c;支持飞行器气动力快速预测与参数…

作者头像 李华
网站建设 2026/9/16 6:25:03

GCC 14.1.0 源码构建指南:离线定制、静态依赖与多阶段编译

简介&#xff1a;gcc-14.1.0.tar.gz 是 GNU 编译器集合&#xff08;GCC&#xff09;最新稳定版的完整源代码发布包&#xff0c;面向 Linux/Unix 系统开发者、嵌入式工程师及编译器研究者&#xff0c;用于自主构建、定制或深度学习 C/C/Fortran 等多语言编译环境。资源共含 2000…

作者头像 李华
网站建设 2026/9/16 6:22:51

Node.js tls模块实战:双向认证加密通信与问题排查

最近在做内网服务端之间的加密通信时&#xff0c;我在 Node.js 的tls模块上踩了不少坑&#xff0c;也顺手把原本只停留在文档层面的 TLS 知识彻底过了一遍。坦白说&#xff0c;网上讲 Node 网络编程的资料很多&#xff0c;但专门把tls模块掰开揉碎讲清楚、还带问题排查的实战文…

作者头像 李华
网站建设 2026/9/16 6:22:27

淘宝爬虫SDK实战:TOP合规调用与动态签名逆向解析

简介&#xff1a;这是一套面向Python开发者与电商数据工程师的淘宝系平台自动化采集工具包&#xff0c;聚焦于淘宝开放平台&#xff08;TOP&#xff09;、淘宝、天猫及阿里巴巴网站的合规登录与结构化数据抓取&#xff0c;解决商品信息监控、竞品分析、价格动态追踪等实际业务需…

作者头像 李华
网站建设 2026/9/16 6:22:21

乳腺癌症图像分类实战:从数据集到模型训练全流程

简介&#xff1a;面向深度学习和医学影像分类任务&#xff0c;这份乳腺癌症图像分类数据集可直接用于二分类模型的训练与验证&#xff0c;适用于科研教学和辅助诊断模型搭建等场景。资源已按目录结构存放&#xff0c;同一类别放在同一文件夹内&#xff0c;并附有JSON类别映射文…

作者头像 李华