stitch-a-ton/WebApp/ImageGenerator.cs

213 lines
7.4 KiB
C#
Raw Normal View History

2025-07-26 06:56:07 +07:00
using System.Collections.Concurrent;
using OpenCvSharp;
namespace WebApp;
public class ImageGenerator
{
private const string PATH = "D:/tiles1705/";
public byte[] GenerateImage(RequestBody requestBody)
{
var start = DateTime.Now;
string[] inputs = requestBody.CanvasRect.Split(":");
Coordinate coord0 = new Coordinate(inputs[0]);
Coordinate coord1 = new Coordinate(inputs[1]);
(var matrix, _, _) = GenerateDict(coord0, coord1);
ConcurrentDictionary<int, Mat> rows = new();
Parallel.ForEach(matrix, pair =>
{
Mat row = new Mat();
List<Mat> mats = new();
foreach (var coord in pair.Value)
{
string fileName = PATH + coord.Name + ".png";
mats.Add(new Mat( fileName ) );
}
Cv2.HConcat(mats, row);
rows[pair.Key] = row;
});
Mat output = new Mat();
Cv2.VConcat(rows.Values, output);
var result = output.ImEncode();
var end = DateTime.Now;
var elapsed = end - start;
Console.WriteLine($"Elapsed: {elapsed.TotalMilliseconds} ms");
return result;
}
public byte[] GenerateImage2(RequestBody requestBody)
{
var start = DateTime.Now;
Coordinate a1 = new Coordinate("A1");
Mat a1Mat = new Mat(a1.Path);
string[] inputs = requestBody.CanvasRect.Split(":");
Coordinate coord0 = new Coordinate(inputs[0]);
Coordinate coord1 = new Coordinate(inputs[1]);
double scale = requestBody.OutputScale;
(var matrix, int rowCount, int colCount) = GenerateMatrix(coord0, coord1);
2025-07-27 16:09:11 +07:00
Mat temp = GenerateMatCanvas(a1Mat, rowCount, colCount, new Rect());
2025-07-26 06:56:07 +07:00
Parallel.ForEach(matrix, item =>
{
Mat mat = new Mat(item.Path);
Rect rect = new Rect((item.Col - 1) * a1Mat.Cols, (item.Row - 1) * a1Mat.Rows, a1Mat.Cols, a1Mat.Rows);
mat.CopyTo(temp[rect]);
});
double newWidth = temp.Width * scale;
double newHeight = temp.Height * scale;
2025-07-26 08:50:47 +07:00
var resized = temp.Resize(new Size(newWidth, newHeight));
var result = resized.ImEncode();
var end = DateTime.Now;
var elapsed = end - start;
Console.WriteLine($"Elapsed: {elapsed.TotalMilliseconds} ms");
return result;
}
public byte[] GenerateImage3(RequestBody requestBody)
{
var start = DateTime.Now;
string[] inputs = requestBody.CanvasRect.Split(":");
double scale = requestBody.OutputScale;
Coordinate a1 = new Coordinate("A1");
Mat a1Mat = new Mat(a1.Path);
int width = a1Mat.Width;
int height = a1Mat.Height;
if (scale < 1)
{
width = (int)(width * scale);
height = (int)(height * scale);
a1Mat = a1Mat.Resize(new Size(width, height));
}
Coordinate coord0 = new Coordinate(inputs[0]);
Coordinate coord1 = new Coordinate(inputs[1]);
(var matrix, int rowCount, int colCount) = GenerateMatrix(coord0, coord1);
2025-07-27 16:09:11 +07:00
Rect canvasRect = GenerateInitialRectCanvas(a1Mat, rowCount, colCount);
//Determine cropping region
var globalRoI = GenerateGlobalRoI(requestBody.CropOffset, requestBody.CropSize, canvasRect.Width,
canvasRect.Height);
2025-07-29 06:49:00 +07:00
Mat canvas = new Mat(globalRoI.Height, globalRoI.Width, a1Mat.Type());
2025-07-26 08:50:47 +07:00
Parallel.ForEach(matrix, item =>
{
2025-07-27 16:09:11 +07:00
try
2025-07-26 08:50:47 +07:00
{
2025-07-27 16:09:11 +07:00
Mat mat = new Mat(item.Path);
if (scale < 1)
{
mat = mat.Resize(new Size(width, height));
}
Rect origin = new Rect((item.Col - 1) * a1Mat.Cols, (item.Row - 1) * a1Mat.Rows, a1Mat.Cols, a1Mat.Rows);
var offset = origin.Location;
var roi = origin.Intersect(globalRoI);
if (roi.Width == 0 || roi.Height == 0) return;
Rect placement = roi.Subtract(globalRoI.Location);
var localRoi = roi.Subtract(offset);
var subMat = mat.SubMat(localRoi);
subMat.CopyTo(canvas[placement]);
}
catch (Exception e)
{
Console.WriteLine( $"Error {item}, {e.Message}" );
2025-07-26 08:50:47 +07:00
}
});
2025-07-27 16:09:11 +07:00
var result = canvas.ImEncode();
2025-07-26 06:56:07 +07:00
var end = DateTime.Now;
var elapsed = end - start;
Console.WriteLine($"Elapsed: {elapsed.TotalMilliseconds} ms");
return result;
}
internal (List<Coordinate> Matrix, int RowCount, int ColCount) GenerateMatrix(Coordinate coordinate1, Coordinate coordinate2)
{
int minRow = Math.Min(coordinate1.Row, coordinate2.Row);
int maxRow = Math.Max(coordinate1.Row, coordinate2.Row);
int minCol = Math.Min(coordinate1.Col, coordinate2.Col);
int maxCol = Math.Max(coordinate1.Col, coordinate2.Col);
int rowCount = maxRow - minRow + 1;
int colCount = maxCol - minCol + 1;
// Initialize collections
List<Coordinate> results = new List<Coordinate>(rowCount*colCount);
for (int i = 1; i <= rowCount; i++)
{
for (int j = 1; j <= colCount; j++)
{
results.Add(new Coordinate(i,j));
}
}
return (results, rowCount, colCount);
}
internal (ConcurrentDictionary<int,List<Coordinate>> Matrix, int RowCount, int ColCount) GenerateDict(Coordinate coordinate1, Coordinate coordinate2)
{
ConcurrentDictionary<int,List<Coordinate>> results = new();
int minRow = Math.Min(coordinate1.Row, coordinate2.Row);
int maxRow = Math.Max(coordinate1.Row, coordinate2.Row);
int minCol = Math.Min(coordinate1.Col, coordinate2.Col);
int maxCol = Math.Max(coordinate1.Col, coordinate2.Col);
int rowCount = maxRow - minRow + 1;
int colCount = maxCol - minCol + 1;
for (int i = 0; i < rowCount; i++)
{
List<Coordinate> result = new();
for (int j = 0; j < colCount; j++)
{
int row = minRow + i;
int col = minCol + j;
result.Add(new Coordinate(row, col));
}
results[i] = result;
}
return (results, rowCount, colCount);
}
2025-07-27 16:09:11 +07:00
internal Mat GenerateMatCanvas(Mat reference, int rowCount, int colCount, Rect canvas)
2025-07-26 06:56:07 +07:00
{
2025-07-27 16:09:11 +07:00
return new Mat(canvas.Width, canvas.Height, reference.Type());
// return new Mat(reference.Rows * rowCount - offset.X, reference.Cols * colCount - offset.Y, reference.Type());
}
private Rect GenerateInitialRectCanvas(Mat reference, int rowCount, int colCount)
{
2025-07-29 06:49:00 +07:00
int width = reference.Width * colCount;
int height = reference.Height * rowCount;
2025-07-27 16:09:11 +07:00
return new Rect(0, 0, width, height);
}
internal Rect GenerateGlobalRoI(double[] cropOffset, double[] cropSize, int width, int height)
{
int x = (int)(cropOffset[0] * width);
int y = (int)(cropOffset[1] * height);
width = (int)(cropSize[0] * width);
height = (int)(cropSize[1] * height);
Point location = new Point(x, y);
Size size = new Size(width, height);
Rect cropRegion = new Rect( location, size);
return cropRegion;
2025-07-26 06:56:07 +07:00
}
}