在实例分割的训练任务中,使用的是 LabelMe 工具进行图像标注,标注文件是 json 格式,而 YOLO 训练则需要 txt 格式的标注文件。
这篇文章提供一个脚本,可以将文件夹内的 YOLO 标注文件批量转换为 JSON 格式,并将 .json 文件输出到指定目录当中。
完整代码脚本如下:
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='jpg'):
"""
将文本文件转换为LabelMe格式的JSON文件。
此函数处理文本文件中的数据,将其转换成LabelMe标注工具使用的JSON格式。包括读取图像,
解析文本文件中的标注信息,并生成相应的JSON文件。
:param txt_path: 文本文件所在的路径
:param image_path: 图像文件所在的路径
:param output_dir: 输出JSON文件的目录
:param class_name: 类别名称列表,索引对应类别ID
:param image_fmt: 图像文件格式,默认为'.jpg'
:return:
"""
# 获取所有文本文件路径
txts = glob.glob(os.path.join(txt_path, "*.txt"))
for txt in txts:
# 初始化LabelMe JSON结构
labelme_json = {
'version': '5.8.1', # labelme版本号
'flags': {},
'shapes': [],
'imagePath': None,
'imageData': None,
'imageHeight': None,
'imageWidth': None,
}
# 获取文本文件名
txt_name = os.path.basename(txt)
# 根据文本文件名生成对应的图像文件名
image_name = txt_name.split("txt")[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
# 读取文本文件内容
with open(txt, 'r') as t:
lines = t.readlines()
for line in lines:
point_list = []
content = line.split(' ')
# 根据类别ID获取标签名称
label = class_name[int(content[0])] # 标签
# 解析点坐标
for index in range(1, len(content)):
if index % 2 == 1: # 下标为奇数,对应横坐标
x = (float(content[index])) * w
point_list.append(x)
else: # 下标为偶数,对应纵坐标
y = (float(content[index])) * h
point_list.append(y)
# 将点列表转换为二维列表,每两个值表示一个点
point_list = [point_list[i:i + 2] for i in range(0, len(point_list), 2)]
# 构造shape字典
shape = {
'label': label,
'points': point_list,
'group_id': None,
'description': None,
'shape_type': 'polygon',
'flags': {},
'mask': None
}
labelme_json['shapes'].append(shape)
# 生成JSON文件名
json_name = txt_name.split('txt')[0] + 'json'
json_name_path = os.path.join(output_dir, json_name)
# 写入JSON文件
fd = open(json_name_path, 'w')
json.dump(labelme_json, fd, indent=2)
fd.close()
# 输出保存信息
print("save json={}".format(json_name_path))
if __name__ == '__main__':
txt_path = r'data/labels'
image_path = r'data/images'
output_dir = r'data/newlabels'
# 标签列表
class_name = ['person', 'car'] # 标签类别名
convert_txt_to_labelme_json(txt_path, image_path, output_dir, class_name)
1. 输入路径参数:
- txt_path: 存放 .txt 标注文件的目录。
- image_path: 对应图像文件的存放路径。
- output_dir: 转换后生成的 .json 文件保存目录。
- class_name: 类别名称列表,用于映射类别 ID 到实际标签名。
2. 获取所有 .txt 文件:
- 使用 glob.glob 获取指定路径下的所有 .txt 文件。
3. 读取对应图像信息:
- 通过 .txt 文件名匹配对应的图像文件。
- 使用 OpenCV 读取图像并解码,获取图像的高度和宽度。
4. 解析 .txt 文件内容:
- 每行数据包含一个对象的类别 ID 和归一化的多边形坐标。
- 将坐标反归一化得到实际像素值,并组织成二维点列表。
5. 构建 LabelMe JSON 格式:
- 构造符合 LabelMe 标注工具要求的 JSON 结构。
- 每个检测对象对应一个多边形标注(shape_type: 'polygon')。
6. 生成输出 .json 文件:
- 根据 .txt 文件名生成对应的 .json 文件名。
- 将构造好的 JSON 数据写入文件