一、dataset2coco
首先将标注好的json和img放在同一个文件夹中,取名为images。
import os
import re
dir_path = '/home/chenghiuyi/03 DLA-CHD/DLA-CHD_TRAIN_NO_CHECK/逻辑分类/01 data/images/'
pattern = re.compile('"imagePath": "(.+?jpg)",')
for file in os.listdir(dir_path):
if os.path.splitext(file)[-1] != '.json':
continue
with open(os.path.join(dir_path, file), encoding='utf-8') as f:
content = f.read()
imagePath = pattern.findall(content)[0]
print('imagePath ', imagePath)
new_content = content.replace(imagePath, os.path.splitext(file)[0]+'.jpg')
with open(os.path.join(dir_path, file), 'w', encoding='utf-8') as nf:
nf.write(new_content)
from encodings import utf_8
from math import dist
import os
import re
from unittest.util import sorted_list_difference
import numpy as np
import json
from collections import Counter
CLASS_REAL_NAMES = ['page box', 'centerfold strip', 'text', 'figure']
dir_path = '/home/chenghiuyi/03 DLA-CHD/DLA-CHD_TRAIN/物理分类/01 data/new_result_json/'
class_ids = []
json_list = os.listdir(dir_path)
for file in os.listdir(dir_path):
if os.path.splitext(file)[-1] != '.json':
continue
with open(dir_path+file, 'r', encoding='utf8') as fp:
json_data = json.load(fp)
json_shapes = json_data["shapes"]
for json_label in json_shapes:
if json_label["label"] not in CLASS_REAL_NAMES:
print('error', json_label["label"], file)
class_ids.append(json_label["label"])
class_ids = np.unique(class_ids)
print('一共有{}种class'.format(len(class_ids)))
print('分别是')
index = 1
for id in class_ids:
print('"{}",'.format(id), end="")
index += 1
print()
index = 1
for id in class_ids:
print('"{}":{},'.format(id, index))
index += 1
最终会输出
一共有4种class
分别是
"centerfold strip","figure","page box","text",
"centerfold strip":1,
"figure":2,
"page box":3,
"text":4,
“centerfold strip”,“figure”,“page box”,“text”,可以直接复制到mmdetection需要修改的类别中。
为每个子集创建测试集、验证集、测试集(使用labelme2coco.py)
将数据集变成coco形式。注意labelme2coco.py(和要转换的images同一个路径)、images里面包含(img和json文件)
注意:
labelme2coco.py进行了较多的修改。如果是本人修改的部分。会有cheng修改的字样。
这里展示的是分别两个数据集划分为8:1:1,然后合并的情况。如果是一个数据集,则不需要(3)步骤
(1) 注释合并数据集过程代码,取消注释处理数据集过程的代码。并修改以下比例。
(2) 运行以下代码,生成按比例分好的子集coco类型数据coco_811_1、coco_811_2
子集分别为 images_1_3000、images_2_1000
① python labelme2coco.py --input_dir images_1_3000 --output_dir coco_811_1 --labels labels.txt
② python labelme2coco.py --input_dir images_2_1000 --output_dir coco_811_2 --labels labels.txt
(3) 合并两个小数据集。
注意:如果只有一个数据集,则不需要这步骤。
① 创建coco_811_merge
② 将coco_811_1、coco_811_2中的train2017,val2017,test2017合并在一起。
③ 注释处理数据集过程代码,取消注释合并数据集过程的代码。
④ 运行
python labelme2coco.py --input_dir images_all --output_dir coco_811 --labels labels.txt
最终生成的images_all就为2个子集的coco文件。
labelme2coco.py代码如下:
注意:如果需要可视化。可以取消注释 可视化的处理 过程。
"""https://www.cnblogs.com/gy77/p/15408027.html"""
# 命令行执行: python labelme2coco.py --input_dir images --output_dir coco --labels labels.txt
# 输出文件夹必须为空文件夹
import argparse
import collections
import datetime
import glob
import imp
import json
import os
import os.path as osp
import shutil
import sys
import uuid
import imgviz
import numpy as np
import labelme
from sklearn.model_selection import train_test_split
import cv2
from matplotlib import pyplot as plt
try:
import pycocotools.mask
except ImportError:
print("Please install pycocotools:\n\n pip install pycocotools\n")
sys.exit(1)
def to_coco(args,label_files,num):
# train 0 :train 1:val 2:test
# 创建 总标签data
now = datetime.datetime.now()
data = dict(
info=dict(
description=None,
url=None,
version=None,
year=now.year,
contributor=None,
date_created=now.strftime("%Y-%m-%d %H:%M:%S.%f"),
),
licenses=[dict(url=None, id=0, name=None,)],
images=[
# license, url, file_name, height, width, date_captured, id
],
type="instances",
annotations=[
# segmentation, area, iscrowd, image_id, bbox, category_id, id
],
categories=[
# supercategory, id, name
],
)
# 创建一个 {类名 : id} 的字典,并保存到 总标签data 字典中。
class_name_to_id = {}
for i, line in enumerate(open(args.labels).readlines()):
class_id = i - 1 # starts with -1
class_name = line.strip() # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
if class_id == -1:
assert class_name == "__ignore__" # background:0, class1:1, ,,
continue
class_name_to_id[class_name] = class_id
data["categories"].append(
dict(supercategory=None, id=class_id, name=class_name,)
)
#------------------------------------------------------------#
# 官方实现
#------------------------------------------------------------#
# if train:
# out_ann_file = osp.join(args.output_dir, "annotations","instances_train2017.json")
# else:
# out_ann_file = osp.join(args.output_dir, "annotations","instances_val2017.json")
#------------------------------------------------------------#
# cheng修改
#------------------------------------------------------------#
if num == 0:
out_ann_file = osp.join(args.output_dir, "annotations","instances_train2017.json")
elif num == 1:
out_ann_file = osp.join(args.output_dir, "annotations","instances_val2017.json")
else:
out_ann_file = osp.join(args.output_dir, "annotations","instances_test2017.json")
for image_id, filename in enumerate(label_files):
label_file = labelme.LabelFile(filename=filename)
base = osp.splitext(osp.basename(filename))[0] # 文件名不带后缀
# if train:
# out_img_file = osp.join(args.output_dir, "train2017", base + ".jpg")
# else:
# out_img_file = osp.join(args.output_dir, "val2017", base + ".jpg")
if num == 0:
out_img_file = osp.join(args.output_dir, "train2017", base + ".jpg")
elif num == 1:
out_img_file = osp.join(args.output_dir, "val2017", base + ".jpg")
else:
out_img_file = osp.join(args.output_dir, "test2017", base + ".jpg")
print("| ",out_img_file)
# ************************** 对图片的处理开始 *******************************************
# 将标签文件对应的图片进行保存到对应的 文件夹。train保存到 train2017/ test保存到 val2017/
# img = labelme.utils.img_data_to_arr(label_file.imageData) # .json文件中包含图像,用函数提出来
img = cv2.imread(filename[:-5]+'.jpg')
# cv2.imwrite(out_img_file, img) # 将图像保存到输出路径
shutil.copy(filename[:-5]+'.jpg', os.path.join(out_img_file)) # 将图像保存到输出路径
# ************************** 对图片的处理结束 *******************************************
# ************************** 对标签的处理开始 *******************************************
data["images"].append(
dict(
license=0,
url=None,
file_name=base+".jpg", # 只存图片的文件名
# file_name=osp.relpath(out_img_file, osp.dirname(out_ann_file)), # 存标签文件所在目录下找图片的相对路径
## out_img_file : "/coco/train2017/1.jpg"
## out_ann_file : "/coco/annotations/annotations_train2017.json"
## osp.dirname(out_ann_file) : "/coco/annotations"
## file_name : ..\train2017\1.jpg out_ann_file文件所在目录下 找 out_img_file 的相对路径
height=img.shape[0],
width=img.shape[1],
date_captured=None,
id=image_id,
)
)
masks = {} # for area
segmentations = collections.defaultdict(list) # for segmentation
for shape in label_file.shapes:
points = shape["points"]
label = shape["label"]
group_id = shape.get("group_id")
shape_type = shape.get("shape_type", "polygon")
mask = labelme.utils.shape_to_mask(
img.shape[:2], points, shape_type
)
if group_id is None:
group_id = uuid.uuid1()
instance = (label, group_id)
if instance in masks:
masks[instance] = masks[instance] | mask
else:
masks[instance] = mask
if shape_type == "rectangle":
(x1, y1), (x2, y2) = points
x1, x2 = sorted([x1, x2])
y1, y2 = sorted([y1, y2])
points = [x1, y1, x2, y1, x2, y2, x1, y2]
else:
points = np.asarray(points).flatten().tolist()
segmentations[instance].append(points)
segmentations = dict(segmentations)
for instance, mask in masks.items():
cls_name, group_id = instance
if cls_name not in class_name_to_id:
continue
cls_id = class_name_to_id[cls_name]
mask = np.asfortranarray(mask.astype(np.uint8))
mask = pycocotools.mask.encode(mask)
area = float(pycocotools.mask.area(mask))
bbox = pycocotools.mask.toBbox(mask).flatten().tolist()
data["annotations"].append(
dict(
id=len(data["annotations"]),
image_id=image_id,
category_id=cls_id,
segmentation=segmentations[instance],
area=area,
bbox=bbox,
iscrowd=0,
)
)
# ************************** 对标签的处理结束 *******************************************
# ************************** 可视化的处理开始 *******************************************
# if not args.noviz:
# labels, captions, masks = zip(
# *[
# (class_name_to_id[cnm], cnm, msk)
# for (cnm, gid), msk in masks.items()
# if cnm in class_name_to_id
# ]
# )
# viz = imgviz.instances2rgb(
# # image=img,
# image=np.uint8(img),
# labels=labels,
# masks=masks,
# captions=captions,
# # font_size=15,
# font_size=30,
# line_width=2,
# )
# out_viz_file = osp.join(
# args.output_dir, "visualization", base + ".jpg"
# )
# imgviz.io.imsave(out_viz_file, viz)
# ************************** 可视化的处理结束 *******************************************
with open(out_ann_file, "w") as f: # 将每个标签文件汇总成data后,保存总标签data文件
json.dump(data, f)
# 主程序执行
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("--input_dir", help="input annotated directory")
parser.add_argument("--output_dir", help="output dataset directory")
parser.add_argument("--labels", help="labels file", required=True)
parser.add_argument("--noviz", help="no visualization", action="store_true")
args = parser.parse_args()
if osp.exists(args.output_dir):
print("Output directory already exists:", args.output_dir)
sys.exit(1)
os.makedirs(args.output_dir)
print("| Creating dataset dir:", args.output_dir)
if not args.noviz:
os.makedirs(osp.join(args.output_dir, "visualization"))
# 创建保存的文件夹
if not os.path.exists(osp.join(args.output_dir, "annotations")):
os.makedirs(osp.join(args.output_dir, "annotations"))
if not os.path.exists(osp.join(args.output_dir, "train2017")):
os.makedirs(osp.join(args.output_dir, "train2017"))
if not os.path.exists(osp.join(args.output_dir, "val2017")):
os.makedirs(osp.join(args.output_dir, "val2017"))
if not os.path.exists(osp.join(args.output_dir, "test2017")):
os.makedirs(osp.join(args.output_dir, "test2017"))
# 获取目录下所有的.jpg文件列表
feature_files = glob.glob(osp.join(args.input_dir, "*.**g"))
print(feature_files)
print('| Image number: ', len(feature_files))
# 获取目录下所有的joson文件列表
label_files = glob.glob(osp.join(args.input_dir, "*.json"))
print('| Json number: ', len(label_files))
#----------------------------------------------------------------------------------------------------#
# 官方实现
#----------------------------------------------------------------------------------------------------#
# feature_files:待划分的样本特征集合 label_files:待划分的样本标签集合 test_size:测试集所占比例
# x_train:划分出的训练集特征 x_test:划分出的测试集特征 y_train:划分出的训练集标签 y_test:划分出的测试集标签
# x_train, x_test, y_train, y_test = train_test_split(feature_files, label_files, test_size=0.2)
# print("| Train number:", len(y_train), '\t Value number:', len(y_test))
# # 把训练集标签转化为COCO的格式,并将标签对应的图片保存到目录 /train2017/
# print("—"*50)
# print("| Train images:")
# to_coco(args,y_train,train=True)
# # 把测试集标签转化为COCO的格式,并将标签对应的图片保存到目录 /val2017/
# print("—"*50)
# print("| Test images:")
# to_coco(args,y_test,train=False)
# ************************** 处理数据集过程开始 *******************************************
# cheng改代码
# 先将1.训练集,2.验证集+测试集,按照8:2进行随机划分
# X_train, X_validate_test, y_train, y_validate_test = train_test_split(feature_files, label_files, test_size = 0.2, random_state = 42)
X_train, X_validate_test, y_train, y_validate_test = train_test_split(feature_files, label_files, test_size = 0.2)
# 再将1.验证集,2.测试集,按照1:1进行随机划分
# X_validate, X_test, y_validate, y_test = train_test_split(X_validate_test, y_validate_test, test_size = 0.5, random_state = 42)
X_validate, X_test, y_validate, y_test = train_test_split(X_validate_test, y_validate_test, test_size = 0.5)
print("| Train number:", len(y_train), '\t Value number:', len(y_validate), '\t Test number:', len(y_test))
print("—"*50)
print("| Train images:")
to_coco(args, y_train, num=0)
# 把测试集标签转化为COCO的格式,并将标签对应的图片保存到目录 /val2017/
print("—"*50)
print("| Val images:")
to_coco(args, y_validate,num=1)
print("—"*50)
print("| Test images:")
to_coco(args, y_test, num=2)
# ************************** 处理数据集过程结束*******************************************
# ************************** 合并数据集过程开始*******************************************
# --------------------------------------------------------------------------------------------------------------------#
# 合并两个coco生成的子集的json步骤
# 1. 注释上面处理数据集过程
# 2. 将两个分好train、val、test子集的数据合并在一起,新建为coco_811_merge(8:1:1)
# python labelme2coco.py --input_dir images_all --output_dir coco --labels labels.txt
# --------------------------------------------------------------------------------------------------------------------#
# train_merge = []
# val_merge = []
# test_merge = []
# y_train_list = os.listdir('coco_811_merge/train2017/')
# y_val_list = os.listdir('coco_811_merge/val2017/')
# y_test_list = os.listdir('coco_811_merge/test2017/')
# for i in y_train_list:
# train_merge.append(os.path.join('images_all', i.split('.')[0] + '.json'))
# for i in y_val_list:
# val_merge.append(os.path.join('images_all', i.split('.')[0] + '.json'))
# for i in y_test_list:
# test_merge.append(os.path.join('images_all', i.split('.')[0] + '.json'))
# print("| Train number:", len(train_merge), '\t Value number:', len(val_merge), '\t Test number:', len(test_merge))
# print("—"*50)
# print("| Train images:")
# to_coco(args, train_merge, num=0)
# # 把测试集标签转化为COCO的格式,并将标签对应的图片保存到目录 /val2017/
# print("—"*50)
# print("| Val images:")
# to_coco(args, val_merge,num=1)
# print("—"*50)
# print("| Test images:")
# to_coco(args, test_merge, num=2)
#************************** 合并数据集过程结束*******************************************
if __name__ == "__main__":
print("—"*50)
main()
print("—"*50)
from pycocotools.coco import COCO
dataDir='/home/chenghiuyi/03 DLA-CHD/DLA-CHD_TRAIN/物理分类/01 data/coco'
# dataType='train2017'
# dataType='val2017'
dataType='test2017'
annFile='{}/annotations/instances_{}.json'.format(dataDir, dataType)
# initialize COCO api for instance annotations
coco=COCO(annFile)
# display COCO categories and supercategories
cats = coco.loadCats(coco.getCatIds())
cat_nms=[cat['name'] for cat in cats]
print('number of categories: ', len(cat_nms))
print('COCO categories: \n', cat_nms)
print("{} {} {}".format('label', 'figure number', 'bbox number'))
# 统计各类的图片数量和标注框数
for catId in coco.getCatIds():
img_number=coco.getImgIds(catIds=catId)
ann_number=coco.getAnnIds(catIds=catId)
print("{} {} {}".format(cat_nms[catId],len(img_number),len(ann_number)))
可以把结果复制到word下,把‘ ’替换成‘,’,然后制成表格。
如下所示:
import pandas as pd
import seaborn as sns
import numpy as np
import json
import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei'] #设置字体为黑体
plt.rcParams['font.family'] = 'sans-serif' #设置字体样式
plt.rcParams['figure.figsize'] = (10.0, 10.0) #设置字体大小
#读取数据
ann_json_path1 = "/home/chenghiuyi/03 DLA-CHD/DLA-CHD_TRAIN/物理分类/01 data/coco/annotations/instances_train2017.json"
ann_json_path2 = "/home/chenghiuyi/03 DLA-CHD/DLA-CHD_TRAIN/物理分类/01 data/coco/annotations/instances_val2017.json"
ann_json_path3 = "/home/chenghiuyi/03 DLA-CHD/DLA-CHD_TRAIN/物理分类/01 data/coco/annotations/instances_test2017.json"
ann_json_path_all = [ann_json_path1, ann_json_path2, ann_json_path3]
aspect_ratio = []
label_number = 5
for i in range(label_number):
aspect_ratio.append([])
#统计bbox的w、h、wh
bbox_w = []
bbox_h = []
bbox_wh = []
all_label_ratio_top3 = []
for ann_json_path in ann_json_path_all:
with open(ann_json_path) as f:
ann=json.load(f)
categorys_dic = dict([(i['id'],i['name']) for i in ann['categories']]) #创建{1: 'multi_signs', 2: 'window_shielding', 3: 'non_traffic_sign'}
categorys_num = dict([i['name'], 0] for i in ann['categories']) #创建{'multi_signs': 0, 'window_shielding': 0, 'non_traffic_sign': 0}
#统计每个类别的数量
for i in ann['annotations']:
categorys_num[categorys_dic[i['category_id']]] +=1
for i in ann['annotations']:
if i['category_id'] in range(label_number):
bbox_w.append(round(i['bbox'][2], 2))
bbox_h.append(round(i['bbox'][3], 2))
wh = round(i['bbox'][2]/i['bbox'][3],0)
if(wh < 1):
wh = round(i['bbox'][3]/i['bbox'][2], 0)
aspect_ratio[i['category_id']].append(wh)
print('label', ' ', 'aspect_ratio')
for i in range(label_number):
#统计所有的宽高比
bbox_wh_unique = set(aspect_ratio[i] )#set挑选出不重复的元素,即挑选出有多少种比例的anchors
# print('\tbbox_wh_unique', list(bbox_wh_unique))
bbox_count_unique = [aspect_ratio[i].count(j) for j in bbox_wh_unique] #统计宽高比数量
# print('\tbbox_count_unique', bbox_count_unique)
sort = np.argsort(-np.array(bbox_count_unique)) # 从大到小排
top_3 = np.array(list(bbox_wh_unique))[sort[0:3]]
print(categorys_dic[i], ' ', top_3)
for j in range(len(top_3)):
all_label_ratio_top3.append(top_3[j])
all_label_ratio_top3 = pd.Series(all_label_ratio_top3)
all_label_ratio_top3 = all_label_ratio_top3.value_counts()
all_label_ratio_top3.sort_index(inplace=True)
print('-'*50)
print('all_label_top3')
print('ratio number')
print(all_label_ratio_top3)
#画图
# wh_dataframe = pd.DataFrame(bbox_count_unique, index=bbox_wh_unique, columns=['宽高比数量'])
# wh_dataframe.plot(kind = 'bar', color="#55aacc" )
# plt.show()
可以把结果复制到word下,把‘ ’替换成‘,’,然后制成表格
结果如下
以上就是把labelme数据转换为coco数据集。并统计有关信息的全过程啦。
本人代码能力有限,如果有不对的地方,希望大家批评指教。