240718_使用Labelme制作自己的图像分割数据集

news2024/11/13 10:15:24

240718_使用Labelme制作自己的图像分割数据集

从目标检测入门的朋友们可能更熟悉的是LabelImg,这里要注意做好区分,LabelImg和Labelme不是一个东西,如下经典图:

image-20240718171255970

(a)图像分类(目标检测):一张图像中是否含某种物体
(b)物体定位(目标检测与目标识别):确定目标位置和所属类别。
(c)语义分割(目标分割和目标分类):对图像进行像素级分类,预测每个像素属于的类别,不区分个体;(所有的CUBE一个颜色)
(d)实例分割(目标分割和目标识别):定位图中每个物体,并进行像素级标注,区分不同个体;(CUBE都是不同颜色)

LabelImg做的是b图的工作,拉框框把目标标注出来,通常用于目标检测和识别任务,其输出为.xml或者.txt。

Labelme可以完成图中所有工作,与LabelImg对比,Labelme可以拉多边形的框,准确的把轮廓标注出来,常用于分割,输出为json。

我们在完成图像识别的任务,例如使用YOLO v5时,可能用到的是LabelImg,但如果需要完成分割的任务,例如使用经典的Unet,我们就需要使用Labelme。

在使用该工具开始工作之前,肯定要先安装工具。

安装Labelme

首先新建一个专属于Labelme的虚拟环境,因为该工具是基于PyQt实现的,所以我们也要在该虚拟环境中安装PyQt。

conda create -n Labelme python=3.9
conda activate Labelme
pip install PyQt5
pip install labelme

使用Labelme进行打标

安装完成后直接在该虚拟环境中输入labelme就可以启动该工具。

image-20240718173454466

image-20240718173520497

点击左上角打开,打开我们的图像,同样可以采取打开目录进行批量打开。点击上方创建多边形,就可以开始画框框了,用过ps钢笔工具或者套索工具的同学应该比较熟练。

image-20240718174218754

拉一个多边形框的最后一步点击初始点就可以闭合,然后会有一个弹窗让我们输入标签名称,此时我输入bottle。

image-20240718174449390

同理完成其他图像的标注。

image-20240718175309354

本来这个杯子我是想先把外围整个框好,再去找删除选区工具把他把手包含的空白删掉的,但好像没有这个工具,只能一笔拉好,产生了路线重叠,见谅。

然后点击CTRL+S保存,就可以保存一份json文件。

P:如果没有目标,比如我们做裂缝检测任务,图像中没有裂缝,我们可以不进行标注,直接CTRL+S保存,也可以生成一份json文件,用作正样本。

json转png

但在我们实际投入神经网络下训练的过程中,通常不使用json格式的标签,而是使用png格式,所以此时我们就需要进行格式转换。

针对这个问题,labelme官方给了解决方案,该工具包含一个json_to_dataset.py文件,在自己的虚拟环境目录下,例如我这里就是

D:\SoftWares\Codes\Anaconda\envs\Labelme\Lib\site-packages\labelme\cli

image-20240719122736702

在使用该py脚本进行格式转换时需要在命令行键入(例如我们的json文件路径为D:\l_139\桌面\Snipaste_2024-07-18_17-38-25.json)(需要进入虚拟环境,往后看看)

python json_to_dataset.py D:\l_139\桌面\Snipaste_2024-07-18_17-38-25.json

当然,官方也给我们准备了可执行的exe文件labelme_json_to_dataset.exe,位于虚拟环境目录下的Scripts文件夹下,我这里的路径为

D:\SoftWares\Codes\Anaconda\envs\Labelme\Scripts

在命令行键入以下命令即可实现转换

labelme_json_to_dataset D:\l_139\桌面\Snipaste_2024-07-18_17-38-25.json

注意哦,以上命令都必须在目标路径下执行哦,直接在桌面上开个命令行窗口可没用,要么就cd到py脚本或exe可执行文件所在目录,要么直接在该目录打开命令行。此处使用exe可执行文件直接进行演示

image-20240719123754550

直接使用py脚本进行转换需要进入虚拟环境,不然会报缺失包,多了一步比较麻烦,如果要用py脚本,可参考:

image-20240719125253569

可以看到,以上两种方法都可以执行,但都有警告说这个py脚本即将弃用,取而代之的是labelme_export_json,那我们就顺应大势所趋,使用人家官方建议你用的呗,不然到时候人家弃用了,咱用前朝的剑斩本朝的官当然是斩不掉咯。(此处提供使用labelme_export_json.exe的代码,以下代码在命令行中逐行输入)

# 如果是在目标路径直接打开命令行则无需以下两步操作,路径更换成自己的
D:
cd D:\SoftWares\Codes\Anaconda\envs\Labelme\Scripts
labelme_export_json D:\l_139\桌面\Snipaste_2024-07-18_17-38-25.json

image-20240719130441697

折腾来折腾去我们终于在根目录看到了一个同名文件夹,里面有四个东西,分别是分别是原图png文件、标签png文件、标签名txt文件、掩膜png文件(带有类型标注),到此处也算是回收封面了。

image-20240719130545211

以上处理方法已经成功将一个json转换为png文件,但在实际应用中,我们往往需要的是把成千上万个json文件转换成png标签,并且我们所需要的也只是上图中的label.png,如果每个json都生成这么一个文件夹,我们在处理过程中会有更多的麻烦。

json批量转为png

原来的py脚本中只转换一次是因为代码只执行了一次,我们要批量转换,最简单的不就是在原本的代码上加上一层循环,实现批量转换嘛,把export_json.py复制一份,更名为multiple_export_json.py并打开(我的在D:\SoftWares\Codes\Anaconda\envs\Labelme\Lib\site-packages\labelme\cli目录下,参考一下,别又找不到了)

首先我们来嵌套循环并修改路径读取代码,修改的没多少,可以用PyCharm的对比看一眼,对比是左侧目录中用Ctrl同时选中两个文件,然后右键,会有一个比较文件(或者选中后直接Ctrl+D)

image-20240719140108320

以下是修改部分的代码:

# multiple_export_json.py

import glob
def main():
    parser = argparse.ArgumentParser()
    # 修改变量名为文件夹变量名
    parser.add_argument("json_dir_file")
    parser.add_argument("-o", "--out", default=None)
    args = parser.parse_args()

    # 使用glob模块查找所有的json文件
    json_file = glob.glob(os.path.join(args.json_dir_file, '*.json'))

    # 添加循环,其下代码整体缩进
    for json_file in json_file:
        '''处理逻辑不变'''


if __name__ == "__main__":
    main()

此处使用的数据是我随便找的几张素描图,打了简陋的标

image-20240719140456192

在命令行中执行

python multiple_export_json.py D:\l_139\桌面\test

image-20240719140644335

在根目录下得到四个文件夹

image-20240719140704662

至此就实现了批量处理,但是还没有实现批量存放label.png,继续改进。

在代码最后保存部分进行修改,在根目录新建一个mask文件夹,把标签文件改名后都存放到mask文件夹中,以下是部分修改代码

		# PIL.Image.fromarray(img).save(osp.join(out_dir, "img.png"))
        # 对label.png更名后进行统一存放
        mask_name = osp.splitext(osp.basename(json_file))[0]
        mask_dir = osp.join( osp.dirname(json_file),'mask')
        if not osp.exists(mask_dir):
            os.mkdir(mask_dir)
        utils.lblsave(osp.join(mask_dir, mask_name+".png"), lbl)
        # PIL.Image.fromarray(lbl_viz).save(osp.join(out_dir, "label_viz.png"))

        # with open(osp.join(out_dir, "label_names.txt"), "w") as f:
        #     for lbl_name in label_names:
        #         f.write(lbl_name + "\n")

        logger.info("Saved to: {}".format(out_dir))

image-20240719153800649

以下是效果:

image-20240719153842254

以下是完整代码:

# multiple_export_json.py
import argparse
import base64
import json
import os
import os.path as osp

import imgviz
import PIL.Image

from labelme import utils
from labelme.logger import logger

import glob
def main():
    parser = argparse.ArgumentParser()
    # 修改变量名为文件夹变量名
    parser.add_argument("json_dir_file")
    parser.add_argument("-o", "--out", default=None)
    # args = parser.parse_args()
    args = parser

    args.json_dir_file="D:\\l_139\\桌面\\test"
    args.out=None
    # 使用glob模块查找所有的json文件
    json_file = glob.glob(os.path.join(args.json_dir_file, '*.json'))

    # 添加循环,其下代码整体缩进
    for json_file in json_file:
        if args.out is None:
            out_dir = osp.splitext(osp.basename(json_file))[0]
            out_dir = osp.join(osp.dirname(json_file), out_dir)
        else:
            out_dir = args.out
        # if not osp.exists(out_dir):
        #     os.mkdir(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}
        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, "img.png"))
        # 对label.png更名后进行统一存放
        mask_name = osp.splitext(osp.basename(json_file))[0]
        mask_dir = osp.join( osp.dirname(json_file),'mask')
        if not osp.exists(mask_dir):
            os.mkdir(mask_dir)
        utils.lblsave(osp.join(mask_dir, mask_name+".png"), lbl)
        # PIL.Image.fromarray(lbl_viz).save(osp.join(out_dir, "label_viz.png"))

        # with open(osp.join(out_dir, "label_names.txt"), "w") as f:
        #     for lbl_name in label_names:
        #         f.write(lbl_name + "\n")

        logger.info("Saved to: {}".format(out_dir))


if __name__ == "__main__":
    main()

如果做的是一个二分类任务,可能会涉及需要将label的像素值归一化为黑白0-1。具体参考240719_图像二分类任务中图像像素值的转换-[0,255]-[0,1]-CSDN博客

参考博客:

labelImg和labelme的区别、安装和基本使用_labelme和labelimg区别-CSDN博客

Labelme做数据标签、批量处理json文件转换为png方法_labelme json文件转换-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1937425.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习·概率论基础

概率基础 这部分太简单,直接略过 条件概率 独立性 独立事件A和B的交集如下 非独立事件 非独立事件A和B的交集如下 贝叶斯定理 先验 事件 后验 在概率论和统计学中,先验概率和后验概率是贝叶斯统计的核心概念 简单来说后验概率就是结合了先验概率的前提…

院内影像一体化平台PACS源码,C#语言的PACS/RIS系统,二级医院应用案例

全院级PACS系统源码,一体化应用系统整合,满足放射、超声、内窥镜中心、病理、检验等多个科室的工作流程和需求,为不同科室提供专业的解决方案,实现了全院乃至区域内信息互联互通、数据统一存储与管理等功能,做到以病人…

微软研发致胜策略 05:进度狂

这是一本老书,作者 Steve Maguire 在微软工作期间写了这本书,英文版于 1994 年发布。我们看到的标题是中译版名字,英文版的名字是《Debugging the Development Process》,这本书详细阐述了软件开发过程中的常见问题及其解决方案&a…

免费视频批量横转竖

简介 视频处理器 v1.3 是一款由是貔貅呀开发的视频编辑和处理工具,提供高效便捷的视频批量横转竖,主要功能: 导入与删除文件:轻松导入多个视频文件,删除不必要的文件。暂停与继续处理:随时暂停和继续处理。…

大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: HadoopHDFSMapReduceHiveFlumeSqoopZookeeperHBaseRedis (正在更新) 章节内容 上一…

python中的数据类型-适合新手-比较完善(写了好久……)

作者的话 首先,我先申明,以下思路仅为个人理解,如有不同,望指导,谢谢。 数据类型它是什么,有什么用,怎么用就是它的全部内容,知识框架串联起来之后就是这三部分内容,没有…

【网络安全科普】勒索病毒 防护指南

勒索病毒简介 勒索病毒是一种恶意软件,也称为勒索软件(Ransomware),其主要目的是在感染计算机后加密用户文件,并要求用户支付赎金以获取解密密钥。这种类型的恶意软件通常通过电子邮件附件、恶意链接、下载的软件或漏洞…

数论基础知识

整除 辗转相除法 同余 模计算机 一次同余方程 费马小定理|欧拉定理|威尔逊定理 孙子定理(中国剩余定理) 快速指数算法(快速模乘法)(反复平方乘) 模重复平方法 二次剩余 Legendre符号欧拉判别法 原根 gc…

golang 解压带密码的zip包

目录 Zip文件详解ZIP 文件格式主要特性常用算法Zip格式结构图总览Zip文件结构详解数据区本地文件头文件数据文件描述 中央目录记录区(核心目录记录区 )中央目录记录尾部区 压缩包解压过程方式1 通过解析中央目录区来解压方式2 通过读取本地文件头来解压两…

JVM常用工具中jmap实现手动进行堆转储(heap dump文件)并使用MAT(Memory Analyzer Tool)进行堆分析-内存消耗分析

场景 JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用: JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用_jvm分析工具-CSDN博客 上面讲了jmap的简单使用。 下面记录其常用功能,实现堆…

C#+layui+echarts实现动态生成折线图

概要 C#layuiecharts实现动态生成折线图 整体架构流程 后端是c#语言编写的业务流程,前端是layui和echarts 技术细节 1.先看echarts折线图需要什么样子的数据,在想后端怎么处理 2.后端代码 List<ValveTempData> list new List<ValveTempData>(); string …

Spring Cloud中怎么使用Resilience4j RateLimiter对接口进行限流

在微服务架构中&#xff0c;限流是保护系统稳定性的重要手段之一。限流可以防止某个服务因流量过大而过载&#xff0c;影响整个系统的稳定性和性能。Resilience4j 提供了多种限流策略&#xff0c;其中 RateLimiter 是一种常用的限流机制。本文将详细介绍如何在 Spring Cloud 项…

组内第一次会议

会议内容 1、科研平台使用 增删改查对文件 cp -r /root/mmdetection/dataset/ /root/user/wbzExperiment/mmdetection/ rm -r /root/user/yolov5-master tar -czvf test03.tar.gz test03/ unzip abc.zip 上传文件、解压文件&#xff1a;要在自己的目录中&#xff0c;进入…

普中51单片机:LED点阵屏组成结构及实现方法详解(九)

文章目录 引言什么是LED点阵屏&#xff1f;工作原理74HC595移位寄存器基本引脚作用级联工作原理 电路图代码演示——16*16LED点阵屏轮播点亮每行LED代码演示——显示数字0代码演示——16*16游动字幕显示 引言 LED点阵屏作为一种广泛应用于现代显示技术的设备&#xff0c;因其能…

Linux_线程的使用

目录 1、线程与进程的关系 2、线程的优缺点 3、创建线程 4、查看启动的线程 5、验证线程是共享地址空间的 6、pthread_create的重要形参 6.1 线程id 6.2 线程实参 7、线程等待 8、线程退出 9、线程取消 10、线程tcb 10.1 线程栈 11、创建多线程 12、__th…

学生信息管理系统设计

学生信息管理系统的设计是一个综合性的项目&#xff0c;涉及到数据的存储、检索、更新和删除等基本操作&#xff0c;同时也需要考虑系统的易用性、安全性和扩展性。以下是一些关键步骤和要素&#xff0c;用于指导设计这样一个系统&#xff1a; 1. 需求分析 目标用户&#xff…

wls2下的centos使用桥接模式连接宿主机网络独立静态ip

前提&#xff1a;wsl2已安装&#xff0c;可正常更新 1.在控制面板中&#xff0c;打开开启或关闭windows功能&#xff0c;将里面的 Hyper-V功能打开&#xff0c;此处涉及重启 2. 按一下win键&#xff0c;输入hy&#xff0c;上面可以看到Hyper-V Manager,点进去 3.选择右边的 Vi…

Redis系列命令更新--Redis有序集合命令

Redis有序集合&#xff08;sorted set&#xff09; &#xff08;1&#xff09;说明&#xff1a; A、Redis有序集合和集合一样也是string类型元素的集合&#xff0c;且不允许重复的成员&#xff1b;不同的是每个元素都会关联一个double类型的分数&#xff1b;redis正式通过分数…

Java语言程序设计——篇五(1)

数组 概述数组定义实例展示实战演练 二维数组定义数组元素的使用数组初始化器实战演练&#xff1a;矩阵计算 &#x1f4ab;不规则二维数组实战演练&#xff1a;杨辉三角形 概述 ⚡️数组是相同数据类型的元素集合。各元素是有先后顺序的&#xff0c;它们在内存中按照这个先后顺…

【ProtoBuf】通讯录实现(网络版)

Protobuf 还常用于通讯协议、服务端数据交换场景。那么在这个示例中&#xff0c;我们将实现一个网络版本的通讯录&#xff0c;模拟实现客户端与服务端的交互&#xff0c;通过 Protobuf 来实现各端之间的协议序列化。 需求如下&#xff1a; 客户端可以选择对通讯录进行以下操…