Refactor
This commit is contained in:
@@ -24,7 +24,9 @@ public struct float4(float r, float g, float b, float a) {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
public record ImageData(MagickImage Image, float3[,] Pixels, List<float2> Edges);
|
public record ImageData(MagickImage Image, float3[,] Pixels, List<float2> Edges);
|
||||||
|
|
||||||
public record MaskData(float3[,] Mask, ImageData Image, List<float2> Edges);
|
public record MaskData(float3[,] Mask, ImageData Image, List<float2> Edges);
|
||||||
|
|
||||||
public record TransitionMaskData(float3[,] Mask, ImageData ImageA, ImageData ImageB);
|
public record TransitionMaskData(float3[,] Mask, ImageData ImageA, ImageData ImageB);
|
||||||
|
|
||||||
public record SDFData(float3[,] SDF);
|
public record SDFData(float3[,] SDF);
|
||||||
@@ -32,28 +34,28 @@ public record SDFData(float3[,] SDF);
|
|||||||
public static class ArrayExt {
|
public static class ArrayExt {
|
||||||
public static float3[,] To2DFloat3(this float[] array, uint width, uint height) {
|
public static float3[,] To2DFloat3(this float[] array, uint width, uint height) {
|
||||||
float3[,] result = new float3[width, height];
|
float3[,] result = new float3[width, height];
|
||||||
for(int i = 0; i < width*height; i++) {
|
for (int i = 0; i < width * height; i++) {
|
||||||
uint x = (uint)(i % width);
|
uint x = (uint)(i % width);
|
||||||
uint y = (uint)(i / width);
|
uint y = (uint)(i / width);
|
||||||
result[y, x] = new (array[i*3], array[i*3+1], array[i*3+2]);
|
result[y, x] = new(array[i * 3], array[i * 3 + 1], array[i * 3 + 2]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float[] ToFloatArray(this float3[,] array) {
|
public static float[] ToFloatArray(this float3[,] array) {
|
||||||
float[] result = new float[array.GetLength(0) * array.GetLength(1) * 3];
|
float[] result = new float[array.GetLength(0) * array.GetLength(1) * 3];
|
||||||
for(int x = 0; x < array.GetLength(0); x++) {
|
for (int x = 0; x < array.GetLength(0); x++) {
|
||||||
for(int y = 0; y < array.GetLength(1); y++) {
|
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] = 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 + 1] = array[x, y].Y;
|
||||||
result[x*array.GetLength(1)*3 + y*3+2] = array[x, y].Z;
|
result[x * array.GetLength(1) * 3 + y * 3 + 2] = array[x, y].Z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Program {
|
public class Program {
|
||||||
private const float MAX = 65535f;
|
private const float MAX = 65535f;
|
||||||
private const float MIN = 0f;
|
private const float MIN = 0f;
|
||||||
private static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
private static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
||||||
@@ -62,17 +64,17 @@ public class Program {
|
|||||||
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<ImageData> Images = new();
|
||||||
static List<TransitionMaskData> TransitionMasks = new();
|
|
||||||
static List<MaskData> ImageMasks = new();
|
static List<MaskData> ImageMasks = new();
|
||||||
|
static List<TransitionMaskData> TransitionMasks = new();
|
||||||
static List<SDFData> SDFs = new();
|
static List<SDFData> SDFs = new();
|
||||||
static List<float3[,]> Gradients = new();
|
static List<float3[,]> Gradients = new();
|
||||||
|
|
||||||
static void ConsoleUpdateLine(string s) => Console.Write("\r"+s);
|
static void ConsoleUpdateLine(string s) => Console.Write("\r" + s);
|
||||||
|
|
||||||
static void LoadImage(string imgPath) {
|
static void LoadImage(string imgPath) {
|
||||||
var image = new MagickImage(imgPath);
|
var image = new MagickImage(imgPath);
|
||||||
float3[,] pixels;
|
float3[,] pixels;
|
||||||
if(image.Channels.Count() ==4)
|
if (image.Channels.Count() == 4)
|
||||||
//skip ever 4th value if we have an alpha channel
|
//skip ever 4th value if we have an alpha channel
|
||||||
pixels = image.GetPixels().ToArray()!
|
pixels = image.GetPixels().ToArray()!
|
||||||
.Where((_, i) => (i + 1) % 4 != 0).ToArray()
|
.Where((_, i) => (i + 1) % 4 != 0).ToArray()
|
||||||
@@ -80,25 +82,25 @@ public class Program {
|
|||||||
else
|
else
|
||||||
pixels = image.GetPixels().ToArray()!
|
pixels = image.GetPixels().ToArray()!
|
||||||
.To2DFloat3(image.Width, image.Height);
|
.To2DFloat3(image.Width, image.Height);
|
||||||
Images.Add(new (image, pixels, new()));
|
Images.Add(new(image, pixels, new()));
|
||||||
Console.WriteLine($"Loaded image: {imgPath}");
|
Console.WriteLine($"Loaded image: {imgPath}");
|
||||||
ImageData(image, image.GetPixels());
|
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++)
|
for (int i = 0; i < 8; i++)
|
||||||
LoadImage($"./{imagesPath}{Path.DirectorySeparatorChar}{i+1:00}.png");
|
LoadImage($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
|
||||||
|
|
||||||
|
|
||||||
//LoadImage("spherecut.png");
|
//LoadImage("spherecut.png");
|
||||||
//LoadImage("spherefull.png");
|
//LoadImage("spherefull.png");
|
||||||
|
|
||||||
//LoadImage("1.png");
|
//LoadImage("1.png");
|
||||||
//LoadImage("2.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
|
||||||
@@ -106,56 +108,59 @@ public class Program {
|
|||||||
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 = Images[0].Image.Width;
|
||||||
var height = Images[0].Image.Height;
|
var height = Images[0].Image.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);
|
||||||
TransitionMasks.Add(new(mask, Images[i], Images[i + 1]));
|
TransitionMasks.Add(new(mask, Images[i], Images[i + 1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Edge detecting masks...");
|
Console.WriteLine("Edge detecting masks...");
|
||||||
//EdgeDetect all masks
|
//EdgeDetect all masks
|
||||||
foreach (var t in ImageMasks) { EdgeDetect(t); }
|
foreach (var t in ImageMasks) {
|
||||||
|
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++) {
|
||||||
var mask = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0), (uint)TransitionMasks[i].Mask.GetLength(1));
|
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.GetPixels().SetPixels(TransitionMasks[i].Mask.ToFloatArray());
|
||||||
mask.Write($"mask{i}.png", MagickFormat.Png24);
|
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) continue;
|
||||||
var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1));
|
var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1));
|
||||||
sdf.GetPixels().SetPixels(SDFs[i].SDF.ToFloatArray());
|
sdf.GetPixels().SetPixels(SDFs[i].SDF.ToFloatArray());
|
||||||
sdf.Write($"sdf{i}.png", MagickFormat.Png48);
|
sdf.Write($"sdf{i}.png", MagickFormat.Png48);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Creating gradients...");
|
Console.WriteLine("Creating gradients...");
|
||||||
for (var i = 0; i < TransitionMasks.Count; i++) {
|
for (var i = 0; i < TransitionMasks.Count; i++) {
|
||||||
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) continue;
|
||||||
var gradient = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0), (uint)TransitionMasks[i].Mask.GetLength(1));
|
var gradient = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0),
|
||||||
|
(uint)TransitionMasks[i].Mask.GetLength(1));
|
||||||
gradient.GetPixels().SetPixels(gradientData.ToFloatArray());
|
gradient.GetPixels().SetPixels(gradientData.ToFloatArray());
|
||||||
gradient.Write($"gradient{i}.png", MagickFormat.Png24);
|
gradient.Write($"gradient{i}.png", MagickFormat.Png24);
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate final image
|
// generate final image
|
||||||
var finalImage = new float3[width, height];
|
var finalImage = new float3[width, height];
|
||||||
var currStep = 0f;
|
var currStep = 0f;
|
||||||
@@ -166,16 +171,16 @@ public class Program {
|
|||||||
for (var x = 0; x < mask.Mask.GetLength(0); x++) {
|
for (var x = 0; x < mask.Mask.GetLength(0); x++) {
|
||||||
for (var y = 0; y < mask.Mask.GetLength(1); y++) {
|
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 || mask.Mask[x, y].Y > 0) continue;
|
||||||
finalImage[x, y] = new(Remap(gradient[x,y].X, MAX, MIN, currStep, currStep + stepIncrement));
|
finalImage[x, y] = new(Remap(gradient[x, y].X, MAX, MIN, currStep, currStep + stepIncrement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currStep += stepIncrement;
|
currStep += stepIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
var finalImageMagick = new MagickImage(MagickColors.Black, (uint)width, (uint)height);
|
var finalImageMagick = new MagickImage(MagickColors.Black, (uint)width, (uint)height);
|
||||||
finalImageMagick.GetPixels().SetPixels(finalImage.ToFloatArray());
|
finalImageMagick.GetPixels().SetPixels(finalImage.ToFloatArray());
|
||||||
finalImageMagick.Write("final.png", MagickFormat.Png24);
|
finalImageMagick.Write("final.png", MagickFormat.Png24);
|
||||||
|
|
||||||
Console.WriteLine("Done!");
|
Console.WriteLine("Done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,22 +191,25 @@ public class Program {
|
|||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
Console.WriteLine("Running edge detection...");
|
Console.WriteLine("Running edge detection...");
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||||
|
{
|
||||||
int x = (int)(i % width);
|
int x = (int)(i % width);
|
||||||
int y = (int)(i / width);
|
int y = (int)(i / width);
|
||||||
|
|
||||||
if (!EdgeKernel(maskData.Mask, x, y, width, height)) return;
|
if (!EdgeKernel(maskData.Mask, x, y, width, height)) return;
|
||||||
var color = maskData.Mask[x, y];
|
var color = maskData.Mask[x, y];
|
||||||
color.Y = MAX;
|
color.Y = MAX;
|
||||||
maskData.Mask[x, y] = color;
|
maskData.Mask[x, y] = color;
|
||||||
lock(maskData.Edges) maskData.Edges.Add(new(x, y));
|
lock (maskData.Edges) maskData.Edges.Add(new(x, y));
|
||||||
iterCount++;
|
iterCount++;
|
||||||
if (iterCount % (width * height / 100) == 0) {
|
if (iterCount % (width * height / 100) == 0) {
|
||||||
ConsoleUpdateLine($"Progress: {iterCount/(float)(width*height):P} | {iterCount/(sw.Elapsed.TotalSeconds):N0} pixels/s");
|
ConsoleUpdateLine(
|
||||||
|
$"Progress: {iterCount / (float)(width * height):P} | {iterCount / (sw.Elapsed.TotalSeconds):N0} pixels/s");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
Console.WriteLine($"Edge pixels: {maskData.Edges.Count} | {maskData.Edges.Count/sw.ElapsedMilliseconds} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
|
Console.WriteLine(
|
||||||
|
$"\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 float3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
|
||||||
@@ -211,32 +219,34 @@ public class Program {
|
|||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
float3[,] temp = new float3[width, height];
|
float3[,] temp = new float3[width, height];
|
||||||
|
|
||||||
var min = MAX;
|
var min = MAX;
|
||||||
var max = MIN;
|
var max = MIN;
|
||||||
|
|
||||||
Console.WriteLine("Running gradient generation...");
|
Console.WriteLine("Running gradient generation...");
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||||
|
{
|
||||||
int x = (int)(i % width);
|
int x = (int)(i % width);
|
||||||
int y = (int)(i / width);
|
int y = (int)(i / width);
|
||||||
|
|
||||||
if(mask.Mask[x,y].X == 0 || mask.Mask[x,y].Y > 0) return;
|
if (mask.Mask[x, y].X == 0 || mask.Mask[x, y].Y > 0) return;
|
||||||
|
|
||||||
var a = sdfA.SDF[x, y].X;
|
var a = sdfA.SDF[x, y].X;
|
||||||
var b = sdfB.SDF[x, y].X;
|
var b = sdfB.SDF[x, y].X;
|
||||||
|
|
||||||
var gradient = a / (a + b);
|
var gradient = a / (a + b);
|
||||||
temp[x, y] = new(Remap(gradient, 0, 1, MIN, MAX));
|
temp[x, y] = new(Remap(gradient, 0, 1, MIN, MAX));
|
||||||
|
|
||||||
if (gradient < min) min = gradient;
|
if (gradient < min) min = gradient;
|
||||||
if (gradient > max) max = gradient;
|
if (gradient > max) max = gradient;
|
||||||
});
|
});
|
||||||
|
|
||||||
Console.WriteLine($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount/(float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
Console.WriteLine(
|
||||||
|
$"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
Console.WriteLine($"Min: {min} | Max: {max}");
|
Console.WriteLine($"Min: {min} | Max: {max}");
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDFData SDF(MaskData mask) {
|
static SDFData SDF(MaskData mask) {
|
||||||
var width = (uint)mask.Mask.GetLength(0);
|
var width = (uint)mask.Mask.GetLength(0);
|
||||||
var height = (uint)mask.Mask.GetLength(1);
|
var height = (uint)mask.Mask.GetLength(1);
|
||||||
@@ -245,79 +255,86 @@ public class Program {
|
|||||||
int iterCount = 0;
|
int iterCount = 0;
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||||
|
{
|
||||||
//convert 1D index to 2D index
|
//convert 1D index to 2D index
|
||||||
var x = (int)(i % width);
|
var x = (int)(i % width);
|
||||||
var y = (int)(i / width);
|
var y = (int)(i / width);
|
||||||
float2 p = new(x, y);
|
float2 p = new(x, y);
|
||||||
|
|
||||||
float minDist = MAX; //initialize the minimum distance to the maximum possible value
|
float minDist = MAX; //initialize the minimum distance to the maximum possible value
|
||||||
|
|
||||||
//loop through all the pixels in the mask
|
//loop through all the pixels in the mask
|
||||||
foreach (var edge in mask.Edges) {
|
foreach (var edge in mask.Edges) {
|
||||||
float dist = float2.DistanceSquared(p, edge);
|
float dist = float2.DistanceSquared(p, edge);
|
||||||
if (dist < minDist) minDist = mask.Mask[x, y].X == 0 ? dist : dist;
|
if (dist < minDist) minDist = mask.Mask[x, y].X == 0 ? dist : dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp[x, y] = new(minDist);
|
temp[x, y] = new(minDist);
|
||||||
if (minDist > AbsMax) AbsMax = minDist;
|
if (minDist > AbsMax) AbsMax = minDist;
|
||||||
iterCount++;
|
iterCount++;
|
||||||
if (iterCount % (width * height / 100) == 0) {
|
if (iterCount % (width * height / 100) == 0) {
|
||||||
ConsoleUpdateLine($"Progress: {iterCount/(width*height):P}% | {iterCount/(sw.Elapsed.TotalSeconds):N0} pixels/s");
|
ConsoleUpdateLine(
|
||||||
|
$"Progress: {iterCount / (float)(width * height):P}% | {iterCount / (sw.Elapsed.TotalSeconds):N0} pixels/s");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Console.WriteLine($"SDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount/sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
Console.WriteLine(
|
||||||
|
$"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
sw.Restart();
|
sw.Restart();
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||||
|
{
|
||||||
//convert 1D index to 2D index
|
//convert 1D index to 2D index
|
||||||
var x = (int)(i % width);
|
var x = (int)(i % width);
|
||||||
var y = (int)(i / width);
|
var y = (int)(i / width);
|
||||||
temp[x, y] = new(Remap(temp[x, y].X, 0, AbsMax, MIN, MAX));
|
temp[x, y] = new(Remap(temp[x, y].X, 0, AbsMax, MIN, MAX));
|
||||||
});
|
});
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|
||||||
Console.WriteLine($"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount/sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
Console.WriteLine(
|
||||||
|
$"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
Console.WriteLine("AbsMax: " + AbsMax);
|
Console.WriteLine("AbsMax: " + AbsMax);
|
||||||
return new(temp);
|
return new(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
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) {
|
private static void ImageData(MagickImage image1, IPixelCollection<float> pixels1) {
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"""
|
$"""
|
||||||
Image file: {image1.Format.ToString()}
|
Image file: {image1.Format.ToString()}
|
||||||
Resolution: {image1.Width}x{image1.Height}
|
Resolution: {image1.Width}x{image1.Height}
|
||||||
Total Pixels: {pixels1.Count()} |{pixels1.Channels} channels, {image1.Depth} bits per channel
|
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];
|
||||||
Parallel.For(0, resX*resY, parallelOptions, (i) => {
|
Parallel.For(0, resX * resY, parallelOptions, (i) =>
|
||||||
|
{
|
||||||
uint x = (uint)(i % resX);
|
uint x = (uint)(i % resX);
|
||||||
uint y = (uint)(i / resX);
|
uint y = (uint)(i / resX);
|
||||||
var pixelA = A[x, y];
|
var pixelA = A[x, y];
|
||||||
var pixelB = B[x, y];
|
var pixelB = B[x, y];
|
||||||
float lumaA = (pixelA.X+pixelA.Y+pixelA.Z)/3;
|
float lumaA = (pixelA.X + pixelA.Y + pixelA.Z) / 3;
|
||||||
float lumaB = (pixelB.X+pixelB.Y+pixelB.Z)/3;
|
float lumaB = (pixelB.X + pixelB.Y + pixelB.Z) / 3;
|
||||||
float resultPixel = lumaB > lumaA ? MAX : MIN;
|
float resultPixel = lumaB > lumaA ? MAX : MIN;
|
||||||
temp[x, y] = new(resultPixel, 0, 0);
|
temp[x, y] = new(resultPixel, 0, 0);
|
||||||
});
|
});
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float3[,] SelfMask(float3[,] A, uint resX, uint resY) {
|
static float3[,] SelfMask(float3[,] A, uint resX, uint resY) {
|
||||||
var temp = new float3[resX, resY];
|
var temp = new float3[resX, resY];
|
||||||
Parallel.For(0, resX*resY, parallelOptions, (i) => {
|
Parallel.For(0, resX * resY, parallelOptions, (i) =>
|
||||||
|
{
|
||||||
uint x = (uint)(i % resX);
|
uint x = (uint)(i % resX);
|
||||||
uint y = (uint)(i / resX);
|
uint y = (uint)(i / resX);
|
||||||
var pixelA = A[x, y];
|
var pixelA = A[x, y];
|
||||||
float lumaA = (pixelA.X+pixelA.Y+pixelA.Z)/3;
|
float lumaA = (pixelA.X + pixelA.Y + pixelA.Z) / 3;
|
||||||
float resultPixel = lumaA > 0 ? MAX : MIN;
|
float resultPixel = lumaA > 0 ? MAX : MIN;
|
||||||
temp[x, y] = new(resultPixel, 0, 0);
|
temp[x, y] = new(resultPixel, 0, 0);
|
||||||
});
|
});
|
||||||
@@ -341,12 +358,12 @@ public class Program {
|
|||||||
//if we didn't find any black pixels, return false
|
//if we didn't find any black pixels, return false
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static T Lerp<T>(T a, T b, float t)
|
static T Lerp<T>(T a, T b, float t)
|
||||||
where T : INumber<T>, IMultiplyOperators<T, float, T>, IAdditionOperators<T, T, T>
|
where T : INumber<T>, IMultiplyOperators<T, float, T>, IAdditionOperators<T, T, T>
|
||||||
=> a * (1 - t) + b * t;
|
=> a * (1 - t) + b * t;
|
||||||
|
|
||||||
static T Remap<T>(T value, T min, T max, T newMin, T newMax)
|
static T Remap<T>(T value, T min, T max, T newMin, T newMax)
|
||||||
where T : INumber<T>, ISubtractionOperators<T, T, T>, IMultiplyOperators<T, T, T>, IAdditionOperators<T, T, T>
|
where T : INumber<T>, ISubtractionOperators<T, T, T>, IMultiplyOperators<T, T, T>, IAdditionOperators<T, T, T>
|
||||||
=> (value - min) / (max - min) * (newMax - newMin) + newMin;
|
=> (value - min) / (max - min) * (newMax - newMin) + newMin;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user