Browse Source

Bulk convert source rows to Vector4

pull/2219/head
Ynse Hoornenborg 4 years ago
parent
commit
bc1162e05b
  1. 11
      src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs
  2. 32
      src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs

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

@ -17,10 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly MedianBlurProcessor definition;
public MedianBlurProcessor(Configuration configuration, MedianBlurProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}
: base(configuration, source, sourceRectangle) => this.definition = definition;
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
@ -31,13 +28,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
source.CopyTo(targetPixels);
Rectangle interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// We use a rectangle with width set to 2 * kernelSize^2 + width, to allocate a buffer big enough
// for kernel source and target bulk pixel conversion.
Rectangle operationBounds = new Rectangle(interest.X, interest.Y, (2 * (kernelSize * kernelSize)) + interest.Width, interest.Height);
var operationBounds = new Rectangle(interest.X, interest.Y, (2 * kernelSize * kernelSize) + interest.Width + (kernelSize * interest.Width), interest.Height);
using KernelSamplingMap map = new KernelSamplingMap(this.Configuration.MemoryAllocator);
using var map = new KernelSamplingMap(this.Configuration.MemoryAllocator);
map.BuildSamplingOffsetMap(kernelSize, kernelSize, interest, this.definition.BorderWrapModeX, this.definition.BorderWrapModeY);
var operation = new MedianRowOperation<TPixel>(

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

@ -51,7 +51,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int kernelCount = this.kernelSize * this.kernelSize;
Span<Vector4> kernelBuffer = span.Slice(0, kernelCount);
Span<Vector4> channelVectorBuffer = span.Slice(kernelCount, kernelCount);
Span<Vector4> targetBuffer = span.Slice(kernelCount << 1, boundsWidth);
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);
@ -59,13 +60,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
Span<float> yChannel = channelBuffer.Slice(this.yChannelStart, kernelCount);
Span<float> zChannel = channelBuffer.Slice(this.zChannelStart, kernelCount);
DenseMatrix<Vector4> kernel = new DenseMatrix<Vector4>(this.kernelSize, this.kernelSize, kernelBuffer);
var kernel = new DenseMatrix<Vector4>(this.kernelSize, this.kernelSize, kernelBuffer);
int row = y - this.bounds.Y;
MedianConvolutionState state = new MedianConvolutionState(in kernel, this.map);
var state = new MedianConvolutionState(in kernel, this.map);
ref int sampleRowBase = ref state.GetSampleRow(row);
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
// First convert the required source rows to Vector4.
for (int i = 0; i < this.kernelSize; i++)
{
int currentYIndex = Unsafe.Add(ref sampleRowBase, i);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(currentYIndex).Slice(boundsX, boundsWidth);
Span<Vector4> sourceVectorRow = sourceVectorBuffer.Slice(i * boundsWidth, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceVectorRow);
}
if (this.preserveAlpha)
{
for (int x = 0; x < boundsWidth; x++)
@ -76,13 +86,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int kY = 0; kY < state.Kernel.Rows; kY++)
{
int currentYIndex = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(currentYIndex).Slice(boundsX, boundsWidth);
ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
Span<Vector4> sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
{
int currentXIndex = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
TPixel pixel = Unsafe.Add(ref sourceRowBase, currentXIndex);
state.Kernel.SetValue(index, pixel.ToVector4());
Vector4 pixel = Unsafe.Add(ref sourceRowBase, currentXIndex);
state.Kernel.SetValue(index, pixel);
index++;
}
}
@ -102,13 +112,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int kY = 0; kY < state.Kernel.Rows; kY++)
{
int currentYIndex = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(currentYIndex).Slice(boundsX, boundsWidth);
ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
Span<Vector4> sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
{
int currentXIndex = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
TPixel pixel = Unsafe.Add(ref sourceRowBase, currentXIndex);
state.Kernel.SetValue(index, pixel.ToVector4());
Vector4 pixel = Unsafe.Add(ref sourceRowBase, currentXIndex);
state.Kernel.SetValue(index, pixel);
index++;
}
}

Loading…
Cancel
Save