制作coco数据集,并在mmdetection上实验

一、dataset2coco
首先将标注好的json和img放在同一个文件夹中,取名为images。

  1. format.py
    统一修改json中的img_path。将路径修改为统一格式。×××.jpg
    format.py 代码如下:
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)
  1. checkClass.py
    检查标注好的文件中的label。检查是否有错误标签。修改CLASS_REAL_NAMES为自己数据集的标签,以及要检查的存放json文件的地址dir_path。
    checkClass.py代码如下:
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需要修改的类别中。

  1. labels.txt
    将labels.txt修改为自己数据集的label
    在这里插入图片描述

  2. 为每个子集创建测试集、验证集、测试集(使用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)
  1. check_label_figure_bbox_number.py
    统计训练集、验证集、测试集label数量
    check_label_figure_bbox_number.py代码如下:
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下,把‘ ’替换成‘,’,然后制成表格。
如下所示:
在这里插入图片描述

  1. statistical_aspect_ratio.py
    统计宽高比
    statistical_aspect_ratio.py代码如下:
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数据集。并统计有关信息的全过程啦。
本人代码能力有限,如果有不对的地方,希望大家批评指教。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值