public static void RunHorizontal1D(NativeArray <byte> pixelBuffer, NativeArray <float> pixelOut,
                                           Kernel2D <short> kernel, int width, int height)
        {
            var xPad = (kernel.Width - 1) / 2;

            for (var r = 0; r < height; r++)
            {
                var rowIndex = r * width;
                for (var c = xPad; c < width - xPad; c++)
                {
                    var centerPixelIndex = rowIndex + c;
                    var kernelIndex      = 0;
                    var kernelSum        = 0f;
                    for (var kX = -xPad; kX < xPad; kX++)
                    {
                        var   pixelIndex       = centerPixelIndex + kX;
                        var   inputPixelValue  = pixelBuffer[pixelIndex];
                        float kernelMultiplier = kernel.Weights[kernelIndex];
                        kernelSum += inputPixelValue * kernelMultiplier;
                        kernelIndex++;
                    }

                    kernelSum /= 255f;
                    pixelOut[centerPixelIndex] = kernelSum;
                }
            }
        }
        public static void ConvolveVertical(this Kernel2D <byte> kernel,
                                            Image <byte> image, NativeArray <float> pixelOut,
                                            int yPad)
        {
            var pixelBuffer = image.Buffer;
            var width       = image.Width;
            var height      = image.Height;

            for (var r = yPad; r < height - yPad; r++)
            {
                var rowIndex = r * width;
                for (var c = 0; c < width; c++)
                {
                    var centerPixelIndex = rowIndex + c;
                    var kernelIndex      = 0;
                    var kernelSum        = 0f;
                    for (var kY = -yPad; kY < yPad; kY++)
                    {
                        var kRowOffset = kY * width;
                        var pixelIndex = centerPixelIndex + kRowOffset;

                        var   inputPixelValue  = pixelBuffer[pixelIndex];
                        float kernelMultiplier = kernel.Weights[kernelIndex];
                        kernelSum += inputPixelValue * kernelMultiplier;
                        kernelIndex++;
                    }

                    pixelOut[centerPixelIndex] = kernelSum;
                }
            }
        }
        public static float3 Accumulate(this Kernel2D <float> kernel,
                                        Image <float3> image, int centerPixelIndex)
        {
            var kernelIndex   = 0;
            var sum           = new float3();
            var pixelBuffer   = image.Buffer;
            var negativeBound = kernel.Bounds.negative;
            var positiveBound = kernel.Bounds.positive;

            for (var y = negativeBound.y; y <= positiveBound.y; y++)
            {
                var rowOffset = y * image.Width;
                var rowIndex  = centerPixelIndex + rowOffset;
                for (var x = negativeBound.x; x <= positiveBound.x; x++)
                {
                    var pixelIndex       = rowIndex + x;
                    var inputPixelValue  = pixelBuffer[pixelIndex];
                    var kernelMultiplier = kernel.Weights[kernelIndex];
                    sum += inputPixelValue * kernelMultiplier;
                    kernelIndex++;
                }
            }

            return(sum);
        }
        public static void RunVertical1D(NativeArray <float> pixelBuffer, NativeArray <float> pixelOut,
                                         Kernel2D <short> kernel, int width, int height)
        {
            var yPad = (kernel.Height - 1) / 2;

            for (var r = yPad; r < height - yPad; r++)
            {
                var rowIndex = r * width;
                for (var c = 0; c < width; c++)
                {
                    var centerPixelIndex = rowIndex + c;
                    var kernelIndex      = 0;
                    var kernelSum        = 0f;
                    for (var kY = -yPad; kY < yPad; kY++)
                    {
                        var kRowOffset = kY * width;
                        var pixelIndex = centerPixelIndex + kRowOffset;

                        var   inputPixelValue  = pixelBuffer[pixelIndex];
                        float kernelMultiplier = kernel.Weights[kernelIndex];
                        kernelSum += inputPixelValue * kernelMultiplier;
                        kernelIndex++;
                    }

                    pixelOut[centerPixelIndex] = kernelSum;
                }
            }
        }
        public static float Accumulate(this Kernel2D <float> kernel,
                                       Image <byte> image, int centerPixelIndex)
        {
            var kernelIndex   = 0;
            var sum           = 0f;
            var pixelBuffer   = image.Buffer;
            var negativeBound = kernel.Bounds.negative;
            var positiveBound = kernel.Bounds.positive;

            for (var y = negativeBound.y; y <= positiveBound.y; y++)
            {
                var rowOffset = y * image.Width;
                var rowIndex  = centerPixelIndex + rowOffset;
                for (var x = negativeBound.x; x <= positiveBound.x; x++)
                {
                    var pixelIndex       = rowIndex + x;
                    var inputPixelValue  = pixelBuffer[pixelIndex];
                    var kernelMultiplier = kernel.Weights[kernelIndex];
                    sum += inputPixelValue * kernelMultiplier;
                    kernelIndex++;
                }
            }

            //convert from 0-255 byte range to 0-1 float range
            const float oneOver255 = 0.0039215686f;

            return(sum * oneOver255);
        }
        public static void ConvolveHorizontal(this Kernel2D <byte> kernel,
                                              Image <byte> image, NativeArray <float> pixelOut,
                                              int xPad)
        {
            var pixelBuffer = image.Buffer;
            var height      = image.Height;
            var width       = image.Width;

            for (var r = 0; r < height; r++)
            {
                var rowIndex = r * width;
                for (var c = xPad; c < width - xPad; c++)
                {
                    var centerPixelIndex = rowIndex + c;
                    var kernelIndex      = 0;
                    var kernelSum        = 0f;
                    for (var kX = -xPad; kX < xPad; kX++)
                    {
                        var   pixelIndex       = centerPixelIndex + kX;
                        var   inputPixelValue  = pixelBuffer[pixelIndex];
                        float kernelMultiplier = kernel.Weights[kernelIndex];
                        kernelSum += inputPixelValue * kernelMultiplier;
                        kernelIndex++;
                    }

                    kernelSum /= 255f;
                    pixelOut[centerPixelIndex] = kernelSum;
                }
            }
        }
        public static float3 AccumulateVector3(this Kernel2D <float> kernel,
                                               Image <float3> image, int centerPixelIndex)
        {
            var kernelIndex   = 0;
            var sum           = new float3();
            var pixels        = image.Buffer;
            var negativeBound = kernel.Bounds.negative;
            var positiveBound = kernel.Bounds.positive;

            for (var y = negativeBound.y; y <= positiveBound.y; y++)
            {
                var rowOffset = y * image.Width;
                var rowIndex  = centerPixelIndex + rowOffset;
                var rowVec    = new float3x3(pixels[rowIndex - 1], pixels[rowIndex], pixels[rowIndex + 1]);

                var row          = (y + 1);
                var kernelRowVec = new float3(kernel.Weights[row * 3], kernel.Weights[row * 3 + 1], kernel.Weights[row * 3 + 2]);
                sum += math.mul(rowVec, kernelRowVec);
            }

            return(sum);
        }
 public Convolution2D(T[,] kernel, int stride = 1, int pad = 1)
 {
     Kernel2D = new Kernel2D <T>(kernel);
     Stride   = new Vector2Int(stride, stride);
     Padding  = new Vector2Int(pad, pad);
 }
 public Convolution2D(Kernel2D <T> kernel, Vector2Int stride, Vector2Int padding)
 {
     Kernel2D = kernel;
     Stride   = stride;
     Padding  = padding;
 }