g
y
7
7
7
7

数据集拆分,互转,可视化,查错

分享数据集的集中常用处理代码,使用的时候记得改一下自己的路径,ann_dir是coco的json文件路径,img_dir是图片路径。如果用pycharm控制台输出的中文为乱码,将pycharm中的编码全改成utf-8(设置->编辑器->文件编码),把能改成utf-8的选项都改了。

1️⃣ 有些数据集中含有unicode编码,也就是对应的中文,我们记录好每个unicode编码对应的id。然后将文件中的unicode编码转成id。

# -*- coding: utf-8 -*-
import json
import os
import random
import time
import shutil
import glob

category=['无瑕疵','花板跳', '水渍', '星跳', '浆斑', '油渍', '烧毛痕', '死皱', '筘路', '浪纹档', '三丝', '跳纱', '双经', '修痕',
          '污渍', '百脚', '松经', '跳花', '吊经', '纬纱不良', '断氨纶', '双纬', '粗维', '磨痕', '云织', '整经结', '稀密档', '断经',
          '粗经', '纬缩', '色差档', '毛粒', '破洞', '结头', '轧痕']

root_path=os.getcwd()
ann_dir=os.path.join(root_path,"smartdiagnosisofclothflaw_round1train1_datasets",
                             "guangdong1_round1_train1_20190818","Annotations")
img_dir=os.path.join(root_path,"smartdiagnosisofclothflaw_round1train1_datasets",
                             "guangdong1_round1_train1_20190818","defect_Images")

# 训练集比例
train_percent = 0.8

#####################################################################################
#####                              数据集中文改英文
#####################################################################################
def unicode2id():
    ann_file=os.path.join(ann_dir,"anno_train.json")
    print(ann_file)

    # # 输出训练数据集中所有的类别
    # category_temp=set()
    # with open(anno_file, 'r', encoding='unicode_escape') as f:
    #     json_data = json.load(f)
    #     for i in json_data:
    #         category.add(i['defect_name'])
    # print(category_temp)
    # print(len(category_temp))

    data1=[]
    # 将数据集中的中文unicode编码,改编成数字id
    with open(ann_file, 'r', encoding='unicode_escape') as f:
        json_data = json.load(f)
        for i in json_data:
            data1.append({'name':i['name'],'defect_name':category.index(i['defect_name']),'bbox':i['bbox']})

    with open(os.path.join(ann_dir,'data.json'), 'w') as f:
         json.dump(data1, f)

2️⃣ COCO数据集划分为train和val

#####################################################################################
#####                              COCO数据集划分为train,val
#####################################################################################
def coco_dataset_split():
    time_start = time.time()

    # 建立输出文件夹
    if not os.path.exists(os.path.join(root_path, "COCO2017")):
        os.makedirs(os.path.join(root_path, "COCO2017"))
    if not os.path.exists(os.path.join(root_path, "COCO2017","annotations")):
        os.makedirs(os.path.join(root_path,"COCO2017", "annotations"))
    if not os.path.exists(os.path.join(root_path, "COCO2017","train2017")):
        os.makedirs(os.path.join(root_path,"COCO2017", "train2017"))
    if not os.path.exists(os.path.join(root_path,"COCO2017", "val2017")):
        os.makedirs(os.path.join(root_path,"COCO2017", "val2017"))

    # 保存路径
    save_img_train_dir = os.path.join(root_path, "COCO2017", "train2017")
    save_img_val_dir = os.path.join(root_path, "COCO2017", "val2017")
    save_ann_train_file = os.path.join(root_path, "COCO2017", "annotations", "instances_train2017.json")
    save_ann_val_file = os.path.join(root_path, "COCO2017", "annotations", "instances_val2017.json")

    # 数据集类别及数量
    images_list = os.listdir(img_dir)
    images_num = len(images_list)

    train_num = int(images_num * train_percent)
    val_num=images_num-train_num
    train_list = random.sample(images_list, train_num)
    val_list = list(set(images_list) - set(train_list))
    print("| Images num: ",images_num)
    print("| Train num: ",train_num)
    print("| Val num: ",val_num)

    # 复制图片。
    for image_name in train_list:
        shutil.copy(os.path.join(img_dir, image_name), os.path.join(save_img_train_dir, image_name))
    for image_name in val_list:
        shutil.copy(os.path.join(img_dir, image_name), os.path.join(save_img_val_dir, image_name))

    ann_path=os.path.join(ann_dir,"anno_train.json")

    # 提取annotation
    train2017=[]
    val2017=[]
    with open(ann_path, 'r', encoding='unicode_escape') as fp:
        json_data = json.load(fp)
        for i in json_data:
            if i['name'] not in val_list:
                train2017.append({'name':i['name'],'defect_name':category.index(i['defect_name']),'bbox':i['bbox']})
            else:
                val2017.append({'name':i['name'],'defect_name':category.index(i['defect_name']),'bbox':i['bbox']})
    # 写入annotation
    with open(save_ann_train_file, 'w') as fp:
        json.dump(train2017, fp)
    with open(save_ann_val_file, 'w') as fp:
        json.dump(val2017, fp)

    time_end = time.time()
    cost_time=time_end-time_start
    print("| Cost time: ",cost_time//60//60,"hour",cost_time//60%60,"min",cost_time%60,"s")

3️⃣ COCO数据集转换成VOC数据集,复制图片比较耗时,耐心等待就行了。为了节省时间,没有可视化复制图片的进度。如果想加,可以百度一下tqdm,加到复制图片的for循环中就可以了。

#####################################################################################
#####                              coco数据集转换成voc数据集
#####################################################################################
def coco2voc():
    from lxml.etree import Element, SubElement, tostring
    from xml.dom.minidom import parseString

    # 创建保存的文件夹
    if not os.path.exists(os.path.join(root_path, "VOCdevkit", "VOC2012")):
        os.makedirs(os.path.join(root_path, "VOCdevkit", "VOC2012"))
        os.makedirs(os.path.join(root_path, "VOCdevkit", "VOC2012", "Annotations"))
        os.makedirs(os.path.join(root_path, "VOCdevkit", "VOC2012", "ImageSets"))
        os.makedirs(os.path.join(root_path, "VOCdevkit", "VOC2012", "ImageSets", "Main"))
        os.makedirs(os.path.join(root_path, "VOCdevkit", "VOC2012", "JPEGImages"))

    # json文件路径
    ann_path = os.path.join(ann_dir,"data.json")
    ann_file = open(ann_path, "r", encoding='utf-8')
    ann_json_list = json.load(ann_file)

    save_xml_path = os.path.join(root_path, "VOCdevkit", 'VOC2012', 'Annotations')

    # 保存每个图片对应的category以及bbox.
    img_names = []
    img_bbox_category = {}
    for ann in ann_json_list:
        # 获取coco数据集中json的信息
        img_name = ann['name']
        category = ann['defect_name']
        bbox = ann['bbox']
        if img_name not in img_names:
            img_names.append(img_name)
            img_bbox_category[img_name] = [{"category":category,"bbox":bbox}]
        else:
            img_bbox_category[img_name].append({"category":category,"bbox":bbox})

    print('| Images start copy.')
    # 复制所有的图片到voc数据集中。
    for img_name in img_names:
        shutil.copy(os.path.join(img_dir, img_name), os.path.join(root_path, "VOCdevkit", 'VOC2012', 'JPEGImages', img_name))
    print('| Images copy finish.')

    print('| Jsons start transform')
    # 第一层循环遍历所有的照片,提出json中所有的信息,并分别放到不同xml文件中。
    for img_name in img_bbox_category.keys():
        # 获取图片名字
        img_name_temp = img_name
        root_node = Element('annotation')
        node_filename = SubElement(root_node, 'filename')
        node_filename.text = img_name_temp

        from PIL import Image
        node_size = SubElement(root_node, 'size')
        node_width = SubElement(node_size, 'width')
        node_height = SubElement(node_size, 'height')
        img_m = Image.open(os.path.join(img_dir,img_name))
        node_width.text = str(img_m.width)       # 图片的宽
        node_height.text = str(img_m.height)     # 图片的高

        # 第二层循环遍历有多少个框
        for bbox_and_category in img_bbox_category[img_name_temp]:
            category_temp = bbox_and_category["category"]
            bbox_temp = bbox_and_category["bbox"]

            # 类别名字
            node_object = SubElement(root_node, 'object')
            node_name = SubElement(node_object, 'name')
            node_name.text = str(category_temp)

            node_bndbox = SubElement(node_object, 'bndbox')
            node_xmin = SubElement(node_bndbox, 'xmin')
            node_xmin.text = str(bbox_temp[0])
            node_ymin = SubElement(node_bndbox, 'ymin')
            node_ymin.text = str(bbox_temp[1])
            node_xmax = SubElement(node_bndbox, 'xmax')
            node_xmax.text = str(bbox_temp[2])
            node_ymax = SubElement(node_bndbox, 'ymax')
            node_ymax.text = str(bbox_temp[3])

        xml = tostring(root_node)
        dom = parseString(xml)
        # print xml 打印查看结果
        img_name_temp = img_name_temp.replace(".jpg", "")
        xml_name = os.path.join(save_xml_path, img_name_temp+'.xml')
        with open(xml_name, 'wb') as f:
            f.write(dom.toprettyxml(indent='\t', encoding='utf-8'))
            # f.write(dom.toprettyxml(indent='\t',))
    print('| Jsons transform finish.')

4️⃣ voc数据集转换成coco数据集

#####################################################################################
#####                           voc数据集转换成coco数据集
#####################################################################################
def voc2coco():
    import datetime
    from PIL import Image

    # 处理coco数据集中category字段。
    # 创建一个 {类名 : id} 的字典,并保存到 总标签data 字典中。
    class_name_to_id = {'class1':1, 'class2':2, 'class3':3, 'class4':4, 'class5':5, 'class6':6, 'class7':7, 'class8':8}
    
    # 创建coco的文件夹
    if not os.path.exists(os.path.join(root_path, "coco2017")):
        os.makedirs(os.path.join(root_path, "coco2017"))
        os.makedirs(os.path.join(root_path, "coco2017", "annotations"))
        os.makedirs(os.path.join(root_path, "coco2017", "train2017"))
        os.makedirs(os.path.join(root_path, "coco2017", "val2017"))

    # 创建 总标签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, file_name,url, height, width, date_captured, id
        ],
        type="instances",
        annotations=[
            # segmentation, area, iscrowd, image_id, bbox, category_id, id
        ],
        categories=[
            # supercategory, id, name
        ],
    )

    for name,id in class_name_to_id.items():
        data["categories"].append(
            dict(supercategory=None, id=id, name=name, )
        )

    # 处理coco数据集train中images字段。
    images_dir=os.path.join(root_path,'VOCdevkit','VOC2012','JPEGImages')
    images=os.listdir(images_dir)

    # 生成每个图片对应的image_id
    images_id={}
    for idx,image_name in enumerate(images):
        images_id.update({image_name[:-4]:idx})

    # 获取训练图片
    train_img=[]
    fp = open(os.path.join(root_path,'VOCdevkit','VOC2012','ImageSets','Main','train.txt'))
    for i in fp.readlines():
        train_img.append(i[:-1]+".jpg")

    # 获取训练图片的数据
    for image in train_img:
        img = Image.open(os.path.join(images_dir,image))
        data["images"].append(
            dict(
                license=0,
                url=None,
                file_name=image,              # 图片的文件名带后缀
                height=img.height,
                width=img.width,
                date_captured=None,
                # id=image[:-4],
                id=images_id[image[:-4]],
            )
        )

    # 获取coco数据集train中annotations字段。
    train_xml=[i[:-4]+'.xml' for i in train_img]

    bbox_id=0
    for xml in train_xml:
        category = []
        xmin = []
        ymin = []
        xmax = []
        ymax = []
        import xml.etree.ElementTree as ET
        tree = ET.parse(os.path.join(root_path,'VOCdevkit','VOC2012','Annotations',xml))
        root = tree.getroot()
        object = root.findall('object')
        for i in object:
            category.append(class_name_to_id[i.findall('name')[0].text])
            bndbox = i.findall('bndbox')
            for j in bndbox:
                xmin.append(float(j.findall('xmin')[0].text))
                ymin.append(float(j.findall('ymin')[0].text))
                xmax.append(float(j.findall('xmax')[0].text))
                ymax.append(float(j.findall('ymax')[0].text))
        for i in range(len(category)):
            data["annotations"].append(
                dict(
                    id=bbox_id,
                    image_id=images_id[xml[:-4]],
                    category_id=category[i],
                    area=(xmax[i]-xmin[i])*(ymax[i]-ymin[i]),
                    bbox=[xmin[i],ymin[i],xmax[i]-xmin[i],ymax[i]-ymin[i]],
                    iscrowd=0,
                )
            )
            bbox_id+=1
    # 生成训练集的json
    json.dump(data, open(os.path.join(root_path,'coco2017','annotations','instances_train2017.json'), 'w'))

    # 获取验证图片
    val_img = []
    fp = open(os.path.join(root_path, 'VOCdevkit', 'VOC2012', 'ImageSets', 'Main', 'val.txt'))
    for i in fp.readlines():
        val_img.append(i[:-1] + ".jpg")

    # 将训练的images和annotations清空,
    del data['images']
    data['images']=[]
    del data['annotations']
    data['annotations']=[]

    # 获取验证集图片的数据
    for image in val_img:
        img = Image.open(os.path.join(images_dir, image))
        data["images"].append(
            dict(
                license=0,
                url=None,
                file_name=image,  # 图片的文件名带后缀
                height=img.height,
                width=img.width,
                date_captured=None,
                id=images_id[image[:-4]],
            )
        )

    # 处理coco数据集验证集中annotations字段。
    val_xml=[i[:-4]+'.xml' for i in val_img]

    for xml in val_xml:
        category = []
        xmin = []
        ymin = []
        xmax = []
        ymax = []
        import xml.etree.ElementTree as ET
        tree = ET.parse(os.path.join(root_path,'VOCdevkit','VOC2012','Annotations',xml))
        root = tree.getroot()
        object = root.findall('object')
        for i in object:
            category.append(class_name_to_id[i.findall('name')[0].text])
            bndbox = i.findall('bndbox')
            for j in bndbox:
                xmin.append(float(j.findall('xmin')[0].text))
                ymin.append(float(j.findall('ymin')[0].text))
                xmax.append(float(j.findall('xmax')[0].text))
                ymax.append(float(j.findall('ymax')[0].text))
        for i in range(len(category)):
            data["annotations"].append(
                dict(
                    id=bbox_id,
                    image_id=images_id[xml[:-4]],
                    category_id=category[i],
                    area=(xmax[i]-xmin[i])*(ymax[i]-ymin[i]),
                    bbox=[xmin[i],ymin[i],xmax[i]-xmin[i],ymax[i]-ymin[i]],
                    iscrowd=0,
                )
            )
            bbox_id+=1
    # 生成验证集的json
    json.dump(data, open(os.path.join(root_path,'coco2017','annotations','instances_val2017.json'), 'w'))
    print('| VOC -> COCO annotations transform finish.')
    print('Start copy images...')

     for img_name in train_img:
         shutil.copy(os.path.join(root_path,"VOCdevkit", "VOC2012", "JPEGImages", img_name), os.path.join(root_path, "coco2017", 'train2017', img_name))
     print('| Train images copy finish.')
    
     for img_name in val_img:
         shutil.copy(os.path.join(root_path,"VOCdevkit", "VOC2012", "JPEGImages", img_name), os.path.join(root_path, "coco2017", 'val2017', img_name))
     print('| Val images copy finish.')

5️⃣ VOC数据集划分为train和val

#####################################################################################
#####                              voc数据集划分为train,val
#####################################################################################
def voc_dataset_split():
    file_train = open(
        os.path.join(root_path, "VOCdevkit", "VOC2012", "ImageSets", "Main", "train.txt"), 'w')
    file_val = open(
        os.path.join(root_path, "VOCdevkit", "VOC2012", "ImageSets", "Main", "val.txt"), 'w')

    xml_total_filename = glob.glob(os.path.join(root_path, "VOCdevkit", 'VOC2012', 'Annotations', "*.xml"))
    for idx,xml in enumerate(xml_total_filename):
        xml_total_filename[idx]=xml.split('\\')[-1]
    num_total = len(xml_total_filename)
    num_train = int(num_total*train_percent)
    train_sample = random.sample(xml_total_filename, num_train)

    for name in xml_total_filename:
        if name in train_sample:
            file_train.write(name[:-4]+'\n')
        else:
            file_val.write(name[:-4]+'\n')

    file_train.close()
    file_val.close()

6️⃣ 检查数据集中图片是否有损坏

#####################################################################################
#####        OSError: image file is truncated (9 bytes not processed)
#####        检查数据集中图片是否有损坏。找到有问题图片,删掉它,并修改数据集。
#####################################################################################
def check_images():
    from PIL import Image
    images_dir=os.path.join(root_path,'VOCdevkit','VOC2012','JPEGImages')
    images=os.listdir(images_dir)
    for i in images:
        try:
            img = Image.open(os.path.join(root_path,'VOCdevkit','VOC2012','JPEGImages',i))  # 如果图片不存在,报错FileNotFoundError
            img.load()  # 如果图片不完整,报错OSError: image file is truncated
        except (FileNotFoundError, OSError):
            print(i)

7️⃣ coco数据集将gt可视化,查看

#####################################################################################
# #####                         coco数据集将gt可视化,查看
# #####################################################################################
def visiual_gt():
    import cv2

    # 获取bboxes
    json_file = os.path.join(root_path,'COCO2017','annotations','instances_train2017.json')
    data = json.load(open(json_file, 'r'))
    # annotations = data['annotations']
    images=[]
    for d in data:
        images.append(d['name'])

    # 读取图片
    for i in random.sample(range(len(images)),5):
        img = cv2.imread(os.path.join(root_path,'COCO2017','train2017',images[i]))

        bboxes = []                                                    # 获取每个图片的bboxes
        for d in data:
            if d['name']==images[i]:
                bboxes.append(d["bbox"])

        # 生成锚框
        for bbox in bboxes:
            left_top = (int(bbox[0]), int(bbox[1]))                     # 这里数据集中bbox的含义是,左上角坐标和右下角坐标。
            right_bottom = (int(bbox[2]), int(bbox[3]))                 # 根据不同数据集中bbox的含义,进行修改。
            cv2.rectangle(img, left_top, right_bottom, (0, 255, 0), 2)  # 图像,左上角,右下坐标,颜色,粗细

        cv2.imshow('image', img)
        cv2.waitKey(0)
    cv2.destroyAllWindows()

博客所有的代码,都同一放到一个python文件中,用那个就调用那个文件。

if __name__ == '__main__':
    random.seed(777)
    print("—" * 50)
    # unicode2id()                      # 数据集unicode编码转id
    # coco_dataset_split()              # coco数据集拆分。
    # coco2voc()                          # coco数据集转换成voc数据集
    # voc_dataset_split()               # voc数据集拆分
    # check_images()                    # 检查图片是否有损坏
    # visiual_gt()                        # coco数据集将gt可视化,查看
    voc2coco()                          # voc数据集转换成coco数据集
    print("—" * 50)

⭐ 完结撒花,如果有需要帮助的评论或者私聊都可以,看到就回答了。

posted @ 2021-12-06 09:49  gy77  阅读(517)  评论(0编辑  收藏  举报