Files
zjsh_yolov11/yolo11_detect/trans_detecttocvat.py
琉璃月光 eb16eeada3 最新推送
2026-03-10 13:58:21 +08:00

142 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import xml.etree.ElementTree as ET
from pathlib import Path
def yolo_detect_to_cvat(
images_dir,
labels_dir,
output_xml,
class_id_to_name,
):
"""
将 YOLO Detect 格式转换为 CVAT XML目标检测 box
Args:
images_dir (str): 图片目录
labels_dir (str): YOLO txt 标注目录
output_xml (str): 输出 CVAT XML 路径
class_id_to_name (dict): {0: "xxx", 1: "yyy"}
"""
images_dir = Path(images_dir)
labels_dir = Path(labels_dir)
# ----------------------------
# 创建 XML 结构
# ----------------------------
annotations = ET.Element("annotations")
version = ET.SubElement(annotations, "version")
version.text = "1.1"
# labels
meta = ET.SubElement(annotations, "meta")
task = ET.SubElement(meta, "task")
labels_elem = ET.SubElement(task, "labels")
for class_id, name in class_id_to_name.items():
label = ET.SubElement(labels_elem, "label")
name_elem = ET.SubElement(label, "name")
name_elem.text = name
image_id = 0
# ----------------------------
# 遍历图片
# ----------------------------
for img_path in sorted(images_dir.iterdir()):
if img_path.suffix.lower() not in [".jpg", ".png", ".jpeg"]:
continue
import cv2
img = cv2.imread(str(img_path))
if img is None:
print(f"⚠️ 无法读取图片: {img_path}")
continue
height, width = img.shape[:2]
image_elem = ET.SubElement(
annotations,
"image",
{
"id": str(image_id),
"name": img_path.name,
"width": str(width),
"height": str(height),
}
)
label_txt = labels_dir / f"{img_path.stem}.txt"
# ----------------------------
# 有 / 无标签都要建 image
# ----------------------------
if label_txt.exists():
with open(label_txt, "r") as f:
for line in f:
line = line.strip()
if not line:
continue
class_id, xc, yc, w, h = map(float, line.split())
class_id = int(class_id)
label_name = class_id_to_name.get(class_id)
if label_name is None:
print(f"⚠️ 未知 class_id: {class_id}")
continue
# YOLO → CVAT 坐标
box_w = w * width
box_h = h * height
xtl = xc * width - box_w / 2
ytl = yc * height - box_h / 2
xbr = xtl + box_w
ybr = ytl + box_h
ET.SubElement(
image_elem,
"box",
{
"label": label_name,
"xtl": f"{xtl:.2f}",
"ytl": f"{ytl:.2f}",
"xbr": f"{xbr:.2f}",
"ybr": f"{ybr:.2f}",
"occluded": "0",
"source": "manual",
}
)
image_id += 1
print(f"{img_path.name}")
# ----------------------------
# 写 XML
# ----------------------------
tree = ET.ElementTree(annotations)
tree.write(output_xml, encoding="utf-8", xml_declaration=True)
print(f"\n🎉 转换完成CVAT XML 已生成:{output_xml}")
if __name__ == "__main__":
IMAGES_DIR = "/media/hx/04e879fa-d697-4b02-ac7e-a4148876ebb0/dataset/detect/1"
LABELS_DIR = "/media/hx/04e879fa-d697-4b02-ac7e-a4148876ebb0/dataset/detect/1"
OUTPUT_XML = "annotations.xml"
# ⚠️ 一定要和 YOLO 训练时一致
CLASS_ID_TO_NAME = {
#0: "hole",
#1: "crack"
0: "bag"
}
yolo_detect_to_cvat(
images_dir=IMAGES_DIR,
labels_dir=LABELS_DIR,
output_xml=OUTPUT_XML,
class_id_to_name=CLASS_ID_TO_NAME
)