尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

睡岗玩手机检测数据集:VOC转YOLO全流程与避坑指南

发布时间:2026/9/28 16:49:38

资讯中心
01
ARTICLE

睡岗玩手机检测数据集:VOC转YOLO全流程与避坑指南

睡岗玩手机检测数据集:VOC转YOLO全流程与避坑指南
简介这份数据集面向安防监控、行为识别方向的算法工程师与高校研究者聚焦办公、值守等场景下的睡岗与玩手机两类异常行为检测可用于训练与验证目标检测模型帮助解决违规行为自动识别、智能巡检等实际问题。资源包共收录2000个文件全部为VOC格式的XML标注文件与4653张原始图像一一对应压缩包整体约140.37MB标注涵盖目标类别与边界框信息可直接接入YOLO、Faster R-CNN等主流检测框架进行格式转换与训练。目前已有773人学习下载具备一定的社区验证基础。数据采集覆盖多时段、多角度场景图像命名包含时间戳信息便于按时间维度划分训练集与测试集也方便排查漏标与错标样本。对于需要快速搭建睡岗、玩手机检测基线或扩充现有数据集的读者这份标注齐全、格式规范的资源能有效节省数据采集与标注成本缩短从数据准备到模型迭代的周期。1. 睡岗玩手机检测数据集4653 张 VOC 标注图能直接喂给哪些模型工厂夜班监控里最头疼的画面不是设备报警而是工位上有人趴着睡、有人低头刷手机。这类行为检测靠传统运动侦测根本分不清低头看仪表和低头玩手机必须上目标检测模型。手头这份睡岗、玩手机数据集4653 张原始图全部配 VOC XML 格式标注覆盖睡岗和玩手机两类行为图片来自真实监控视角文件名带时间戳和分辨率后缀如72-94、72-76说明是从连续视频流抽帧来的。它解决的是从零标注成本太高这个卡点——4653 张图如果自己标按熟练工一天 800 张算也要近一周。适合做安防行为识别、工地/车间合规检测、边缘盒子部署的从业者也适合想跑通 YOLO 全流程但缺真实场景数据的新手。VOC XML 是通用中间格式转 YOLO、COCO、CSV 都有成熟脚本不用被格式绑死。2. VOC XML 标注结构拆解先看懂再动手转2.1 一份 XML 里到底存了什么VOC 格式的标注文件本质是一个结构化描述图片尺寸、通道数、每个目标的类别名和边界框坐标。拿项目正文里那份2021-08-25-07-59-06_72-94_4_png_jpg.rf.a14ae348d4d5d40bdb03368d0adad45b.xml来说文件名里的72-94大概率对应图片宽高比或分辨率标识rf.后面那串是抽帧/增强时的哈希保证文件名唯一。打开后典型结构如下annotation folderimages/folder filename2021-08-25-07-59-06_72-94_4_png_jpg.rf.a14ae348d4d5d40bdb03368d0adad45b.jpg/filename size width1920/width height1080/height depth3/depth /size object namesleep/name !-- 类别名睡岗 -- poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin412/xmin ymin236/ymin xmax688/xmax ymax540/ymax /bndbox /object object namephone/name !-- 类别名玩手机 -- bndbox xmin900/xmin ymin300/ymin xmax1010/xmax ymax470/ymax /bndbox /object /annotationsize里的宽高是原图尺寸bndbox是左上角和右下角绝对像素坐标。difficult标记难样本训练时可以选择忽略。truncated表示目标是否被截断。这些字段在转 YOLO 时只有name和bndbox是必须的其余可丢弃。理解这一点后面写转换脚本就不会被多余字段干扰。2.2 为什么选 VOC 而不是直接给 YOLO txtVOC XML 可读性强用文本编辑器就能改标注工具 LabelImg 默认就存这个格式。YOLO 的 txt 是归一化后的class x_center y_center w h人眼几乎没法校对。数据集给 XML 等于把可编辑的源文件交到你手上转成什么格式取决于你的训练框架。常见做法是保留 XML 作为原始标注训练前用脚本生成一份 YOLO 格式副本原始文件不动。这样换模型、换框架时不用重新标注。另一个原因是 VOC 被 PASCAL 系列工具链支持得最久很多老项目和标注平台导入导出都认它兼容性比直接给 txt 稳。2.3 目录组织与文件配对检查拿到 4653 张图加对应 XML第一步不是急着转格式而是确认图片和标注一一对应。常见目录结构是JPEGImages/放图Annotations/放 XML文件名主干相同、扩展名不同。先跑一遍配对检查import os img_dir JPEGImages xml_dir Annotations imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .png, .jpeg))} xmls {os.path.splitext(f)[0] for f in os.listdir(xml_dir) if f.lower().endswith(.xml)} only_img imgs - xmls # 有图没标注 only_xml xmls - imgs # 有标注没图 print(f图片总数: {len(imgs)}, 标注总数: {len(xmls)}) print(f缺标注的图: {len(only_img)}, 缺图的标注: {len(only_xml)}) if only_img: print(示例:, list(only_img)[:5])这段脚本用集合差集找出不配对的样本。only_img非空说明有图没标训练时要么删掉要么补标only_xml非空说明标注文件是孤儿直接删。4653 张的规模配对检查几秒就跑完但能避免训练时报找不到标注这种低级错误。我一般还会顺手统计每个类别的框数量看两类是否严重失衡——如果睡岗 8000 个框、玩手机只有 900 个后面训练就得考虑类别权重。3. 转 YOLO 格式脚本、参数与坐标归一化3.1 坐标转换的数学逻辑YOLO 要的是归一化中心点加宽高公式不复杂但容易写错。设图宽W、高H框xmin, ymin, xmax, ymax中心 x(xmin xmax) / 2 / W中心 y(ymin ymax) / 2 / H宽(xmax - xmin) / W高(ymax - ymin) / H四个值都落在 0 到 1 之间。类别名要映射成从 0 开始的整数索引比如sleep: 0、phone: 1。映射表必须固定训练和推理用同一套否则模型学出来的类别是乱的。下面脚本把 VOC 转成 YOLO txt同时生成classes.txt和data.yaml。import os import xml.etree.ElementTree as ET classes [sleep, phone] # 类别顺序固定不可随意改 cls_map {name: i for i, name in enumerate(classes)} xml_dir Annotations out_dir labels os.makedirs(out_dir, exist_okTrue) def convert(xml_path, out_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) W int(size.find(width).text) H int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in cls_map: continue # 跳过未定义类别避免索引越界 bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) # 裁剪到图像边界防止标注越界导致归一化后超出 0~1 xmin, xmax max(0, xmin), min(W, xmax) ymin, ymax max(0, ymin), min(H, ymax) cx (xmin xmax) / 2 / W cy (ymin ymax) / 2 / H bw (xmax - xmin) / W bh (ymax - ymin) / H lines.append(f{cls_map[name]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines)) for f in os.listdir(xml_dir): if f.endswith(.xml): convert(os.path.join(xml_dir, f), os.path.join(out_dir, f.replace(.xml, .txt))) print(转换完成)关键参数说明classes列表顺序就是最终类别索引改顺序等于改标签含义max(0, xmin)和min(W, xmax)是边界裁剪真实标注里偶尔会出现xmax比图宽大几个像素的情况不裁会导致归一化值大于 1部分框架直接报错:.6f保留六位小数YOLO 官方推荐精度太少会丢框。转换后随便抽一个 txt 和原 XML 对照中心点应该在 0.5 附近目标居中时宽高小于 1。3.2 生成 data.yaml 与训练集划分YOLOv8 训练要一个 yaml 描述路径和类别。划分训练验证集按 8:2 或 9:14653 张建议留 400 到 500 张做验证。脚本按文件名随机划分固定随机种子保证可复现import os, random, shutil random.seed(42) # 固定种子划分可复现 img_dir, lbl_dir JPEGImages, labels names [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .png))] random.shuffle(names) split int(len(names) * 0.9) sets {train: names[:split], val: names[split:]} for s, items in sets.items(): os.makedirs(fdataset/images/{s}, exist_okTrue) os.makedirs(fdataset/labels/{s}, exist_okTrue) for n in items: for ext in (.jpg, .png): src os.path.join(img_dir, n ext) if os.path.exists(src): shutil.copy(src, fdataset/images/{s}/{n}{ext}) break shutil.copy(os.path.join(lbl_dir, n .txt), fdataset/labels/{s}/{n}.txt) yaml_text fpath: {os.path.abspath(dataset)} train: images/train val: images/val nc: {len(classes)} names: {classes} with open(data.yaml, w) as f: f.write(yaml_text) print(划分完成:, {k: len(v) for k, v in sets.items()})seed(42)保证每次划分结果一致方便对比实验。nc是类别数这里等于 2。names顺序必须和转换脚本里的classes完全一致。跑完检查dataset/images/train和labels/train文件数是否相等不等说明有图缺标注回到 2.3 的配对检查排查。3.3 起训命令与关键超参数据就绪后YOLOv8 一条命令起训yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/sleep_phonemodelyolov8n.pt是 nano 版边缘盒子部署首选精度不够再换yolov8s。imgsz640是输入尺寸监控图目标偏小的话可以提到 960但显存和速度要权衡。batch16按显存调8G 显存跑 640 尺寸 16 一般够。patience20表示 20 轮验证指标不升就早停省时间。lr00.01是初始学习率YOLOv8 默认值数据量 4000 多张不用大改。训练时盯mAP50和mAP50-95两个指标睡岗和玩手机两类如果某一类 AP 明显低多半是样本少回去补该类数据或加类别权重。4. 避坑与排查标注和转换里最容易翻车的五处4.1 类别名大小写不一致导致漏标现象转换后某些图 txt 是空的但 XML 里明明有框。原因标注时同一类写成Sleep、sleep、SLEEP混用脚本里cls_map只认小写其余全被continue跳过。解决转换前先统计所有 XML 里出现过的name值统一转小写再映射或在脚本里加name name.strip().lower()。我一般会先跑一遍grep -h name *.xml | sort | uniq -c看类别名到底有几种写法。4.2 坐标越界让归一化值大于 1现象训练启动报normalized coordinates out of range或 loss 直接 NaN。原因标注框xmax超过图宽、ymax超过图高归一化后大于 1。解决转换脚本里做边界裁剪3.1 已加或者训练前用校验脚本扫一遍所有 txt发现任一分量大于 1 就定位到对应 XML 修标注。裁剪是兜底根治还得改标注源文件。4.3 图片和标注文件名主干不匹配现象训练报No labels found但 labels 目录里文件不少。原因图片是.png标注是.jpg.xml或主干多了后缀配对不上。解决跑 2.3 的配对检查把不匹配的列出来。常见于从不同批次合并的数据集文件名规则不统一。统一改成主干相同、扩展名不同再继续。4.4 空标注文件被当成负样本现象模型把没目标的图也学出框误检偏高。原因有些图确实没有睡岗和玩手机XML 里没有object转出来是空 txt。YOLO 会把空 txt 当负样本这是对的但如果空 txt 是因为类别名没匹配上4.1那就成了假负样本模型学到有目标也不该报。解决区分真空标注和转换失败。真空标注保留转换失败的要修类别名重转。统计空 txt 数量和 XML 里无 object 的数量对比两者应一致。4.5 训练验证集划分泄漏现象验证集 mAP 高得离谱实际部署一塌糊涂。原因同一段视频抽的帧被分到训练和验证两边画面几乎一样等于变相泄漏。这批数据文件名带时间戳同一时刻附近的帧高度相似。解决按时间戳前缀分组划分同一段连续抽帧整体进训练或整体进验证不要随机打散。简单做法是取文件名前 16 位到秒做分组键按组划分。5. 进阶小目标增强与部署前验证玩手机这个类别有个天然难点——手机在监控画面里往往只占几十个像素属于小目标。640 输入下一个 60×40 像素的手机框缩到 640 后只剩 20 像素左右特征很弱。我一般会做两件事一是把imgsz提到 960 或 1280代价是推理变慢边缘盒子要实测帧率二是开 Mosaic 和 Copy-Paste 增强YOLOv8 默认开 MosaicCopy-Paste 需要自己加把手机框抠出来贴到其他位置增加小目标密度。另一个技巧是单独统计手机框的面积分布import os areas [] for f in os.listdir(labels/train): for line in open(os.path.join(labels/train, f)): p line.split() if len(p) 5 and p[0] 1: # 类别 1 phone areas.append(float(p[3]) * float(p[4])) # 归一化宽×高 areas.sort() n len(areas) print(f手机框数量: {n}) print(f面积中位数: {areas[n//2]:.6f}) print(f最小 10%: {areas[n//10]:.6f})归一化面积乘上imgsz²就是实际像素面积。如果中位数对应的像素面积小于 32×32就属于 COCO 定义的小目标必须上高分辨率或专门的小目标检测头。部署前验证别只看 mAP拿一段没参与训练的监控视频跑推理人工数误报和漏报。我习惯用混淆矩阵看两类互相误判的比例——睡岗被误判成玩手机通常是因为人趴着时手部位置和手机框重叠这种要靠补充难样本解决不是调参能救的。从那以后我每次拿到新数据集都强制先跑配对检查、类别名统计、坐标越界扫描这三步再动转换脚本。这三步加起来不到十分钟能省掉后面几小时的训练排查。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。