简介:这份手机识别数据集面向计算机视觉初学者、目标检测算法练习者以及需要手机类目样本的开发者,用于训练和验证手机目标检测或图像分类模型。资源包共2000个文件,以1997张jpg原始图片为主,另附3个json标注文件,压缩包约82.97MB,图片命名包含IMG与pp等前缀,覆盖多种拍摄场景与角度,json文件采用coco格式,可直接对接主流检测框架的数据加载流程。目前已有715人学习下载,说明其在手机识别任务中具备一定参考价值。读者可借助这批原始图片与coco标注,快速搭建训练集与验证集,完成模型微调、数据增强或标注格式转换等实验,省去自行采集与标注的时间成本,适合作为课程设计、毕业项目或算法入门的实战素材。
1. 手机识别数据集落地:2628 张原始图片与 COCO JSON 标注到底怎么用
手里有一批手机拍摄的原始照片,想训练一个能识别手机的检测模型,最卡脖子的往往不是网络结构,而是标注。这份手机识别数据集给了 2628 张原始图片,标注直接以 COCO JSON 格式提供,意味着你不需要从零画框,拿到手就能接进主流检测框架。它适合三类人:一是想跑通目标检测全流程的新手,二是需要快速验证模型结构或数据增强策略的算法工程师,三是做手机检测相关应用、缺一份干净标注数据的从业者。文件名里那些IMG20211010...和mobile-phones-_jpg.rf...的命名,说明图片来自真实拍摄场景,不是合成图,这对模型泛化是好事。下面按「数据长什么样 → 怎么转成训练格式 → 怎么训 → 坑在哪」的顺序拆开讲。
2. COCO JSON 标注结构拆解:先看懂再动手
2.1 COCO 标注的四个核心字段
COCO 格式的标注文件本质是一个大 JSON,检测任务里你只需要盯住四个顶层字段:images、annotations、categories、info。images记录每张图的id、file_name、width、height;annotations是每个标注框,含image_id、category_id、bbox、area、iscrowd;categories定义类别,手机识别通常只有一个类,id可能是 1 或 0,这点必须先确认,否则训练时类别对不上。bbox的格式是[x, y, width, height],注意是左上角坐标加宽高,不是[x1, y1, x2, y2],这是新手最容易翻车的地方。
先用一段 Python 把标注读出来,确认字段和类别:
import json # 换成你的标注文件路径 with open("annotations/instances.json", "r", encoding="utf-8") as f: coco = json.load(f) print("图片数量:", len(coco["images"])) print("标注数量:", len(coco["annotations"])) print("类别:", coco["categories"]) # 看第一条标注的 bbox 格式 first = coco["annotations"][0] print("bbox:", first["bbox"], "category_id:", first["category_id"])这段代码的作用是先做数据体检。len(coco["images"])应该接近 2628,如果差很多,说明标注文件不完整或图片有缺失。categories打印出来要确认类别数和id,后面转 YOLO 时要用。bbox打印出来看数值范围,如果出现负数或超出图片宽高,说明标注有脏数据,得先清洗。
2.2 图片与标注的对应关系校验
COCO 里图片靠file_name关联磁盘文件,标注靠image_id关联图片。常见问题是标注文件里的file_name和实际图片文件名对不上,比如多了前缀路径或扩展名大小写不一致。写个校验脚本,把缺失和多余的都列出来:
import os img_dir = "images" disk_files = set(os.listdir(img_dir)) anno_files = set(img["file_name"] for img in coco["images"]) missing = anno_files - disk_files # 标注里有、磁盘上没有 extra = disk_files - anno_files # 磁盘上有、标注里没有 print("标注有但图片缺失:", len(missing)) print("图片有但标注缺失:", len(extra)) print("示例缺失:", list(missing)[:5])missing不为空说明有标注找不到图,训练时会直接报错;extra不为空说明有图没标注,可以留着做测试集或直接忽略。这一步花两分钟,能省掉后面训练时反复排查的时间。我一般会把校验结果写进日志,数据一换就重跑一遍。
2.3 类别 id 与训练配置的映射
手机识别通常是单类,但 COCO 的category_id不一定是 0。YOLO 系列要求类别从 0 开始连续,所以转换时必须做一次映射。假设categories里手机的id是 1,那转换后所有框的类别都要减 1 变成 0。如果直接拿 COCO 的category_id去训 YOLO,会出现类别索引越界或全部预测成背景的玄学现象。转换脚本里加一行映射表就能解决,后面第 3 章会给完整代码。
3. 转成 YOLO 训练格式:转换脚本与参数说明
3.1 为什么优先转 YOLO txt 而不是直接用 COCO
COCO JSON 适合做数据管理和评估,但训练时很多框架读 COCO 的效率不如读 txt。YOLOv5、YOLOv8 默认吃的是每张图一个.txt,每行class_id x_center y_center width height,且坐标是归一化到 0~1 的。转成这种格式后,训练时不用每次解析大 JSON,数据加载更快,也方便你直接看某个框对不对。常见做法是保留原始 COCO JSON 做备份,另生成一份 YOLO 格式的目录结构。
3.2 完整转换脚本
下面这个脚本把 COCO JSON 转成 YOLO 的 images/labels 结构,同时做类别映射和坐标归一化:
import json import os from PIL import Image coco_path = "annotations/instances.json" out_img_dir = "yolo/images" out_lbl_dir = "yolo/labels" os.makedirs(out_img_dir, exist_ok=True) os.makedirs(out_lbl_dir, exist_ok=True) with open(coco_path, "r", encoding="utf-8") as f: coco = json.load(f) # 建立 image_id -> 图片信息 的索引 img_info = {img["id"]: img for img in coco["images"]} # 类别 id 映射:COCO 原始 id -> 从 0 开始的连续 id cat_ids = sorted(c["id"] for c in coco["categories"]) cat_map = {cid: idx for idx, cid in enumerate(cat_ids)} print("类别映射:", cat_map) # 按 image_id 聚合标注 from collections import defaultdict anno_by_img = defaultdict(list) for ann in coco["annotations"]: anno_by_img[ann["image_id"]].append(ann) for img_id, info in img_info.items(): w, h = info["width"], info["height"] file_name = info["file_name"] # 复制或软链图片到 yolo/images src = os.path.join("images", file_name) dst = os.path.join(out_img_dir, file_name) if os.path.exists(src) and not os.path.exists(dst): os.symlink(os.path.abspath(src), dst) # 软链省空间,也可用 shutil.copy # 写 label 文件 label_name = os.path.splitext(file_name)[0] + ".txt" with open(os.path.join(out_lbl_dir, label_name), "w") as lf: for ann in anno_by_img.get(img_id, []): x, y, bw, bh = ann["bbox"] # 归一化并转中心点 xc = (x + bw / 2) / w yc = (y + bh / 2) / h nw = bw / w nh = bh / h cls = cat_map[ann["category_id"]] lf.write(f"{cls} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}\n") print("转换完成")逻辑上分四步:先建image_id到图片信息的索引,避免循环里反复查;再做类别 id 映射,保证从 0 开始;然后按image_id把标注聚合,减少遍历;最后逐图写 txt,坐标从[x, y, w, h]转成归一化的中心点格式。参数上,cat_map是关键,如果你的数据集类别 id 本来就是 0,映射后不变;symlink那行如果系统不支持软链,换成shutil.copy即可。归一化保留 6 位小数足够,再多没必要。
3.3 生成训练用的 data.yaml
YOLO 训练需要一个 yaml 描述数据路径和类别:
path: ./yolo train: images val: images nc: 1 names: ["phone"]nc是类别数,手机识别填 1;names顺序必须和cat_map的值对应,即索引 0 对应 phone。如果后面你加了别的类别,这里要同步改。train和val这里先都指向 images,正式训练前应该按 8:2 划分,别拿训练集当验证集,否则指标虚高,上线就翻车。
4. 训练与验证:从 2628 张图跑出可用模型
4.1 训练命令与关键参数
以 YOLOv8 为例,装好环境后一条命令就能起训:
yolo detect train \ data=./yolo/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/phone \ name=exp1model=yolov8n.pt用预训练权重,2628 张图不算多,从头训容易过拟合,迁移学习更稳。imgsz=640是常见输入尺寸,如果原图分辨率很高且手机目标小,可以提到 960,但显存和速度要权衡。batch=16按显存调,爆显存就降到 8。patience=20表示 20 轮没提升就早停,省时间。lr0=0.01是初始学习率,小数据集可以降到 0.001 更稳。
4.2 验证指标怎么看
训练完看runs/phone/exp1下的结果,重点看mAP50、mAP50-95和precision/recall。手机识别单类,mAP50上 0.9 通常说明数据质量不错;如果mAP50高但recall低,说明漏检多,可能是小目标或遮挡样本不够。混淆矩阵里如果背景被大量误检成手机,检查标注里有没有把非手机区域框进去。验证时用yolo detect val指定同一份 data.yaml,别手动改路径,容易对不上。
4.3 推理与结果导出
训完直接推理一张图:
yolo detect predict \ model=runs/phone/exp1/weights/best.pt \ source=test.jpg \ conf=0.25 \ save=Trueconf=0.25是置信度阈值,手机检测场景可以调到 0.4 减少误报。save=True会把画框结果存下来,方便肉眼检查。如果发现框偏了,多半是转换时坐标没归一化对,回头查第 3 章的脚本。
5. 避坑与排查:标注和训练里最容易翻车的五件事
5.1 现象:训练 loss 一直不降,mAP 接近 0
原因通常是类别 id 没映射,COCO 的category_id是 1,YOLO 按 0 读,导致所有框被当成无效类。解决:回到第 3 章脚本,确认cat_map输出,data.yaml的names索引和它一致。
5.2 现象:报错「No labels found」
原因多是 label 目录结构和 data.yaml 不匹配,或者 txt 文件名和图片名没对上。YOLO 要求图片和同名 txt 在同一级或对应目录。解决:检查yolo/labels下是否有和图片同名的.txt,data.yaml 里train路径指向的目录下要有images和labels两个子目录,或者用train: images加labels自动推断。
5.3 现象:框位置整体偏移或缩放
原因是 bbox 没归一化,或者用了[x1,y1,x2,y2]当[x,y,w,h]。COCO 的 bbox 是左上角加宽高,YOLO 要中心点加宽高再除以宽高。解决:在转换脚本里打印一条转换前后的框,和原图对照,确认中心点落在目标上。
5.4 现象:验证集指标高,实际推理漏检严重
原因是训练集和验证集没分开,或者验证集图片和训练集重复。2628 张图如果全拿去训,验证指标没有意义。解决:按 8:2 划分,用脚本随机 split,确保验证集图片不出现在训练集里。
5.5 现象:显存爆掉或训练极慢
原因是imgsz或batch太大,或者图片分辨率远超模型输入。解决:先降batch到 8 或 4,再考虑降imgsz。如果原图是 4000 像素宽,训练前统一 resize 到 640 或 960,别让数据加载成为瓶颈。
6. 进阶技巧:用 COCO 评估接口反查标注质量
训完模型别急着收工,用 COCO 官方评估接口跑一遍,能反查出标注里的问题。COCO 的pycocotools支持按面积、类别统计,如果某些尺寸的框 AP 特别低,说明那类目标标注可能有问题。装好pycocotools后,把预测结果转成 COCO 格式再评估:
from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval # 加载原始标注和模型预测结果(预测需转成 COCO results 格式) coco_gt = COCO("annotations/instances.json") coco_dt = coco_gt.loadRes("predictions.json") e = COCOeval(coco_gt, coco_dt, iouType="bbox") e.evaluate() e.accumulate() e.summarize() # 按面积看 AP,定位小目标问题 for area in ["small", "medium", "large"]: e.params.areaRng = [e.params.areaRng[0], e.params.areaRngLbl.index(area)] e.evaluate() e.accumulate() print(area, e.stats[0])这段代码的价值在于把整体指标拆到不同尺度。如果small的 AP 明显低于large,说明小手机目标标注或增强不够,可以针对性加 mosaic、copy-paste 增强。predictions.json需要你从 YOLO 输出转成 COCO 的[x,y,w,h,score,category_id]格式,写个小转换函数即可。我一般会在第一次训练后就跑这个评估,把低 AP 的类别和尺度记下来,回头补标注或调增强,比盲目加轮数有效得多。从那以后我每次拿到新数据集,都强制先跑一遍 COCO 评估再决定训练策略,省下的时间够多训好几轮。希望帮到你。
本文还有配套的精品资源,点击获取