最新推送

This commit is contained in:
琉璃月光
2026-03-10 13:58:21 +08:00
parent 032479f558
commit eb16eeada3
97 changed files with 16865 additions and 670 deletions

View File

@ -0,0 +1,292 @@
<?xml version="1.0" encoding="utf-8"?>
<annotations>
<version>1.1</version>
<meta>
<task>
<id>282</id>
<name>detect12.31</name>
<size>64</size>
<mode>annotation</mode>
<overlap>0</overlap>
<bugtracker></bugtracker>
<created>2025-12-31 01:23:25.627596+00:00</created>
<updated>2025-12-31 01:50:37.361043+00:00</updated>
<subset>default</subset>
<start_frame>0</start_frame>
<stop_frame>63</stop_frame>
<frame_filter></frame_filter>
<segments>
<segment>
<id>195</id>
<start>0</start>
<stop>63</stop>
<url>http://www.xj-robot.com:9000/api/jobs/195</url>
</segment>
</segments>
<owner>
<username>huangxin</username>
<email>2193534909@qq.com</email>
</owner>
<assignee></assignee>
<labels>
<label>
<name>clamp1</name>
<color>#edb093</color>
<type>any</type>
<attributes>
</attributes>
</label>
<label>
<name>clamp0</name>
<color>#b7aa2c</color>
<type>any</type>
<attributes>
</attributes>
</label>
<label>
<name>bag</name>
<color>#ff0033</color>
<type>any</type>
<attributes>
</attributes>
</label>
<label>
<name>bag35</name>
<color>#00ff00</color>
<type>any</type>
<attributes>
</attributes>
</label>
</labels>
</task>
<dumped>2025-12-31 01:50:58.885062+00:00</dumped>
</meta>
<image id="0" name="20251113103451.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="451.30" xbr="54.10" ybr="748.27" z_order="0">
</box>
</image>
<image id="1" name="20251114144244.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1241.10" ytl="375.60" xbr="1627.70" ybr="798.70" z_order="0">
</box>
</image>
<image id="2" name="20251118172322.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.44" ytl="453.60" xbr="110.36" ybr="764.20" z_order="0">
</box>
</image>
<image id="3" name="20251120150918.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.93" ytl="449.50" xbr="138.81" ybr="759.26" z_order="0">
</box>
</image>
<image id="4" name="20251125134834.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1465.20" ytl="407.40" xbr="1791.10" ybr="729.50" z_order="0">
</box>
</image>
<image id="5" name="20251126094509.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="445.68" xbr="66.30" ybr="742.65" z_order="0">
</box>
</image>
<image id="6" name="20251204152220.jpg" width="1920" height="1080">
<box label="bag35" source="manual" occluded="0" xtl="507.10" ytl="419.30" xbr="1038.71" ybr="809.16" z_order="0">
</box>
</image>
<image id="7" name="20251204152803.jpg" width="1920" height="1080">
<box label="bag35" source="manual" occluded="0" xtl="494.46" ytl="424.40" xbr="1013.09" ybr="807.64" z_order="0">
</box>
</image>
<image id="8" name="20251205152201.jpg" width="1920" height="1080">
<box label="bag35" source="manual" occluded="0" xtl="475.76" ytl="398.23" xbr="1021.55" ybr="803.70" z_order="0">
</box>
</image>
<image id="9" name="20251205155845.jpg" width="1920" height="1080">
<box label="bag35" source="manual" occluded="0" xtl="500.30" ytl="408.06" xbr="1029.10" ybr="804.43" z_order="0">
</box>
</image>
<image id="10" name="20251205160635.jpg" width="1920" height="1080">
<box label="bag35" source="manual" occluded="0" xtl="491.49" ytl="402.80" xbr="1028.60" ybr="825.40" z_order="0">
</box>
</image>
<image id="11" name="20251205171012.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1338.20" ytl="381.20" xbr="1579.10" ybr="826.70" z_order="0">
</box>
</image>
<image id="13" name="20251206144825.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1397.10" ytl="383.10" xbr="1622.10" ybr="835.10" z_order="0">
</box>
</image>
<image id="14" name="20251206152857.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1589.40" ytl="357.00" xbr="1910.60" ybr="720.20" z_order="0">
</box>
</image>
<image id="15" name="20251206155437.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1541.90" ytl="450.40" xbr="1920.00" ybr="753.85" z_order="0">
</box>
</image>
<image id="16" name="20251206155749.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="767.73" ytl="383.15" xbr="1355.62" ybr="803.24" z_order="0">
</box>
</image>
<image id="17" name="20251206160106.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1370.00" ytl="407.40" xbr="1601.50" ybr="845.40" z_order="0">
</box>
</image>
<image id="18" name="20251206160652.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="2.96" ytl="418.93" xbr="245.27" ybr="794.64" z_order="0">
</box>
</image>
<image id="19" name="20251206165236.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1394.30" ytl="390.60" xbr="1611.80" ybr="843.50" z_order="0">
</box>
</image>
<image id="21" name="20251207112047.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1332.60" ytl="409.30" xbr="1575.40" ybr="839.80" z_order="0">
</box>
</image>
<image id="22" name="20251207112635.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1439.10" ytl="393.39" xbr="1637.00" ybr="810.80" z_order="0">
</box>
</image>
<image id="23" name="20251207113241.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="2.83" ytl="451.29" xbr="87.80" ybr="748.25" z_order="0">
</box>
</image>
<image id="24" name="20251207113739.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="843.30" ytl="349.50" xbr="1384.90" ybr="761.30" z_order="0">
</box>
<box label="bag" source="manual" occluded="0" xtl="1308.30" ytl="445.70" xbr="1651.90" ybr="822.00" z_order="0">
</box>
</image>
<image id="25" name="20251207125532.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1378.40" ytl="421.40" xbr="1603.40" ybr="837.90" z_order="0">
</box>
</image>
<image id="26" name="20251207131551.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.20" ytl="453.10" xbr="57.13" ybr="756.00" z_order="0">
</box>
</image>
<image id="27" name="20251207133134.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1395.20" ytl="411.10" xbr="1608.10" ybr="830.40" z_order="0">
</box>
</image>
<image id="29" name="20251208095901.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.23" ytl="438.40" xbr="106.46" ybr="786.55" z_order="0">
</box>
</image>
<image id="30" name="20251208111050.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="3.77" ytl="455.02" xbr="113.90" ybr="751.99" z_order="0">
</box>
</image>
<image id="31" name="20251208111456.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1233.60" ytl="395.30" xbr="1633.30" ybr="809.90" z_order="0">
</box>
</image>
<image id="32" name="20251208111840.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1375.60" ytl="406.50" xbr="1601.50" ybr="833.20" z_order="0">
</box>
</image>
<image id="33" name="20251208112750.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="4.70" ytl="455.02" xbr="74.70" ybr="751.99" z_order="0">
</box>
</image>
<image id="34" name="20251208140111.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1332.60" ytl="398.06" xbr="1574.40" ybr="825.80" z_order="0">
</box>
</image>
<image id="35" name="20251208141110.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1386.80" ytl="416.73" xbr="1618.30" ybr="828.60" z_order="0">
</box>
</image>
<image id="36" name="20251208141959.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1405.50" ytl="407.40" xbr="1627.70" ybr="829.50" z_order="0">
</box>
</image>
<image id="38" name="20251208143931.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1411.13" ytl="417.70" xbr="1632.30" ybr="829.49" z_order="0">
</box>
</image>
<image id="39" name="20251208155510.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="808.70" ytl="384.96" xbr="1367.10" ybr="776.26" z_order="0">
</box>
<box label="bag" source="manual" occluded="0" xtl="1323.29" ytl="431.20" xbr="1629.50" ybr="822.50" z_order="0">
</box>
</image>
<image id="40" name="20251208160835.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1363.03" ytl="409.75" xbr="1604.70" ybr="841.20" z_order="0">
</box>
</image>
<image id="42" name="20251209160625.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1338.75" ytl="401.34" xbr="1577.70" ybr="841.20" z_order="0">
</box>
</image>
<image id="43" name="20251212094345.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.90" ytl="423.97" xbr="69.54" ybr="788.06" z_order="0">
</box>
</image>
<image id="44" name="20251212102833.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="456.10" xbr="92.00" ybr="750.55" z_order="0">
</box>
</image>
<image id="46" name="20251212111954.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1377.16" ytl="406.77" xbr="1603.90" ybr="846.50" z_order="0">
</box>
</image>
<image id="48" name="20251212112958.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="457.10" xbr="69.60" ybr="739.40" z_order="0">
</box>
</image>
<image id="49" name="20251212125451.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.27" ytl="454.30" xbr="111.50" ybr="749.60" z_order="0">
</box>
</image>
<image id="50" name="20251212141425.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="454.30" xbr="58.40" ybr="741.24" z_order="0">
</box>
</image>
<image id="51" name="20251212152645.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1393.93" ytl="405.83" xbr="1615.10" ybr="842.80" z_order="0">
</box>
</image>
<image id="52" name="20251212155613.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="456.10" xbr="120.80" ybr="768.26" z_order="0">
</box>
</image>
<image id="53" name="20251212160246.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="453.30" xbr="81.70" ybr="756.14" z_order="0">
</box>
</image>
<image id="54" name="20251212160553.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.00" ytl="452.40" xbr="92.00" ybr="761.73" z_order="0">
</box>
</image>
<image id="55" name="20251212161201.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="868.73" ytl="399.54" xbr="1421.51" ybr="821.97" z_order="0">
</box>
</image>
<image id="56" name="20251212163016.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.39" ytl="450.79" xbr="109.99" ybr="774.78" z_order="0">
</box>
</image>
<image id="57" name="20251212163740.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1.18" ytl="443.90" xbr="387.87" ybr="821.80" z_order="0">
</box>
</image>
<image id="58" name="20251212164158.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1378.09" ytl="398.38" xbr="1599.26" ybr="810.17" z_order="0">
</box>
</image>
<image id="60" name="20251217100715.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1382.75" ytl="404.90" xbr="1609.50" ybr="816.70" z_order="0">
</box>
</image>
<image id="61" name="20251217112739.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="0.27" ytl="451.50" xbr="106.90" ybr="750.55" z_order="0">
</box>
</image>
<image id="62" name="20251217132610.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1396.72" ytl="402.11" xbr="1614.20" ybr="828.80" z_order="0">
</box>
</image>
<image id="63" name="20251217135234.jpg" width="1920" height="1080">
<box label="bag" source="manual" occluded="0" xtl="1403.24" ytl="393.72" xbr="1624.41" ybr="829.70" z_order="0">
</box>
</image>
</annotations>

View File

@ -0,0 +1,100 @@
import os
import xml.etree.ElementTree as ET
from pathlib import Path
def cvat_to_yolo_detect(xml_path, output_dir, class_name_to_id=None):
"""
将 CVAT 导出的 XML目标检测模式转换为 YOLO Detect 格式
Args:
xml_path (str): CVAT 导出的 XML 文件路径
output_dir (str): 输出 .txt 标注文件的目录
class_name_to_id (dict, optional): 类别名到 ID 的映射。
如果为 None则自动从 XML 的 <labels> 中按顺序分配0,1,2...
"""
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
tree = ET.parse(xml_path)
root = tree.getroot()
# 自动提取类别顺序(如果未提供映射)
if class_name_to_id is None:
class_name_to_id = {}
labels_elem = root.find(".//labels")
if labels_elem is not None:
for idx, label in enumerate(labels_elem.findall("label")):
name = label.find("name").text
class_name_to_id[name] = idx
else:
print("⚠️ 未找到 <labels>,请手动提供 class_name_to_id")
print(f"类别映射: {class_name_to_id}")
# 遍历所有 <image>
for image in root.findall("image"):
img_name = image.get("name")
width = int(image.get("width"))
height = int(image.get("height"))
# 构建 .txt 文件名(去掉扩展名)
stem = Path(img_name).stem
txt_path = output_dir / f"{stem}.txt"
boxes = []
for box in image.findall("box"):
label = box.get("label")
if label not in class_name_to_id:
print(f"⚠️ 未知类别 '{label}',跳过(图片: {img_name}")
continue
class_id = class_name_to_id[label]
xtl = float(box.get("xtl"))
ytl = float(box.get("ytl"))
xbr = float(box.get("xbr"))
ybr = float(box.get("ybr"))
# 转为 YOLO 格式(归一化)
x_center = (xtl + xbr) / 2 / width
y_center = (ytl + ybr) / 2 / height
w = (xbr - xtl) / width
h = (ybr - ytl) / height
# 限制在 [0,1](防止因标注误差越界)
x_center = max(0.0, min(1.0, x_center))
y_center = max(0.0, min(1.0, y_center))
w = max(0.0, min(1.0, w))
h = max(0.0, min(1.0, h))
boxes.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}")
# 写入 .txt 文件(即使无框也创建空文件)
with open(txt_path, "w") as f:
f.write("\n".join(boxes))
print(f"{img_name}{len(boxes)} 个目标")
print(f"\n🎉 转换完成YOLO 标注已保存至: {output_dir}")
if __name__ == "__main__":
# ====== 配置区 ======
XML_PATH = "annotations.xml" # 替换为你的 CVAT XML 路径
OUTPUT_LABELS_DIR = "labels" # 输出的 YOLO .txt 目录
# 方式1自动从 XML 提取类别(推荐)
#CLASS_MAP = None
# 方式2手动指定确保与训练时一致
CLASS_MAP = {
"bag": 0,
"bag35": 1,
}
# ====== 执行转换 ======
cvat_to_yolo_detect(
xml_path=XML_PATH,
output_dir=OUTPUT_LABELS_DIR,
class_name_to_id=CLASS_MAP
)

View File

@ -0,0 +1,141 @@
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
)