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

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.pyimport 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 ospimport imgviz
import PIL.Imagefrom labelme import utils
from labelme.logger import loggerimport glob
def main():parser = argparse.ArgumentParser()# 修改变量名为文件夹变量名parser.add_argument("json_dir_file")parser.add_argument("-o", "--out", default=None)# args = parser.parse_args()args = parserargs.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_valuelbl, _ = 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] = namelbl_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.rhkb.cn/news/381131.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kubernetes集群部署elasticsearch集群,包含无认证和有认证模式

1、背景: 因公司业务需要,需要在测试、生产kubernetes集群中部署elasticsearch集群,因不同环境要求,需要部署不同模式的elasticsearch集群, 1、测试环境因安全性要求不高,是部署一套默认配置; 2…

外部网络设计

外部网络设计 https://support.huawei.com/enterprise/zh/doc/EDOC1100368575/e64f745b#ZH-CN_TOPIC_0268148455 在Fabric网络的资源模型设计中,通过在Border节点创建外部网络,使得园区内部终端能够访问外部Internet等。Border上创建的每个外部网络资源…

【网络】socket套接字基础知识

> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:理解并掌握socket套接字。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自:网络…

argon主题调整日记

前言 argon主题是一款由solstice23开发的一款简洁美观的WordPress主题,在使用过程中也发现了几个可以优化的点,在查阅主题文档无果后对其进行以下几点修改。 1、使用子主题 为了避免修改源文件而引起主题更新后修改丢失的问题,还是尽量使用子…

Java | Leetcode Java题解之第274题H指数

题目&#xff1a; 题解&#xff1a; class Solution {public int hIndex(int[] citations) {int left0,rightcitations.length;int mid0,cnt0;while(left<right){// 1 防止死循环mid(leftright1)>>1;cnt0;for(int i0;i<citations.length;i){if(citations[i]>mi…

【计算机网络】0 课程主要内容(自顶向下方法,中科大郑烇、杨坚)(待)

1 教学目标 掌握计算机网络 基本概念 工作原理 常用技术 为将来学习、应用和研究计算机网络打下坚实基础 2 课程主要内容 1 计算机网络和互联网2 应用层3 传输层4 网络层&#xff1a;数据平面5 网络层&#xff1a;控制平面6 数据链路层和局域网7 网络安全8 无线和移动网络9 多…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(四)-无人机认证与授权

引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 【免费】3GPPTS23.256技术报告-无人机系…

Websocket自动消息回复服务端工具

点击下载《Websocket自动消息回复服务端工具》 1. 前言 在进行Websocket开发时&#xff0c;前端小伙伴通常是和后端开发人员同步进行项目开发&#xff0c;经常会遇到后端开发人员接口还没开发完&#xff0c;也没有可以调试的环境&#xff0c;只能按照接口文档进行“脑回路开发…

从0开始的STM32HAL库学习6

外部时钟源选择 配置环境 选择TIM2 配置红色框图中的各种配置 时钟源选择外部时钟 2 1. 预分频器 Prescaler &#xff0c;下面填0&#xff0c;不分频 2. 计数模式 CounterModer &#xff0c;计数模式选择为向上计数 3. 自动重装寄存器 CouterPeriod &#xff0c;自动重…

Go语言并发编程-Channel通信_2

Channel通信 Channel概述 不要通过共享内存的方式进行通信&#xff0c;而是应该通过通信的方式共享内存 这是Go语言最核心的设计模式之一。 在很多主流的编程语言中&#xff0c;多个线程传递数据的方式一般都是共享内存&#xff0c;而Go语言中多Goroutine通信的主要方案是Cha…

[计算机基础]一、计算机组成原理

计算机组成原理的考察目标为&#xff1a; 1. 掌握单处理器计算机系统中主要部件的工作原理、组成结构以及相互连接方式。 2. 掌握指令集体系结构的基本知识和基本实现方法&#xff0c;对计算机硬件相关问题进行分析&#xff0c;并能够对相关部件进行设计。 3. 理解计算机系统的…

Spark调优特殊case- Task倾斜

首先我们观察下上面的stage5, Task MaxTime2.4Min, 但是stage5的整体耗时竟然可以达到55Min, 其实分区1000&#xff0c; 300个executor&#xff0c; 按照最大的TaskTime2.4Min来估算所有Task运行完成时间, 那么时间应该是- 2.4Min * 3 2.4Min 9.6Min 也就是最慢也就跑10分钟就…

pcie数据传输

一 数据传输通道总体设计 在上传数据时首先将 FPGA 中数据缓存到 DDR3 存储器&#xff0c;然后上位机请求后把数据从DDR3 存储器中取出并通过 PCIE 总线将数据传输到上位机&#xff1b;在下传数据时上位机中的数据首先通过 PCIE 总线下传至 FPGA&#xff0c;FPGA 读取这些数据并…

掌握这4种翻译方式,阅读外语文件不再困难

如果你作为学生需要学习或者研究外国文件&#xff0c;或者出国旅游前也需要了解一些外国文件。如果掌握文件翻译工具&#xff0c;那这些问题就不是问题啦。这里我给你介绍几个效果不错的文件翻译工具吧。 1.福.昕文献翻译网站 这个工具只要在线就能使用&#xff0c;而且在线丝…

SpringBoot 最大连接数及最大并发数是多少

SpringBoot 最大连接数及最大并发数 Spring Boot 是一个基于 Spring 框架的快速开发框架&#xff0c;它本身并不直接管理数据库连接或网络连接的最大连接数和最大并发数。这些参数通常由底层的基础设施和组件来控制&#xff0c;例如&#xff1a; 数据库连接池&#xff1a;Spri…

windows USB 设备驱动开发-USB 客户端驱动程序验证程序

USB 客户端驱动程序验证程序是 USB 3.0 驱动程序堆栈的一项功能&#xff0c;包含在 Windows 8 中。 启用验证程序后&#xff0c;USB 驱动程序堆栈会失败或修改客户端驱动程序执行的某些操作。 这些失败模拟的错误条件&#xff0c;否则可能难以找到&#xff0c;并可能导致以后产…

【Spring Boot】网页五子棋项目中遇到的困难及解决方法

目录 一、HikariPool-1 - Starting异常二、Invalid bound statement (not found)异常三、The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary异常四、The server time zone value时区报错异常五、补充知识点…

Python入门基础教程(非常详细)

现在找工作真的越来越难了&#xff01;今年更是难上加难 前几天在网上刷到这样一条热搜&#xff1a; #23岁找工作因年龄大被HR拒绝了# 是这个世界疯了还是我疯了&#xff1f; 合着只想要有20年以上工作经验的应届毕业生是吧 这好像就是现在的就业市场现状&#xff1a;“35岁…

【iOS】——探究isKindOfClass和isMemberOfClass底层实现

isKindOfClass 判断该对象是否为传入的类或其子类的实例 // 类方法实现&#xff0c;用于检查一个类是否属于另一个类或其父类链上的任何类。(BOOL)isKindOfClass:(Class)cls {// 从当前类开始&#xff0c;tcls将沿着元类的继承链向上遍历。for (Class tcls self->ISA(); …

MQTT micro-ROS:构建高效的机器人应用

什么是 micro-ROS&#xff1f; 在之前的 MQTT & FreeRTOS&#xff1a;打造你的远程控制实时应用 中&#xff0c;我们介绍了如何在 FreeRTOS 中构建你的 MQTT 应用。 FreeRTOS 主要应用在对实时性要求较高的场景中&#xff0c;但这类 RTOS 专注于提供实时任务调度和同步机…