C#本地,将labelme数据集转换为机器视觉yolo数据集格式
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.RegularExpressions;
using System.Text.Unicode;
using System.Threading.Tasks;
using System.Windows.Ink;
using System.Windows.Media.Media3D;
namespace WpfAppYolo11_test1
{
/// <summary>
/// 将labelme数据集转换为yolo数据集格式
/// </summary>
public class LabelmeToYoloDataSetUtils
{
Dictionary<string, short> labels = new Dictionary<string, short>();
/// <summary>
/// 转换后保存目录
/// </summary>
const string outDir = "D:\\yoloTrainDataSet";
const int saveLength = 10;
/// <summary>
/// labelme转yolo格式数据,要转换的目录
/// </summary>
/// <param name="inputDir"></param>
/// 2025-3-4 00:45:38,
public void FileConvert(string inputDir)
{
//labels.Clear();
var files = System.IO.Directory.GetFiles(inputDir, "*.json");
if (files == null || files.Length == 0)
{
return;
}
//获取目录中文件夹,以数字升序命名最新的训练文件夹
var folders = Directory.GetDirectories(outDir);
int lastNum = 1;
if (folders != null && folders.Length > 0)
{
List<DirectoryInfo> dirList = new List<DirectoryInfo>();
foreach (var item in folders)
{
DirectoryInfo directoryInfo = new DirectoryInfo(item);
dirList.Add(directoryInfo);
}
var lastDir = dirList.OrderByDescending(g => g.CreationTime).FirstOrDefault();
//获取文件夹后缀
var lastNumStr = Regex.Match(lastDir.Name, "\\d*$").Value;
lastNum = Convert.ToInt32(lastNumStr) + 1;
}
//此次训练保存的文件夹
string newTrainDir = "train" + lastNum;
//string dirNew = "train" + Guid.NewGuid().ToString("n");
string dirNew = outDir + "\\" + newTrainDir + "\\train";
//处理json文件
foreach (var item in files)
{
//处理单个json文件
SingleFileConvert(item, dirNew);
}
//挑选训练图片前两个图片作为验证集
//创建val文件夹
string val = Path.Combine(outDir, newTrainDir, "val");
var files21 = System.IO.Directory.GetFiles(inputDir, "*.jpg");
var files22 = System.IO.Directory.GetFiles(inputDir, "*.png");
var fileContainer = files21.Union(files22).ToList();
var first1 = fileContainer[0];
var first2 = fileContainer[1];
//将训练图片全部复制到train中
var trainImgNew = Path.Combine(dirNew, "images");
if (!Directory.Exists(trainImgNew))
{
Directory.CreateDirectory(trainImgNew);
}
foreach (var itemImg in fileContainer)
{
string fileNew2 = Path.Combine(trainImgNew, Path.GetFileName(itemImg));
File.Copy(itemImg, fileNew2);
}
//只有2个样本时,将训练的文件夹作为验证
if (files.Length <= 2)
{
val = dirNew;
goto Val_done;
}
if (!Directory.Exists(val))
{
Directory.CreateDirectory(val);
}
//图片文件夹
string valImage = Path.Combine(val, "images");
if (!Directory.Exists(valImage))
{
Directory.CreateDirectory(valImage);
}
string file1Name = Path.GetFileName(first1);
string file2Name = Path.GetFileName(first2);
string img1 = Path.Combine(valImage, file1Name);
File.Copy(first1, img1);
string img2 = Path.Combine(valImage, file2Name);
File.Copy(first2, img2);
//坐标数据
string vallabels = Path.Combine(val, "labels");
if (!Directory.Exists(vallabels))
{
Directory.CreateDirectory(vallabels);
}
//找到train目录中的坐标数据
string vallabels2 = Path.Combine(dirNew, "labels");
string txt1 = Path.GetFileNameWithoutExtension(file1Name) + ".txt";
string txt2 = Path.GetFileNameWithoutExtension(file2Name) + ".txt";
string fileLabel1 = Path.Combine(vallabels2, txt1);
string fileLabel2 = Path.Combine(vallabels2, txt2);
if (File.Exists(fileLabel1))
{
string fileLabelTxt1 = Path.Combine(vallabels, txt1);
File.Copy(fileLabel1, fileLabelTxt1);
}
if (File.Exists(fileLabel2))
{
string fileLabelTxt2 = Path.Combine(vallabels, txt2);
File.Copy(fileLabel2, fileLabelTxt2);
}
Val_done:
//生成data.yaml
string dir = dirNew;//Path.Combine(outDir, newTrainDir);
dir = dir.Replace("\\", "/");
val = val.Replace("\\", "/");
StringBuilder sb = new StringBuilder();
sb.AppendLine("train: " + dir);
sb.AppendLine("val: " + val);
sb.AppendLine("test: " + val);
sb.AppendLine("");
sb.AppendLine("nc: " + labels.Count);
//设置编码支持中文
string labelName = System.Text.Json.JsonSerializer.Serialize(labels.Keys,
new System.Text.Json.JsonSerializerOptions()
{
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
}
);
labelName = labelName.Replace("\"", "'");//替换双引号为单引号
sb.AppendLine("names: " + labelName);
//保存
//var arr = inputDir.Split("\\");
//var lastDir = arr.Last();
//string newDir = inputDir.TrimEnd(lastDir.ToArray());
//string filePath = Path.Combine(newDir, "yoloTrainDataSet", "data.yaml");
string yamlDir = outDir + "\\" + newTrainDir;
string filePath = Path.Combine(yamlDir, "data.yaml");
System.IO.File.WriteAllText(filePath, sb.ToString());
}
/// <summary>
/// 单个json文件转换
/// </summary>
public void SingleFileConvert(string file, string inputDir)
{
string json = System.IO.File.ReadAllText(file);
var data2 = System.Text.Json.JsonSerializer.Deserialize<LabelMeView>(json);
if (data2 == null || data2.shapes == null || data2.shapes.Count == 0)
{
return;
}
StringBuilder stringBuilder = new StringBuilder();
//读取每个形状
foreach (var item in data2.shapes)
{
//忽略没名称的形状
if (string.IsNullOrEmpty(item.label))
{
continue;
}
labels.TryAdd(item.label, 1);
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (item.shape_type == "rectangle")
{
x1 = item.points[0][0];
y1 = item.points[0][1];
x2 = item.points[1][0];
y2 = item.points[1][1];
}
else if (item.shape_type == "polygon")
{
x1 = item.points.Select(g => g[0]).Min();
y1 = item.points.Select(g => g[1]).Min();
x2 = item.points.Select(g => g[0]).Max();
y2 = item.points.Select(g => g[1]).Max();
}
//中心点
double x_center = (x1 + x2) / (double)2 / data2.imageWidth;
double y_center = (y1 + y2) / (double)2 / data2.imageHeight;
double width = Math.Abs((x2 - x1) / data2.imageWidth);
double height = Math.Abs((y2 - y1) / data2.imageHeight);
//获取对象id
int classId = labels.Keys.ToList().IndexOf(item.label);
stringBuilder.AppendLine($"{classId} {x_center} {y_center} {width} {height}");
}
//保存txt文件
//var arr = inputDir.Split("\\");
//var lastDir = arr.Last();
//string newDir = inputDir.TrimEnd(lastDir.ToArray());
// string dir = System.IO.Path.Combine( outDir, "labels");
string dir = System.IO.Path.Combine(inputDir, "labels");
if (!System.IO.Directory.Exists(dir))
{
System.IO.Directory.CreateDirectory(dir);
}
//string fileName = Path.GetFileName(file) + "_" + Guid.NewGuid().ToString("n") + ".txt";
string fileName = Path.GetFileNameWithoutExtension(file) + ".txt";
string filePath = System.IO.Path.Combine(dir, fileName);
File.WriteAllText(filePath, stringBuilder.ToString());
}
}
public class LabelMeView
{
public string version { get; set; }
public List<ShapeView> shapes { get; set; }
public string imagePath { get; set; }
/// <summary>
/// 图片高度,px
/// </summary>
public int imageHeight { get; set; }
/// <summary>
/// 图片宽度,px
/// </summary>
public int imageWidth { get; set; }
}
public class ShapeView
{
/// <summary>
/// 对象说明,标签
/// </summary>
public string label { get; set; }
/// <summary>
/// 形状描述;rectangle;polygon
/// </summary>
public string shape_type { get; set; }
public object flags { get; set; }
/// <summary>
/// 坐标点
/// </summary>
public List<double[]> points { get; set; }
public string version { get; set; }
}
}