
简介基于YOLOv8的智慧校园人脸识别与公路汽车检测项目面向目标检测与人脸识别方向的学生适合用于毕业设计、课程设计或工程实训。项目以校园门口学生出入监控为场景使用YOLOv8模型完成人脸检测与跟踪再利用dlib模型提取128维特征判断是否为校内学生绿色放行、红色告警同时统计识别数量并提供车辆检测功能覆盖公路场景应用。压缩包共34个文件包括预训练模型、Python脚本、示例图片、演示视频、特征数据文件等大小约334MB目录结构清晰便于按模块对照学习。已有459人学习使用完整覆盖从模型加载、人脸识别到结果判断的实现流程可独立运行体验也可继续改进或集成到更大系统适合快速掌握目标检测与人脸识别的实战方法。1. 基于YOLOv8的智慧校园人脸识别与公路汽车检测一次跑通两套任务学校门口早晚高峰的人脸识别通行和公路监控里的车辆检测计数看上去是两种完全不沾边的任务但在这份基于YOLOv8的智慧校园人脸识别和公路汽车检测项目里它们被同一个 YOLOv8 推理框架串成了一个可直接运行的工程包。压缩包里既有 Face_Main.py 这套校园人脸识别主程序也有 Car_Track.py 这套公路车辆检测程序还附带 yolov8l-face.pt、yolov8l.pt、dlib 特征提取模型和中文字体解压后把依赖补齐就能跑起来。适合拿来做课程设计、毕业设计也适合想从零接触 YOLOv8 目标检测、目标跟踪和 dlib 人脸识别的进阶学习者。它解决的痛点很具体校园闸机怎么通过人脸特征判断校内人员公路视频怎么稳定跟踪并统计车辆而不是只停留在训练一个检测器的层面。2. 项目链路拆解YOLOv8 检测 目标跟踪 dlib 128 维特征比对为什么不是一套模型走到底2.1 两个模型分路人脸与车辆对检测器的要求完全不同YOLOv8 是目前目标检测领域最常用的框架之一它把 Anchor-Free、C2f 特征层和任务解耦头结合到一起推理速度比上一代更快训练和部署流程也简单。项目里分别放了 yolov8n.pt、yolov8l.pt、yolov8n-face.pt、yolov8l-face.pt 四个权重文件这不是随便堆的而是针对两个场景做了分工yolov8n.pt 和 yolov8l.pt 是 COCO 预训练的通用目标检测权重能识别人、车、狗等 80 类物体yolov8n-face.pt 和 yolov8l-face.pt 是人脸专用权重专门在 WIDER FACE 这类人脸数据集上训练过。校园门口的人脸框很小而且经常半遮挡如果用通用模型去框人脸会出现框偏大、框漂移的情况所以在 Face_Main.py 里优先用 yolov8l-face.pt 做人脸检测公路场景里的车是大目标用 yolov8l.pt 就够了。实际加载模型时常见写法是先用 ultralytics 库的 YOLO 类加载权重文件然后调用 predict 或 track 方法。项目中的 Car_Track.py 和 Face_Main.py 也是基于这套 API 写的只是不同脚本传入的模型路径不同。这里要特别注意YOLOv8 官方权重里没有 face 系列yolov8l-face.pt 这种是第三方在 YOLOv8 基础上用人脸数据集训练出来的所以下载资源时不要用官方的 yolov8l.pt 去替代否则人脸检测会退化成通用行人检测识别逻辑直接失效。from ultralytics import YOLO # 人脸场景必须使用人脸专用权重 face_model YOLO(model/yolov8l-face.pt) results face_model.predict(media/Student.mp4, conf0.45, saveTrue) # 公路场景使用 COCO 通用权重并过滤出车辆类别 vehicle_model YOLO(model/yolov8l.pt) results vehicle_model.predict(media/car.mp4, classes[2, 5, 7], conf0.30)这段代码的逻辑很直接先加载两个不同的模型分别处理人脸视频和车辆视频。conf参数控制置信度阈值高于阈值的检测框才会保留。classes[2, 5, 7]是 COCO 数据集中 car、bus、truck 三个类别的编号用来把检测结果过滤到只保留车辆避免把行人、骑自行车的人也算成车。如果你在项目里看到 Car_Track.py 的检测框包住了行人多半就是没有做类别过滤后面避坑章节会再展开。2.2 Face_Main.py 的识别流程track 之后才轮到 dlibFace_Main.py 的完整识别流程可以拆成四步。第一步用 yolov8l-face.pt 在视频帧上检测人脸框第二步用 YOLOv8 内置的 track 能力对检测框做跨帧跟踪给每个人脸分配一个稳定的 track id第三步对跟踪到的人脸区域调用 dlib 的 shape_predictor_68_face_landmarks.dat 提取 68 个关键点再用 dlib_face_recognition_resnet_model_v1.dat 计算 128 维人脸特征向量第四步把这 128 维向量和 dataset 里的已知学生特征做欧氏距离比较距离小于阈值就判定为校内学生框变绿色否则是外来人员框变红色。这里最容易混淆的是「检测」和「跟踪」的分工。YOLOv8 本身是单帧检测器它不知道当前画面里的人脸和上一帧是不是同一个人。track 技术的作用就是给检测框排队通过相似度和运动信息把同一张脸在前后帧里串起来。项目摘要里强调“通过该模型中的 track 技术实现检测出的人脸进行自动跟踪”实际用到的就是 ultralytics 里的 model.track()它会自动给每个目标分配box.id。后续 dlib 特征提取只针对跟踪成功的人脸做而不是每一帧对全画面做这样能减少重复计算也能让识别结果更稳定。import cv2 import numpy as np import dlib from ultralytics import YOLO # 初始化模型 face_model YOLO(model/yolov8l-face.pt) sp dlib.shape_predictor(model/shape_predictor_68_face_landmarks.dat) facerec dlib.face_recognition_model_v1(model/dlib_face_recognition_resnet_model_v1.dat) cap cv2.VideoCapture(media/Student.mp4) while cap.isOpened(): ret, frame cap.read() if not ret: break # 1. YOLOv8 检测人脸 results face_model.track(frame, persistTrue, conf0.45) if results[0].boxes is not None: boxes results[0].boxes.xyxy.cpu().numpy() ids results[0].boxes.id.cpu().numpy() if results[0].boxes.id is not None else None for i, box in enumerate(boxes): x1, y1, x2, y2 map(int, box) face_crop frame[y1:y2, x1:x2] if face_crop.size 0: continue # 2. dlib 关键点与 128 维特征 dets dlib.get_frontal_face_detector()(face_crop, 1) if len(dets) 0: continue shape sp(face_crop, dets[0]) descriptor np.array(facerec.compute_face_descriptor(face_crop, shape)) # 3. 与预存特征比较distance 0.5 认为是校内学生 # distance compare_with_dataset(descriptor) # 绿色或红色框这里省略这段代码演示了主循环的骨架。persistTrue是 track 的关键参数意思是让跟踪器保留上一帧的目标状态否则每次调用 track 都等于重新检测无法维持同一目标的稳定 id。conf设 0.45 是我在校园监控场景里常用的值太低会有大量误检框太高又会漏掉远距离小脸。face_crop是当前人脸区域dlib 在这个小图上做关键点提取比全图提取快很多。项目里预存的 128 维特征放在 dataset 中你可以理解为是一个“注册库”每位学生用一张正脸照片注册程序运行时会逐帧拿现场人脸去库里查找最接近的向量。2.3 Car_Track.py 的车辆检测track id 就是计数的钥匙公路汽车检测相对人脸识别要简单一些难点不在识别而在计数。如果只做单帧检测同一辆车在视频里连续出现几十帧计数器就会算几十次数据完全失真。Car_Track.py 的做法是利用 YOLOv8 的跟踪模式让每辆车在离开画面之前保持同一个 track id计数时按 id 去重。这样一辆车从画面右侧驶入左侧不管中间被其它车遮挡只要跟踪器没有丢最后就只算一次。from ultralytics import YOLO model YOLO(model/yolov8l.pt) results model.track(media/car.mp4, persistTrue, classes[2, 5, 7], conf0.30, iou0.50, saveTrue) for r in results: if r.boxes is None or r.boxes.id is None: continue boxes r.boxes.xyxy.cpu().numpy() clss r.boxes.cls.cpu().numpy() ids r.boxes.id.cpu().numpy() for box, cls, track_id in zip(boxes, clss, ids): print(ftrack_id{int(track_id)}, class{int(cls)}, box{box})iou0.50是 NMS 的 IoU 阈值值越大越容易保留重叠的检测框值越小越容易合并相邻框。车辆检测场景里 0.5 属于中间值能避免道路上的两辆并排车被误合并成一辆。classes过滤同样重要公路视频里出现行人和自行车很正常如果不过滤最后的计数结果会包含非机动车报告就没法看了。从整个链路来看项目的技术选型是合理的人脸检测要求模型对密集小目标敏感所以用 face 专用权重车辆检测要求类别过滤和稳定跟踪所以用通用权重加 track id。dlib 的 128 维特征向量可以做到几十毫秒级比对对校园门口这种人数不多的场景完全够用不需要上大型人脸识别服务。3. 环境配置与第一次运行从压缩包到 UI 窗口出现3.1 安装依赖ultralytics、dlib、opencv 的版本坑这份资源里没有 environment.yml 或固定 requirements.txt 的完整内容从 README.md 和文件结构看核心依赖主要是 ultralytics、opencv-python、dlib、numpy、torch。如果你在 Ubuntu 20.04 上搭建 YOLOv8 环境且只有 CPU 版本最需要注意的是 torch 和 torchvision 的版本匹配以及 dlib 编译依赖。常见做法是先装好 cmake 和 gcc再装 dlib否则会报CMake was not found或Failed to build wheel for dlib。# Ubuntu 20.04 CPU 环境 sudo apt update sudo apt install -y cmake build-essential python3-pip pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics8.1.34 opencv-python dlib numpyWindows 用户如果遇到 dlib 编译失败需要先安装 Visual Studio Build Tools并且勾选 C 桌面开发工具。这里多说一句dlib 版本不要盲目追新19.24.x 对 Python 3.8 到 3.10 的支持比较稳定我之前在 Python 3.11 上装 dlib 翻过车编译报一堆语法错误后来退回 Python 3.10 一次通过。3.2 文件清单里哪些权重必须保留压缩包里的 model 目录是项目的命脉少了任何一个都会导致运行时报文件不存在。按照项目正文model 文件夹下至少需要保留以下六个文件文件用途缺失后果yolov8n.pt通用轻量检测权重可用于重训训练车辆模型时无法加载预训练yolov8l.ptCOCO 通用大模型用于车辆检测Car_Track.py 无法运行yolov8n-face.pt轻量人脸检测权重低配机器无法做人脸推理yolov8l-face.pt高精度人脸检测权重Face_Main.py 无法运行shape_predictor_68_face_landmarks.datdlib 人脸关键点模型无法提取 68 点特征dlib_face_recognition_resnet_model_v1.datdlib 人脸识别模型无法生成 128 维特征另外还有 SimHei.ttf 中文字体这个容易忽略。OpenCV 默认的 putText 画中文会乱码项目里用这个字体在识别结果上显示“校内学生”“校外人员”等中文标签如果路径不对程序会跑到绘制阶段才报错而且报错信息不一定是指字体很莫名。第一次运行前把 SimHei.ttf 放到和主脚本同一个目录或者直接把项目里原有的相对路径保持住。3.3 修改 Face_Main.py 的输入源和参数拿到资源后的第一个目标不是理解代码而是让识别窗口弹出来。Face_Main.py 默认可能是读取视频文件也可能读摄像头这取决于 README 里的说明。我一般会先在代码开头找到视频读取那一行把它固定改成media/Student.mp4确认数据来源可控。import cv2 # 把视频源改成项目自带的学生视频便于第一次跑通 video_path media/Student.mp4 cap cv2.VideoCapture(video_path) # 如果要用摄像头改成 cap cv2.VideoCapture(0) conf_thres 0.45 # 人脸检测置信度阈值 iou_thres 0.50 # NMS IoU 阈值 match_distance 0.55 # dlib 特征欧氏距离阈值参数不是越大越好。conf_thres调到 0.6 以上人脸识别框会明显变少远距离的同学直接被忽略conf_thres调到 0.2 以下墙上的人像海报也会被识别成人脸。match_distance决定了判断“校内学生”的松紧程度阈值越小越严格0.55 是我按项目里 rec-face 目录下这些登记照测试过的经验值如果发现认识的人也变成红色可以适当放宽到 0.65但要注意误识率也会上升。第一次运行时先不要改 dlib 部分只改视频路径等窗口正常显示检测框后再逐步调参。3.4 运行 Car_Track.py 与识别阈值调整车辆检测脚本的运行方式类似但更推荐在命令行里通过参数控制方便反复测试。假设项目里 Car_Track.py 已经支持命令行解析可以这样跑python Car_Track.py --video media/car.mp4 --weight model/yolov8l.pt --conf 0.30 --iou 0.50如果脚本不支持命令行参数就直接改文件里的默认值。车辆检测的conf阈值推荐 0.25 到 0.35太高的代价是漏检远处的小车太低的代价是把路牌阴影误检成车。公路场景光照变化比校园门口大建议先跑一遍 car.mp4观察结果目录 result 下生成的视频重点看弯道和树荫处的检测框是否稳定再决定阈值方向。运行结束后项目会在 result 目录里输出带框的视频。这里有一个判断标准如果同一辆车在连续帧中 track id 频繁变化比如从 12 变成 45说明跟踪断开需要降低 conf 或调整 iou。如果 id 稳定但计数重复说明去重逻辑没生效要去检查 Car_Track.py 里是否用了集合存储已统计的 id。第一次跑通不需要追求完美能看到绿色或红色框在视频上跟着目标走就说明环境配置和权重文件都是完整的。4. 训练自己的数据集把校园名单和公路车辆接进 YOLOv84.1 数据准备视频抽帧、标注与 YOLO 格式转换项目自带的 rec-face 是登记照model 里的权重是现成的但如果想把某个班级的学生或者某种特定车辆识别得更准就得训练自己的数据集。第一步是收集图像。如果你有监控视频不要直接把视频扔给 YOLO 训练要先按间隔抽帧避免相邻帧高度相似影响训练集的多样性。import cv2 import os os.makedirs(images, exist_okTrue) cap cv2.VideoCapture(media/car.mp4) frame_id 0 saved 0 while True: ret, frame cap.read() if not ret: break # 每 10 帧抽 1 帧车辆高速运动时可以每 5 帧抽 1 帧 if frame_id % 10 0: cv2.imwrite(fimages/frame_{frame_id:06d}.jpg, frame) saved 1 frame_id 1 cap.release() print(f保存了 {saved} 张图片)抽帧之后需要用 labelme 或 LabelImg 手动标注。labelme 标注保存的是 JSON 格式YOLO 训练需要的是每个图片对应一个同名 txt 文件每行格式为类别序号 x_center y_center width height坐标都归一化到 0~1。我习惯在标注完成后写一段转换脚本而不是手工改文件因为几十张图手改还能忍几百张图手改会崩溃。import json import os import glob # 假设 labelme 生成的 JSON 都在 json_dir 下 json_dir labelme_json txt_dir yolo_labels os.makedirs(txt_dir, exist_okTrue) class_map {person: 0, car: 1, truck: 2, bus: 3} for json_path in glob.glob(os.path.join(json_dir, *.json)): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] txt_name os.path.splitext(os.path.basename(json_path))[0] .txt lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue points shape[points] x_min min(p[0] for p in points) x_max max(p[0] for p in points) y_min min(p[1] for p in points) y_max max(p[1] for p in points) x_center (x_min x_max) / 2 / img_w y_center (y_min y_max) / 2 / img_h width (x_max - x_min) / img_w height (y_max - y_min) / img_h lines.append(f{class_map[label]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) with open(os.path.join(txt_dir, txt_name), w, encodingutf-8) as f: f.write(\n.join(lines))转换脚本里最需要注意的是坐标归一化很多人漏掉除以宽高训练时报 shape mismatch。另外类别编号必须和 data.yaml 中一致不要随意调整顺序否则模型学到的类别和推理时的映射对不上。4.2 训练命令yolov8n.pt / yolov8l.pt 的合理超参数据准备好之后在项目根目录新建 dataset 文件夹把 images 和 yolo_labels 放进去再写一个 data.yaml。然后就可以开始训练了。项目自带的 yolov8n.pt 和 yolov8l.pt 都是很好的预训练起点不要从零初始化否则小数据集很难收敛。# data.yaml path: dataset train: images val: images names: 0: person 1: car 2: truck 3: bus# 用 yolov8n.pt 做轻量训练适合先验证数据没问题 yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0 optimizerAdamW lr00.001 # 用 yolov8l.pt 做高精度训练显存够时就选这个 yolo detect train datadata.yaml modelyolov8l.pt epochs150 imgsz640 batch8 device0 optimizerSGD patience30这里每个参数都有实际意义。epochs不是越大越好关键看损失曲线imgsz是输入尺寸640 是训练和推理的速度平衡点想提高小目标检测能力可以试 768但显存占用会明显上升batch受显存限制常见做法是先用 batch16 试显存不足就减半optimizer会影响收敛速度我自己的经验是小数据集用 AdamW 更容易快速调到低 loss数据集超过 5000 张时 SGD 会更稳。patience30表示 30 个 epoch 内验证集指标没有提升就提前停止避免过拟合。训练完成后会在 runs/detect/train 下生成 best.pt用它替换 project 里的对应权重文件即可。注意替换前备份原模型因为模型经过微调后特征分布会变化再检测原始视频的效果不一定更好。4.3 dlib 人脸特征库的更新方法YOLOv8 训练解决的是“人脸的框在哪里”dlib 解决的是“这张脸是谁”。如果学校换了新班级不需要重新训练 dlib 模型只需要把新学生的登记照加入特征库。项目正文中 rec-face 目录下的图片命名是“编号-姓名.png”比如 47-唐晶.png这就是一个现成的注册机制。你的任务是把这些图片转成 128 维特征向量并保存新版学生重新放一张正脸照即可。import dlib import numpy as np import glob import os sp dlib.shape_predictor(model/shape_predictor_68_face_landmarks.dat) facerec dlib.face_recognition_model_v1(model/dlib_face_recognition_resnet_model_v1.dat) detector dlib.get_frontal_face_detector() feature_list [] label_list [] for path in glob.glob(rec-face/*.png): img dlib.load_rgb_image(path) dets detector(img, 1) if len(dets) ! 1: print(f跳过 {path}, 检测到 {len(dets)} 张脸) continue shape sp(img, dets[0]) descriptor np.array(facerec.compute_face_descriptor(img, shape)) feature_list.append(descriptor) # 文件名去掉编号前缀保留姓名 label os.path.basename(path).split(-, 1)[1].replace(.png, ) label_list.append(label) np.save(face_features.npy, np.array(feature_list)) np.save(face_labels.npy, np.array(label_list))这段逻辑每次运行会把 rec-face 目录下的所有登记照重新生成特征库所以新增照片后重跑一次即可。len(dets) ! 1的检查很实用有些登记照是合影dlib 可能检测出多张脸直接跳过能避免错误特征入库。如果你的登记照角度偏侧dlib 正脸检测器可能检测不到脸这是 dlib 模型的固有限制解决办法是尽量使用证件照式正脸图。4.4 用 test.py 批量验证精度与速度项目里有 test.py这类脚本的作用通常是对指定视频或图片做一次性推理输出检测结果和时间。训练完新模型后不要直接上 UI先用 test.py 跑几个测试文件确认模型没有退化。python test.py --weights runs/detect/train/best.pt --source media/Student.mp4 --conf 0.45如果 test.py 支持打印每帧耗时你能直观看到模型推理速度。以 yolov8l-face.pt 为例在 GPU 上大约能跑到 30 到 50 FPS在 CPU 上可能只有 5 到 10 FPS。如果发现 FPS 太低先确认代码里是否用了model.predict(frame)而不是model(frame)两者逻辑相同但 predict 多了一层预处理封装在循环里会慢不少。这个细节我在低配机器上踩过换成直接调用模型对象后速度提升明显。5. 避坑指南人脸识别与车辆检测里最容易翻车的 5 个细节5.1 人脸框闪烁track 参数和 NMS 阈值的关系现象视频中同一个人脸上的人脸框忽大忽小并且每隔几帧就消失一次重新出现后 track id 已经变了导致 dlib 重复提取特征。原因模型对人脸的置信度本来就波动特别是侧脸和低头时分数会掉到 0.45 以下。如果conf设得太低会有大量低质量检测框参与 NMS框的位置上下跳如果conf设得太高又会出现丢帧。跟踪器persist参数没有保持 True 时每次调用 track 都重新初始化跟踪器会更加放大这种闪烁。解决把conf稳定在 0.4 到 0.5 之间iou设为 0.5并确保track(..., persistTrue)。如果还是闪烁对人脸框做一次轻度平滑例如保留前几帧的框坐标平均值再画框。我在校园场景里的经验是宁可漏掉单帧的人脸也不要让跟踪器频繁重建因为 dlib 特征提取是针对跟踪到的人脸一旦 id 断开识别结果就会跳变。5.2 dlib 特征比对误报欧氏距离阈值要分开设现象实际不在名单里的人视频里却显示绿色学生框而名单里的学生有时候识别成红色。原因dlib 的 128 维特征在同一校园场景下不同人之间的欧氏距离可能只有 0.5 左右特别是发型和眼镜相似时。项目里如果用单一全局阈值 0.5 判断所有陌生人必然有交叉。另一个隐性原因是登记照和现场摄像头分辨率差太多导致特征向量细节丢失。解决先用已有的 rec-face 目录计算库内两两距离统计出最大类内距离作为基准。具体做法是每张登记照生成特征向量后任意两张算欧氏距离如果最大距离已经超过 0.5阈值就要跟着放大。更稳妥的方式是不设全局阈值而是给每个学生生成均值向量后再为每个人都保存一个容忍半径比对时取最小距离除以该学生的半径得到归一化分数。5.3 车辆检测把行人当车类名过滤与输入尺寸现象Car_Track.py 输出的视频里路人被框成 car计数结果明显偏大。原因yolov8l.pt 是 COCO 全类别权重能同时检测行人和车辆。如果代码直接使用model.track(frame, persistTrue)没有指定 classes检测器会把所有 COCO 类别都留下再靠后续计数组件去区分是哪一类一旦组件没写类别判断人就被算成车。解决在 track 调用中强制加classes[2, 5, 7]。如果过滤后仍然发生误检比如把路牌误检成车则把imgsz从 640 提升到 736 再试一次大输入尺寸对小细节更友好。如果误检来自树影和光照则提高conf到 0.35并限制检测区域只保留道路区域可以用像素坐标裁剪掉画面两边的建筑区域。5.4 GPU 显存不足batch 与 imgsz 的妥协现象训练刚开始就报CUDA out of memory进程直接被杀没有生成任何权重。原因yolov8l 模型参数量本身就比 n 系列大训练时的梯度占据大量显存。如果 batch 设 16、imgsz 设 640常见 6G 显存会直接爆掉。很多教程默认给你 batch16这是坑因为你不知道对方显存多大。解决第一步把 batch 降到 4imgsz 降到 640如果还报错imgsz 降到 512。第二步开启ampTrue混合精度训练能省约三分之一显存。我一般会先用yolo detect train ... batch4 imgsz640 ampTrue做一次 20 epoch 的快速验证确认数据和流程没问题后再用大 batch 跑正式训练不要把正式训练直接压在第一次运行上。5.5 中文标签乱码SimHei.ttf 到底该放哪现象识别框上的中文名字全部显示成□□□□或者程序在画框时报奇怪的font type错误。原因OpenCV 内置的cv2.putText只能绘制 ASCII 字符对中文直接返回乱码。项目准备了 SimHei.ttf但没有把字体路径正确传给绘制函数。另一个常见原因是字体文件在项目根目录而脚本在 model 目录下执行相对路径解析不到。解决在绘制中文前先用cv2.imread确认字体文件存在然后通过 PIL 加载字体绘制到图像上不要用cv2.putText。简单做法是把字体转成图片后叠加到原帧。如果只是想让中文不报错可以把所有中文标签改成拼音或英文但毕业设计展示时会显得不够专业。把那句代码一次性封装好后续换任何模型都不再碰这个坑。import os from PIL import Image, ImageDraw, ImageFont font_path os.path.join(os.path.dirname(__file__), SimHei.ttf) font ImageFont.truetype(font_path, 24)6. 进阶用法用识别结果驱动门禁闸机和车辆计数上报6.1 把结果写成 JSON 行协议识别结果如果只停留在视频框上很难和校园闸机、车辆统计系统对接。我一般会在 Face_Main.py 的识别循环里增加一个结构化输出把每一帧的识别内容写成 JSON行协议便于实时消费。payload { time: timestamp, track_id: int(track_id), label: name, is_student: bool(is_student), distance: float(distance), box: [x1, y1, x2, y2] } with open(output.log, a) as f: f.write(json.dumps(payload, ensure_asciiFalse) \n)这段代码的价值在于下游门禁系统只要读这个日志就能根据track_id和is_student判断是否开闸不需要重新跑一次检测。6.2 车辆计数的稳定化用 track id 去重车辆计数的进阶技巧是用集合记录已经过线车的 id。常见做法是在画面中央画一条虚拟线当车的跟踪框中心跨过这条线且 id 不在集合中就计数加一。这样能避免同辆车在画面中反复被计。注意在 id 进入集合后不要立刻删除否则车辆在画面里绕一圈会被再计一次。6.3 一个验证技巧用 result 目录回放对比每次改完参数不要只看控制台输出要回放 result 目录下生成的视频。我会把同一段视频用不同阈值各跑一遍导出到不同子目录然后用双屏对比。这个方法在项目迭代里帮了我很多次尤其是调 dlib 匹配阈值时肉眼对比绿色框和红色框的数量比看数值更直观。我从这个项目里最大的教训是模型权重和跟踪参数都是“场景相关”的校园门口和公路监控需要完全不同的阈值不能一套参数走天下。从那以后我每次部署这类 YOLOv8 工程都强制自己先准备一段目标场景的真实视频跑通后再调参数避免在项目自带演示视频上表现完美、换到实际现场就翻车。希望这份拆解能让你少走弯路把这套资源真正用到自己的场景里。本文还有配套的精品资源点击获取