Removed imageMagick

This commit is contained in:
Samuele Lorefice
2025-03-29 00:42:21 +01:00
parent e158cfc95b
commit 78efd4fcc2
3 changed files with 100 additions and 160 deletions

View File

@@ -1,4 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AImage_007BTPixel_007D_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F98f0ece83ba33754ab932bd7b5c712d12f3a59029f9f14067f553a3a318c8f_003FImage_007BTPixel_007D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APixelTypeInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc3cfdca1fb93eb6df5e51a81da5df646adfab8b862fd1a07ee5d247b49c5179_003FPixelTypeInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F2c8e7ca976f350cba9836d5565dac56b11e0b56656fa786460eb1395857a6fa_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AVector3_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fmm00_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F6edafe13d8727aa238b865f5dc91dbc984b5abfbc60bece3744f6311c2c_003FVector3_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AVector3_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fmm00_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F6edafe13d8727aa238b865f5dc91dbc984b5abfbc60bece3744f6311c2c_003FVector3_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue">&lt;AssemblyExplorer&gt; <s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue">&lt;AssemblyExplorer&gt;
&lt;Assembly Path="/mnt/nvme2/Railgun/SDFMapCreator/SDFMapCreator/bin/Debug/net8.0/Magick.NET-Q16-HDRI-OpenMP-x64.dll" /&gt; &lt;Assembly Path="/mnt/nvme2/Railgun/SDFMapCreator/SDFMapCreator/bin/Debug/net8.0/Magick.NET-Q16-HDRI-OpenMP-x64.dll" /&gt;

View File

@@ -1,33 +1,17 @@
using System.Diagnostics; using System.Diagnostics;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ImageMagick; //using ImageMagick;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using float2 = System.Numerics.Vector2; using float2 = System.Numerics.Vector2;
using float3 = System.Numerics.Vector3; using float3 = System.Numerics.Vector3;
using float4 = System.Numerics.Vector4;
/* public record Image(float3[,] Pixels, int Width, int Height);
public struct float2(float x, float y) {
public float x = x, y = y;
}
public struct float3(float r, float g, float b) { public record MaskData(float3[,] Mask, Image Image, List<float2> Edges);
public float r = r, g = g, b = b;
public float3(float value) : this(value, value, value) {}
public float3(float r, float g) : this(r, g, 0f) {}
}
public struct float4(float r, float g, float b, float a) { public record TransitionMaskData(float3[,] Mask, Image ImageA, Image ImageB);
public float r = r, g = g, b = b, a = a;
public float4(float value) : this(value, value, value, value) {}
public float4(float r, float g, float b) : this(r, g, b, 1f) {}
}*/
public record ImageData(MagickImage Image, float3[,] Pixels, List<float2> Edges);
public record MaskData(float3[,] Mask, ImageData Image, List<float2> Edges);
public record TransitionMaskData(float3[,] Mask, ImageData ImageA, ImageData ImageB);
public record SDFData(float3[,] SDF); public record SDFData(float3[,] SDF);
@@ -57,83 +41,82 @@ public static class ArrayExt {
public static class ImageUtil { public static class ImageUtil {
public static T[,] LoadImage<T>(string path) where T : struct, IEquatable<T> { public static T[,] LoadImage<T>(string path) where T : struct, IEquatable<T> {
var image = new MagickImage(path); var image = SixLabors.ImageSharp.Image.Load(path);
var pixels = image.GetPixels().ToArray(); using var image16 = image as Image<Rgba64> ?? throw new NotSupportedException($"Image format not supported");
uint width = image.Width; int width = image.Width;
uint height = image.Height; int height = image.Height;
if (pixels == null) throw new ("Failed to read image."); var result = new T[image.Width, image.Height];
image16.ProcessPixelRows(accessor => {
T[,] result = new T[image.Width, image.Height]; //we use Y as the row index and X as the column index
uint channels = image.ChannelCount; for (int y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y);
if(channels > 4) throw new NotSupportedException($"Image has {channels} channels, only 1-4 channels are supported."); for (int x = 0; x < width; x++) {
switch (result) { switch (result) {
case float[,] f: case float[,] f:
//remainder of index / channels must be 0 f[x, y] = span[x].R;
var data = pixels.Where((_, i) => i % channels != 0).ToArray(); break;
return LoadFloat(data, width, height) as T[,] ?? throw new InvalidOperationException(); case Vector2[,] f:
case Vector2[,]: f[x,y] = new (span[x].R, span[x].G);
//can't read 1 channel images break;
if (channels < 2) throw new NotSupportedException($"Image has {channels} channels, only 2+ channels are supported."); case Vector3[,] f:
//remainder of index / channels must be 0 or 1 (2 values) f[x,y] = new (span[x].R, span[x].G, span[x].B);
var data2 = pixels.Where((_, i) => i % channels >= 1).ToArray(); break;
return LoadVec2(data2, width, height) as T[,] ?? throw new InvalidOperationException(); case Vector4[,] f:
case Vector3[,]: f[x,y] = new (span[x].R, span[x].G, span[x].B, 1f);
//can't read <2 channel images break;
if(channels<3) throw new NotSupportedException($"Image has {channels} channels, only 3+ channels are supported.");
//remainder of index / channels must be 0, 1 or 2 (3 values)
var data3 = pixels.Where((_, i) => i % channels >= 2).ToArray();
return LoadVec3(data3, width, height) as T[,] ?? throw new InvalidOperationException();
case Vector4[,]v4:
//can't read <3 channel images
if(channels<4) throw new NotSupportedException($"Image has {channels} channels, only 4+ channels are supported.");
//remainder of index / channels must be between 0 or 3 (4 values)
var data4 = pixels.Where((_, i) => i % channels >= 3).ToArray();
return LoadVec4(data4, width, height) as T[,] ?? throw new InvalidOperationException();
default:
throw new NotSupportedException($"Type {typeof(T)} is not supported.");
} }
} }
private static float[,] LoadFloat(float[] array, uint width, uint height) {
float[,] result = new float[width, height];
for (int i = 0; i < width * height; i++) {
uint x = (uint)(i % width);
uint y = (uint)(i / width);
result[x, y] = array[i];
} }
});
ImageData(image, path);
return result; return result;
} }
private static Vector2[,] LoadVec2(float[] array, uint width, uint height) { public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
Vector2[,] result = new Vector2[width, height]; var width = array.GetLength(0);
for (int i = 0; i < width * height; i++) { var height = array.GetLength(1);
uint x = (uint)(i % width); uint channels = array switch {
uint y = (uint)(i / width); float[,] => 1,
result[x, y] = new(array[i * 2], array[i * 2 + 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;
} }
return result; }
}
});
Console.WriteLine($"Done!");
image.Save(path);
} }
private static Vector3[,] LoadVec3(float[] array, uint width, uint height) { private static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
Vector3[,] result = new Vector3[width, height]; Console.WriteLine(
for (int i = 0; i < width * height; i++) { $"""
uint x = (uint)(i % width); Image file: {path}
uint y = (uint)(i / width); Resolution: {image1.Width}x{image1.Height}
result[x, y] = new(array[i * 3], array[i * 3 + 1], array[i * 3 + 2]); Total Pixels: {image1.Width*image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel/4} bits per channel
}
return result;
}
private static Vector4[,] LoadVec4(float[] array, uint width, uint height) { """);
Vector4[,] result = new Vector4[width, height];
for (int i = 0; i < width * height; i++) {
uint x = (uint)(i % width);
uint y = (uint)(i / width);
result[x, y] = new(array[i * 4], array[i * 4 + 1], array[i * 4 + 2], array[i * 4 + 3]);
}
return result;
} }
} }
@@ -145,7 +128,7 @@ public class Program {
private const bool outputSDFs = true; private const bool outputSDFs = true;
private const bool outputGradients = true; private const bool outputGradients = true;
static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS }; static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS };
static List<ImageData> Images = new(); static List<Image> Images = new();
static List<MaskData> ImageMasks = new(); static List<MaskData> ImageMasks = new();
static List<TransitionMaskData> TransitionMasks = new(); static List<TransitionMaskData> TransitionMasks = new();
static List<SDFData> SDFs = new(); static List<SDFData> SDFs = new();
@@ -153,51 +136,29 @@ public class Program {
static void ConsoleUpdateLine(string s) => Console.Write("\r" + s); static void ConsoleUpdateLine(string s) => Console.Write("\r" + s);
static void LoadImage(string imgPath) {
var image = new MagickImage(imgPath);
float3[,] pixels;
if (image.Channels.Count() == 4)
//skip ever 4th value if we have an alpha channel
pixels = image.GetPixels().ToArray()!
.Where((_, i) => (i + 1) % 4 != 0).ToArray()
.To2DFloat3(image.Width, image.Height);
else
pixels = image.GetPixels().ToArray()!
.To2DFloat3(image.Width, image.Height);
Images.Add(new(image, pixels, new()));
Console.WriteLine($"Loaded image: {imgPath}");
ImageData(image, image.GetPixels());
}
public static void Main(string[] args) { public static void Main(string[] args) {
Console.WriteLine("Reading images..."); Console.WriteLine("Reading images...");
//foreach image in arguments load the image //foreach image in arguments load the image
var imagesPath = "images"; var imagesPath = "images";
for (int i = 0; i < 8; i++) {
var pixels = ImageUtil.LoadImage<Vector3>($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
}
for (int i = 0; i < 8; i++)
LoadImage($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
//LoadImage("spherecut.png");
//LoadImage("spherefull.png");
//LoadImage("1.png");
//LoadImage("2.png");
//check if all the images in Images are the same resolution //check if all the images in Images are the same resolution
if (Images.Select(img => (img.Image.Width, img.Image.Height)).Distinct().Count() > 1) { if (Images.Select(img => (img.Width, img.Height)).Distinct().Count() > 1) {
Console.WriteLine("Error: Not all images have the same resolution."); Console.WriteLine("Error: Not all images have the same resolution.");
Environment.Exit(1); Environment.Exit(1);
} }
Console.WriteLine("Creating masks..."); Console.WriteLine("Creating masks...");
//for each image pair, create a mask //for each image pair, create a mask
var width = Images[0].Image.Width; var width = (uint)Images[0].Width;
var height = Images[0].Image.Height; var height = (uint)Images[0].Height;
for (int i = 0; i < Images.Count; i++) { for (int i = 0; i < Images.Count; i++) {
ImageMasks.Add(new(SelfMask(Images[i].Pixels, width, height), Images[i], new())); ImageMasks.Add(new(SelfMask(Images[i].Pixels, width, height), Images[i], new()));
if (i < Images.Count - 1) { if (i < Images.Count - 1) {
Console.WriteLine($"Creating mask {i}..."); Console.WriteLine($"Creating mask {i}...");
var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels, width, height); var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels, width, height);
@@ -207,28 +168,18 @@ public class Program {
Console.WriteLine("Edge detecting masks..."); Console.WriteLine("Edge detecting masks...");
//EdgeDetect all masks //EdgeDetect all masks
foreach (var t in ImageMasks) { foreach (var t in ImageMasks) EdgeDetect(t);
EdgeDetect(t);
}
if (outputMasks) { if (outputMasks) {
Console.WriteLine("Writing masks..."); Console.WriteLine("Writing masks...");
for (int i = 0; i < TransitionMasks.Count; i++) { for (int i = 0; i < TransitionMasks.Count; i++) ImageMasks[i].Mask.SaveImage($"mask{i}.png");
var mask = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0),
(uint)TransitionMasks[i].Mask.GetLength(1));
mask.GetPixels().SetPixels(TransitionMasks[i].Mask.ToFloatArray());
mask.Write($"mask{i}.png", MagickFormat.Png24);
}
} }
Console.WriteLine("Creating SDFs..."); Console.WriteLine("Creating SDFs...");
for (var i = 0; i < ImageMasks.Count; i++) { for (var i = 0; i < ImageMasks.Count; i++) {
var mask = ImageMasks[i]; var mask = ImageMasks[i];
SDFs.Add(SDF(mask)); SDFs.Add(SDF(mask));
if (!outputSDFs) continue; if (outputSDFs) mask.Mask.SaveImage($"sdf{i}.png");
var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1));
sdf.GetPixels().SetPixels(SDFs[i].SDF.ToFloatArray());
sdf.Write($"sdf{i}.png", MagickFormat.Png48);
} }
Console.WriteLine("Creating gradients..."); Console.WriteLine("Creating gradients...");
@@ -236,11 +187,7 @@ public class Program {
Console.WriteLine($"Generating gradient {i}..."); Console.WriteLine($"Generating gradient {i}...");
var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]); var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]);
Gradients.Add(gradientData); Gradients.Add(gradientData);
if (!outputGradients) continue; if (outputGradients) gradientData.SaveImage($"gradient{i}.png");
var gradient = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0),
(uint)TransitionMasks[i].Mask.GetLength(1));
gradient.GetPixels().SetPixels(gradientData.ToFloatArray());
gradient.Write($"gradient{i}.png", MagickFormat.Png24);
} }
// generate final image // generate final image
@@ -258,17 +205,13 @@ public class Program {
} }
currStep += stepIncrement; currStep += stepIncrement;
} }
finalImage.SaveImage("final.png");
var finalImageMagick = new MagickImage(MagickColors.Black, (uint)width, (uint)height);
finalImageMagick.GetPixels().SetPixels(finalImage.ToFloatArray());
finalImageMagick.Write("final.png", MagickFormat.Png24);
Console.WriteLine("Done!"); Console.WriteLine("Done!");
} }
private static void EdgeDetect(MaskData maskData) { private static void EdgeDetect(MaskData maskData) {
uint width = maskData.Image.Image.Width; uint width = (uint)maskData.Image.Width;
uint height = maskData.Image.Image.Height; uint height = (uint)maskData.Image.Height;
int iterCount = 0; int iterCount = 0;
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
@@ -295,8 +238,8 @@ public class Program {
} }
static float3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) { static float3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
uint width = mask.ImageA.Image.Width; uint width = (uint)mask.ImageA.Width;
uint height = mask.ImageA.Image.Height; uint height = (uint)mask.ImageA.Height;
int iterCount = 0; int iterCount = 0;
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
@@ -383,15 +326,7 @@ public class Program {
private static float EuclideanDistance(float2 a, float2 b) => private static float EuclideanDistance(float2 a, float2 b) =>
MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2)); MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2));
private static void ImageData(MagickImage image1, IPixelCollection<float> pixels1) {
Console.WriteLine(
$"""
Image file: {image1.Format.ToString()}
Resolution: {image1.Width}x{image1.Height}
Total Pixels: {pixels1.Count()} |{pixels1.Channels} channels, {image1.Depth} bits per channel
""");
}
static float3[,] GetABMask(float3[,] A, float3[,] B, uint resX, uint resY) { static float3[,] GetABMask(float3[,] A, float3[,] B, uint resX, uint resY) {
var temp = new float3[resX, resY]; var temp = new float3[resX, resY];

View File

@@ -9,6 +9,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Magick.NET-Q16-HDRI-OpenMP-x64" Version="14.5.0" /> <PackageReference Include="Magick.NET-Q16-HDRI-OpenMP-x64" Version="14.5.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.5" />
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" /> <PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
</ItemGroup> </ItemGroup>