Files
辉鸭蛋 e5629f1bb4 5.5 map
2025-03-25 00:37:58 +08:00

239 lines
8.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using OpenCvSharp;
namespace BetterGenshinImpact.Test.Simple.AllMap;
public class MapPuzzle
{
public static List<string> PicWhiteHashList = new List<string>
{
"25E23B0D18C2CBEA19D28E5E399D42FA",
"3B4847FEA7D506EAF3B75D4F4541E867",
"CCCAF02768432A46AA0001E51DC5991B",
"F80C609208063B289A05B8A1E0351226",
"06767779699056515930D0597072AB7D",
"04F757BD57FBB5FA74A6C9C0634BB122",
"04C1EDFCD89249209D1DD885DD2F2129",
"01B8641F5F58BBDE6E10F53D56EA7288",
"AF56BDE27BDF534317A9FB34E08165C0",
"05F4EAB8C6BFBADD60B8A5CCDD614F83"
};
public static MD5 Md5Service = MD5.Create();
public static void PutAll()
{
// 保存2048大图
var img2048 = Put(2048);
Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\拼图结果\5.5\map_55_2048.png", img2048);
// 保存1024
// var img1024 = Put(1024);
// Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\有用的素材\5.2\map_52_1024.png", img1024);
// 保存256
// var grayImage = new Mat();
// Cv2.CvtColor(img1024.Resize(new Size(img1024.Width / 4, img1024.Height / 4), 0, 0, InterpolationFlags.Cubic), grayImage, ColorConversionCodes.BGR2GRAY);
// Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\有用的素材\5.2\map_52_256.png", grayImage);
}
public static Mat Put(int block = 2048)
{
string folderPath = @"E:\HuiTask\更好的原神\地图匹配\地图块素材\UI_Map_最新"; // 图片文件夹路径
string pattern = @"UI_MapBack_([-+]?\d+)_([-+]?\d+)(.*)";
var images = Directory.GetFiles(folderPath, "*.png", SearchOption.TopDirectoryOnly); // 获取所有图片文件路径
// 解析图片位置信息并存储到字典中
var imageLocations = new Dictionary<(int row, int col), ImgInfo>();
foreach (var imagePath in images)
{
// 获取文件大小
var fileInfo = new FileInfo(imagePath);
// 解析图片名称中的行列信息
var name = Path.GetFileNameWithoutExtension(imagePath);
var match = Regex.Match(name, pattern);
int row, col;
if (match.Success)
{
// Debug.WriteLine($"已匹配 ({match.Groups[1].Value}, {match.Groups[2].Value}) {name}");
row = int.Parse(match.Groups[1].Value);
col = int.Parse(match.Groups[2].Value);
}
else
{
// Debug.WriteLine($"未匹配 {name}");
continue;
}
// 排除指定行列的图片
if ((row, col) == (4, 6) || (row, col) == (5, 6) || (row, col) == (5, 5) || (row, col) == (5, 2) || (row, col) == (5, 1) || (row, col) == (4, 1))
{
continue;
}
// 读取图片并计算hash值
Mat img = Cv2.ImRead(imagePath);
var hashBytes = Md5Service.ComputeHash(File.ReadAllBytes(imagePath));
var hash = BitConverter.ToString(hashBytes).Replace("-", "").ToUpperInvariant();
if (img.Width < 8)
{
Debug.WriteLine($"太小的不要 ({row}, {col}) {img.Width} {img.Height} {name}");
continue;
}
// 如果只要城市拼接,取消注释这段
// if (block == 2048 && img.Width != 2048)
// {
// Debug.WriteLine($"不是2048的不要 ({row}, {col}) {img.Width} {img.Height} {name}");
// continue;
// }
// 如果当前位置已经有图片了,保留尺寸较大的图片
if (imageLocations.ContainsKey((row, col)))
{
// 如果当前位置的图片已经被hash锁定跳过
if (imageLocations[(row, col)].Locked)
{
Debug.WriteLine($"已锁定 ({row}, {col}) {name}");
continue;
}
if (img.Width > imageLocations[(row, col)].Img.Width || fileInfo.Length > imageLocations[(row, col)].FileLength || PicWhiteHashList.Contains(hash))
{
imageLocations[(row, col)] = new ImgInfo(img, name, fileInfo.Length, PicWhiteHashList.Contains(hash));
}
else
{
Debug.WriteLine($"重复 ({row}, {col}) {img.Width} {img.Height} {name}");
}
}
else
{
imageLocations[(row, col)] = new ImgInfo(img, name, fileInfo.Length, PicWhiteHashList.Contains(hash));
}
}
int minRow = imageLocations.Keys.Min(key => key.row);
int minCol = imageLocations.Keys.Min(key => key.col);
// 确定大图的行数和列数
int maxRow = imageLocations.Keys.Max(key => key.row);
int maxCol = imageLocations.Keys.Max(key => key.col);
// 计算大图的总宽度和高度
var lenCol = maxCol - minCol;
var lenRow = maxRow - minRow;
Debug.WriteLine($"列数X: {lenCol+1}, 行数Y: {lenRow+1}");
int totalWidth = (lenCol + 1) * block;
int totalHeight = (lenRow + 1) * block;
// 创建空白大图
Mat largeImage = new Mat(totalHeight, totalWidth, MatType.CV_8UC3, new Scalar(0, 0, 0));
// 拼接图片
int[,] arr = new int[lenRow + 1, lenCol + 1];
foreach (var location in imageLocations)
{
int row = location.Key.row - minRow;
int col = location.Key.col - minCol;
Mat img = location.Value.Img;
arr[row, col] = 1;
// 计算当前图片在大图中的左上角位置
int x = (lenCol - col) * block; // 顺序倒过来了,屮
int y = (lenRow - row) * block; // 顺序倒过来了,屮
// 将图片粘贴到大图上
if (img.Width != block || img.Height != block)
{
img = img.Resize(new Size(block, block), 0, 0, InterpolationFlags.Nearest);
}
// 添加位置标识
// img.PutText($"{location.Key.row} , {location.Key.col}", new Point(50, 50), HersheyFonts.HersheyComplex, 2, Scalar.Red, 2, LineTypes.Link8);
img.CopyTo(new Mat(largeImage, new Rect(x, y, img.Width, img.Height)));
}
// 康康二维数组的拼接结果
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Debug.Write(arr[i, j] + " ");
}
Debug.WriteLine("");
}
// 地图图片块
// SaveImagesAs1024X1024(arr, imageLocations, @"E:\HuiTask\更好的原神\地图匹配\有用的素材\5.0\地图块", minRow, minCol);
// Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\combined_image_small.png", largeImage.Resize(new Size(1400, 1300), 0, 0, InterpolationFlags.Cubic));
// 释放资源
return largeImage;
}
public static void SaveImagesAs1024X1024(int[,] arr, Dictionary<(int row, int col), ImgInfo> imageLocations, string outputFolder, int minRow, int minCol)
{
if (!Directory.Exists(outputFolder))
{
Directory.CreateDirectory(outputFolder);
}
for (int row = 0; row < arr.GetLength(0); row++)
{
for (int col = 0; col < arr.GetLength(1); col++)
{
if (arr[row, col] == 1)
{
var key = (row + minRow, col + minCol);
if (imageLocations.TryGetValue(key, out var imgInfo))
{
var img = imgInfo.Img;
if (img.Width != 1204 || img.Height != 1204)
{
img = imgInfo.Img.Resize(new Size(1024, 1024), 0, 0, InterpolationFlags.Nearest);
}
var outputPath = Path.Combine(outputFolder, $"{row}_{col}.png");
Cv2.ImWrite(outputPath, img);
img.Dispose();
}
}
}
}
}
public class ImgInfo
{
public Mat Img { get; set; }
public string Name { get; set; }
/// <summary>
/// 文件大小
/// </summary>
public long FileLength { get; set; }
public bool Locked { get; set; }
public ImgInfo(Mat mat, string name, long fileLength, bool locked = false)
{
Img = mat;
Name = name;
FileLength = fileLength;
Locked = locked;
}
}
}