mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-08 11:57:53 +08:00
157 lines
8.2 KiB
C#
157 lines
8.2 KiB
C#
using System.Diagnostics;
|
|
using System.IO;
|
|
using OpenCvSharp;
|
|
|
|
namespace BetterGenshinImpact.Test.Dataset;
|
|
|
|
public class AvatarClassifyGen
|
|
{
|
|
// 基础图像文件夹
|
|
private const string BaseDir = @"E:\HuiTask\更好的原神\自动秘境\自动战斗\队伍识别\分类器\";
|
|
|
|
// 背景图像文件夹
|
|
private static readonly string BackgroundDir = Path.Combine(BaseDir, "background");
|
|
|
|
private static readonly Random Rd = new Random();
|
|
|
|
public static void GenAll()
|
|
{
|
|
// 读取基础图像
|
|
// List<string> sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "*.png", SearchOption.TopDirectoryOnly).ToList();
|
|
// 只用一个图像
|
|
List<string> sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_HutaoCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList();
|
|
List<string> sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Iansan.png", SearchOption.TopDirectoryOnly).ToList();
|
|
sideImageFiles.AddRange(sideImageFiles2);
|
|
List<string> sideImageFiles3 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Citlali.png", SearchOption.TopDirectoryOnly).ToList();
|
|
sideImageFiles.AddRange(sideImageFiles3);
|
|
List<string> sideImageFiles4 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Lanyan.png", SearchOption.TopDirectoryOnly).ToList();
|
|
sideImageFiles.AddRange(sideImageFiles4);
|
|
List<string> sideImageFiles5 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_XianglingCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList();
|
|
sideImageFiles.AddRange(sideImageFiles5);
|
|
List<string> sideImageFiles6 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Mavuika.png", SearchOption.TopDirectoryOnly).ToList();
|
|
sideImageFiles.AddRange(sideImageFiles6);
|
|
|
|
// 生成训练集
|
|
GenTo(sideImageFiles, Path.Combine(BaseDir, @"dateset\train"), 200);
|
|
// 生成测试集
|
|
GenTo(sideImageFiles, Path.Combine(BaseDir, @"dateset\test"), 40);
|
|
// GenTo(new List<string> { sideImageFiles[1] }, Path.Combine(BaseDir, @"dateset\test"), 1);
|
|
}
|
|
|
|
static void GenTo(List<string> sideImageFiles, string dataFolder, int count)
|
|
{
|
|
// 保留区域 从底边中心为固定点
|
|
var reservedSize = new Size(60, 80);
|
|
|
|
Directory.CreateDirectory(dataFolder);
|
|
// 循环生成每个基础图像对应的数据集
|
|
foreach (string sideImageFile in sideImageFiles)
|
|
{
|
|
// 获取基础图像文件名
|
|
string sideImageFileName = Path.GetFileNameWithoutExtension(sideImageFile);
|
|
sideImageFileName = sideImageFileName.Replace("UI_AvatarIcon_Side_", "");
|
|
// 创建基础图像对应的数据集文件夹
|
|
string sideDataFolder = Path.Combine(dataFolder, sideImageFileName);
|
|
Directory.CreateDirectory(sideDataFolder);
|
|
|
|
// 读取基础图像
|
|
Mat sideImageSrc = Cv2.ImRead(sideImageFile, ImreadModes.Unchanged);
|
|
var channels = sideImageSrc.Split();
|
|
var alphaChannel = channels[3]; // 透明通道
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
Cv2.Multiply(channels[i], alphaChannel, channels[i], 1 / 255.0);
|
|
}
|
|
|
|
var sideImage = new Mat();
|
|
Cv2.Merge(channels[..3], sideImage);
|
|
|
|
// Cv2.ImShow("avatar", sideImage);
|
|
|
|
// 循环生成图像
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
// 随机挑选一张背景图像
|
|
string backgroundImageFile = Path.Combine(BackgroundDir, Directory.GetFiles(BackgroundDir, "*.png")[Rd.Next(Directory.GetFiles(BackgroundDir, "*.png").Length)]);
|
|
|
|
// 从背景图像中随机取一块 128x128 的区域
|
|
Mat backgroundImage = Cv2.ImRead(backgroundImageFile, ImreadModes.Color);
|
|
Rect backgroundRect = new Rect(Rd.Next(backgroundImage.Width - 128), new Random().Next(backgroundImage.Height - 128), 128, 128);
|
|
Mat backgroundImageRegion = backgroundImage[backgroundRect];
|
|
|
|
// 随机平移、缩放保留区域
|
|
float scale = (float)(Rd.NextDouble() * (1.6 - 0.7) + 0.7);
|
|
int w = (int)(sideImage.Width * scale);
|
|
int h = (int)(sideImage.Height * scale);
|
|
|
|
Debug.WriteLine($"{sideImageFileName} 生成随机缩放{scale}");
|
|
|
|
// 把保留区域合成到背景图像上
|
|
Mat backgroundImageRegionClone = backgroundImageRegion.Clone();
|
|
var resizedSideImage = new Mat();
|
|
Cv2.Resize(sideImage, resizedSideImage, new Size(128 * scale, 128 * scale));
|
|
// Cv2.ImShow("resizedSideImage", resizedSideImage);
|
|
var resizedMaskImage = new Mat();
|
|
// Cv2.Threshold(alphaChannel, alphaChannel, 200, 255, ThresholdTypes.Otsu);
|
|
Cv2.Resize(255 - alphaChannel, resizedMaskImage, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic);
|
|
var resizedAlphaChannel = new Mat();
|
|
Cv2.Resize(alphaChannel, resizedAlphaChannel, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic);
|
|
|
|
// Cv2.ImShow("resizedMaskImage", resizedMaskImage);
|
|
// generatedImage[transformedRect] = resizedSideImage;
|
|
Mat result;
|
|
if (scale > 1)
|
|
{
|
|
int xSpace1 = (int)((128 - reservedSize.Width * scale) / 2.0);
|
|
int ySpace1 = (int)(128 - reservedSize.Height * scale);
|
|
int xSpace2 = (int)((resizedSideImage.Width - 128) / 2.0);
|
|
int ySpace2 = resizedSideImage.Height - 128;
|
|
int xSpace = Math.Min(xSpace1, xSpace2);
|
|
int ySpace = Math.Min(ySpace1, ySpace2);
|
|
int offsetX = Rd.Next(-xSpace, xSpace);
|
|
int offsetY = Rd.Next(-ySpace, 0);
|
|
Debug.WriteLine($"{sideImageFileName} 缩放{scale}大于1 偏移 ({offsetX},{offsetY})");
|
|
|
|
var roi = new Rect((resizedSideImage.Width - 128) / 2 + offsetX, (resizedSideImage.Height - 128) + offsetY, 128, 128);
|
|
// result = new Mat();
|
|
// Cv2.BitwiseAnd(backgroundImageRegionClone, backgroundImageRegionClone, result, resizedMaskImage[roi]);
|
|
result = Mul(backgroundImageRegionClone, resizedAlphaChannel[roi]);
|
|
Cv2.Add(result, resizedSideImage[roi], result);
|
|
}
|
|
else
|
|
{
|
|
int xSpace = (128 - w) / 2;
|
|
int ySpace = 128 - h;
|
|
int offsetX = Rd.Next(-xSpace, xSpace);
|
|
int offsetY = Rd.Next(-ySpace, 0);
|
|
Debug.WriteLine($"{sideImageFileName} 缩放{scale}小于等于1 偏移 ({offsetX},{offsetY})");
|
|
|
|
var roi = new Rect((128 - resizedSideImage.Width) / 2 + offsetX, (128 - resizedSideImage.Height) + offsetY, resizedSideImage.Width, resizedSideImage.Height);
|
|
var res = new Mat();
|
|
// Cv2.BitwiseAnd(backgroundImageRegionClone[roi], backgroundImageRegionClone[roi], res, resizedMaskImage);
|
|
res = Mul(backgroundImageRegionClone[roi], resizedAlphaChannel);
|
|
Cv2.Add(res, resizedSideImage, res);
|
|
backgroundImageRegionClone[roi] = res;
|
|
result = backgroundImageRegionClone.Clone();
|
|
}
|
|
|
|
// Cv2.ImShow("avatarR", result);
|
|
// 保存生成的图像
|
|
Cv2.ImWrite(Path.Combine(sideDataFolder, $"{sideImageFileName}_{i}.png"), result);
|
|
}
|
|
}
|
|
|
|
static Mat Mul(Mat background, Mat alphaChannel)
|
|
{
|
|
var channels = background.Split();
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
Cv2.Multiply(channels[i], 255 - alphaChannel, channels[i], 1 / 255.0);
|
|
}
|
|
Mat result = new Mat();
|
|
Cv2.Merge(channels[..3], result);
|
|
return result;
|
|
}
|
|
}
|
|
}
|