From c292c75acd6f2960d54f71004cc8d71f15a425e1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 15 Aug 2017 19:56:12 +0200 Subject: [PATCH] implemented TolerantImageComparer --- .../ImageComparison/ExactImageComparer.cs | 4 +- .../ImageComparison/ImageComparer.cs | 2 + .../ImageComparison/ImageSimilarityReport.cs | 3 + .../ImageComparison/TolerantImageComparer.cs | 60 ++++++++++++++++++- 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index d7cd397290..3cae9d9890 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -11,7 +11,9 @@ namespace ImageSharp.Tests.TestUtilities.ImageComparison { public static ExactImageComparer Instance { get; } = new ExactImageComparer(); - public override ImageSimilarityReport CompareImagesOrFrames(ImageBase expected, ImageBase actual) + public override ImageSimilarityReport CompareImagesOrFrames( + ImageBase expected, + ImageBase actual) { if (expected.Size() != actual.Size()) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index d88bc66ee5..d2781ca70d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -6,6 +6,8 @@ namespace ImageSharp.Tests.TestUtilities.ImageComparison using ImageSharp.PixelFormats; + using SixLabors.Primitives; + public abstract class ImageComparer { public static ImageComparer Exact { get; } = ExactImageComparer.Instance; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs index 7c63b0e55c..fd0b265741 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs @@ -14,6 +14,9 @@ this.Differences = differences.ToArray(); } + public static ImageSimilarityReport Empty => + new ImageSimilarityReport(null, null, Enumerable.Empty()); + public IImageBase ExpectedImage { get; } public IImageBase ActualImage { get; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 64ec92d975..d1e20f88c0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -1,6 +1,11 @@ namespace ImageSharp.Tests.TestUtilities.ImageComparison { using System; + using System.Collections.Generic; + + using ImageSharp.PixelFormats; + + using SixLabors.Primitives; public class TolerantImageComparer : ImageComparer { @@ -34,7 +39,60 @@ public override ImageSimilarityReport CompareImagesOrFrames(ImageBase expected, ImageBase actual) { - throw new NotImplementedException(); + if (expected.Size() != actual.Size()) + { + throw new InvalidOperationException("Calling ImageComparer is invalid when dimensions mismatch!"); + } + + int width = actual.Width; + + // TODO: Comparing through Rgba32 is not robust enough because of the existance of super high precision pixel types. + + Rgba32[] aBuffer = new Rgba32[width]; + Rgba32[] bBuffer = new Rgba32[width]; + + double totalDifference = 0.0; + + var differences = new List(); + + for (int y = 0; y < actual.Height; y++) + { + Span aSpan = expected.GetRowSpan(y); + Span bSpan = actual.GetRowSpan(y); + + PixelOperations.Instance.ToRgba32(aSpan, aBuffer, width); + PixelOperations.Instance.ToRgba32(bSpan, bBuffer, width); + + for (int x = 0; x < width; x++) + { + int d = GetDifferenceInPixelByteSum(ref aBuffer[x], ref bBuffer[x]); + + if (d > this.PixelThresholdInPixelByteSum) + { + var diff = new PixelDifference(new Point(x, y), aBuffer[x], bBuffer[x]); + differences.Add(diff); + + float percentageDiff = (float)d / 4.0f / 255.0f; + totalDifference += percentageDiff; + } + } + } + + if (totalDifference > this.ImageThreshold) + { + return new ImageSimilarityReport(expected, actual, differences); + } + else + { + return ImageSimilarityReport.Empty; + } + } + + + private static int GetDifferenceInPixelByteSum(ref Rgba32 expected, ref Rgba32 actual) + { + return (int)actual.R - (int)expected.R + (int)actual.G - (int)expected.G + (int)actual.B - (int)expected.B + + (int)actual.A - (int)expected.A; } } } \ No newline at end of file