0. 前言
一直都在用 COCO 数据集,但对这个API了解不够深入。
1. 安装
Linux
现在安装终于不用git clone数据了。pip install cython pycocotools
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
方法实现。
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)。
{ 'supercategory' : 'person' , 'id' : 1 , 'name' : 'person' }
{
'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' : [ . . . ] ,
}
{
'segmentation' : . . . ,
'area' : 702.1057499999998 ,
'iscrowd' : 0 ,
'image_id' : 289343 ,
'bbox' : [ 473.07 , 395.93 , 38.65 , 28.67 ] ,
'keypoints' : [ . . . ] ,
'category_id' : 18 ,
'id' : 1768
}
{
'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. 其他方法
description: COCO 2017 Dataset
url: http://cocodataset.org
version: 1.0
year: 2017
contributor: COCO Consortium
date_created: 2017/09/01
download
:下载数据集,我也用不上。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. 基本使用
cocoGt=..., 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
# 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
这两个成员变量。
%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
% matplotlib inline
import matplotlib. pyplot as plt
from pycocotools. coco import COCO
from pycocotools. cocoeval import COCOeval
import os, sys, zipfile
import urllib. request
import shutil
import numpy as np
import skimage. io as io
import pylab
pylab. rcParams[ 'figure.figsize' ] = ( 10.0 , 8.0 )
print ( "os: %s" % os. name)
print ( "sys: %s" % sys. version)
print ( "numpy: %s, %s" % ( np. __version__, np. __file__) )
annType = [ 'segm' , 'bbox' , 'keypoints' ]
annType = annType[ 1 ]
prefix = 'person_keypoints' if annType== 'keypoints' else 'instances'
print ( 'Running demo for *%s* results.' % ( annType) )
dataDir = '../..'
dataType = 'val2014'
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)
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)
cocoGt= COCO( annFile)
resFile= '%s/results/%s_%s_fake%s100_results.json'
resFile = resFile% ( dataDir, prefix, dataType, annType)
cocoDt= cocoGt. loadRes( resFile)
imgIds= sorted ( cocoGt. getImgIds( ) )
imgIds= imgIds[ 0 : 100 ]
imgId = imgIds[ np. random. randint( 100 ) ]
cocoEval = COCOeval( cocoGt, cocoDt, annType)
cocoEval. params. imgIds = imgIds
cocoEval. evaluate( )
cocoEval. accumulate( )
cocoEval. summarize( )