ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

YOLOv8实战:从校园人脸识别到公路车辆检测的完整流程

YOLOv8实战:从校园人脸识别到公路车辆检测的完整流程 简介一套基于YOLOv8的智慧校园人脸识别与公路汽车检测综合项目资源面向目标检测和人脸识别方向的学习者适用于毕业设计、课程设计或工程实训。项目核心流程包括利用yolov8l-face模型检测并跟踪校园门口的人脸再借助dlib库中的resnet模型提取128维人脸特征与已有数据集比对后判断是否为校内学生绿色表示通过、红色表示未通过画面中央还会实时统计可识别人脸数量另一部分则提供基于YOLOv8的公路汽车检测脚本可用于车辆目标检测实验。资源包共34个文件压缩后约334MB主要包含Python源码、pt模型文件、dat特征数据、png样本图、mp4演示视频以及md说明文档解压即可对照运行。已有459人学习下载包内不仅提供完整代码和模型权重还配有测试视频与README文档能从模型加载、实时检测到结果可视化的完整链路给出清晰示例帮助读者掌握YOLOv8的检测与跟踪技巧理解dlib人脸特征匹配的实践方法同时为后续算法改进或二次开发提供良好起点。1. 一个课题两个场景YOLOv8如何同时支撑校园人脸识别与公路汽车检测校园门口一台人脸识别门禁机马路对面一台车辆道闸相机两套系统在学校里通常由一个团队维护底层的视觉算法却出奇一致目标检测。这个课题把两件表面无关的事拉到同一条技术线上——YOLOv8负责先框出人脸和车辆再分别接身份识别与车流计数的下游任务。它真正要解决的不是算法论文而是一套能跑通的数据、训练、部署链路环境怎么搭、数据怎么标、参数怎么调、坑怎么避。对正在做毕业设计或第一次接手校园视觉项目的从业者来说这是用一套框架吃透两类落地场景的最短路径。下面按我实际做这一路的顺序展开。2. 环境与数据准备在Ubuntu20.04搭建YOLOv8CPU版也能跑并用labelme转YOLO格式整个项目我习惯先搭环境再碰数据。这一步最花时间的往往不是命令而是版本之间的隐性冲突。Ubuntu20.04是很多学校服务器和工控机的主力系统LTS支持周期长教程覆盖面也广所以拿它举例最省事。如果你手头只有一台纯CPU机器也不用慌CPU版完全能跑通后续所有代码只是训练会很慢。我一般建议先用CPU版把数据流和脚本调试完再换到有显卡的机器上跑正式训练这样能省掉大量排队等待的时间。2.1 在Ubuntu20.04搭建YOLOv8环境CPU版与GTX1660Ti两种装法先用Anaconda创建独立环境这是我认为最重要的一步。很多人习惯直接往系统Python里pip install装到后面把环境弄乱重装系统才能解决。下面这组命令在Ubuntu20.04上可以直接执行conda create -n yolo python3.9 -y conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics pip install opencv-python第一行创建名为yolo的独立环境Python版本选3.9这是ultralytics支持很稳的版本第二行激活环境第三行从PyTorch官方CPU索引安装CPU版torch避免pip默认拉取体积巨大的CUDA版第四行安装ultralytics包它会把yolo命令行工具一起装好最后装opencv-python用于图片读取和画框。如果是纯CPU环境到这里就已经够了。如果你的机器是GTX1660Ti那就要换成CUDA版PyTorch。1660Ti虽然是老卡但跑YOLOv8训练完全没问题关键在于torch版本要匹配驱动。我习惯用CUDA 11.8的索引pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118装完后用一行命令验证环境是否识别GPUpython -c import torch, ultralytics; print(torch.__version__, torch.cuda.is_available())输出里torch.cuda.is_available()为True说明CUDA可用。注意先执行nvidia-smi确认驱动版本再决定装cu118还是cu121老驱动强行装新CUDA运行时会在import torch时报错。装完后跑一个最小推理验证整个链路yolo predict modelyolov8n.pt sourcebus.jpg这条命令会下载yolov8n.pt权重然后对bus.jpg执行目标检测并把标注结果保存到runs/detect/predict目录。第一次运行如果网络慢模型可能下载很久可以手动把yolov8n.pt下载好放到当前目录命令会优先读取本地文件。这个动作对应大家常说的yolov8安装和yolov8环境配置其实核心就这几步不需要自己编译源码。有个习惯值得养成用PyCharm打开项目时在Settings里把Project Interpreter指向conda环境下的python解释器路径一般是~/anaconda3/envs/yolo/bin/python。命令行里明明可以用yoloPyCharm里运行却报ModuleNotFoundError十有八九是解释器选错了。2.2 数据准备labelme标注转YOLO格式四个边界坑环境跑通后就进入整个项目最不能省略的环节准备数据集。人脸识别训练的是一个人脸检测模型车辆检测训练的是另一个车辆检测模型它们的data.yaml、标注、训练命令结构完全一样差别只在类别定义和图片内容。这个课题里我建议把两个数据集分开管理不要混在一个yaml里。标注工具我常用labelme因为它安装简单输出JSON格式方便做二次处理。标注时不要随手画矩形尽量用多边形把目标轮廓圈出来因为人脸和车辆经常有遮挡矩形框会把大量背景包进来影响模型收敛。标注完成后需要把labelme的JSON转成YOLO需要的txt格式。下面这段脚本我每次都会用到import json import os from PIL import Image def convert_labelme_to_yolo(json_file, img_dir, out_dir, class_map): with open(json_file, r, encodingutf-8) as f: data json.load(f) img_name data[imagePath] img Image.open(os.path.join(img_dir, img_name)) w, h img.size lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue pts shape[points] xs [p[0] for p in pts] ys [p[1] for p in pts] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # YOLO格式要求归一化后的中心点x, 中心点y, 框宽, 框高 cx ((x_min x_max) / 2) / w cy ((y_min y_max) / 2) / h bw (x_max - x_min) / w bh (y_max - y_min) / h lines.append(f{class_map[label]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_name os.path.splitext(os.path.basename(json_file))[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines))这段脚本的逻辑是读取labelme的JSON文件从imagePath拿到原图用PIL读取真实宽高然后遍历所有shape取每个多边形所有顶点的最小外接矩形作为检测框最后把坐标归一化后写入txt文件。关键点在于归一化必须除以原图宽高不能拿标注界面里显示的缩放尺寸否则导出后所有框都会错位。class_map是类别映射字典比如{face: 0}或{car: 0, truck: 1}它决定了txt每行开头的数字。处理数据集用于YOLOv8训练时还有四个容易踩的边界坑。第一txt文件名必须和图片文件名完全一致包括后缀前的名字不能改后缀名否则标签加载不上。第二data.yaml里的path建议写成绝对路径相对路径在换目录执行命令时经常找不到图片。第三训练集和验证集要按场景分层抽样不要把所有白天图片放训练集、所有夜晚图片放验证集否则会得到“白天效果很好、傍晚完全失灵”的模型。第四转换完成后要检查图片和标签数量是否一致ls images/train | wc -l ls labels/train | wc -l两个数字相等才说明标签没有丢失。data.yaml的写法是这样的path: /home/user/data/face_det train: images/train val: images/val names: 0: face这里names的类别顺序必须和txt里的class_id一致。如果训练人脸检测names就写face训练车辆检测就换成car、truck、bus这些实际类别。数据量不需要一开始就追求上万张我做过校园人脸检测几百张充分标注的图片就能训出可用的模型关键是质量。3. 人脸识别这半边先用YOLOv8把人脸框出来再用OpenCV完成身份比对这是整个项目里最容易跑偏的地方。“基于YOLOv8的人脸识别”听起来像是一个模型解决所有问题实际工程里检测和识别是两件事。YOLOv8只负责检测输出的是人脸框坐标判断“框里是谁”属于识别需要另外一套特征提取和比对逻辑。很多第一次做门禁项目的人把大量时间花在改进YOLOv8结构上却没有想清楚识别链路最后demo只能画框不能认人。3.1 检测和识别必须拆分YOLOv8输出的坐标框不是身份我拆分的理由很实际。人脸库会变每年有新生入学、老生毕业如果让YOLOv8直接做人脸分类训练类别写死在模型里新增人员就要重新训练整个模型。而检测加比对的架构里新增人员只需要往特征库里插入一条记录模型完全不用动。门禁场景的常见做法是YOLOv8检测人脸框裁剪出人脸区域再做姿态对齐喂给特征提取模型最后和注册库比对相似度。检测模型的训练数据标注也简单所有标注为face的框就够。识别模型的训练数据则是裁剪好的人脸图片按人员ID分文件夹存放。两套数据可以完全独立维护这也让模型迭代轻松很多。如果你只是做课程设计或毕业设计YOLOv8加OpenCV的组合完全能撑起完整流程。3.2 用opencv-contrib跑通人脸比对LBPH的训练与识别OpenCV自带的LBPH人脸识别模块非常轻量不需要GPU不需要额外下载大模型装一个opencv-contrib-python就能用。第一次做这个课题时我只装了opencv-python运行cv2.face.LBPHFaceRecognizer_create()直接报错后来才发现face模块在contrib包里。这个坑很典型先记住pip install opencv-contrib-pythonLBPH的原理不复杂把灰度图分成若干小块统计每块的局部二值模式直方图再把所有块的直方图拼起来当作人脸特征。识别时计算两个直方图的距离距离越小说明越相似。由于特征本身对光照敏感使用时要做好预处理。下面这段代码演示如何用YOLOv8裁剪的人脸图训练LBPH模型import cv2 import os import glob face_dir faces # 每个子目录是一个人目录名是工号或姓名 images, labels [], [] label_map {} for idx, person_dir in enumerate(sorted(os.listdir(face_dir))): label_map[idx] person_dir for img_path in glob.glob(os.path.join(face_dir, person_dir, *.jpg)): img cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) img cv2.resize(img, (112, 112)) images.append(img) labels.append(idx) recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.train(images, labels) recognizer.write(face_recognizer.yml)代码的逻辑是遍历faces目录下的每个子目录把每张人脸图转成灰度并缩放到112x112同时记录对应的标签索引最后用LBPH训练并保存模型文件。112x112是常见的人脸输入尺寸太小会丢掉特征太大会让直方图维度过高。每个人员建议至少采集20张不同角度的正脸图角度差的样本太少识别阶段会频繁误拒。识别阶段同样需要加载模型把YOLOv8检测到的人脸裁剪图缩放后送进predictimport cv2 recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.read(face_recognizer.yml) gray cv2.cvtColor(face_crop, cv2.COLOR_BGR2GRAY) gray cv2.resize(gray, (112, 112)) label, confidence recognizer.predict(gray) if confidence 50: print(f识别成功{label_map[label]}置信度{confidence:.2f}) else: print(未注册人员)这里threshold取50是我在校园门禁项目上的起点值。LBPH的置信度越小表示越相似50这个值偏严能降低误识别率但也会增加误拒率。实际部署时应该拿现场采集的测试集调这个阈值我习惯把阈值设在40到60之间然后结合业务诉求调整。如果是门禁考勤场景宁可误拒也不要误放。提示LBPH应对正脸还行一旦出现侧脸、口罩、帽子识别率会明显下降。校园门禁固定机位通常要求正脸刷门所以够用。3.3 树莓派、门禁机与PyCharm联动算力不足时的取舍人脸识别门禁机和我们自己搭的树莓派系统本质是同一套逻辑差别只在算力和摄像头位置。树莓派4B跑YOLOv8n做推理还能接受但把检测、裁剪、特征识别整条链路都压在树莓派上视频流帧率会明显下降。我建议把方案拆成两种一是树莓派只抓拍和显示结果检测识别放在局域网服务器二是树莓派本地跑onnxruntime加速的YOLOv8n每隔几帧检测一次不做全实时。如果硬件是STM32这类MCUYOLO基本跑不动人脸检测必须交给上位机处理。还有一个很常见的问题就是前面提到的PyCharm和Anaconda联动。明明在终端用conda activate yolo后一切正常打开PyCharm却import不到ultralytics和cv2。原因是PyCharm默认用了自己创建的新解释器没有指向Anaconda里那个yolo环境。解决方法很简单File - Settings - Project - Python Interpreter选Conda Environment指定Existing environment为yolo。这个问题和算法无关但每年都有人卡在这。4. 公路汽车检测这半边车辆数据集、freeze冻结训练与损失函数曲线怎么看公路车辆检测与人脸检测都是目标检测但难点取向完全不同。人脸框在画面里的尺寸相对稳定而公路监控视角下的车辆尺度变化极大远处车辆只有十几个像素近处货车能占半幅画面。夜间车灯衍射、雨天反光、树木遮挡都会让漏检率飙升。所以车辆检测模型的训练参数不能直接照搬人脸检测那套。4.1 车辆检测用YOLOv8n还是YOLOv8s预训练权重怎么选先决定模型规模。如果部署在普通服务器或边缘盒子上我习惯在两个尺度上各跑一版先跑yolov8n再跑yolov8s夜间样本上肉眼对比漏检率。n模型推理快但远处小车的召回明显不足s模型精度好一截对GTX1660Ti来说训练也不算吃力。如果相机安装在立杆高处视野开阔但车辆很小还可以试yolov8m不过显存要求会更高。数据集方面公路场景的常见做法是拿公开车辆数据集或COCO预训练权重做起点。yolov8s.pt本身已经在COCO上训练过COCO包含car、truck、bus这些类如果你的需求就是检测这些可以直接复用预训练权重的类别。如果还要区分大货车、小轿车、SUV就得用自己的标注数据重新微调。我建议先直接用COCO预训练模型跑一段真实监控视频看看哪些类别漏检严重再决定要不要自训。对自训的小数据集不要从头训练。从头训练yolov8s需要大量数据和更长的训练时间而基于COCO预训练权重微调几百张车辆图就能看到不错的效果。这就是为什么我始终强调第一次做YOLOv8训练自己的数据集一定要带model某个.pt预训练文件而不是不带模型参数硬训。4.2 车辆检测训练参数怎么定imgsz、freeze、batch与lr0车辆检测的显存瓶颈常常出现在输入分辨率上。监控画面里小目标多imgsz越大小车的特征保留越完整。下面是我在GTX1660Ti上常用的参数组合yolo train datavehicle.yaml modelyolov8s.pt epochs100 imgsz1280 batch8 freeze10 lr00.005这些参数按场景调整的空间很大先看一张表参数建议值说明imgsz960到1280远距离小目标需要高分辨率显存不够时优先降到640batch86GB显存下imgsz1280可能OOM降级到4或2freeze10小数据集冻结前10层加快训练并稳定损失lr00.005到0.01数据量小时用0.005更稳量大用0.01epochs100不用死等100轮看曲线提前停药freeze这个参数经常被忽略。它的作用是冻结模型前若干层的权重只训练后面部分。对于只有几百张车辆的私有数据集冻结前10层能显著降低过拟合风险训练速度也更快。如果数据集上了几千张可以缩小freeze层数或干脆不冻结让底层特征也参与适配。探测车灯眩光这类特殊场景时我建议不要冻结太多层因为COCO预训练特征里没有这种光照模式。显存不够时的退路是把batch降到4同时lr0降到0.002左右。batch变小会让梯度噪声变大损失曲线会抖动如果继续用0.01的学习率训练很容易震荡。这也是很多人在GTX1660Ti上跑yolov8翻车的原因只降batch不降lr结果loss曲线一路跳。训练完成后用best.pt做推理验证yolo predict modelruns/detect/train/weights/best.pt sourcehighway_test.jpg imgsz1280推理时imgsz要和训练保持一致否则模型看到的物体尺度变化精度会受影响。4.3 画损失函数曲线图怎么判断模型训练状态YOLOv8训练过程中会自动保存results.csv里面包含每个epoch的train和val损失以及precision、recall、mAP等指标。我每次训练完都会画一张损失函数曲线图判断训练是否正常。代码很简短import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns [c.strip() for c in df.columns] plt.figure(figsize(10, 5)) plt.plot(df[epoch], df[train/box_loss], labeltrain/box_loss) plt.plot(df[epoch], df[val/box_loss], labelval/box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.grid(True) plt.show()这段代码先读取results.csv再strip掉列名首尾空格因为不同版本YOLOv8的列名格式可能带空格。然后画出train和val的box_loss曲线。判断标准很简单train和val同时下降说明模型在学习train降但val不降或上涨说明过拟合需要增加数据增强或早停两者都平坦不动说明学习率太低或模型容量不够。也可以把metrics/mAP50(B)画在同一张图里用来确认精度和损失是否对应。车辆检测项目里我还会特别关注val_loss曲线的抖动幅度。如果是白天黑夜混合的训练集val_loss出现周期性波动是正常的因为验证集里不同时段的图片难度不一样。但如果波动大到mAP从0.8掉到0.3就要检查验证集是不是混入了标注质量很差的图片。5. 避坑指南人脸识别与汽车检测从训练到部署的4个高频翻车点从数据到部署这个课题里的问题更多出现在工程链路而不是算法本身。下面这4个坑我基本每次都会遇到按现象、原因、解决三步讲清楚。5.1 数据集训练正常启动但mAP始终为0标签根本没加载现象训练日志一切正常每个epoch的loss也在下降但precision和mAP始终是0明显不对劲。原因data.yaml里的path指向错误目录或images和labels的目录结构对不上。YOLOv8要求images/train和labels/train两个目录名严格对应如果你把标签放在labels/train下但图片在images/train下两者文件名不一致数据就静默丢失。解决先检查目录树确认标签文件与图片文件一一对应。然后用ultralytics自带的check_det_dataset做一次校验python -c from ultralytics.data.utils import check_det_dataset; check_det_dataset(data.yaml)如果输出里显示的类别数和图片数与你预期不符就看data.yaml的path是不是绝对路径。我遇到过最隐蔽的一次是把path写成了相对路径在项目根目录执行yolo命令没问题换到上级目录执行就全乱了。后来我统一规定data.yaml里path永远写绝对路径。5.2 训练损失函数曲线锯齿状vval_loss不降反升现象train/box_loss在下降但val/box_loss波动非常大甚至持续上升mAP也上不去。原因数据集划分不均衡。公路车辆数据如果白天图片全在训练集、夜晚图片全在验证集val_loss必然下不来。另一种可能是batch_size太小梯度噪声过大SGD优化器稳不住。解决划分数据集时按场景分层采样让白天、夜晚、雨天、逆光等场景在训练集和验证集中比例接近。batch_size至少给到8如果显存不足就同时降低imgsz而不是只调batch。还可以把lr0从0.01降到0.005观察损失曲线是否变得平滑。记住一点损失曲线震荡不等于模型坏要看趋势不抓单个epoch的尖峰。5.3 部署GPU上训练好的模型转成onnx到CPU或RK3588后精度掉点现象训练集上mAP不错导出onnx后在CPU上跑同一张测试图漏检明显变多框的位置也有偏移。原因部署时输入尺寸和训练时不统一。训练用了imgsz1280导出onnx时却用了默认640远处小目标直接丢失另外部署端的预处理如果直接用cv2.resize而不是用YOLOv8训练时的letterbox方式图像会被拉伸变形检测框自然不准。解决导出onnx时固定输入尺寸并保证和训练一致yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz1280推理代码里要复现YOLOv8的letterbox逻辑把图像等比缩放后填充到指定尺寸而不是简单拉伸。这条对RK3588这类板端芯片尤其重要很多部署教程直接讲模型转换却忽略了预处理一致性问题。5.4 人脸识别A刷脸把B放进来了误识别问题现象置信度阈值设了50测试时A的照片被识别成B门禁直接放行。原因LBPH的置信度受光照影响很大。YOLOv8裁剪出的人脸框如果直接缩放到112x112没有做双眼对齐同一个人的特征在不同角度下差异很大和库里另一个人的特征距离反而更近。解决裁剪人脸后先做关键点对齐让两只眼睛保持在同一水平线再进行缩放。阈值从50收紧到40让系统更严格。更稳妥的方案是加确认逻辑比如连续三帧识别为同一人才判定通过单帧误识别不会直接触发开门。门禁系统的原则是宁可误拒不可误放。6. 把两个模型串成智慧校园应用模型导出与推理联调的完整闭环人脸模型和车辆模型都训好后回到“智慧校园”这个最终目标要做的是把两个模型放进同一个推理服务里。不要在一个循环里串行调用两个模型的predict那样处理速度会明显变慢。常见做法是一个视频流进来后先按业务类型走不同分支人脸识别走检测加比对链路车辆检测走检测加计数链路或者用两个进程分别处理两路视频流再汇总结果。下面这个最小框架我在本地验证时经常用跑通了再搬到服务器from ultralytics import YOLO import cv2 face_model YOLO(face_best.pt) vehicle_model YOLO(vehicle_best.pt) def handle_frame(frame, task): if task face: results face_model(frame, conf0.6, imgsz640, verboseFalse) for r in results: for box in r.boxes.xyxy.cpu().numpy(): x1, y1, x2, y2 map(int, box) face_crop frame[y1:y2, x1:x2] # 裁剪后送LBPH或特征模型比对 elif task vehicle: results vehicle_model(frame, conf0.4, imgsz640, verboseFalse) # 记录车辆框中心点统计车流量代码里几个细节值得注意verboseFalse可以让推理时不刷屏适合视频流逐帧处理conf阈值对人脸设0.6对车辆设0.4因为车辆误检的代价比人脸误检低宁可多框一些再做业务过滤imgsz统一用640这是CPU推理和边缘设备上的常见折中选择。r.boxes.xyxy返回的是tensor需要先转numpy再取整否则画框时会报类型错误。等流程稳定后再把模型导出成onnx这是我做部署前必做的一步yolo export modelface_best.pt formatonnx imgsz640 yolo export modelvehicle_best.pt formatonnx imgsz640导出后CPU上可以用onnxruntime替换ultralytics推理内存占用和延迟都会改善如果要上TensorRT或板端芯片onnx也是统一的中间格式。我个人的习惯是导出onnx后一定先在本地对比几个典型场景的输出框确认和原始模型一致后再去部署这个习惯帮我省掉过很多次现场调试。整个课题做完你会发现最花时间的不是YOLOv8结构本身而是数据质量和部署一致性。先把这两件事做扎实再考虑轻量化改进也不迟。希望帮到你。本文还有配套的精品资源点击获取
返回列表