先把用到的记录一下。
- labelme格式是json格式,标签类型和坐标记录在一起,坐标是像素坐标
- yolo格式是txt格式,只用数字记录,标签类型用标号,坐标使用归一化坐标;另外有一个classes.txt保存标签类型,前面提到的标号就是在这里对应的。
包括根目录的文件目录结构:
E:/yolov8/20240624/escala/ # 根目录
images/ # 存放图片数据集
test/
train/
val/
labels/ # 存放原先的yolo标注
test/
train/
val/
train/classes.txt
labelmes/ # 存放生成的labelme标注
test/
train/
val/
yolo转labelme:
import os
import json
from PIL import Image
# 基本路径
base_path = "E:/yolov8/20240624/escala/"
image_dirs = ["images/test", "images/train", "images/val"]
label_dirs = ["labels/test", "labels/train", "labels/val"]
output_dir = "labelmes/"
# 读取类别文件
classes_path = os.path.join(base_path, "labels/train/classes.txt")
with open(classes_path, 'r') as f:
classes = f.read().strip().split('\n')
# 创建输出目录
for dir_name in image_dirs:
os.makedirs(os.path.join(base_path, output_dir, os.path.basename(dir_name)), exist_ok=True)
# 遍历所有图片目录
for image_dir, label_dir in zip(image_dirs, label_dirs):
image_dir_path = os.path.join(base_path, image_dir)
label_dir_path = os.path.join(base_path, label_dir)
output_dir_path = os.path.join(base_path, output_dir, os.path.basename(image_dir))
for image_file in os.listdir(image_dir_path):
if image_file.endswith('.jpg'):
image_path = os.path.join(image_dir_path, image_file)
yolo_anno_path = os.path.join(label_dir_path, os.path.splitext(image_file)[0] + '.txt')
output_anno_path = os.path.join(output_dir_path, os.path.splitext(image_file)[0] + '.json')
# 读取图片尺寸
image = Image.open(image_path)
img_width, img_height = image.size
# 读取YOLOv8标注文件,如果文件不存在则跳过
if not os.path.exists(yolo_anno_path):
print(f"No annotation file for {image_file}, skipping...")
continue
with open(yolo_anno_path, 'r') as f:
yolo_annotations = f.read().strip().split('\n')
# 计算图片的相对路径,相对于输出目录
relative_image_path = os.path.relpath(image_path, output_dir_path)
# YOLOv8到LabelMe格式的转换
labelme_annotations = {
"version": "5.5.0",
"flags": {},
"shapes": [],
"imagePath": relative_image_path,
"imageData": None,
"imageHeight": img_height,
"imageWidth": img_width
}
for anno in yolo_annotations:
class_id, x_center, y_center, width, height = map(float, anno.split())
class_name = classes[int(class_id)]
# YOLOv8的中心点和宽高转换为LabelMe的四个点
x_min = (x_center - width / 2) * img_width
y_min = (y_center - height / 2) * img_height
x_max = (x_center + width / 2) * img_width
y_max = (y_center + height / 2) * img_height
shape = {
"label": class_name,
"points": [
[x_min, y_min],
[x_max, y_min],
[x_max, y_max],
[x_min, y_max]
],
"group_id": None,
"shape_type": "polygon",
"flags": {}
}
labelme_annotations["shapes"].append(shape)
# 保存为LabelMe格式的JSON文件
with open(output_anno_path, 'w') as f:
json.dump(labelme_annotations, f, indent=4)
print(f"YOLOv8 annotations for {image_file} have been converted to LabelMe format and saved to {output_anno_path}")
labelme转yolo:
import os
import json
# 基本路径
base_path = "E:/yolov8/20240624/escala/"
image_dirs = ["images/test", "images/train", "images/val"]
label_dirs = ["labelmes/test", "labelmes/train", "labelmes/val"]
output_base_dir = "me2yolo/"
# 创建输出目录
for dir_name in image_dirs:
os.makedirs(os.path.join(base_path, output_base_dir, os.path.basename(dir_name)), exist_ok=True)
# 遍历所有图片目录
for image_dir, label_dir in zip(image_dirs, label_dirs):
image_dir_path = os.path.join(base_path, image_dir)
label_dir_path = os.path.join(base_path, label_dir)
output_dir_path = os.path.join(base_path, output_base_dir, os.path.basename(image_dir))
classes_set = set()
# 第一步,收集所有标签名称
for image_file in os.listdir(image_dir_path):
if image_file.endswith('.jpg'):
labelme_anno_path = os.path.join(label_dir_path, os.path.splitext(image_file)[0] + '.json')
if not os.path.exists(labelme_anno_path):
continue
with open(labelme_anno_path, 'r') as f:
labelme_annotations = json.load(f)
for shape in labelme_annotations["shapes"]:
class_name = shape["label"]
classes_set.add(class_name)
sorted_classes = sorted(classes_set)
class_name_to_id = {class_name: idx for idx, class_name in enumerate(sorted_classes)}
# 保存类别文件
classes_path = os.path.join(output_dir_path, "classes.txt")
with open(classes_path, 'w') as f:
f.write('\n'.join(sorted_classes))
print(f"Classes file saved to {classes_path}")
# 第二步,转换标注文件
for image_file in os.listdir(image_dir_path):
if image_file.endswith('.jpg'):
image_path = os.path.join(image_dir_path, image_file)
labelme_anno_path = os.path.join(label_dir_path, os.path.splitext(image_file)[0] + '.json')
yolo_anno_path = os.path.join(output_dir_path, os.path.splitext(image_file)[0] + '.txt')
if not os.path.exists(labelme_anno_path):
print(f"No annotation file for {image_file}, skipping...")
continue
with open(labelme_anno_path, 'r') as f:
labelme_annotations = json.load(f)
img_width = labelme_annotations["imageWidth"]
img_height = labelme_annotations["imageHeight"]
yolo_annotations = []
for shape in labelme_annotations["shapes"]:
class_name = shape["label"]
points = shape["points"]
x_min = min(points, key=lambda p: p[0])[0]
y_min = min(points, key=lambda p: p[1])[1]
x_max = max(points, key=lambda p: p[0])[0]
y_max = max(points, key=lambda p: p[1])[1]
x_center = (x_min + x_max) / 2 / img_width
y_center = (y_min + y_max) / 2 / img_height
width = (x_max - x_min) / img_width
height = (y_max - y_min) / img_height
class_id = class_name_to_id[class_name]
yolo_annotations.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
# 保存为YOLO格式的txt文件
with open(yolo_anno_path, 'w') as f:
f.write('\n'.join(yolo_annotations))
print(f"LabelMe annotations for {image_file} have been converted to YOLO format and saved to {yolo_anno_path}")
@ 1313