mirror of https://github.com/SixLabors/ImageSharp
4 changed files with 34 additions and 427 deletions
@ -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 |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods to perform convolution operations.
|
|
||||
/// </summary>
|
|
||||
internal static class Convolver |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Computes the sum of vectors in the span referenced by <paramref name="targetRowRef"/> weighted by the two kernel weight values.
|
|
||||
/// Using this method the convolution filter is not applied to alpha in addition to the color channels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
/// <param name="state">The 2D convolution kernels state.</param>
|
|
||||
/// <param name="sourcePixels">The source frame.</param>
|
|
||||
/// <param name="targetRowRef">The target row base reference.</param>
|
|
||||
/// <param name="row">The current row.</param>
|
|
||||
/// <param name="column">The current column.</param>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static void Convolve2D3<TPixel>( |
|
||||
in Convolution2DState state, |
|
||||
Buffer2D<TPixel> sourcePixels, |
|
||||
ref Vector4 targetRowRef, |
|
||||
int row, |
|
||||
int column) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Computes the sum of vectors in the span referenced by <paramref name="targetRowRef"/> weighted by the two kernel weight values.
|
|
||||
/// Using this method the convolution filter is applied to alpha in addition to the color channels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
/// <param name="state">The 2D convolution kernels state.</param>
|
|
||||
/// <param name="sourcePixels">The source frame.</param>
|
|
||||
/// <param name="targetRowRef">The target row base reference.</param>
|
|
||||
/// <param name="row">The current row.</param>
|
|
||||
/// <param name="column">The current column.</param>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static void Convolve2D4<TPixel>( |
|
||||
in Convolution2DState state, |
|
||||
Buffer2D<TPixel> sourcePixels, |
|
||||
ref Vector4 targetRowRef, |
|
||||
int row, |
|
||||
int column) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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<TPixel>( |
|
||||
in Convolution2DState state, |
|
||||
Buffer2D<TPixel> sourcePixels, |
|
||||
int row, |
|
||||
int column, |
|
||||
ref Vector4 targetVector) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Computes the sum of vectors in the span referenced by <paramref name="targetRowRef"/> weighted by the kernel weight values.
|
|
||||
/// Using this method the convolution filter is not applied to alpha in addition to the color channels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
/// <param name="state">The convolution kernel state.</param>
|
|
||||
/// <param name="sourcePixels">The source frame.</param>
|
|
||||
/// <param name="targetRowRef">The target row base reference.</param>
|
|
||||
/// <param name="row">The current row.</param>
|
|
||||
/// <param name="column">The current column.</param>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static void Convolve3<TPixel>( |
|
||||
in ConvolutionState state, |
|
||||
Buffer2D<TPixel> sourcePixels, |
|
||||
ref Vector4 targetRowRef, |
|
||||
int row, |
|
||||
int column) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Computes the sum of vectors in the span referenced by <paramref name="targetRowRef"/> weighted by the kernel weight values.
|
|
||||
/// Using this method the convolution filter is applied to alpha in addition to the color channels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
/// <param name="state">The convolution kernel state.</param>
|
|
||||
/// <param name="sourcePixels">The source frame.</param>
|
|
||||
/// <param name="targetRowRef">The target row base reference.</param>
|
|
||||
/// <param name="row">The current row.</param>
|
|
||||
/// <param name="column">The current column.</param>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static void Convolve4<TPixel>( |
|
||||
in ConvolutionState state, |
|
||||
Buffer2D<TPixel> sourcePixels, |
|
||||
ref Vector4 targetRowRef, |
|
||||
int row, |
|
||||
int column) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Computes the sum of vectors in the span referenced by <paramref name="sourceRow"/> weighted
|
|
||||
/// by the kernel weight values.
|
|
||||
/// Using this method the convolution filter is not applied to alpha in addition
|
|
||||
/// to the color channels.
|
|
||||
/// </summary>
|
|
||||
/// <param name="state">The convolution kernel state.</param>
|
|
||||
/// <param name="sourceRow">The source row.</param>
|
|
||||
/// <param name="targetRow">The target row.</param>
|
|
||||
/// <param name="kY">The current kernel row.</param>
|
|
||||
/// <param name="bX">The interest x-bounds relative to the interest image.</param>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static void ConvolveRow3( |
|
||||
in ConvolutionState state, |
|
||||
Span<Vector4> sourceRow, |
|
||||
Span<Vector4> 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; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Computes the sum of vectors in the span referenced by <paramref name="sourceRow"/> weighted
|
|
||||
/// by the kernel weight values.
|
|
||||
/// Using this method the convolution filter is applied to alpha in addition to the
|
|
||||
/// color channels.
|
|
||||
/// </summary>
|
|
||||
/// <param name="state">The convolution kernel state.</param>
|
|
||||
/// <param name="sourceRow">The source row.</param>
|
|
||||
/// <param name="targetRow">The target row.</param>
|
|
||||
/// <param name="kY">The current kernel row.</param>
|
|
||||
/// <param name="bX">The interest x-bounds relative to the interest image.</param>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static void ConvolveRow4<TPixel>( |
|
||||
in ConvolutionState state, |
|
||||
Span<Vector4> sourceRow, |
|
||||
Span<Vector4> targetRow, |
|
||||
int kY, |
|
||||
int bX) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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<TPixel>( |
|
||||
in ConvolutionState state, |
|
||||
Buffer2D<TPixel> sourcePixels, |
|
||||
int row, |
|
||||
int column, |
|
||||
ref Vector4 targetVector) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
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; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue