Compare commits
3 Commits
925e4c9989
...
b072eea732
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b072eea732 | ||
|
|
69d3b517f3 | ||
|
|
2d1368a908 |
@@ -111,6 +111,18 @@ public class Program {
|
|||||||
}
|
}
|
||||||
currStep += stepIncrement;
|
currStep += stepIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply directional blur
|
||||||
|
var iterations = 10;
|
||||||
|
var radius = 3f;
|
||||||
|
var step = .5f;
|
||||||
|
var sigma = 1f;
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Applying directional blur {i + 1}/{iterations}...");
|
||||||
|
finalImage = DirectionalBlur(finalImage, ImageMasks[0].Mask, radius, step, sigma);
|
||||||
|
}
|
||||||
|
|
||||||
finalImage.SaveImage("final.png");
|
finalImage.SaveImage("final.png");
|
||||||
Console.WriteLine("Done!");
|
Console.WriteLine("Done!");
|
||||||
}
|
}
|
||||||
@@ -175,6 +187,22 @@ public class Program {
|
|||||||
|
|
||||||
return new(temp);
|
return new(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vector3[,] DirectionalBlur(Vector3[,] image, Vector3[,] mask, float radius = 3f, float step = .5f, float sigma = 1f) {
|
||||||
|
var width = (uint)image.GetLength(0);
|
||||||
|
var height = (uint)image.GetLength(1);
|
||||||
|
var output = new Vector3[width, height];
|
||||||
|
|
||||||
|
var sw = new Stopwatch();
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
|
kernels.DirectionalBlur(image, mask, out var temp, radius, step, sigma);
|
||||||
|
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Directional Blur Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static float EuclideanDistance(Vector2 a, Vector2 b) =>
|
private static float EuclideanDistance(Vector2 a, Vector2 b) =>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ILGPU" Version="1.5.2" />
|
<PackageReference Include="ILGPU" Version="1.5.2" />
|
||||||
|
<PackageReference Include="ILGPU.Algorithms" Version="1.5.2" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||||
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
|
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -76,10 +76,64 @@ public partial class SdfKernels {
|
|||||||
ArrayView2D<Vector3, Stride2D.DenseX> sdfb,
|
ArrayView2D<Vector3, Stride2D.DenseX> sdfb,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX> gradient
|
ArrayView2D<Vector3, Stride2D.DenseX> gradient
|
||||||
) { //early exit if not on mask
|
) { //early exit if not on mask
|
||||||
if(mask[index].X == 0f || mask[index].Y > 0f) return;
|
if(mask[index].X == 0f || mask[index].Y == 0f) return;
|
||||||
float a = sdfa[index].X;
|
float a = sdfa[index].X; float b = sdfb[index].X;
|
||||||
float b = sdfb[index].X;
|
gradient[index] = new (a / (a + b));
|
||||||
float result = a / (a + b);
|
|
||||||
gradient[index] = new (result);
|
private static void DirectionalBlurKernel(Index2D index,
|
||||||
|
ArrayView2D<Vector3, Stride2D.DenseX> image,
|
||||||
|
ArrayView2D<Vector3, Stride2D.DenseX> mask,
|
||||||
|
ArrayView2D<Vector3, Stride2D.DenseX> output,
|
||||||
|
float radius, float step, float sigma,
|
||||||
|
int width, int height
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int x = index.X;
|
||||||
|
int y = index.Y;
|
||||||
|
Vector3 value = image[x, y];
|
||||||
|
Vector3 maskValue = mask[x, y];
|
||||||
|
if (maskValue.X == 0f)
|
||||||
|
{
|
||||||
|
output[x, y] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gradient = Vector2.Zero;
|
||||||
|
|
||||||
|
for (int dx = -1; dx <= 1; dx++)
|
||||||
|
{
|
||||||
|
for (int dy = -1; dy <= 1; dy++)
|
||||||
|
{
|
||||||
|
if (x + dx < 0 || x + dx >= width || y + dy < 0 || y + dy >= height) continue;
|
||||||
|
gradient += new Vector2(dx, dy) * image[x + dx, y + dy].X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gradient == Vector2.Zero)
|
||||||
|
{
|
||||||
|
output[x, y] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gradient = Vector2.Normalize(gradient);
|
||||||
|
float sum = 0;
|
||||||
|
|
||||||
|
// now we follow the direction line and sample the image for length;
|
||||||
|
for (float l = -radius; l <= radius; l += step)
|
||||||
|
{
|
||||||
|
int xOffset = (int)(gradient.X * l);
|
||||||
|
int yOffset = (int)(gradient.Y * l);
|
||||||
|
int xSample = x + xOffset;
|
||||||
|
int ySample = y + yOffset;
|
||||||
|
|
||||||
|
if (xSample < 0 || xSample >= width || ySample < 0 || ySample >= height) continue;
|
||||||
|
|
||||||
|
Vector3 sampleValue = image[xSample, ySample];
|
||||||
|
float weight = MathF.Exp(-l * l / (2f * sigma * sigma));
|
||||||
|
output[x, y] += sampleValue * weight;
|
||||||
|
sum += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
output[x, y] /= sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ILGPU.Runtime;
|
|||||||
using ILGPU.Runtime.CPU;
|
using ILGPU.Runtime.CPU;
|
||||||
using ILGPU.Runtime.Cuda;
|
using ILGPU.Runtime.Cuda;
|
||||||
using ILGPU.Runtime.OpenCL;
|
using ILGPU.Runtime.OpenCL;
|
||||||
|
using ILGPU.Algorithms;
|
||||||
|
|
||||||
namespace SDFMapCreator;
|
namespace SDFMapCreator;
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ public partial class SdfKernels {
|
|||||||
.Cuda()
|
.Cuda()
|
||||||
.CPU()
|
.CPU()
|
||||||
.Math(MathMode.Fast32BitOnly)
|
.Math(MathMode.Fast32BitOnly)
|
||||||
|
.EnableAlgorithms()
|
||||||
);
|
);
|
||||||
|
|
||||||
Console.WriteLine("Reading available accelerators (CUDA only)...");
|
Console.WriteLine("Reading available accelerators (CUDA only)...");
|
||||||
@@ -159,6 +161,34 @@ public partial class SdfKernels {
|
|||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
|
||||||
gradient = bufferGradient.GetAsArray2D();
|
gradient = bufferGradient.GetAsArray2D();
|
||||||
|
|
||||||
|
public void DirectionalBlur(Vector3[,] image, Vector3[,] mask, out Vector3[,] output, float radius = 3f, float step = .5f, float sigma = 1f) {
|
||||||
|
var dev = gpuContext.GetPreferredDevice(preferCPU:false);
|
||||||
|
int width = image.GetLength(0);
|
||||||
|
int height = image.GetLength(1);
|
||||||
|
output = new Vector3[width, height];
|
||||||
|
using Accelerator accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
|
using var imageBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
||||||
|
imageBuffer.CopyFromCPU(image);
|
||||||
|
|
||||||
|
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
||||||
|
maskBuffer.CopyFromCPU(mask);
|
||||||
|
|
||||||
|
using var outputBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
||||||
|
|
||||||
|
var blurKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||||
|
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||||
|
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||||
|
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||||
|
float, float, float, int, int>(DirectionalBlurKernel);
|
||||||
|
|
||||||
|
blurKernel(new (width, height), imageBuffer.View, maskBuffer.View, outputBuffer.View,
|
||||||
|
radius, step, sigma, width, height);
|
||||||
|
|
||||||
|
accelerator.Synchronize();
|
||||||
|
|
||||||
|
output = outputBuffer.GetAsArray2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetInfoString(Accelerator a)
|
private static string GetInfoString(Accelerator a)
|
||||||
@@ -167,4 +197,4 @@ public partial class SdfKernels {
|
|||||||
a.PrintInformation(infoString);
|
a.PrintInformation(infoString);
|
||||||
return infoString.ToString();
|
return infoString.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user