目标检测(labelimg)与语义分割(labelme)数据集制作

(一)环境安装配置

  在之前的文章中已经介绍了Anaconda环境的配置,因此这里我们直接从数据集制作的环境开始说起。那么我自己使用的数据及制作则是如标题所示,语义分割使用labelme,目标检测使用labelimg。首先创建一个新环境“label”,并在其中进行软件环境的下载。

conda create -n label python=3.7

在这里插入图片描述

  激活环境备用,并添加kernel。

#激活新环境
activate label
#在jupyter中添加kernel
pip install ipykernel
#然后添加新的kernel
python -m ipykernel install --name label

在这里插入图片描述)
在这里插入图片描述

(二)labelme

1. labelme下载

  下载labelme

pip install labelme

在这里插入图片描述

2. labelme使用(以多分类进行举例)

  在对应环境输入labelme打开标注窗口。
在这里插入图片描述
  选择标注文件路径,并打开。
在这里插入图片描述
 点击Edit–>Create Plygons,围绕目标周围进行标注,输入分类名称。可以点击File–>Save Automatically自动保存。
在这里插入图片描述
在这里插入图片描述
 标注完成后,会生成.json文件。
在这里插入图片描述

3. 代码转化

3.1 二分类(便于做二值分割的使用)

import json
import os
import numpy as np
from PIL import Image
from labelme import utils

def json2mask_multi(json_path, save_path):

    if not os.path.exists(save_path):
        os.makedirs(save_path)

    for json_name in os.listdir(json_path):

        data = json.load(open(os.path.join(json_path, json_name)))
        json_name = json_name.split('.')[0]
        # 根据imageData字段的字符可以得到原图像
        img = utils.img_b64_to_arr(data['imageData'])
        # lbl为label图像(用类别名对应的数字来标,背景为0)
        # lbl_names为label名和数字的对应关系字典
        lbl, lbl_names = utils.labelme_shapes_to_label(img.shape, data['shapes'])
        mask = Image.fromarray(lbl).convert('L')
        # putpalette给对象加上调色板,相当于上色:R,G,B
        # 三个数一组,对应于RGB通道,可以自己定义标签颜色
        mask.putpalette([0, 0, 0,  
                        255, 255, 255,
                        255, 255, 255,
                        128, 128, 128])
        mask.save(os.path.join(save_path, json_name +".png"))
#json路径与目标路径
json_path = "E:\\jupyter\\bao\\image_programming\\labelme\\seg\\val\\json"
save_path = "E:\\jupyter\\bao\\image_programming\\labelme\\seg\\val\\png"
json2mask_multi(json_path,save_path)

结果展示
在这里插入图片描述

在这里插入图片描述

3.2 多分类

import argparse
import base64
import json
import os
import os.path as osp
 
import imgviz
import PIL.Image
 
from labelme.logger import logger
from labelme import utils
 
import glob
 
# 最前面加入导包
import yaml
 
def main():
    logger.warning(
        "This script is aimed to demonstrate how to convert the "
        "JSON file to a single image dataset."
    )
    logger.warning(
        "It won't handle multiple JSON files to generate a "
        "real-use dataset."
    )
 
    parser = argparse.ArgumentParser()
    ###############################################json文件位置##############################
    # parser.add_argument("json_file")
    parser.add_argument("-json_dir",default="E:\\jupyter\\bao\\image_programming\\labelme\\seg\\val\\json")
    #######################################mask输出文件位置##################################
    parser.add_argument("-out", default="E:\\jupyter\\bao\\image_programming\\labelme\\seg\\val\\png")
    args = parser.parse_args(args=[])
 
    assert args.json_dir is not None and len(args.json_dir) > 0
    # json_file = args.json_file
    json_dir = args.json_dir
 
    if osp.isfile(json_dir):
        json_list = [json_dir] if json_dir.endswith('.json') else []
    else:
        json_list = glob.glob(os.path.join(json_dir, '*.json'))
 
    for json_file in json_list:
        json_name = osp.basename(json_file).rsplit('.',1)[0]
        out_dir = args.out if (args.out is not None) else osp.join(osp.dirname(json_file), json_name)
        if not osp.exists(out_dir):
            os.makedirs(out_dir)
 
        data = json.load(open(json_file))
        imageData = data.get("imageData")
 
        if not imageData:
            imagePath = os.path.join(os.path.dirname(json_file), data["imagePath"])
            with open(imagePath, "rb") as f:
                imageData = f.read()
                imageData = base64.b64encode(imageData).decode("utf-8")
        img = utils.img_b64_to_arr(imageData)
        ######################################种类修改##################################
        label_name_to_value = {"_background_": 0,"Deep grinding mark": 1,"Scratch": 2,"Pit": 3,"Adhesion": 4,"Bulge": 5}
        for shape in sorted(data["shapes"], key=lambda x: x["label"]):
            label_name = shape["label"]
            if label_name in label_name_to_value:
                label_value = label_name_to_value[label_name]
            else:
                label_value = len(label_name_to_value)
                label_name_to_value[label_name] = label_value
        lbl, _ = utils.shapes_to_label(
            img.shape, data["shapes"], label_name_to_value
        )
 
        label_names = [None] * (max(label_name_to_value.values()) + 1)
        for name, value in label_name_to_value.items():
            label_names[value] = name
 
        lbl_viz = imgviz.label2rgb(
            lbl, imgviz.asgray(img), label_names=label_names, loc="rb"
        )
 
        PIL.Image.fromarray(img).save(osp.join(out_dir, json_name+"img.png"))
        utils.lblsave(osp.join(out_dir, json_name+"label.png"), lbl)
        PIL.Image.fromarray(lbl_viz).save(osp.join(out_dir, json_name+"label_viz.png"))
 
        with open(osp.join(out_dir,json_name+ "label_names.txt"), "w") as f:
            for lbl_name in label_names:
                f.write(lbl_name + "\n")
 
        logger.info("Saved to: {}".format(out_dir))
        #######
        #增加了yaml生成部分
        logger.warning('info.yaml is being replaced by label_names.txt')
        info = dict(label_names=label_names)
        with open(osp.join(out_dir, 'info.yaml'), 'w') as f:
            yaml.safe_dump(info, f, default_flow_style=False)
        logger.info('Saved to: {}'.format(out_dir))
 
if __name__ == "__main__":
    main()

结果展示
在这里插入图片描述

在这里插入图片描述

3.3 多分类x_label更名与原文件同名

 自己的数据集读取习惯是原图与label名称一致,所以进行更名。

import os
 
class BatchRename():
    '''
    批量重命名文件夹中的图片文件
    '''
    def __init__(self):
        self.path = 'E:\\jupyter\\bao\\image_programming\\labelme\\seg\\val\\png'  #表示需要命名处理的文件夹
    def rename(self):
        filelist = os.listdir(self.path) #获取文件路径
        total_num = len(filelist) #获取文件长度(个数)
        for item in filelist:
            #print(item)
            if item.endswith('label.png'):  #初始的图片的格式为png格式的(或者其他格式,后面的转换格式就可以调整为自己需要的格式即可)
                src = os.path.join(os.path.abspath(self.path), item)#当前文件中图片的地址
                image_name = item.split('_')[0]
                dst = os.path.join(self.path+ "\\"+image_name + '.png')#处理后文件的地址和名称,可以自己按照自己的要求改进
                os.rename(src, dst)
        print ('Finished')

if __name__ == '__main__':
    demo = BatchRename()
    demo.rename()

结果展示
在这里插入图片描述
 之后按照数据集的分布进行处理即可,部分被、内容可参考这里面的(一)

(三)labelimg

1. labelimg下载

 在环境中输入

pip install labelimg

在这里插入图片描述

2. labelimg使用

 与上述类似,不多赘述,直接上图。注意保存的标签路径。
在这里插入图片描述
在这里插入图片描述

3. 代码转化

 不同的数据集类型输入的标签有所差异,此处提供xml_to_txt。
xml_to_txt

# -*- coding: utf-8 -*-
 
import xml.etree.ElementTree as ET
from tqdm import tqdm
from os import getcwd
import os
import random
import argparse
import shutil

sets = ['train']
#修改分类
classes = ['Deep grinding mark', 'Scratch', 'Pit', 'Adhesion', 'Bulge','Burn']
#image,xml,txt的路径
image_path = 'E:/jupyter/bao/image_programming/labelme/seg/val/image'
xml_path = 'E:/jupyter/bao/image_programming/labelme/seg/val/xml'
txt_path = 'E:/jupyter/bao/image_programming/labelme/seg/val/txt'

parser = argparse.ArgumentParser()
parser.add_argument('--xml_path', default = xml_path, type=str, help='input xml label path')
parser.add_argument('--txt_path', default = txt_path, type=str, help='output txt label path')
opt = parser.parse_args([])
'''
num = len(total_xml)
list_index = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list_index, tv)
train = random.sample(trainval, tr)
'''
xmlfilepath = opt.xml_path
txtsavepath = opt.txt_path
total_xml = os.listdir(xmlfilepath)
if not os.path.exists(txtsavepath):
    os.makedirs(txtsavepath)

num = len(total_xml)
train = range(0,num)
 
file_train = open(txtsavepath + '/train.txt', 'w')
 
for i in train:
    name = total_xml[i][:-4] + '\n'
    if i in train:
        file_train.write(name)

file_train.close()

def convert(size, box):
    dw = 1. / (size[0])
    dh = 1. / (size[1])
    x = (box[0] + box[1]) / 2.0 - 1
    y = (box[2] + box[3]) / 2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return x, y, w, h
 

def convert_annotation(image_id):
    # try:
        in_file = open(xml_path + '/%s.xml' % (image_id), encoding='utf-8')
        out_file = open(txt_path + '/%s.txt' % (image_id), 'w', encoding='utf-8')
        tree = ET.parse(in_file)
        root = tree.getroot()
        size = root.find('size')
        w = int(size.find('width').text)
        h = int(size.find('height').text)
        for obj in root.iter('object'):
            difficult = obj.find('difficult').text
            cls = obj.find('name').text
            if cls not in classes or int(difficult) == 1:
                continue
            cls_id = classes.index(cls)
            xmlbox = obj.find('bndbox')
            b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
                 float(xmlbox.find('ymax').text))
            b1, b2, b3, b4 = b
            # 标注越界修正
            if b2 > w:
                b2 = w
            if b4 > h:
                b4 = h
            b = (b1, b2, b3, b4)
            bb = convert((w, h), b)
            out_file.write(str(cls_id) + " " +
                           " ".join([str(a) for a in bb]) + '\n')
    # except Exception as e:
    #     print(e, image_id)
 
 
wd = getcwd()
for image_set in sets:
    if not os.path.exists('txt_path'):
        os.makedirs('txt_path')
    image_ids = open(txt_path +'/train.txt').read().strip().split()
    list_file = open(txt_path + '/train.txt', 'w')
    for image_id in tqdm(image_ids):
        list_file.write(image_path + '/%s.jpg\n' % (image_id))
        convert_annotation(image_id)
    list_file.close()
#删除多余的train.txt文件
if os.path.exists(txt_path +'/train.txt'):
    os.remove(txt_path +'/train.txt')

结果展示
在这里插入图片描述
 转换完成后,可以根据代码特色进行数据集划分,至此,本篇结束,感谢批评与指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值