COCO数据集标注详解

来源 | 极链AI云(性价比最高的共享GPU算力平台,双十活动进行中 10.9-10.11,充值就送!最多可送2500元现金券!免费试用地址https://cloud.videojj.com/

文章来源:https://cloud.videojj.com/bbs/topic/112/coco数据集标注详解

COCO的 全称是Common Objects in Context,是微软团队提供的一个可以用来进行图像识别的数据集。这里以COCO2017数据集为例。MS COCO数据集中的图像分为训练、验证和测试集。一共80个类,分别是:

[‘person’, ‘bicycle’, ‘car’, ‘motorcycle’, ‘airplane’, ‘bus’, ‘train’, ‘truck’, ‘boat’, ‘traffic light’, ‘fire hydrant’, ‘stop sign’, ‘parking meter’, ‘bench’, ‘bird’, ‘cat’, ‘dog’, ‘horse’, ‘sheep’, ‘cow’, ‘elephant’, ‘bear’, ‘zebra’, ‘giraffe’, ‘backpack’, ‘umbrella’, ‘handbag’, ‘tie’, ‘suitcase’, ‘frisbee’, ‘skis’, ‘snowboard’, ‘sports ball’, ‘kite’, ‘baseball bat’, ‘baseball glove’, ‘skateboard’, ‘surfboard’, ‘tennis racket’, ‘bottle’, ‘wine glass’, ‘cup’, ‘fork’, ‘knife’, ‘spoon’, ‘bowl’, ‘banana’, ‘apple’, ‘sandwich’, ‘orange’, ‘broccoli’, ‘carrot’, ‘hot dog’, ‘pizza’, ‘donut’, ‘cake’, ‘chair’, ‘couch’, ‘potted plant’, ‘bed’, ‘dining table’, ‘toilet’, ‘tv’, ‘laptop’, ‘mouse’, ‘remote’, ‘keyboard’, ‘cell phone’, ‘microwave’, ‘oven’, ‘toaster’, ‘sink’, ‘refrigerator’, ‘book’, ‘clock’, ‘vase’, ‘scissors’, ‘teddy bear’, ‘hair drier’, ‘toothbrush’]
COCO数据集现在有3种标注类型:object instances(目标实例,用于目标检测), object keypoints(目标上的关键点,用于姿态估计), and image captions(看图说话),每种标注类型都有相应的json标注文件。如下图,这是COCO的训练集、验证集的标注文件:

基本的json结构体类型

object instances(目标实例)、object keypoints(目标上的关键点)、image captions(看图说话)这3种类型共享这些基本类型:info、image、license。而annotation类型则呈现出了多态:

{
    "info": info,
    "licenses": [license],
    "images": [image],
    "annotations": [annotation],
}

上面的info又包括以下内容
info{
    "year": int,
    "version": str,
    "description": str,
    "contributor": str,
    "url": str,
    "date_created": datetime,
}

licence又包括以下内容
license{
    "id": int,
    "name": str,
    "url": str,
} 

image又包括以下内容
image{
    "id": int,
    "width": int,
    "height": int,
    "file_name": str,
    "license": int,
    "flickr_url": str,
    "coco_url": str,
    "date_captured": datetime,
}
 

1、info类型,比如一个info类型的实例

"info": {
         "description": "COCO 2017 Dataset",
         "url": "http://cocodataset.org",
         "version": "1.0",
         "year": 2017,
         "contributor": "COCO Consortium",
         "date_created": "2017/09/01"
         }

2、Images是包含多个image实例的数组,对于一个image类型的实例:

{
   "license": 4,
   "file_name": "000000397133.jpg",
   "coco_url": "http://images.cocodataset.org/val2017/000000397133.jpg",
   "height": 427,
   "width": 640,
   "date_captured": "2013-11-14 17:02:52",
   "flickr_url": "http://farm7.staticflickr.com/6116/6255196340_da26cf2c9e_z.jpg",
   "id": 397133
}
 

3、licenses是包含多个license实例的数组,对于一个license类型的实例:

{
  "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/",
  "id": 1,
  "name": "Attribution-NonCommercial-ShareAlike License"
}

Object Instance 类型的标注格式

相应的训练、验证标注文件为 instances_train2017.json、instances_val2017.json

Object Instance这种格式的文件从头至尾按照顺序分为以下段落:

{
    "info": info,
    "licenses": [license],
    "images": [image],
    "annotations": [annotation],
    "categories": [category]
}

其中,info、licenses、images这三个结构体/类型 在上一节中已经说了,在不同的JSON文件中这三个类型是一样的,定义是共享的。不共享的是annotation和category这两种结构体,他们在不同类型的JSON文件中是不一样的。

images数组元素的数量等同于划入训练集(或者测试集)的图片的数量;

annotations数组元素的数量等同于训练集(或者测试集)中bounding box的数量;

categories数组元素的数量为80(2017年);

from pycocotools.coco import COCO   # 这里需要事先安装pycocotools,安装方法见 https://blog.csdn.net/qq_29631521/article/details/89038361

ann_train_file='dataset/coco/2017/annotations/instances_train2017.json'
coco_train = COCO(ann_train_file)
print(len(coco_train.dataset['categories'])) # 80
print(len(coco_train.dataset['images'])) # 118287
print(len(coco_train.dataset['annotations'])) # 860001
 

2、annotations字段
annotations字段是包含多个annotation实例的一个数组,annotation类型本身又包含了一系列的字段,如这个目标的category id和segmentation mask。segmentation格式取决于这个实例是一个单个的对象(即iscrowd=0,将使用polygons-多边形格式)还是一组对象(即iscrowd=1,将使用RLE格式-一种压缩方式)。如下所示:

annotation{
    "id": int,    
    "image_id": int,                  #图片id
    "category_id": int,               # 类别id,对应COCO 81个类中的一个
    "segmentation": RLE or [polygon], # 目标的分割区域
    "area": float,                    # 标注区域面积
    "bbox": [x,y,width,height],       #图片中目标的边框 ;注意这里给的是左上角坐标及宽度、高度,有时需要转化为左上角、右下角坐标
    "iscrowd": 0 or 1,                # 一个目标(0)还是多个目标(1)
}
 

注意,单个的对象(iscrowd=0)可能需要多个polygon来表示,比如这个对象在图像中被挡住了。而iscrowd=1时(将标注一组对象,比如一群人)的segmentation使用的就是RLE格式。

注意啊,只要是iscrowd=0那么segmentation就是polygon格式;只要iscrowd=1那么segmentation就是RLE格式。另外,每个对象(不管是iscrowd=0还是iscrowd=1)都会有一个矩形框bbox ,矩形框左上角的坐标和矩形框的长宽会以数组的形式提供,数组第一个元素就是左上角的横坐标值。

area是area of encoded masks,是标注区域的面积。如果是矩形框,那就是高乘宽;如果是polygon或者RLE,那就复杂点。

最后,annotation结构中的categories字段存储的是当前对象所属的category的id,以及所属的supercategory的name。

iscrowd = 0,polygon格式比较简单,这些数按照相邻的顺序两两组成一个点的xy坐标,如果有n个数(必定是偶数),那么就是n/2个点坐标。下面就是一段解析polygon格式的segmentation并且显示多边形的示例代码:

from PythonAPI.pycocotools.coco import COCO
from skimage import io
from matplotlib import pyplot as plt

anno_file = 'dataset/coco/2017/annotations/instances_train2017.json'
coco = COCO(anno_file)
catIds = coco.getCatIds(catNms=['person'])
imgIds = coco.getImgIds(catIds=catIds)

for i in range(len(imgIds)):
    image = coco.loadImgs(imgIds[i])[0]
    I = io.imread(image['coco_url'])
    plt.imshow(I)
    anno_id = coco.getAnnIds(imgIds = image['id'], catIds = catIds, iscrowd= None)
    annotation = coco.loadAnns(anno_id)
    coco.showAnns(annotation)
    plt.show()
 

效果图
512ca12e-237e-4dee-ac22-c0bdf6100136-image.png

如果iscrowd=1,那么segmentation就是RLE格式(segmentation字段会含有counts和size数组),在json文件中gemfield挑出一个这样的例子,如下所示:

segmentation : 
{
    u'counts': [272, 2, 4, 4, 4, 4, 2, 9, 1, 2, 16, 43, 143, 24......], 
    u'size': [240, 320]
}
 

COCO数据集的RLE都是uncompressed RLE格式(与之相对的是compact RLE)。 RLE所占字节的大小和边界上的像素数量是正相关的。RLE格式带来的好处就是当基于RLE去计算目标区域的面积以及两个目标之间的unoin和intersection时会非常有效率。 上面的segmentation中的counts数组和size数组共同组成了这幅图片中的分割 mask。其中size是这幅图片的宽高,然后在这幅图像中,每一个像素点要么在被分割(标注)的目标区域中,要么在背景中。很明显这是一个bool量:如果该像素在目标区域中为true那么在背景中就是False;如果该像素在目标区域中为1那么在背景中就是0。对于一个240x320的图片来说,一共有76800个像素点,根据每一个像素点在不在目标区域中,我们就有了76800个bit,比如像这样(随便写的例子,和上文的数组没关系):00000111100111110…;但是这样写很明显浪费空间,我们直接写上0或者1的个数不就行了嘛(Run-length encoding),于是就成了54251…,这就是上文中的counts数组。
可以使用下面的代码将这个rle数组表示的分割区域画出来:

import numpy as np
from PythonAPI.pycocotools.coco import COCO
from skimage import io
from matplotlib import pyplot as plt

anno_file = 'dataset/coco/2017/annotations/instances_val2017.json'
coco = COCO(anno_file)
catIds = coco.getCatIds(catNms=['person'])
anno_id = coco.getAnnIds(catIds = catIds, iscrowd= 1)
annotations = coco.loadAnns(anno_id)
for j in range(len(annotations)):
    annotation = annotations[j]
    rle = annotation['segmentation']['counts']
    height = annotation['segmentation']['size'][0]
    width = annotation['segmentation']['size'][1]
    assert sum(rle) == height*width
    M = np.zeros(height*width)
    N = len(rle)
    n = 0
    val = 1
    for pos in range(N):
        val = not val
        for c in range(rle[pos]):
            M[n] = val
            n += 1

    GEMFIELD = M.reshape(([height, width]), order='F')
    plt.imshow(GEMFIELD)
    plt.show()
 

显示结果:
dec6d7a4-0c49-434f-b899-baed4092b7eb-image.png

3,categories字段
categories是一个包含多个category实例的数组,而category结构体描述如下:

{
    "id": int,
    "name": str,                # 类别名(子类名)
    "supercategory": str,       # 父类名
}
 

从instances_val2017.json文件中摘出的2个category实例如下所示:

{
	"supercategory": "person",
	"id": 1,
	"name": "person"
},
{
	"supercategory": "vehicle",
	"id": 2,
	"name": "bicycle"
},
 

Object Keypoint 类型的标注格式

1,整体JSON文件格式

相应的标注文件为person_keypoints_train2017.json、person_keypoints_val2017.json

Object Keypoint这种格式的文件从头至尾按照顺序分为以下段落,看起来和Object Instance一样啊:

{
    "info": info,
    "licenses": [license],
    "images": [image],
    "annotations": [annotation],
    "categories": [category]
}
 

其中,info、licenses、images这三个结构体/类型 在第一节中已经说了,在不同的JSON文件中这三个类型是一样的,定义是共享的。不共享的是annotation和category这两种结构体,他们在不同类型的JSON文件中是不一样的。

images数组元素数量是划入训练集(测试集)的图片的数量;

annotations是bounding box的数量,在这里只有人这个类别的bounding box;

categories数组元素的数量为1,只有一个:person(2017年);

2,annotations字段
这个类型中的annotation结构体包含了Object Instance中annotation结构体的所有字段,再加上2个额外的字段。

新增的keypoints是一个长度为3*k的数组,其中k是category中keypoints的总数量。每一个keypoint是一个长度为3的数组,第一和第二个元素分别是x和y坐标值,第三个元素是个标志位v,v为0时表示这个关键点没有标注(这种情况下x=y=v=0),v为1时表示这个关键点标注了但是不可见(被遮挡了),v为2时表示这个关键点标注了同时也可见。

num_keypoints表示这个目标上被标注的关键点的数量(v>0),比较小的目标上可能就无法标注关键点。

annotation{
    "keypoints": [x1,y1,v1,...],       # 关节点信息,按照(x,y,v)的顺序排列,即坐标为(x,y),可见性为v; v=0,没有标注;v=1,有标注不可见;v=2,有标注可见
    "num_keypoints": int,              # 标注的关节点数
    "id": int,
    "image_id": int,                   # 图片id
    "category_id": int,                # 类别id,等于1表示人这一类
    "segmentation": RLE or [polygon],  # 分割信息
    "area": float,                     # 标注区域面积
    "bbox": [x,y,width,height],        # 图片中人的边框
    "iscrowd": 0 or 1,                 # 是否是单人
}
 

从person_keypoints_val2017.json文件中摘出一个annotation的实例如下:

{
	"segmentation": [[125.12,539.69,140.94,522.43...]],
	"num_keypoints": 10,
	"area": 47803.27955,
	"iscrowd": 0,
	"keypoints": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,309,1,177,320,2,191,398...],
	"image_id": 425226,"bbox": [73.35,206.02,300.58,372.5],"category_id": 1,
	"id": 183126
},
 

3,categories字段
对于每一个category结构体,相比Object Instance中的category新增了2个额外的字段,keypoints是一个长度为k的数组,包含了每个关键点的名字;skeleton定义了各个关键点之间的连接性(比如人的左手腕和左肘就是连接的,但是左手腕和右手腕就不是)。目前,COCO的keypoints只标注了person category (分类为人)。

定义如下:

{
    "id": int,
    "name": str,
    "supercategory": str,
    "keypoints": [str],
    "skeleton": [edge]
}
 

从person_keypoints_val2017.json文件中摘出一个category的实例如下:

{
	"supercategory": "person",
	"id": 1,
	"name": "person",
	"keypoints": ["nose","left_eye","right_eye","left_ear","right_ear","left_shoulder","right_shoulder","left_elbow","right_elbow","left_wrist","right_wrist","left_hip","right_hip","left_knee","right_knee","left_ankle","right_ankle"],
	"skeleton": [[16,14],[14,12],[17,15],[15,13],[12,13],[6,12],[7,13],[6,7],[6,8],[7,9],[8,10],[9,11],[2,3],[1,2],[1,3],[2,4],[3,5],[4,6],[5,7]]
}

Image Caption的标注格式
1,整体JSON文件格式

对应的文件是captions_train2017.json、captions_val2017.json
Image Caption这种格式的文件从头至尾按照顺序分为以下段落,看起来和Object Instance一样,不过没有最后的categories字段:

{
    "info": info,
    "licenses": [license],
    "images": [image],
    "annotations": [annotation]
}
 

其中,info、licenses、images这三个结构体/类型 在第一节中已经说了,在不同的JSON文件中这三个类型是一样的,定义是共享的。不共享的是annotations这种结构体,它在不同类型的JSON文件中是不一样的。

images数组的元素数量等于划入训练集(或者测试集)的图片的数量;

annotations的数量要多于图片的数量,这是因为一个图片可以有多个场景描述;

2,annotations字段
这个类型中的annotation用来存储描述图片的语句。每个语句描述了对应图片的内容,而每个图片至少有5个描述语句(有的图片更多)。annotation定义如下:

annotation{
    "id": int,
    "image_id": int,
    "caption": str
}

从captions_val2017.json中摘取的一个annotation实例如下:

{
	"image_id": 179765,
	"id": 38,"caption": "A black Honda motorcycle parked in front of a garage."
}

猜你喜欢

转载自blog.csdn.net/weixin_51072772/article/details/108977334