MSCOCO数据标注详解

参考:python


完整代码点击此处git



JSON文件

json文件主要包含如下几个字段:
详细描述参考 COCO 标注详解github

{
    "info": info, # dict
    "licenses": [license], # list ,内部是dict
    "images": [image], # list ,内部是dict
    "annotations": [annotation], # list ,内部是dict
    "categories": # list ,内部是dict
}

打开JSON文件查看数据特色

因为JSON文件太大,不少都是重复定义的,因此只提取一张图片,存储成新的JSON文件,便于观察。web

# -*- coding:utf-8 -*-

from __future__ import print_function
from pycocotools.coco import COCO
import os, sys, zipfile
import urllib.request
import shutil
import numpy as np
import skimage.io as io
import matplotlib.pyplot as plt
import pylab
import json

json_file='./annotations/instances_val2017.json' # # Object Instance 类型的标注
# person_keypoints_val2017.json # Object Keypoint 类型的标注格式
# captions_val2017.json # Image Caption的标注格式

data=json.load(open(json_file,'r'))

data_2={}
data_2['info']=data['info']
data_2['licenses']=data['licenses']
data_2['images']=[data['images'][0]] # 只提取第一张图片
data_2['categories']=data['categories']
annotation=[]

# 经过imgID 找到其全部对象
imgID=data_2['images'][0]['id']
for ann in data['annotations']:
    if ann['image_id']==imgID:
        annotation.append(ann)

data_2['annotations']=annotation

# 保存到新的JSON文件,便于查看数据特色
json.dump(data_2,open('./new_instances_val2017.json','w'),indent=4) # indent=4 更加美观显示

Object Instance 类型的标注格式

主要有如下几个字段:json

这里写图片描述

info

"info": { # 数据集信息描述
        "description": "COCO 2017 Dataset", # 数据集描述
        "url": "http://cocodataset.org", # 下载地址
        "version": "1.0", # 版本
        "year": 2017, # 年份
        "contributor": "COCO Consortium", # 提供者
        "date_created": "2017/09/01" # 数据建立日期
    },

licenses

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

images

"images": [
        {
            "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",# flickr网路地址
            "id": 397133 # 图片的ID编号(每张图片ID是惟一的)
        },
        ……
        ……
    ],

categories

"categories": [ # 类别描述
        {
            "supercategory": "person", # 主类别
            "id": 1, # 类对应的id (0 默认为背景)
            "name": "person" # 子类别
        },
        {
            "supercategory": "vehicle", 
            "id": 2,
            "name": "bicycle"
        },
        {
            "supercategory": "vehicle",
            "id": 3,
            "name": "car"
        },
        ……
        ……
    ],

注: bicycle 与car都属于vehicle,但二者又属于不一样的类别。例如:羊(主类别)分为山羊、绵羊、藏羚羊(子类别)等api

annotations

"annotation": [
        {
            "segmentation": [ # 对象的边界点(边界多边形)
                [
                    224.24,297.18,# 第一个点 x,y坐标
                    228.29,297.18, # 第二个点 x,y坐标
                    234.91,298.29,
                    ……
                    ……
                    225.34,297.55
                ]
            ],
            "area": 1481.3806499999994, # 区域面积
            "iscrowd": 0, # 
            "image_id": 397133, # 对应的图片ID(与images中的ID对应)
            "bbox": [217.62,240.54,38.99,57.75], # 定位边框 [x,y,w,h]
            "category_id": 44, # 类别ID(与categories中的ID对应)
            "id": 82445 # 对象ID,由于每个图像有不止一个对象,因此要对每个对象编号(每一个对象的ID是惟一的)
        },
        ……
        ……
        ]

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


可视化

如今调用cocoapi显示刚生成的JSON文件,并检查是否有问题。app

# -*- coding:utf-8 -*-

from __future__ import print_function
from pycocotools.coco import COCO
import os, sys, zipfile
import urllib.request
import shutil
import numpy as np
import skimage.io as io
import matplotlib.pyplot as plt
import pylab
pylab.rcParams['figure.figsize'] = (8.0, 10.0)

annFile='./new_instances_val2017.json'
coco=COCO(annFile)

# display COCO categories and supercategories
cats = coco.loadCats(coco.getCatIds())
nms=[cat['name'] for cat in cats]
print('COCO categories: \n{}\n'.format(' '.join(nms)))

nms = set([cat['supercategory'] for cat in cats])
print('COCO supercategories: \n{}'.format(' '.join(nms)))

# imgIds = coco.getImgIds(imgIds = [324158])
imgIds = coco.getImgIds()
img = coco.loadImgs(imgIds[0])[0]
dataDir = '.'
dataType = 'val2017'
I = io.imread('%s/%s/%s'%(dataDir,dataType,img['file_name']))

plt.axis('off')
plt.imshow(I)
plt.show()


# load and display instance annotations
# 加载实例掩膜
# catIds = coco.getCatIds(catNms=['person','dog','skateboard']);
# catIds=coco.getCatIds()
catIds=[]
for ann in coco.dataset['annotations']:
    if ann['image_id']==imgIds[0]:
        catIds.append(ann['category_id'])

plt.imshow(I); plt.axis('off')
annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
anns = coco.loadAnns(annIds)
coco.showAnns(anns)

# initialize COCO api for person keypoints annotations
annFile = '{}/annotations/person_keypoints_{}.json'.format(dataDir,dataType)
coco_kps=COCO(annFile)

# load and display keypoints annotations
# 加载肢体关键点
plt.imshow(I); plt.axis('off')
ax = plt.gca()
annIds = coco_kps.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
anns = coco_kps.loadAnns(annIds)
coco_kps.showAnns(anns)

# initialize COCO api for caption annotations
annFile = '{}/annotations/captions_{}.json'.format(dataDir,dataType)
coco_caps=COCO(annFile)

# load and display caption annotations
# 加载文本描述
annIds = coco_caps.getAnnIds(imgIds=img['id']);
anns = coco_caps.loadAnns(annIds)
coco_caps.showAnns(anns)
plt.imshow(I); plt.axis('off'); plt.show()

这里写图片描述

A man is in a kitchen making pizzas.
Man in apron standing on front of oven with pans and bakeware
A baker is working in the kitchen rolling dough.
A person standing by a stove in a kitchen.
A table with pies being made and a person standing near a wall with pots and pans hanging on the wall.

仿照COCO JSON文件

仿照COCO的数据格式,将labelme的JSON改形成COCO的JSONdom

首先是要labelme作好图片标注

这里写图片描述

这里写图片描述

这里写图片描述

说明:(类别不必定对,只是为了说明问题)
bobcat-美国短耳猫
plushcat-布偶猫
deerhound-小鹿犬
mainecat-缅因猫
golden-金毛svg

将labelme的JSON转成COCO格式JSON

这里写一个class实现如下功能,labelme2COCO.py中 的部分代码以下:

def image(self,data,num):
        image={}
        img = utils.img_b64_to_array(data['imageData'])  # 解析原图片数据
        # img=io.imread(data['imagePath']) # 经过图片路径打开图片
        # img = cv2.imread(data['imagePath'], 0)
        height, width = img.shape[:2]
        img = None
        image['height']=height
        image['width'] = width
        image['id']=num+1
        image['file_name'] = data['imagePath'].split('/')[-1]

        self.height=height
        self.width=width

        return image

   def categorie(self,label):
       categorie={}
       categorie['supercategory'] = label[0]
       categorie['id']=len(self.label)+1 # 0 默认为背景
       categorie['name'] = label[1]
       return categorie

   def annotation(self,points,label,num):
       annotation={}
       annotation['segmentation']=[list(np.asarray(points).flatten())]
       annotation['iscrowd'] = 0
       annotation['image_id'] = num+1
       # annotation['bbox'] = str(self.getbbox(points)) # 使用list保存json文件时报错(不知道为何)
       # list(map(int,a[1:-1].split(','))) a=annotation['bbox'] 使用该方式转成list
       annotation['bbox'] = list(map(float,self.getbbox(points)))

       annotation['category_id'] = self.getcatid(label)
       annotation['id'] = self.annID
       return annotation

注:这里只实现images、categories、annotations三个字段内容,由于只用到这几个字段


可视化数据

这部分是使用COCO的API接口打开刚才本身生成的JSON文件,以验证是否存在问题。

visualization.py

# -*- coding:utf-8 -*-

from __future__ import print_function
from pycocotools.coco import COCO
import os, sys, zipfile
import urllib.request
import shutil
import numpy as np
import skimage.io as io
import matplotlib.pyplot as plt
import pylab
pylab.rcParams['figure.figsize'] = (8.0, 10.0)

annFile='./new.json'
coco=COCO(annFile)

# display COCO categories and supercategories
cats = coco.loadCats(coco.getCatIds())
nms=[cat['name'] for cat in cats]
print('COCO categories: \n{}\n'.format(' '.join(nms)))

nms = set([cat['supercategory'] for cat in cats])
print('COCO supercategories: \n{}'.format(' '.join(nms)))

# imgIds = coco.getImgIds(imgIds = [324158])
imgIds = coco.getImgIds()
imgId=np.random.randint(0,len(imgIds))
img = coco.loadImgs(imgIds[imgId])[0]
dataDir = '.'
# dataType = 'val2017'
# I = io.imread('%s/%s/%s'%(dataDir,dataType,img['file_name']))
I = io.imread('%s/%s'%(dataDir,img['file_name']))

plt.axis('off')
plt.imshow(I)
plt.show()


# load and display instance annotations
# 加载实例掩膜
# catIds = coco.getCatIds(catNms=['person','dog','skateboard']);
# catIds=coco.getCatIds()
catIds=[]
for ann in coco.dataset['annotations']:
    if ann['image_id']==imgIds[imgId]:
        catIds.append(ann['category_id'])

plt.imshow(I); plt.axis('off')
annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None)
anns = coco.loadAnns(annIds)
coco.showAnns(anns)
plt.show()

显示结果:

这里写图片描述

这里写图片描述

这里写图片描述


Object Keypoint 类型的标注格式

运行脚本one_image_json.py 获得单张图片的JSON信息。

基本上内容与Object Instance的标注格式同样,不一样的地方在于categories、annotations字段内容不同。

主要内容有:

{
    "info": { 
        "description": "COCO 2017 Dataset",
        "url": "http://cocodataset.org",
        "version": "1.0",
        "year": 2017,
        "contributor": "COCO Consortium",
        "date_created": "2017/09/01"
    },
    "licenses": [
        {
            "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/",
            "id": 1,
            "name": "Attribution-NonCommercial-ShareAlike License"
        },
        ……
        ……
    ],
    "images": [
        {
            "license": 4,
            "file_name": "000000397133.jpg", # 图片名
            "coco_url": "http://images.cocodataset.org/val2017/000000397133.jpg", # coco 连接地址
            "height": 427, # 高
            "width": 640, # 宽
            "date_captured": "2013-11-14 17:02:52", # 获取日期
            "flickr_url": "http://farm7.staticflickr.com/6116/6255196340_da26cf2c9e_z.jpg", # flickr 连接地址
            "id": 397133 # 图片ID(每张图片ID惟一)
        }
    ],
    "categories": [
        {
            "supercategory": "person", # 主类
            "id": 1,  # class id
            "name": "person", # 子类(具体类别)
            "keypoints": [ # 相比Object Instance多了这个字段
                "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
                ],
               ……
               ……
                [
                    5,7
                ]
            ]
        }
    ],
    "annotations": [
        {
            "segmentation": [
                [
                    446.71,70.66, # 多边形(对象mask)第一个点 x,y
                    466.07,72.89,
                    471.28,78.85,
                    473.51,88.52,
                    473.51,98.2,
                   ……
                   ……
                    443.74,69.92
                ]
            ],
            "num_keypoints": 13, # 关键点数
            "area": 17376.91885,
            "iscrowd": 0,
            "keypoints": [
                # v=0 表示这个关键点没有标注(这种状况下x=y=v=0)
                # v=1 表示这个关键点标注了可是不可见(被遮挡了)
                # v=2 表示这个关键点标注了同时也可见
                433,94,2, # x,y,v 
                434,90,2,
                0,0,0,
                443,98,2,
                0,0,0,
                ……
                ……
            ],
            "image_id": 397133, # 对应的图片ID
            "bbox": [
                388.66,69.92,109.41,277.62 # [x,y,w,h] 对象定位框
            ],
            "category_id": 1, # 类别id
            "id": 200887 # 对象id(每一个对象id都是惟一的,即不能出现重复)
        },
        ……
        ……
    ]
}

Image Caption的标注格式

运行脚本one_image_json.py 获得单张图片的JSON信息。

基本上内容与Object Instance的标注格式同样,不一样的地方在于annotations字段内容不同以及没有categories字段

{
    "info": {
        "description": "COCO 2017 Dataset",
        "url": "http://cocodataset.org",
        "version": "1.0",
        "year": 2017,
        "contributor": "COCO Consortium",
        "date_created": "2017/09/01"
    },
    "licenses": [
        {
            "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/",
            "id": 1,
            "name": "Attribution-NonCommercial-ShareAlike License"
        },
       ……
       ……
    ],
    "images": [
        {
            "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
        }
    ],
    "annotations": [
        {
            "image_id": 397133, # 图片ID(惟一)
            "id": 370509, # 对象ID(惟一) (没有类别ID)
            "caption": "A man is in a kitchen making pizzas." # 图片描述
        },
    ……
    ……  
        {
            "image_id": 397133,
            "id": 375891,
            "caption": "A table with pies being made and a person standing near a wall with pots and pans hanging on the wall."
        }
    ]
}

这三种标注的info,licenses,images的内容是同样的。