简介这份数据集以COCO JSON格式组织面向矿井下智能监控与目标检测场景内容覆盖安全帽、指示器、人员、自救器等关键目标的像素级标注可用于训练和评估安全巡检、违规穿戴识别等视觉模型。压缩包共2000个文件主体为1997张井下作业现场的JPG图像另附3个JSON标注文件分别对应COCO格式的标注信息与类别映射整体包体约294.93MB适合直接接入MMDetection、Detectron2等主流检测框架。目前已有492人浏览学习。借助该数据集开发者可快速搭建井下安全帽佩戴检测、人员与自救器定位等模型并结合官方提供的识别率96.3%的基线结果进行对照调优同时标注文件遵循统一schema便于扩展新类别或迁移到其他低光、粉尘及复杂背景的井下视觉任务。图像采集自真实矿井环境涵盖不同光照、遮挡与姿态变化能够帮助模型更好地适应实际部署场景。1. 矿井下带标注COCO数据集识别安全帽、人与自救器96.3%不是玄学做过煤矿或非煤矿山视觉项目的人都知道井下光线暗、粉尘大、设备反光算法在实验室跑得再漂亮到了掌子面往往直接翻车。这份资源给的是一个带COCO JSON标注的矿井下目标检测数据集标注类别覆盖安全帽、指示器、人、自救器四类宣称识别率可达96.3%。它不是拿公开的VOC或COCO数据拼凑出来的通用模型而是贴着井下真实工况做的标注数据拿来微调YOLO、MMRotate或RT-DETR都能用。如果你是做矿山安全巡检、人员定位、违章行为识别的算法工程师或者正在给煤矿智能化验收攒训练数据这份数据集能省掉你大量下井采图、人工标注的时间。我拆完发现真正的价值不在那四类标注框而在JSON字段里标注方式的细节以及它对训练策略的暗示。2. 拆开这个COCO JSON字段结构、类别映射与边界框坐标2.1 COCO JSON的核心组成images、annotations与categories三段式COCO格式并不是把标注塞进一张图片的文件夹里而是一个自包含的JSON文件记录图片路径、尺寸、目标框、类别和分割信息。拿到这份矿井下数据集第一件事不是急着丢给训练脚本而是先看JSON的顶层键确认它到底长什么样。常见的COCO标注文件里有五个关键字段info、licenses、images、annotations、categories但实际训练时真正被使用的只有后三个。import json with open(mine_under.json, r, encodingutf-8) as f: coco_data json.load(f) print(coco_data[images][0]) # 输出第一张图的 meta 信息 print(coco_data[annotations][0]) # 输出第一个标注框 print(coco_data[categories]) # 输出类别表这段代码的作用是快速体检。打印images里的字段看有没有height、width、file_name这些训练必需的键打印annotations里的字段看是只有bbox还是带了segmentation多边形打印categories确认四类目标的id分配。很多人在这一步就翻车比如category id从1开始还是从0开始直接影响后处理后模型输出头的类别数设定。矿井下数据集的categories一般是这样排的1对应人、2对应安全帽、3对应指示器、4对应自救器。注意安全帽和人之间的id顺序看似随意实际上如果训练脚本用了filter_classes这种按id过滤的功能顺序错了就会导致类别张冠李戴。2.2 bbox格式x, y, width, height还是四点坐标COCO的bbox字段在官方文档里定义是[x, y, width, height]x和y是框左上角坐标width和height是框的宽高。但实际拿到手的标注尤其是一些外包标注团队给的数据经常把人头、安全帽这种小目标标成polygon多边形或者四点坐标。这个时候直接用pycocotools去算mAP会报错因为多数目标检测框架在加载COCO时默认bbbox是list[int]类型传入带浮点的list会导致类型校验失败。# 检查单个标注框的格式 ann coco_data[annotations][0] bbox ann[bbox] print(len(bbox), type(bbox), bbox) # 如果长度为8说明是四个点坐标而非COCO标准bbox if len(bbox) 8: x_coords bbox[0::2] y_coords bbox[1::2] x_min min(x_coords) y_min min(y_coords) w max(x_coords) - x_min h max(y_coords) - y_min print(converted bbox:, [x_min, y_min, w, h])这里的逻辑是把四点坐标拆成x和y两个列表取最小x和最小y作为左上角最大减最小得到宽高。这样转换会有一个小问题如果原标注框是旋转框转换后的外接矩形会引入部分背景噪声但矿井下数据集的目标大多是仪表盘、开关、安全帽这类近正立的物体外接矩形足够用。真正要小心的是指示器这个类别它可能是旋转的圆形仪表盘或者倾斜的开关状态指示器转换时如果只取外接矩形会框进大量无关背景把开关闭合检测这类任务搞成特征混淆。2.3 类别不均衡与annotation的area字段陷阱COCO JSON里的area字段在某些标注工具里是自动按bbox宽乘高算好的但它对数据集质量分析很有价值。矿井下场景中人的目标面积通常很大安全帽很小自救器是中等偏小指示器大小不一。如果area字段保留了原始多边形面积而训练脚本采样本时用的是area做尺度过滤就会把大量小目标滤掉导致安全帽那一类直接学不到。from collections import Counter ann coco_data[annotations] area_tuples [(a[category_id], a[area]) for a in ann] for cat_id in sorted(set(x[0] for x in area_tuples)): areas [x[1] for x in area_tuples if x[0] cat_id] print(fcat {cat_id}: count{len(areas)}, avg_area{sum(areas)/len(areas):.1f})统计之后如果发现安全帽类别的平均面积小于32x32也就是1024像素以下那在训练时就应该关闭multi-scale training里的尺度抖动或者把img_size调大。很多进mine下的数据都带着这种小目标难题COCO原始数据里小目标也占大头但矿井下的安全帽因为戴口罩、戴矿灯视觉特征更弱平均面积会更小。3. 标注与格式转换把labelme、CVAT的产物归一成标准COCO JSON3.1 验证标注工具输出与COCO格式的兼容性拿到这份矿井下数据集时最好确认一下原始标注是用什么工具做的。labelme输出的JSON是单个图片对应一个文件数据结构是shapes列表每一行是一个字典包含label和points。CVAT导出COCO格式时会生成一套train.json和val.json类别ID顺序容易和训练脚本的类别列表对不上。这块是矿井数据集使用里踩坑频率最高的位置因为很多标注外包是按CVAT交付的而源码给的类别映射表往往是按训练顺序排列的两者不一致时模型会在训练时打印warning但不会报错结果就是安全帽和自救器来回切换。# labelme 转 COCO 的关键映射逻辑 def labelme_to_coco(labelme_json_list, category_map): images [] annotations [] ann_id 1 for img_id, path in enumerate(labelme_json_list): # 读取 labelme 单文件 with open(path, encodingutf-8) as f: data json.load(f) images.append({ id: img_id, file_name: data[imagePath], width: data[imageWidth], height: data[imageHeight] }) for shape in data[shapes]: label shape[label] if label not in category_map: continue points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, y_min min(xs), min(ys) w max(xs) - x_min h max(ys) - y_min annotations.append({ id: ann_id, image_id: img_id, category_id: category_map[label], bbox: [x_min, y_min, w, h], area: w * h, iscrowd: 0 }) ann_id 1 return {images: images, annotations: annotations, categories: [ {id: v, name: k} for k, v in category_map.items() ]}这里category_map的写法值得多说一句它是显式映射表比如{helmet: 1, person: 2, indicator: 3, self_rescuer: 4}。很多人不写映射表而是直接用label字符串做dict key等训练脚本一跑类别索引错乱得莫名其妙。做转换时还必须把labelme的imagePath里可能带的多级目录去掉否则训练时读不到图片报出一堆file not found。另一个常见问题是labelme的points坐标可能是浮点型COCO的bbox在严格模式下是int类型但检测框架通常能处理float只是在最后nms阶段转成int时会丢掉一点框精度。3.2 用pycocotools做完整性校验能在训练前发现80%的问题pycocotools不只是拿来算mAP的它自带的loadRes和COCO类可以做标注一致性校验。把转换完的JSON加载进去调用coco.loadImgs和coco.loadAnns如果某张图引用了不存在的image_id或者某个annotation的bbox超出图像边界pycocotools会抛出断言或者警告。这一步训练前必做因为它能抓出两类致命错误一类是图片分辨率在标注时被缩放、但bbox没有同步缩放另一类是旋转框转换后在图像边界外的裁剪问题。from pycocotools.coco import COCO coco COCO(mine_under_converted.json) # 检查每个标注框是否在图像边界内 for ann_id in coco.getAnnIds()[:200]: ann coco.loadAnns(ann_id)[0] img_info coco.loadImgs(ann[image_id])[0] x, y, w, h ann[bbox] if x 0 or y 0 or x w img_info[width] or y h img_info[height]: print(fbbox out of range: ann_id{ann_id}, img_id{ann[image_id]})边界越界的标注一般出现在图像右侧和下侧原因是部分标注人员用矩形框工具时拉出了画布范围导出的JSON里xw或yh超出了width、height数值。这种脏数据喂给网络后模型会在训练初期就把anchor匹配算错表现为loss前期不下降、后期震荡。推荐的做法是直接把越界框裁剪到边界内而不是删除因为矿井下数据本身量不大丢弃标注框会导致正样本进一步缺失。3.3 单类标注的合并当人、安全帽、自救器同时出现在一个框内矿井下图像里经常出现人戴安全帽、腰间挂自救器的组合情况标注时不同标注员的理解不一样有人把安全帽单独框出一块有人把帽子和人头框成一个框。如果这批数据的标注框存在大量重叠训练时会因为正样本IoU分配混乱导致mAP提升缓慢。一个实际的处理办法是做一个NMS式的合并对同类别且IoU超过0.8的框进行合并保留置信度高的那个框如果是人和安全帽两个不同类别高度重叠不能合并反而应该保留这能让模型学到人头顶上的安全帽是一个独立小目标而不是把人整体当成一个目标。这个操作需要写脚本批量处理手动改不现实。合并完了还得跑一次上面的越界检查因为合并后的框可能变成原始两个框的union边缘更容易超界。4. 训练与评估带着96.3%的期望值去复现识别链路4.1 训练预处理直方图均衡与混合增强是不是必须做矿井下图像的特点是整体亮度偏低、灰度集中在暗部绿色头盔和深色工装在暗背景下区分度差。直接在原图上训练卷积核需要更多层去拟合亮度分布收敛慢且容易过拟合。我一般会在训练管线里追加一个直方图均衡化的预处理不用太复杂OpenCV的createCLAHE就够用。对比度限制设置在2.0左右网格大小8x8可以明显把矿灯照射产生的过曝区域和暗部区域的纹理同时拉出来。import cv2 import numpy as np def clahe_preprocess(img): # 输入为 BGR 格式的井下原图 lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) l clahe.apply(l) lab cv2.merge([l, a, b]) return cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)这个预处理放在数据加载阶段相当于在数据流里做增强不会污染原图。要注意的事CLAHE对噪声有放大效应如果原图是低照度下手机拍的会有大量彩色噪点被强化这时候应该先做一次轻微的bilateral filter再进CLAHE否则模型会对噪点纹理过拟合。增强策略上Mosaic和MixUp可以做但别开太猛。矿井下目标有很强的语义关联人旁边大概率有安全帽和自救器Mosaic的随机拼接会破坏这种上下文。把Mosaic概率调到0.5以下或者干脆只保留随机翻转、随机亮度和对比度抖动能更好保留井下场景的共现特征。96.3%的识别率通常是在一张测试集上刷出来的如果你的验证集和训练集同采区高度相似跑出甚至超过这个数值都不奇怪但换到另一个采区就要降一截预期。4.2 模型选型YOLOv8和RT-DETR哪个更适合煤矿场景井下检测落地时部署端的算力是硬约束。如果你要跑在防爆摄像仪或者边缘计算盒子上YTOLOv8n或者YOLOv8s是稳妥选项模型体积小INT8量化后能跑到实时。RT-DETR精度更高但Transformer结构在NPU上支持不友好很多矿用摄像头里的芯片跑不起来。如果你的算力是机架式服务器GPU那RT-DETR值得试它处理重叠目标和小目标的表现比YOLO系强尤其对指示器这种尺寸变化大的类别。训练命令以YOLOv8为例数据yaml里必须严格指定类别名和路径path: /data/mine_dataset train: images/train val: images/val names: 0: person 1: helmet 2: indicator 3: self_rescuer注意names这里的顺序必须和前面category_map的id顺序一致也就是0对应person、1对应helmet而不是按COCO原始id顺序。如果直接沿用COCO JSON里1到4的category_id但yaml从0开始编号模型输出头的类别数和映射关系全乱套。这也是为什么前面花那么大篇幅强调查看categories字段的原因。启动训练的代码一行就能跑但参数里imgsz要按你数据里最小目标尺度来设一般建议--imgsz 640起步如果安全帽在图像中平均只有20x20像素建议直接拉到1024代价是训练速度减半收益却是小目标召回率显著提升。yolo detect train datamine.yaml modelyolov8s.pt epochs200 imgsz640 batch16 device0,1epochs在这个场景不要设太少因为井下光照差异大模型需要更多轮次去拟合不同采区亮度下的特征。200轮是一个比较合适的起点配合早停机制看val loss连续20个epoch不降就停。4.3 评估指标不能只看mAP要看每一类的APCOCO格式数据集的评测标准是AP0.5:0.95但矿井数据集里四类目标的尺寸差异巨大整体的mAP会被大目标的人拉高掩盖小目标安全帽的漏检。比如整体mAP 96.3%如果拆开看person的AP到了98%而helmet只有88%这种mAP并没有太大工程意义。跑完训练后用pycocotools逐类输出AP或者直接在验证阶段打印每类的PR曲线重点关注helmet和indicator两个类别。指示器是这里面最特殊的矿井下的指示灯有红绿两种状态如果标注时没有区分状态而统一归为indicator那它的AP上限会被状态间的外观差异卡死。from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval coco_gt COCO(mine_annotations.json) coco_dt coco_gt.loadRes(results.json) evaler COCOeval(coco_gt, coco_dt, bbox) evaler.evaluate() evaler.accumulate() evaler.summarize() # 逐类统计 AP for cat_id in coco_gt.getCatIds(): evaler.params.catIds [cat_id] evaler.evaluate() evaler.accumulate() evaler.summarize()逐类跑一次需要重新整体evaluate因为COCOeval内部会按catIds重新计算匹配。实际上更快的做法是直接用模型框架自带的per-class指标打印YOLOv8在训练结束后会自动输出每个类别的mAP50和mAP50-95不用重复调用COCOeval。用pycocotools的好处是能拿到更细的area分组指标比如small/medium/large三个尺度的AP可以直观确认安全帽这一类是不是在小目标区间塌了。5. 避坑与排查标注错位、类别不均衡、过拟合的真实记录5.1 现象训练loss正常下降但验证集mAP一直卡在70%上不去原因大概率是训练集和验证集的数据分布不一致常见的是验证集里包含了大量的非井下图片或检修状态图片模型见过的井下正常工况特征并没有覆盖到验证集的目标。另一种可能是验证集的标注框坐标有系统性偏移比如标注工具导出时自动加了padding导致框整体往右下偏了几个像素。解决的办法是先画几张验证集图片的GT框和预测框肉眼对比偏移量。如果是padding偏移直接批量修正JSON里的bbox坐标把x和y同时减小固定像素值重新跑evaluate。5.2 现象helmet的AP值明显低但数据量其实不少排查顺序先从数据质量看。如果安全帽的框里有大量未被标注的安全帽也就是漏标那AP低是正常的模型学到的正样本本身就不完整。用模型预测结果和GT做一次差异对比把漏检的图挑出来看如果漏掉的是远距离的、戴在头上只有十几个像素的安全帽那就不是标注问题而是目标尺度问题需要加大imgsz或者用SAHI做切片推理。如果是近距离的安全帽大量漏检大概率是标注框把帽檐排除在了框外导致模型学到的安全帽特征不完整。5.3 现象指示器这个类别的置信度很高但框的位置偏在表盘中心这个通常是旋转框转换为水平矩形框时造成的。圆形表盘的旋转框外接水平矩形会包含表盘四周的黑色区域特征上表盘中心读数区域和外框背景混在一起模型被迫学了表盘中心那一小块区域的特征。解决思路是改用带角度的标注格式比如DOTA或OBBD格式用MMRotate训练旋转目标检测模型。如果你不想换框架另一个做法是把指示器类的标注从表盘改成表盘上的指示灯区域小目标矩形框的表征更干净模型更好学。5.4 现象模型在井下现场检测时把矿灯识别成安全帽矿灯是戴在安全帽上的两者高度重合灯头部分的外观和黄色安全帽在某些角度下很像。训练数据里如果矿灯总是戴在帽子上模型会把帽顶的灯头当作安全帽的一个特征。解决的办法是在增强时加入随机裁剪把安全帽上半部分裁掉一部分让模型不能只靠灯头判断。另一个更关键的是标注规范安全帽框应该严格框住帽体的外沿不要把灯头包含进去从源头切掉这种特征混淆。5.5 现象用YOLOv8加载这个数据集时报错类别数不匹配COCO JSON里category id如果包含0而yaml里names列表从0开始训练框架会默认把0号类别视为背景导致真正的person被顶到4类别总数对不上。这个问题不只在矿井数据集上出现COCO原始数据集也存在因为COCO的category id从1开始。解决方式是在数据准备脚本里统一对category_id做一次减1操作并重构所有annotation的category_id字段保证类别ID从0开始且严格连续映射关系里不要出现跳号。6. 进阶把预训练权重冷启动你的矿井视觉基线拿到矿井下数据集之后还有一个容易被忽略的玩法——用它做知识蒸馏的teacher模型。因为矿井下场景没有大规模预训练数据集用一个在通用COCO上预训练的YOLOv8l或者RT-DETR作为teacher在这个矿井数据上先训一轮得到teacher输出然后训练一个YOLOv8n作为studentloss里加入teacher的特征蒸馏项。这样能保证边缘设备上的轻量模型也能拿到接近教师模型的精度部分实测能把小模型的安全帽AP再拉高3到5个点。蒸馏代码不需要从零写ultralytics框架里已经内置了蒸馏逻辑的接口核心参数是蒸馏权重和特征层对齐位置。我一般把蒸馏的alpha设为0.4也就是最终的loss里40%来自蒸馏损失、60%来自原始检测损失太高的alpha会让student过度模仿teacher而忽略GT框的监督信号。实操上还有一个小技巧矿井下的图像整体色调偏冷训练时把输入图像的色彩空间从BGR转到HSV对安全帽的黄色和指示器红绿灯会有更好的特征区分度。在数据加载时做一个非常轻量的HSV变换色相通道不做调整饱和度和明度做小幅随机增强让模型对矿灯照射下的色彩漂移更鲁棒。这个改动不增加训练时间但对指示器颜色状态识别有实质性帮助。训练完成后不要急着整个模型替换先在矿上的历史视频上做帧级验证。看三类指标安全帽检出率、人员重复id切换频率、自救器漏检率。井下人员大部分时间在走动如果检测框频繁闪烁多半是NMS阈值设得过于激进调低conf_thres到0.25、IoU_thres保持默认0.7。如果自救器检测在人员弯腰时大量消失需要在训练集里补充含有弯腰姿态的图像而不是调算法参数因为模型根本没有见过这个正样本形态。我用这份数据集复现时的最终习惯是把所有标注先按采区划分成不同子集每个子集单独做一次模型评测而不是把所有矿井图片混在一起训练后只看一个整体mAP。这样能暴露出哪些采区的光照条件和标注质量拖了后腿。从那以后我每次用带标注的矿井数据训练前都强制走一遍逐类AP的评估和采区分布检查宁可慢半天也不再让黑匣子式的总体指标糊弄过去。希望帮到你。本文还有配套的精品资源点击获取