Browse Source

Update ProjectiveTransformProcessor{TPixel}.cs

pull/1108/head
James Jackson-South 7 years ago
parent
commit
01f2c05f72
  1. 117
      src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs

117
src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs

@ -3,7 +3,9 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -48,7 +50,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
int width = this.targetSize.Width; int width = this.targetSize.Width;
Rectangle sourceBounds = this.SourceRectangle;
var targetBounds = new Rectangle(Point.Empty, this.targetSize); var targetBounds = new Rectangle(Point.Empty, this.targetSize);
Configuration configuration = this.Configuration; Configuration configuration = this.Configuration;
@ -57,73 +58,127 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (this.resampler is NearestNeighborResampler) if (this.resampler is NearestNeighborResampler)
{ {
Rectangle sourceBounds = this.SourceRectangle;
var nearestRowAction = new NearestNeighborRowIntervalAction(ref sourceBounds, ref matrix, width, source, destination);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
targetBounds, targetBounds,
configuration, configuration,
rows => in nearestRowAction);
return;
}
using var kernelMap = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler);
var rowAction = new RowIntervalAction(configuration, kernelMap, ref matrix, width, source, destination);
ParallelRowIterator.IterateRows<RowIntervalAction, Vector4>(
targetBounds,
configuration,
in rowAction);
}
private readonly struct NearestNeighborRowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly Matrix4x4 matrix;
private readonly int maxX;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public NearestNeighborRowIntervalAction(
ref Rectangle bounds,
ref Matrix4x4 matrix,
int maxX,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{
this.bounds = bounds;
this.matrix = matrix;
this.maxX = maxX;
this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows)
{ {
for (int y = rows.Min; y < rows.Max; y++) for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> destRow = destination.GetPixelRowSpan(y); Span<TPixel> destRow = this.destination.GetPixelRowSpan(y);
for (int x = 0; x < width; x++) for (int x = 0; x < this.maxX; x++)
{ {
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, matrix); Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
int px = (int)MathF.Round(point.X); int px = (int)MathF.Round(point.X);
int py = (int)MathF.Round(point.Y); int py = (int)MathF.Round(point.Y);
if (sourceBounds.Contains(px, py)) if (this.bounds.Contains(px, py))
{ {
destRow[x] = source[px, py]; destRow[x] = this.source[px, py];
}
} }
} }
} }
});
return;
} }
var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler); private readonly struct RowIntervalAction : IRowIntervalAction<Vector4>
{
private readonly Configuration configuration;
private readonly TransformKernelMap kernelMap;
private readonly Matrix4x4 matrix;
private readonly int maxX;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
try [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction(
Configuration configuration,
TransformKernelMap kernelMap,
ref Matrix4x4 matrix,
int maxX,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{ {
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>( this.configuration = configuration;
targetBounds, this.kernelMap = kernelMap;
configuration, this.matrix = matrix;
(rows, vectorBuffer) => this.maxX = maxX;
this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory)
{ {
Span<Vector4> vectorSpan = vectorBuffer.Span; Span<Vector4> vectorSpan = memory.Span;
for (int y = rows.Min; y < rows.Max; y++) for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y); Span<TPixel> targetRowSpan = this.destination.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan);
ref float ySpanRef = ref kernel.GetYStartReference(y); ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
ref float xSpanRef = ref kernel.GetXStartReference(y); ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
for (int x = 0; x < width; x++) for (int x = 0; x < this.maxX; x++)
{ {
// Use the single precision position to calculate correct bounding pixels // Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds. // otherwise we get rogue pixels outside of the bounds.
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, matrix); Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
kernel.Convolve( this.kernelMap.Convolve(
point, point,
x, x,
ref ySpanRef, ref ySpanRef,
ref xSpanRef, ref xSpanRef,
source.PixelBuffer, this.source.PixelBuffer,
vectorSpan); vectorSpan);
} }
PixelOperations<TPixel>.Instance.FromVector4Destructive( PixelOperations<TPixel>.Instance.FromVector4Destructive(
configuration, this.configuration,
vectorSpan, vectorSpan,
targetRowSpan); targetRowSpan);
} }
});
}
finally
{
kernel.Dispose();
} }
} }
} }

Loading…
Cancel
Save