completed refactoring, added 32x32 test images
This commit is contained in:
@@ -7,10 +7,6 @@ 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;
|
||||
//result = new T[image.Width, image.Height];
|
||||
return image switch {
|
||||
Image<Rgba64> img => img.ProcessPixelsRgba64<T>(),
|
||||
Image<Rgb24> img => img.ProcessPixelsRgb24<T>(),
|
||||
@@ -21,6 +17,7 @@ public static class ImageUtil {
|
||||
}
|
||||
|
||||
static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> {
|
||||
var max = 65535f;
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
@@ -31,16 +28,16 @@ public static class ImageUtil {
|
||||
for (int x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max;
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +47,7 @@ public static class ImageUtil {
|
||||
}
|
||||
|
||||
static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> {
|
||||
var max = 255f;
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
@@ -60,16 +58,16 @@ public static class ImageUtil {
|
||||
for (int x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max;
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, 1f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -79,6 +77,7 @@ public static class ImageUtil {
|
||||
}
|
||||
|
||||
static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> {
|
||||
var max = 255f;
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
@@ -89,16 +88,16 @@ public static class ImageUtil {
|
||||
for (int x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max;
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -108,27 +107,27 @@ public static class ImageUtil {
|
||||
}
|
||||
|
||||
static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> {
|
||||
using var image16 = image as Image<Rgb48> ?? throw new NotSupportedException($"Image format not supported");
|
||||
var max = 65535f;
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
image16.ProcessPixelRows(accessor => {
|
||||
image.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;
|
||||
f[x, y] = span[x].R / max;
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, 1f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -155,16 +154,16 @@ public static class ImageUtil {
|
||||
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]);
|
||||
span[x] = new Rgb48((ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535), (ushort)(f[x,y] * 65535));
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, 0);
|
||||
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), 0);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
|
||||
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), (ushort)(f[x,y].Z * 65535));
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
|
||||
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), (ushort)(f[x,y].Z * 65535));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
|
||||
using SDFMapCreator;
|
||||
|
||||
public class Program {
|
||||
private const float MAX = 65535f;
|
||||
private const float MAX = 1f;
|
||||
private const float MIN = 0f;
|
||||
private static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
||||
private const bool outputMasks = true;
|
||||
@@ -24,10 +24,23 @@ public class Program {
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
/*
|
||||
var pixels = ImageUtil.LoadImage<Vector3>($"./sphereempty.png");
|
||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||
pixels = ImageUtil.LoadImage<Vector3>($"./spherehalf.png");
|
||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||
pixels = ImageUtil.LoadImage<Vector3>($"./spherecut.png");
|
||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||
pixels = ImageUtil.LoadImage<Vector3>($"./spherefull.png");
|
||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||
*/
|
||||
|
||||
|
||||
//check if all the images in Images are the same resolution
|
||||
if (Images.Select(img => (img.Width, img.Height)).Distinct().Count() > 1) {
|
||||
@@ -61,7 +74,7 @@ public class Program {
|
||||
for (var i = 0; i < ImageMasks.Count; i++) {
|
||||
var mask = ImageMasks[i];
|
||||
SDFs.Add(SDF(mask));
|
||||
if (outputSDFs) mask.Mask.SaveImage($"sdf{i}.png");
|
||||
if (outputSDFs) SDFs[i].SDF.SaveImage($"sdf{i}.png");
|
||||
}
|
||||
|
||||
Console.WriteLine("Creating gradients...");
|
||||
@@ -75,13 +88,14 @@ public class Program {
|
||||
// generate final image
|
||||
var finalImage = new Vector3[width, height];
|
||||
var currStep = 0f;
|
||||
var stepIncrement = MAX / (Gradients.Count + 1);
|
||||
var stepIncrement = MAX / (Gradients.Count);
|
||||
for (var i = 0; i < Gradients.Count; i++) {
|
||||
var mask = ImageMasks[i + 1];
|
||||
var gradient = Gradients[i];
|
||||
Console.WriteLine($"Applying gradient {i}..., {currStep} -> {currStep + stepIncrement}");
|
||||
for (var x = 0; x < mask.Mask.GetLength(0); x++) {
|
||||
for (var y = 0; y < mask.Mask.GetLength(1); y++) {
|
||||
if (mask.Mask[x, y].X == 0 || mask.Mask[x, y].Y > 0) continue;
|
||||
if (mask.Mask[x, y].X == 0) continue;
|
||||
finalImage[x, y] = new(Remap(gradient[x, y].X, MAX, MIN, currStep, currStep + stepIncrement));
|
||||
}
|
||||
}
|
||||
@@ -116,7 +130,7 @@ public class Program {
|
||||
});
|
||||
sw.Stop();
|
||||
Console.WriteLine(
|
||||
$"\nEdge pixels: {maskData.Edges.Count} | {maskData.Edges.Count / sw.ElapsedMilliseconds} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
|
||||
$"\nEdge pixels: {maskData.Edges.Count} | {maskData.Edges.Count / (sw.ElapsedMilliseconds+1)} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
|
||||
}
|
||||
|
||||
static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
|
||||
@@ -167,16 +181,20 @@ public class Program {
|
||||
//convert 1D index to 2D index
|
||||
var x = (int)(i % width);
|
||||
var y = (int)(i / width);
|
||||
Vector2 p = new(x, y);
|
||||
Vector2 p = new(x/(float)width, y/(float)height); //get the pixel position as a Vector2
|
||||
|
||||
float minDist = MAX; //initialize the minimum distance to the maximum possible value
|
||||
float minDist = MAX + 1; //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 = Vector2.DistanceSquared(p, edge);
|
||||
if (dist < minDist) minDist = mask.Mask[x, y].X == 0 ? dist : dist;
|
||||
Vector2 edgeNorm = new(edge.X / (float)width, edge.Y / (float)height);
|
||||
float dist = Vector2.DistanceSquared(p, edgeNorm);
|
||||
if (dist < minDist) minDist = dist;
|
||||
}
|
||||
|
||||
if (minDist > MAX)
|
||||
minDist = MAX;
|
||||
|
||||
temp[x, y] = new(minDist);
|
||||
if (minDist > AbsMax) AbsMax = minDist;
|
||||
iterCount++;
|
||||
|
||||
@@ -55,6 +55,18 @@
|
||||
<None Update="spherehalf.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="spherehalf32.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="spherefull32.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="spherecut32.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="sphereempty.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
BIN
SDFMapCreator/spherecut32.png
Normal file
BIN
SDFMapCreator/spherecut32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 680 B |
BIN
SDFMapCreator/sphereempty.png
Normal file
BIN
SDFMapCreator/sphereempty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
SDFMapCreator/spherefull32.png
Normal file
BIN
SDFMapCreator/spherefull32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 693 B |
BIN
SDFMapCreator/spherehalf32.png
Normal file
BIN
SDFMapCreator/spherehalf32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
Reference in New Issue
Block a user