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++)
{
var transformedPoint = Point.Transform(new Point(x, y), matrix);
if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y))
var point = Point.Transform(new Point(x, y), matrix);
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;
}
int maxX = source.Width - 1;
int maxY = source.Height - 1;
int maxSourceX = source.Width - 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(
0,
height,
new ParallelOptions { MaxDegreeOfParallelism = 1 },
configuration.ParallelOptions,
y =>
{
Span<TPixel> destRow = destination.GetPixelRowSpan(y);
for (int x = 0; x < width; x++)
{
var transformedPoint = Point.Transform(new Point(x, y), matrix);
if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y))
// Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
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];
WeightsWindow windowY = this.VerticalWeights.Weights[transformedPoint.Y];
continue;
}
Vector4 dXY = this.ComputeWeightedSumAtPosition(source, maxX, maxY, ref windowX, ref windowY, ref transformedPoint);
ref TPixel dest = ref destRow[x];
dest.PackFromVector4(dXY);
// It appears these have to be calculated manually.
// Using the precalculated weights give the wrong values.
// 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>
/// Computes the weighted sum at the given XY position
/// Calculates the sampling radius for the current sampler
/// </summary>
/// <param name="source">The source image</param>
/// <param name="maxX">The maximum x value</param>
/// <param name="maxY">The maximum y value</param>
/// <param name="windowX">The horizontal weights</param>
/// <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)
/// <param name="sourceSize">The source dimension size</param>
/// <param name="destinationSize">The destination dimension size</param>
/// <returns>The radius, and scaling factor</returns>
private (float radius, float scale) GetSamplingRadius(int sourceSize, int destinationSize)
{
// What, in theory, is supposed to happen here is the following...
//
// 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;
}
float ratio = (float)sourceSize / destinationSize;
float scale = ratio;
if (right >= maxX)
if (scale < 1F)
{
// Trim the length of our weights iterator across the x-axis.
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;
}
scale = 1F;
}
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.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
@ -14,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x)
{
if (x < 0F)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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