0. 前言
- 一直都在用 COCO 数据集,但对这个API了解不够深入。
- 现在搞完了,感觉使用已经差不多了。
- 如果说还有什么要深入的话,那就是Mask的具体使用,以及COCOEval的基本原理了。
1. 安装
- Linux
pip install cython; pip install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'
- Windows
- Gihub: cocoapi windows version
- 在PythonAPI文件夹中运行
python setup.py build_ext install
即可。 - 可能会报错
error: Unable to find vcvarsall.bat
- 解决:在这里下载
Visual C++ Build Tools 2015
,在win10下安装。
- 解决:在这里下载
2. COCO 类
- 位于
coco.py
中。 - 作用:整合一系列图像以及对应的标注结果。
2.1. 初始化
- 初始化该类需要导入配置文件。COCO中配置文件主要分为三类:
- 用于实例分割与物体检测的
instances_{}.json
- 用于关键点识别的
person_keypoints_{}.json
- 提供简单介绍图像的文字
captions_{}.json
- 用于实例分割与物体检测的
- 代码基本流程:
- 第一步:读取json文件,作为
self.dataset
实例。 - 第二步:根据
self.dataset
对象,获取五个成员变量,下面分别介绍imgs
:key为数字id,value为字典,2.2. 基本方法
中会介绍该字典。cats
:key为数字id,value为字典,2.2. 基本方法
中会介绍该字典。anns
:key为数字id,value为字典,2.2. 基本方法
中会介绍该字典。imgToAnns
:key为数字id,value为list,list中每个元素是个字典,该字典内容与anns
一致。catToImgs
:key为数字id,value为list,list中每个元素是个字典,该字典内容与imgs
一致。- 这一步主要就是通过
createIndex
方法实现。
- 第一步:读取json文件,作为
2.2. 基本方法
get系列:获取各种id。
def getCatIds(self, catNms=[], supNms=[], catIds=[])
- 通过分类名称、父类名称、分类编号获取分类编号。
- 三个条件要同时成立。
def getImgIds(self, imgIds=[], catIds=[])
- 通过图片编号与分类编号获取图片编号。
- 注意,如果有多个类型编号,则要求一张图片中包含所有指定的类型。
def getAnnIds(self, imgIds=[], catIds=[], areaRng=[], iscrowd=None)
- 通过图片编号、分类编号、面积范围、crowd记号来获取对应的标签。
- 所有条件必须同时满足。
load系列:根据id获取各种实际数据。
- 共有
loadCats
,loadAnns
,loadImgs
三个方法,结果举例如下。 - 注意,anno中对应的
segmentation
有两种形式- 当iscrowd为0时,是polygon形式。
- 当iscrowd为1时,是rle形式。
- 注意,anno中对应的
keypoints
表示17个关键点信息,用以为数组表示。- 该数组可以转换为
[17, 3]
,其中三个数字分别是横坐标、纵坐标、关键点可见性(0或1)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54# instances: loadCats
{'supercategory': 'person', 'id': 1, 'name': 'person'}
# keypoints: loadCats
{
'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': [...], # 关键点连接性,编号从1开始
}
# loadAnns
{
'segmentation': ...,
'area': 702.1057499999998,
'iscrowd': 0,
'image_id': 289343,
'bbox': [473.07, 395.93, 38.65, 28.67],
'keypoints': [...],
'category_id': 18,
'id': 1768
}
# loadImgs
{
'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
}
- 该数组可以转换为
- 共有
mask转换方法
annToMask
:将ann
中的segmentation
转换为 binary mask形式。annToRLE
:将ann
中的segmentation
转换为RLE形式。
2.3. 其他方法
info
:输出数据集基本信息,参考结果如下。1
2
3
4
5
6description: COCO 2017 Dataset
url: http://cocodataset.org
version: 1.0
year: 2017
contributor: COCO Consortium
date_created: 2017/09/01download
:下载数据集,我也用不上。def showAnns(self, anns)
- 在plt上展示注释结果,可以用来展示mask和关键点,好像不能用来展示bbox。
- 这个需要之前先用
plt.imshow()
展示原始图片。 - 调用了
plt.gca()
方法,好像意思是会自动寻找plt.figure
。
loadRes
- 将JSON形式的结果转换为COCO对象。
- 好像可以用在后续的评估方法中。
loadNumpyAnnotations
- 将一个
[Nx7]
的ndarray
对象转换为list[dict]
形式。 - 其中每个字典包括
image_id, bbox, score, category_id
四个属性。 [Nx7]
中每一行的形式为{imageID,x1,y1,w,h,score,class}
。
- 将一个
2.4. 注意事项
- 在源码中会设置
import matplotlib; matplotlib.use('Agg')
,就算直接只Python源码也没用,可能需要修改源码后重新重新安装才行。
3. COCOeval
- 位于
cocoeval.py
中。 - 作用:用于性能指标评估。
3.1. 初始化
- 函数形式:
def __init__(self, cocoGt=None, cocoDt=None, iouType='segm')
- 构造主要通过两个COCO对象以及比较结果来定义
- 两个COCO对象分别表示Ground Truth以及预测结果。
iouType
有三个选择,分别是'segm', 'bbox', 'keypoints'
。
3.2. 基本使用
基本流程
1
2
3
4
5
6cocoGt=..., cocoDt=... # load dataset and results
E = CocoEval(cocoGt,cocoDt); # initialize CocoEval object
E.params.recThrs = ...; # set parameters as desired
E.evaluate(); # run per image evaluation
E.accumulate(); # accumulate per image results
E.summarize(); # display summary metrics of results在
E.params
中可以设置的参数包括1
2
3
4
5
6
7
8
9
10
11
12# The evaluation parameters are as follows (defaults in brackets):
# imgIds - [all] N img ids to use for evaluation
# catIds - [all] K cat ids to use for evaluation
# iouThrs - [.5:.05:.95] T=10 IoU thresholds for evaluation
# recThrs - [0:.01:1] R=101 recall thresholds for evaluation
# areaRng - [...] A=4 object area ranges for evaluation
# maxDets - [1 10 100] M=3 thresholds on max detections per image
# iouType - ['segm'] set iouType to 'segm', 'bbox' or 'keypoints'
# iouType replaced the now DEPRECATED useSegm parameter.
# useCats - [1] if true use category labels for evaluation
# Note: if useCats=0 category labels are ignored as in proposal scoring.
# Note: multiple areaRngs [Ax2] and maxDets [Mx1] can be specified.
4. 举例
- 两个官方实例放出来,也没注释,看看就看懂了。
4.1. pycocoDemo
- 好像也没啥要说的。
- 一般流程是根据catIds获取imgIds,最后获取annIds,然后分别通过load方法导入信息。
- 其实可以活用
imgToAnns
catToImgs
这两个成员变量。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99%matplotlib inline
# from __future__ import print_function # 为了在3.6中正常运行,好像需要注释
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)
# Record package versions for reproducibility
print("os: %s" % os.name)
print("sys: %s" % sys.version)
print("numpy: %s, %s" % (np.__version__, np.__file__))
# Setup data paths
dataDir = '../..'
dataType = 'val2017'
annDir = '{}/annotations'.format(dataDir)
annZipFile = '{}/annotations_train{}.zip'.format(dataDir, dataType)
annFile = '{}/instances_{}.json'.format(annDir, dataType)
annURL = 'http://images.cocodataset.org/annotations/annotations_train{}.zip'.format(dataType)
print (annDir)
print (annFile)
print (annZipFile)
print (annURL)
# Download data if not available locally
if not os.path.exists(annDir):
os.makedirs(annDir)
if not os.path.exists(annFile):
if not os.path.exists(annZipFile):
print ("Downloading zipped annotations to " + annZipFile + " ...")
with urllib.request.urlopen(annURL) as resp, open(annZipFile, 'wb') as out:
shutil.copyfileobj(resp, out)
print ("... done downloading.")
print ("Unzipping " + annZipFile)
with zipfile.ZipFile(annZipFile,"r") as zip_ref:
zip_ref.extractall(dataDir)
print ("... done unzipping")
print ("Will use annotations in " + annFile)
# initialize COCO api for instance annotations
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)))
# get all images containing given categories, select one at random
catIds = coco.getCatIds(catNms=['person','dog','skateboard']);
imgIds = coco.getImgIds(catIds=catIds );
imgIds = coco.getImgIds(imgIds = [324158])
img = coco.loadImgs(imgIds[np.random.randint(0,len(imgIds))])[0]
# load and display image
I = io.imread('%s/images/%s/%s'%(dataDir,dataType,img['file_name']))
# use url to load image
# I = io.imread(img['coco_url'])
plt.axis('off')
plt.imshow(I)
plt.show()
# load and display instance annotations
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()
4.2. pycocoEvalDemo
1 | %matplotlib inline |