资讯动态

监控摄像头玩手机检测数据集:4974张图三格式标注与YOLO实战指南

发布时间:2026/10/14 14:46:30 来源:尧图企业网站定制
简介玩手机识别检测数据集由室内监控摄像头在多角度、多背景下抓拍采集共4974张图片因体积较大拆成两部分当前压缩包为第一部分。压缩包共4126个文件整体约991.65MB核心内容是1375张jpg原图以及与之一一对应的1375个xmlVOC格式和1375个txtYOLO格式标注文件xml便于Pascal VOC系列算法读取txt可直接用于YOLO系列模型训练标签类别统一为playphone同时附带1个包含第二部分数据下载链接的7z文件。所有数据源自博主实际项目标注精准玩手机姿态多样、场景背景丰富可直接用于岗位分心监测、课堂或工位玩手机识别等目标检测任务也可作为课程作业、算法设计与竞赛的验证数据。整体已有773人学习下载适合需要室内玩手机识别样本的开发者直接使用。1. 玩手机检测数据集在监控场景的价值一份4974张、三种格式的“现货”能省多少事做监控行为检测的人都有一个共同烦恼公开数据集里“玩手机”的图大多是手机随手拍或者近距离摆拍人占画面比例大、角度正、光线好模型在验证集上跑得挺漂亮一部署到真实监控画面就漏检。监控摄像头通常装在墙角或高处俯视角度拍摄人在画面中可能只有几百个像素手机更小还经常被手部遮挡。所谓“玩手机数据集”核心价值恰恰在于它叫“多角度多背景-监控摄像头拍摄”并且规模给到了4974张配套VOC、YOLO、JSON三种标签格式。这意味着拿到压缩包之后无论你的训练管线习惯用哪种标注都能直接对接省掉了最耗时的数据清洗和格式转换环节。这篇文章就围绕这个数据集讲清楚它的场景边界、格式之间的换算关系、实际训练的参数设定以及那些容易让人翻车的细节。2. 监控摄像头视角下多角度多背景为什么是玩手机检测的命门很多从业者第一次拿到这类数据集时第一反应是看图。看久了会发现监控画面里的“玩手机”和普通图片里的“玩手机”完全是两种分布不能用常规思路去套用模型。2.1 从“自拍角度”到“俯视角度”监控数据集的分布差异监控摄像头的安装位置决定了拍摄视角走廊尽头的枪机往往是平视带俯角大厅上方的球机几乎是大角度俯视抓拍机则可能是斜向45度。这些视角下人体姿态和手机在画面中的形态差异非常大。正面平视时手机是一个清晰的矩形俯视时手机只是一个被手部包裹的小亮块边缘信息大量丢失斜侧角度时手机屏幕反光会直接把目标过曝成白斑。这就是“多角度”三个字背后的工程含义模型必须对不同视角下的同一行为有统一的特征表达。我在某监控项目中做过对比实验只用正面角度数据训练的模型在俯视测试集上漏检率直接翻倍。原因很好理解卷积神经网络对目标外观的变化是敏感的一旦训练分布里缺少某个视角的样本模型就会把该视角下的目标当作背景。所以数据集里如果注明了“多角度”通常意味着采集时覆盖了平视、俯视、斜视等多种机位而不是简单地把同一批图片翻转变换。多背景同样关键。监控场景的部署环境千差万别工厂车间有复杂的机械结构办公区有隔断和玻璃反光学校走廊有大面积的墙面纹理不同环境的纹理特征会干扰检测器对前景目标的判断。背景越丰富模型越不容易“背下”某个固定场景泛化能力才会真正体现在新场景上。这也是为什么很多实际项目宁可要少量多场景数据也不要大量单场景数据——前者是“处方药”后者只是“安慰剂”。2.2 用这张数据集能做什么三个典型落地场景与两个不适用场景以我接触过的项目来看这张数据集对应的实际需求主要在以下三个场景落地场景摄像头视角检测目标特点数据适配度工厂安全生产行为检测高位俯视/斜视人员远离镜头手机面积小高监控视角高度吻合考场纪律监控严肃场合教室顶装球机手部在桌面区域活动有遮挡较高需要配合区域限定使用客服坐席合规检测工位正面/斜前方手机在桌面或耳边目标较大高多背景利于跨工位泛化这两个场景则不适用第一类是手机型号或品牌识别因为它需要手机正面高清纹理监控画面根本无法提供第二类是近距离行为识别比如判断“刷视频还是回消息”这类需要屏幕内容语义必须靠更高分辨率的素材4974张监控图也撑不起这样的任务。判断一份监控数据集适不适合自己的项目最直接的问题是我的摄像头装在哪个高度目标在画面里大概占多少像素如果答案和数据集描述差距很大那再多的图片也帮不上忙。提示如果目标是“是否出现手机”这种二分类检测那张数据集的价值在于难例——小目标、部分遮挡、类背景干扰。如果目标是“手机品牌、屏幕内容”应该直接放弃。3. 三种标签格式协同工作VOC、YOLO、JSON的转换与校验拿到数据集后先别急着训练。很多新手会习惯性地用标注工具打开看一眼图片却忽略了标签格式本身的细节。我一般会先写几个脚本把三种格式的标注量做交叉验证确认没有问题再进训练。3.1 坐标体系对照XML的绝对坐标、TXT的归一化坐标、JSON的box数组在动手转换之前先搞清楚三种格式在“坐标”上的本质区别。VOC格式是XML文件每个目标用绝对像素坐标表示即xmin, ymin, xmax, ymax它描述的是目标框的左上角和右下角在图片上的物理位置。YOLO格式是TXT文件每一行代表一个目标格式为class x_center y_center width height所有数值都归一化到0到1之间坐标中心点、宽高都除以图片的宽和高。JSON格式最常见的实现是COCO风格annotations里的bbox字段是[x, y, width, height]同样是绝对像素坐标但和VOC的表示方式又不同。这三种格式的差异看起来只是一个算术问题实际工程里却埋了一个大坑图像尺寸不一致。监控视频流经常被裁剪、缩放同一批数据里可能出现1280×720和1920×1080混合的情况。YOLO格式因为做了归一化天然不受尺寸影响VOC和JSON是绝对像素坐标一旦图片被resize而标注没同步更新坐标就全错了。所以转换脚本里一定要以图片实际尺寸为准而不是盲信XML里的size字段。3.2 VOC转YOLO一个能直接跑的Python脚本如果你的训练框架是YOLO系列最常见的操作就是把VOC格式转成YOLO格式。下面这个脚本不依赖第三方标注库只用标准库里的xml.etree.ElementTree就能完成处理import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, output_path, class_list): tree ET.parse(xml_path) root tree.getroot() # 用PIL读取真实图片尺寸避免XML里的size字段和实际不一致 img_path xml_path.replace(.xml, .jpg) with Image.open(img_path) as img: img_w, img_h img.size lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_list: continue class_id class_list.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) # 钳制坐标防止标注出界导致训练报错 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) # 转换成YOLO的归一化中心点坐标和宽高 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) with open(output_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: # 类别顺序必须和后续训练配置里的data.yaml保持一致 classes [phone] xml_dir annotations/voc txt_dir annotations/yolo os.makedirs(txt_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue xml_path os.path.join(xml_dir, xml_file) txt_path os.path.join(txt_dir, xml_file.replace(.xml, .txt)) voc_to_yolo(xml_path, txt_path, classes)这段代码有四个值得注意的点。第一用Image.open读真实尺寸而不是信任XML里的size这能避免坐标整体偏移是数据集质量参差时最有效的兜底手段。第二坐标钳制到图像范围内防止个别标注框超出边界产生负数宽高这类问题往往不会在训练时报错而是悄悄拉低精度。第三class_list的顺序就是YOLO训练时的类别索引一旦顺序和后面data.yaml里的names不一致所有标注都会指向错误类别。第四输出坐标保留6位小数对监控这种小目标场景来说精度损失可以忽略但能显著减小标注文件体积。3.3 JSON转YOLO兼容COCO风格的转换脚本JSON格式最常遇到的是COCO风格。转换时需要注意一个细节COCO的bbox是[x, y, width, height]其中x、y是左上角坐标并不是VOC那种xmin, ymin需要计算宽高。转换脚本如下import json import os def coco_json_to_yolo(json_path, output_dir, images_dir): with open(json_path, r) as f: data json.load(f) # 建立image_id到文件名和尺寸的映射 image_info {} for img in data[images]: image_info[img[id]] { file_name: img[file_name], width: img[width], height: img[height] } # 建立category_id到类别索引的映射 # 注意COCO数据集的id往往不是从0开始的必须重新编号 category_map {} for idx, cat in enumerate(data[categories]): category_map[cat[id]] idx annotations_by_image {} for ann in data[annotations]: img_id ann[image_id] if img_id not in annotations_by_image: annotations_by_image[img_id] [] annotations_by_image[img_id].append(ann) for img_id, ann_list in annotations_by_image.items(): img image_info[img_id] img_w img[width] img_h img[height] lines [] for ann in ann_list: x, y, w, h ann[bbox] # COCO的bbox可能带小数需要处理负数和越界 x max(0, float(x)) y max(0, float(y)) w min(float(w), img_w - x) h min(float(h), img_h - y) if w 0 or h 0: continue x_center (x w / 2.0) / img_w y_center (y h / 2.0) / img_h width w / img_w height h / img_h cls_id category_map[ann[category_id]] lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 输出文件使用image_id对应的文件名 txt_name os.path.splitext(img[file_name])[0] .txt txt_path os.path.join(output_dir, txt_name) with open(txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: coco_json_to_yolo(annotations/instances.json, annotations/yolo, images)这段代码的核心逻辑是重新映射类别编号。COCO数据集的category_id是从1开始的而YOLO要求类别索引从0开始连续编号如果不做category_map映射就会造成类别错位。很多人在这一步翻了车还查不出原因因为训练日志里loss在下降精度却始终上不去最后仔细比对才发现训练数据和标注文件的类别编号对不上。另外这段脚本做了一个合理假设输出TXT文件名和图片文件名一一对应且放在同一个目录层级下。如果原始JSON里的file_name带了子路径建议统一清洗成纯文件名避免后续YOLO按相对路径找图时出现路径混乱。做完转换后我习惯对每个TXT文件做一次检查文件中不能有空行、不能有坐标小于0或大于1的数值这一条可以过滤掉90%的“坏标注”。注意所有转换脚本都应该在转换后做一次“坐标回读验证”——把YOLO的归一化坐标乘以图片宽高画框保存出来人工抽查20张图。这一步虽然慢但比训练到一半才发现数据有问题要省太多时间。4. 用YOLO把这4974张图跑成可用模型训练链路与参数设定数据格式校验完成后接下来就是把数据集喂给模型。这一章讲的不是YOLO的基础用法而是针对“监控摄像头玩手机检测”这个小目标场景的参数取舍。4.1 目录结构与数据集划分先避免“数据泄漏”再谈训练拿到数据集的第一步是整理目录结构。按YOLO官方习惯数据集应该组织成下面这样dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ ├── data.yaml └── train.txtdata.yaml的写法需要注意类别顺序和转换脚本里的一致path: /path/to/dataset train: images/train val: images/val names: 0: phone文件划分看起来是个简单操作但监控数据有一个特殊的“泄漏”风险同一段视频抽出来的连续帧内容非常相似如果随机划分训练集和验证集模型在验证集上看到的画面几乎和训练集一样指标虚高。拿到4974张图后我先按文件名前缀或采集时间段分组确保同一段监控视频的帧要么全在训练集、要么全在验证集再做随机打乱。这个习惯能有效避免训练阶段精度很高、实际部署时完全无用的尴尬局面。验证集比例我一般控制在15%到20%。4974张图的话验证集留800张左右比较合适。再少则评估结果波动大指标忽高忽低再多则训练数据不足小目标检测本来就吃数据。划分脚本的写法很简单import os import random import shutil random.seed(42) img_paths [f for f in os.listdir(images) if f.endswith(.jpg)] # 按文件名前缀分组例如以视频ID为前缀 video_groups {} for p in img_paths: prefix p.split(_)[0] video_groups.setdefault(prefix, []).append(p) train_files, val_files [], [] for prefix, files in video_groups.items(): random.shuffle(files) split_point int(len(files) * 0.85) train_files.extend(files[:split_point]) val_files.extend(files[split_point:])按前缀分组划分的核心目的就是把“数据泄漏”风险压到最低。如果你发现所有图片文件名都是无规律的hash值无法区分视频源那就退而求其次按时间戳排序每隔N帧抽一张进验证集。总原则是验证集必须尽量模拟“没见过的新场景”而不是同一段画面的复读。4.2 训练启动模型选型、图像尺寸与超参设置模型选型上监控场景的小目标检测不需要一上来就上最大的模型。以YOLO系列为例yolov8s或yolov9s这类小模型在监控场景的性价比最高——精度接近中等模型推理速度却快一倍。如果项目部署的是边缘盒子甚至可以考虑yolov8n起步先跑通流程再根据精度瓶颈升级。训练启动命令大致如下yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ imgsz640 \ epochs200 \ batch16 \ lr00.01 \ mosaic0.5 \ close_mosaic10 \ workers4参数说明这里多写几句。imgsz640是监控场景的默认起点输入太小则远处的手机目标可能只有几个像素特征完全丢失输入太大则训练显存和推理延迟都受不了。如果硬件条件允许可以试试imgsz960对漏检的改善立竿见影但推理速度会明显下降。mosaic0.5是我建议调低的参数——监控场景的行人姿态有比较强的空间约束Mosaic把四张图拼在一起会制造大量不自然的场景拼接反而增加学习难度。close_mosaic10表示最后10个epoch关闭Mosaic让模型在真实分布上收尾这个参数对最终精度的影响经常比改学习率还大。epochs设为200并不是绝对原则。小目标检测任务的前100个epoch往往就能看到指标稳定但要达到生产可用的精度200个epoch是比较稳妥的选择。重点观察训练日志里的val指标——如果验证集的指标连续30个epoch没有提升就可以考虑提前停止避免过拟合。4.3 监控场景下怎么验收指标之外还要看什么模型训练完成后千万不要只盯着mAP。监控场景里有两个更值得关心的维度。第一个是PR曲线靠近右上角的程度即精确率和召回率的均衡。玩手机检测的误报代价和漏检代价在不同场景里权重不同工厂安全生产场景漏检可能导致事故上报缺失应偏向召回客服坐席场景频繁误报会打扰正常办公应偏向精确。这些偏好通过对置信度阈值做后处理就能调整训练时不必过度纠结。第二个是“距离-目标尺寸”的实际测试。拿训练好的模型去跑一段没参与训练的真实监控视频人为统计在不同距离和姿态下的表现。最有效的验收方式是画一张检测结果分布表横轴为目标占画面比例纵轴为检测置信度。你会发现模型在目标较小时置信度普遍偏低这时应该考虑的不是调阈值而是补充小目标训练样本。我把这类“验证集之外”的测试称为“照妖镜”因为它的结果往往和训练指标差很多。数据划分再严谨验证集也只是对训练分布的一个采样监控场景长尾分布里那些模糊、遮挡、反光的姿势只有真实视频里才能遇到。5. 避坑把这份数据集用好的5个常见问题这类监控数据集交付时通常已经做过了清洗但并不意味着可以直接无脑训练。下面这几个问题是我在不同项目里反复遇到的按“现象、原因、解决”的顺序逐个说清楚。5.1 图像尺寸不一致导致标注集体偏移现象训练时loss正常下降但画出来的检测框整体偏左上或偏右下尤其在图片边缘的目标上特别明显。原因VOC或JSON格式的标注是绝对像素坐标如果转换脚本读取的图片尺寸和标注生成时的图片尺寸不一致所有坐标都会按比例缩放错位。常见的坑是XML里的size字段写着1280×720但实际图片是1920×1080转换后框的位置会整体偏移。解决转换脚本强制用PIL读一遍图片的真实宽高作为基准不信任任何标注文件里的尺寸描述。如果图片数量大读取耗时也值得因为这个错误一旦进入训练排查成本远高于读取成本。5.2 类别索引错位YOLO的cls是从0开始的整数现象训练和推理都正常但检测结果里phone类别总是和别的目标混淆画出的框在手机和手掌之间跳来跳去。或者验证集上精度始终不收敛到合理区间。原因VOC的name是字符串phoneYOLO的类别是整数索引。如果转换脚本里把phone排到索引1而data.yaml的names列表把phone放在索引0模型就会把所有的类别预测往后错一位。这种错误在单类数据集里很容易被忽略因为只有一个类别时错位表现为“没检测到”而不是“检测成别的”。解决训练前打印一次标注文件的内容和data.yaml的类别清单逐行核对。更稳妥的做法是在转换脚本里把类别名和索引映射以配置文件形式写死避免每次手动填写时手滑。5.3 多角度带来的小目标漏检验证集高但实拍漏现象验证集mAP达到0.9看起来效果很好但部署到真实场景后监控画面里远处有人掏手机模型完全没反应帧率倒是稳定。原因验证集里的图片虽然来自不同摄像头但参与训练的那些角度和测试角度分布相近指标自然虚高。真实场景中目标在画面中占的比例可能只有训练数据的几分之一超过模型的有效感受野范围。解决单独收集一条“困难样本集”专门挑那些目标占比小、背景杂、角度刁钻的图片做测试。训练时针对性地在训练集里加入这些困难样本并对部分小目标做二次裁剪放大后重复标注相当于给模型做“目标放大训练”。4974张数据的规模不算大用这种方式把有效样本密度提上来比单纯加epoch更管用。5.4 空标注和异常坐标训练中loss变成nan的常见元凶现象训练跑到某个epochloss突然变成nan之后一直不恢复日志里偶发Warning提示某个图片的标注框异常。原因转换脚本的数值检查不够严格。比如某个XML里出现了一个坐标为负数的框转成YOLO格式后中心点为负值模型在计算损失时除零或开方异常直接让梯度爆炸。更隐蔽的是空标注文件——图片存在但TXT内容为空YOLO会把它当成负样本如果数量过多模型倾向把所有区域都预测为背景。解决加一个训练前的数据体检脚本逐文件检查三件事TXT文件是否为空、每行是否有且只有5个数值、所有数值是否在0到1之间宽高还要大于0。任何一条不满足就把对应图片移出训练集。这一步花不了几分钟但能避免数小时训练打水漂。5.5 增强配置失当Mosaic与旋转反而让监控模型变笨现象训练损失很低验证指标也不错但拿到真实场景里一测目标只要不是正面的基本全漏。原因数据增强在监控场景是一把双刃剑。YOLO默认的Mosaic会把不同图片拼接模拟出复杂背景但也会制造大量的“行人横着躺”“手机悬浮在空中”这类现实中不可能出现的画面。监控场景有自己稳定的视角规律模型学到的应该是“人在画面中的常见形态”而不是学会无视这些不正常的拼接样本。解决训练配置里关掉或大幅调低mosaic、degrees旋转和shear错切这三个参数保留translate、flipud这类不影响物理规律的增强。degrees甚至可以直接设为0因为监控画面很少发生大角度旋转而flipud依赖摄像头安装方式地装和顶装的画面语义不同盲目翻转也会引入噪声。增强配置的“后手”是等模型跑一遍真实测试哪些增强可以用再逐渐加回去而不是一开始就全开。6. 进阶从验证集到真实场景的最后一公里训练指标再漂亮模型最终要面对的是真实监控视频流。这一章聊聊两个让模型真正“能用”的进阶操作。6.1 导出ONNX并在真实监控截图上做端到端推理YOLO训练得到的权重是PyTorch格式部署时通常需要转成ONNX再用推理引擎跑。导出命令如下yolo export modelbest.pt formatonnx imgsz640 opset12导出后不要直接相信我务必找几张没参与训练的真实监控截图跑一次端到端推理并和PyTorch格式的推理结果逐一比对。对比的标准有三条检测框位置偏差是否在1像素以内、置信度差异是否在0.01以内、漏检目标是否一致。任何一条不满足都说明导出过程有兼容性问题可能是某些算子不支持或被重新排序了。我在实际项目里遇到过一次典型翻车ONNX导出的模型在GPU上推理结果正常换到CPU推理引擎后检测框整体偏移了几个像素。排查了很久才意识到是模型在导出时有一步坐标反算被编译优化掉了CPU和GPU的浮点计算顺序不同导致误差累积。到处没后悔药吃最后只能重新导出并固定了推理引擎的优化等级。所以我的习惯是每次导出后都用同一张图同时跑PyTorch和ONNX两个版本把结果并排打印出来看一眼这个习惯救了我很多次。6.2 难例挖掘用模型自己补数据的闭环小目标检测模型的提升往往不在网络结构上而在难例挖掘上。流程并不复杂拿训练好的模型跑一段覆盖多种场景的未标注监控视频输出低于置信度阈值但形状匹配的“模糊检测结果”把这些结果抽帧保存人工快速复核将确认是玩手机行为的图片补进训练集。这个闭环每一轮都能给模型注入新样本效果往往好过单纯增加epoch。4974张的初始规模经过两三轮难例挖掘后真正有效的训练分布会远比原始数据更贴近实际部署条件。我一般会每跑完一轮训练就执行一次难例挖掘循环三四次。最后分享一个私人习惯所有监控类检测项目我都先做“只划分、不训练”的全流程试跑——数据检查、格式转换、目录划分、导出推理全部走通一遍确认没有低级错误再启动正式训练。这套流程看着多花半天时间真正到部署阶段能省下的排查时间却是以天计算的。希望这篇关于玩手机数据集的使用笔记能帮到你让你的监控检测项目少走一段弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑