C# 编写一个XmlToDota的转换工具

以下代码可以将Labelme标注的旋转框Xml格式文件转换为Yolo标注格式的txt文件,以便用Yolo OBB训练自己的数据集:

using System;

using System.Collections.Generic;

using System.IO;

using System.Xml;

using System.Linq;

using System.Globalization;

namespace XmlToDotaConverter

{

class Program

{

static readonly List<string> clsList = new List<string> { "Hole1", "Hole2" };

static void Main(string\[\] args)

{

string roxmlPath = @"C:\BAN\orgin-xml";

string dotaxmlPath = @"C:\BAN\new-xml";

string outPath = @"C:\BAN\out-txt";

// 创建输出目录

Directory.CreateDirectory(dotaxmlPath);

Directory.CreateDirectory(outPath);

// 第一步:转换XML格式

var xmlFiles = Directory.GetFiles(roxmlPath, "*.xml");

foreach (var xmlFile in xmlFiles)

{

string outputXml = Path.Combine(dotaxmlPath, Path.GetFileName(xmlFile));

EditXml(xmlFile, outputXml);

}

// 第二步:转换为TXT格式

ToTxt(dotaxmlPath, outPath);

}

static void EditXml(string xmlFile, string dotaxmlFile)

{

XmlDocument doc = new XmlDocument();

doc.Load(xmlFile);

XmlNodeList objectNodes = doc.SelectNodes("//object");

foreach (XmlNode objNode in objectNodes)

{

XmlNode bndbox = objNode.SelectSingleNode("bndbox");

XmlNode robndbox = objNode.SelectSingleNode("robndbox");

// 处理普通矩形框

if (robndbox == null && bndbox != null)

{

ConvertRectangleBox(bndbox);

}

// 处理旋转矩形框

else if (robndbox != null)

{

ConvertRotatedBox(objNode, robndbox);

}

}

// 保存修改后的XML

doc.Save(dotaxmlFile);

}

static void ConvertRectangleBox(XmlNode bndbox)

{

double xmin = Math.Max(GetDoubleValue(bndbox, "xmin"), 0);

double ymin = Math.Max(GetDoubleValue(bndbox, "ymin"), 0);

double xmax = Math.Max(GetDoubleValue(bndbox, "xmax"), 0);

double ymax = Math.Max(GetDoubleValue(bndbox, "ymax"), 0);

// 移除旧节点

RemoveChildNodes(bndbox);

// 添加四个角点坐标

AddPoint(bndbox, "x0", xmin.ToString());

AddPoint(bndbox, "y0", ymax.ToString());

AddPoint(bndbox, "x1", xmax.ToString());

AddPoint(bndbox, "y1", ymax.ToString());

AddPoint(bndbox, "x2", xmax.ToString());

AddPoint(bndbox, "y2", ymin.ToString());

AddPoint(bndbox, "x3", xmin.ToString());

AddPoint(bndbox, "y3", ymin.ToString());

}

static void ConvertRotatedBox(XmlNode objNode, XmlNode robndbox)

{

// 将robndbox重命名为bndbox

XmlNode bndbox = objNode.OwnerDocument.CreateElement("bndbox");

objNode.ReplaceChild(bndbox, robndbox);

double cx = GetDoubleValue(robndbox, "cx");

double cy = GetDoubleValue(robndbox, "cy");

double w = GetDoubleValue(robndbox, "w");

double h = GetDoubleValue(robndbox, "h");

double angle = GetDoubleValue(robndbox, "angle");

// 计算旋转后的四个角点

var p0 = RotatePoint(cx, cy, cx - w / 2, cy - h / 2, -angle);

var p1 = RotatePoint(cx, cy, cx + w / 2, cy - h / 2, -angle);

var p2 = RotatePoint(cx, cy, cx + w / 2, cy + h / 2, -angle);

var p3 = RotatePoint(cx, cy, cx - w / 2, cy + h / 2, -angle);

// 添加四个角点坐标

AddPoint(bndbox, "x0", p0.X.ToString());

AddPoint(bndbox, "y0", p0.Y.ToString());

AddPoint(bndbox, "x1", p1.X.ToString());

AddPoint(bndbox, "y1", p1.Y.ToString());

AddPoint(bndbox, "x2", p2.X.ToString());

AddPoint(bndbox, "y2", p2.Y.ToString());

AddPoint(bndbox, "x3", p3.X.ToString());

AddPoint(bndbox, "y3", p3.Y.ToString());

}

static (int X, int Y) RotatePoint(double cx, double cy, double xp, double yp, double theta)

{

double xoff = xp - cx;

double yoff = yp - cy;

double cosTheta = Math.Cos(theta);

double sinTheta = Math.Sin(theta);

double pResx = cosTheta * xoff + sinTheta * yoff;

double pResy = -sinTheta * xoff + cosTheta * yoff;

return ((int)(cx + pResx), (int)(cy + pResy));

}

static void ToTxt(string xmlPath, string outPath)

{

foreach (string xmlFile in Directory.GetFiles(xmlPath, "*.xml"))

{

string fileName = Path.GetFileNameWithoutExtension(xmlFile);

string txtPath = Path.Combine(outPath, fileName + ".txt");

XmlDocument doc = new XmlDocument();

doc.Load(xmlFile);

using StreamWriter writer = new StreamWriter(txtPath);

foreach (XmlNode objNode in doc.SelectNodes("//object"))

{

string cls = objNode.SelectSingleNode("name").InnerText;

XmlNode bndbox = objNode.SelectSingleNode("bndbox");

int\[\] points = new int8;

points0 = Math.Max((int)GetDoubleValue(bndbox, "x0"), 0);

points1 = Math.Max((int)GetDoubleValue(bndbox, "y0"), 0);

points2 = Math.Max((int)GetDoubleValue(bndbox, "x1"), 0);

points3 = Math.Max((int)GetDoubleValue(bndbox, "y1"), 0);

points4 = Math.Max((int)GetDoubleValue(bndbox, "x2"), 0);

points5 = Math.Max((int)GetDoubleValue(bndbox, "y2"), 0);

points6 = Math.Max((int)GetDoubleValue(bndbox, "x3"), 0);

points7 = Math.Max((int)GetDoubleValue(bndbox, "y3"), 0);

int clsIndex = clsList.IndexOf(cls);

if (clsIndex == -1) continue;

writer.WriteLine($"{points0} {points1} {points2} {points3} " +

$"{points4} {points5} {points6} {points7} " +

$"{cls} {clsIndex}");

}

}

}

#region Helper Methods

static double GetDoubleValue(XmlNode parent, string nodeName)

{

return double.Parse(parent.SelectSingleNode(nodeName).InnerText,

CultureInfo.InvariantCulture);

}

static void RemoveChildNodes(XmlNode node)

{

while (node.HasChildNodes)

{

node.RemoveChild(node.FirstChild);

}

}

static void AddPoint(XmlNode parent, string name, string value)

{

XmlElement elem = parent.OwnerDocument.CreateElement(name);

elem.InnerText = value;

parent.AppendChild(elem);

}

#endregion

}

}

相关推荐
SilentSamsara17 小时前
高并发 API 压测与调优:locust + 火焰图 + 瓶颈定位
开发语言·python·青少年编程·docker·中间件
决战灬17 小时前
llamaIndex BatchEvalRunner(一)
人工智能
fl17683117 小时前
智慧医疗腹腔断层CT脏器识别分割数据集labelme格式1030张4类别
人工智能
数智工坊17 小时前
周志华《Machine Learning》学习笔记--第七章--贝叶斯分类器
人工智能·笔记·神经网络·学习·机器学习
myenjoy_117 小时前
开源!Go+Wails+Vue3 手搓一个 PLC 实时监控桌面工具
开发语言·golang·开源
MartinYeung517 小时前
[论文学习]使用全同态加密实现实用隐私保护机器学习训练
人工智能·学习
财经资讯数据_灵砚智能17 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年6月4日
人工智能·python·ai·信息可视化·自然语言处理·ai编程·灵砚智能
侃谈科技圈18 小时前
2026免费AI自动抠图工具汇总:全平台+电脑在线全方案,无水印零套路
人工智能
apcipot_rain18 小时前
计科八股20260604——AI安全、K-means、SVM、nano
人工智能·神经网络·安全·支持向量机·kmeans
Flash.kkl18 小时前
C++基于websocketpp的多用户网页五子棋项目
开发语言·网络·数据库·c++·websocket·mysql