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.pswp.cn/web/94474.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94474.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Android] 人体细胞模拟器1.5

[Android] 人体细胞模拟器1.5 链接&#xff1a;https://pan.xunlei.com/s/VOYVUieTpjNVJq-bMys4EEDGA1?pwdm7m6# 省流:这个软件的开发者有点逆天&#xff0c;一个模拟人体器官的软件&#xff0c;细致到有血液报告&#xff0c;还缝合了生理学和病理学&#xff0c;甚至还能做切…

【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描

在网络安全管理中&#xff0c;了解网络中的设备、开放的端口以及运行的服务是至关重要的。Nmap&#xff08;Network Mapper&#xff09;是一个功能强大的开源工具&#xff0c;用于网络发现和安全审计。它可以扫描网络中的设备&#xff0c;识别开放的端口和运行的服务&#xff0…

【Linux仓库】进程的“夺舍”与“飞升”:exec 驱动的应用现代化部署流水线

&#x1f31f; 各位看官好&#xff0c;我是egoist2023&#xff01; &#x1f30d; Linux Linux is not Unix &#xff01; &#x1f680; 今天来学习exec系列的进程程序替换,从"fork"的"克隆"到"exec"的"重生"。 &#x1f44d; 如果觉…

Reachability Query

题目分析 该代码实现了一个动态集合管理系统&#xff0c;支持三种操作&#xff1a;合并集合、切换元素状态、查询集合中是否- 存在活跃元素。核心数据结构为并查集&#xff0c;结合状态标记数组和计数器。关键数据结构与函数 初始化 fa[N]&#xff1a;并查集父节点数组&#xf…

SSL移动接入方案和移动资源发布

一、SSL VPN概述SSL VPN是一种基于SSL/TLS协议的远程安全接入技术&#xff0c;因其广泛兼容Web浏览器&#xff0c;支持“无客户端”部署&#xff0c;具备易于使用和维护的特点。它通过插件系统支持非Web类TCP/UDP应用&#xff0c;并且支持对用户的访问可以做出限制&#xff0c;…

C++STL---count() 统计容器中特定元素出现次数

在 C 标准库中&#xff0c;count 是一个用于统计容器中特定元素出现次数的函数&#xff0c;定义在 <algorithm> 头文件中。它可以快速计算某个值在容器&#xff08;如数组、vector、list 等&#xff09;中出现的次数&#xff0c;避免手动编写循环计数的麻烦。 一、函数原…

Tesla自动驾驶域控制器(AutoPilot HW)的系统化梳理

目前网络上对Tesla自动驾驶硬件&#xff08;AP1-AP4、HW1.0-HW4.0&#xff09;迭代的相关介绍比较混乱&#xff0c;本文这里进行系统化梳理并澄清&#xff0c;并对一些错误进行更正。1、AutoPilot HW迭代图图1 AutoPilot HWMCU迭代图图2 AutoPilot HW 散热设计迭代图&#xff0…

C 语言:第 20 天笔记:typedef(类型重命名规则、应用场景与实战案例)

C语言&#xff1a;第20天笔记 内容提要 构造类型枚举类型typedef综合案例:斗地主预处理 构造类型&#xff1a;枚举类型 使用建议 如果定义不相干的常量&#xff0c;使用宏定义&#xff08;符号常量&#xff09;&#xff1b;如果需要定义一组相关联的常量&#xff08;如月份011、…

在 vue3 和 vue2 中,v-for 和 v-if 可以一起用吗,区别是什么

在 Vue 2 和 Vue 3 中&#xff0c;v-for 和 v-if 可以一起使用&#xff0c;但两者在处理顺序和推荐用法上存在明显区别&#xff0c;主要体现在优先级和最佳实践上&#xff1a; 1. Vue 2 中的 v-for 与 v-if优先级&#xff1a;v-for 的优先级高于 v-if。 这意味着 Vue 会先循环渲…

Linux-进程相关函数

文章目录Linux-进程相关函数父子进程关系父子进程地址空间getpid函数 获取本进程号getppid函数 获取当前进程的进程的父进程号getpgid函数 获取进程组号示例fork函数 创建进程区分父子进程exit函数 进程退出wait函数 等待子进程退出waitpid函数Linux-进程相关函数 每个进程都由…

数据挖掘 6.1 其他降维方法(不是很重要)

6.1 Other dimensionality reduction methods 6.1 其他降维方法 其他降维方法前言问题答案流形3 降维大纲3.1 线性方法3.2 非线性方法3.2.1 流形学习方法&#xff08;Manifold Learning&#xff09;3.2.2 概率方法&#xff08;Probabilistic Approaches&#xff09;3.2.3 拓扑数…

Unity中的特殊文件夹

一.工程路径获取print(Application.dataPath);只用于游戏开发编辑器模式下&#xff0c;游戏发布后此路径就不存在了二.Resources 资源文件夹//路径获取: //一般不获取 //只能使用Resources相关API进行加载 //如果硬要获取 可以用工程路径拼接print(Application.dataPath "…

Seaborn数据可视化实战:Seaborn高级使用与性能优化教程

Seaborn最佳实践与技巧 学习目标 本课程将深入探讨Seaborn库的高级使用技巧&#xff0c;包括性能优化、常见问题解决方法等&#xff0c;旨在帮助学员掌握如何高效地使用Seaborn进行数据可视化&#xff0c;提升图表的美观度和信息传达效率。 相关知识点 Seaborn最佳实践与技巧 学…

分布式系统与单机系统的优劣势对比

近期有遇到一个本地部署的需求&#xff0c;他们希望用主备方案&#xff0c;这就涉及到了备用系统怎么收费的问题。我们是单机系统&#xff0c;其他友商是分布式系统&#xff0c;那20坐席的手拨需求到底是选单机系统好&#xff0c;还是选分布式系统好呢&#xff1f;了解了两者的…

深度学习:从手写数字识别案例认识pytorch框架

目录 一、PyTorch 核心优势与框架定位 二、实战基础&#xff1a;核心库与数据准备 1. 关键库导入与功能说明 2. MNIST 数据集加载与可视化 &#xff08;1&#xff09;数据集下载与封装 &#xff08;2&#xff09;数据集可视化&#xff08;可选&#xff09; 3. DataLoade…

二分|组合|旋转数组

lc1976dijk min_pathpq. min_wlcr187同lc1823.约瑟夫环class Solution { public:int iceBreakingGame(int num, int target) {int x0;for(int i2;i<num;i){x(xtarget)%i;} return x;} };lc2972计算数组中可移除的子数组数量先找最长递增前缀&#xff0c;再结合递增后缀…

【C语言16天强化训练】从基础入门到进阶:Day 10

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

云计算与云原生技术探索

&#x1f31f; Hello&#xff0c;我是蒋星熠Jaxonic&#xff01; &#x1f308; 在浩瀚无垠的技术宇宙中&#xff0c;我是一名执着的星际旅人&#xff0c;用代码绘制探索的轨迹。 &#x1f680; 每一个算法都是我点燃的推进器&#xff0c;每一行代码都是我航行的星图。 &#x…

STM32之ADC详解

一、ADC概述 ADC&#xff08;模拟量转数字量转换器&#xff09;&#xff0c;在 STM32 开发中&#xff0c;利用 ADC 端口的电压数据&#xff0c;转换为对应的具体数字量数据内容。可通过 ADC 方式获取常用数据内容有&#xff1a; 光敏电阻、电池电量、油箱油量 ADC 转换…

深入理解计算机网络:从基础到应用的全面解析

标题&#xff1a;深入理解计算机网络&#xff1a;从基础到应用的全面解析 引言 计算机网络已经渗透到我们生活的方方面面。从家庭Wi-Fi到全球互联网&#xff0c;我们每天都在通过各种设备进行数据交换。本文将带领你走进计算机网络的世界&#xff0c;深入探讨网络的基础知识、常…