简介:面向深度学习与机器学习目标检测任务的人物玩手机图片数据集,可用于训练模型识别人们使用手机的典型姿态与状态。数据集共收录2015张jpg图像,并配套同等数量的xml标注文件,压缩包整体约311MB,数据规模适中,便于快速上手。标注框细分telephone、hold、nohold三类,分别对应手机、手持手机与未持有手机,标签采用VOC格式,兼容YOLO、SSD等主流目标检测框架。所有图片来自现实场景拍摄与网络收集,覆盖多种真实场景与人物状态;由团队自行标注并经过实际任务验证,标注质量较高,可作为训练集或验证集直接投入模型开发与精度评估。压缩包内目录结构清晰,图片与标签一一对应,省去自行整理匹配的麻烦;资源已有2870人学习,适合需要快速获取高质量玩手机检测数据的初学者与进阶开发者。
1. 人物玩手机图片数据集:监控画面里最难找的小目标
“人物玩手机图片数据集”在课堂专注度评估、工地安全告警和驾驶分心检测里,是需求量很大但公开资源很少的一块。它解决的核心问题是让深度学习模型在复杂背景中稳定识别“人正在使用手机”这个动作,而不是把手机当成普通物体分类。这个任务比想象中难:监控画面里的手机常常只有二三十个像素,低头看手机的姿势又和看书、趴桌高度重合,通用目标检测模型直接上场很容易翻车。因此需要一批标注规范、视角多样、正负样本平衡的图片数据集来支撑模型微调与验证。适合正在做行为识别项目、机器学习课程设计,以及想找一个完整实战项目练手的工程师和学生;动手之前,先把数据集的来路、边界和坑想清楚,能少走一半弯路。
2. 玩手机图片数据从哪来:公开集复用、自采与抽帧清洗的具体做法
2.1 公开数据集能提供的只是“底子”
常见做法是先拿公开数据集打底。MIO-TCD 和 VisDrone 这类交通监控数据集包含大量俯拍行人,但“手机”不是独立类别;COCO 有 cell phone 类目,但样本以近景生活照为主,监控视角下的手持手机样本非常少。所以公开集的价值有两个:一是让模型先具备通用特征提取能力,用 COCO 预训练权重初始化训练,比从头随机初始化收敛快得多;二是作为困难负样本——如果模型把屏幕反光误检成人脸,把这类反光图片混进训练集并标注为空背景,可以明显压制误检。我的习惯是公开集只用来初始化权重,而每次迭代微调的基准,始终以自建的人物玩手机图片数据集为准。原因很简单:公开集和你的摄像头角度、分辨率、场景光照不一致,混太多反而引入偏差。
具体到公开集的用法,我一般会从 COCO 里过滤出 cell phone 类目,下载约 500 张近景图片,和自采数据混合作为初始训练集;这一步能显著减少自采数据冷启动时第一版模型完全检不出的情况。之后再逐步用自采数据替换掉公开样本,最终版本里公开集占比不超过 10%。这样做的好处是模型先学会“手机长什么样”,再学习“监控画面里的手机长什么样”,比一步到位容易很多。
2.2 自采数据的三种路径:监控抽帧、模拟拍摄与合成增强
自采决定了数据集的天花板。三条路径可以并行,比例上我一般按 6:3:1 分配。
第一条是从已有的合规监控视频抽帧。注意必须是已经获得授权且完成脱敏的视频,这是工程上线的前提,不要在授权上存侥幸。抽帧用 ffmpeg 一条命令就能做:
# 从监控视频中每秒抽 1 帧,按带来源前缀的文件名保存 ffmpeg -i classroom_01.mp4 -vf "fps=1" -q:v 2 frames/classroom_01_frame_%04d.jpgfps=1 表示每秒输出 1 帧。玩手机这个动作通常持续数秒到十几秒,每秒 1 帧能保留姿态变化又不会产生大量近似重复帧;如果只抓“快速掏出手机看一眼”的瞬间,可以提到 fps=5,但标注量会成倍增加,建议先跑通再加密。文件名里的 classroom_01 前缀很关键,后面按视频维度划分数据集时,一眼就能认出帧归属。-q:v 2 控制 JPEG 输出质量,数值越小越好,我用 2;用默认值的话压缩痕迹重,标注小目标时连屏幕边缘都看不清楚。
第二条是模拟拍摄。找办公室、教室或厂房空地,架两个机位:一个 45 度俯拍模拟监控,一个平视模拟同桌视角。让志愿者轮流做四种动作:看屏幕、打字、打电话、手机放桌上。每个机位录 10 分钟,大约能产出 600 张有效帧。这里有两个容易忽略的点:第一,背景要杂,窗户、白墙、绿植、显示器各占一部分,否则模型会把背景颜色当成特征,换场景就废;第二,同一个志愿者不要连续录太久,否则人脸和衣服颜色会成为隐藏特征,导致模型在陌生人身上泛化变差。动作顺序也要随机化,避免模型学到动作出现的先后顺序。我一般每个志愿者录两轮就换人,每轮动作顺序打乱。
第三条是合成增强。把已经标注好的手机目标抠出来,随机旋转 15 度、透视拉伸,再贴到不包含手机的人体附近,可以低成本扩充样本。这是数据增强的一种常见做法,能缓解“手机只出现在画面固定区域”的偏差。但合成样本不能替代真实样本,比例建议控制在 20% 以内,否则模型会对贴图边缘的光影异常敏感。这一步也是机器学习实战里最容易被跳过的环节,很多人直接 commit 代码就开始训练,等到验证集指标虚高才回头补数据,得不偿失。
2.3 先删相似帧,再删模糊帧
抽完帧直接标注是大忌。视频里一个人低头看手机可能连续几十帧几乎一样,这些近似重复帧如果同时进入训练集和验证集,训练出来的 mAP 会虚高,上线就露馅。我一般用感知哈希做一次去重:
import os import imagehash from PIL import Image folder = "frames" seen = {} for fname in sorted(os.listdir(folder)): path = os.path.join(folder, fname) if not path.lower().endswith((".jpg", ".jpeg", ".png")): continue h = imagehash.dhash(Image.open(path), hash_size=16) for old_h, old_name in seen.items(): if h - old_h < 6: print(f"remove duplicate: {fname} ~ {old_name}") os.remove(path) break else: seen[h] = fname这里用 dhash 把图片缩成 16×16 的灰度网格,再用汉明距离衡量相似度,阈值取 6。为什么不用 MD5?因为视频抽帧的连续照片只是内容相似,像素不可能完全相同,MD5 一张都去不掉。这个脚本在几千张规模下没有问题,到几万张时 O(n^2) 的比对会变慢,可以把策略改成“只看相邻时间戳的帧”,效果相当且快得多。
去重之后还要去模糊。夜间监控和低码率视频经常产出糊成一片的帧,模型在模糊帧上能学到的特征非常有限。我用 OpenCV 的 Laplacian 算子计算清晰度方差,低于阈值的直接删:
import cv2 threshold = 20 for fname in sorted(os.listdir("frames")): img = cv2.imread(f"frames/{fname}") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) var = cv2.Laplacian(gray, cv2.CV_64F).var() if var < threshold: print(f"remove blurry: {fname}, variance={var:.1f}") os.remove(f"frames/{fname}")threshold=20 是针对普通 1080p 监控的经验值,不能照抄。第一次跑的时候先打印所有帧的方差分布,选一个能删掉底部 5% 的数值;如果视频本身是 4K,方差整体会上一个量级,阈值要跟着调。这个脚本最值得注意的点是别把动态模糊帧误删——人在快速转头导致的动态模糊,和目标本身糊是两回事,前者往往还保留着手机轮廓。
2.4 数据集的目录与版本,决定了后面能走多远
数据清理完,按 YOLO 的习惯组织目录:
datasets/phone/ images/ train/ val/ test/ labels/ train/ val/ test/images 和 labels 必须保持相同文件名,训练时 ultralytics 靠文件前缀匹配。给每个文件加上来源前缀,比如 camera01_frame_0217.jpg,这样后面排查某个 badcase 时能直接定位到原始视频。数据集每做一次增量更新,就把类别的总框数、平均框宽高、类别比例存成一个 stats.txt 放进目录里。别小看这个文件,它能让你在三个月后快速回忆这一版数据到底改了什么。数据版本不需要搞得很复杂,记录变更时间、样本量、标注规范版本就够了。
数据集文件命名也建议带上时间或版本标记,比如 v20240601 目录。我在迭代过程中经常遇到的问题是:三个月前标注的版本找不到了,或者找到了但不知道它和当前的差异。stats.txt 加目录命名能解决大部分这类问题。模型训练是科学,数据集管理很多时候是体力活,但正是这些体力活决定了项目能不能持续推进。
3. 把“玩手机”标成模型能懂的框:VOC 转 YOLO 与标注边界
3.1 标注对象怎么定义:两类目标与最难判定的低头场景
动手标之前,先要把“玩手机”拆成可执行的标注规范。同一个动作,不同人理解完全不同:有人把手机握在手里但没看屏幕,算不算玩手机?有人趴在桌上睡觉但手里攥着手机,算不算?我一般把类别拆成两个:
- holding_phone:手持手机,视线不一定在屏幕上;
- looking_phone:手持手机且视线朝向屏幕。
如果项目只需要一个布尔告警,可以把这两类合并成同一个类名,但训练时分开标、推理时再合并,模型学到的特征会更干净,因为两者在姿态上有明显差异。第三类是背景负样本:放在桌上的手机、插在口袋里的手机轮廓都不标,但如果画面里存在屏幕反光,建议画一个 ignore 区域,避免模型把亮度斑块学成手机。这个做法在监控玻璃反光多的场景尤其重要。
最难判定的是“低头看大腿”:可能在看手机,也可能只是休息。我统一按 looking_phone 标,理由很实际:真实场景里低头看手机的比例远高于闭眼休息,而且告警任务漏检的代价通常大于误检。这个先验是实际项目里比较重要的经验,标注规范里写清楚,比让标注员自己纠结高效得多。
类别不均衡在这个任务里几乎必然存在。多数监控场景中 holding_phone 的样本量可能是 looking_phone 的 5 倍,模型会天然偏向多数类,表现为 looking_phone 的召回率明显偏低。这不只是训练阶段的问题,数据准备阶段就要干预:少数类可以过采样复制,或者拍摄时专门安排更多“看屏幕”的动作。这些处理方式属于深度学习中容易忽略的知识点,很多人直到看到混淆矩阵才发现问题。
3.2 标注工具:LabelImg 与半自动标注的取舍
小规模数据用 LabelImg 足够,但几百张之后手会很酸。我现在更常用 X-AnyLabeling:先用一个已经能跑的检测模型对全部图片做预标注,生成 VOC 格式的 XML,再在工具里人工修正。这样单人一小时能处理 100 张左右,比纯手工快 3 倍以上,而且能把精力集中在调整边界而不是画新框上。
流程是:先手工标 200 张训练出第一版模型 → 用这个模型去标注剩余图片 → 人工重点检查置信度低于 0.6 的框和宽高比异常的框。预标注的框通常偏大,常见的是把整个前臂框进去,修正时贴着手机边缘收紧。如果多人协作,标注规范里还要明确一件事:手机屏幕亮灭都算手机,但只露出一根线的不算。这句话能避免大量无意义的返工。
批量标注完成后,不要直接全部转格式。我习惯随机抽 20 张,请第二个人独立复核,计算一下框的 IoU 一致性。两人对同一目标的框 IoU 低于 0.7 的图片单独列出来重新讨论。这个抽检只花 20 分钟,但能把标注标准的分歧控制在项目早期。等训练完再发现有错,返工成本就高很多了。这个习惯对几百张的数据集意义不大,到几千张时几乎是必须的。
3.3 VOC 转 YOLO:格式转换脚本与数据集划分
标注工具默认导出 VOC 格式 XML,YOLO 训练需要的是每张图对应一个 TXT,里面每行是“类别 中心点x 中心点y 宽度 高度”。转换脚本如下:
import xml.etree.ElementTree as ET import os classes = ["holding_phone", "looking_phone"] # 顺序必须与 data.yaml 的 names 一致 def convert(xml_path, out_txt): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") w, h = int(size.find("width").text), int(size.find("height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in classes: continue b = obj.find("bndbox") x1, y1, x2, y2 = (float(b.find(t).text) for t in ("xmin", "ymin", "xmax", "ymax")) x_c, y_c = (x1 + x2) / 2 / w, (y1 + y2) / 2 / h bw, bh = (x2 - x1) / w, (y2 - y1) / h lines.append(f"{classes.index(name)} {x_c:.6f} {y_c:.6f} {bw:.6f} {bh:.6f}") with open(out_txt, "w") as f: f.write("\n".join(lines)) for xml_file in os.listdir("annotations"): if xml_file.endswith(".xml"): convert(f"annotations/{xml_file}", f"labels/{xml_file[:-4]}.txt")转换后坐标是 0~1 的归一化值,所以无论训练时把图缩放到 640 还是 960,框都不会错位。脚本里有几处容易出错:classes 的顺序必须和后面 data.yaml 的 names 完全一致,否则混淆矩阵会是乱的;bndbox 里四个值读出来都是字符串,要记得转 float。跑完脚本后抽 3 张图,把 TXT 里的数值反算成像素坐标画框看一眼,这是最便宜的验证方式,30 秒能排查 90% 的转换问题。
数据集划分上,我坚持按视频而不是按帧分。同一个视频的连续帧只允许进入 train、val、test 中的一个集合,这样验证集分数才反映真实泛化能力,而不是反映模型对背景的背诵水平。比例用 8:1:1,随机种子固定,保证实验可比。实现上先按视频名分组再切分,不要直接对文件列表随机切。
3.4 难样本回标:把模型不认识的图片挑出来重标
第一版模型训练完后,拿它对全部未标注图片做推理,把预测分数很低但实际有手机的图片挑出来回标。这个操作叫 hard case 追溯,本质是让数据集向模型的盲区倾斜。回标时重点关注两类:一是手机被手臂或头发遮挡超过一半的样本;二是手机亮度与背景接近、几乎融为一体的样本。这两类是玩手机检测最主要的漏检来源,比再多拍 500 张常规图片都管用。
4. 用 YOLOv8 把玩手机数据集跑成模型:环境、命令与参数调优
4.1 深度学习环境配置:Ubuntu 20.04 下的 conda 与 CUDA 匹配
训练环境是第一个翻车点。给一套能在 Ubuntu 20.04 上直接跑通的配置:
conda create -n yolo python=3.10 -y conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics装 PyTorch 前先执行 nvidia-smi,看右上角 Driver 支持的 CUDA 版本。比如驱动支持 12.1,就选 cu121 的包;驱动版本老,硬装 cu121 会报 libcudart 不匹配。这里最常见的坑是很多人直接用 pip install torch 装了默认 CPU 版,或者 CUDA 版本对不上,训练慢得离谱。ultralytics 会自动拉依赖,网络不稳定就换国内镜像源。这一套流程几乎是每个深度学习项目都要走的,属于最常见也最基础的环节。
4.2 训练参数怎么定:imgsz、epochs、batch 与 weight_decay
数据准备好后,先建 phone.yaml:
path: /home/yourname/datasets/phone train: images/train val: images/val test: images/test names: 0: holding_phone 1: looking_phonepath 建议写绝对路径,省得换机器还要改配置。names 顺序必须和第 3 章转换脚本里的 classes 完全一致,类别索引错一位,模型输出就乱了。
训练命令:
yolo detect train \ data=phone.yaml \ model=yolov8n.pt \ imgsz=640 \ epochs=100 \ batch=16 \ device=0 \ workers=4 \ weight_decay=0.0005逐个说关键参数。imgsz=640 是速度和精度的折中点。监控画面里手机往往只有 20×40 像素,如果 mAP 上不去,可以提到 960,训练时间会增加约一倍,但小目标召回率通常能涨 3~5 个点。epochs=100 不是无脑照抄,我一般看前 30 轮的趋势决定是否提前停;如果第 10 轮 loss 还在原地踏步,优先查标注而不是加轮数。batch 由显存决定,6G 显存用 16,12G 可以用 32;batch 太小会让 BN 层的统计量不稳定,loss 震荡。
weight_decay=0.0005 就是 L2 正则化在 PyTorch 训练里的落地参数,对应很多人问的“L2 正则化防止过拟合到底怎么设”。它的作用是惩罚过大权重,样本量只有两三千张时尤其重要,调成 0 往往训练 loss 很漂亮,验证集却很快过拟合。数据量增大到 1 万张以上时,可以把 weight_decay 降到 0.0002,让模型更信任数据本身。
前面说过 looking_phone 样本可能只有 holding_phone 的五分之一,除了在数据侧做采样,最直接的办法是在训练命令里加 class_weights 参数。Ultralytics 支持传入按类别索引的权重列表,比如 class_weights='[1.0, 5.0]',让 loss 对少数类更敏感。注意这个参数和 weight_decay 一样属于正则化手段,权重别拉太高,超过 5 会让模型在多数类上误检激增。
数据增强方面,我保留 ultralytics 默认的 mosaic 和 fliplr,把 hsv_h 从默认 0.015 提到 0.03。监控画面颜色偏灰,适当加强颜色抖动可以让模型对灯光色温变化更鲁棒。mosaic 对小目标很友好,它把四张图拼在一起,变相提高了小目标在整图中的占比;但训练最后 10 轮我会关掉 mosaic,否则模型的框定位会偏粗糙。具体做法是用 ultralytics 的 cfg 参数覆盖增强项,而不是改源码。
模型规模上,第一版直接用 yolov8n 跑通,不要一上来就上 yolov8x。n 模型权重小、训练快,先快速验证数据有没有问题;等数据稳定后再试 yolov8s 或 yolov8m,通常能再涨 1~2 个点。另一种稳模型的做法是冻结骨干层。数据集只有几千张时,直接全量微调容易把预训练学到的底层特征抹掉。我一般先用 freeze=10 跑 20 轮冻结训练,再解冻微调 80 轮,在少量数据时比全量微调更稳。训练这件事有时候挺玄学,换模型带来的提升,往往不如往训练集里加 200 张难样本明显。
4.3 训练完先看三个数:mAP50、mAP50-95 与召回率
训练结束不要急着部署。先看验证集报表里的三个数:
- mAP50 高于 0.9:典型场景已能检出;
- mAP50 在 0.75~0.9:检查漏检集中在哪些视角,补对应样本;
- mAP50 低于 0.7:大概率是标注问题,回去查框边界,而不是调参。
mAP50-95 对框定位精度更敏感,如果它远低于 mAP50,说明框普遍偏大或偏小,去看验证集的可视化结果。还会用混淆矩阵看两类混叠:如果 holding_phone 大量被预测成 looking_phone,说明多人标注时“是否看屏幕”的标准已经漂移,需要重新对齐标注规范。召回率在在告警任务里的意义比精确率更重:recall 低意味着漏报,precision 低意味着误报;做安全告警宁可误报多一些也要保证 recall,做体验类产品则反过来。最后,把 val 里漏检的图单独导出,按漏检原因粗略分类,这比盯着总指标能更快定位问题。
ultralytics 每次训练都会在 runs/detect/train 下生成 results.png 和混淆矩阵,我习惯训练完把这两张图截到项目的 README 里,方便后面横向比较版本。这个习惯能省掉很多“我之前那版好像更好”的纠结。
5. 玩手机数据集实战避坑:能让 mAP 腰斩的 5 个标注与训练问题
玩手机图片数据集训练的翻车点基本都在数据,而不在模型结构。以下 5 个问题我都在真实项目里遇过,按现象、原因、解决三块写清楚。
5.1 屏幕反光被当成目标:模型学到了亮度斑块
现象:训练集里大量包含屏幕亮起的画面,验证集 mAP 虚高,部署到玻璃幕墙、白板反光的场景后疯狂误检。
原因:反光的视觉特征和手机屏幕几乎一样,模型本质上是在匹配高亮矩形,而不是理解“人手附近的高亮矩形”。根子是负样本缺失。
解决:在训练集加入 100~200 张包含反光但没有人的图片,不标任何框;同时对原图做亮度抖动增强,让屏幕亮度不再成为稳定特征。在 ultralytics 的增强配置里,把 brightness_limit=0.3 和 contrast_limit=0.3 直接加到增强参数即可。如果误检集中在某个特定机位,把这个机位的背景帧单独做成负样本集,效果最直接。
5.2 侧身玩手机大量漏检:采集视角太单一
现象:正面检测很好,侧面和背对镜头的人一掏出手机,recall 掉到一半以下。
原因:采集机位单一,正样本里八成是正面视角,模型没见过侧面持机的形态。
解决:重新录一段侧面视角视频,补标 300 张;更快的办法是把现有正面框做水平翻转,能模拟一部分左右侧视角。采集时列一个视角清单:正面、左侧 45 度、右侧 45 度、背面、被遮挡一半,每种至少 50 张。标注时把前臂轻微包进框里,而不是只框手机本身,模型就能利用手臂姿态作为辅助特征,侧面漏检会明显减少。注意镜像翻转会翻转手机上的文字,如果后续要做屏幕内容识别,不要用翻转图训练。
5.3 mAP 虚高、线上拉胯:时间相邻帧泄漏
现象:验证集 mAP 0.93,接到视频流后频繁把拿起水杯误检成玩手机。
原因:划分数据集时按文件随机切,同一个视频的连续帧同时进了训练集和验证集,模型实际上背下了画面背景,而不是学会了目标特征。这是整个项目里最隐蔽的坑。
解决:严格按视频维度划分,一个视频的帧只能出现在一个集合。实现上按视频名分组,再对分组做切分,而不是对单帧索引随机切。这个改动通常会让验证集 mAP 掉 5 个点左右,但线上表现会明显变稳,属于越掉越放心的那种下降。判断是否泄漏还有一个快速办法:训练完用模型跑一遍训练集,mAP 接近 1.0 而验证集只有 0.6,大概率是训练集内重复太多或场景过于单一;再跑测试集中同一段视频的不同片段,分数若起伏很大,说明模型没学到泛化特征。这时候先不要折腾超参数,回到数据划分上找问题。
提示:按视频维度划分后,验证集 mAP 下降是正常现象,别急着回滚,先看线上表现是否变稳。
5.4 训练 loss 不降,标注框比手机大三倍
现象:训练到第 10 轮 loss 还在 2.0 以上震荡,可视化结果里大量框把整个前臂包进去。
原因:多人协作时标注标准不统一,有人按手机边缘标,有人按“手部活动范围”标,标签噪声太大,模型无法收敛到稳定的框回归方向。
解决:开工前写一页标注 SOP,明确“框边贴着手机边缘,误差不超过 3 像素”;训练前统计所有标注框的宽高比分布,超过 3:1 的框自动列出来人工复检。这个统计用 pandas 读一遍所有 TXT 就能出结果,值得在每次训练前跑一次。SOP 里还要写明多类别时的优先级:如果一个人同时在打电话和看屏幕,只标一个主类别,不要两个都标,否则边界框会互相重叠,混淆矩阵也解释不清。
5.5 手机只有十几个像素,模型根本学不到特征
现象:低码率监控视频里,手机在整图中占比不到 5%,训练后该类召回率几乎为零。
原因:YOLO 下采样到 640 时,十几个像素的物体只剩一两个特征点。这不是模型不够强,是图像分辨率与目标尺寸不匹配。
解决:两个方向配合。一是训练时用 imgsz=1280,推理时配合切片检测,把大图切成 256×256 的 patch 再检测;二是数据侧做 copy-paste 增强,把已经标好的手机目标随机贴到背景图的多个位置,人为制造更多小目标样本。后者对数据集的效果立竿见影,但贴图位置要符合物理约束,别把手机贴在人的头顶上,否则模型学到的是“手机在画面任意位置”,而不是“手机在人手附近”。
以上 5 个问题如果同时出现,优先处理第 5.3 条的数据划分,因为它影响的是对模型能力的判断,其他问题大多会在划分修正后自愈一部分。
6. 把检测模型落到真实监控:切片推理、动态阈值与 badcase 台账
6.1 用切片推理救小目标
纯整图推理在小目标场景总有 3~5 个点的漏检。用 SAHI 做切片推理,把大图切成 256×256 的小块分别检测,手机在切片里相当于被放大了,漏检率能明显下降:
from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model = AutoDetectionModel.from_pretrained( model_type="ultralytics", model_path="best.pt", confidence_threshold=0.35, image_size=640, device="cuda:0", ) result = get_sliced_prediction( image="test_02.jpg", detection_model=model, slice_height=256, slice_width=256, overlap_height_ratio=0.2, overlap_width_ratio=0.2, )slice 尺寸取 256,是因为手机目标通常小于 50 像素,切分后能占到 1/5 画面;重叠率 0.2 防止目标被切在边界上被截断。代价是推理时间涨 3~5 倍,离线抽检用没问题,实时流可以只在 ROI 区域启用。
6.2 阈值不要全局统一
同一个模型在不同机位下,置信度分布完全不同:45 度俯拍的手机更完整,0.5 阈值足够;平视遮挡多,手机经常只露出一半,阈值降到 0.25 才能把 recall 拉回来。我的做法是每个通道配一个 conf 参数,上线前用一周的离线视频调一次,比在模型上反复调参划算得多。
6.3 badcase 台账是数据集的增量来源
模型上线不是结束。把每天误检和漏检的截图存进一个 badcase 文件夹,每周挑出有代表性的回标,再合入训练集重新微调。这个循环跑三个月,会比换任何网络结构都更有效。
我第一次做这个任务时,图快从公开网图里拉了一堆“手机”直接训练,结果在真实教室里 mAP 掉到 0.4,后来老老实实按视频维度划分、补负样本、建台账,模型才慢慢稳下来。这其中的大部分弯路都在前面几章踩过了,希望帮到你。
本文还有配套的精品资源,点击获取