Browse Source

more refactor on Weights stuff

af/merge-core
Anton Firszov 9 years ago
parent
commit
b9fc389402
  1. 4
      src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
  2. 144
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
  3. 72
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
  4. 34
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

4
src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs

@ -119,7 +119,7 @@ namespace ImageSharp.Processing.Processors
for (int x = minX; x < maxX; x++)
{
// Ensure offsets are normalised for cropping and padding.
Weights ws = this.HorizontalWeights.Weights[x - startX];
WeightsWindow ws = this.HorizontalWeights.Weights[x - startX];
float* horizontalValues = ws.Ptr;
int left = ws.Left;
@ -147,7 +147,7 @@ namespace ImageSharp.Processing.Processors
y =>
{
// Ensure offsets are normalised for cropping and padding.
Weights ws = this.VerticalWeights.Weights[y - startY];
WeightsWindow ws = this.VerticalWeights.Weights[y - startY];
float* verticalValues = ws.Ptr;
int left = ws.Left;

144
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs

@ -0,0 +1,144 @@
namespace ImageSharp.Processing.Processors
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
/// <content>
/// Conains the definition of <see cref="WeightsWindow"/> and <see cref="WeightsBuffer"/>.
/// </content>
internal abstract partial class ResamplingWeightedProcessor<TColor>
{
/// <summary>
/// Points to a collection of of weights allocated in <see cref="WeightsBuffer"/>.
/// </summary>
protected unsafe struct WeightsWindow
{
/// <summary>
/// The local left index position
/// </summary>
public int Left;
/// <summary>
/// The span of weights pointing to <see cref="WeightsBuffer"/>.
/// </summary>
public BufferSpan<float> Span;
/// <summary>
/// Initializes a new instance of the <see cref="WeightsWindow"/> struct.
/// </summary>
/// <param name="left">The local left index</param>
/// <param name="span">The span</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal WeightsWindow(int left, BufferSpan<float> span)
{
this.Left = left;
this.Span = span;
}
/// <summary>
/// Gets an unsafe float* pointer to the beginning of <see cref="Span"/>.
/// </summary>
public float* Ptr => (float*)this.Span.PointerAtOffset;
/// <summary>
/// Gets the lenghth of the weights window
/// </summary>
public int Length => this.Span.Length;
/// <summary>
/// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this <see cref="WeightsWindow"/> instance.
/// </summary>
/// <param name="rowSpan">The input span of vectors</param>
/// <returns>The weighted sum</returns>
public Vector4 ComputeWeightedRowSum(BufferSpan<Vector4> rowSpan)
{
float* horizontalValues = this.Ptr;
int left = this.Left;
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float xw = horizontalValues[i];
int index = left + i;
result += rowSpan[index] * xw;
}
return result;
}
/// <summary>
/// Computes the sum of vectors in 'firstPassPixels' at a column pointed by 'x',
/// weighted by weight values, pointed by this <see cref="WeightsWindow"/> instance.
/// </summary>
/// <param name="firstPassPixels">The buffer of input vectors in row first order</param>
/// <param name="x">The column position</param>
/// <returns>The weighted sum</returns>
public Vector4 ComputeWeightedColumnSum(PinnedImageBuffer<Vector4> firstPassPixels, int x)
{
float* verticalValues = this.Ptr;
int left = this.Left;
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float yw = verticalValues[i];
int index = left + i;
result += firstPassPixels[x, index] * yw;
}
return result;
}
}
/// <summary>
/// Holds the <see cref="WeightsWindow"/> values in an optimized contigous memory region.
/// </summary>
protected class WeightsBuffer : IDisposable
{
private PinnedImageBuffer<float> dataBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="WeightsBuffer"/> class.
/// </summary>
/// <param name="sourceSize">The size of the source window</param>
/// <param name="destinationSize">The size of the destination window</param>
public WeightsBuffer(int sourceSize, int destinationSize)
{
this.dataBuffer = new PinnedImageBuffer<float>(sourceSize, destinationSize);
this.dataBuffer.Clear();
this.Weights = new WeightsWindow[destinationSize];
}
/// <summary>
/// Gets the calculated <see cref="Weights"/> values.
/// </summary>
public WeightsWindow[] Weights { get; }
/// <summary>
/// Disposes <see cref="WeightsBuffer"/> instance releasing it's backing buffer.
/// </summary>
public void Dispose()
{
this.dataBuffer.Dispose();
}
/// <summary>
/// Slices a weights value at the given positions.
/// </summary>
/// <param name="destIdx">The index in destination buffer</param>
/// <param name="leftIdx">The local left index value</param>
/// <param name="rightIdx">The local right index value</param>
/// <returns>The weights</returns>
public WeightsWindow GetWeightsWindow(int destIdx, int leftIdx, int rightIdx)
{
BufferSpan<float> span = this.dataBuffer.GetRowSpan(destIdx).Slice(leftIdx, rightIdx - leftIdx);
return new WeightsWindow(leftIdx, span);
}
}
}
}

72
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs

@ -7,7 +7,6 @@ namespace ImageSharp.Processing.Processors
{
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
@ -15,7 +14,7 @@ namespace ImageSharp.Processing.Processors
/// Adapted from <see href="http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/filter_rcg.c"/>
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
internal abstract class ResamplingWeightedProcessor<TColor> : ImageProcessor<TColor>
internal abstract partial class ResamplingWeightedProcessor<TColor> : ImageProcessor<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
@ -62,12 +61,12 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// Gets or sets the horizontal weights.
/// </summary>
protected Weights.Buffer HorizontalWeights { get; set; }
protected WeightsBuffer HorizontalWeights { get; set; }
/// <summary>
/// Gets or sets the vertical weights.
/// </summary>
protected Weights.Buffer VerticalWeights { get; set; }
protected WeightsBuffer VerticalWeights { get; set; }
/// <inheritdoc/>
protected override void BeforeApply(ImageBase<TColor> source, Rectangle sourceRectangle)
@ -84,6 +83,7 @@ namespace ImageSharp.Processing.Processors
}
}
/// <inheritdoc />
protected override void AfterApply(ImageBase<TColor> source, Rectangle sourceRectangle)
{
base.AfterApply(source, sourceRectangle);
@ -96,7 +96,10 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// Computes the weights to apply at each pixel when resizing.
/// </summary>
protected unsafe Weights.Buffer PrecomputeWeights(int destinationSize, int sourceSize)
/// <param name="destinationSize">The destination size</param>
/// <param name="sourceSize">The source size</param>
/// <returns>The <see cref="WeightsBuffer"/></returns>
protected unsafe WeightsBuffer PrecomputeWeights(int destinationSize, int sourceSize)
{
float ratio = (float)sourceSize / destinationSize;
float scale = ratio;
@ -108,8 +111,8 @@ namespace ImageSharp.Processing.Processors
IResampler sampler = this.Sampler;
float radius = (float)Math.Ceiling(scale * sampler.Radius);
Weights.Buffer result = new Weights.Buffer(sourceSize, destinationSize);
WeightsBuffer result = new WeightsBuffer(sourceSize, destinationSize);
for (int i = 0; i < destinationSize; i++)
{
float center = ((i + .5F) * ratio) - .5F;
@ -129,8 +132,8 @@ namespace ImageSharp.Processing.Processors
float sum = 0;
result.Weights[i] = result.Slice(i, left, right);
Weights ws = result.Weights[i];
WeightsWindow ws = result.GetWeightsWindow(i, left, right);
result.Weights[i] = ws;
float* weights = ws.Ptr;
@ -154,56 +157,5 @@ namespace ImageSharp.Processing.Processors
return result;
}
/// <summary>
/// Represents a collection of weights and their sum.
/// </summary>
protected unsafe struct Weights
{
/// <summary>
/// The local left index position
/// </summary>
public int Left;
public BufferSpan<float> Span;
public float* Ptr => (float*)Span.PointerAtOffset;
public int Length => Span.Length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Weights(int left, BufferSpan<float> span)
{
this.Left = left;
this.Span = span;
}
internal unsafe class Buffer : IDisposable
{
private PinnedImageBuffer<float> dataBuffer;
public Weights[] Weights { get; }
public float* DataPtr { get; }
internal Weights Slice(int i, int leftIdx, int rightIdx)
{
var span = dataBuffer.GetRowSpan(i).Slice(leftIdx, rightIdx - leftIdx);
return new Weights(leftIdx, span);
}
public Buffer(int sourceSize, int destinationSize)
{
this.dataBuffer = new PinnedImageBuffer<float>(sourceSize, destinationSize);
this.dataBuffer.Clear();
this.DataPtr = (float*)this.dataBuffer.Pointer;
this.Weights = new Weights[destinationSize];
}
public void Dispose()
{
this.dataBuffer.Dispose();
}
}
}
}
}

34
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -104,6 +104,8 @@ namespace ImageSharp.Processing.Processors
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
// TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
using (PixelAccessor<TColor> sourcePixels = source.Lock())
@ -128,23 +130,8 @@ namespace ImageSharp.Processing.Processors
for (int x = minX; x < maxX; x++)
{
// Ensure offsets are normalised for cropping and padding.
Weights ws = this.HorizontalWeights.Weights[x - startX];
float* horizontalValues = ws.Ptr;
int left = ws.Left;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < ws.Length; i++)
{
float xw = horizontalValues[i];
int index = left + i;
destination += tempRowBuffer[index] * xw;
}
firstPassPixels[x, y] = destination;
WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer);
}
}
});
@ -157,21 +144,12 @@ namespace ImageSharp.Processing.Processors
y =>
{
// Ensure offsets are normalised for cropping and padding.
Weights ws = this.VerticalWeights.Weights[y - startY];
float* verticalValues = ws.Ptr;
int left = ws.Left;
WeightsWindow window = this.VerticalWeights.Weights[y - startY];
for (int x = 0; x < width; x++)
{
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < ws.Length; i++)
{
float yw = verticalValues[i];
int index = left + i;
destination += firstPassPixels[x, index] * yw;
}
Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);
TColor d = default(TColor);
d.PackFromVector4(destination);

Loading…
Cancel
Save