mirror of https://github.com/SixLabors/ImageSharp
Browse Source
If we normalize the weights to make this work when the output is scaled down we break the edge pixel output. Somehow fix this.pull/386/head
4 changed files with 249 additions and 41 deletions
@ -0,0 +1,47 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Numerics; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Processing.Processors |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides methods that allow the tranformation of images using various algorithms.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
internal class TransformProcessor<TPixel> : AffineProcessor<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="TransformProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="matrix">The transformation matrix</param>
|
||||
|
public TransformProcessor(Matrix3x2 matrix) |
||||
|
: this(matrix, KnownResamplers.NearestNeighbor) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="TransformProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="matrix">The transformation matrix</param>
|
||||
|
/// <param name="sampler">The sampler to perform the transform operation.</param>
|
||||
|
public TransformProcessor(Matrix3x2 matrix, IResampler sampler) |
||||
|
: base(sampler) |
||||
|
{ |
||||
|
this.TransformMatrix = matrix; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the transform matrix
|
||||
|
/// </summary>
|
||||
|
public Matrix3x2 TransformMatrix { get; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
protected override Matrix3x2 GetTransformMatrix() |
||||
|
{ |
||||
|
return this.TransformMatrix; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Numerics; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Processing; |
||||
|
using SixLabors.ImageSharp.Processing.Processors; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Extension methods for the <see cref="Image{TPixel}"/> type.
|
||||
|
/// </summary>
|
||||
|
public static partial class ImageExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Transforms an image by the given matrix.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
/// <param name="source">The image to skew.</param>
|
||||
|
/// <param name="matrix">The transformation matrix.</param>
|
||||
|
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
||||
|
public static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix3x2 matrix) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
=> Transform(source, matrix, KnownResamplers.NearestNeighbor); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Transforms an image by the given matrix using the specified sampling algorithm.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
/// <param name="source">The image to skew.</param>
|
||||
|
/// <param name="matrix">The transformation matrix.</param>
|
||||
|
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
|
||||
|
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
||||
|
public static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix3x2 matrix, IResampler sampler) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
=> source.ApplyProcessor(new TransformProcessor<TPixel>(matrix, sampler)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.Processing.Transforms |
||||
|
{ |
||||
|
using System.Numerics; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Processing; |
||||
|
using SixLabors.Primitives; |
||||
|
|
||||
|
using Xunit; |
||||
|
|
||||
|
public class TransformTests : FileTestBase |
||||
|
{ |
||||
|
public static readonly TheoryData<float, float, float> TransformValues |
||||
|
= new TheoryData<float, float, float> |
||||
|
{ |
||||
|
{ 20, 10, 50 }, |
||||
|
{ -20, -10, 50 } |
||||
|
}; |
||||
|
|
||||
|
public static readonly List<string> ResamplerNames |
||||
|
= new List<string> |
||||
|
{ |
||||
|
nameof(KnownResamplers.Bicubic), |
||||
|
//nameof(KnownResamplers.Box),
|
||||
|
//nameof(KnownResamplers.CatmullRom),
|
||||
|
//nameof(KnownResamplers.Hermite),
|
||||
|
//nameof(KnownResamplers.Lanczos2),
|
||||
|
//nameof(KnownResamplers.Lanczos3),
|
||||
|
//nameof(KnownResamplers.Lanczos5),
|
||||
|
//nameof(KnownResamplers.Lanczos8),
|
||||
|
//nameof(KnownResamplers.MitchellNetravali),
|
||||
|
//nameof(KnownResamplers.NearestNeighbor),
|
||||
|
//nameof(KnownResamplers.Robidoux),
|
||||
|
//nameof(KnownResamplers.RobidouxSharp),
|
||||
|
//nameof(KnownResamplers.Spline),
|
||||
|
//nameof(KnownResamplers.Triangle),
|
||||
|
//nameof(KnownResamplers.Welch),
|
||||
|
}; |
||||
|
|
||||
|
[Theory] |
||||
|
[WithFileCollection(nameof(DefaultFiles), nameof(TransformValues), DefaultPixelType)] |
||||
|
public void ImageShouldTransformWithSampler<TPixel>(TestImageProvider<TPixel> provider, float x, float y, float z) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
|
||||
|
foreach (string resamplerName in ResamplerNames) |
||||
|
{ |
||||
|
IResampler sampler = GetResampler(resamplerName); |
||||
|
using (Image<TPixel> image = provider.GetImage()) |
||||
|
{ |
||||
|
Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(-z); |
||||
|
|
||||
|
// TODO, how does scale work? 2 means half just now,
|
||||
|
Matrix3x2 scale = Matrix3x2Extensions.CreateScale(new SizeF(2F, 2F)); |
||||
|
|
||||
|
|
||||
|
image.Mutate(i => i.Transform(scale * rotate, sampler)); |
||||
|
image.DebugSave(provider, string.Join("_", x, y, resamplerName)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static IResampler GetResampler(string name) |
||||
|
{ |
||||
|
PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); |
||||
|
|
||||
|
if (property == null) |
||||
|
{ |
||||
|
throw new Exception("Invalid property name!"); |
||||
|
} |
||||
|
|
||||
|
return (IResampler)property.GetValue(null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue