using ILGPU; using ILGPU.Runtime; using OpenCvSharp; namespace Hawkeye.VisionBuilder.Workflow.ColorStudioClasses; public static class Kernels { static Kernels() { Init(); AppDomain.CurrentDomain.ProcessExit += Destruct; } private static void Destruct(object? sender, EventArgs e) { _accelerator.Dispose(); _gpuContext.Dispose(); } private static object _lock = new object(); private static ILGPU.Context _gpuContext; private static Accelerator _accelerator; private static Action, ArrayView, ArrayView> _spatialKernel; private static Action, ArrayView> _dilationKernel; public static Action, ArrayView, ArrayView> SpatialKernel => _spatialKernel; public static Action, ArrayView> Dilation => _dilationKernel; public static Accelerator Accelerator { get => _accelerator; set => _accelerator = value; } static Dictionary> _imageCache = new (); public static unsafe MemoryBuffer1D TransformImageCached(Mat image) { if (_imageCache.ContainsKey(image)) return _imageCache[image]; var imageBytes = new Span(image.DataPointer, image.Width * image.Height * 3); var res=Kernels.Accelerator.Allocate1D(imageBytes.ToArray()); _imageCache[image] = res; return res; } static void Init() { lock (_lock) { if (_gpuContext != null) return; _gpuContext = ILGPU.Context.Create(builder => builder.AllAccelerators()); _accelerator = _gpuContext.Devices.First(x => x.AcceleratorType == AcceleratorType.Cuda) .CreateAccelerator(_gpuContext); Console.WriteLine("GPU acceleration initialized"); _spatialKernel = _accelerator .LoadAutoGroupedStreamKernel, ArrayView, ArrayView>( Kernels.TransformSpatialKernel); _dilationKernel = _accelerator .LoadAutoGroupedStreamKernel,ArrayView>( Kernels.DilationKernel); } } private static void TransformSpatialKernel(Index1D index, int w, int mw, ArrayView candyBytes, ArrayView maskBytes, ArrayView res) { var i = index; var p = i * 3; var y = p / w; var x = p % w; var yp = (int)candyBytes[p + 0]; var xp = candyBytes[p + 1]; var vp = (byte)(candyBytes[p + 2] / 5f) * 255; var hp = yp + vp; var maskColor = maskBytes[hp * mw + xp]; if (maskColor > 0) res[i] = 255; else res[i] = 0; } private static void DilationKernel(Index1D index, int w, int size, ArrayView maskBytes, ArrayView res) { var i = index; var p = i ; var y = p / w; var x = p % w; var halfSize = size-1 / 2; if (maskBytes[p] > 0) { for (int j = -halfSize; j <= halfSize; j++) { for (int k = -halfSize; k <= halfSize; k++) { var yp = y + j; var xp = x + k; if (yp < 0 || yp >= w || xp < 0 || xp >= w) continue; res[yp * w + xp] = 255; } } } } private static void ErosionKernel(Index1D index, int w, int size, ArrayView maskBytes, ArrayView res) { var i = index; var p = i ; var y = p / w; var x = p % w; var halfSize = size-1 / 2; if (maskBytes[p] <255) { for (int j = -halfSize; j <= halfSize; j++) { for (int k = -halfSize; k <= halfSize; k++) { var yp = y + j; var xp = x + k; if (yp < 0 || yp >= w || xp < 0 || xp >= w) continue; res[yp * w + xp] = 0; } } } } }