尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

多场景抽烟行为数据集构建与YOLOv8训练实战全流程

多场景抽烟行为数据集构建与YOLOv8训练实战全流程 简介目标检测是计算机视觉的核心任务之一其效果高度依赖于训练数据的场景覆盖与标注质量。在行为识别类应用中数据集不仅需要多角度、多光照、多背景的多样性还需要合理的类别体系与严格的标注规范否则模型难以适应真实环境。高质量数据集结合YOLOv8等主流检测框架能够显著提升小目标与遮挡场景的泛化能力。本文结合安防监控、工地安全等应用场景完整复盘了一个多场景抽烟检测数据集的构建与训练过程涵盖数据采集、清洗、标注、增强、调参与排错为类似行为识别项目提供可复用的工程方法论。 拉过一个多场景抽烟数据集项目从零开始搞定数据到训练模型整个过程踩了不少坑。今天把完整经验写出来从数据采集、标注规范到训练调参、场景适配一次性讲清楚。其实刚开始接手这个项目时我第一反应是直接用开源数据集。但找了一圈发现公开的抽烟检测数据集要么场景太单一要么标注质量参差不齐。有的数据集中在室内固定角度一到室外、夜晚、远距离场景就翻车。后来索性决定自己构建一套覆盖多场景的抽烟行为数据集顺便把整套训练链路跑通。写这篇内容一个是记录另一个是给正在折腾类似任务的朋友提供一份可参考的实操文档。项目标题多场景抽烟行为数据集深度学习数据集先说结论一份高质量数据集的价值远高于调参技巧。模型结构再先进喂进去的数据场景覆盖不够、标注混乱最终上线就是各种误检漏检。这篇我按数据设计、采集、标注、训练、调优、排错几个环节来讲重点是可复现、可落地。1. 项目整体思路与痛点分析1.1 为什么“多场景”会是这个项目的核心难点抽烟行为检测本质上属于目标检测细粒度动作识别的问题但它比普通目标检测麻烦在几个地方。第一烟支本身是小目标。普通目标检测数据集中目标通常占图像面积比较大。而一根香烟在监控画面里往往只有十几个像素尤其是在距离稍远、画面分辨率不够的情况下特征极其微弱。如果只在近距离、正面、光线好的场景下采集数据模型学到的特征就限定在这一类场景里换一个摄像头角度就失效。第二环境干扰多。香烟的烟雾、手势、手机、笔、细长物体都可能和抽烟动作混淆。晚上烟头发出的红光和某些指示灯、按钮、其他光源在颜色特征上高度相似。背景复杂的场景中手部动作幅度小给检测带来额外干扰。第三行为识别还需要时序上下文单帧图像无法判断是抽烟还是只是手放到嘴边。数据集如果只包含单帧静态图模型很容易被误导。解决的办法是在构建数据时保留连续多帧并合理安排帧间间隔。1.2 数据集要覆盖哪些“场景”维度我在设计这个数据集时把“多场景”拆解成了几个具体维度光照条件白天强光、阴天柔和光、夜晚路灯、室内白炽灯、逆光环境、暗光环境。摄像头角度平视、俯视、侧视、斜上视角。人物姿态站立、坐着、行走中、骑电动车/自行车、背对镜头、侧身面对镜头。背景复杂度干净的室内墙面、杂乱的办公室、人群密集的街道、地铁站、商场。目标距离近景人物占据画面大部分、中景全身可见、远景人物较小烟支难以辨认。天气条件晴天、阴天、雨天因为雨天气会影响摄像头画质从而影响检测。每一类场景都要有足够的样本量否则模型无法学到场景无关的特征。1.3 项目适合哪些人和哪些场景如果你是做安防监控、工地安全、机房管理、网吧/娱乐场所管理或者做行为识别方向的学生、研究工程师这份数据集的构建思路对你会有帮助。特别适合以下这几类需求需要实现智能监管对重点区域内抽烟行为进行自动识别告警。对已有检测模型在真实复杂环境下的泛化能力不满意希望通过数据层面进行优化。想构建自定义数据集但对采集、标注、质检流程还没有完整概念。下面要讲的是一套完整的数据集生产流程你完全可以按自己的场景需求替换类别、扩大规模。2. 数据集构建的关键设计决策2.1 类别体系设计几个类别才是最优解数据处理的第一步是确定标注哪些类别。我见过不少人一上来就标“cigarette”“smoke”“person”三个类别但实际训练效果并不理想。原因在于类别定义太细时小目标类别香烟很难被准确标注和检测类别太粗时又容易混淆。我在这个项目里最终采用了三个类别smoking_person正在做抽烟动作的人包含烟已点燃、烟在手边接近嘴部等状态。holding_cigarette手拿香烟但未做抽烟动作比如夹着烟走路、拿着烟说话。cigarette独立的烟支目标用于帮助模型学习烟支的视觉特征。看到这里你可能会问为什么不在所有场景都标注cigarette实际操作中当人物距离较远、烟支只有几个像素时人眼都很难标准标出来的框噪声反而干扰训练。所以近景和中景标注cigarette远景只标注smoking_person这是我在反复试错后定的规则。两个行为类区分的是动作状态让模型能够同时具备检测能力和时空上下文判断基础。方便后期结合视频帧序列做行为识别时不依赖单帧的模糊猜测。2.2 数据规模与分布策略数据量并不是越多越好而是每个场景都要覆盖到位。我在项目中总共采集和收集了约 1.2 万张原始图像筛选后保留 8600 张有效图像经过增强后得到 30000 张训练图像。划分比例如下数据集图像数说明训练集7000增强后 25000覆盖全部场景类别验证集900用于调参保证场景分布均匀测试集700模拟真实部署场景不参与训练关键点是训练/验证/测试的划分必须按场景来切而不是随机切分。比如某一段视频的连续帧如果既出现在训练集又出现在测试集模型就等于提前看到了答案测试指标虚高上线后立刻打回原形。所以我按“摄像头ID时间段”进行了分组划分同一个摄像头同一天的画面只能落在一个集合里。类别平衡同样重要。如果 90% 的数据都是白天室内模型自然只对这类场景敏感。我设定了一个分布目标白天室外 30%白天室内 30%夜间/暗光 20%逆光/低照度 20%这样模型不会因为单一光照条件产生系统性偏差。2.3 数据来源与版权注意事项数据获取方式有几种自己拍摄、网络公开素材、已有监控录像脱敏。我是几种方式混合使用。自己拍摄保证场景可控比如专门补拍夜间数据网络公开素材用来扩充人群、服装、背景多样性。这里必须强调一个合规问题涉及人物肖像的素材必须进行脱敏处理尤其是人脸和人体的可辨识特征用于商业项目的数据集务必确认素材授权链条清晰。一些开源的视频素材网站虽然素材本身允许下载使用但再加工成训练集并商用授权边界各不相同。我在项目初期吃过亏后来干脆把素材来源限定在自己有权使用的范围内省去后续版权纠纷的麻烦。3. 数据采集与预处理实操3.1 拍摄设备与采集方案设备方面不一定非要用昂贵的专业相机。我使用的是一组 1080P 分辨率的普通摄像头与手机分布在不同高度和角度。关键在于模拟真实监控场景的物理特性所以摄像头分辨率、画面畸变、帧率要尽量接近实际部署设备。拍摄时的注意点每个场景至少拍摄 20 条视频每条 30 秒到 2 分钟不等。连续视频帧比逐张图片更容易提供相似的场景分布同时抽取关键帧时还能保持动作连续性。同一个动作重复多遍。不同人、不同体型、不同衣服状态下抽烟动作幅度差异很大。我安排了不同体型的志愿者以自然习惯的方式完成抽烟、夹烟、放下烟、弹烟灰等动作。夜间场景使用环境本身的灯光不额外补光。如果夜间数据都用强补光训练出来的模型在真实暗光环境下会明显失活。逆光场景必须单独录制。这个场景容易导致烟支区域过暗甚至过曝形态完全看不见。采集完成后我使用ffmpeg进行抽帧。比如对一段 1080P、25fps 的视频我先按每秒 2 帧抽取再根据动作状态决定保留哪些帧。动作变化快的部分比如抬手、低头吸烟可以多抽几帧静止站立的部分减少抽帧频率避免大量冗余的相似画面。# 按每秒2帧抽取视频帧输出为jpg格式 ffmpeg -i input.mp4 -vf fps2 frame_%04d.jpg # 如需统一缩放尺寸到1280x720可加上scale滤镜 ffmpeg -i input.mp4 -vf fps2,scale1280:720 frame_%04d.jpg抽帧后我还有一个筛选逻辑画面模糊的帧运动模糊、对焦不准、人物被大面积遮挡的帧、目标在画面边缘超过 50% 的帧全部剔除。这些数据喂给模型只会增加标注成本拉低整体质量。3.2 图像清洗与场景均衡清洗不是简单看一眼觉得行就行而是要做系统化统计。我用 Python 脚本统计了每一帧的基础信息文件名、来源视频编号、场景类型、光照标签、图像分辨率、图像亮度均值、人眼可辨识目标数量等。具体的筛选逻辑如下亮度均值低于 30 的帧标记为“暗场”数量不足再进行补充拍摄。亮度均值高于 220 的帧标记为“过曝”通常是逆光或者强光直射数量超过一定比例时单独分析。图像尺寸一致化到 1280x720避免模型训练时输入尺寸变化过大。一个容易忽略的细节是不要把所有过暗的帧都删掉夜间场景本来就需要这些低亮度样本。当暗场样本是正常训练需要的时需要做的是补充更多其他角度的暗场而不是删除原有的暗场。要理解清洗的目标是去脏数据而不是去难数据。3.3 标注工具选型与标注规范标注这一步直接影响模型的性能上限。我用过很多工具最终在此项目里选用LabelImg和X-AnyLabeling组合。LabelImg 是老牌工具轻量稳定X-AnyLabeling 支持交互式分割适合标注边缘模糊的烟支等小目标。标注规范的制定是整个项目中最容易被低估的一环。团队协作时如果多人标注标准不统一数据质量会非常糟糕。我在项目里明文规定了以下几点边界框必须紧贴目标不能为了省事把人和烟框在一起。smoking_person框的是整个人身主体从头部到躯干不包括下肢边缘多余的背景。烟支在近景中必须标注中景和远景只标注行为类别。遮挡处理规则当人物手部被身体遮挡但明显有手持物靠近嘴部时标注为smoking_person当仅能看到手部夹着烟但无法确认是否正在吸时标注为holding_cigarette。不确定的样本单独存放不强行打标签。后期由项目负责人统一审核。同一视频帧标注一致性从同一段视频抽出的连续帧同一人物的标签不能在不同帧之间来回切换。比如前一帧标为smoking_person下一帧如果动作还没变就不能标成holding_cigarette直到动作确实变化为止。标注完成后还需要按比例抽检。我抽检了约 15% 的样本重点检查边界框的标注框尺寸是否合理因为边界框面积对检测器训练的影响很大。4. 基于数据集的模型训练与调优4.1 数据集目录组织与格式转换标注完成后需要整理成模型可直接读取的格式。以YOLOv8为例我按下面这种目录结构组织dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── README.mddata.yaml配置如下train: /path/to/dataset/images/train val: /path/to/dataset/images/val test: /path/to/dataset/images/test nc: 3 names: [smoking_person, holding_cigarette, cigarette]要注意LabelImg默认输出的是 PASCAL VOC 的 XML 格式YOLO 需要的是 txt 格式。我写了一个转换脚本将 XML 转成 YOLO 的归一化坐标格式。这里有个小坑VOC 中坐标是绝对像素值YOLO 必须是相对于图像宽高的比例值不能简单复制坐标。import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_path, output_dir, classes): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) out_file os.path.join(output_dir, os.path.basename(xml_path).replace(.xml, .txt)) with open(out_file, w, encodingutf-8) as f: for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_idx classes.index(cls_name) box obj.find(bndbox) x_min int(box.find(xmin).text) y_min int(box.find(ymin).text) x_max int(box.find(xmax).text) y_max int(box.find(ymax).text) x_center (x_min x_max) / 2.0 / img_w y_center (y_min y_max) / 2.0 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h f.write(f{cls_idx} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) if __name__ __main__: classes [smoking_person, holding_cigarette, cigarette] xml_dir annotations/xml out_dir annotations/yolo os.makedirs(out_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if xml_name.endswith(.xml): convert_voc_to_yolo(os.path.join(xml_dir, xml_name), out_dir, classes)4.2 YOLOv8 训练配置与参数调整模型方面我用的是YOLOv8m在精度和速度之间相对均衡。如果部署设备是低功耗边缘计算设备如 Jetson Nano 一类的建议用YOLOv8s如果追求极致精度且显卡性能充裕可以试试YOLOv8l。关键超参数设置如下epochs: 200 patience: 20 batch: 16 imgsz: 640 optimizer: SGD lr0: 0.01 lrf: 0.01 warmup_epochs: 3 mosaic: 1.0 close_mosaic: 10实操中发现几个比较重要的点关闭 mosaic 的最后 10 个 epoch。YOLOv8 默认会在训练早期开 Mosaic 增强最后阶段自动关闭。如果数据集中小目标较多Mosaic 对小目标的提升明显但最后阶段关闭是为了让模型稳定收敛避免持续使用拼接图导致定位偏移。这个参数不能省否则测试集指标会飘忽不定。imgsz 选择 640。我的数据集里近景烟支目标很小初始试过 imgsz480结果小目标的 AP 掉得很厉害。换到 640 之后小目标检测能力提升明显。对于烟支这种极小的目标甚至可以考虑 768 或 896但训练时间和显存占用会显著上升。实际项目以部署设备限制为最终边界不能一味追求高分辨率。batch 大小依据显存调整。如果是单张 8GB 显存显卡batch16、imgsz640 配合 YOLOv8m 可能直接 OOM建议降到 batch8 或换 YOLOv8s。不必强上大 batch因为小目标检测任务中更大的 batch 并不一定带来更好的效果。类别权重调整。因为holding_cigarette数量相对较少我在 loss 计算中给这个类别增加了一点权重避免模型把这类样本学成近似背景。如果你是修改 YOLO 源码来做这件事可以直接调整loss.py中的cls权重参数。如果不想改源码先把数据平衡做好比强行调权重更有效。4.3 数据增强策略怎么增才不会“增坏”数据增强是提升泛化能力的重要手段。但很多人一上来就各种翻转、旋转、颜色抖动叠满结果模型泛化没提升反而学了太多噪声特征。我在项目中使用的增强组合随机水平翻转概率 0.5对行为检测有效因为左右手动作具有对称性。随机亮度/对比度调整适度调整区间控制在 -25% 到 25%模拟不同光照条件。随机缩放0.5 到 1.5 倍增强模型对距离变化的鲁棒性。HSV 色度扰动色调变化不大控制在 -10 到 10避免改变烟支和肤色的基本色调。高斯噪声概率 0.1模拟暗光环境下的画质噪声。Mosaic 和 MixUp按 YOLO 默认配置启用。有一个很容易被忽略的问题如果你的验证集也做了增强那验证结果就完全失真了。验证集必须保持原始图像不做任何增强。训练集增强是让模型见过更多分布验证集要保持“裸奔”测试集更是要完全模拟真实场景。5. 多场景泛化的踩坑与优化5.1 夜间与逆光场景的专项优化第一次训练完成后我单独统计了不同场景子集下的性能指标。结果夜间场景的 mAP 只有白天场景的 60%逆光场景甚至更低。问题出在哪夜间烟支特征完全依赖烟头火光而火光目标极小且容易和光源混淆。逆光下人物轮廓反差极低行为动作辨识困难。针对夜间场景我做了两个处理一是对夜间图像采用自适应直方图均衡化CLAHE作为预处理增强局部对比度。这个过程可以放到训练前的图像预处理中也可以作为数据增强的一环。二是专门补拍夜间近距离样本让模型有更多机会看到“烟头火光”这个强判别性特征。如果条件不具备也可以用图像编辑工具对现有暗场图像进行亮度分区增强但这只是备选方案效果不如真实补拍。逆光场景的处理思路不同。逆光时烟支区域经常变成黑色剪影信息完全丢失。此时依赖外形特征比依赖颜色特征更可靠。我在增强策略中把色阶反转、暗部细节增强这类算子加入并增加了侧光、逆光下用手遮烟、低头看烟等常见姿态的采样。5.2 小目标与遮挡目标的检测对策烟支小目标检测是这类任务里最突出的痛点。我实测下来直接用小目标标注的数据训练对小目标的提升有限真正有效的是多尺度训练。YOLOv8 本身使用特征金字塔结构对多尺度目标有一定鲁棒性。但烟支过小时浅层特征图上的语义信息不足深层特征图又丢失了空间细节。我在训练时设置了多尺度增强scale: 0.5, 1.5这会让每张训练图在输入模型前随机缩放相当于把同一目标在不同尺度下重复训练提升模型对尺度变化的适应能力。另外在推理阶段我使用了分层阈值。大目标面积 64x64置信度阈值设为 0.35。中等目标面积 16x16 到 64x64阈值设为 0.5。小目标面积 16x16阈值设为 0.65。这个策略可以大幅减少小目标的误检降低夜间场景中错误触发告警的概率。对烟支这种目标来说宁可漏检也不误检因为误检在真实业务中会直接消耗人力去排查。遮挡问题只靠单帧解决不了。当前帧被遮挡时模型无法判断。我是采用帧间投票策略连续 3 帧中至少 2 帧检测到smoking_person才判定为有效抽烟事件。这个后处理逻辑在真实部署中非常实用能过滤掉大量因遮挡导致的单帧误判。如果后续想做更完整的视频动作识别可以考虑结合时序模型。大部分实际项目用帧序列投票已经基本够用不必把工程搞得太重。5.3 跨摄像头场景迁移的实践心得跨摄像头泛化是这类任务上线的关键指标。同一个模型换一个摄像头、换一个安装高度、换一个画面比例检测性能就可能变化很大。我踩过的一个典型坑训练集里 80% 的摄像头视角是平视角度换到俯视摄像头后mAP 从 0.89 掉到了 0.72。问题的根源是视角分布过于单一。解决方式是在采集阶段就刻意控制视角多样性俯视、仰视、斜上方、平视各占一定比例。如果项目推进到后期发现某一类视角特别缺再针对性补采集。另外我还对真实摄像头画面做了分辨率适配测试。因为部署端有可能是 720P 也可能 1080P模型在训练时看到的分辨率如果和部署不一致效果也会打折扣。最佳实践是在推理管线中统一缩放分辨率到 640x640和训练时的输入保持一致。如果条件允许可以引入相机标定信息做归一化让不同摄影角度下的人体尺度一致后再输入模型但这需要比较强的工程配套通常场景优先级没那么高。我建议优先把数据覆盖度和后处理策略做扎实模型本身就能获得较好的跨场景泛化能力。6. 常见问题与排查技巧实录6.1 数据标注不一致导致训练震荡训练 log 显示 mAP 在 70 到 80 之间来回震荡怎么都不收敛而且 loss 曲线迟迟不下降。排除学习率因素后我抽了一批标注检查发现问题主要出在多人协作标注的边界框风格不统一。有人标注习惯紧贴边缘有人喜欢留一点空间还有人把人和烟框在一起。同一批数据在特征空间里就存在标签噪声模型学起来自然痛苦。解决方案标准化标注工具中的标签框显示方式让每个标注员都能看到参考示例。抽检时计算每个标注员的平均框大小与整体平均框大小的偏差偏差异常大的重新学习规范。对标注质量较差的数据直接返工。实践下来标注规范比训练技巧对最终指标的影响更明显。建议在项目启动第一天就让所有协作成员充分对齐规范特别是边界框的边界定义。6.2 类别不均衡的调整前面提到holding_cigarette数量最少。一开始没有处理类别不平衡模型对holding_cigarette的召回率很低经常把它识别成smoking_person。这两类在视觉上本身就相似数据偏少时模型更容易混淆。后续做了两件事专门补了一批holding_cigarette的标注数据。在损失函数中提高了该类别的权重。提升后召回率从 0.63 提升到 0.81说明数据量的影响比权重更大。所以尽量先数据补充再考虑调权重。不要一上来就调 loss数据分布才是根因。6.3 夜间误检严重夜间场景误检主要来源于两类一是路灯、车灯、烟头点状光源被误检为烟支二是把“手扶栏杆”或“拿手机”的动作误判为手持香烟。针对光源误检我发现单纯降低置信度阈值没有用噪声源的置信度常常也很高。需要结合位置和上下文特征比如烟支应该在面部附近或手部周围单独出现在画面远处的小光点大概率不是烟支。我在后处理中加入了“烟支位置与人体框的相对关系”判断如果检测到cigarette但其中心远离任何smoking_person或holding_cigarette的框且距离超过一定比率则降低其置信度或直接过滤。这是基于业务经验的规则但效果立竿见影。类似的规则还可以扩展烟支的宽高比应该在合理范围一般 1:2 到 1:6长宽比明显异常的检测结果大概率是误检。拿手机和吸烟只靠静态帧难以区分需要结合动作上下文。实际部署时我会观察连续帧中的手部朝向与抬起幅度。如果场景允许接入一个轻量的关键点模型如 YOLOv8-pose 或 MediaPipe辅助动作判断会更准确。6.4 测试集效果好真实场景效果差这是最让人头痛的问题。测试集 mAP 0.88现场一跑只有 0.6。排查后基本就三类原因一是训练集和测试集之间存在数据泄漏。前面讲过的按摄像头/时间段划分就是为了规避这个问题。要避免同一段视频的帧被拆分进训练集和测试集。二是部署环境的输入管线和训练时不一致。训练时我做了颜色增强部署时如果摄像头画面还会经过额外的 ISP 处理白平衡、对比度都和训练分布不一致。最好采集一段部署摄像头的真实画面加入训练集微调。三是目标尺寸分布偏移。现场摄像头安装高度和距离和训练数据差距太大导致人体框大小不在训练分布范围内。解决办法是调整安装位置或者采集现场数据重训。我通常会准备一个“真实场景冒烟测试集”只包含部署现场抓拍的少量真实画面比如几百张用于上线前的最终验证。如果在这个测试集上效果好再上生产才放心。6.5 标注工具使用中的几个效率技巧最后补充几个标注和工程落地上的小技巧。用X-AnyLabeling的自动标注功能做预标注人工只需要修正错误框。对抽烟检测场景可以先用一个略粗糙的模型跑出全量候选框再人工修正能节省约 50% 左右的标注时间。同一个人、同一个摄像头视角下的连续帧首次标注后可以使用脚本进行标签传播把相同的目标位置复制到相邻若干帧再用人工微调。如果做视频级行为识别建议每个抽烟行为打上起始帧和终止帧方便后续做时序标注而不是只标单帧。标注完成的文件需要做持久化备份。防止硬盘故障、误删导致前功尽弃这个代价真的很高。回到最初的选择如果当时凑合用了开源数据集项目上线时间可能更早但夜间和逆光场景大概率会被客户直接打回。数据集的构建确实耗时耗力但它是整个模型效果的根基。在实际操作中我最大的体会是多场景数据集的精髓不在于“数量大”而在于“可控的分布多样性”。每一类场景、每一种光照、每一种视角都要刻意地采集、标注、统计、验证。拿结果说话模型在陌生场景下表现得稳不稳完全取决于数据处理阶段用没用心。后续要扩展这个项目我建议往两个方向走一是加入视频时序信息从静帧检测升级为动作识别从“检测到烟”变为“识别完整的吸烟事件”二是扩充更多高危场景比如加油站、化工厂、仓库等这类场景对误报率要求极高需要更精细的数据设计和规则后处理。这套流程不只适用于抽烟检测也适用于其他细粒度行为识别项目。希望这份记录能帮你省掉几个月的试错时间。本文还有配套的精品资源点击获取
返回列表