Browse Source

Update ProjectiveTransformProcessor{TPixel}.cs

af/octree-no-pixelmap
James Jackson-South 6 years ago
parent
commit
046d966c0f
  1. 167
      src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs

167
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);
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> destRow = destination.GetPixelRowSpan(y);
for (int x = 0; x < width; x++)
{
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, matrix);
int px = (int)MathF.Round(point.X);
int py = (int)MathF.Round(point.Y);
if (sourceBounds.Contains(px, py))
{
destRow[x] = source[px, py];
}
}
}
});
return; return;
} }
var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler); 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;
try [MethodImpl(InliningOptions.ShortMethod)]
public NearestNeighborRowIntervalAction(
ref Rectangle bounds,
ref Matrix4x4 matrix,
int maxX,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{ {
ParallelRowIterator.IterateRowsWithTempBuffer<Vector4>( this.bounds = bounds;
targetBounds, this.matrix = matrix;
configuration, this.maxX = maxX;
(rows, vectorBuffer) => this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows)
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> destRow = this.destination.GetPixelRowSpan(y);
for (int x = 0; x < this.maxX; x++)
{
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
int px = (int)MathF.Round(point.X);
int py = (int)MathF.Round(point.Y);
if (this.bounds.Contains(px, py))
{ {
Span<Vector4> vectorSpan = vectorBuffer.Span; destRow[x] = this.source[px, py];
for (int y = rows.Min; y < rows.Max; y++) }
{ }
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y); }
PixelOperations<TPixel>.Instance.ToVector4(configuration, targetRowSpan, vectorSpan);
ref float ySpanRef = ref kernel.GetYStartReference(y);
ref float xSpanRef = ref kernel.GetXStartReference(y);
for (int x = 0; x < width; x++)
{
// Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, matrix);
kernel.Convolve(
point,
x,
ref ySpanRef,
ref xSpanRef,
source.PixelBuffer,
vectorSpan);
}
PixelOperations<TPixel>.Instance.FromVector4Destructive(
configuration,
vectorSpan,
targetRowSpan);
}
});
} }
finally }
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;
[MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction(
Configuration configuration,
TransformKernelMap kernelMap,
ref Matrix4x4 matrix,
int maxX,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
{ {
kernel.Dispose(); this.configuration = configuration;
this.kernelMap = kernelMap;
this.matrix = matrix;
this.maxX = maxX;
this.source = source;
this.destination = destination;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Memory<Vector4> memory)
{
Span<Vector4> vectorSpan = memory.Span;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = this.destination.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan);
ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
for (int x = 0; x < this.maxX; x++)
{
// Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix);
this.kernelMap.Convolve(
point,
x,
ref ySpanRef,
ref xSpanRef,
this.source.PixelBuffer,
vectorSpan);
}
PixelOperations<TPixel>.Instance.FromVector4Destructive(
this.configuration,
vectorSpan,
targetRowSpan);
}
} }
} }
} }

Loading…
Cancel
Save