Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revised & extended test coverage for Resize #782

Merged
merged 10 commits into from Dec 10, 2018
9 changes: 7 additions & 2 deletions src/ImageSharp/Common/Helpers/TolerantMath.cs
Expand Up @@ -16,6 +16,13 @@ namespace SixLabors.ImageSharp

private readonly double negEpsilon;

/// <summary>
/// A read-only default instance for <see cref="TolerantMath"/> using 1e-8 as epsilon.
/// It is a field so it can be passed as an 'in' parameter.
/// Does not necessarily fit all use cases!
/// </summary>
public static readonly TolerantMath Default = new TolerantMath(1e-8);

public TolerantMath(double epsilon)
{
DebugGuard.MustBeGreaterThan(epsilon, 0, nameof(epsilon));
Expand All @@ -24,8 +31,6 @@ public TolerantMath(double epsilon)
this.negEpsilon = -epsilon;
}

public static TolerantMath Default { get; } = new TolerantMath(1e-8);

/// <summary>
/// <paramref name="a"/> == 0
/// </summary>
Expand Down
Expand Up @@ -208,10 +208,7 @@ private void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize,
{
var result = new TheoryData<string, int, int>();

string[] resamplerNames = typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static)
.Select(p => p.Name)
.Where(name => name != nameof(KnownResamplers.NearestNeighbor))
.ToArray();
string[] resamplerNames = TestUtils.GetAllResamplerNames(false);

int[] dimensionVals =
{
Expand Down
Expand Up @@ -20,42 +20,82 @@ public class ResizeTests : FileTestBase
public static readonly string[] CommonTestImages = { TestImages.Png.CalliphoraPartial };

private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F);

public static readonly TheoryData<string, IResampler> AllResamplers =
new TheoryData<string, IResampler>

public static readonly string[] AllResamplerNames = TestUtils.GetAllResamplerNames();

public static readonly string[] SmokeTestResamplerNames =
{
{ "Bicubic", KnownResamplers.Bicubic },
{ "Triangle", KnownResamplers.Triangle},
{ "NearestNeighbor", KnownResamplers.NearestNeighbor },
{ "Box", KnownResamplers.Box },
// { "Lanczos2", KnownResamplers.Lanczos2 }, TODO: Add expected file
{ "Lanczos3", KnownResamplers.Lanczos3 },
{ "Lanczos5", KnownResamplers.Lanczos5 },
{ "MitchellNetravali", KnownResamplers.MitchellNetravali },
{ "Lanczos8", KnownResamplers.Lanczos8 },
{ "Hermite", KnownResamplers.Hermite },
{ "Spline", KnownResamplers.Spline },
{ "Robidoux", KnownResamplers.Robidoux },
{ "RobidouxSharp", KnownResamplers.RobidouxSharp },
{ "Welch", KnownResamplers.Welch }
nameof(KnownResamplers.NearestNeighbor),
nameof(KnownResamplers.Bicubic),
nameof(KnownResamplers.Box),
nameof(KnownResamplers.Lanczos5),
};

[Theory]
[WithTestPatternImages(nameof(AllResamplers), 100, 100, DefaultPixelType, 0.5f)]
[WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.5f)]
[WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.3f)]
public void Resize_WorksWithAllResamplers<TPixel>(TestImageProvider<TPixel> provider, string name, IResampler sampler, float ratio)
[WithFileCollection(nameof(CommonTestImages), nameof(AllResamplerNames), DefaultPixelType, 0.5f, null, null)]
[WithFileCollection(nameof(CommonTestImages), nameof(SmokeTestResamplerNames), DefaultPixelType, 0.3f, null, null)]
[WithFileCollection(nameof(CommonTestImages), nameof(SmokeTestResamplerNames), DefaultPixelType, 1.8f, null, null)]
[WithTestPatternImages(nameof(SmokeTestResamplerNames), 100, 100, DefaultPixelType, 0.5f, null, null)]
[WithTestPatternImages(nameof(SmokeTestResamplerNames), 100, 100, DefaultPixelType, 1f, null, null)]
[WithTestPatternImages(nameof(SmokeTestResamplerNames), 50, 50, DefaultPixelType, 8f, null, null)]
[WithTestPatternImages(nameof(SmokeTestResamplerNames), 201, 199, DefaultPixelType, null, 100, 99)]
[WithTestPatternImages(nameof(SmokeTestResamplerNames), 301, 1180, DefaultPixelType, null, 300, 480)]
[WithTestPatternImages(nameof(SmokeTestResamplerNames), 49, 80, DefaultPixelType, null, 301, 100)]
public void Resize_WorksWithAllResamplers<TPixel>(
TestImageProvider<TPixel> provider,
string samplerName,
float? ratio,
int? specificDestWidth,
int? specificDestHeight)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
SizeF newSize = image.Size() * ratio;
image.Mutate(x => x.Resize((Size)newSize, sampler, false));
FormattableString details = $"{name}-{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
IResampler sampler = TestUtils.GetResampler(samplerName);

image.DebugSave(provider, details);
image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.02f), provider, details);
}
// NeirestNeighbourResampler is producing slightly different results With classic .NET framework on 32bit
// most likely because of differences in numeric behavior.
// The difference is well visible when comparing output for
// Resize_WorksWithAllResamplers_TestPattern301x1180_NearestNeighbor-300x480.png
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is worth to check (and cry).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not worth us trying to fix it. NN is low quality anyway and 32bit NET Framework would be increasingly rare. I’d put a note and skip test on those platforms.

// TODO: Should we investigate this?
bool allowHigherInaccuracy = !TestEnvironment.Is64BitProcess
&& string.IsNullOrEmpty(TestEnvironment.NetCoreVersion)
&& sampler is NearestNeighborResampler;

var comparer = ImageComparer.TolerantPercentage(allowHigherInaccuracy ? 0.3f : 0.01f);

provider.RunValidatingProcessorTest(
ctx =>
{

SizeF newSize;
string destSizeInfo;
if (ratio.HasValue)
{
newSize = ctx.GetCurrentSize() * ratio.Value;
destSizeInfo = ratio.Value.ToString(System.Globalization.CultureInfo.InvariantCulture);
}
else
{
if (!specificDestWidth.HasValue || !specificDestHeight.HasValue)
{
throw new InvalidOperationException(
"invalid dimensional input for Resize_WorksWithAllResamplers!");
}

newSize = new SizeF(specificDestWidth.Value, specificDestHeight.Value);
destSizeInfo = $"{newSize.Width}x{newSize.Height}";
}

FormattableString testOutputDetails = $"{samplerName}-{destSizeInfo}";
ctx.Apply(
img => img.DebugSave(
provider,
$"{testOutputDetails}-ORIGINAL",
appendPixelTypeToFileName: false));
ctx.Resize((Size)newSize, sampler, false);
return testOutputDetails;
},
comparer,
appendPixelTypeToFileName: false);
}

[Theory]
Expand Down
Expand Up @@ -61,7 +61,7 @@ public override IEnumerable<object[]> GetData(MethodInfo testMethod)
addedRows = memberItems.Select(x => x as object[]);
if (addedRows.Any(x => x == null))
{
throw new ArgumentException($"Property {this.MemberName} on {this.MemberType ?? testMethod.DeclaringType} yielded an item that is not an object[]");
addedRows = memberItems.Select(x => new[] { x });
}
}
}
Expand Down
Expand Up @@ -16,10 +16,9 @@ public abstract partial class TestImageProvider<TPixel>
/// <summary>
/// A test image provider that produces test patterns.
/// </summary>
/// <typeparam name="TPixel"></typeparam>
private class TestPatternProvider : BlankProvider
{
static Dictionary<string, Image<TPixel>> testImages = new Dictionary<string, Image<TPixel>>();
static readonly Dictionary<string, Image<TPixel>> TestImages = new Dictionary<string, Image<TPixel>>();

public TestPatternProvider(int width, int height)
: base(width, height)
Expand All @@ -35,17 +34,17 @@ public TestPatternProvider()

public override Image<TPixel> GetImage()
{
lock (testImages)
lock (TestImages)
{
if (!testImages.ContainsKey(this.SourceFileOrDescription))
if (!TestImages.ContainsKey(this.SourceFileOrDescription))
{
Image<TPixel> image = new Image<TPixel>(this.Width, this.Height);
DrawTestPattern(image);
testImages.Add(this.SourceFileOrDescription, image);
TestImages.Add(this.SourceFileOrDescription, image);
}
}

return testImages[this.SourceFileOrDescription].Clone();
return TestImages[this.SourceFileOrDescription].Clone();
}

/// <summary>
Expand Down Expand Up @@ -202,6 +201,7 @@ private static void Rainbow(Buffer2D<TPixel> pixels)
Rgba32 t = new Rgba32(0);

for (int x = left; x < right; x++)
{
for (int y = top; y < bottom; y++)
{
t.PackedValue += stepsPerPixel;
Expand All @@ -210,6 +210,7 @@ private static void Rainbow(Buffer2D<TPixel> pixels)
c.FromVector4(v);
pixels[x, y] = c;
}
}
}
}
}
Expand Down
47 changes: 47 additions & 0 deletions tests/ImageSharp.Tests/TestUtilities/TestUtils.cs
Expand Up @@ -193,6 +193,45 @@ internal static TPixel GetPixelOfNamedColor<TPixel>(string colorName)
}
}

internal static void RunValidatingProcessorTest<TPixel>(
this TestImageProvider<TPixel> provider,
Func<IImageProcessingContext<TPixel>, FormattableString> processAndGetTestOutputDetails,
ImageComparer comparer = null,
bool appendPixelTypeToFileName = true,
bool appendSourceFileOrDescription = true)
where TPixel : struct, IPixel<TPixel>
{
if (comparer == null)
{
comparer = ImageComparer.TolerantPercentage(0.001f);
}

using (Image<TPixel> image = provider.GetImage())
{
FormattableString testOutputDetails = $"";
image.Mutate(
ctx => { testOutputDetails = processAndGetTestOutputDetails(ctx); }
);

image.DebugSave(
provider,
testOutputDetails,
appendPixelTypeToFileName: appendPixelTypeToFileName,
appendSourceFileOrDescription: appendSourceFileOrDescription);

// TODO: Investigate the cause of pixel inaccuracies under Linux
if (TestEnvironment.IsWindows)
{
image.CompareToReferenceOutput(
comparer,
provider,
testOutputDetails,
appendPixelTypeToFileName: appendPixelTypeToFileName,
appendSourceFileOrDescription: appendSourceFileOrDescription);
}
}
}

public static void RunValidatingProcessorTestOnWrappedMemoryImage<TPixel>(
this TestImageProvider<TPixel> provider,
Action<IImageProcessingContext<TPixel>> process,
Expand Down Expand Up @@ -297,5 +336,13 @@ public static IResampler GetResampler(string name)

return (IResampler)property.GetValue(null);
}

public static string[] GetAllResamplerNames(bool includeNearestNeighbour = true)
{
return typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static)
.Select(p => p.Name)
.Where(name => includeNearestNeighbour || name != nameof(KnownResamplers.NearestNeighbor))
.ToArray();
}
}
}
Expand Up @@ -9,6 +9,7 @@
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
// ReSharper disable InconsistentNaming

namespace SixLabors.ImageSharp.Tests
{
Expand Down Expand Up @@ -313,6 +314,17 @@ public void Use_WithMemberFactoryAttribute<TPixel>(TestImageProvider<TPixel> pro

}

[Theory]
[WithTestPatternImages(49,20, PixelTypes.Rgba32)]
public void Use_WithTestPatternImages<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> img = provider.GetImage())
{
img.DebugSave(provider);
}
}

public static readonly TheoryData<object> BasicData = new TheoryData<object>()
{
TestImageProvider<Rgba32>.Blank(10, 20),
Expand Down
2 changes: 1 addition & 1 deletion tests/Images/External
Submodule External updated 80 files
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Bicubic-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Bicubic-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Bicubic-1.8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Box-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Box-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Box-1.8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_CatmullRom-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Hermite-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Lanczos2-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Lanczos3-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Lanczos5-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Lanczos5-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Lanczos5-1.8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Lanczos8-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_MitchellNetravali-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_NearestNeighbor-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_NearestNeighbor-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_NearestNeighbor-1.8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Robidoux-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_RobidouxSharp-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Spline-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Triangle-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_CalliphoraPartial_Welch-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Bicubic-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Box-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Hermite-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Hermite-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Lanczos3-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Lanczos3-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Lanczos5-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Lanczos5-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Lanczos8-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Lanczos8-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_MitchellNetravali-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Robidoux-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Robidoux-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_RobidouxSharp-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_RobidouxSharp-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Spline-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Spline-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Triangle-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Triangle-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Welch-0.3.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Welch-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Bicubic-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Box-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Hermite-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Lanczos3-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Lanczos5-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Lanczos8-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_MitchellNetravali-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Robidoux-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_RobidouxSharp-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Spline-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Triangle-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_Rgba32_TestPattern100x100_Welch-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_Bicubic-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_Bicubic-1.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_Box-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_Box-1.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_Lanczos5-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_Lanczos5-1.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_NearestNeighbor-0.5.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern100x100_NearestNeighbor-1.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern201x199_Bicubic-100x99.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern201x199_Box-100x99.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern201x199_Lanczos5-100x99.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern201x199_NearestNeighbor-100x99.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern301x1180_Bicubic-300x480.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern301x1180_Box-300x480.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern301x1180_Lanczos5-300x480.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern301x1180_NearestNeighbor-300x480.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern49x80_Bicubic-301x100.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern49x80_Box-301x100.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern49x80_Lanczos5-301x100.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern49x80_NearestNeighbor-301x100.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern50x50_Bicubic-8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern50x50_Box-8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern50x50_Lanczos5-8.png
+ ReferenceOutput/ResizeTests/Resize_WorksWithAllResamplers_TestPattern50x50_NearestNeighbor-8.png