目录
[1. 介绍](#1. 介绍)
[2. 使用方法](#2. 使用方法)
[3. 注意事项](#3. 注意事项)
[4. 示例](#4. 示例)
1. 介绍
该脚本用于将多个 COCO 格式的 JSON 标注文件合并为一个 JSON 文件。COCO 格式常用于目标检测和图像分割任务,包含以下三个主要部分:
"images":图像信息,如图像 ID、文件名等。
"annotations":标注信息,如边界框、类别 ID 等。
"categories":类别信息,如类别 ID、名称等。
在合并过程中,脚本会重新分配 image id、bbox id 和 category id,以避免 ID 冲突并保持一致性。合并后的 image id 和 bbox id 将从 0 开始顺序排列。
2. 使用方法
打开脚本文件(例如 concat_json.py),并修改以下两个路径:
files_root:存放 JSON 文件的文件夹路径。
output_file:合并后 JSON 文件的保存路径。
python
files_root = r'D:\w-dataset\AOFandODV2\annotations\val' # 修改为您的 JSON 文件夹路径
output_file = r'D:\w-dataset\AOFandODV2\annotations\val\output.json' # 修改为输出文件路径
3. 注意事项
JSON 格式:确保所有 JSON 文件都是有效的 COCO 格式。脚本不会检查格式错误。
ID 重新分配:合并后的 image id 和 bbox id 将从 0 开始重新分配,原始 ID 会被覆盖。
类别合并:相同的类别名称将共享同一个 category id。新的类别 ID 从 1 开始分配(0 被预留给 "ignored")。
ID 冲突:如果原始 JSON 文件中存在相同的 image id 或 bbox id,脚本会自动重新分配以避免冲突。
4. 示例
假设有以下文件夹结构:
D:\w-dataset\AOFandODV2\annotations\val
├── file1.json
├── file2.json
└── file3.json
打开 concat_json.py 脚本。
修改 files_root 为 'D:\\w-dataset\\AOFandODV2\\annotations\\val'。
修改 output_file 为 'D:\\w-dataset\\AOFandODV2\\annotations\\val\\output.json'。
保存脚本并在终端中运行 python concat_json.py。
运行后,合并后的 JSON 文件将保存在 'D:\\w-dataset\\AOFandODV2\\annotations\\val\\output.json'。
5.完整代码
python
import json
from pathlib import Path
"""
拼接多个coco格式的json file
支持多个categories
会自动将 image id 与 bbox id 顺序排列
"""
def concat(files_root:str, output_file = 'output.json'):
files_root = Path(files_root)
#total_data = {"images": [], "categories": [{ "supercategory": None, "id": 0, "name": "_background_" }], "annotations": []}
#ignored
total_data = {"images": [], "categories": [{"supercategory": None, "id": 0, "name": "ignored"}],"annotations": []}
file_list = [str(i) for i in files_root.iterdir() if i.suffix == '.json']
img_id_count, bbox_id_count, categories_count = 0, 0, 1
categories_dict:dict= {}
for json_file in file_list:
print(f'Now Processing {json_file}')
with open(file=json_file,mode='r') as f:
json_data = json.load(f)
images = json_data['images']
annotations = json_data['annotations']
categories = json_data['categories']
for img_idx, image in enumerate(images):
image_new = image.copy()
origin_img_id = image['id']
image_new['id'] = img_id_count
total_data['images'].append(image_new)
for anno_idx, anno in enumerate(annotations):
if anno['image_id'] == origin_img_id:
anno_new = anno.copy()
anno_new['id'] = bbox_id_count
anno_new['image_id'] = img_id_count
total_data['annotations'].append(anno_new)
bbox_id_count += 1
for category in categories:
if anno['category_id'] == category['id'] and \
category['name'] not in categories_dict.keys():
categories_dict[category['name']] = categories_count
total_data['categories'].append(dict(supercategory = None, id =categories_count, name = category['name']))
categories_count += 1
if anno['category_id'] == category['id']:
anno_new['category_id'] = categories_dict[category['name']]
img_id_count += 1
with open(output_file, 'w') as f:
json.dump(total_data, f)
if __name__ == '__main__':
files_root = r'D:\w-dataset\AOFandODV2\annotations\val' # 修改为文件夹路径
output_file = r'D:\w-dataset\AOFandODV2\annotations\val\output.json' # 输出文件,默认为当前路径下的 output.json
concat(files_root, output_file=output_file)