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