From a4ff07edd2b02ea194584772e56df7d7fde73d34 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 7 Dec 2020 14:53:47 +0000 Subject: [PATCH] Cleanup --- .../Convolution2DProcessor{TPixel}.cs | 78 ----- .../Convolution2DRowOperation{TPixel}.cs | 36 +- .../ConvolutionRowOperation{TPixel}.cs | 38 +-- .../Processors/Convolution/Convolver.cs | 309 ------------------ 4 files changed, 34 insertions(+), 427 deletions(-) delete mode 100644 src/ImageSharp/Processing/Processors/Convolution/Convolver.cs diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index e787b3ec7..bb559019b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -1,10 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -94,80 +91,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } - - /// - /// A implementing the convolution logic for . - /// - private readonly struct RowOperation : IRowOperation - { - private readonly Rectangle bounds; - private readonly Buffer2D targetPixels; - private readonly Buffer2D sourcePixels; - private readonly KernelSamplingMap map; - private readonly DenseMatrix kernelY; - private readonly DenseMatrix kernelX; - private readonly Configuration configuration; - private readonly bool preserveAlpha; - - [MethodImpl(InliningOptions.ShortMethod)] - public RowOperation( - Rectangle bounds, - Buffer2D targetPixels, - Buffer2D sourcePixels, - KernelSamplingMap map, - DenseMatrix kernelY, - DenseMatrix kernelX, - Configuration configuration, - bool preserveAlpha) - { - this.bounds = bounds; - this.targetPixels = targetPixels; - this.sourcePixels = sourcePixels; - this.map = map; - this.kernelY = kernelY; - this.kernelX = kernelX; - this.configuration = configuration; - this.preserveAlpha = preserveAlpha; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(int y, Span span) - { - ref Vector4 targetRowRef = ref MemoryMarshal.GetReference(span); - Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); - - var state = new Convolution2DState(this.kernelY, this.kernelX, this.map); - int row = y - this.bounds.Y; - - if (this.preserveAlpha) - { - for (int column = 0; column < this.bounds.Width; column++) - { - Convolver.Convolve2D3( - in state, - this.sourcePixels, - ref targetRowRef, - row, - column); - } - } - else - { - for (int column = 0; column < this.bounds.Width; column++) - { - Convolver.Convolve2D4( - in state, - this.sourcePixels, - ref targetRowRef, - row, - column); - } - } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); - } - } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs index 6528a2f85..802d1809f 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs @@ -72,10 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Span targetXBuffer = span.Slice(boundsWidth * 2, boundsWidth); var state = new Convolution2DState(in this.kernelMatrixY, in this.kernelMatrixX, this.map); - ReadOnlyKernel kernelY = state.KernelY; - ReadOnlyKernel kernelX = state.KernelX; - int row = y - this.bounds.Y; - ref int sampleRowBase = ref state.GetSampleRow(row); + ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); // Clear the target buffers for each row run. targetYBuffer.Clear(); @@ -83,12 +80,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ref Vector4 targetBaseY = ref MemoryMarshal.GetReference(targetYBuffer); ref Vector4 targetBaseX = ref MemoryMarshal.GetReference(targetXBuffer); + ReadOnlyKernel kernelY = state.KernelY; + ReadOnlyKernel kernelX = state.KernelX; Span sourceRow; for (int kY = 0; kY < kernelY.Rows; kY++) { // Get the precalculated source sample row for this kernel row and copy to our buffer. - int offsetY = Unsafe.Add(ref sampleRowBase, kY); - sourceRow = this.sourcePixels.GetRowSpan(offsetY).Slice(boundsX, boundsWidth); + int sampleY = Unsafe.Add(ref sampleRowBase, kY); + sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth); PixelOperations.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); @@ -101,15 +100,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int kX = 0; kX < kernelY.Columns; kX++) { - int offsetX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; - Vector4 sample = Unsafe.Add(ref sourceBase, offsetX); + int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; + Vector4 sample = Unsafe.Add(ref sourceBase, sampleX); targetY += kernelX[kY, kX] * sample; targetX += kernelY[kY, kX] * sample; } } } - // Now we need to combine the values and copy the original alpha values from the source row. + // Now we need to combine the values and copy the original alpha values + // from the source row. sourceRow = this.sourcePixels.GetRowSpan(y).Slice(boundsX, boundsWidth); PixelOperations.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Convolve4(int y, Span span) { - // Span is 2x bounds. + // Span is 3x bounds. int boundsX = this.bounds.X; int boundsWidth = this.bounds.Width; Span sourceBuffer = span.Slice(0, boundsWidth); @@ -138,10 +138,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Span targetXBuffer = span.Slice(boundsWidth * 2, boundsWidth); var state = new Convolution2DState(in this.kernelMatrixY, in this.kernelMatrixX, this.map); - ReadOnlyKernel kernelY = state.KernelY; - ReadOnlyKernel kernelX = state.KernelX; - int row = y - this.bounds.Y; - ref int sampleRowBase = ref state.GetSampleRow(row); + ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); // Clear the target buffers for each row run. targetYBuffer.Clear(); @@ -149,11 +146,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ref Vector4 targetBaseY = ref MemoryMarshal.GetReference(targetYBuffer); ref Vector4 targetBaseX = ref MemoryMarshal.GetReference(targetXBuffer); + ReadOnlyKernel kernelY = state.KernelY; + ReadOnlyKernel kernelX = state.KernelX; for (int kY = 0; kY < kernelY.Rows; kY++) { // Get the precalculated source sample row for this kernel row and copy to our buffer. - int offsetY = Unsafe.Add(ref sampleRowBase, kY); - Span sourceRow = this.sourcePixels.GetRowSpan(offsetY).Slice(boundsX, boundsWidth); + int sampleY = Unsafe.Add(ref sampleRowBase, kY); + Span sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth); PixelOperations.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); Numerics.Premultiply(sourceBuffer); @@ -167,14 +166,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int kX = 0; kX < kernelY.Columns; kX++) { - int offsetX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; - Vector4 sample = Unsafe.Add(ref sourceBase, offsetX); + int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; + Vector4 sample = Unsafe.Add(ref sourceBase, sampleX); targetY += kernelX[kY, kX] * sample; targetX += kernelY[kY, kX] * sample; } } } + // Now we need to combine the values for (int x = 0; x < targetYBuffer.Length; x++) { ref Vector4 target = ref Unsafe.Add(ref targetBaseY, x); diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionRowOperation{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionRowOperation{TPixel}.cs index 82aecdaf7..9876b2885 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionRowOperation{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionRowOperation{TPixel}.cs @@ -67,24 +67,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Span sourceBuffer = span.Slice(0, this.bounds.Width); Span targetBuffer = span.Slice(this.bounds.Width); - ref Vector4 targetRowRef = ref MemoryMarshal.GetReference(span); - Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); - var state = new ConvolutionState(in this.kernelMatrix, this.map); - ReadOnlyKernel kernel = state.Kernel; - int row = y - this.bounds.Y; - ref int sampleRowBase = ref state.GetSampleRow(row); + ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); // Clear the target buffer for each row run. targetBuffer.Clear(); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); + ReadOnlyKernel kernel = state.Kernel; Span sourceRow; for (int kY = 0; kY < kernel.Rows; kY++) { // Get the precalculated source sample row for this kernel row and copy to our buffer. - int offsetY = Unsafe.Add(ref sampleRowBase, kY); - sourceRow = this.sourcePixels.GetRowSpan(offsetY).Slice(boundsX, boundsWidth); + int sampleY = Unsafe.Add(ref sampleRowBase, kY); + sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth); PixelOperations.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); @@ -96,8 +92,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int kX = 0; kX < kernel.Columns; kX++) { - int offsetX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; - Vector4 sample = Unsafe.Add(ref sourceBase, offsetX); + int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; + Vector4 sample = Unsafe.Add(ref sourceBase, sampleX); target += kernel[kY, kX] * sample; } } @@ -113,7 +109,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), x).W; } - PixelOperations.Instance.FromVector4Destructive(this.configuration, targetBuffer, targetRowSpan); + Span targetRow = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); + PixelOperations.Instance.FromVector4Destructive(this.configuration, targetBuffer, targetRow); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -125,23 +122,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Span sourceBuffer = span.Slice(0, this.bounds.Width); Span targetBuffer = span.Slice(this.bounds.Width); - ref Vector4 targetRowRef = ref MemoryMarshal.GetReference(span); - Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); - var state = new ConvolutionState(in this.kernelMatrix, this.map); - ReadOnlyKernel kernel = state.Kernel; - int row = y - this.bounds.Y; - ref int sampleRowBase = ref state.GetSampleRow(row); + ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); // Clear the target buffer for each row run. targetBuffer.Clear(); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); + ReadOnlyKernel kernel = state.Kernel; for (int kY = 0; kY < kernel.Rows; kY++) { // Get the precalculated source sample row for this kernel row and copy to our buffer. - int offsetY = Unsafe.Add(ref sampleRowBase, kY); - Span sourceRow = this.sourcePixels.GetRowSpan(offsetY).Slice(boundsX, boundsWidth); + int sampleY = Unsafe.Add(ref sampleRowBase, kY); + Span sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth); PixelOperations.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); Numerics.Premultiply(sourceBuffer); @@ -154,8 +147,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int kX = 0; kX < kernel.Columns; kX++) { - int offsetX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; - Vector4 sample = Unsafe.Add(ref sourceBase, offsetX); + int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; + Vector4 sample = Unsafe.Add(ref sourceBase, sampleX); target += kernel[kY, kX] * sample; } } @@ -163,7 +156,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Numerics.UnPremultiply(targetBuffer); - PixelOperations.Instance.FromVector4Destructive(this.configuration, targetBuffer, targetRowSpan); + Span targetRow = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); + PixelOperations.Instance.FromVector4Destructive(this.configuration, targetBuffer, targetRow); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs deleted file mode 100644 index 721f7bbad..000000000 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Convolution; - -namespace SixLabors.ImageSharp -{ - /// - /// Provides methods to perform convolution operations. - /// - internal static class Convolver - { - /// - /// Computes the sum of vectors in the span referenced by weighted by the two kernel weight values. - /// Using this method the convolution filter is not applied to alpha in addition to the color channels. - /// - /// The pixel format. - /// The 2D convolution kernels state. - /// The source frame. - /// The target row base reference. - /// The current row. - /// The current column. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Convolve2D3( - in Convolution2DState state, - Buffer2D sourcePixels, - ref Vector4 targetRowRef, - int row, - int column) - where TPixel : unmanaged, IPixel - { - Vector4 vector = default; - - Convolve2DImpl( - in state, - sourcePixels, - row, - column, - ref vector); - - ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - vector.W = target.W; - - Numerics.UnPremultiply(ref vector); - target = vector; - } - - /// - /// Computes the sum of vectors in the span referenced by weighted by the two kernel weight values. - /// Using this method the convolution filter is applied to alpha in addition to the color channels. - /// - /// The pixel format. - /// The 2D convolution kernels state. - /// The source frame. - /// The target row base reference. - /// The current row. - /// The current column. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Convolve2D4( - in Convolution2DState state, - Buffer2D sourcePixels, - ref Vector4 targetRowRef, - int row, - int column) - where TPixel : unmanaged, IPixel - { - Vector4 vector = default; - - Convolve2DImpl( - in state, - sourcePixels, - row, - column, - ref vector); - - ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - Numerics.UnPremultiply(ref vector); - target = vector; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Convolve2DImpl( - in Convolution2DState state, - Buffer2D sourcePixels, - int row, - int column, - ref Vector4 targetVector) - where TPixel : unmanaged, IPixel - { - ReadOnlyKernel kernelY = state.KernelY; - ReadOnlyKernel kernelX = state.KernelX; - int kernelHeight = kernelY.Rows; - int kernelWidth = kernelY.Columns; - - Vector4 vectorY = default; - Vector4 vectorX = default; - - ref int sampleOffsetRowBase = ref state.GetSampleRow(row); - for (int y = 0; y < kernelHeight; y++) - { - int offsetY = Unsafe.Add(ref sampleOffsetRowBase, y); - ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourcePixels.GetRowSpan(offsetY)); - ref int sampleOffsetColumnBase = ref state.GetSampleColumn(column); - - for (int x = 0; x < kernelWidth; x++) - { - int offsetX = Unsafe.Add(ref sampleOffsetColumnBase, x); - var sample = Unsafe.Add(ref sourceRowBase, offsetX).ToVector4(); - Numerics.Premultiply(ref sample); - vectorX += kernelX[y, x] * sample; - vectorY += kernelY[y, x] * sample; - } - } - - targetVector = Vector4.SquareRoot((vectorX * vectorX) + (vectorY * vectorY)); - } - - /// - /// Computes the sum of vectors in the span referenced by weighted by the kernel weight values. - /// Using this method the convolution filter is not applied to alpha in addition to the color channels. - /// - /// The pixel format. - /// The convolution kernel state. - /// The source frame. - /// The target row base reference. - /// The current row. - /// The current column. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Convolve3( - in ConvolutionState state, - Buffer2D sourcePixels, - ref Vector4 targetRowRef, - int row, - int column) - where TPixel : unmanaged, IPixel - { - Vector4 vector = default; - - ConvolveImpl( - state, - sourcePixels, - row, - column, - ref vector); - - ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - vector.W = target.W; - - Numerics.UnPremultiply(ref vector); - target = vector; - } - - /// - /// Computes the sum of vectors in the span referenced by weighted by the kernel weight values. - /// Using this method the convolution filter is applied to alpha in addition to the color channels. - /// - /// The pixel format. - /// The convolution kernel state. - /// The source frame. - /// The target row base reference. - /// The current row. - /// The current column. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Convolve4( - in ConvolutionState state, - Buffer2D sourcePixels, - ref Vector4 targetRowRef, - int row, - int column) - where TPixel : unmanaged, IPixel - { - Vector4 vector = default; - - ConvolveImpl( - state, - sourcePixels, - row, - column, - ref vector); - - ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - Numerics.UnPremultiply(ref vector); - target = vector; - } - - /// - /// Computes the sum of vectors in the span referenced by weighted - /// by the kernel weight values. - /// Using this method the convolution filter is not applied to alpha in addition - /// to the color channels. - /// - /// The convolution kernel state. - /// The source row. - /// The target row. - /// The current kernel row. - /// The interest x-bounds relative to the interest image. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvolveRow3( - in ConvolutionState state, - Span sourceRow, - Span targetRow, - int kY, - int bX) - { - ReadOnlyKernel kernel = state.Kernel; - ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceRow); - ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetRow); - - Numerics.Premultiply(sourceRow); - - for (int x = 0; x < sourceRow.Length; x++) - { - Vector4 vector = default; - ref int sampleOffsetColumnBase = ref state.GetSampleColumn(x); - - for (int kX = 0; kX < kernel.Columns; kX++) - { - int offsetX = Unsafe.Add(ref sampleOffsetColumnBase, kX) - bX; - Vector4 sample = Unsafe.Add(ref sourceBase, offsetX); - vector += kernel[kY, kX] * sample; - } - - ref Vector4 target = ref Unsafe.Add(ref targetBase, x); - vector.W = target.W; - Numerics.UnPremultiply(ref vector); - target = vector; - } - } - - /// - /// Computes the sum of vectors in the span referenced by weighted - /// by the kernel weight values. - /// Using this method the convolution filter is applied to alpha in addition to the - /// color channels. - /// - /// The convolution kernel state. - /// The source row. - /// The target row. - /// The current kernel row. - /// The interest x-bounds relative to the interest image. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ConvolveRow4( - in ConvolutionState state, - Span sourceRow, - Span targetRow, - int kY, - int bX) - where TPixel : unmanaged, IPixel - { - ReadOnlyKernel kernel = state.Kernel; - - ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceRow); - ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetRow); - - Numerics.Premultiply(sourceRow); - - for (int x = 0; x < sourceRow.Length; x++) - { - ref int sampleOffsetColumnBase = ref state.GetSampleColumn(x); - ref Vector4 target = ref Unsafe.Add(ref targetBase, x); - - for (int kX = 0; kX < kernel.Columns; kX++) - { - int offsetX = Unsafe.Add(ref sampleOffsetColumnBase, kX) - bX; - Vector4 sample = Unsafe.Add(ref sourceBase, offsetX); - target += kernel[kY, kX] * sample; - } - } - - Numerics.UnPremultiply(targetRow); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ConvolveImpl( - in ConvolutionState state, - Buffer2D sourcePixels, - int row, - int column, - ref Vector4 targetVector) - where TPixel : unmanaged, IPixel - { - ReadOnlyKernel kernel = state.Kernel; - int kernelHeight = kernel.Rows; - int kernelWidth = kernel.Columns; - - ref int sampleOffsetRowBase = ref state.GetSampleRow(row); - for (int y = 0; y < kernelHeight; y++) - { - int offsetY = Unsafe.Add(ref sampleOffsetRowBase, y); - ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourcePixels.GetRowSpan(offsetY)); - ref int sampleOffsetColumnBase = ref state.GetSampleColumn(column); - - for (int x = 0; x < kernelWidth; x++) - { - int offsetX = Unsafe.Add(ref sampleOffsetColumnBase, x); - var sample = Unsafe.Add(ref sourceRowBase, offsetX).ToVector4(); - Numerics.Premultiply(ref sample); - targetVector += kernel[y, x] * sample; - } - } - } - } -}