矿车与人员检测实战:MineCarWithPeople数据集与YOLO训练全流程
发布时间:2026/9/28 16:07:27来源:尧图网络
简介这份数据集面向矿业自动化与计算机视觉开发者专注于轨道上矿车及人员检测任务采用YOLO格式标注包含Normal与With People两个类别可直接用于YOLO系列模型训练与验证。包内共2000个文件其中1045张jpg图像、954个txt标签及1个yaml配置文件压缩包整体约206.69MB训练集与验证集划分清晰便于快速开展实验。数据来源为实际矿业轨道环境近一千张图像覆盖矿车正常运行及人员出现场景可为安全生产监测提供高质量训练样本。目前已有118人学习下载适合正在构建矿井人员安全预警系统的算法工程师与研究人员。通过该数据集开发者可省去繁琐的采集标注流程直接聚焦于检测模型调优在提升矿车区域人员识别准确率的同时加速矿业智能化安全方案的落地。1. 轨道场景先想清楚矿车和人员检测难在哪煤矿、金属矿山的地面轨道运输区摄像头常年对着同一条道画面里来来去去就两类东西矿车和人。可就是这么个看似简单的目标检测任务部署起来却让不少团队翻车。原因在于轨道场景跟通用物体检测差异很大——矿车是长条形大目标多半是侧视角车头车尾难以分辨人员站在轨道旁常常只有二三十像素高还容易被车体遮挡住。MineCarWithPeople 这个数据集提供的就是这种轨道场景下矿车与人员的 YOLO 格式标注数据能直接拿来训练工业级安全监测模型。它的价值不是“又多了一个数据集”而是把现场最头疼的小目标与遮挡问题打包好了。适合正在做智能矿山、轨道交通巡检、工业安防视觉的算法工程师也适合刚接触 YOLO 想找真实场景练手的学习者。下面我按拿到压缩包之后的操作顺序把从解压到训练验证的完整路径讲透。2. 打开 zip 的姿势目录结构、YOLO 标注和三类标签2.1 解压后先别急着训练先看清目录长什么样我拿到数据压缩包后的第一件事不是解压完就跑训练而是先把目录树完整列出来搞清楚图片和标注的对应关系。常见的 YOLO 格式数据集内部结构通常长这样MineCarWithPeople也不例外MineCarWithPeople/ ├── images/ │ ├── train/ │ │ ├── img_0001.jpg │ │ └── img_0002.jpg │ └── val/ │ ├── img_1001.jpg │ └── img_1002.jpg ├── labels/ │ ├── train/ │ │ ├── img_0001.txt │ │ └── img_0002.txt │ └── val/ │ ├── img_1001.txt │ └── img_1002.txt ├── data.yaml └── README.md逻辑说清楚每张.jpg对应一个同名.txt文件名必须完全一致后缀不同而已。图片放images/train标注放labels/train验证集同理。这个配对规则是 YOLO 系列模型加载数据的前提只要你改了一个文件的名字训练时就会报出找不到标注之类的错误。接下来打开一个标注文件看看内容。每一行对应一个目标框格式是五个数字类别ID 中心点x 中心点y 框宽 框高其中坐标值都是归一化到 01 的浮点数不是像素值。例如下面这行0 0.4825 0.5317 0.2134 0.1682参数说明第一个0是类别编号对应data.yaml里names列表的下标后面四个值分别是目标框中心点和宽高在整张图中的相对比例。如果想把归一化坐标还原成像素坐标用原图宽高去乘就行x_pixel cx * widthy_pixel cy * height。很多标注工具导出时自动完成分人工写错中心点坐标是标注阶段最常见的低级错误。2.2 data.yaml 是模型理解任务的钥匙data.yaml是训练时的入口配置里面写的是路径和类别名。数据集自带的data.yaml通常长这样train: images/train val: images/val nc: 2 names: [minecar, person]这个文件很关键因为nc和names必须与标注文件里的第一个数字严格对应。如果names写成[person, minecar]而标签里0指的是矿车那模型训练出来的结果就是把矿车识别成人损失函数照样会降但推理时全线崩溃。这种坑我已经踩过不止一次后面避坑章节还会细说。值得注意的还有一点这里train和val用的是相对路径实际训练时 YOLO 会以data.yaml所在目录为基准去拼接。如果数据集被移动过位置或者你在服务器上换了目录跑训练相对路径是最不容易出问题的写法。有些数据集作者喜欢在yaml里写绝对路径解压到不同机器后必然报错这种时候改data.yaml里的路径就能解决。2.3 标注规范里藏着的语义陷阱这个数据集同时包含矿车和人员意味着存在两类之间互相遮挡的情况。标注时候需要明确的规则是“矿车框住车体的整体轮廓即使人被矿车挡住也照常标人”。但实际操作中如果标注工具不提供“遮挡标记”能力标注员往往会把被挡了一半的矿车画成一个奇怪的多边形甚至漏标。检查数据集时我一般会重点关注两点一是是否存在大量“矿车人员”同框的样本二是标注框宽高比是否集中在异常范围。矿车侧视角的宽高比大正视角则接近正方形人员则是细长的竖框。如果出现大量宽高比小于 0.3 的矿车框说明标注时把车头尾的局部当成了整车。3. 训练前把数据理顺校验脚本与 train/val 划分3.1 拿到 zip 先做“体检”别让坏数据偷走时间数据集解压出来不等于能用我先会用一段 Python 脚本把图片和标注全部过一遍检查三类问题标注文件缺失、坐标越界、图片损坏。这一步是纯体力活但能省下后面几天的排错时间。我常用的校验脚本如下你可以直接跑from pathlib import Path from PIL import Image def validate(images_dir: Path, labels_dir: Path, tolerance: float 0.02): 校验YOLO标注与图片是否匹配。 tolerance: 边界溢出容差标注框允许超出画面边界的比例。 img_paths list(images_dir.glob(*.jpg)) list(images_dir.glob(*.png)) for img_path in img_paths: label_path labels_dir / (img_path.stem .txt) if not label_path.exists(): print(f缺标注: {img_path.name}) continue try: w, h Image.open(img_path).size except Exception: print(f图片损坏或无法读取: {img_path.name}) continue for i, line in enumerate(label_path.read_text().splitlines(), 1): parts line.split() if len(parts) ! 5: print(f标注格式错误: {label_path.name} 第{i}行) continue cls, cx, cy, bw, bh parts cx, cy, bw, bh map(float, (cx, cy, bw, bh)) if not (0 cx 1 and 0 cy 1): print(f中心点超出0~1: {label_path.name} 第{i}行) if bw 1 tolerance or bh 1 tolerance: print(f框尺寸超出画面: {label_path.name} 第{i}行) base Path(MineCarWithPeople) validate(base / images / train, base / labels / train) validate(base / images / val, base / labels / val)逻辑说明脚本按文件名配对找标注先查是否缺失再尝试用 PIL 打开图片验证完整性最后逐行解析坐标判断是否在 01 范围内。注意tolerance参数我给了0.02也就是允许标注框越界画面 2%这是人工标注时贴边目标的常见误差超过这个值就要人工复核。参数说明0.02不是硬性规则如果你打算直接拿这个数据集训练而不做裁剪建议把容差调到0因为 YOLO 会把越界的部分直接裁掉。如果是矿车贴画面边缘的图片很多小于 1% 的溢出其实对训练影响不大真正要警惕的是中心点跑到 01 之外那多半是标注工具导出换算错误。3.2 训练/验证集划分随机种子是你的后悔药如果压缩包里已经分好了train/val跳过这一步如果没有或者你想做交叉验证就用下面的脚本按 8:2 重新划分。这里的关键是固定随机种子否则每次划分的结果不同模型对比就没有可比性。import random import shutil from pathlib import Path src_images Path(MineCarWithPeople/images) src_labels Path(MineCarWithPeople/labels) out_images Path(split_data/images) out_labels Path(split_data/labels) for subset in (train, val, test): (out_images / subset).mkdir(parentsTrue, exist_okTrue) (out_labels / subset).mkdir(parentsTrue, exist_okTrue) random.seed(42) # 固定种子保证分割可复现 img_paths list(src_images.glob(*.jpg)) list(src_images.glob(*.png)) random.shuffle(img_paths) val_cnt int(len(img_paths) * 0.2) for i, img in enumerate(img_paths): subset val if i val_cnt else train label src_labels / (img.stem .txt) if not label.exists(): print(f跳过缺失标注的图片: {img.name}) continue shutil.copy(img, out_images / subset / img.name) shutil.copy(label, out_labels / subset / label.name)逻辑说明脚本先把所有图片路径收集起来按 8:2 的量级分成验证集和训练集再把对应的标注文件一起拷过去。sku逻辑里特意加了label.exists()检查防止把没有标注的图片直接丢进训练集——YOLO 训练时如果遇到这种情况不一定报错但会对损失函数产生误导这个细节很容易被忽略。参数说明val_cnt int(len(img_paths) * 0.2)这里的0.2按需调整就行样本总量少就保持 20% 验证样本多可以降到 10%。random.seed(42)建议固定这样每次跑结果一致方便复现别人的实验数据。3.3 类别不平衡别让矿车把人员“淹没”轨道场景里矿车的出镜频率通常远大于人员训练集里可能 90% 的标注框都是矿车。这种不平衡会直接导致模型在推理时倾向于“看见什么都框成矿车”。处理方式有两种常见做法是先不动数据训练时给cls_loss配置类别权重。YOLO 的data.yaml支持直接指定权重参数但我更习惯用脚本统计各类别的框数量再决定要不要做数据增强补样python -c from pathlib import Path from collections import Counter cnt Counter() for txt in Path(MineCarWithPeople/labels/train).glob(*.txt): for line in txt.read_text().splitlines(): cnt[int(line.split()[0])] 1 print(cnt) 如果跑出来的结果显示person的框数量只有minecar的十分之一即使损失函数里加了类别权重效果也有限。这时候的常规做法是补充人员样本包括但不限于从视频流里抽帧、用其他公开行人检测数据集做迁移、或者对已有人员样本做随机裁剪放大。网络上有些团队直接调 loss 权重到 1:5实测效果时好时坏我自己的经验是数据层面补样本比调权重更稳定。4. 让 YOLO 学会“车在人也在”模型选型与训练参数4.1 模型选型从 yolov5s 到 yolov8s 怎么挑轨道的目标检测任务模型选型不是越大越好而是要看部署平台。如果最终要落地到矿山的边缘计算盒子或摄像头内嵌芯片算力非常有限我从实际项目的角度推荐按下面这张表选型模型推理速度参考占显存适合场景yolov5s快低边缘盒子、嵌入式yolov8s中等中等工控机、服务器推理yolov8m较慢较高后端批量分析yolov10n最快最低低功耗设备表格说明这里不写具体帧率数字因为同一模型在不同芯片上的表现差异很大但s和n后缀模型的推理速度优势是明确的。标定推断能力时yolov5s在老旧的 TensorRT 环境里兼容性更好yolov8s在框架支持和精度上更均衡尤其适用于人员小目标检测。轨道场景更看重人员和矿车的召回率我一般用 yolo 系列的s型号起步跑通之后根据短板决定裁剪还是升级。4.2 最小可复现的训练命令数据集准备好之后训练命令非常简洁ultralytics 已经把大部分细节封装好了。下面这条命令我建议直接保存成train.sh使用yolo detect train \ dataMineCarWithPeople/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ patience20 \ projectruns/track_mine \ nameexp1逻辑说明这条命令让模型在data.yaml定义的数据集上微调yolov8s.pt输入图片尺寸统一缩放到640x640训练轮次最多 150 轮。关键在patience20意思是若连续 20 轮验证集 mAP 都没提升训练自动停止避免空转浪费时间。project和name指定了训练日志和权重的输出目录最终结果在runs/track_mine/exp1里。参数说明imgsz是轨道检测里最值得调的参数。人员只有二十几个像素高的时候640可能不够我建议先试768或960代价是推理速度变慢和显存占用上升。batch的大小受限于 GPU 显存16是一般 8G 显存卡的安全值显存不够优先减imgsz不要硬调batch。首次运行时会自动下载预训练模型网络环境受限的话需要手动把yolov8s.pt放到本地缓存目录再在命令里指定绝对路径。4.3 损失函数曲线训练翻车了要能看懂yolo 预训练模型下载好、训练跑起来之后不要只看 mAP要盯住三个损失分量box_loss框回归损失、cls_loss分类损失和dfl_loss分布焦点损失。这三条曲线能告诉你模型到底卡在哪box_loss降不下去标注框的边界标得不准或者矿车长条形导致回归难。解决思路是检查标注框是否覆盖完整车体而不是只标了车斗。cls_loss反复横跳类别间特征重叠严重比如把远处的人误判成车。解决思路是增加人员样本或者提高输入分辨率让细节显现。dfl_loss振荡一般跟学习率过大有关或者训练集里存在大量极端长宽比的框导致模型难以学习稳定的框分布。很多人拿到这类数据集上来就默认epochs300实际上轨道场景数据量不大时150 轮以内往往已经收敛。看曲线比死等轮数靠谱得多曲线都平了后面的训练只是消耗电费。5. 避坑轨道目标检测常见的四个真实翻车点5.1 类别顺序错位loss 很低但预测全错现象训练时损失函数正常下降验证集 mAP 也在涨但拿到现场一跑发现矿车被识别成了人人也变成了矿车。原因data.yaml里names的顺序和标注文件里的类目下标对不上最常见的是标注工具导出时把person当作0、minecar当作1但yaml里写反了。解决训练前花三分钟检查标签数字含义打开一张训练图的标注文件把第一个数字和names列表对照一下确认0到底是谁。5.2 路径写死换机就跑不起来现象在自己电脑上训练没问题把整个目录拷到服务器上再跑报错FileNotFoundError怎么也找不到图片。原因压缩包里自带的data.yaml里写的是作者机器的绝对路径比如/home/xxx/MineCarWithPeople/images换个环境就失效。解决把yaml里的train和val改成相对于yaml文件所在目录的写法或者在训练命令里用data/绝对路径/data.yaml并在yaml里写相对路径。这个坑比预期常见得多我接手别人项目时第一件事就是看yaml路径。5.3 小目标人员漏检严重现象正式识别时矿车框得很准但轨道旁边站着的工人偶尔被漏掉尤其是离摄像头远的位置。原因imgsz640时一个 30 像素高的人缩放后只剩十几个像素特征图上的信息太少。解决分两步训练时把imgsz提高到960或1280看显存决定推理时对原图做切片推理把大图拆成几块分别检测再合并结果这个做法我在第 6 章会给出具体方案。请注意提高imgsz不是万能的有时候反而是过拟合了训练集里的近景人员所以才要配合切片推理。5.4 矿车标注框宽高比混乱现象部分矿车检测框只框住了车斗把车头和车轮漏了导致准确率虚高但实际定位很烂。原因矿车的侧视角目标长度跨度大标注员在快速标注时倾向于框住最醒目的部分也就是车斗。解决明确数据标注规范整车矿车的框必须包含完整车体和车轮在压缩包内没有标注说明文档的情况下你可以在训练前自行按车体轮廓修正明显错误的框。如果修正成本太高另一个折中做法是训练时把box_loss的权重调低让模型自己学会适应标注噪声但效果有限。5.5 忽略验证集最后只能靠现场试错现象本地训练完拿视频测试发现大量误报回头调参又得重训一轮循环往复。原因没有独立验证集或者验证集里只包含和训练集相同的场景。这个数据集如果连val目录都没有划分出来训练完就失去客观评估依据。解决严格按第 3 章的划分脚本分出一部分真实场景图片不参与训练每次训练完先看验证集 mAP 和混淆矩阵再决定是否改参数而不是用现场试错。6. 验证不只看 mAP混淆矩阵、PR 曲线与小目标切片推理训练结束best.pt就躺在runs/track_mine/exp1/weights/里。但 mAP 数字虚高是常有的事轨道场景下画面里大部分区域是空的背景类负样本没参与训练模型很容易刷高分。我会用下面这段代码做值机验证from ultralytics import YOLO model YOLO(runs/track_mine/exp1/weights/best.pt) results model.val( dataMineCarWithPeople/data.yaml, splitval, plotsTrue, conf0.001, iou0.5, )逻辑说明plotsTrue会生成混淆矩阵confusion_matrix.png、PR 曲线以及各类别统计结果。这里给conf0.001的目的很关键为了画 PR 曲线必须让所有置信度阈值的预测都参与计算如果只按推理时的0.25阈值来PR 曲线会丢失低置信度段的形状你看不到远端小目标被模型以多低的分数捡起来。参数说明splitval直接从data.yaml里找验证集如果之前划分时没单独留 val可以用这个参数指定某个目录。对于人员小目标我最常用的落地技巧是切片推理也叫滑窗推理。把大图按固定大小拆成有重叠的块各自推理后用 NMS 把重叠区域的重复框合并import numpy as np from ultralytics import YOLO model YOLO(runs/track_mine/exp1/weights/best.pt) def slide_infer(model, img, tile640, overlap64, conf0.25): h, w img.shape[:2] boxes, scores, classes [], [], [] step tile - overlap for y in range(0, h, step): for x in range(0, w, step): y1, y2 y, min(y tile, h) x1, x2 x, min(x tile, w) crop img[y1:y2, x1:x2] result model.predict(crop, confconf, verboseFalse)[0] for box in result.boxes: bx1, by1, bx2, by2 map(float, box.xyxy[0]) boxes.append([bx1 x1, by1 y1, bx2 x1, by2 y1]) scores.append(float(box.conf[0])) classes.append(int(box.cls[0])) # 合并重叠框用模型自带的NMS逻辑 return np.array(boxes), np.array(scores), np.array(classes)切片推理的本质是让每个小目标在独立切片中占据更大画面比例YOLO 的检测头就不会因为目标太小而漏掉。要注意overlap不能太小否则目标正好卡在交界处时会被两个切片各截一半导致重复框增多64 像素重叠在 640 切片下是安全值。合并时的 NMS 我给iou0.5重叠区域出现大量框时可以把iou降低到0.3来抑制误检。我在跑完轨道场景的项目后养成一个习惯任何数据集到手先花 15 分钟做数据校验再看一张训练图片的标注可视化最后才允许自己启动训练。这十几分钟的成本换来的是不深夜盯着 loss 曲线怀疑人生。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网