参考链接:Labelme安装及使用教程 Labelme与YOLO标签格式互转,含实例分割和目标检测,轻松实现数据扩充_labelme yolo-CSDN博客

安装

安装包括创建环境、安装相关环境、安装labelme,具体指令如下:

首先在终端中依次执行:

1
2
3
4
conda create -n labelme python=3.6
conda activate labelme
conda install pyqt
conda install pillow

最后安装labelme,conda安装有时候会报错,这个时候可以切换成pip。

1
2
3
conda install labelme=3.16.2 
#conda安装命令如果出错也可以使用pip命令
pip install labelme==3.16.2

注意这里的labelme版本其实很老了,labelme在4之后的标注json文件中的格式与版本4之前的存在一定的差异,可以根据你的需求来选择具体版本。

启动

在需要标注的图片文件夹下用vscode或者pycharm打开,之后在终端中执行命令:

1
labelme

执行之后就会打开它的QT界面,然后选择图片或者文件夹进行标注即可。

Labelme格式转换

这里主要讨论目标检测中的yolo和labelme格式的互相转换。

Labelme转yolo

Labelme转yolo一般用于labelme标注文件在标注后转换成模型可以训练用的格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import json
import os

def labelme2yolo_det(class_name, json_dir, labels_dir):

list_labels = [] # 存放json文件的列表
# 0.创建保存转换结果的文件夹
os.makedirs(labels_dir, exist_ok=False)

# 1.获取目录下所有的labelme标注好的Json文件,存入列表中
for files in os.listdir(json_dir): # 遍历json文件夹下的所有json文件
file = os.path.join(json_dir, files) # 获取一个json文件
list_labels.append(file) # 将json文件名加入到列表中

for labels in list_labels: # 遍历所有json文件
with open(labels, "r") as f:
file_in = json.load(f)
shapes = file_in["shapes"]

txt_filename = os.path.basename(labels).replace(".json", ".txt")
txt_path = os.path.join(labels_dir, txt_filename) # 使用labels_dir变量指定保存路径

with open(txt_path, "w+") as file_handle:
for shape in shapes:
line_content = [] # 初始化一个空列表来存储每个形状的坐标信息
line_content.append(str(class_name.index(shape['label']))) # 添加类别索引
[[x1, y1], [x2, y2]] = shape['points']
x1, x2 = x1 / file_in['imageWidth'], x2 / file_in['imageWidth']
y1, y2 = y1 / file_in['imageHeight'], y2 / file_in['imageHeight']
cx, cy = (x1 + x2) / 2, (y1 + y2) / 2 # 中心点归一化的x坐标和y坐标
wi, hi = abs(x2 - x1), abs(y2 - y1) # 归一化的目标框宽度w,高度h
line_content.append(str(cx))
line_content.append(str(cy))
line_content.append(str(wi))
line_content.append(str(hi))
# 使用空格连接列表中的所有元素,并写入文件
file_handle.write(" ".join(line_content) + "\n")

print("转换完成:", txt_filename)

Yolo转Labelme

Yolo转Labelme一般用于目标检测模型可以检测出一些目标,之后在输出的yolo标注的基础上再进行标注的情况。

请注意这里是Labelme版本为3.16.2的格式转换代码,在该版本中需要增加line_colorfill_color这两个字段,而在新版本中不需要。如果您使用的是新版本的则需要将 line_colorfill_color在代码中去掉,并将版本号修改成当前版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import os
import glob
import numpy as np
import cv2
import json

# 可以将yolov8目标检测生成的txt格式的标注转为json,可以使用labelme查看标注
# 该方法可以用于辅助数据标注
def convert_txt_to_labelme_json(txt_path, image_path, output_dir, class_name, image_fmt='.png' ):
"""
将文本文件转换为LabelMe格式的JSON文件。
此函数处理文本文件中的数据,将其转换成LabelMe标注工具使用的JSON格式。包括读��图像,
解析文本文件中的标注信息,并生成相应的JSON文件。
:param txt_path: 文本文件所在的路径
:param image_path: 图像文件所在的路径
:param output_dir: 输出JSON文件的目录
:param class_name: 类别名称列表,索引对应类别ID
:param image_fmt: 图像文件格式,默认为'.png'
:return:
"""
# 获取所有文本文件路径
txts = glob.glob(os.path.join(txt_path, "*.txt"))
for txt in txts:
labelme_json = {
'version': '3.16.2',
'flags': {},
'shapes': [],
'lineColor': [0, 255, 0, 128], # 3.16.2 版本需要的全局线框颜色
'fillColor': [255, 0, 0, 128], # 3.16.2 版本需要的全局填充颜色
'imagePath': None,
'imageData': None,
'imageHeight': None,
'imageWidth': None,
}
# 获取文本文件名
txt_name = os.path.basename(txt)
# 根据文本文件名生成对应的图像文件名
image_name = txt_name.split(".")[0] + image_fmt
labelme_json['imagePath'] = image_name
# 构造完整图像路径
image_name = os.path.join(image_path, image_name)
# 检查图像文件是否存在,如果不存在则抛出异常
if not os.path.exists(image_name):
raise Exception('txt 文件={},找不到对应的图像={}'.format(txt, image_name))

# 读取图像
image = cv2.imdecode(np.fromfile(image_name, dtype=np.uint8), cv2.IMREAD_COLOR)
# 获取图像高度和宽度
h, w = image.shape[:2]
labelme_json['imageHeight'] = h
labelme_json['imageWidth'] = w
os.makedirs(output_dir, exist_ok=True)

# 读取文本文件内容
with open(txt, 'r') as t:
lines = t.readlines()
for line in lines:
point_list = []
content = line.strip().split(' ')
if len(content) < 5:
continue # 忽略不完整的行

# 根据类别ID获取标签名称
label = class_name[int(content[0])] # 标签

# 解析点坐标 (YOLO txt为: class cx cy w h 归一化格式)
cx = float(content[1])
cy = float(content[2])
wi = float(content[3])
hi = float(content[4])

x1 = (2 * cx * w - w * wi) / 2
x2 = (w * wi + 2 * cx * w) / 2
y1 = (2 * cy * h - h * hi) / 2
y2 = (h * hi + 2 * cy * h) / 2

point_list.append(x1)
point_list.append(y1)
point_list.append(x2)
point_list.append(y2)

# 将点列表转换为二维列表,每两个值表示一个点
point_list = [point_list[i:i+2] for i in range(0, len(point_list), 2)]

# 构造shape字典 (修改为严格符合 3.16.2 版本的格式)
shape = {
'label': label,
'line_color': None, # 3.16.2 必须有的字段
'fill_color': None, # 3.16.2 必须有的字段
'points': point_list,
'shape_type': 'rectangle',
'flags': {}
# 删除了 group_id, description, mask 等新版字段
}
labelme_json['shapes'].append(shape)

# 生成JSON文件名
json_name = txt_name.split('.')[0] + '.json'
json_name_path = os.path.join(output_dir, json_name)

# 写入JSON文件
with open(json_name_path, 'w', encoding='utf-8') as fd:
json.dump(labelme_json, fd, indent=2, ensure_ascii=False)

# 输出保存信息
print("save json={}".format(json_name_path))

if __name__ == '__main__':
txt_path = 'yolo格式标签文件夹路径'
image_path ='图像文件夹路径(用于读取图像名和图像大小)'
output_dir = 'labelme标签输出文件夹路径'
# 标签列表
class_name = ['orange''apple'] # 标签类别名
convert_txt_to_labelme_json(txt_path, image_path, output_dir, class_name)