Gradient + Transitions
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user