Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f79024e
Get transforms working
JimBobSquarePants Mar 22, 2018
5f9aff4
Merge branch 'master' into js/projective-transforms
JimBobSquarePants Apr 10, 2018
815264d
Init projective transform testing
JimBobSquarePants Apr 10, 2018
2d48d57
Merge branch 'master' into js/projective-transforms
JimBobSquarePants Apr 23, 2018
c6cce4d
Optimize transforms and reduce struct copying.
JimBobSquarePants Apr 23, 2018
7f7c513
Begin adding tests.
JimBobSquarePants Apr 23, 2018
16183a4
Revert ref extensions.
JimBobSquarePants Apr 24, 2018
75d6729
Add another test and make some methods public
JimBobSquarePants Apr 24, 2018
c45fb1a
Rename helper
JimBobSquarePants Apr 26, 2018
a3dcedc
Enable tests
JimBobSquarePants Apr 26, 2018
5d9dd8f
workaround Vector2 CLR bug + cover taper parameters with tests
antonfirsov Apr 28, 2018
368903a
use "fixed" reference output + reduce tolerance
antonfirsov Apr 28, 2018
92d50ba
OK, I give it up,let's increase the tolerance again.
antonfirsov Apr 28, 2018
bca48a6
Merge branch 'master' into js/projective-transforms
JimBobSquarePants Apr 28, 2018
0d08cb7
Merge branch 'master' into js/projective-transforms
JimBobSquarePants Apr 28, 2018
003debc
Merge branch 'master' into js/projective-transforms
JimBobSquarePants Apr 29, 2018
ec04a6f
Enable comparison tests.
JimBobSquarePants Apr 30, 2018
4f9edfa
Merge branch 'master' into js/projective-transforms
JimBobSquarePants May 2, 2018
df19dd0
increase tolerance for Transform_WithTaperMatrix
antonfirsov May 2, 2018
775aa90
floating points from hell
antonfirsov May 2, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
Expand Down Expand Up @@ -120,9 +122,9 @@ protected override void OnFrameApply(
configuration.ParallelOptions,
y =>
{
Span<TPixel> destRow = destination.GetPixelRowSpan(y);
Span<float> ySpan = yBuffer.GetRowSpan(y);
Span<float> xSpan = xBuffer.GetRowSpan(y);
ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y));
ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y));
ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y));

for (int x = 0; x < width; x++)
{
Expand Down Expand Up @@ -164,24 +166,24 @@ protected override void OnFrameApply(
// I've optimized where I can but am always open to suggestions.
if (yScale > 1 && xScale > 1)
{
CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ySpan);
CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, xSpan);
CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ref ySpanRef, yLength);
CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, ref xSpanRef, xLength);
}
else
{
CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ySpan);
CalculateWeightsScaleUp(minX, maxX, point.X, sampler, xSpan);
CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef);
CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef);
}

// Now multiply the results against the offsets
Vector4 sum = Vector4.Zero;
for (int yy = 0, j = minY; j <= maxY; j++, yy++)
{
float yWeight = ySpan[yy];
float yWeight = Unsafe.Add(ref ySpanRef, yy);

for (int xx = 0, i = minX; i <= maxX; i++, xx++)
{
float xWeight = xSpan[xx];
float xWeight = Unsafe.Add(ref xSpanRef, xx);
var vector = source[i, j].ToVector4();

// Values are first premultiplied to prevent darkening of edge pixels
Expand All @@ -190,7 +192,7 @@ protected override void OnFrameApply(
}
}

ref TPixel dest = ref destRow[x];
ref TPixel dest = ref Unsafe.Add(ref destRowRef, x);

// Reverse the premultiplication
dest.PackFromVector4(sum.UnPremultiply());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ protected InterpolatedTransformProcessorBase(IResampler sampler)
/// <param name="point">The transformed point dimension</param>
/// <param name="sampler">The sampler</param>
/// <param name="scale">The transformed image scale relative to the source</param>
/// <param name="weights">The collection of weights</param>
/// <param name="weightsRef">The reference to the collection of weights</param>
/// <param name="length">The length of the weights collection</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, Span<float> weights)
protected static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, ref float weightsRef, int length)
{
float sum = 0;
ref float weightsBaseRef = ref weights[0];

// Downsampling weights requires more edge sampling plus normalization of the weights
for (int x = 0, i = min; i <= max; i++, x++)
Expand All @@ -65,14 +65,14 @@ protected static void CalculateWeightsDown(int min, int max, int sourceMin, int

float weight = sampler.GetValue((index - point) / scale);
sum += weight;
Unsafe.Add(ref weightsBaseRef, x) = weight;
Unsafe.Add(ref weightsRef, x) = weight;
}

if (sum > 0)
{
for (int i = 0; i < weights.Length; i++)
for (int i = 0; i < length; i++)
{
ref float wRef = ref Unsafe.Add(ref weightsBaseRef, i);
ref float wRef = ref Unsafe.Add(ref weightsRef, i);
wRef = wRef / sum;
}
}
Expand All @@ -85,15 +85,14 @@ protected static void CalculateWeightsDown(int min, int max, int sourceMin, int
/// <param name="sourceMax">The maximum source bounds</param>
/// <param name="point">The transformed point dimension</param>
/// <param name="sampler">The sampler</param>
/// <param name="weights">The collection of weights</param>
/// <param name="weightsRef">The reference to the collection of weights</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, Span<float> weights)
protected static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, ref float weightsRef)
{
ref float weightsBaseRef = ref weights[0];
for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++)
{
float weight = sampler.GetValue(i - point);
Unsafe.Add(ref weightsBaseRef, x) = weight;
Unsafe.Add(ref weightsRef, x) = weight;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
Expand Down Expand Up @@ -70,6 +72,7 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixe

// Convert from screen to world space.
Matrix4x4.Invert(matrix, out matrix);
const float Epsilon = 0.0000001F;

if (this.Sampler is NearestNeighborResampler)
{
Expand All @@ -83,10 +86,15 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixe

for (int x = 0; x < width; x++)
{
var point = Point.Round(Vector2.Transform(new Vector2(x, y), matrix));
if (sourceBounds.Contains(point.X, point.Y))
var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix);

float z = MathF.Max(v3.Z, Epsilon);
int px = (int)MathF.Round(v3.X / z);
int py = (int)MathF.Round(v3.Y / z);

if (sourceBounds.Contains(px, py))
{
destRow[x] = source[point.X, point.Y];
destRow[x] = source[px, py];
}
}
});
Expand All @@ -100,7 +108,10 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixe
(float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height);
float xScale = xRadiusScale.scale;
float yScale = yRadiusScale.scale;
var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius);

// Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable:
var radius = new Vector4(xRadiusScale.radius, yRadiusScale.radius, 0, 0);

IResampler sampler = this.Sampler;
var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY);
int xLength = (int)MathF.Ceiling((radius.X * 2) + 2);
Expand All @@ -117,19 +128,23 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixe
configuration.ParallelOptions,
y =>
{
Span<TPixel> destRow = destination.GetPixelRowSpan(y);
Span<float> ySpan = yBuffer.GetRowSpan(y);
Span<float> xSpan = xBuffer.GetRowSpan(y);
ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y));
ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y));
ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(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.
var point = Vector2.Transform(new Vector2(x, y), matrix);
var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix);
float z = MathF.Max(v3.Z, Epsilon);

// Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable:
Vector4 point = new Vector4(v3.X, v3.Y, 0, 0) / z;

// Clamp sampling pixel radial extents to the source image edges
Vector2 maxXY = point + radius;
Vector2 minXY = point - radius;
Vector4 maxXY = point + radius;
Vector4 minXY = point - radius;

// max, maxY, minX, minY
var extents = new Vector4(
Expand Down Expand Up @@ -161,24 +176,24 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixe
// I've optimized where I can but am always open to suggestions.
if (yScale > 1 && xScale > 1)
{
CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ySpan);
CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, xSpan);
CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ref ySpanRef, yLength);
CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, ref xSpanRef, xLength);
}
else
{
CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ySpan);
CalculateWeightsScaleUp(minX, maxX, point.X, sampler, xSpan);
CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef);
CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef);
}

// Now multiply the results against the offsets
Vector4 sum = Vector4.Zero;
for (int yy = 0, j = minY; j <= maxY; j++, yy++)
{
float yWeight = ySpan[yy];
float yWeight = Unsafe.Add(ref ySpanRef, yy);

for (int xx = 0, i = minX; i <= maxX; i++, xx++)
{
float xWeight = xSpan[xx];
float xWeight = Unsafe.Add(ref xSpanRef, xx);
var vector = source[i, j].ToVector4();

// Values are first premultiplied to prevent darkening of edge pixels
Expand All @@ -187,7 +202,7 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixe
}
}

ref TPixel dest = ref destRow[x];
ref TPixel dest = ref Unsafe.Add(ref destRowRef, x);

// Reverse the premultiplication
dest.PackFromVector4(sum.UnPremultiply());
Expand Down
Loading