资讯中心

吸烟识别数据集实战:COCO格式解析与YOLOv8训练指南

📅 2026/8/27 6:28:17
吸烟识别数据集实战:COCO格式解析与YOLOv8训练指南
简介目标检测是计算机视觉的基础任务但检测“香烟”这类小目标却面临尺度小、半透明、遮挡等挑战使得吸烟识别比常规检测更复杂。COCO格式作为主流标注标准能有效表达多实例与行为上下文为模型训练提供高质量数据支撑。通过一个包含10162张覆盖多场景图像的吸烟行为数据集结合YOLOv8的快速部署能力可以将识别能力落地到宿舍抽烟预警、工地安全帽下吸烟检测、加油站烟火监控等实际安防场景中。数据集中的姿势多样性、COCO JSON结构解析以及YOLO格式转换都是提高模型泛化能力的关键环节。围绕这些实践可以系统解决吸烟识别从数据到训练的技术路径。 上周和同行聊一个园区安防项目客户点名要加吸烟检测说最好能同时识别出拿烟的手、烟头位置。我原本觉得这活儿不就是目标检测吗标注几万张图训个YOLO完事。真跑起来才发现吸烟识别比普通检测难得多烟是半透明的手会遮挡灯光一暗烟头几乎看不见远处的目标框小到只剩二三十个像素。最后换了那份带COCO格式标注的吸烟抽烟行为识别数据集10162张各种姿势和场景的图片重训之后识别率才真正能看。这篇文章就从这份数据集入手把格式解析、训练过程和踩坑记录完整展开。无论你打算做宿舍抽烟预警、工地安全帽下的吸烟识别还是加油站烟火检测这篇都适合留下来当参考。1. 为什么吸烟识别比想象中更难先弄懂你要解决的是什么1.1 从宿舍到加油站吸烟检测的真实需求在哪儿我在过去半年里接触的需求方五花八门。学校管理部门想抓宿舍阳台抽烟工地管安全的想识别工人是否在禁烟区抽烟加油站监控想检测站内烟火还有医院想统计室外吸烟点位。它们的共同点很直接已经有摄像头已有简单的监控系统想加一个自动看见有人在抽烟的模块。这个模块如果做得准就能替代人工盯屏还能留证据、能够自动联动告警。所以从产品形态看吸烟识别往往不是独立系统而是安防大平台里的一个行为分析子模块和人员越界、区域入侵、打电话识别这些任务并列。说到这里很多人会认为那就在原有检测框架里加一个类别就好。实际不是。吸烟行为识别有一个天然缺陷你检测的目标香烟实在太小。一套1080p枪机画面里一个人站在二十米外烟支可能只有不到10个像素宽很多检测头在这个尺度上直接放弃。而且香烟本身不发光除非烟头部分颜色和背景融为一体漏检率天然比检测人车这种大目标高。所以算法方案必须专门为这个目标设计这也是这类数据集的价值所在。另外客户常说的识别抽烟其实有三种口径。第一种是检测烟支/烟头这个物体模型输出香烟的框。第二种是检测吸烟动作用整个人的框或者上半身框表达正在抽烟这个行为。第三种是识别抽烟持烟手势需要更精细的关键点或更细粒度的行为分类。拿到数据集的时候首先要看categories字段定义的是哪一种否则后面训练对齐会出大问题。这一点我会在第3章详细拆。1.2 烟是半透明的、手是遮挡的、光是多变的把难题拆开看吸烟识别对视觉算法不友好主要是四件事。第一目标尺度极端。正常监控画面里人脸检测已经有难度但烟支比人脸小得多。同样是1080p一支香烟的检测框可能只有20×8像素烟头就更小。YOLO系检测器在640输入下目标只要小于一个特定的网格尺度几乎就学不到有效特征。第二天然遮挡。吸烟时手、嘴、烟三者重叠手要挡住一部分烟身嘴唇又会压住烟嘴。模型经常学到的是手嘴附近有一个亮色小点而不是真正学到烟支结构。第三半透明与颜色退化。烟身是白色或米黄色在墙面、皮肤、衣服这些颜色差异不大的背景下对比度很低烟雾本身半透明和背景融合后甚至看不到烟支轮廓。第四光照变化。室内正常光还行室外背光时烟支全黑夜里只有烟头那个红点是稳定的信号。可如果模型只学会找红色亮点路灯下的红色广告牌、车尾灯都会变成误报源。这里插一句我个人的认知很多人以为吸烟识别难在要训练一个特别强的模型其实难点在数据。为什么一个10162张、覆盖各种姿势场景的数据集能出效果因为它把上面这些问题用样本量压平了。你不需要一个天才模型你需要一个见过足够多刁钻场景的普通模型。数据集的场景覆盖越广模型的泛化能力越接近真实部署这比一味加大模型容量管用。2. 这份10162张的吸烟数据集到底覆盖了什么2.1 先看数字图片量、标注框、场景分布怎么读拿到一个zip包之后第一个动作不是立即训练而是把数据读一遍。先从文件名和目录结构开始通常会看到 images文件夹有些叫JPEGImages和annotations文件夹annotations下面放着instances_train.json、instances_val.json这类文件。这份数据集有10162张图具体标注框数量要解压后看annotations数组的长度但按我的经验这类专门为行为识别收集的数据集通常不会每张图只标一个框。一张图里可能有多个人、多支烟、多个持烟手势。我建议解压后自己统计方法很简单import json with open(annotations/instances_train.json, encodingutf-8) as f: coco json.load(f) print(len(coco[images]), len(coco[annotations]))如果图片数和标注数都落在合理范围比如标注数是图片数的1.5到2倍以上说明数据是实例级标注。如果一张图只有一个框那可能整个框表示正在吸烟的人这个行为框而不是标注每支烟。这两种标注思路训练出来的模型形态完全不同所以建议先跑一下统计再决定后续策略。我这里按常见设计把这类数据集的构成列成一个参考表格实际以你解压后的json为准项目常见内容图片总数10162张标注格式COCO JSONbbox segmentation category_id图片分辨率多为1920x1080或1280x720需自行确认场景覆盖室内、室外、白天、夜间、背光、侧光常见标注目标香烟/烟头、吸烟行为框、人员框视categories定义压缩包结构images/ annotations/ 说明文档2.2 各种姿势场景意味着什么低头、抬手、叼烟、弹烟灰这份数据集的标题里特意写了各种姿势场景这是最有信息量的一句话。我见过的很多公开吸烟数据集问题恰恰在于姿势太单一全是人对镜头正面、烟夹在食指中指之间、嘴张开的瞬间。这种数据训出来的模型换个视角就废了。而覆盖姿势多样性至少包括这几个维度。角度上有正脸、侧脸、低头看手机、仰头吐烟手部动作上有夹烟、递烟、弹烟灰、把烟放在烟灰缸边、反手夹烟场景上有办公室、楼道、阳台、停车场、工棚、室外步行还有夜间路灯下。这些看似只是数量多实际上把模型的决策空间撑开了。模型不再倾向于记住某个固定角度下手指缝里有个白条而是慢慢学会了在手的附近、嘴的附近出现一个短而细的条状物并且和背景有边界这是一个烟支。这对部署的价值是决定性的。比如宿舍抓拍场景学生可能趴在阳台栏杆上摄像头从侧面斜拍手还放在窗沿下方。如果你的训练集里没有低头手部被栏杆遮挡的样本模型大概率漏掉。反过来如果训练集包含手在背景中有长条物体的场景模型就可能把栏杆、窗帘杆误认成烟。2.3 COCO标注格式为什么是COCO而不是VOC我看过不少人拿到数据集之后先问能不能转成VOC的XML或者为什么不用LabelImg的Pascal格式直接存。我的回答是直接用COCO更好至少在这个任务里是。COCO格式的核心是单个JSON文件包含了images、annotations、categories三块。它的嵌套结构和id关联关系能表达多实例、多类别、甚至同一个目标带细粒度分割边缘的复杂标注。对吸烟识别来说同一个img_id下可以挂多个annotation一个表示香烟一个表示持烟的手给模型训练增加了上下文信息。VOC一套一个XML文件数量多、管理麻烦也不方便做多级标签体系。而且COCO是众多现代检测框架的默认输入格式之一Detectron2、MMDetection、YOLOv5的COCO支持都很好Ultralytics也提供了直接的COCO格式示例。后续你要做预训练权重迁移、在更大的COCO预训练模型上微调数据结构一致就能省掉很多转换API的适配工作。3. COCO格式标注从解压到喂给模型json文件完全拆解3.1 解压后的目录结构先确定文件是否完整先说个小坑。很多人解压这个zip后发现annotations里只有instances_train.json没有val.json就开始瞎拆。我建议先核对一下unzip smoking_dataset.zip -d smoke_data find smoke_data -type f | head -30 find smoke_data -name *.jpg | wc -l如果只有一份json可以自己按8:2或9:1切分但切分时要注意场景隔离这个坑我在第5章展开。另外Windows上解压可能会因为文件名过长报错尤其是数据集图片命名很长的时候建议在压缩包所在路径短一点的目录里解压避免路径超过系统上限。解压完不要急着删除zip如果后续忘了原文件结构还能重新对照。3.2 COCO JSON 四大块images、annotations、categories、infoCOCO的JSON结构其实非常直白。我习惯用一个脚本先做数据体检import json with open(annotations/instances_train.json, encodingutf-8) as f: coco json.load(f) # 1. categories print(categories:, json.dumps(coco[categories], ensure_asciiFalse, indent2)) # 2. 单张图片 print(image sample:, coco[images][0]) # 3. 单个标注 print(annotation sample:, coco[annotations][0])categories长这样[ { id: 0, name: cigarette, supercategory: smoke } ]也可能长这样[ {id: 0, name: smoking, supercategory: action}, {id: 1, name: cigarette, supercategory: object} ]不同数据包的类别设计不一样这一步决定你后面训练的是什么。如果categories里既有smoking又有cigarette说明它把吸烟行为和香烟目标分开标注如果只有smoking则更可能是行为级检测。后面转YOLO格式时类别索引不是按id顺延而是要有意排成你想要的检测目标顺序。annotation里的bbox长这样{ id: 1, image_id: 0, category_id: 1, bbox: [612.0, 318.0, 38.0, 10.0], area: 380.0, segmentation: [[...]], iscrowd: 0 }这里bbox的四个值是[x, y, width, height]单位是像素原点在图像左上角。很多第一次接触COCO的同学最容易在这里翻车他们把x和xw当成对角线、或者忘记了宽高是绝对像素值导致下采样后坐标错位。记住COCO的bbox不是归一化的与YOLO格式完全相反。area字段在评估阶段会被用到如果你在解压后对图片做了裁剪或缩放area必须跟着重新算否则mAP评估会偏。segmentation字段可以是一个多边形数组也可以是一个RLE编码字符串取决于标注工具。对大部分检测训练流程来说bbox就够用了但如果后续要做实例分割就保留segmentation。3.3 可视化检查我建议每个类别先看20个框光看json还不够一定要把标注框可视化到图上。不要相信标注完成就一定是准的尤其吸烟数据里烟支小、边界模糊标注时很容易出现手误。一个简单的可视化方法是用OpenCV把框画出来import json import cv2 import os with open(annotations/instances_train.json, encodingutf-8) as f: coco json.load(f) id2img {img[id]: img for img in coco[images]} ann_by_img {} for ann in coco[annotations]: ann_by_img.setdefault(ann[image_id], []).append(ann) sample coco[images][0] img_path os.path.join(images, sample[file_name]) img cv2.imread(img_path) for ann in ann_by_img[sample[id]]: x, y, w, h [int(v) for v in ann[bbox]] cv2.rectangle(img, (x, y), (x w, y h), (0, 255, 0), 2) cv2.imwrite(check_sample.jpg, img)检查时重点看三类问题烟支框是不是比实际大很多包进去一段手指或嘴唇是不是只标了烟头没标烟身是不是把嘴里的笔、吸管也画了框。标签不干净直接决定了后续训练的上限所以这一步别省。如果发现整个数据集标注风格和你预期的检测目标不一致宁可先做一轮修正也不要直接开训。4. 用YOLOv8把识别率跑上去从配置文件到训练结果4.1 工具链选择为什么我用YOLOv8而不是更重的检测器目标检测框架很多Faster R-CNN、RetinaNet、DETR、YOLOv8各有人气。吸烟识别这个任务我个人的选择一直是YOLOv8系列的yolov8s或yolov8m理由有三点。第一训练和部署之间的转换链路最短。YOLOv8可以直接导出ONNX再转成TensorRT或OpenVINO在市面上大多数盒子里都能跑。两阶段检测器虽然精度上限可能更高但部署复杂度高对一个只需要检测烟支/吸烟行为的安防场景并不划算。第二YOLOv8是anchor-free对任意长宽比的小目标比如香烟这种细长条不需要像anchor系模型那样微调anchor尺寸。第三Ultralytics把训练、验证、导出、推理都封装得很干净训练脚本写起来不费劲数据集YAML一写就能跑。如果你手里有更大的算力我建议先从yolov8m开始而不是一上来就yolov8x。因为吸烟识别的瓶颈主要在数据和标签质量模型容量过大会在数据不足时过拟合得更厉害。10162张图训yolov8m完全够用yolov8x反而可能让训练时间翻倍识别率的提升却很有限。4.2 把COCO转成YOLO能直接用的格式Ultralytics YOLOv8默认读取的标签不是COCO JSON而是每张图一个同名txt文件每行是class_id cx cy w h且全部是归一化到0-1的数值。所以需要一个转换脚本把COCO的bbox转换成YOLO格式的txt。我之前写的脚本可以用注意几个关键点类别索引必须从0开始连续归一化时要用每张图原始宽高而不是统一假设640如果bbox超出了图像边界要做clip处理。import json import os def coco_to_yolo(coco_path, image_dir, label_dir): os.makedirs(label p a hrefhttps://download.csdn.net/download/pbymw8iwm/90061014 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p