YOLOv8智慧工地数据集实战:训练安全帽反光衣行人检测模型
发布时间:2026/10/2 8:37:22来源:尧图网络
简介面向智慧工地安全监管的标注数据集覆盖反光衣、安全帽、行人等多类目标可为反光衣穿戴检测、安全帽佩戴检测、人员入侵抓拍告警等场景提供训练基础适合视觉算法工程师、监控系统开发人员和深度学习学习者使用。压缩包约585.74MB内含3065份XML标注、3065份TXT标注和672张JPG监控图像提供VOC与YOLO两种主流格式标签由LabelImg手工绘制图像与标注一一对应背景为工地监控多视角、多场景抓拍可直接用于YOLO系列、SSD、CenterNet、PP-YOLO等目标检测算法也适合开展算法对比与参数调优实验。全部图片来自真实工地监控摄像头人物姿态、遮挡、光线差异明显有助于提升模型鲁棒性。目前已有1436人学习/下载包内还附有完整图片获取说明方便训练时扩展数据总量对于需要快速获得真实场景数据的团队可大大缩短数据采集与标注周期整体实用价值高。1. 智慧工地数据集3065张图检测反光衣、安全帽、行人能干什么工地安全巡检现在不是靠人盯屏幕而是靠检测模型自动盯监控画面。这个智慧工地数据集就是为这类行人检测任务准备的3065张工地监控多视角多场景抓拍图标注了反光衣、安全帽、行人三类目标自带VOC和YOLO两种标签格式。拿到手不用再折腾格式转换YOLO可以直接开训VOC格式留下来做二次校验或跑其他检测框架。适合两类人一是刚接触目标检测、想用一个贴近真实场景的数据集跑通yolov8训练流程的从业者二是做工地安监项目、需要验证算法在安全帽和反光衣场景下可行性的算法工程师。2. 数据集结构VOC和YOLO两套标签怎么摆、怎么检查、怎么互转拿到数据集的第一件事不是开训练是把目录结构和标签质量摸清楚。这个zip包里同时给了VOC和YOLO两套标签反而比单格式更考验对两种格式的理解。下面从实际排查顺序讲照着做能省大半天的返工。2.1 解压后先按这套流程确认目录别急着开训常见的VOC格式目录是JPEGImages放图片、Annotations放XML文件YOLO格式则是images放图片、labels放TXT文件。解压完先跑三组命令确认目录写法、图片数量和标签数量是否对得上# 1. 看压缩包内部结构确认目录名是images还是JPEGImages unzip -l 智慧工地数据集.zip | head -40 # 2. 数图片数量标题写3065张先对一下有没有缺图 find . -name *.jpg -o -name *.png | wc -l # 3. 数两套标签数量VOC和YOLO各统计一遍 find . -path *Annotations*.xml | wc -l find . -path *labels*.txt | wc -l这三条命令做的事情分别对应三个检查点第一确认顶层目录到底叫images还是JPEGImages后面写训练配置时路径必须跟实际目录名一致第二核对图片是不是3065张有些卖家用视频抽帧填充数量抽帧去重后实际只有两千出头这会影响训练轮数和batch配置第三对比XML和TXT数量两套标签数量不一致说明转换环节有遗漏。如果发现图片和标签数量对不上别急着认定是数据集有缺陷。工地监控画面里经常出现没人的空场景这类图可能没有标注也没有标签文件对YOLO训练来说是有效的负样本但对VOC转YOLO的脚本是个坑转换前要单独处理。还有一种常见情况是标注员漏标了某个XML这个在2.4节会给自检脚本。接下来要确认类别名是否统一XML里存的类别名必须是英文而且同一个类不能有多个叫法# 从所有xml里提取出现过的类别名称去重统计 grep -h name Annotations/*.xml | sort | uniq -c | sort -rn这个命令把Annotations目录下所有XML的name字段统计一遍。正常情况下应该看到三类英文名类似hardhat、vest、person的组合。如果出现helmet和safety_helmet两种写法说明标注人员前后命名不统一必须合并后再转格式否则类别数会从3变成4训练配置跟着全错。2.2 VOC和YOLO标签的本质差异坐标系与归一化VOC的XML记录的是绝对像素坐标xmin、ymin、xmax、ymax单位是像素范围受图片宽高限制。YOLO的TXT记录的是归一化后的相对坐标class cx cy w hcx和cy是目标框中心点的相对坐标w和h是宽高全部除以图片宽高后落在0到1之间。这是两种格式最核心的区别也是转换脚本里最容易算错的地方。第二个区别是坐标表达方式。VOC里两个点定义左上角和右下角YOLO里是一个中心点加宽高。很多人在手写转换脚本时把中心坐标算成xmin加上一半宽但归一化时忘了除以图片宽算出来的框全部偏到图片的一侧训练直接不收敛。中心坐标的归一化必须用(xmin xmax) / 2再除以图宽不能先除再加。还有一个容易被忽略的点YOLO的类别id是从0开始编号的整数VOC的XML里存的是类别名字符串。转换时必须维护一个类别名到id的映射表id的排列顺序还要和训练配置里names列表的顺序完全一致。比如names列表写[hardhat, person, vest]那id 0对应hardhat1对应person2对应vest。任何一个环节的顺序对不上模型学出来的就是错位标签。2.3 一键把VOC转成YOLO脚本与参数说明虽然标题说数据集已经自带两种格式但实操里你经常拿到VOC格式的版本或者需要自己重新转一遍来排查问题。我一般先把转换脚本准备好任何工地数据集拿到手都用同一套流程处理import os import xml.etree.ElementTree as ET from pathlib import Path # 类别映射表顺序必须与后续data.yaml中names完全一致 CLASS_NAMES [hardhat, person, vest] # 按数据集的xml实际内容改 def convert_voc_to_yolo(xml_path: str, out_dir: str): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_NAMES: print(f[跳过] 未注册类别 {name} in {xml_path}) continue class_id CLASS_NAMES.index(name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 先算像素宽高再归一化中心坐标用两端点相加除2 box_w xmax - xmin box_h ymax - ymin cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w box_w / img_w h box_h / img_h # 越界保护归一化值限制在0~1区间 cx, cy min(max(cx, 0), 1), min(max(cy, 0), 1) w, h min(max(w, 0), 1), min(max(h, 0), 1) lines.append(f{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) if lines: out_path Path(out_dir) / (Path(xml_path).stem .txt) out_path.write_text(\n.join(lines) \n, encodingutf-8) # 批量转换 xml_dir Annotations out_dir labels Path(out_dir).mkdir(exist_okTrue) for xml_file in Path(xml_dir).glob(*.xml): convert_voc_to_yolo(str(xml_file), out_dir)脚本逻辑说明先读XML里的图片宽高再遍历每个object把像素坐标转成归一化中心坐标和宽高。三个关键点——第一中心坐标先算两端点平均值再除以图宽第二类别映射表的id顺序必须和后续data.yaml的names一致第三越界保护把数值clip到0到1之间防止标注框略微超界导致训练时loss异常。另外未注册的类别会被跳过并打印提示这么设计是为了在批量转换时把类别名不统一的问题暴露出来而不是悄悄漏掉。参数说明CLASS_NAMES要按你数据集的XML实际内容改顺序定了就不要动图片宽高从XML的size节点读不能假设所有图片同尺寸工地监控多视角抓拍的数据集里分辨率经常是混合的1280x720和1920x1080混在一起很常见。2.4 自检工具图片、XML、TXT三方交叉核对格式转完了不一定是干净的。经验是写一个自检脚本把图片文件、XML文件、TXT文件做三方交叉比对找出三类典型问题有图无标签、有XML无TXT、标签类别id越界。这个脚本每次拿到新数据集都会跑属于开工前的固定动作from pathlib import Path img_dir Path(images) label_dir Path(labels) xml_dir Path(Annotations) img_stems {p.stem for p in img_dir.glob(*)} label_stems {p.stem for p in label_dir.glob(*.txt)} xml_stems {p.stem for p in xml_dir.glob(*.xml)} print(图片数:, len(img_stems)) print(txt数:, len(label_stems)) print(xml数:, len(xml_stems)) print(有图无txt:, len(img_stems - label_stems)) print(有xml无txt:, len(xml_stems - label_stems)) print(有txt无图:, len(label_stems - img_stems)) # 检查txt中类别id是否越界 bad [] for txt in label_dir.glob(*.txt): for line in txt.read_text().strip().splitlines(): cls int(line.split()[0]) if cls 3: # 3类数据集id只能是0,1,2 bad.append((txt.name, cls)) print(类别id越界样本:, bad[:10])这段脚本先用集合做差集一次性找出图片和标签对不上的文件再逐行扫TXT检查类别id是否越界。三个检查是训练前必须过关的关卡——有图无TXT意味着图片被当成了负样本有XML无TXT说明转换脚本漏了或图片本身损坏类别id越界说明标签和训练配置里的nc对不上。任何一个问题不处理就开训后面排查起来都不是一小时能解决的。经验在确认数据干净之前不要开训练越早停手越省时间。第5章会把标签越界、样本不均衡这些坑单独拎出来细讲。3. 用YOLOv8跑通3065张工地图data.yaml配置与训练参数详解数据检查完下一步是把数据集接到YOLOv8里训练。这个环节最常见的问题是路径配错、names顺序和标签不一致、训练参数不适合3065张这样的中小规模数据集。下面按配置到命令的顺序过一遍。3.1 数据目录怎么摆训练脚本才不会报错YOLOv8对数据目录没有绝对强制的结构但训练脚本是按data.yaml里的path去拼接路径的所以目录组织越规整越不容易出错。常用的组织方式是把图片和标签分开放各带train和valdataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/train和val的划分比例一般按8:2做3065张图留600张左右当验证集剩下2400多张训练单卡也能跑动。划分时有个讲究如果是视频抽帧的工地监控数据不能随便随机打乱要按监控场景划分——同一个机位的帧要么全进train要么全进val否则验证集会混入和训练集高度相似的帧指标虚高。这一点第5章的5.3节还会专门展开。如果拿到的压缩包没有按train/val分目录需要先手动建目录、用脚本挪文件。我一般按场景编号或者拍摄时间段来分保证同一场景不跨集合。具体划分脚本不复杂但核心是分组的依据必须是场景而不是单张图片的随机抽签。3.2 data.yaml的三个坑path、nc、namesdata.yaml是YOLOv8训练的核心入口配置错了训练半天全白费。针对这个数据集的data.yaml写法如下path: /data/construction_safety # 数据集根目录建议写绝对路径 train: images/train val: images/val nc: 3 names: 0: hardhat 1: person 2: vest参数说明path必须是绝对路径YOLOv8对相对路径的解析在不同版本里有差异写绝对路径最稳train和val填的是相对于path的图片目录要填到train/val这一层不是图片根目录nc是类别数这个数据集是3names的索引顺序必须和第2章转换脚本里CLASS_NAMES的顺序一致0对0、1对1错一个模型学出来的就是错位标签。提示names列表的顺序一旦定下来转换脚本和data.yaml必须同步。改任何一个都要检查另一个这是工地数据集里最容易翻车的位置。很多人在names上翻车写成中文安全帽反光衣行人YOLOv8本身能显示中文类别名但names里存的字符串同时用于匹配训练时的类别id中文字符串在后续推理和部署转ONNX时容易出编码问题而且和转换脚本里的英文类别名对应不上。统一用英文是最省事的方案。3.3 训练参数怎么设imgsz、batch、epochs与patience3065张图不算大型数据集参数不需要像大模型那样激进。用下面这组起步参数消费级显卡也能跑yolo detect train \ modelyolov8n.pt \ dataconstruction_data.yaml \ imgsz640 \ batch16 \ epochs100 \ patience15 \ workers4逐项说明modelyolov8n.pt是nano版本参数量最小先跑通流程imgsz640是YOLOv8默认输入尺寸工地监控抓拍虽然常见1280x720甚至更高分辨率但模型内部会做resize640对中远距离行人和安全帽已经够用想在小目标上追精度再试imgsz960代价是显存占用翻倍batch16在8G显存上用yolov8n没问题显存只有6G就改成8epochs100配合patience15连续15个epoch验证集指标不涨就早停不会白白烧时间workers4是数据加载线程数Windows上报错就改成0。这里有个和数据集体量相关的判断3065张图不算大yolov8n从预训练权重开始一般30到50个epoch就能看到mAP曲线平稳。如果50个epoch后mAP还在明显上升优先检查是不是类别样本太少或标注噪声大而不是继续加epoch。曲线不收敛八成是数据问题不是训练时长问题。3.4 单卡怎么最省事地跑起来最小可复现命令环境没装YOLOv8的话先花两分钟装好pip install ultralytics训练就执行上一条yolo命令。训练结束后权重默认存在runs/detect/train/weights目录下best.pt是验证集指标最好的权重last.pt是最后一轮的权重。部署和测试一律用best.ptlast.pt只是用来断点续训的。如果你拿到的版本只有VOC标签或者想重新划分train/val用第2.3节的脚本把XML统一转成TXT再按3.1节的目录结构摆放。Ultralytics也提供了格式转换工具但建议自己跑一遍转换脚本原因很简单自跑一遍能顺带发现类别名不统一、坐标越界这些问题交给工具一把梭出问题时反而更难定位。训练时还可以加上数据增强参数。对工地监控场景我会额外设置yolo detect train \ modelyolov8n.pt \ dataconstruction_data.yaml \ imgsz640 \ batch16 \ epochs100 \ patience15 \ scale0.5 \ fliplr0.5scale0.5控制训练时随机缩放范围对行人、安全帽的尺度变化有帮助工地监控里近处大目标、远处小目标并存这个参数值得开。fliplr是水平翻转概率0.5是常规值。反光衣、安全帽、行人这类目标不受左右方向语义影响水平翻转是安全的如果换成人脸朝向、车辆朝向这类带方向语义的任务fliplr反而会干扰学习。超参数不用照着抄理解每个参数为什么这么设再按自己显卡调整。YOLOv8训练这类数据集的规律是数据干净程度大于样本均衡大于输入分辨率大于模型大小大于超参数微调。把前几项做好效果差距不在超参数上。4. 结果评估mAP、混淆矩阵与漏检分布怎么看训练跑完不代表模型能用。验证集上的指标、混淆矩阵里的热点、holdout场景上的表现三者结合才能判断这个模型能不能上工地。这一章按看结果的顺序展开。4.1 验证集上的三项指标精度、召回、mAP0.5训练结束后YOLOv8会自动在验证集上评估控制台和results.csv里会给出足够的指标。最常用的三个precision精度衡量检测出的框里真正是目标的占比。recall召回衡量所有真实目标里被找回来的占比。mAP0.5是IoU阈值取0.5时所有类别的平均精度。对工地安全场景安全帽和反光衣漏检的代价远高于误检所以recall比precision更要紧。mAP0.5到0.85以上精度比召回低0.1左右这个模型用于自动巡检告警是能接受的如果mAP0.5只有0.6上下不要急着调参先回去看标签和划分数据层面出问题的概率更大。如果还要看更严格的标准YOLOv8会同时输出mAP0.5:0.95这是把IoU阈值从0.5到0.95每隔0.05计算一次再取平均。工地场景的框普遍偏大mAP0.5和mAP0.5:0.95的差距通常在0.15到0.25之间。如果两个值差得特别大说明模型框的定位精度不够常见原因是标签的边界框本身就标得不准而不是模型能力问题。这个指标在对比yolov8n和yolov8m时很有参考价值nano和medium的差距往往主要体现在这个值上。4.2 混淆矩阵读出类别混淆反光衣到底在跟谁打架YOLOv8的验证输出里有confusion_matrix.png这是最先看的图比mAP数字更有信息量。混淆矩阵的行是真实类别列是预测类别对角线是正确预测。对这个三分类安全检测数据集两个常见问题都能从矩阵里直接读出来一是反光衣和普通行人互相混淆。工地监控里黄色或橙色的反光衣在正常光照下很明显但工人背对镜头或反光衣被外套遮住大半时模型容易把反光衣框到行人类。矩阵里反映为vest行在person列有非零值。处理办法不是加epoch是检查这些样本的真值标注——很多数据里工人反光衣没拉拉链的图标注员直接标了person而不是vest这类标签噪声在混淆矩阵里一眼就能看出来。二是安全帽和背景混淆。矩阵右下角是背景类安全帽尺寸小多视角抓拍下远景工人的安全帽只有几十个像素模型倾向于把这种小目标判成背景。矩阵里表现为hardhat行在background列有非零值。这个问题的方向不是调参数是考虑加大输入尺寸或在训练时用mosaic增强把小目标比例提上来。注意YOLO的混淆矩阵图里每一行求和不一定等于1。很多刚上手的人看到hardhat行加起来不是1就以为图错了其实这是正常现象——置信度阈值以下的预测被归入背景类且不同版本的归一化方式有差异。看矩阵时重点看非对角线上的热点不是纠结行和。4.3 按场景抽帧验证效果避免高估工地现场表现验证集mAP高不代表现场好。工地监控数据集是多视角多场景抓拍如果train和val是从同一段监控视频里抽的帧相邻帧几乎一样模型等于见过验证集指标自然虚高。验证模型能不能上场标准动作是单独留一批没参与训练的场景或时间段yolo detect predict \ modelruns/detect/train/weights/best.pt \ source./holdout_scene/ \ conf0.25 \ save_txtTrue \ save_confTruesource指向一个单独隔离的验证目录里面放和训练集不同时段、不同机位的监控抓拍conf0.25是默认置信度阈值预测TXT落在runs/detect/predict/labels下每行是class_id cx cy w h加上conf置信度。然后用脚本把预测框和真实框比对统计不同距离、不同光照条件下的漏检分布。如果现场反馈白天还行傍晚反光衣漏检厉害那就去统计预测结果里置信度低于0.3的框看是不是集中在傍晚样本上。这说明训练集里低光照正样本太少下一步是补充傍晚和逆光场景的样本而不是把conf调低——把conf调低只能提高召回同时会带来大量误检工地告警场景误检会把报警通道刷爆。5. 训练工地安全检测数据的五个常见问题与排查训练这类智慧工地数据集翻车点相对固定。把下面五条按现象、原因、解决的顺序写清楚每一条都是实际跑数据时踩过的坑。5.1 训练到一半loss变成nan或训练中断现象loss曲线在某个epoch突然掉到nan或者训练进程直接中断重启后仍复现。原因标签坐标越界是首要嫌疑。VOC转YOLO时归一化算错TXT里出现cx、cy超过1的坐标部分YOLO版本计算loss时直接算崩也就是常说的bn崩溃——loss正常跑几十个epoch后突然爆掉根源往往是输入侧混入了异常像素或越界坐标。另一个常见原因是数据里有损坏的图片文件解码出来是空图数据加载器把异常值送到loss里。解决训练前先跑第2.4节的自检脚本过滤越界标签和损坏图片。训练中出现nan先看日志里最后加载的batch对应哪几张图直接定位到具体文件删除或修复后从断点续训。5.2 反光衣和安全帽类别标签混乱现象训练完后混淆矩阵里vest行和hardhat行在彼此位置有明显热点推理时把黄色安全帽识别成反光衣。原因黄色安全帽和黄色反光衣在低分辨率监控画面下颜色特征接近标注员框边界时标准不一致。更典型的是工人弯腰作业时反光衣和安全帽叠在一起两个框几乎重合转换脚本没处理重叠训练时同一个像素位置被两个类别同时监督模型学得两头摇摆。解决写一个脚本把IoU超过0.7且类别不同的框对挑出来人工复查。重叠框如果确实属于安全帽戴在反光衣上方保留面积更明确的那个框删掉另一个不要两个都留。这类标签噪声修完混淆矩阵里的热点会明显消退。5.3 验证集指标虚高现场效果却翻车现象验证集mAP0.5到0.9拿到工地现场试跑漏检一大堆尤其远处行人和侧面安全帽。原因数据集划分方式有漏洞。如果按视频帧直接随机划分train和val同一场景的相邻帧一个进了训练集一个进了验证集模型等于开卷考试。3065张抓拍图如果不按场景隔离划分这个坑出现的概率极高。解决按监控机位、日期、时段划分而不是按帧划分。先把数据来源的拍摄场景列成清单每个场景的图要么全部进train要么全部进val再训练一次对比。调整后真实mAP可能比原来低5到10个点这个数字才是能上线的预期。5.4 安全帽类别样本太少recall上不去现象三个类别里hardhat的recall明显低于其他两类val曲线里安全帽对应的损失波动大。原因多视角工地抓拍通常是行人占大面积、反光衣次之、安全帽集中在头部区域一张1280x720的图上安全帽可能只有40x40像素。样本数量少加目标尺寸小模型没法学好。解决第一步统计三个类别各自的框数量如果安全帽框数低于其他类别一半考虑mosaic增强和小目标复制粘贴增强。第二步把imgsz从640提到960batch等比下调。如果还不行在训练命令里给hardhat类别单独加class权重比如class[1.0, 1.0, 2.0]让模型对安全帽的误检更敏感。5.5 训练集和验证集有重复图片或近似重复帧现象训练完val指标非常漂亮但用best.pt去跑一张训练集里没出现过的同机位图效果明显缩水。原因视频抽帧数据集去重不干净同一时段同一机位抓到的帧几乎一样文件名不同但内容重复。这类数据跨train和val等于验证集泄漏还会让模型过拟合到具体场景的纹理上。解决抽帧按时间间隔而不是连续帧比如每3秒抽1帧训练前用感知哈希计算图片相似度相似度超过0.95的帧聚成一组保证同一组只落在同一个集合。最后用4.3节的holdout场景验证把这个流程固化成每次训练的固定动作能提前拦住绝大多数指标虚高问题。6. 从离线训练到现场告警反光衣与安全帽检测的三个进阶技巧模型在验证集上达标了距离真正部署到工地监控还有一段路。说三个实际项目里验证过有效的进阶做法。第一重新按场景划分后对比不同模型尺寸。如果前面已经按第4、5章验证过建议把train/val按机位时间段重新划分跑一轮完整训练这次把yolov8n换成yolov8m。3065张数据也能支撑中等模型mAP0.5:0.95通常会比nano高3到5个点。工地监控机位固定推理端转成TensorRT后单帧检测可以压到20毫秒以内medium模型照样能扛住实时告警。第二针对反光衣的时段差异做颜色增强。工地反光衣在正午强光和傍晚弱光下的颜色表现差异极大HSV增强里把饱和度与色调扰动加大能让模型对反光衣在不同时段下的色差更鲁棒。一组实测可用的参数yolo detect train \ modelyolov8m.pt \ dataconstruction_data.yaml \ imgsz960 \ batch8 \ epochs80 \ hsv_h0.02 \ hsv_s0.8 \ hsv_v0.5hsv_h0.02控制色调扰动幅度0.02对黄色这类敏感色相是安全的不会把黄色安全帽拧成红色hsv_s0.8把饱和度扰动拉大模拟阴天和强光下的颜色衰减hsv_v0.5让亮度变化更剧烈解决傍晚逆光下反光衣变暗的问题。这三个值对安全帽这种小目标也友好不会引入过多噪声。第三部署阶段的置信度策略不能用一刀切。工地安全巡检的告警逻辑里安全帽漏检属于事故级错误单独把hardhat类别的conf阈值降到0.15vest降到0.25person保持0.35——每个类别独立设阈值再用告警二次确认消化误检比全局调一个conf实用得多。我自己在工地数据上最深刻的一次教训拿到这类数据集第一周我全在调参mAP始终卡在0.7上不去。后来停下来花两天把标签逐一检查发现大约12%的框存在类别错标和边界偏移。把标签修干净之后同一套参数mAP直接跳到0.85。从那以后我拿到任何数据集第一件事永远是检查标签而不是开训练。先把标签当回事模型才会给你一个好的结果。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网