尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

COCO数据集全解析:从JSON标注到pycocotools实战

COCO数据集全解析:从JSON标注到pycocotools实战 简介面向目标检测初学者的COCO数据集实战代码包将COCO数据集的介绍与YOLOv8训练流程封装为可直接运行的Python工程帮助读者快速搭建目标检测实验环境。COCO数据集具备高通用性和多样性包含超过12万张图像、80类常见物体覆盖城市、家庭、自然和运动等真实场景可支撑目标检测、实例分割、关键点检测等任务并适配YOLOv5、YOLOv8、Faster R-CNN等主流框架。包内共9个文件压缩后仅12KB核心包括训练、验证、推理三个Python脚本分别对应模型训练、精度评估与自定义图片推理data.yaml与requirements.txt完成数据与依赖配置index.html用于可视化展示数据集说明TODO.md记录后续优化方向。已有170人浏览学习。资源提供了从环境配置、数据准备、模型训练、验证与测试到自定义推理和部署建议的完整流程并附带应用场景、样本展示和使用建议等说明能显著降低学习成本适合目标检测入门和项目快速验证。 COCO数据集Common Objects in Context可以说是做目标检测、实例分割、人体关键点检测绕不开的一个名字。无论是刚入门的同学还是打了多年比赛的老人训练模型之前都绕不过“先下个COCO看看”。我最早接触COCO是为了复现一个Mask R-CNN的demo当时以为就是下载个zip然后解压结果光是理解annotation文件里的JSON结构就花了一整天。这篇内容我把COCO数据集的整体结构、标注文件逻辑、pycocotools的使用方式以及几个真实踩坑经验都整理出来给准备拿COCO做训练或者做自定义数据集的人做个参考。标题里带“代码”所以我会把常用的读取、可视化、格式转换代码也一起放上来这些都是我自己跑通的版本可以直接复用。1. COCO凭什么成了目标检测的“默认考场”1.1 这套数据集的诞生背景COCO全称是Common Objects in Context由微软团队发起。2014年首次发布2015年补充了更多图片和标注到2017年形成了现在最常用的版本。它的核心目标不是做那种“物体在正中间、背景干净”的分类图片而是强调“context”也就是物体所在的上下文环境一张图里多个物体互相遮挡、目标有大有小、有远有近这更接近真实场景。我对比过VOC和COCO之后最大的感受就是VOC像课堂测验COCO像综合性考试。VOC的20个类别、每张图目标相对简单而COCO有80个类别图片里目标密度高小目标特别多。评测指标也狠COCO在0.5到0.95区间取多个IoU阈值算mAP比VOC只看IoU0.5严格得多。所以现在论文报告实验结果几乎都会给COCO的AP、AP50、AP75这一串数据这不是没道理的它更能反映模型在复杂场景下的真实能力。1.2 2014版和2017版到底怎么选很多新手卡在“2014还是2017”这个问题上。我的建议很简单新项目直接用2017版。2014版主要用于早期的论文和比赛train/val/test划分是另外用annotation文件指定的test阶段还分test-dev、test-challenge对一般人来说很麻烦。2017版把train和val的图片集直接固定成文件目录train2017有118287张图val2017有5000张图用起来直观得多。关键点标注和实例分割标注在2017版也划分得更清晰不用自己去处理那些历史遗留的跨年份兼容问题。虽然两个版本的图片内容大部分重叠但具体文件名和标注ID组织方式不同。如果你不是必须复现一篇2017年之前的论文就不要给自己找麻烦直接下载2017。2. 下载与目录结构别让文件白下2.1 官方下载地址与体积COCO数据集的下载地址很分散不是一个大压缩包解决所有事而是按图像和标注分开下载。官网上的大致情况如下文件内容体积train2017.zip训练集图片约18GBval2017.zip验证集图片约1GBannotations_trainval2017.zip训练/验证标注约840MBtest2017.zip测试集图片无公开标注约6GBstuff_annotations_trainval2017.zipStuff分割标注约560MB如果你只想跑目标检测或实例分割最核心的就是train2017、val2017和annotations_trainval2017这三个。stuff标注是给场景理解这类任务用的不是第一步需要的东西。下载时我强烈建议用命令行工具不要用浏览器。我用aria2开16线程下载train2017速度能跑满带宽时间能缩短很多。命令大概是这样的aria2c -x 16 -s 16 -o train2017.zip http://images.cocodataset.org/zips/train2017.zip下载过程中经常会因为网络波动中断aria2的好处是支持断点续传重新执行一次命令就能接着下载。2.2 解压之后应该形成什么文件层级COCO官方没有强制的目录结构但在绝大多数据加载代码里默认组织方式是这样的coco/ ├── train2017/ │ ├── 000000000139.jpg │ ├── 000000000285.jpg │ └── ... ├── val2017/ │ └── ... └── annotations/ ├── instances_train2017.json ├── instances_val2017.json ├── person_keypoints_train2017.json ├── person_keypoints_val2017.json └── captions_train2017.json很多人解压完发现图片没放在指定的相对位置后面用Detectron2或者MMDetection就会报找不到文件。这不是代码的bug而是路径配置问题。我一般会用软链接把数据集指到统一的目录比如ln -s /data/datasets/coco /workspace/coco这样不管在哪个项目里跑只需要修改一处路径环境变量就能复用同一份数据集不用反复拷贝十几G的数据。3. JSON标注文件应该怎么读3.1 顶层字段的定位annotations目录里最常用的是instances_val2017.json它是整个数据集的“说明书”。用任意JSON解析工具打开顶层有五个字段info数据集的版本、发布时间等元信息licenses图片的许可信息images所有图片的信息列表annotations所有标注物体信息列表categories类别定义列表我一开始犯过的错误是以为images和annotations是一一对应的其实不是。一张图片在images里有一个条目但在annotations里可能有多个条目因为一张图里往往标注了几十个物体实例。要看懂数据必须先把images和annotations通过图片ID关联起来。3.2 images字段和annotations字段images里的一个元素长这样{ id: 139, file_name: 000000000139.jpg, width: 640, height: 426, date_captured: 2013-11-21 01:34:41, license: 1 }它描述的是“这张图本身的性质”。id是全局唯一的图片IDfile_name是对应到train2017或val2017目录下的jpg文件名。annotations里的一个元素长这样{ id: 1286, image_id: 139, category_id: 3, bbox: [116.0, 105.0, 342.0, 261.0], area: 89262.0, segmentation: { counts: ..., size: [426, 640] }, iscrowd: 0 }这里的关键信息有几个image_id对应images字段里的id用来找图片category_id对应categories里的id注意这个id不是从0开始的连续索引而是从1开始的稀疏编号bbox是[x, y, width, height]格式x和y是左上角坐标width和height是宽高segmentation是分割掩码iscrowd为0时是polygon多边形格式iscrowd为1时是RLE格式表示一组密集重叠的物体比如一群人3.3 categories的索引陷阱categories字段是按数组顺序排列的但里面的id并不等于数组下标。比如categories: [ {id: 1, name: person}, {id: 2, name: bicycle}, {id: 3, name: car} ]这里数组下标0对应的是person但如果代码里直接用coco.loadCats(0)得到的是bicycle这不是bug而是COCO的id设计如此。实际应用中如果想把类别连续化比如从0开始编号用于模型训练必须自己维护一个映射表不能想当然用下标。4. 用pycocotools把数据变成训练样本4.1 pycocotools的安装与基本结构pycocotools是COCO数据集的官方工具库所有数据处理基本都离不开它。安装比较简单pip install pycocotoolsWindows如果装不上一般是因为缺少C编译环境需要先安装Visual Studio Build Tools或者用conda装预编译版本。核心用法是创建一个COCO对象然后通过API去遍历图片和标注。它的内部其实已经帮你做了images和annotations的关联不需要自己手写哈希表。4.2 加载并可视化一个实例我写了一个常见的可视化脚本把某张图里的目标框和分割掩码画出来方便确认数据是否正常from pycocotools.coco import COCO import requests import numpy as np from PIL import Image import matplotlib.pyplot as plt import matplotlib.patches as patches ann_file annotations/instances_val2017.json img_dir val2017 coco COCO(ann_file) img_ids coco.getImgIds() img_info coco.loadImgs(img_ids[0])[0] img_path f{img_dir}/{img_info[file_name]} img Image.open(img_path).convert(RGB) plt.figure(figsize(12, 8)) plt.imshow(img) ax plt.gca() ann_ids coco.getAnnIds(imgIdsimg_info[id]) anns coco.loadAnns(ann_ids) for ann in anns: bbox ann[bbox] rect patches.Rectangle( (bbox[0], bbox[1]), bbox[2], bbox[3], linewidth2, edgecolorred, facecolornone ) ax.add_patch(rect) cat coco.loadCats(ann[category_id])[0][name] ax.text(bbox[0], bbox[1]-5, cat, colorred, fontsize12) plt.axis(off) plt.savefig(coco_visualization.jpg, bbox_inchestight)运行这个脚本你会看到图片上叠加了红框和类别名称。如果某个矩形框显示不正常先检查bbox里有没有负数或宽高为0的情况这种脏数据在COCO里虽然少但也不是没有。如果需要绘制分割掩码可以用coco.annToMask()函数把RLE或多边形转成二值掩码mask coco.annToMask(ann) plt.imshow(mask, alpha0.5)这个函数是pycocotools里性价比最高的功能之一省去了自己解析polygon的麻烦。4.3 转到YOLO格式时的坐标换算用YOLOv8训练COCO或其他自定义数据时需要把COCO的bbox转成YOLO的归一化格式。YOLO要求的是中心点坐标x_center、y_center和宽高w、h并且要除以图片的宽和高。转换脚本可以这样写def coco_bbox_to_yolo(bbox, img_width, img_height): x, y, w, h bbox x_center (x w / 2) / img_width y_center (y h / 2) / img_height w_norm w / img_width h_norm h / img_height return [x_center, y_center, w_norm, h_norm]注意YOLO的标签文件每一行是“class_id x_center y_center width height”这里的class_id要求从0开始连续编号所以必须把COCO的category_id重新映射一遍否则训练时类别会错位。我在做这个转换的时候遇到过一个奇怪的问题有些图片的标注框坐标超出了图片范围导致YOLO训练报错。后来发现是原始标注里小部分框的坐标比width或height略大一点原因是标注时物体边缘刚好在图像外。解决办法是做一个裁剪把坐标限制在[0, 1]之间。这个处理在自定义数据集上也经常碰到。5. 我在COCO上踩过的坑5.1 一个“看起来成功”的加载失败案例有一次我自信满满地写了一个数据加载器跑起来也没有报错但训练出来的模型指标特别差。一开始我怀疑是模型的问题折腾了一整天。后来我打印了几张训练样本才发现标注框和图片内容完全对不上。原因是我的代码里用了categories数组的下标当作category_id但COCO的id不是连续的。模型训练时的监督信号从头到尾都是错的相当于对着错误的答案学习效果自然不会好。排查这个问题的方法很简单加载数据时打印image_id、category_id和实际类别名人眼看几张图就能发现问题。不要只依赖训练loss的变化loss下降不代表数据没问题。5.2 关键点标注的结构与常见误解如果做人体姿态估计会用到person_keypoints_val2017.json。这个文件里的annotations元素在实例分割的基础上多了两个字段keypoints长度为17*3的数组每三个一组表示一个关键点的x、y、visibility0不可见1遮挡但存在2可见num_keypoints有效关键点数量我的误解点在于一开始以为person类型的物体都在person_keypoints文件里标注了关键点实际上不是。这个文件虽然只包含person类别的标注但不是所有person都有完整的关键点标注有些实例的num_keypoints是0关键点全是[0, 0, 0]。训练时需要对这类样本做过滤否则模型会被无效的关键点坐标干扰。5.3 磁盘空间与解压问题COCO全套数据量很大最好预留60GB以上的磁盘空间。我遇过最尴尬的情况是下载完train2017.zip解压时提示磁盘空间不足结果zip被解到一半就崩了最后只能删除重新解压。更稳妥的做法是解压前用df -h检查当前剩余空间然后定向解压到数据盘比如unzip train2017.zip -d /data/datasets/coco/如果磁盘实在紧张另一种做法是训练时用在线下载脚本按需读取但要保证网络足够稳定。对刚开始做实验的人来说我还是建议一次性把数据备齐反复下载的时间成本远高于磁盘成本。6. 自定义数据集如何“蹭”COCO生态6.1 把自己的数据转成COCO格式多数开源框架包括MMDetection、Detectron2都实现了COCO格式的数据加载器。所以自定义数据集最省力的路线不是写一个全新的Dataset类而是把数据转换成COCO格式然后直接用现成加载器。转换时最少需要准备三个列表images每张图片的id、file_name、width、heightannotations每个目标的id、image_id、category_id、bbox、areacategories类别的id和name我写过一个小脚本把自家的工业检测数据集整理成COCO结构。这里有一个比较关键的细节如果不会算分割多边形可以只提供bbox和area但area必须提供因为COCO的mAP计算里会按面积分大小类。如果area漏填或者算错评测指标就会失真。import json def build_coco_json(images, annotations, categories): return { images: images, annotations: annotations, categories: categories, } # 自己组装images/annotations/categories # 注意category_id从1开始并且要连续6.2 用现成项目跑通的路径配置得到COCO格式的JSON后用MMDetection训练时只需要在配置里指定data_root和ann_file路径不需要改造模型代码data dict( traindict( typeCocoDataset, data_rootdata/my_dataset/, ann_fileannotations/instances_train.json, img_prefixtrain/, classes(defect_a, defect_b), ) )这里有一个新手容易忽略的问题如果自定义数据集的类别不是COCO的80类必须要覆盖classes字段否则框架会用COCO的类别名称去匹配训练时类别数对不上直接报错。6.3 我处理数据时的建议顺序如果是第一次接触COCO我不建议一上来就训练模型。最靠谱的路线是先把instances_val2017.json里的images和annotations对应关系跑通用pycocotools可视化几百张图看标注长什么样把自己理解的数据格式写成一个小的统计脚本打印每个类别的样本数量再进入训练阶段这套流程走下来对数据的理解会扎实很多之后做自定义数据集时不会觉得无从下手。我个人最深的体会有两点。第一COCO的价值不仅在于图片数量大、类别多更在于它把目标检测、实例分割、关键点检测、图片描述等多个任务的标注范式统一到了一套JSON结构里学会了这套结构很多工具链都能顺带打通。第二处理COCO时最花时间的往往不是模型结构而是标注坐标转换、类别映射、遮挡目标过滤这些数据工程细节。把这些基础工作想清楚训练模型时能省下大量排查问题的时间。最后分享一个小技巧如果你只想做快速实验可以只下载val2017这5000张图再写几行代码从annotations里筛出关注类别的小样本构造一个mini训练集。这样能大幅缩短数据加载和模型迭代的时间等方案稳定后再迁移到完整COCO上。这个mini数据集的做法比直接啃完整数据更适合用来验证代码流程。本文还有配套的精品资源点击获取
返回列表