Giga Refactor

This commit is contained in:
Samuele Lorefice
2025-03-29 00:50:52 +01:00
parent 78efd4fcc2
commit a77e9b7989
3 changed files with 110 additions and 135 deletions

View File

@@ -0,0 +1,86 @@
using System.Numerics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
namespace SDFMapCreator;
public static class ImageUtil {
public static T[,] LoadImage<T>(string path) where T : struct, IEquatable<T> {
var image = SixLabors.ImageSharp.Image.Load(path);
using var image16 = image as Image<Rgba64> ?? throw new NotSupportedException($"Image format not supported");
int width = image.Width;
int height = image.Height;
var result = new T[image.Width, image.Height];
image16.ProcessPixelRows(accessor => {
//we use Y as the row index and X as the column index
for (int y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) {
switch (result) {
case float[,] f:
f[x, y] = span[x].R;
break;
case Vector2[,] f:
f[x,y] = new (span[x].R, span[x].G);
break;
case Vector3[,] f:
f[x,y] = new (span[x].R, span[x].G, span[x].B);
break;
case Vector4[,] f:
f[x,y] = new (span[x].R, span[x].G, span[x].B, 1f);
break;
}
}
}
});
ImageData(image, path);
return result;
}
public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
var width = array.GetLength(0);
var height = array.GetLength(1);
uint channels = array switch {
float[,] => 1,
Vector2[,] => 2,
Vector3[,] => 3,
Vector4[,] => 4,
_ => throw new NotSupportedException($"Type {typeof(T)} is not supported.")
};
Console.Write($"Writing image {path}...");
using Image<Rgb48> image = new(width, height);
image.ProcessPixelRows(accessor => {
for (int y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) {
switch (array) {
case float[,] f:
span[x] = new Rgb48((ushort)f[x, y], (ushort)f[x, y], (ushort)f[x,y]);
break;
case Vector2[,] f:
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, 0);
break;
case Vector3[,] f:
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
break;
case Vector4[,] f:
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
break;
}
}
}
});
Console.WriteLine($"Done!");
image.Save(path);
}
private static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
Console.WriteLine(
$"""
Image file: {path}
Resolution: {image1.Width}x{image1.Height}
Total Pixels: {image1.Width*image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel/4} bits per channel
""");
}
}

View File

@@ -1,124 +1,7 @@
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
//using ImageMagick;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using float2 = System.Numerics.Vector2;
using float3 = System.Numerics.Vector3;
public record Image(float3[,] Pixels, int Width, int Height);
public record MaskData(float3[,] Mask, Image Image, List<float2> Edges);
public record TransitionMaskData(float3[,] Mask, Image ImageA, Image ImageB);
public record SDFData(float3[,] SDF);
public static class ArrayExt {
public static float3[,] To2DFloat3(this float[] array, uint width, uint height) {
float3[,] result = new float3[width, height];
for (int i = 0; i < width * height; i++) {
uint x = (uint)(i % width);
uint y = (uint)(i / width);
result[y, x] = new(array[i * 3], array[i * 3 + 1], array[i * 3 + 2]);
}
return result;
}
public static float[] ToFloatArray(this float3[,] array) {
float[] result = new float[array.GetLength(0) * array.GetLength(1) * 3];
for (int x = 0; x < array.GetLength(0); x++) {
for (int y = 0; y < array.GetLength(1); y++) {
result[x * array.GetLength(1) * 3 + y * 3] = array[x, y].X;
result[x * array.GetLength(1) * 3 + y * 3 + 1] = array[x, y].Y;
result[x * array.GetLength(1) * 3 + y * 3 + 2] = array[x, y].Z;
}
}
return result;
}
}
public static class ImageUtil {
public static T[,] LoadImage<T>(string path) where T : struct, IEquatable<T> {
var image = SixLabors.ImageSharp.Image.Load(path);
using var image16 = image as Image<Rgba64> ?? throw new NotSupportedException($"Image format not supported");
int width = image.Width;
int height = image.Height;
var result = new T[image.Width, image.Height];
image16.ProcessPixelRows(accessor => {
//we use Y as the row index and X as the column index
for (int y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) {
switch (result) {
case float[,] f:
f[x, y] = span[x].R;
break;
case Vector2[,] f:
f[x,y] = new (span[x].R, span[x].G);
break;
case Vector3[,] f:
f[x,y] = new (span[x].R, span[x].G, span[x].B);
break;
case Vector4[,] f:
f[x,y] = new (span[x].R, span[x].G, span[x].B, 1f);
break;
}
}
}
});
ImageData(image, path);
return result;
}
public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
var width = array.GetLength(0);
var height = array.GetLength(1);
uint channels = array switch {
float[,] => 1,
Vector2[,] => 2,
Vector3[,] => 3,
Vector4[,] => 4,
_ => throw new NotSupportedException($"Type {typeof(T)} is not supported.")
};
Console.Write($"Writing image {path}...");
using Image<Rgb48> image = new(width, height);
image.ProcessPixelRows(accessor => {
for (int y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) {
switch (array) {
case float[,] f:
span[x] = new Rgb48((ushort)f[x, y], (ushort)f[x, y], (ushort)f[x,y]);
break;
case Vector2[,] f:
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, 0);
break;
case Vector3[,] f:
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
break;
case Vector4[,] f:
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
break;
}
}
}
});
Console.WriteLine($"Done!");
image.Save(path);
}
private static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
Console.WriteLine(
$"""
Image file: {path}
Resolution: {image1.Width}x{image1.Height}
Total Pixels: {image1.Width*image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel/4} bits per channel
""");
}
}
using SDFMapCreator;
public class Program {
private const float MAX = 65535f;
@@ -132,13 +15,12 @@ public class Program {
static List<MaskData> ImageMasks = new();
static List<TransitionMaskData> TransitionMasks = new();
static List<SDFData> SDFs = new();
static List<float3[,]> Gradients = new();
static List<Vector3[,]> Gradients = new();
static void ConsoleUpdateLine(string s) => Console.Write("\r" + s);
public static void Main(string[] args) {
Console.WriteLine("Reading images...");
//foreach image in arguments load the image
var imagesPath = "images";
@@ -191,7 +73,7 @@ public class Program {
}
// generate final image
var finalImage = new float3[width, height];
var finalImage = new Vector3[width, height];
var currStep = 0f;
var stepIncrement = MAX / (Gradients.Count + 1);
for (var i = 0; i < Gradients.Count; i++) {
@@ -237,13 +119,13 @@ public class Program {
$"\nEdge pixels: {maskData.Edges.Count} | {maskData.Edges.Count / sw.ElapsedMilliseconds} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
}
static float3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
uint width = (uint)mask.ImageA.Width;
uint height = (uint)mask.ImageA.Height;
int iterCount = 0;
var sw = new Stopwatch();
sw.Start();
float3[,] temp = new float3[width, height];
Vector3[,] temp = new Vector3[width, height];
var min = MAX;
var max = MIN;
@@ -275,7 +157,7 @@ public class Program {
static SDFData SDF(MaskData mask) {
var width = (uint)mask.Mask.GetLength(0);
var height = (uint)mask.Mask.GetLength(1);
var temp = new float3[width, height];
var temp = new Vector3[width, height];
float AbsMax = MIN;
int iterCount = 0;
var sw = new Stopwatch();
@@ -285,13 +167,13 @@ public class Program {
//convert 1D index to 2D index
var x = (int)(i % width);
var y = (int)(i / width);
float2 p = new(x, y);
Vector2 p = new(x, y);
float minDist = MAX; //initialize the minimum distance to the maximum possible value
//loop through all the pixels in the mask
foreach (var edge in mask.Edges) {
float dist = float2.DistanceSquared(p, edge);
float dist = Vector2.DistanceSquared(p, edge);
if (dist < minDist) minDist = mask.Mask[x, y].X == 0 ? dist : dist;
}
@@ -323,13 +205,12 @@ public class Program {
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float EuclideanDistance(float2 a, float2 b) =>
private static float EuclideanDistance(Vector2 a, Vector2 b) =>
MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2));
static float3[,] GetABMask(float3[,] A, float3[,] B, uint resX, uint resY) {
var temp = new float3[resX, resY];
static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B, uint resX, uint resY) {
var temp = new Vector3[resX, resY];
Parallel.For(0, resX * resY, parallelOptions, (i) =>
{
uint x = (uint)(i % resX);
@@ -344,8 +225,8 @@ public class Program {
return temp;
}
static float3[,] SelfMask(float3[,] A, uint resX, uint resY) {
var temp = new float3[resX, resY];
static Vector3[,] SelfMask(Vector3[,] A, uint resX, uint resY) {
var temp = new Vector3[resX, resY];
Parallel.For(0, resX * resY, parallelOptions, (i) =>
{
uint x = (uint)(i % resX);
@@ -358,7 +239,7 @@ public class Program {
return temp;
}
static bool EdgeKernel(float3[,] mask, int x, int y, uint width, uint height) {
static bool EdgeKernel(Vector3[,] mask, int x, int y, uint width, uint height) {
//if we are already empty, return false
if (mask[x, y].X == 0) return false;
//if we are on the edge of the image, return false

8
SDFMapCreator/Records.cs Normal file
View File

@@ -0,0 +1,8 @@
using System.Numerics;
namespace SDFMapCreator;
public record Image(Vector3[,] Pixels, int Width, int Height);
public record MaskData(Vector3[,] Mask, Image Image, List<Vector2> Edges);
public record SDFData(Vector3[,] SDF);
public record TransitionMaskData(Vector3[,] Mask, Image ImageA, Image ImageB);