
简介YOLO安全帽检测数据集面向目标检测与计算机视觉学习者可用于训练和验证YOLOv5/YOLOv8模型识别戴安全帽与未戴安全帽两类目标。标注覆盖室内、室外、人群等多种常见场景并附带yaml配置文件方便直接开展模型训练与测试。资源压缩包为zip格式共2000个文件其中1999个txt标注文件、1个yaml配置文件包体约900MB。已有367人学习下载。标注由作者手工完成在YOLOv5和YOLOv8上实测mAP0.5达0.9以上适合需要高质量安全帽检测数据的算法工程师、科研人员及竞赛选手可减少数据清洗与标注时间直接用于模型训练和效果验证。1. 6000 张安全帽数据集能做什么YOLO 目标检测的落地价值与真实边界工地安全帽检测是目标检测里最典型的小目标、高遮挡、实时性三难场景。监控画面里的工人通常只占几十像素高安全帽往往只有十几个甚至几个像素很多开发者以为下载一个现成的 YOLO 预训练模型就能直接上线结果在真实工地上漏检、误报接连不断。真正决定项目成败的不是模型选型而是数据集——标注规范、场景覆盖、类别平衡这三件事没做好再新的 YOLO 版本也救不回来。这篇笔记围绕6000 张图片的安全帽检测数据集 YOLO 目标检测这条技术路线完整拆解从采集、标注、训练到部署验证的过程。6000 张图在工业数据集里不算大但场景铺得开、框标得准足以训练出一个能在现场使用的模型反过来图再多、质量参差不齐换个工地就翻车。适合两类人看一是要给工地、工厂、园区做安全监管系统的开发者二是刚接触计算机视觉、想用真实场景练手的学习者。如果你已经能把 YOLO 跑通但效果不理想建议直接从第 5 章踩坑记录看起。2. 安全帽检测为什么首选 YOLO从检测原理到标注格式的底层逻辑2.1 单阶段检测器在工地场景的三个优势速度、小目标、易部署YOLO 是单阶段目标检测器图片输入后只走一次前向推理同时输出所有目标的类别和边框。对比两阶段检测器——先产生候选区域、再对每个区域分类——YOLO 把两步合并成一步代价是候选框质量的理论上限略低换来的却是推理速度和工程复杂度的明显下降。安全帽检测的部署场景通常是工地出入口的固定摄像头或球机一个现场可能需要同时分析几十路画面实时性要求 25 FPS 起步这个算力账用两阶段结构很难算平。第二个优势是多尺度特征融合。YOLO 在不同下采样倍率的特征图上并行预测大尺寸特征图比如 80×80 网格上的每个格子对应原图更小的区域天然适合捕捉小目标。安全帽在监控画面里经常只有 20×20 像素恰好落在高分辨率特征图的管辖范围内。相比之下很多基于区域提议的检测器会把小目标的细节特征在下采样过程中弄丢需要额外做特征金字塔的精细调优。YOLO 的做法更直接把输入分辨率从 640 提到 1280小目标召回率肉眼可见地上升这种调参即见效的特性非常利于现场排障也是我在安全帽项目里愿意优先选它的原因。第三个优势是部署链路的成熟度。YOLO 生态几乎覆盖了从训练到上线的全部工具训练完的权重可以导出 ONNX、再转成 TensorRT 引擎或者做 INT8 量化跑在边缘盒子上。安全帽项目绝大多数要落在工地的本地服务器或边缘设备上GPU 算力有限YOLO 的轻量型号n/s 系列在 CPU 上也能勉强达到准实时这让项目从原型到交付的周期比其他检测框架短得多。另外YOLO 社区里针对小目标、遮挡等场景的衍生资料非常多踩坑时能找到大量对照经验。2.2 标注格式选型YOLO txt 与 COCO JSON、VOC XML 的关键差异YOLO 训练要求每个图片对应一个同名 txt 文件每行一条目标记录类别ID、中心点横坐标、中心点纵坐标、框宽、框高数值全部归一化到 01 之间。举例说明一行0 0.5132 0.2718 0.2100 0.1800的含义是类别 0安全帽的边框中心位于图片水平方向 51.32% 的位置、垂直方向 27.18% 的位置边框宽度占图片宽度的 21%高度占图片高度的 18%。这种格式之所以成为工程首选是因为它不携带冗余元数据训练时做随机裁剪、缩放等数据增强只需要按同样的比例换算坐标逻辑最简单出错面最小。COCO 格式用一个 JSON 文件描述全部图片和标注信息坐标一律用像素绝对值还附带目标的 segmentation 多边形和 area 字段VOC 格式则每张图一个 XML 文件同样是像素绝对坐标。COCO 是学术评测的事实标准很多开源模型的预训练数据都是这个结构VOC 则被早期的开源标注工具广泛采用。区别的本质在于COCO/VOC 面向统一描述复杂标注YOLO txt 面向单一场景、高速读取、易做增强。三者的对比如下格式坐标表示组织方式使用场景YOLO txt归一化每图一个 txtYOLO 训练默认读取与增强最快COCO JSON像素绝对值全量一个 JSON学术评测、多任务数据集标准VOC XML像素绝对值每图一个 XML早期标注工具默认格式在实际项目里先拿到 VOC 或 COCO 格式的数据再转 YOLO 是常态。下面是我常用的一个 VOC XML 转 YOLO txt 脚本足够应付大部分标注工具产出的文件import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_dir, class_map): tree ET.parse(xml_path) root tree.getroot() img_w float(root.find(size/width).text) img_h float(root.find(size/height).text) lines [] for obj in root.findall(object): cls obj.find(name).text if cls not in class_map: continue # 未登记类别直接跳过避免崩溃 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 角点坐标转中心点宽高再做归一化 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_map[cls]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_path os.path.join(out_dir, os.path.splitext(os.path.basename(xml_path))[0] .txt) with open(out_path, w) as f: f.write(\n.join(lines)) class_map {helmet: 0, head: 1} # 0戴帽人头, 1未戴帽人头 voc_to_yolo(sample.xml, labels, class_map)这段代码的逻辑分三块先读取 XML 里的图片宽高和所有目标然后逐个把 里的 xmin/ymin/xmax/ymax 角点坐标换算成中心点格式最后除以图片宽高得到归一化数值写入 txt 文件。参数方面class_map 的 key 必须和 XML 里 的文本完全一致比如标注工具写的是 Helmet 而映射表里是 helmet目标会被静默丢弃标注量越用越少——这类问题不报错只能靠事后抽检发现。提示转换脚本跑完后随机抽 5 张图把 txt 里的坐标画回图上肉眼核对一遍确认类别和框位置都没问题再进入训练。转换完成后要抽检三件事一是坐标是否越界部分标注工具的框会超出图片边界导致 w 或 h 大于 1二是类别 ID 是否从 0 连续编号跳号会让配置文件和标签错位三是 txt 文件名是否和图片文件名前缀完全一致YOLO 通过同名匹配建立对应关系后缀不一致会直接报找不到标注。2.3 6000 张图片的样本量够不够类别平衡与场景覆盖的判断标准6000 张这个规模在目标检测数据集里属于够用但必须精打细算。我评估数据集时第一个看的是实例数而不是图数。按工地监控平均每张图 23 个有效人头计算6000 张图大约对应 1200018000 个目标实例这个量级足够让模型学到安全帽的颜色、形状和典型遮挡关系前提是类别别偏得太离谱。类别设计上安全帽检测的普遍做法是两类0 号类 helmet 表示佩戴安全帽的人头区域1 号类 head 表示未佩戴的人头区域。模型一次推理直接把违规目标框出来后处理不需要再做人头框和安全帽框的重叠匹配。也有团队只标安全帽一个类另配一个人头检测模型用两套框的 IOU 判断是否违规——这种方式在单模型精度不足时确实更稳定但它要求两个模型都训练到位工程量接近翻倍。对 6000 张图的规模我倾向于单模型两类后处理简单部署也轻。场景覆盖是比图数更硬的指标。6000 张如果全部来自同一个工地同一个机位模型可能只需要记住那个固定背景就能刷出极高验证分换到新工地立刻崩盘。我一般的底线要求是至少 5 个不同来源场景每个场景的图片按时间抽帧而不是连续帧全采否则同一监控视频里相邻帧背景几乎一样等于变相重复样本。光照方面正午顶光、黄昏逆光、夜间红外补光三种情况至少要各覆盖一批——安全帽在不同光线下颜色偏移非常大黄色安全帽在黄昏和正午呈现的特征差别足以让模型产生系统性漏检。3. 构建安全帽数据集图像采集、标注工具、划分策略与目录组织3.1 采集阶段的多样性控制机位、光照、遮挡三个维度怎么铺开安全帽检测的数据采集本质上是在三个维度上做正交覆盖机位角度、光照条件、遮挡程度。机位角度里最常见的是监控俯视角摄像头装在大门或塔吊高位向下 3060 度俯拍其次是手持或巡检设备拍摄的平视角视角不同安全帽呈现的椭圆形态差异很大。我见过不止一个项目只采集俯视角训练出来的模型在平视角测试视频上漏检率翻倍原因就是平视角下帽檐形状和俯视差异太大模型没见过。光照维度要拆成三个硬场景正午强光、黄昏逆光、夜间红外补光。正午强光下安全帽高光过曝黄色安全帽容易整体发白黄昏逆光下人头区域变成剪影帽子的色相特征几乎消失夜间红外补光下画面变成灰度颜色完全无法作为依据模型只能依赖形状和边缘。如果项目要求 7×24 小时运转这三个光照段必须出现在训练集里。遮挡维度则包括安全帽被脚手架钢管遮挡、戴帽后再抬手遮挡、远处人群重叠等这些场景决定了模型在真实工地上的鲁棒性。采集阶段的具体做法常见的是从工地现有的录像系统抽帧再配合现场手机补拍。抽帧时不要连续帧全采我通常按每 5 秒抽一帧再按 8:2 比例从白天的不同时段各采一部分。负样本也要单独采一批纯背景图——空无一人的基坑、堆满黄色管道和油漆桶的角落、挂着黄色安全网的外墙这些图不包含任何目标专门用来压制误检。6000 张总量里我建议至少 500 张是不含目标的负样本背景图。3.2 用标注工具产出 YOLO 格式标注规范与导出检查标注阶段我常用的工具是支持 YOLO 格式导出的开源标注器操作不复杂加载图片目录按快捷键切换上一张下一张鼠标拖拽画框选择类别保存即得到同名 txt。比起直接用文本编辑器写坐标图形化标注最大的价值在于框的紧贴度可以人工控制。规范要一开始就定死安全帽的框紧紧包住帽体不要把人脸和肩膀画进去未戴帽人头框包住整个头部轮廓。两条类别的框如果画得太松模型学出来的框就会偏大部署后做违规判断时边界会很模糊。多人重叠场景也要有统一规则前面人的安全帽和后面人的头部只要肉眼可分就分别标注如果目标被遮挡超过一半跳过不标。规则不统一是最隐蔽的坑同一个数据集两个人执行两套标准模型学到的框分布会撕裂。标注完成后务必用脚本检查一遍类别分布和框尺寸分布我常用的检查脚本如下import os def inspect_labels(label_dir): class_cnt {} tiny 0 total 0 for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f), r) as fp: for line in fp: parts line.strip().split() if len(parts) 5: continue # 空行或残缺行跳过事后人工复查 cls int(parts[0]) w float(parts[3]) h float(parts[4]) total 1 class_cnt[cls] class_cnt.get(cls, 0) 1 if w * h 0.01: # 框面积小于原图1%记为小目标 tiny 1 print(类别统计:, class_cnt) if total 0: print(小目标占比: {:.1f}%.format(tiny / total * 100)) inspect_labels(labels)脚本做了两件关键事情统计每个类别的标注数量暴露类别失衡统计小目标框面积占比小于 1%的比例如果小目标占比超过 30%训练时必须把输入分辨率调大否则这批标注等于白标。细节上有几个注意点行内字段不足 5 个说明标注文件被中途写坏这类文件要返回去重新导出小目标阈值 0.01 是按面积占比算的和图片原始分辨率无关可以统一适应不同来源的图片。输出结果里如果某个类别数量为 0说明类别映射写错了要立刻查配置而不是往下训练。3.3 数据集划分按场景划分比按图片随机划分更可靠数据集划分是安全帽项目里最容易被低估的一步。很多人习惯把所有图片混在一起按 8:1:1 随机切分为训练、验证、测试三份这在纯公开数据集上问题不大但在工地采集数据上会埋雷同一个工地同一个机位抽出来的几百帧背景几乎一致随机划分后相似的帧会同时出现在训练集和验证集里验证指标一路虚高模型上线换一个工地就崩。正确的做法是先把所有图片按来源场景分组再以场景为最小单位划分。我一般按 8:1:1 的比例在场景层面划分如果一共有 10 个工地场景训练集用 8 个验证集和测试集各用 1 个保证验证集里的工地模型从未见过。如果场景数量不够至少也要按时间片划分——同一个工地的录像前 70% 时间进训练后 30% 进验证而不是随机抽帧混合。这一条直接决定了你看到的 mAP 是真实能力还是记忆训练集。目录组织上用下面的结构最省心helmet_data/ ├── data.yaml ├── images/ │ ├── train/ # 约4800张 │ ├── val/ # 约600张 │ └── test/ # 约600张 └── labels/ ├── train/ ├── val/ └── test/images 和 labels 的 train/val/test 子目录名称必须完全对应图片和标签只靠文件名前缀关联。强调一点test 目录在训练阶段不要碰它只用于最终验证。很多人训练时就忍不住去看 test 指标看多了就会照着 test 调参等于把 test 集变成了 val 集最后的评估就完全失真了。4. 用 YOLOv8 训练安全帽检测模型从 data.yaml 到评估指标的最小可复现路径4.1 配置文件与目录结构data.yaml 的写法与路径陷阱在 YOLO 生态里训练第一步不是写模型代码而是写数据集配置文件 data.yaml。这个文件声明数据集的根目录、训练/验证/测试图片路径、以及类别名称列表。安全帽检测场景下常见的配置如下# 安全帽检测数据集配置 path: ./helmet_data # 数据集根目录相对当前工作目录 train: images/train # 训练图片子目录 val: images/val # 验证图片子目录 test: images/test # 测试图片子目录可选训练不会用到 names: 0: helmet # 戴安全帽的人头 1: head # 未戴安全帽的人头path 字段是这里最大的坑。YOLO 框架解析 data.yaml 时train/val 路径是相对 path 拼接的如果 path 写成绝对路径换机器就要改文件如果写成相对路径又依赖启动时的当前工作目录。我习惯在项目根目录下统一执行所有命令data.yaml 里用相对路径整个项目拷到别的机器上不用改配置。names 的索引必须和标注 txt 里的类别 ID 一一对应安全帽检测的 0/1 顺序建议固定下来不要中途对调否则训练好的模型在后处理代码里也要同步改。注意换机器跑训练时data.yaml 的 path 用相对路径可以省掉一多半路径报错用绝对路径的话每换一台机器都要改一次配置。另一个常见问题是图片和标签缺失不报错。训练启动时框架只扫描图片如果某张图片没有对应的 txt 标签文件不会中断而是把这张图当作纯背景图参与训练。这本身不是坏事——等于免费加了负样本但如果批量转换标注时把部分 txt 生成漏了模型会额外学习没有标签的图就是背景对后续小目标检测有害。启动训练前先跑一遍标签完整性检查图片目录下的文件数和标签目录的文件数要对得上。4.2 训练命令解读epochs、imgsz、batch 等关键参数的调法配置就绪后用命令行启动训练。以 YOLOv8 的 CLI 为例一套安全帽检测常用的训练命令如下yolo detect train \ datahelmet_data.yaml \ modelyolov8s.pt \ epochs120 \ imgsz1280 \ batch16 \ lr00.01 \ patience20 \ device0 \ projectruns/helmet \ nameexp1每个参数在安全帽场景下的选型逻辑值得单独说。modelyolov8s.pt 表示从预训练权重继续训练这里用 s 级而不是最大的 x 级是因为安全帽项目的部署端算力通常有限训练时选 s 可以避免最后压缩模型带来的精度落差如果验证集 mAP 未达标再换 m 或 l 级不要一开始就上最大模型。epochs120 是安全帽小数据集的合理范围6000 张图 120 轮训练时间可控配合早期停止机制防止过拟合。imgsz1280 是关键参数安全帽属于小目标640 分辨率下边框只有十几个像素信息量太少1280 能把小目标的有效特征尺寸翻倍。batch16 由显存决定如果训练时报 CUDA out of memory先把 batch 降到 8 或 4不要同时降 imgsz否则小目标优势会丢掉。lr00.01 是默认学习率6000 张图规模下通常不用动偶尔遇到 loss 震荡可以降到 0.005。patience20 表示连续 20 轮验证集指标没有提升就提前结束防止无效训练浪费时间。device0 指定第一块 GPU没 GPU 时去掉这项纯 CPU 训练 6000 张图会很慢通常要过夜但不影响结果正确性。我还有一个常用的习惯先用 imgsz640 快速跑 30 个 epoch 验证数据集流程是否跑通确认类别 ID、路径、标签都正确后再正式用 imgsz1280 跑全量。这个两步法能省掉大量因低级错误导致的重复训练时间。4.3 评估指标怎么算合格mAP50、Precision、Recall 在安全帽场景的解读训练结束后YOLO 会在验证集上输出一组指标安全帽场景主要看 mAP50 和 mAP50-95以及每个类别的 Precision 和 Recall。mAP50 是指预测框与真实框的 IOU 大于 0.5 即算命中时的平均精度安全帽检测因为框都很小IOU 0.5 的判定相对宽松通常 mAP50 达到 0.85 以上才说明模型对目标找到了、且大致定位准。mAP50-95 把 IOU 阈值从 0.5 到 0.95 做了平均对安全帽这类小目标非常苛刻——一个 20×20 像素的帽子框偏移 2 个像素就会把 IOU 拉低很多。安全帽项目的 mAP50-95 有 0.5 已经算健康不必追求学术榜单上的 0.7盲目用更大的模型去硬追 mAP50-95容易在部署端陷入算力困境。Precision 和 Recall 要分开看业务含义Precision 高代表误报少如果系统报警后需要安全员去现场核实误报多了会产生狼来了效应这类场景要求 Precision 0.9 以上Recall 高代表漏检少如果项目定位是事后追责漏检的代价更大Recall 应压到 0.85 以上。常用的指标参考范围如下表但最终阈值要结合现场验证结果调整指标可接受下限说明mAP500.85达标线低于此值先找数据问题mAP50-950.5小目标定位精度参考不宜硬追Precision0.9误报敏感场景优先看Recall0.85漏检敏感场景优先看还有两类输出要习惯性去看训练生成的 confusion_matrix.png 要重点看 helmet 和 head 两个类之间有没有大面积互混互混意味着标注边界本身就含糊需要回头统一标注规范results.png 里如果 val_loss 曲线在后期回升而 train_loss 还在下降就是过拟合信号此时不是加训练轮数而是减少训练轮数或加大数据增强。提示confusion_matrix.png 里如果 helmet 与 head 互相混淆严重优先回头统一标注规范而不是急着加深网络。5. 安全帽检测训练与部署避坑五个高频翻车点与排查方法5.1 远距离小目标漏检安全帽在图里只有十几个像素怎么办现象监控画面里远处的工人人眼能看出戴了帽子但模型就是没框出来把同一张图放大看安全帽大约只有 12×12 像素。这类漏检集中在画面远端和球机变焦后的广角段。原因输入分辨率不够和数据增强不当叠加导致。imgsz640 时12×12 像素的帽子经过下采样后只剩很小的特征响应模型没有足够信息区分黄色圆形和噪声mosaic 增强会把多张图缩放到同一画布小目标被进一步缩小有些在增强后甚至不足 4 像素直接被杀掉。解决把 imgsz 提到 1280这一步通常能显著提升远端召回。如果显存不够对视频远端区域做 ROI 裁剪后再送检测或者用切片推理把画面切块放大分别检测。数据层面对小目标图片做单独增强把尺寸较小的安全帽复制到场景空白区域产生更多小目标样本。我见过一个项目仅把 imgsz 从 640 改到 1280远端漏检率直接下降一半这是性价比最高的一步调整。5.2 误检成灾黄色油漆桶、圆形标志被当成安全帽现象模型在纯背景图或无人堆料区频繁输出安全帽框工地安全网、球形路灯、圆形警示牌都能触发报警。这类误检在算法演示阶段极其难看也容易让现场安全员失去对系统的信任。原因安全帽的正样本里黄色帽占绝对多数模型实际学到的特征是黄色 圆形 小尺寸的组合而不是位于人头上的帽子。加上训练集背景单一模型对场景里什么位置该出现帽子完全没有约束。解决采集阶段加入大量负样本背景图且负样本要和正样本场景同源——同样机位、同样光照下无人无帽的画面。训练时不用担心负样本拉低指标YOLO 会正常把无目标的图当作背景参与训练。推理阶段把 confidence 阈值从默认 0.25 提到 0.40.5误检数量通常断崖式下降。如果仍有漏网之鱼再加一条后处理规则安全帽框必须与一个人头候选框有重叠才算有效报警用几何约束把漂浮的帽子全部过滤掉。5.3 验证指标虚高同源场景划分带来的假象现象训练时验证集 mAP50 高达 0.95现场测试却频繁漏检两个指标差得离谱换一个从未参与训练的工地视频测试mAP 直接掉到 0.6 左右。原因划分数据时用了全局随机洗牌同一个工地同一个机位相邻帧的图片被同时分进了训练集和验证集。模型在训练时已经记住了那个背景墙和地面纹理验证时遇到几乎一样的画面等于开卷考试考了原题真正的陌生场景没有参与验证问题被完全掩盖。解决严格按场景分组建模划分验证集必须包含模型从未见过的工地或时间片划分前先打印每组图片的文件列表确认没有跨组混合。同时把第二工地验证纳入项目流程——训练完成后另找一段独立录制的工地视频做野测以野测结果作为验收依据而不是看训练时的验证集 mAP。这条经验我每次都能拦下一些指标好看但现场不行的模型。5.4 类别失衡戴帽样本远多于未戴帽违规目标学不出来现象工地合规率高采集到的绝大多数人头都戴了帽子helmet 类标注了 12000 个head 类只有 1500 个。训练后模型对未戴帽人头的召回率低违规场景漏检严重——而违规检测恰恰是这个项目存在的意义。原因类别失衡导致梯度被多数类主导head 类学到的特征不够有区分度mosaic 这类增强又以随机采样填充画布少数类目标出现的频率被进一步压低。解决先尝试过采样训练时对 head 类所在图片重复采样让每轮 epoch 中少数类目标的出现次数接近多数类。6000 张图的规模下这是最省力的办法。如果过采样后模型仍学不出来就要去补充收集违规样本——找一段时间内违规较多的工地、或者工人在出入口脱帽休息的时段专门采集。不推荐用简单复制小图的方式硬造违规样本会出现大量不合比例的训练数据。训练时还可以给少数类一个更高的类别损失权重但那是最后的微调手段先解决样本来源问题更根本。5.5 部署掉帧训练时没考虑推理端的算力约束现象训练用 l 级模型验证集精度漂亮拿给现场边缘盒子一跑1080p 视频只能跑 5 FPS完全达不到实时。回头换小模型重新训练又发现精度不够陷入两难。原因训练和部署没有在同一套约束下选型。模型参数量和输入分辨率是推理延迟的两个主导因素现场设备的 CPU/内存/散热决定了它跑不动训练时的配置。这更像是一个流程问题而不是技术问题——很多人直到交付阶段才考虑推理端。解决在训练第一天就固定目标部署平台按它反推模型规格和 imgsz。例如边缘盒子只能跑 s 级模型、imgsz 640那就直接用这个配置训练不要在 l 级模型上浪费时间。推理端做 TensorRT 导出和 INT8 量化通常能有 23 倍加速但量化后小目标精度会有损失量化前后要用野测视频重新验证指标。还有一个工程妥协对球机画面做间隔检测每两帧取一帧或者只在人员活动区域做检测、静止区域用帧差法跳过都可以把有效帧率提到实时。6. 把安全帽模型用活的进阶技巧切片推理增强与真实视频验证如果现场远端小目标仍然拉不满召回切片推理是最后一招。它把大图切成 640×640 的切片分别送模型检测再合并结果等效于把每块区域的 imgsz 放大小目标特征显著变清晰。切片时设置合适的切片大小和重叠率检测框会有重复用 NMS 合并即可代价是推理次数成倍增加通常只用于重点区域而不是全画面。模型定稿前我的习惯是用一段真实工地视频做野测而不是只看验证集指标。一个简洁的验证脚本长这样import cv2 from ultralytics import YOLO model YOLO(best.pt) cap cv2.VideoCapture(site_demo.mp4) frame_id 0 violations 0 while cap.isOpened(): ret, frame cap.read() if not ret: break frame_id 1 results model.predict(frame, conf0.4, imgsz1280, verboseFalse) # 取出 head 类未戴帽和 helmet 类戴帽的框 heads [b for b in results[0].boxes if int(b.cls) 1] helms [b for b in results[0].boxes if int(b.cls) 0] for h in heads: hx1, hy1, hx2, hy2 map(float, h.xyxy[0]) overlap False for m in helms: mx1, my1, mx2, my2 map(float, m.xyxy[0]) ox max(0, min(hx2, mx2) - max(hx1, mx1)) oy max(0, min(hy2, my2) - max(hy1, my1)) if ox * oy 0: overlap True break if not overlap: violations 1 print(疑似违规人头数:, violations)这段脚本的逻辑是逐帧推理取出 head 类和 helmet 类的所有框对每个 head 框检查它是否与某个 helmet 框有重叠没有重叠就记为违规。参数上 conf0.4 是推理阈值要和训练时的验证阈值保持一致才有可比性imgsz1280 保证小目标检测能力与训练一致实际项目里可以把 violations 换成逐帧报警回传接入现场安全管理系统。判定逻辑是简化版正式项目还要加上目标跟踪器防止同一个违规人头在连续帧里被重复计数。我个人的教训是安全帽检测这类项目八成的时间应该花在数据而不是模型上。第一次做的时候我把精力都放在换模型和调参数上结果换了个工地就翻车后来才发现是场景划分和负样本的问题。现在我的流程固定成先跑 30 轮小模型验证流程再按场景划分全量数据、补足负样本最后才调参。这套顺序让后面的安全帽项目几乎没有返工过。希望帮到你。本文还有配套的精品资源点击获取