当前位置: 首页 > backend >正文

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 int[8];
points[0] = Math.Max((int)GetDoubleValue(bndbox, "x0"), 0);
points[1] = Math.Max((int)GetDoubleValue(bndbox, "y0"), 0);
points[2] = Math.Max((int)GetDoubleValue(bndbox, "x1"), 0);
points[3] = Math.Max((int)GetDoubleValue(bndbox, "y1"), 0);
points[4] = Math.Max((int)GetDoubleValue(bndbox, "x2"), 0);
points[5] = Math.Max((int)GetDoubleValue(bndbox, "y2"), 0);
points[6] = Math.Max((int)GetDoubleValue(bndbox, "x3"), 0);
points[7] = Math.Max((int)GetDoubleValue(bndbox, "y3"), 0);

                    int clsIndex = clsList.IndexOf(cls);
if (clsIndex == -1) continue;

                    writer.WriteLine($"{points[0]} {points[1]} {points[2]} {points[3]} " +
$"{points[4]} {points[5]} {points[6]} {points[7]} " +
$"{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
}
}

http://www.xdnf.cn/news/18302.html

相关文章:

  • Seaborn数据可视化实战:Seaborn入门-环境搭建与基础操作
  • [ Servlet 服务器]
  • electron-vite_18Less和Sass共用样式指定
  • 基于混合注意力网络和深度信念网络的鲁棒视频水印技术基础理论深度解析
  • AI设计师-标小智旗下AI在线设计平台
  • [论文阅读] 人工智能 + 软件工程 | 当AI成为文学研究员:Agentic DraCor如何用MCP解锁戏剧数据分析
  • 设计模式之观察者模式
  • 为什么可以kvcache
  • 订单簿数据深度学习方法在大单发现应用
  • 微信小程序集成vant-weapp时,构建npm报错的解决办法
  • 深度学习-计算机视觉-物体检测与边缘框实现
  • 区块链联邦学习思路一
  • 机器学习两大核心算法:集成学习与 K-Means 聚类详解
  • 如何保证数据库和缓存的一致性?
  • Java设计模式-模板方法模式
  • 常见开源协议详解:哪些行为被允许?哪些被限制?
  • B站 韩顺平 笔记 (Day 24)
  • K8S-Secret资源对象
  • 学习数组①
  • 1.Shell脚本修炼手册之---为什么要学Shell编程?
  • 【MySQL的卸载】
  • 读《精益数据分析》:规模化(Scale)—— 复制成功,进军新市场
  • PiscCode集成Hand Landmarker:实现高精度手部姿态检测与分析
  • JVM面试精选 20 题(终)
  • 【北京迅为】iTOP-4412精英版使用手册-第三十二章 网络通信-TCP套字节
  • 30.Linux cobbler自动化部署
  • 基于51单片机自动浇花1602液晶显示设计
  • STM32_0001 KEILMDK V5.36 编译一个STM32F103C8T6说core_cm3.h文件找不到以及编译器版本不匹配的解决办法
  • 多模型创意视频生成平台
  • 设计模式1-单例模式