前情提要
coco数据集的annotations是一个json文件,其格式对应了Python中的dict类型,所以我们可以用python中的json.loads()方法来将一个json文件读取为一个dict。
import json
coco = dict()
with open('./instances_val2017.json', 'r', encoding='UTF-8') as f:
coco = json.loads(f.read())
print(coco.keys())
# Output:
# dict_keys(['info', 'licenses', 'images', 'annotations', 'categories'])
以上代码运行结果表明其有五个键,分别是'info', 'licenses', 'images', 'annotations', 'categories'。我们在合并数据集时,对于第一个键'info'和第二个键'licenses'我们在实际训练中完全不需要用到,可以不用操作,接下来我们对其他几个字段进行一一合并。
合并前的操作
首先读取自己和coco的官方数据集,并且找到coco官方数据集中图片的id和标签的id最大是多少,我们下一步进行合并的时候在比它们大的id开始,以防id重复。
import json
# 填写自己的数据集、coco数据集和合并后输出的路径
oursPath = 'our_annotations_val.json'
cocoPath = 'instances_val2017.json'
output_filename = './output.json'
# 读取自己的数据集
print('Loading ours...', end='')
ours = {}
with open(oursPath, 'r', encoding='UTF-8') as f:
ours = json.loads(f.read())
print('Done')
# 读取coco官方数据集
print('Loading COCO...', end='')
output = {}
with open(cocoPath, 'r', encoding='UTF-8') as f:
output = json.loads(f.read())
print('Done')
# 找到coco官方数据集中图片id和标签id最大是多少
print('Finding max ids of COCO...', end='')
coco_max_id = -1
max_anno_id = -1
for i in range(0, len(output['annotations'])):
max_anno_id = output['annotations'][i]['id'] if output['annotations'][i]['id'] > max_anno_id else max_anno_id
for i in range(0, len(output['images'])):
coco_max_id = output['images'][i]['id'] if output['images'][i]['id'] > coco_max_id else coco_max_id
print('Max(image_id) = {}, Max(anno_id) = {}'.format(coco_max_id, max_anno_id))
合并categories字段
我自己的数据集只有两个类别,所以这里我使用手动的方式来合并。
# 将新的两个类别插入,XXX91,YYY92
print('Processing categories...', end='')
output['categories'].append({'supercategory': 'indoor', 'id': 91, 'name': 'XXX'})
output['categories'].append({'supercategory': 'indoor', 'id': 92, 'name': 'YYY'})
print('Done')
合并images字段
在合并images和annotations字段的时候需要注意,这两个字段的值分别都是一个list,list中的每一个元素又是一个dict,其中的id字段都是整数类型的。
# 先处理ours的图片id,将其全部置于coco_max_id后,防止与coco自带的重复,并插入coco中
print("Processing images...", end='')
for i in range(0, len(ours['images'])):
ours['images'][i]['id'] = ours['images'][i]['id'] + coco_max_id + 1
ours['images'][i]['license'] = 1 # license 随便填即可
output['images'].append(ours['images'][i])
print('Done')
合并annotations字段
这里我直接使用了1对应91,2对应92,如果类别多的话可以开一个list来映射
# 把每一个annotation的image_id加上coco_max_id来对应之前的id
print("Processing ours' image_id and category_id of annotations...", end='')
for i in range(0, len(ours['annotations'])):
ours['annotations'][i]['image_id'] = ours['annotations'][i]['image_id'] + coco_max_id + 1
ours['annotations'][i]['category_id'] = 91 if ours['annotations'][i]['category_id'] == 1 else 92
ours['annotations'][i]['id'] = max_anno_id + i + 1
output['annotations'].append(ours['annotations'][i])
print('Done')
写入文件
最后将dict写入json文件即可
# 将output字典写入json文件
print('Writing to {}...'.format(output_filename), end='')
with open(output_filename, 'w', encoding='utf-8') as f:
json.dump(output, f)
print('Done')
print('Everything Done.')
总结
只需一个一个对应加进去即可,主要要注意id重复的问题,我的categories合并的部分没有处理好。