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

本文介绍了语义分割和目标检测数据集制作的环境配置,重点讲解了labelme和labelimg的下载、使用及代码转化。labelme用于语义分割,可进行多分类标注并生成.json文件;labelimg用于目标检测,保存时需注意标签路径,还提供了xml_to_txt转换代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)环境安装配置

  在之前的文章中已经介绍了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')

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

### 使用 LabelImg 进行图像分割数据集的多边形标注 LabelImg 是一款功能强大的开源图像标注工具,提供了简单易用的操作界面,能够帮助用户高效完成图像中标记对象的任务。对于需要精确标记不规则形状的对象时,可以采用多边形标注的方式。 #### 启动 LabelImg 并加载图片 启动应用程序后,在主界面上点击 `Open Dir` 来打开待处理的图片文件夹;接着选择要开始编辑的第一张照片并确认加载到工作区中[^1]。 #### 创建新的多边形标签 为了定义一个多边形区域,先从菜单栏里选取 `Create Polyline` 或者按下快捷键 `Ctrl+T` (Windows/Linux) / `Cmd+T`(Mac),此时光标的样式会变为十字线型态表示已切换至绘图模式。随后按照实际物体轮廓依次单击各顶点位置以构建封闭图形,当回到起点附近再次点击即完成该闭合路径的确立[^2]。 #### 编辑调整现有线条 如果发现所画的边缘不够精准,则可以通过双击某一边缘上的任意处进入节点修改状态,这时会出现一些蓝色的小圆圈代表各个控制手柄,拖拽它们即可微调相应部分直至满意为止。另外还支持删除特定端点以及增加额外转折等功能来优化最终效果。 #### 设置类别名称及其他属性 每个多边形都应该关联一个预设好的分类名以便后续训练模型识别不同种类的目标物。这一步骤通常是在创建完成后弹出对话框内指定,如果没有自动显示的话也可以手动右键选中的shape然后挑选 “Edit Labels”,输入合适的描述文字保存下来作为此次操作的结果记录。 #### 导出标注成果 最后别忘了定期保存进度以防意外丢失重要更改。可通过顶部导航条里的 `Save` 功能实现当前文档连同所有已完成的工作一起存档备份。而针对整个项目而言则建议利用 `Change Save Dir` 设定专门存储这些XML格式元数据的位置方便日后查阅管理。 ```bash # 安装依赖库(首次运行前) pip install pyqt5 lxml # 下载最新版可执行程序包解压后直接运行labelimg.exe(Windows)/labelImg(MacOS&Linux) git clone https://github.com/tzutalin/labelImg.git cd labelImg make qt5py3 ./labelImg ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值