mirror of https://github.com/SixLabors/ImageSharp
9 changed files with 225 additions and 108 deletions
@ -0,0 +1,54 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A stack only struct used for reducing reference indirection during 2D convolution operations.
|
||||
|
/// </summary>
|
||||
|
internal readonly ref struct Convolution2DState |
||||
|
{ |
||||
|
private readonly Span<int> rowOffsetMap; |
||||
|
private readonly Span<int> columnOffsetMap; |
||||
|
private readonly int kernelHeight; |
||||
|
private readonly int kernelWidth; |
||||
|
|
||||
|
public Convolution2DState( |
||||
|
in DenseMatrix<float> kernelY, |
||||
|
in DenseMatrix<float> kernelX, |
||||
|
KernelSamplingMap map) |
||||
|
{ |
||||
|
// We check the kernels are the same size upstream.
|
||||
|
this.KernelY = new ReadOnlyKernel(kernelY); |
||||
|
this.KernelX = new ReadOnlyKernel(kernelX); |
||||
|
this.kernelHeight = kernelY.Rows; |
||||
|
this.kernelWidth = kernelY.Columns; |
||||
|
this.rowOffsetMap = map.GetRowOffsetSpan(); |
||||
|
this.columnOffsetMap = map.GetColumnOffsetSpan(); |
||||
|
} |
||||
|
|
||||
|
public ReadOnlyKernel KernelY |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get; |
||||
|
} |
||||
|
|
||||
|
public ReadOnlyKernel KernelX |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public int GetRowSampleOffset(int row, int kernelRow) |
||||
|
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (row * this.kernelHeight) + kernelRow); |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public int GetColumnSampleOffset(int column, int kernelColumn) |
||||
|
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (column * this.kernelWidth) + kernelColumn); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A stack only struct used for reducing reference indirection during convolution operations.
|
||||
|
/// </summary>
|
||||
|
internal readonly ref struct ConvolutionState |
||||
|
{ |
||||
|
private readonly Span<int> rowOffsetMap; |
||||
|
private readonly Span<int> columnOffsetMap; |
||||
|
private readonly int kernelHeight; |
||||
|
private readonly int kernelWidth; |
||||
|
|
||||
|
public ConvolutionState( |
||||
|
in DenseMatrix<float> kernel, |
||||
|
KernelSamplingMap map) |
||||
|
{ |
||||
|
this.Kernel = new ReadOnlyKernel(kernel); |
||||
|
this.kernelHeight = kernel.Rows; |
||||
|
this.kernelWidth = kernel.Columns; |
||||
|
this.rowOffsetMap = map.GetRowOffsetSpan(); |
||||
|
this.columnOffsetMap = map.GetColumnOffsetSpan(); |
||||
|
} |
||||
|
|
||||
|
public ReadOnlyKernel Kernel |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public int GetRowSampleOffset(int row, int kernelRow) |
||||
|
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (row * this.kernelHeight) + kernelRow); |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public int GetColumnSampleOffset(int column, int kernelColumn) |
||||
|
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (column * this.kernelWidth) + kernelColumn); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A stack only, readonly, kernel matrix that can be indexed without
|
||||
|
/// bounds checks when compiled in release mode.
|
||||
|
/// </summary>
|
||||
|
internal readonly ref struct ReadOnlyKernel |
||||
|
{ |
||||
|
private readonly ReadOnlySpan<float> values; |
||||
|
|
||||
|
public ReadOnlyKernel(DenseMatrix<float> matrix) |
||||
|
{ |
||||
|
this.Columns = matrix.Columns; |
||||
|
this.Rows = matrix.Rows; |
||||
|
this.values = matrix.Span; |
||||
|
} |
||||
|
|
||||
|
public int Columns |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get; |
||||
|
} |
||||
|
|
||||
|
public int Rows |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get; |
||||
|
} |
||||
|
|
||||
|
public float this[int row, int column] |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get |
||||
|
{ |
||||
|
this.CheckCoordinates(row, column); |
||||
|
ref float vBase = ref MemoryMarshal.GetReference(this.values); |
||||
|
return Unsafe.Add(ref vBase, (row * this.Columns) + column); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Conditional("DEBUG")] |
||||
|
private void CheckCoordinates(int row, int column) |
||||
|
{ |
||||
|
if (row < 0 || row >= this.Rows) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the matrix bounds."); |
||||
|
} |
||||
|
|
||||
|
if (column < 0 || column >= this.Columns) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outwith the matrix bounds."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue