基于YOLOv8的智慧校园毕设:人脸识别与车辆检测双任务实战

发布时间:2026/9/15 5:31:44
基于YOLOv8的智慧校园毕设:人脸识别与车辆检测双任务实战
简介基于YOLOv8的智慧校园人脸识别与公路汽车检测项目面向计算机视觉、毕业设计及智能交通应用开发者提供一套完整可运行的源码与预训练模型。项目整合了人脸识别、车辆检测两大场景包含Face_Main.py、Car_Track.py等核心脚本并附有训练好的yolov8n-face.pt、yolov8l.pt等权重文件以及dlib人脸关键点模型与测试视频可快速复现识别、跟踪与统计流程。资源共40个文件涵盖Python源码、pt模型、xml配置、png示例图片、mp4演示视频等类型压缩包约334MB结构清晰便于按模块查阅。已有189人学习下载项目经本地编译运行评审分达95分以上难度适中适合毕业设计参考、课程实践或算法入门能够帮助使用者理解YOLOv8在目标检测与人脸识别中的实际部署方法。1. 基于 YOLOv8 的智慧校园项目先分清人脸识别和车辆检测的任务边界这个题目看起来是把两个模块塞进一个毕设但「人脸识别」和「公路车辆检测」在工程上是两种相反的任务一个求「不能漏人」一个求「不能误检」。基于 YOLOv8 做这个项目最可靠的落地路线是训两个检测权重——人脸分支只负责出框后面再接特征比对模型完成身份确认车辆分支直接用 YOLOv8 的输出画框、计数。适合正在做毕业设计、想跑通代码又能答上答辩问题的读者也适合需要快速搭一套校园门禁加卡口原型的工程师。先把这条双任务的链路想清楚后面的环境配置、训练、部署才不会绕路。2. YOLOv8 的结构选型C2f、解耦头与双任务模型怎么配2.1 从 C3 到 C2fYOLOv8 backbone 的改动到底解决了什么YOLOv8 的网络结构可以拆成三段理解backbone 负责特征提取neck 负责多尺度融合head 负责输出。backbone 里最核心的改动是 C2f 模块它替代了 YOLOv5 的 C3CSP Bottleneck with 3 convolutions。C2f 的做法是先把输入经过一个 1x1 卷积分成两支一支直连一支串过 n 个 Bottleneck然后把中间每一层的输出都 concat 到最终特征上。这里和 C3 的关键差异在于C3 只把最后一个 Bottleneck 的输出并入主路C2f 把每一层的输出都收进来再拼接相当于给梯度回传开了多条短路。对于人脸这种尺寸小、边缘特征密集的目标C2f 的多层拼接让浅层细节和深层语义能同时进到 neck对小目标召回有直接帮助。neck 部分仍然是 PAN-FPN自顶向下传语义、自底向上补定位。head 则换成了 anchor-free 的解耦头分类和回归分成两个分支输出不再依赖预设 anchor。anchor-free 对公路车辆检测的影响常被忽略。公路场景里车辆尺度跨度很大近处的车能占画面三分之一远处的车可能只有二三十个像素而且长宽比从轿车到卡车差了几倍。用 anchor 的方案需要为每种尺度和长宽比预先聚类聚不好就会拉低计数准确率。YOLOv8 的解耦头在每个特征图位置上直接预测「这个点离目标中心有多远」配合 DFLDistribution Focal Loss学习边界框的分布对尺度变化的鲁棒性比 anchor 类方案好一截。2.1.1 模型尺寸怎么选人脸和车辆不是同一个最优解YOLOv8 提供 n/s/m/l/x 五个尺寸参数量从 3.2M 到 68.2M。人脸检测的目标是别漏人门禁漏一次就形同虚设车辆检测的目标是别把树影、灯杆当车。常见做法是车辆检测用 YOLOv8s 或 YOLOv8m 就够人脸检测在固定机位场景用 YOLOv8n 或 YOLOv8s 出框把算力预算留给后面的特征提取模型。模型参数量COCO mAP50GTX1660Ti FP16 推理耗时适合任务YOLOv8n3.2M37.3约 3ms人脸检测、边缘设备YOLOv8s11.2M44.9约 6ms人脸检测、车辆检测YOLOv8m25.9M50.2约 12ms高密度车辆场景YOLOv8l43.7M52.9约 20ms离线分析YOLOv8x68.2M53.9约 35ms离线分析、精度优先别把 COCO 的 mAP 当成自己数据集的预期值那是 80 类平均值换到自己标注的数据集后数值会完全不同。我见过不少毕设把 YOLOv8n 在车辆数据上刷到 0.9 以上 mAP50但一到夜间或逆光就崩原因是训练数据根本没覆盖这些光照条件模型选型要跟着场景走不是越大越好。2.2 人脸识别为什么必须拆成「检测 特征比对」两段这是整个项目里最容易在答辩时被问住的地方。YOLOv8 是人脸检测器输出的是框和置信度框里这个人是谁YOLOv8 不负责。识别需要把一张脸映射成固定长度的特征向量再和库里注册的特征做距离计算。工程上有两种常见选型。一是 dlib 的 face_recognition 库内置 ResNet 特征提取器输出 128 维向量调用简单但遮挡和角度变化下精度一般。二是 InsightFaceArcFace输出 512 维向量在遮挡、侧脸上的鲁棒性好很多更符合智慧校园这种需要长期稳定使用的场景。ArcFace 的核心是在 softmax 里给类别间加角度间隔约束让同类特征的夹角比传统 softmax 更紧学出来的特征在阈值判断时区分度更高。两段式的数据流用代码表示就是下面这个顺序检测模型和特征模型各自独立加载from ultralytics import YOLO import insightface # 1. YOLOv8 只负责出人脸框 face_detector YOLO(runs/detect/face/weights/best.pt) boxes face_detector(frame, conf0.4, imgsz640) # 2. 按框裁剪并做仿射对齐112x112 # 3. InsightFace 提取 512 维特征 rec_model insightface.model_zoo.get_model(buffalo_l/recognition.onnx) emb rec_model.get_embedding(aligned_face) # 4. 与注册库做余弦相似度比对超过阈值判同一个人这段流程里检测和识别用两个模型意味着两套推理开销。在 GPU 上不是问题但如果要部署到香橙派这类边缘设备就得考虑把两个模型都导出成 ONNX 放进同一个推理进程或者用更轻的特征模型。2.3 公路车辆检测的类别设计多一类就多一分误检公路汽车检测的类别数一般控制在 4 到 6 类car、bus、truck、motorcycle、bicycle最多加一个 person。不要一开始就分 sedan、suv、van 这种细类标注一致性很难保证同一个车型在不同标注员眼里会落进不同类别训练出来的类别边界会互相污染。公开数据集里UA-DETRAC 以车辆检测为主适合做基准BDD100K 包含 car、bus、truck、motorcycle、bicycle还自带天气和时段标注最适合公路场景Cityscapes 侧重城市道路。做毕设的话直接从 BDD100K 裁剪出需要的类别转成 YOLO 格式比自己标几千张图高效得多。3. YOLOv8 环境配置与训练自己的数据集从安装到损失曲线判读3.1 Windows PyCharm 下 YOLOv8 环境搭建的最小可行组合环境配置是检索热度最高的环节pytorch、CUDA、显卡驱动的版本组合不对第一个 import 就报错。当前这个阶段最稳的组合是 Python 3.10 PyTorch 2.1 CUDA 11.8或者 Python 3.10 PyTorch 2.3 CUDA 12.1。GTX1660Ti 这类 6G 显存的老卡用 CUDA 11.8 更稳原因不是性能差异而是 CUDA 12.x 对较老的驱动要求更高驱动版本停在 5xx 以下就会出现「no kernel image is available」的运行时错误。用 conda 建独立虚拟环境是必做步骤不要直接装在 base 里。下面这套命令在 Windows 和 Ubuntu 20.04 上都验证过唯一前提是 N 卡驱动版本不低于 452.39CUDA 11.8 的最低要求。conda create -n yolov8 python3.10 -y conda activate yolov8 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics装完先别急着训练用最小推理验证 GPU 是否真的被 PyTorch 识别yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg device0输出里出现device:cuda且耗时正常说明 GPU 可用。常见坑是 torch 装成了 CPU 版在 PyTorch 官网命令里漏掉--index-url参数就会这样。验证命令是python -c import torch; print(torch.cuda.is_available())返回 True 才继续做数据集。注意如果torch.cuda.is_available()返回 False先检查pip list里 torch 的版本号是否带cu118不带就是装成 CPU 版了从安装源开始排查不要先怀疑显卡。3.1.1 ubuntu20.04 上多一个 opencv 兼容步骤Ubuntu 20.04 上装 ultralytics 会自动带上 opencv-python但系统自带的 libGL 库可能缺失报错libGL.so.1: cannot open shared object file。执行sudo apt install libgl1 libglib2.0-0 -y即可Windows 没有这个问题。另外 pip 建议先升级到最新否则解析 ultralytics 依赖链失败时会报莫名其妙的 ValueError看起来像网络问题实际上是 pip 版本太旧。3.2 把自己的数据集转成 YOLO 格式目录结构与 data.yaml人脸和车辆训练数据的格式完全一样每张图片对应一个同名 .txt 文件每行是class_id cx cy w h坐标是归一化到 0 到 1 的相对值cx、cy 是中心点w、h 是宽高。标注工具用 labelImg 或 X-AnyLabelingX-AnyLabeling 支持用 YOLO 模型预标注后人工修正标车辆能省一半时间。数据集目录结构必须严格按下图组织ultralytics 的 dataloader 只认这种结构datasets/ ├── vehicle/ │ ├── images/ │ │ ├── train/ # 训练图片 │ │ └── val/ # 验证图片 │ ├── labels/ │ │ ├── train/ # 对应的 yolo 标注 txt │ │ └── val/ │ └── data.yaml # 数据配置data.yaml 内容如下path是数据集根目录路径names的索引必须和标注文件里的 class_id 一一对应path: D:/projects/vehicle train: images/train val: images/val nc: 5 names: 0: car 1: bus 2: truck 3: motorcycle 4: bicycle训练集和验证集按 9:1 或 8:2 划分时要按整个视频片段或整个场景切不要把一个视频的连续帧同时分进 train 和 val。否则验证集会因为和训练集帧高度相似而虚高答辩时被质疑数据泄漏很难解释。3.3 训练自己的数据集训练命令与损失曲线判读数据集准备好之后最简训练命令是yolo detect train datavehicle/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 patience20 device0参数说明epochs100是总轮数上限配合patience20早停连续 20 轮验证集指标无改善就自动停止实际训练通常停在 60 到 80 轮imgsz640是输入尺寸车辆是大目标没必要上 1280人脸数据集可以试 800 或 960 提升小脸召回batch16在 6G 显存跑 YOLOv8s 的 640 分辨率下是上限爆显存就降到 8并同步把 epochs 加大。训练到一半想看趋势可以随时打开runs/detect/train/results.png那是最新的损失曲线。参数示例值作用与注意事项imgsz640车辆 640 即可人脸可试 800 提升小脸召回batch8~166G 显存跑 YOLOv8s 建议 816 是上限epochs80~120配合早停使用不必跑满patience20连续 20 轮验证指标无改善即停止lr00.01学习率曲线锯齿明显时降到 0.001 试跑 10 轮训练完成后重点看results.png里的三条线train/box_loss和val/box_loss训练损失在降、验证损失升到某个点开始反弹或震荡就是过拟合信号此时应回退到验证损失最低的 epochultralytics 会自动保存best.pt。metrics/precision和metrics/recall门禁场景重 recall卡口计数场景重 precision两个指标的平衡点靠后面调 conf 阈值完成。val/box_loss一直降不下去且伴随val/cls_loss反弹通常是类别不平衡比如 car 占 80% 样本而 motorcycle 只有 3%需要给少样本类别补数据或加强在线增强而不是盲目加 epochs。注意results.png里曲线剧烈锯齿通常说明 batch size 太小或学习率过高先试lr00.001跑 10 轮看趋势不要直接重训。4. 人脸识别与车辆检测的推理实现两段式流程与参数调校4.1 车辆检测推理代码conf、iou 与 classes 三个参数的实际意义模型训练完推理代码的核心是把 YOLOv8 的原始输出转成业务结果。用 ultralytics 的 Python 接口最短的车辆检测推理是这样的from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict( sourcetest_video.mp4, # 视频文件路径或摄像头设备号 0 conf0.45, # 置信度阈值低于此值的框丢弃 iou0.5, # NMS 的 IoU 阈值 imgsz640, # 推理尺寸与训练一致 classes[0, 1, 2], # 只输出 car/bus/truck device0, ) for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() # [x1, y1, x2, y2] 像素坐标 print(fclass{model.names[cls_id]} conf{conf:.2f} box{xyxy})conf0.45不是随便设的它只过滤单次检测的置信度。iou0.5是 NMS 时两个框重叠超过 50% 就合并。公路场景里追尾或并排时两个车的框 IoU 容易超过 0.5NMS 会把其中一个吞掉。如果遮挡场景漏检严重把iou调到 0.3 减少框被合并的概率反过来一辆车被框两遍说明太低回调到 0.6。classes[0,1,2]是业务过滤在只统计机动车的卡口场景排除摩托车和自行车比训练时多花一个类别的精力更干净。4.1.1 视频流的线程化处理先保帧率再谈精度处理视频流时不要在主循环里又读帧又推理。OpenCV 的VideoCapture.read()是阻塞的直接串行跑会导致画面掉帧。常见做法是开一个生产者线程读帧放进queue.Queue(maxsize8)主线程从队列取帧做推理队列积压超过 4 帧就丢弃旧帧。这样推理永远处理最新画面对安防场景来说丢帧比延迟更可接受因为目标从入画到出画通常有几十帧的窗口。4.2 人脸识别两段式实现YOLOv8 检测框 InsightFace 特征比对人脸识别的推理比纯检测多一个特征提取环节。用 face_recognition 库实现最简单但既然项目基于 YOLOv8更合理的人脸识别组合是YOLOv8 人脸检测模型负责出框InsightFace 负责特征检测头针对人脸充分训练特征质量也远好于 face_recognition 的 128 维向量。import cv2 import numpy as np from ultralytics import YOLO import insightface # 1. 加载人脸检测(YOLOv8) 与 特征提取(InsightFace) face_detector YOLO(runs/detect/face/weights/best.pt) feature_model insightface.model_zoo.get_model( buffalo_l/recognition.onnx, # 512 维特征模型 providers[CUDAExecutionProvider], ) # 2. 注册库姓名 - 512 维特征向量程序启动时加载一次 known_faces {} for name, img_path in {zhangsan: db/zhangsan.jpg, lisi: db/lisi.jpg}.items(): known_faces[name] feature_model.get_embedding(cv2.imread(img_path)) def recognize(face_img): emb feature_model.get_embedding(face_img) best_name, best_sim unknown, -1.0 for name, ref_emb in known_faces.items(): sim np.dot(emb, ref_emb) / (np.linalg.norm(emb) * np.linalg.norm(ref_emb)) if sim best_sim: best_sim, best_name sim, name return best_name, best_sim cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break faces face_detector(frame, conf0.5, imgsz640, device0) for r in faces: for box in r.boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) face_crop frame[y1:y2, x1:x2] if face_crop.size 0: continue face_resized cv2.resize(face_crop, (112, 112)) name, sim recognize(face_resized) if sim 0.45: # 余弦相似度阈值 cv2.putText(frame, f{name} {sim:.2f}, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) else: cv2.putText(frame, unknown, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)这段代码有两个容易踩的坑。一是get_embedding内部不做对齐假设输入已经是对齐后的人脸直接用检测框裁剪会有角度偏差导致特征质量下降。InsightFace 官方流程是先跑自带的 det 再跑 recognitionYOLOv8 的框直接拿过来用最好注册和识别都走同一套裁剪逻辑保持流程统一。二是相似度阈值 0.45 只是起点不同摄像头、光照下要重新标定方法在下一章说。注册库的加载也要注意不要每帧从磁盘读模板图程序启动时把所有已知特征加载进内存识别只做矩阵运算。模板数量到几千人时把所有参考特征堆成一个大矩阵一次性做矩阵乘法算全部相似度比 Python 循环快两个数量级。部署场景conf 阈值相似度阈值侧重点人脸门禁0.3~0.40.45~0.55高召回别漏人公路车辆计数0.5~0.6不适用高精确别误检夜间 / 低光照0.2~0.30.40~0.50容忍虚检靠相似度兜底提示InsightFace 的 buffalo_l 模型首次初始化会自动下载权重部署前先把权重文件缓存到本地避免现场初始化时卡在下载上。4.3 性能瓶颈分析与香橙派边缘部署人脸双模型在 GTX1660Ti 上的实测参考值YOLOv8s 人脸检测约 6msInsightFace buffalo_l 特征提取约 8ms一帧单脸总耗时 15ms 左右。实际卡顿几乎总是出现在视频解码上而不是模型推理。用摄像头时把CAP_PROP_BUFFERSIZE设为 1避免 OpenCV 内部缓冲堆积旧帧设定CAP_PROP_FPS后不做额外 sleep让推理速度自然限制帧率。边缘设备上香橙派 5 或 Jetson 系列的第一件事是导出 ONNX 并开启半精度。双模型从 GPU 换到 ARM 平台推理延迟可能从十几毫秒涨到三百毫秒以上此时换 YOLOv8n 检测加 MobileFaceNet 特征模型比任何代码层面的优化都有效。显存或内存有限时模型变小带来的收益是决定性的。5. 阈值标定、ONNX 导出与部署前的验证技巧5.1 用验证集的正负样本标定 conf 阈值很多人把 conf 阈值当成拍脑袋的值实际上它有客观标定方法。把 val 分割里所有检测框按置信度从高到低排序再和真实标注框算 IoUIoU 大于 0.5 的记为 TP否则记为 FP。取不同 conf 阈值统计 precision 和 recallyolo val modelbest.pt datavehicle/data.yaml conf0.1 iou0.5然后看输出的 PR 曲线数据。人脸场景高召回优先选误检还能接受的最高 recall 点车辆计数高精确优先宁可漏检也不把一个阴影当车阈值就右移。这个标定过程应该在训练完当天做因为不同数据集、不同光照下最优阈值差异很大。5.2 导出 ONNX 并用半精度做部署推理部署时脱离 ultralytics 的 Python 依赖常见做法是导出 ONNX 后用 onnxruntime 推理延迟比 PyTorch 推理低 30% 到 50%还可以在无 GPU 的机器上跑 CPU 推理yolo export modelbest.pt formatonnx opset12 simplifyTrue dynamicTrue导出后检查dynamicTrue的效果它允许 batch 维和宽高维动态变化。如果部署端固定输入尺寸把 dynamic 关掉能再压几个百分点的延迟。需要 TensorRT 加速就在目标设备上执行trtexec --onnxbest.onnx --saveEnginebest.engine --fp16TensorRT 版本必须和设备的 CUDA 版本匹配否则报 engine could not be loaded。5.3 一个值得复用的技巧为两类任务维护两份独立的阈值配置这个项目是双任务但很多实现把两个模型共用一个 conf这是最常踩的坑。正确做法是把人脸和车辆完全解耦人脸模型的 conf 定在 0.3 到 0.4因为侧脸和遮挡时置信度会掉到 0.4 以下阈值太严会漏人识别兜底靠相似度阈值车辆模型的 conf 定在 0.5 左右因为树影、水渍都可能产生 0.3 到 0.5 之间的虚检必须用更严的阈值压掉。把两组阈值写进一个 YAML 配置文件部署时只改配置不动代码。最后在真实场景录一段 5 分钟视频分别统计漏报数和误报数对照阈值调整方向用数据说话而不是答辩前临时调参。本文还有配套的精品资源点击获取