Browse Source

It works!!!!

Now we need to refactor and optimize this.
pull/386/head
James Jackson-South 8 years ago
parent
commit
7d4e29591c
  1. 154
      src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs
  2. 3
      src/ImageSharp/Processing/Transforms/Resamplers/BicubicResampler.cs
  3. 3
      src/ImageSharp/Processing/Transforms/Resamplers/BoxResampler.cs
  4. 3
      src/ImageSharp/Processing/Transforms/Resamplers/CatmullRomResampler.cs
  5. 3
      src/ImageSharp/Processing/Transforms/Resamplers/HermiteResampler.cs
  6. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs
  7. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs
  8. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs
  9. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs
  10. 3
      src/ImageSharp/Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs
  11. 3
      src/ImageSharp/Processing/Transforms/Resamplers/NearestNeighborResampler.cs
  12. 3
      src/ImageSharp/Processing/Transforms/Resamplers/RobidouxSharpResampler.cs
  13. 3
      src/ImageSharp/Processing/Transforms/Resamplers/SplineResampler.cs
  14. 3
      src/ImageSharp/Processing/Transforms/Resamplers/TriangleResampler.cs
  15. 5
      src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs

154
src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs

@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.Processing.Processors
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
var transformedPoint = Point.Transform(new Point(x, y), matrix); var point = Point.Transform(new Point(x, y), matrix);
if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y)) if (sourceBounds.Contains(point.X, point.Y))
{ {
destRow[x] = source[transformedPoint.X, transformedPoint.Y]; destRow[x] = source[point.X, point.Y];
} }
} }
}); });
@ -101,29 +101,58 @@ namespace SixLabors.ImageSharp.Processing.Processors
return; return;
} }
int maxX = source.Width - 1; int maxSourceX = source.Width - 1;
int maxY = source.Height - 1; int maxSourceY = source.Height - 1;
(float radius, float scale) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width);
(float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height);
float xScale = xRadiusScale.scale;
float yScale = yRadiusScale.scale;
float xRadius = xRadiusScale.radius;
float yRadius = yRadiusScale.radius;
Parallel.For( Parallel.For(
0, 0,
height, height,
new ParallelOptions { MaxDegreeOfParallelism = 1 }, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> destRow = destination.GetPixelRowSpan(y); Span<TPixel> destRow = destination.GetPixelRowSpan(y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
var transformedPoint = Point.Transform(new Point(x, y), matrix); // Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y)) var point = PointF.Transform(new PointF(x, y), matrix);
int maxX = (int)MathF.Ceiling(point.X + xRadius);
int maxY = (int)MathF.Ceiling(point.Y + yRadius);
int minX = (int)MathF.Floor(point.X - xRadius);
int minY = (int)MathF.Floor(point.Y - yRadius);
// Clamp sampling pixels to the source image edge
maxX = maxX.Clamp(0, maxSourceX);
minX = minX.Clamp(0, maxSourceX);
maxY = maxY.Clamp(0, maxSourceY);
minY = minY.Clamp(0, maxSourceY);
if (minX == maxX || minY == maxY)
{ {
WeightsWindow windowX = this.HorizontalWeights.Weights[transformedPoint.X]; continue;
WeightsWindow windowY = this.VerticalWeights.Weights[transformedPoint.Y]; }
Vector4 dXY = this.ComputeWeightedSumAtPosition(source, maxX, maxY, ref windowX, ref windowY, ref transformedPoint); // It appears these have to be calculated manually.
ref TPixel dest = ref destRow[x]; // Using the precalculated weights give the wrong values.
dest.PackFromVector4(dXY); // TODO: Find a way to speed this up.
Vector4 sum = Vector4.Zero;
for (int i = minX; i <= maxX; i++)
{
float weightX = this.Sampler.GetValue((i - point.X) / xScale);
for (int j = minY; j <= maxY; j++)
{
float weightY = this.Sampler.GetValue((j - point.Y) / yScale);
sum += source[i, j].ToVector4() * weightX * weightY;
}
} }
ref TPixel dest = ref destRow[x];
dest.PackFromVector4(sum);
} }
}); });
} }
@ -143,99 +172,22 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <summary> /// <summary>
/// Computes the weighted sum at the given XY position /// Calculates the sampling radius for the current sampler
/// </summary> /// </summary>
/// <param name="source">The source image</param> /// <param name="sourceSize">The source dimension size</param>
/// <param name="maxX">The maximum x value</param> /// <param name="destinationSize">The destination dimension size</param>
/// <param name="maxY">The maximum y value</param> /// <returns>The radius, and scaling factor</returns>
/// <param name="windowX">The horizontal weights</param> private (float radius, float scale) GetSamplingRadius(int sourceSize, int destinationSize)
/// <param name="windowY">The vertical weights</param>
/// <param name="point">The transformed position</param>
/// <returns>The <see cref="Vector4"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected Vector4 ComputeWeightedSumAtPosition(
ImageFrame<TPixel> source,
int maxX,
int maxY,
ref WeightsWindow windowX,
ref WeightsWindow windowY,
ref Point point)
{ {
// What, in theory, is supposed to happen here is the following... float ratio = (float)sourceSize / destinationSize;
// float scale = ratio;
// We identify the maximum possible pixel offsets allowable by the current sampler
// clamping values to ensure that we do not go outwith the bounds of our image.
//
// Then we get the weights of that offset value from our pre-calculated vaues.
// First we grab the weight on the y-axis, then the x-axis and then we multiply
// them together to get the final weight.
//
// Unfortunately this simply does not seem to work!
// The output is rubbish and I cannot see why :(
ref float horizontalValues = ref windowX.GetStartReference();
ref float verticalValues = ref windowY.GetStartReference();
int yLength = windowY.Length;
int xLength = windowX.Length;
int yRadius = (int)MathF.Ceiling((yLength - 1) * .5F);
int xRadius = (int)MathF.Ceiling((xLength - 1) * .5F);
int left = point.X - xRadius;
int right = point.X + xRadius;
int top = point.Y - yRadius;
int bottom = point.Y + yRadius;
int yIndex = 0;
int xIndex = 0;
// Faster than clamping + we know we are only looking in one direction
if (left < 0)
{
// Trim the length of our weights iterator across the x-axis.
// Offset our start index across the x-axis.
xIndex = ImageMaths.FastAbs(left);
xLength -= xIndex;
left = 0;
}
if (top < 0)
{
// Trim the length of our weights iterator across the y-axis.
// Offset our start index across the y-axis.
yIndex = ImageMaths.FastAbs(top);
yLength -= yIndex;
top = 0;
}
if (right >= maxX) if (scale < 1F)
{ {
// Trim the length of our weights iterator across the x-axis. scale = 1F;
xLength -= right - maxX;
}
if (bottom >= maxY)
{
// Trim the length of our weights iterator across the y-axis.
yLength -= bottom - maxY;
}
Vector4 result = Vector4.Zero;
// We calculate our sample by iterating up-down/left-right from our transformed point.
for (int y = top, yi = yIndex; yi < yLength; y++, yi++)
{
float yweight = Unsafe.Add(ref verticalValues, yi);
for (int x = left, xi = xIndex; xi < xLength; x++, xi++)
{
float xweight = Unsafe.Add(ref horizontalValues, xi);
float weight = yweight * xweight;
result += source[x, y].ToVector4() * weight;
}
} }
return result; return (MathF.Ceiling(scale * this.Sampler.Radius), scale);
} }
} }

3
src/ImageSharp/Processing/Transforms/Resamplers/BicubicResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/BoxResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -13,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 0.5F; public float Radius => 0.5F;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x > -0.5F && x <= 0.5F) if (x > -0.5F && x <= 0.5F)

3
src/ImageSharp/Processing/Transforms/Resamplers/CatmullRomResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,6 +17,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0; const float B = 0;

3
src/ImageSharp/Processing/Transforms/Resamplers/HermiteResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0F; const float B = 0F;

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 3; public float Radius => 3;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 5; public float Radius => 5;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 8; public float Radius => 8;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -13,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0.3333333F; const float B = 0.3333333F;

3
src/ImageSharp/Processing/Transforms/Resamplers/NearestNeighborResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -13,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 1; public float Radius => 1;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
return x; return x;

3
src/ImageSharp/Processing/Transforms/Resamplers/RobidouxSharpResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -13,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0.2620145123990142F; const float B = 0.2620145123990142F;

3
src/ImageSharp/Processing/Transforms/Resamplers/SplineResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -13,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 1F; const float B = 1F;

3
src/ImageSharp/Processing/Transforms/Resamplers/TriangleResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 1; public float Radius => 1;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

5
src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -13,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 3; public float Radius => 3;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)
@ -28,4 +31,4 @@ namespace SixLabors.ImageSharp.Processing
return 0F; return 0F;
} }
} }
} }
Loading…
Cancel
Save