Gradient + Transitions

This commit is contained in:
Samuele Lorefice
2025-03-26 06:42:46 +01:00
parent e3dbb82587
commit 809068e270

View File

@@ -120,11 +120,44 @@ public class Program {
Console.WriteLine("Creating SDFs...");
for (var i = 0; i < Masks.Count; i++) {
var mask = Masks[i];
var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1));
SDFs.Add(SDF(mask));
if(!outputSDFs) continue;
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...");
for (var i = 0; i < Masks.Count - 1; i++) {
var gradientData = Gradient(Masks[i], SDFs[i], SDFs[i + 1]);
Gradients.Add(gradientData);
if(!outputGradients) continue;
var gradient = new MagickImage(MagickColors.Black, (uint)Masks[i].Mask.GetLength(0), (uint)Masks[i].Mask.GetLength(1));
gradient.GetPixels().SetPixels(gradientData.ToFloatArray());
gradient.Write($"gradient{i}.png", MagickFormat.Png24);
}
Console.WriteLine("Preparing transitions...");
//for each gradient read the corresponding mask
//for each pixel in the mask, lerp the pixel value with the gradient value
//write the result to a new image
int width = Masks[0].Mask.GetLength(0);
int height = Masks[0].Mask.GetLength(1);
for (var i = 0; i < Gradients.Count; i++) {
var mask = Masks[i + 1];
var gradient = Gradients[i];
var transition = new float3[width, height];
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].r == 0) continue;
transition[x, y] = new(Lerp(Images[i].Pixels[x,y].r, MAX, gradient[x,y].r));
}
}
var transitionImage = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1));
transitionImage.GetPixels().SetPixels(transition.ToFloatArray());
transitionImage.Write($"transition{i}.png", MagickFormat.Png24);
}
Console.WriteLine("Done!");
}
@@ -153,6 +186,32 @@ public class Program {
Console.WriteLine($"Edge pixels: {maskData.Edges.Count} | {maskData.Edges.Count/sw.ElapsedMilliseconds} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
}
static float3[,] Gradient(MaskData mask, SDFData sdfA, SDFData sdfB) {
uint width = mask.A.Image.Width;
uint height = mask.A.Image.Height;
int iterCount = 0;
var sw = new Stopwatch();
sw.Start();
float3[,] temp = new float3[width, height];
Console.WriteLine("Running edge detection...");
Parallel.For(0, width * height, (i) => {
int x = (int)(i % width);
int y = (int)(i / width);
var a = (sdfA.SDF[x,y].r + sdfB.SDF[x,y].g + sdfB.SDF[x,y].b )/ 3;
var b = (sdfB.SDF[x,y].r + sdfB.SDF[x,y].g + sdfB.SDF[x,y].b )/ 3;
var gradient = a / (a + b);
temp[x, y] = new(Remap(gradient, 0, 1, MIN, MAX));
});
Console.WriteLine($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount/sw.Elapsed.TotalSeconds:N0} pixels/s)");
var min = temp.Cast<float3>().Min(x => x.r);
var max = temp.Cast<float3>().Max(x => x.r);
Console.WriteLine($"Min: {min} | Max: {max}");
return temp;
}
static SDFData SDF(MaskData mask) {
var width = (uint)mask.Mask.GetLength(0);
var height = (uint)mask.Mask.GetLength(1);
@@ -166,11 +225,6 @@ public class Program {
var x = (int)(i % width);
var y = (int)(i / width);
float2 p = new(x, y);
//skip all pixels we don't care about
if(mask.Mask[x, y].r == 0) {
temp[x, y] = new(MIN);
return;
}
float minDist = MAX; //initialize the minimum distance to the maximum possible value
@@ -231,6 +285,19 @@ public class Program {
return temp;
}
static float3[,] SelfMask(float3[,] A, uint resX, uint resY) {
var temp = new float3[resX, resY];
Parallel.For(0, resX*resY, (i) => {
uint x = (uint)(i % resX);
uint y = (uint)(i / resX);
var pixelA = A[x, y];
float lumaA = (pixelA.r+pixelA.g+pixelA.b)/3;
float resultPixel = lumaA > 0 ? MAX : MIN;
temp[x, y] = new(resultPixel, 0, 0);
});
return temp;
}
static bool EdgeKernel(float3[,] mask, int x, int y, uint width, uint height) {
//if we are already empty, return false
if (mask[x, y].r == 0) return false;