news 2026/10/15 20:58:47

基于YOLO的轨道矿车与人员检测:小数据集训练与部署实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLO的轨道矿车与人员检测:小数据集训练与部署实战

简介:这份资源是面向矿业智能化与计算机视觉方向的YOLO格式目标检测数据集,聚焦轨道场景下矿车与人员的识别任务,适合从事工业安全监测、深度学习目标检测的开发者与研究人员使用。压缩包共2000个文件,包含1045张jpg图像、954个txt标注文件及1个yaml配置文件,整体约206.69MB,标注类别为Normal与With People两类,可直接对接YOLO系列训练流程。数据集图像取自真实矿业轨道环境,覆盖矿车正常运行与人员干扰两类场景,标注框清晰,便于模型专注学习矿车与人员两种特定目标。目前已有118人学习下载。借助该数据集,读者可快速搭建训练与验证环境,完成模型训练、精度评估与场景适配,为矿业安全生产中的实时检测方案提供可靠的数据支撑与实验基础。

1. 轨道矿车与人员检测:近千张 YOLO 标注数据能解决什么

井下轨道运输最怕的场景不是设备故障,而是矿车运行轨迹上突然出现人。传统做法靠司机目视和调度喊话,一旦视线被弯道、粉尘或设备遮挡,留给反应的时间往往只有一两秒。这套 MineCarWithPeople 数据集就是冲着这个痛点来的:近一千张实拍轨道场景图像,按 YOLO 格式标注,只分Normal和With People两类,专门训练"轨道上有没有人"这个二分类检测任务。它适合做矿业安全监测的算法工程师、做工业视觉落地的团队,以及想拿真实场景练 YOLO 全流程的人。类别少不代表简单,恰恰因为只有两类,模型能把全部容量压到"人"和"矿车"这两个目标上,收敛快、误报可控,这是它比通用数据集更适合工业现场的地方。

2. 数据集结构与 YOLO 标注格式:先看懂再动手

拿到一个数据集,我第一件事不是急着跑训练,而是把目录结构和标注文件翻一遍。翻车最多的环节从来不是模型,而是数据本身对不上。这套数据按 YOLO 标准组织,data.yaml里写死了训练和验证路径,类别数nc: 2,类别名是Normal和With People。理解这套结构,后面换路径、改类别、接自己的训练脚本才不会抓瞎。

2.1 目录布局与 data.yaml 字段含义

标准 YOLO 数据集长这样,训练集和验证集各自带images和labels两个子目录:

MineCarWithPeople_yolo_data/ ├── data.yaml ├── train/ │ ├── images/ # 训练图像,jpg 格式 │ └── labels/ # 对应标注,txt 格式,与图像同名 └── valid/ ├── images/ # 验证图像 └── labels/ # 对应标注

data.yaml的内容就是摘要里给的那几行:

train: ../train/images val: ../valid/images nc: 2 names: - Normal - With People

这里有几个参数必须说清楚。train和val用的是相对路径,相对的是data.yaml所在目录,所以你把整个文件夹挪位置时,只要内部结构不变,路径就不用改;但如果你把data.yaml单独拎出来放到别处,这两个路径立刻失效,训练会直接报找不到图像。nc: 2是类别数量,它必须和names列表长度严格一致,多一个少一个都会在加载标签时报索引越界。names的顺序决定了标签文件里类别 id 的含义:id0对应Normal,id1对应With People,顺序写反了模型学到的就是反的,这个坑后面避坑章节还会细说。

提示:names里带空格的With People在 YAML 里是合法字符串,但如果你后续用某些脚本按空格切分类别名,会切出两个词,建议在代码里始终按列表索引取类别,不要按名字匹配。

2.2 标注文件长什么样:一行一个目标

YOLO 的标注是纯文本,每张图对应一个同名.txt,文件里每一行描述一个目标框,格式是:

<class_id> <x_center> <y_center> <width> <height>

五个字段全部归一化到 0 到 1 之间,x_center、y_center是框中心点相对图像宽高的比例,width、height是框宽高相对图像宽高的比例。举个例子,一张 1920×1080 的图里有个矿车,框的像素范围是左上角 (400, 300) 到右下角 (1000, 700),那么:

  • 框宽 = 1000 - 400 = 600,归一化 width = 600 / 1920 ≈ 0.3125
  • 框高 = 700 - 300 = 400,归一化 height = 400 / 1080 ≈ 0.3704
  • 中心 x = (400 + 1000) / 2 = 700,归一化 x_center = 700 / 1920 ≈ 0.3646
  • 中心 y = (300 + 700) / 2 = 500,归一化 y_center = 500 / 1080 ≈ 0.4630

写进 txt 就是0 0.3646 0.4630 0.3125 0.3704。理解这个换算,你才能自己写校验脚本,也才能在标注出错时判断到底是框画歪了还是归一化算错了。下面这段脚本我每次拿到新数据集都会先跑一遍,检查标签和图像是否一一对应、坐标是否越界:

import os from pathlib import Path def check_yolo_dataset(root): """检查 YOLO 数据集图像与标签的对应关系及坐标合法性""" for split in ["train", "valid"]: img_dir = Path(root) / split / "images" lbl_dir = Path(root) / split / "labels" imgs = {p.stem for p in img_dir.glob("*.jpg")} lbls = {p.stem for p in lbl_dir.glob("*.txt")} # 图像有但标签缺失,或标签有但图像缺失,都是问题 missing_lbl = imgs - lbls missing_img = lbls - imgs print(f"[{split}] 图像 {len(imgs)} 张, 标签 {len(lbls)} 个") if missing_lbl: print(f" 缺标签: {list(missing_lbl)[:5]}") if missing_img: print(f" 缺图像: {list(missing_img)[:5]}") # 逐行校验坐标范围 bad = 0 for lbl in lbl_dir.glob("*.txt"): for line in lbl.read_text().strip().splitlines(): parts = line.split() if len(parts) != 5: bad += 1 continue cls, x, y, w, h = parts vals = [float(x), float(y), float(w), float(h)] if any(v < 0 or v > 1 for v in vals): bad += 1 print(f" 坐标越界或格式错误行数: {bad}") check_yolo_dataset("MineCarWithPeople_yolo_data")

这段脚本做了三件事:比对图像和标签的文件名集合,找出单边缺失的样本;逐行读取标签,检查字段数是否为 5;检查四个坐标值是否落在 0 到 1 之间。任何一项报警,都说明数据在进入训练前就需要修,别指望模型能容忍脏标签。参数上,root指向数据集根目录,脚本默认图像后缀是.jpg,如果你的数据混了.png,把glob("*.jpg")改成同时匹配两种后缀即可。

2.3 两类标签的语义边界:Normal 到底指什么

这套数据只有两类,但Normal这个词有歧义。从任务描述看,它指的是"轨道矿车场景中无人员干扰"的正常状态,With People是"矿车周围出现人员"。这里有个容易忽略的点:如果一张图里既没有矿车也没有人,它算不算Normal?按二分类检测的常规做法,Normal类通常框的是矿车本体,With People框的是人,两类目标在空间上可能同时出现。你在训练前最好抽十几张图可视化一下标注框,确认每个类的框到底框在什么目标上,否则模型学出来的语义和你部署时想要的语义可能对不上。可视化用下面这段就够:

import cv2 from pathlib import Path def draw_labels(img_path, lbl_path, names): """把 YOLO 标签画到图上,用于人工核对标注语义""" img = cv2.imread(str(img_path)) h, w = img.shape[:2] for line in Path(lbl_path).read_text().strip().splitlines(): cls, x, y, bw, bh = map(float, line.split()) # 归一化坐标还原成像素坐标 x1 = int((x - bw / 2) * w) y1 = int((y - bh / 2) * h) x2 = int((x + bw / 2) * w) y2 = int((y + bh / 2) * h) color = (0, 255, 0) if int(cls) == 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, names[int(cls)], (x1, max(y1 - 5, 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite("check_vis.jpg", img) draw_labels("MineCarWithPeople_yolo_data/train/images/new_04_30.jpg", "MineCarWithPeople_yolo_data/train/labels/new_04_30.txt", ["Normal", "With People"])

draw_labels把归一化坐标反算回像素,按类别上色,Normal画绿框、With People画红框,输出一张check_vis.jpg。抽几张不同场景的图各跑一次,你就能判断标注质量:框是否贴紧目标、有没有漏标的人、Normal框的是矿车还是空轨道。这一步花十分钟,能省掉后面几小时的调参玄学。

3. 用 YOLOv8 跑通训练与验证:从 data.yaml 到指标

数据看懂了,接下来就是把它喂进模型。这套数据命名里带 yolo,就是给 YOLO 系列准备的,我用 YOLOv8 走一遍完整流程,因为它的命令行接口最省事,yolov8n.pt这种小模型在单卡上几十分钟就能出结果,适合先验证数据可用性。整条链路是:装环境、改配置、起训练、看指标、导出模型。

3.1 环境安装与目录准备

先建一个干净的虚拟环境,避免和系统里的包打架。ultralytics 是 YOLOv8 的官方库,一条命令装齐:

python -m venv yolo_env source yolo_env/bin/activate # Windows 用 yolo_env\Scripts\activate pip install ultralytics opencv-python

装完验证一下版本,yolo version能打印出版本号就说明环境通了。然后把数据集解压到一个固定位置,比如~/datasets/MineCarWithPeople_yolo_data,确认data.yaml里的train和val相对路径指向的train/images、valid/images真实存在。如果你把数据放在别处,最稳妥的做法是直接改data.yaml里的路径,而不是去改训练命令,因为路径解析以data.yaml为基准,改一处就够。

注意:valid这个目录名是这套数据用的,YOLOv8 默认也认val,两者都能识别,但data.yaml里写的是哪个就必须存在哪个,别自己重命名成test又不改配置。

3.2 训练命令与关键参数

YOLOv8 训练一行命令就能起,但参数得按数据规模调。近一千张图属于小数据集,轮数要给够,否则欠拟合:

yolo detect train \ data=MineCarWithPeople_yolo_data/data.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=16 \ patience=30 \ project=runs/minecar \ name=exp1

逐个说参数。data指向data.yaml,类别数和类别名都从那里读,不用在命令里重复。model=yolov8n.pt用 nano 版预训练权重,小数据集上 nano 往往比大模型更不容易过拟合,而且推理快,适合工业边缘设备。epochs=150是上限,配合patience=30做早停:连续 30 轮验证指标不涨就停,避免白跑。imgsz=640是输入分辨率,如果你的原图很大、远处的人很小,可以提到960或1280,代价是显存和耗时上升。batch=16按显存调,8G 显存跑 640 分辨率一般能到 16,爆显存就降到 8。project和name决定结果存到runs/minecar/exp1,每次实验换个name,方便对比。

训练过程中终端会打印每轮的 box_loss、cls_loss 和 mAP。小数据集上 loss 抖动是正常的,重点看mAP50和mAP50-95是否稳定上升。如果mAP50卡在很低的值不动,八成是标签或路径有问题,回到第 2 章的校验脚本查。

3.3 验证与指标解读

训练完,用验证集单独跑一次评估,确认指标不是训练集上的假象:

yolo detect val \ model=runs/minecar/exp1/weights/best.pt \ data=MineCarWithPeople_yolo_data/data.yaml \ imgsz=640

输出里几个指标要会看。mAP50是 IoU 阈值 0.5 下的平均精度,反映"框得差不多就算对"的水平;mAP50-95更严格,IoU 从 0.5 到 0.95 每隔 0.05 算一次再平均,反映框的精准度。工业检测里如果只是判断"有没有人",mAP50够用;如果要精确定位人员位置做联动,mAP50-95更值得盯。另外看每个类别的 P(精确率)和 R(召回率):安全场景下召回率比精确率更重要,漏检一个人比多报一次代价大得多,所以宁可让With People的 R 高一些,哪怕 P 低一点。如果With People召回明显偏低,说明这类样本太少或太难,需要补数据或调类别权重。

3.4 推理与导出部署格式

验证过关后,拿一张图跑推理,直观看看效果:

yolo detect predict \ model=runs/minecar/exp1/weights/best.pt \ source=MineCarWithPeople_yolo_data/valid/images \ conf=0.25 \ save=True

conf=0.25是置信度阈值,低于它的框不输出。安全场景可以调低到0.15提高召回,代价是误报变多,具体值要在现场数据上试。结果默认存到runs/detect/predict。要上边缘设备,把模型导出成 ONNX 或 TensorRT:

yolo export model=runs/minecar/exp1/weights/best.pt format=onnx imgsz=640 yolo export model=runs/minecar/exp1/weights/best.pt format=engine imgsz=640 half=True

ONNX 通用性好,TensorRT 的engine在 NVIDIA 设备上推理最快,half=True用 FP16 进一步提速,但精度会掉一点点,导出后务必用同一批图对比一下导出前后的检测结果,确认没掉太多。

4. 避坑与排查:标注、路径、过拟合的常见翻车

这套数据规模不大、类别又少,看起来简单,但小数据集该踩的坑一个不少。下面几条是我在类似项目里反复遇到的,按"现象 → 原因 → 解决"列出来,你对照排查能省不少时间。

现象一:训练一启动就报No labels found或nc不匹配。原因通常是data.yaml里的路径写错,或者标签目录名不是labels。YOLO 找标签是按图像路径把images替换成labels再找同名 txt,如果你把标签放在别的目录,它就找不到。解决:确认train/images和train/labels同级,且data.yaml的train指向的是images目录而不是根目录。

现象二:训练 loss 正常下降,但验证 mAP 一直很低。大概率是类别 id 和names顺序对不上。比如标注里With People用的是 id0,而data.yaml里0是Normal,模型学到的语义就反了,验证时按错误语义算指标自然低。解决:抽几张图用第 2 章的draw_labels可视化,确认框的颜色和类别名一致,不一致就统一改标注或改names顺序。

现象三:训练集 mAP 很高,验证集明显低一截。这是过拟合,近一千张图对检测任务来说偏少,尤其With People这类可能样本更少。解决:先用yolov8n而不是大模型,加数据增强(YOLOv8 默认开了 mosaic、翻转等),必要时冻结主干先训头部,或者补采With People场景的图。别一上来就堆 epochs,过拟合时训得越久验证越差。

现象四:推理时同一辆车被框出好几个重叠框。这是 NMS(非极大值抑制)没压干净,或者conf设太低。解决:推理时适当提高conf,或在predict里调iou参数控制 NMS 阈值,默认 0.7,重叠框多就降到 0.5 左右。工业场景里矿车目标大、人目标小,两类框的尺度差异大,NMS 阈值要兼顾,必要时分类别设。

现象五:换到自己的机器上路径全失效。因为data.yaml用的是相对路径,一旦你把data.yaml和数据分开存放就崩。解决:要么保持整个数据集目录结构不动,要么把data.yaml里的路径改成绝对路径。我一般倾向保持结构不动,绝对路径换机器又要改一遍。

提示:每次改完data.yaml或标注,先跑一遍第 2 章的校验脚本再起训练,比训练跑一半报错再回头查省事得多。

5. 小数据集的进阶技巧:把两类检测做到可上线

两类检测听起来简单,但要真上线,光跑通训练不够。近一千张图的小数据集,模型很容易在训练集上表现漂亮、到现场就拉胯。我一般会从三个方向压榨这套数据的价值:用交叉验证判断数据是否够用、用类别权重和阈值调优平衡漏检误检、用困难样本挖掘补数据。下面这套流程是我在工业检测项目里固定会走的。

先做 K 折交叉验证,判断模型表现是否稳定。把训练集切成 5 份,轮流留一份做验证,看 5 次 mAP 的波动。如果波动很大,说明数据分布不均,某一折里可能With People样本特别少,这时候补数据比调参有用。YOLOv8 本身不直接带 K 折,但可以写脚本切分后循环调用训练,或者用split参数控制。波动小于 3 个点,基本可以认为数据够用。

再调类别权重和置信度阈值。安全场景的核心矛盾是漏检和误报的权衡。漏检一个人可能出事故,误报一次只是多看一眼。所以我会把With People的召回率作为第一指标,做法是推理时把conf从 0.25 降到 0.15 甚至 0.1,看召回能提到多少、误报增加多少,画一条 P-R 曲线找拐点。如果降阈值后误报爆炸,说明模型对With People的判别力不够,得回去补这类样本,而不是硬压阈值。

最后是困难样本挖掘。跑完一轮推理,把验证集里漏检和误检的图挑出来,人工看它们有什么共性:是光线太暗、粉尘遮挡,还是人在远处太小。把这些图单独存一个目录,作为下一轮训练的补充数据,或者用它们做针对性增强(比如调亮度、加噪声)。这套数据里文件名是new_04_30.jpg这种编号,没有场景标签,所以困难样本得靠你自己看。我一般会把漏检图按场景归类,发现某一类场景反复漏,就重点补那类。

from ultralytics import YOLO import cv2 from pathlib import Path model = YOLO("runs/minecar/exp1/weights/best.pt") # 低阈值推理,把漏检的图挑出来 results = model.predict( source="MineCarWithPeople_yolo_data/valid/images", conf=0.1, # 故意压低,宁可多框 save=True, project="runs/hard_mining", name="low_conf" ) # 统计每张图检出的 With People 数量,为 0 的重点人工复核 for r in results: names = r.names counts = {} for c in r.boxes.cls.tolist(): counts[names[int(c)]] = counts.get(names[int(c)], 0) + 1 if counts.get("With People", 0) == 0: print(f"疑似漏检: {Path(r.path).name}")

这段脚本用conf=0.1跑验证集,把没有检出With People的图打印出来,这些就是最可能漏检的候选,人工复核后决定是否加入训练。参数上conf压得越低,候选越多,但复核成本也越高,0.1 是个经验起点。跑完这一轮,你对这套数据的边界就有数了:哪些场景它扛得住,哪些场景必须补数据。

从那以后我每次拿到小数据集,都强制先跑一遍交叉验证看波动、再跑一遍低阈值推理挖困难样本,这两步走完才敢谈调参。希望这套流程能帮到你,把轨道上的人和矿车真正盯住。

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

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

Python版PL0课设包拆解:词法、语法、语义到P-code实现

简介&#xff1a;南京航空航天大学编译原理课程设计的完整实现&#xff0c;采用Python语言编写PL0语言编译器&#xff0c;面向计算机专业本科生、编译原理课程学习者以及需要完成同类课设的开发者。压缩包共8个文件&#xff0c;包含5个Python源码文件&#xff08;词法分析器、语…

作者头像 李华
网站建设 2026/10/14 18:15:48

基于CNN的人脸识别考勤系统:预训练模型快速落地实战

简介&#xff1a;这是一套面向深度学习入门者与课程设计需求者的CNN人脸识别考勤系统完整项目&#xff0c;包含可直接运行的预训练模型&#xff0c;帮助读者跳过繁琐训练环节&#xff0c;快速搭建并验证人脸考勤流程。压缩包共4848个文件&#xff0c;以4835张jpg人脸图像构成训…

作者头像 李华
网站建设 2026/10/14 14:39:56

Spring Boot启动失败:BeanDefinitionStoreException异常排查全攻略

谁还没在启动Spring Boot项目时被控制台那一大片红色吓过。尤其当你看到第一行写着Application run failed&#xff0c;下面跟着一行org.springframework.beans.factory.BeanDefinitionStoreException时&#xff0c;很多人的第一反应是去搜“BeanDefinitionStoreException是什么…

作者头像 李华
网站建设 2026/10/14 10:16:11

无人机三维路径规划的Matlab实现:A星算法原理、代码与调试全解析

A星算法、无人机、三维路径规划、Matlab&#xff0c;这四个词放在一起&#xff0c;基本就是这几年无人机方向毕设和工程预研里最常出现的组合之一。我自己用Matlab做这种基于栅格地图的路径规划也有几年了&#xff0c;代码从最早只能在二维小地图里跑通&#xff0c;一路改到能处…

作者头像 李华
网站建设 2026/10/14 18:29:52

微信小程序swiper和switch组件

这次做的是微信小程序的 swiper 轮播组件和 switch 开关组件&#xff0c;需求是上面一个轮播图&#xff0c;下面一排开关&#xff0c;拨哪个开关&#xff0c;轮播就开启对应的效果。一共四个开关&#xff1a;显示指示点、自动播放、衔接滑动、竖向滑动&#xff0c;拨开关的时候…

作者头像 李华
网站建设 2026/10/14 12:16:02

微电网日前经济调度实战:风光储与需求响应Matlab建模

最近好几个做微电网方向的同学都在问同一件事&#xff1a;怎么看懂别人分享的“基于风光储能和需求响应的微电网日前经济调度”Matlab代码&#xff0c;以及怎么把它改成自己能跑、能复现、能写进论文里的版本。这个方向确实火&#xff0c;风、光、储能、需求响应&#xff08;DR…

作者头像 李华