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

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.dtcms.com/a/342141.html

相关文章:

  • 关于CentOS7无法使用使用
  • 在Java项目中去理解通用工具为什么能通用,以及如何写出类似的工具类
  • 实践题:智能化风控体系升级方案
  • 医疗器械注册证识别技术:实现从图像到结构化数据的智能转化,提升行业效率与准确性
  • 深度解析游戏引擎中的相机:视图矩阵
  • 【数据结构】深入解析选择排序与堆排序:从基础到高效实现的完全指南
  • 如何在Docker配置中启用实验性模式
  • 对实验室管理而言,LIMS系统究竟有无作用
  • 【STM32】HAL库中的实现(八):I2C通信(以 AT24C02 为例)
  • CentOS系统安装Git全攻略
  • 面试准备革命:面试汪 vs 传统方法,谁更胜一筹?
  • 「数据获取」《中国环境统计年鉴》(1998-2024)(获取方式看绑定的资源)
  • Linux命令大全-userdel命令
  • awk 命令的使用
  • 《P2700 逐个击破》
  • Design Compiler:逻辑库名与逻辑库文件名及其指定方式
  • 自学嵌入式第二十四天:数据结构(4)-栈
  • JetBrains Mono字体
  • Django ModelForm
  • 用 Python 写的自动化测试 WPF 程序的一个案例
  • Jmeter接口测试之文件上传
  • XXL-Job REST API 工具类完全解析:简化分布式任务调度集成
  • WebSocket和跨域问题
  • Android为ijkplayer设置音频发音类型usage
  • 如何用 SolveigMM Video Splitter 从视频中提取 AAC 音频
  • CMake3: CMake的嵌套使用与自定义库
  • Spring Event 企业级应用
  • 笔试——Day45
  • Prompt魔法:提示词工程与ChatGPT行业应用读书笔记:提示词设计全能指南
  • 第四章:大模型(LLM)】07.Prompt工程-(7)角色提示