Browse Source

Update to match new build rules.

pull/2219/head
James Jackson-South 4 years ago
parent
commit
b6fb196982
  1. 33
      src/ImageSharp/Processing/Processors/Convolution/Kernel.cs
  2. 9
      src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs
  3. 21
      src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs

33
src/ImageSharp/Processing/Processors/Convolution/Kernel.cs

@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// A stack only, readonly, kernel matrix that can be indexed without
/// bounds checks when compiled in release mode.
/// </summary>
/// <typeparam name="T">The type of each element in the kernel.</typeparam>
internal readonly ref struct Kernel<T>
where T : struct, IEquatable<T>
{
@ -39,10 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
public ReadOnlySpan<T> Span
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.values;
}
get => this.values;
}
public T this[int row, int column]
@ -54,26 +52,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref T vBase = ref MemoryMarshal.GetReference(this.values);
return Unsafe.Add(ref vBase, (row * this.Columns) + column);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetValue(int row, int column, T value)
{
this.SetValue((row * this.Columns) + column, value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.CheckCoordinates(row, column);
ref T vBase = ref MemoryMarshal.GetReference(this.values);
Unsafe.Add(ref vBase, (row * this.Columns) + column) = value;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetValue(int index, T value)
{
this.CheckIndex(index);
ref T vBase = ref MemoryMarshal.GetReference(this.values);
Unsafe.Add(ref vBase, index) = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
this.values.Clear();
}
public void Clear() => this.values.Clear();
[Conditional("DEBUG")]
private void CheckCoordinates(int row, int column)
@ -88,5 +86,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outside the matrix bounds.");
}
}
[Conditional("DEBUG")]
private void CheckIndex(int index)
{
if (index < 0 || index >= this.values.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), index, $"{index} is outside the matrix bounds.");
}
}
}
}

9
src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Applies an median filter.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal sealed class MedianBlurProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -28,17 +29,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
source.CopyTo(targetPixels);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
Rectangle interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// We use a rectangle with width set wider, to allocate a buffer big enough
// for kernel source, channel buffers, source rows and target bulk pixel conversion.
int operationWidth = (2 * kernelSize * kernelSize) + interest.Width + (kernelSize * interest.Width);
var operationBounds = new Rectangle(interest.X, interest.Y, operationWidth, interest.Height);
Rectangle operationBounds = new(interest.X, interest.Y, operationWidth, interest.Height);
using var map = new KernelSamplingMap(this.Configuration.MemoryAllocator);
using KernelSamplingMap map = new(this.Configuration.MemoryAllocator);
map.BuildSamplingOffsetMap(kernelSize, kernelSize, interest, this.definition.BorderWrapModeX, this.definition.BorderWrapModeY);
var operation = new MedianRowOperation<TPixel>(
MedianRowOperation<TPixel> operation = new(
interest,
targetPixels,
source.PixelBuffer,

21
src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs

@ -14,6 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Applies an median filter.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal readonly struct MedianRowOperation<TPixel> : IRowOperation<Vector4>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -49,21 +50,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int boundsX = this.bounds.X;
int boundsWidth = this.bounds.Width;
int kernelCount = this.kernelSize * this.kernelSize;
Span<Vector4> kernelBuffer = span.Slice(0, kernelCount);
Span<Vector4> kernelBuffer = span[..kernelCount];
Span<Vector4> channelVectorBuffer = span.Slice(kernelCount, kernelCount);
Span<Vector4> sourceVectorBuffer = span.Slice(kernelCount << 1, this.kernelSize * boundsWidth);
Span<Vector4> targetBuffer = span.Slice((kernelCount << 1) + sourceVectorBuffer.Length, boundsWidth);
// Stack 4 channels of floats in the space of Vector4's.
Span<float> channelBuffer = MemoryMarshal.Cast<Vector4, float>(channelVectorBuffer);
Span<float> xChannel = channelBuffer.Slice(0, kernelCount);
Span<float> xChannel = channelBuffer[..kernelCount];
Span<float> yChannel = channelBuffer.Slice(this.yChannelStart, kernelCount);
Span<float> zChannel = channelBuffer.Slice(this.zChannelStart, kernelCount);
var kernel = new DenseMatrix<Vector4>(this.kernelSize, this.kernelSize, kernelBuffer);
DenseMatrix<Vector4> kernel = new(this.kernelSize, this.kernelSize, kernelBuffer);
int row = y - this.bounds.Y;
var state = new MedianConvolutionState(in kernel, this.map);
MedianConvolutionState state = new(in kernel, this.map);
ref int sampleRowBase = ref state.GetSampleRow(row);
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
@ -85,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
for (int kY = 0; kY < state.Kernel.Rows; kY++)
{
Span<Vector4> sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
Span<Vector4> sourceRow = sourceVectorBuffer[(kY * boundsWidth)..];
ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
{
@ -96,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
}
target = this.FindMedian3(state.Kernel.Span, xChannel, yChannel, zChannel, kernelCount);
target = FindMedian3(state.Kernel.Span, xChannel, yChannel, zChannel);
}
}
else
@ -109,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
for (int kY = 0; kY < state.Kernel.Rows; kY++)
{
Span<Vector4> sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
Span<Vector4> sourceRow = sourceVectorBuffer[(kY * boundsWidth)..];
ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
{
@ -120,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
}
target = this.FindMedian4(state.Kernel.Span, xChannel, yChannel, zChannel, wChannel, kernelCount);
target = FindMedian4(state.Kernel.Span, xChannel, yChannel, zChannel, wChannel);
}
}
@ -129,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 FindMedian3(ReadOnlySpan<Vector4> kernelSpan, Span<float> xChannel, Span<float> yChannel, Span<float> zChannel, int stride)
private static Vector4 FindMedian3(ReadOnlySpan<Vector4> kernelSpan, Span<float> xChannel, Span<float> yChannel, Span<float> zChannel)
{
int halfLength = (kernelSpan.Length + 1) >> 1;
@ -152,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 FindMedian4(ReadOnlySpan<Vector4> kernelSpan, Span<float> xChannel, Span<float> yChannel, Span<float> zChannel, Span<float> wChannel, int stride)
private static Vector4 FindMedian4(ReadOnlySpan<Vector4> kernelSpan, Span<float> xChannel, Span<float> yChannel, Span<float> zChannel, Span<float> wChannel)
{
int halfLength = (kernelSpan.Length + 1) >> 1;

Loading…
Cancel
Save