From a9aa3e5ef6b1d1f8759063d1ba6661cdb580fa81 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 1 Aug 2020 21:51:32 +0100 Subject: [PATCH] Update tests --- .../Convolution/DetectEdgesExtensions.cs | 245 ++++++++++++------ ...erators.cs => KnownEdgeDetectorKernels.cs} | 2 +- .../EntropyCropProcessor{TPixel}.cs | 2 +- .../Samplers/DetectEdges.cs | 22 +- .../Processing/Convolution/DetectEdgesTest.cs | 196 +++++++++++--- .../Processors/Convolution/DetectEdgesTest.cs | 92 ++++++- 6 files changed, 417 insertions(+), 142 deletions(-) rename src/ImageSharp/Processing/{KnownEdgeDetectionOperators.cs => KnownEdgeDetectorKernels.cs} (97%) diff --git a/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs index f30d8ad57..2377151bb 100644 --- a/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors.Convolution; namespace SixLabors.ImageSharp.Processing @@ -12,144 +11,230 @@ namespace SixLabors.ImageSharp.Processing public static class DetectEdgesExtensions { /// - /// Detects any edges within the image. Uses the filter - /// operating in grayscale mode. + /// Detects any edges within the image. + /// Uses the kernel operating in grayscale mode. /// /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext DetectEdges(this IImageProcessingContext source) => - DetectEdges(source, new SobelProcessor(true)); + DetectEdges(source, KnownEdgeDetectorKernels.Sobel); /// - /// Detects any edges within the image. Uses the filter - /// operating in grayscale mode. + /// Detects any edges within the image. + /// Uses the kernel operating in grayscale mode. /// /// The image this method extends. /// /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext DetectEdges(this IImageProcessingContext source, Rectangle rectangle) => - DetectEdges(source, rectangle, new SobelProcessor(true)); + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + Rectangle rectangle) => + DetectEdges(source, KnownEdgeDetectorKernels.Sobel, rectangle); /// - /// Detects any edges within the image. + /// Detects any edges within the image operating in grayscale mode. /// /// The image this method extends. - /// The filter for detecting edges. + /// The 2D edge detector kernel. /// The to allow chaining of operations. public static IImageProcessingContext DetectEdges( this IImageProcessingContext source, - KnownEdgeDetectionOperators filter) => - DetectEdges(source, GetProcessor(filter, true)); + EdgeDetector2DKernel kernel) => + DetectEdges(source, kernel, true); /// - /// Detects any edges within the image. + /// Detects any edges within the image using a . /// /// The image this method extends. - /// The filter for detecting edges. - /// Whether to convert the image to grayscale first. Defaults to true. + /// The 2D edge detector kernel. + /// + /// Whether to convert the image to grayscale before performing edge detection. + /// /// The to allow chaining of operations. public static IImageProcessingContext DetectEdges( this IImageProcessingContext source, - KnownEdgeDetectionOperators filter, - bool grayscale) => - DetectEdges(source, GetProcessor(filter, grayscale)); + EdgeDetector2DKernel kernel, + bool grayscale) + { + var processor = new EdgeDetector2DProcessor(kernel, grayscale); + source.ApplyProcessor(processor); + return source; + } /// - /// Detects any edges within the image. + /// Detects any edges within the image operating in grayscale mode. /// /// The image this method extends. - /// The filter for detecting edges. + /// The 2D edge detector kernel. /// /// The structure that specifies the portion of the image object to alter. /// - /// Whether to convert the image to grayscale first. Defaults to true. /// The to allow chaining of operations. public static IImageProcessingContext DetectEdges( this IImageProcessingContext source, - KnownEdgeDetectionOperators filter, - Rectangle rectangle, - bool grayscale = true) => - DetectEdges(source, rectangle, GetProcessor(filter, grayscale)); + EdgeDetector2DKernel kernel, + Rectangle rectangle) => + DetectEdges(source, kernel, true, rectangle); /// - /// Detects any edges within the image. + /// Detects any edges within the image using a . /// /// The image this method extends. - /// The filter for detecting edges. + /// The 2D edge detector kernel. + /// + /// Whether to convert the image to grayscale before performing edge detection. + /// + /// + /// The structure that specifies the portion of the image object to alter. + /// /// The to allow chaining of operations. - private static IImageProcessingContext DetectEdges(this IImageProcessingContext source, IImageProcessor filter) + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetector2DKernel kernel, + bool grayscale, + Rectangle rectangle) { - return source.ApplyProcessor(filter); + var processor = new EdgeDetector2DProcessor(kernel, grayscale); + source.ApplyProcessor(processor, rectangle); + return source; } /// - /// Detects any edges within the image. + /// Detects any edges within the image operating in grayscale mode. /// /// The image this method extends. - /// - /// The structure that specifies the portion of the image object to alter. + /// The edge detector kernel. + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorKernel kernel) => + DetectEdges(source, kernel, true); + + /// + /// Detects any edges within the image using a . + /// + /// The image this method extends. + /// The edge detector kernel. + /// + /// Whether to convert the image to grayscale before performing edge detection. /// - /// The filter for detecting edges. /// The to allow chaining of operations. - private static IImageProcessingContext DetectEdges( + public static IImageProcessingContext DetectEdges( this IImageProcessingContext source, - Rectangle rectangle, - IImageProcessor filter) + EdgeDetectorKernel kernel, + bool grayscale) { - source.ApplyProcessor(filter, rectangle); + var processor = new EdgeDetectorProcessor(kernel, grayscale); + source.ApplyProcessor(processor); return source; } - private static IImageProcessor GetProcessor(KnownEdgeDetectionOperators filter, bool grayscale) - { - IImageProcessor processor; - - switch (filter) - { - case KnownEdgeDetectionOperators.Kayyali: - processor = new KayyaliProcessor(grayscale); - break; - - case KnownEdgeDetectionOperators.Kirsch: - processor = new KirschProcessor(grayscale); - break; - - case KnownEdgeDetectionOperators.Laplacian3x3: - processor = new Laplacian3x3Processor(grayscale); - break; - - case KnownEdgeDetectionOperators.Laplacian5x5: - processor = new Laplacian5x5Processor(grayscale); - break; - - case KnownEdgeDetectionOperators.LaplacianOfGaussian: - processor = new LaplacianOfGaussianProcessor(grayscale); - break; - - case KnownEdgeDetectionOperators.Prewitt: - processor = new PrewittProcessor(grayscale); - break; + /// + /// Detects any edges within the image operating in grayscale mode. + /// + /// The image this method extends. + /// The edge detector kernel. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorKernel kernel, + Rectangle rectangle) => + DetectEdges(source, kernel, true, rectangle); - case KnownEdgeDetectionOperators.RobertsCross: - processor = new RobertsCrossProcessor(grayscale); - break; + /// + /// Detects any edges within the image using a . + /// + /// The image this method extends. + /// The edge detector kernel. + /// + /// Whether to convert the image to grayscale before performing edge detection. + /// + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorKernel kernel, + bool grayscale, + Rectangle rectangle) + { + var processor = new EdgeDetectorProcessor(kernel, grayscale); + source.ApplyProcessor(processor, rectangle); + return source; + } - case KnownEdgeDetectionOperators.Robinson: - processor = new RobinsonProcessor(grayscale); - break; + /// + /// Detects any edges within the image operating in grayscale mode. + /// + /// The image this method extends. + /// Thecompass edge detector kernel. + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorCompassKernel kernel) => + DetectEdges(source, kernel, true); - case KnownEdgeDetectionOperators.Scharr: - processor = new ScharrProcessor(grayscale); - break; + /// + /// Detects any edges within the image using a . + /// + /// The image this method extends. + /// Thecompass edge detector kernel. + /// + /// Whether to convert the image to grayscale before performing edge detection. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorCompassKernel kernel, + bool grayscale) + { + var processor = new EdgeDetectorCompassProcessor(kernel, grayscale); + source.ApplyProcessor(processor); + return source; + } - default: - processor = new SobelProcessor(grayscale); - break; - } + /// + /// Detects any edges within the image operating in grayscale mode. + /// + /// The image this method extends. + /// Thecompass edge detector kernel. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorCompassKernel kernel, + Rectangle rectangle) => + DetectEdges(source, kernel, true, rectangle); - return processor; + /// + /// Detects any edges within the image using a . + /// + /// The image this method extends. + /// Thecompass edge detector kernel. + /// + /// Whether to convert the image to grayscale before performing edge detection. + /// + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext DetectEdges( + this IImageProcessingContext source, + EdgeDetectorCompassKernel kernel, + bool grayscale, + Rectangle rectangle) + { + var processor = new EdgeDetectorCompassProcessor(kernel, grayscale); + source.ApplyProcessor(processor, rectangle); + return source; } } } diff --git a/src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs b/src/ImageSharp/Processing/KnownEdgeDetectorKernels.cs similarity index 97% rename from src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs rename to src/ImageSharp/Processing/KnownEdgeDetectorKernels.cs index e41fb00ce..2e279d340 100644 --- a/src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs +++ b/src/ImageSharp/Processing/KnownEdgeDetectorKernels.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Contains reusable static instances of known edge detection kernels. /// - public static class KnownEdgeDetectionOperators + public static class KnownEdgeDetectorKernels { /// /// Gets the Kayyali edge detector kernel. diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs index ebc8f0e4f..dd9c06938 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Configuration configuration = this.Source.GetConfiguration(); // Detect the edges. - new SobelProcessor(false).Execute(this.Configuration, temp, this.SourceRectangle); + new EdgeDetector2DProcessor(KnownEdgeDetectorKernels.Sobel, false).Execute(this.Configuration, temp, this.SourceRectangle); // Apply threshold binarization filter. new BinaryThresholdProcessor(this.definition.Threshold).Execute(this.Configuration, temp, this.SourceRectangle); diff --git a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs index cf46c4f52..ce2fa988c 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs @@ -37,17 +37,17 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp DetectEdges")] public void ImageProcessorCoreDetectEdges() { - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Kayyali)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Kayyali)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Kirsch)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Laplacian3x3)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Laplacian5x5)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.LaplacianOfGaussian)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Prewitt)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.RobertsCross)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Robinson)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Scharr)); - this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Sobel)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Kayyali)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Kayyali)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Kirsch)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Laplacian3x3)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Laplacian5x5)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.LaplacianOfGaussian)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Prewitt)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.RobertsCross)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Robinson)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Scharr)); + this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Sobel)); } } } diff --git a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs index fd41a04e2..e14ab748f 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs @@ -1,12 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; - using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Convolution; -using SixLabors.ImageSharp.Tests.TestUtilities; - using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Convolution @@ -14,62 +10,190 @@ namespace SixLabors.ImageSharp.Tests.Processing.Convolution public class DetectEdgesTest : BaseImageOperationsExtensionTest { [Fact] - public void DetectEdges_SobelProcessorDefaultsSet() + public void DetectEdges_EdgeDetector2DProcessorDefaultsSet() { this.operations.DetectEdges(); + EdgeDetector2DProcessor processor = this.Verify(); - // TODO: Enable once we have updated the images - SobelProcessor processor = this.Verify(); Assert.True(processor.Grayscale); + Assert.Equal(KnownEdgeDetectorKernels.Sobel, processor.Kernel); } [Fact] - public void DetectEdges_Rect_SobelProcessorDefaultsSet() + public void DetectEdges_Rect_EdgeDetector2DProcessorDefaultsSet() { this.operations.DetectEdges(this.rect); + EdgeDetector2DProcessor processor = this.Verify(this.rect); + + Assert.True(processor.Grayscale); + Assert.Equal(KnownEdgeDetectorKernels.Sobel, processor.Kernel); + } + + public static TheoryData EdgeDetector2DKernelData = + new TheoryData + { + { KnownEdgeDetectorKernels.Kayyali, true }, + { KnownEdgeDetectorKernels.Kayyali, false }, + { KnownEdgeDetectorKernels.Prewitt, true }, + { KnownEdgeDetectorKernels.Prewitt, false }, + { KnownEdgeDetectorKernels.RobertsCross, true }, + { KnownEdgeDetectorKernels.RobertsCross, false }, + { KnownEdgeDetectorKernels.Scharr, true }, + { KnownEdgeDetectorKernels.Scharr, false }, + { KnownEdgeDetectorKernels.Sobel, true }, + { KnownEdgeDetectorKernels.Sobel, false }, + }; + + [Theory] + [MemberData(nameof(EdgeDetector2DKernelData))] + public void DetectEdges_EdgeDetector2DProcessor_DefaultGrayScale_Set(EdgeDetector2DKernel kernel, bool _) + { + this.operations.DetectEdges(kernel); + EdgeDetector2DProcessor processor = this.Verify(); + + Assert.True(processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + [Theory] + [MemberData(nameof(EdgeDetector2DKernelData))] + public void DetectEdges_Rect_EdgeDetector2DProcessor_DefaultGrayScale_Set(EdgeDetector2DKernel kernel, bool _) + { + this.operations.DetectEdges(kernel, this.rect); + EdgeDetector2DProcessor processor = this.Verify(this.rect); + + Assert.True(processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + [Theory] + [MemberData(nameof(EdgeDetector2DKernelData))] + public void DetectEdges_EdgeDetector2DProcessorSet(EdgeDetector2DKernel kernel, bool grayscale) + { + this.operations.DetectEdges(kernel, grayscale); + EdgeDetector2DProcessor processor = this.Verify(); + + Assert.Equal(grayscale, processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + [Theory] + [MemberData(nameof(EdgeDetector2DKernelData))] + public void DetectEdges_Rect_EdgeDetector2DProcessorSet(EdgeDetector2DKernel kernel, bool grayscale) + { + this.operations.DetectEdges(kernel, grayscale, this.rect); + EdgeDetector2DProcessor processor = this.Verify(this.rect); + + Assert.Equal(grayscale, processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + public static TheoryData EdgeDetectorKernelData = + new TheoryData + { + { KnownEdgeDetectorKernels.Laplacian3x3, true }, + { KnownEdgeDetectorKernels.Laplacian3x3, false }, + { KnownEdgeDetectorKernels.Laplacian5x5, true }, + { KnownEdgeDetectorKernels.Laplacian5x5, false }, + { KnownEdgeDetectorKernels.LaplacianOfGaussian, true }, + { KnownEdgeDetectorKernels.LaplacianOfGaussian, false }, + }; + + [Theory] + [MemberData(nameof(EdgeDetectorKernelData))] + public void DetectEdges_EdgeDetectorProcessor_DefaultGrayScale_Set(EdgeDetectorKernel kernel, bool _) + { + this.operations.DetectEdges(kernel); + EdgeDetectorProcessor processor = this.Verify(); - // TODO: Enable once we have updated the images - SobelProcessor processor = this.Verify(this.rect); Assert.True(processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); } - public static IEnumerable EdgeDetectionTheoryData => new[] + [Theory] + [MemberData(nameof(EdgeDetectorKernelData))] + public void DetectEdges_Rect_EdgeDetectorProcessor_DefaultGrayScale_Set(EdgeDetectorKernel kernel, bool _) { - new object[] { new TestType(), KnownEdgeDetectionOperators.Kayyali }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Kirsch }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Laplacian3x3 }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Laplacian5x5 }, - new object[] { new TestType(), KnownEdgeDetectionOperators.LaplacianOfGaussian }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Prewitt }, - new object[] { new TestType(), KnownEdgeDetectionOperators.RobertsCross }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Robinson }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Scharr }, - new object[] { new TestType(), KnownEdgeDetectionOperators.Sobel }, - }; + this.operations.DetectEdges(kernel, this.rect); + EdgeDetectorProcessor processor = this.Verify(this.rect); + + Assert.True(processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } [Theory] - [MemberData(nameof(EdgeDetectionTheoryData))] - public void DetectEdges_filter_SobelProcessorDefaultsSet(TestType type, KnownEdgeDetectionOperators filter) - where TProcessor : EdgeDetectorProcessor + [MemberData(nameof(EdgeDetectorKernelData))] + public void DetectEdges_EdgeDetectorProcessorSet(EdgeDetectorKernel kernel, bool grayscale) { - this.operations.DetectEdges(filter); + this.operations.DetectEdges(kernel, grayscale); + EdgeDetectorProcessor processor = this.Verify(); + + Assert.Equal(grayscale, processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + [Theory] + [MemberData(nameof(EdgeDetectorKernelData))] + public void DetectEdges_Rect_EdgeDetectorProcessorSet(EdgeDetectorKernel kernel, bool grayscale) + { + this.operations.DetectEdges(kernel, grayscale, this.rect); + EdgeDetectorProcessor processor = this.Verify(this.rect); + + Assert.Equal(grayscale, processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + public static TheoryData EdgeDetectorCompassKernelData = + new TheoryData + { + { KnownEdgeDetectorKernels.Kirsch, true }, + { KnownEdgeDetectorKernels.Kirsch, false }, + { KnownEdgeDetectorKernels.Robinson, true }, + { KnownEdgeDetectorKernels.Robinson, false }, + }; + + [Theory] + [MemberData(nameof(EdgeDetectorCompassKernelData))] + public void DetectEdges_EdgeDetectorCompassProcessor_DefaultGrayScale_Set(EdgeDetectorCompassKernel kernel, bool _) + { + this.operations.DetectEdges(kernel); + EdgeDetectorCompassProcessor processor = this.Verify(); + + Assert.True(processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + [Theory] + [MemberData(nameof(EdgeDetectorCompassKernelData))] + public void DetectEdges_Rect_EdgeDetectorCompassProcessor_DefaultGrayScale_Set(EdgeDetectorCompassKernel kernel, bool _) + { + this.operations.DetectEdges(kernel, this.rect); + EdgeDetectorCompassProcessor processor = this.Verify(this.rect); - // TODO: Enable once we have updated the images - var processor = this.Verify(); Assert.True(processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); + } + + [Theory] + [MemberData(nameof(EdgeDetectorCompassKernelData))] + public void DetectEdges_EdgeDetectorCompassProcessorSet(EdgeDetectorCompassKernel kernel, bool grayscale) + { + this.operations.DetectEdges(kernel, grayscale); + EdgeDetectorCompassProcessor processor = this.Verify(); + + Assert.Equal(grayscale, processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); } [Theory] - [MemberData(nameof(EdgeDetectionTheoryData))] - public void DetectEdges_filter_grayscale_SobelProcessorDefaultsSet(TestType type, KnownEdgeDetectionOperators filter) - where TProcessor : EdgeDetectorProcessor + [MemberData(nameof(EdgeDetectorCompassKernelData))] + public void DetectEdges_Rect_EdgeDetectorCompassProcessorSet(EdgeDetectorCompassKernel kernel, bool grayscale) { - bool grey = (int)filter % 2 == 0; - this.operations.DetectEdges(filter, grey); + this.operations.DetectEdges(kernel, grayscale, this.rect); + EdgeDetectorCompassProcessor processor = this.Verify(this.rect); - // TODO: Enable once we have updated the images - var processor = this.Verify(); - Assert.Equal(grey, processor.Grayscale); + Assert.Equal(grayscale, processor.Grayscale); + Assert.Equal(kernel, processor.Kernel); } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs index a96b05d63..7a3b104b3 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs @@ -3,6 +3,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Convolution; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; @@ -20,18 +21,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector; - public static readonly TheoryData DetectEdgesFilters = new TheoryData + public static readonly TheoryData DetectEdgesFilters + = new TheoryData { - KnownEdgeDetectionOperators.Kayyali, - KnownEdgeDetectionOperators.Kirsch, - KnownEdgeDetectionOperators.Laplacian3x3, - KnownEdgeDetectionOperators.Laplacian5x5, - KnownEdgeDetectionOperators.LaplacianOfGaussian, - KnownEdgeDetectionOperators.Prewitt, - KnownEdgeDetectionOperators.RobertsCross, - KnownEdgeDetectionOperators.Robinson, - KnownEdgeDetectionOperators.Scharr, - KnownEdgeDetectionOperators.Sobel + KnownEdgeDetectorKernels.Laplacian3x3, + KnownEdgeDetectorKernels.Laplacian5x5, + KnownEdgeDetectorKernels.LaplacianOfGaussian, + }; + + public static readonly TheoryData DetectEdges2DFilters + = new TheoryData + { + KnownEdgeDetectorKernels.Kayyali, + KnownEdgeDetectorKernels.Prewitt, + KnownEdgeDetectorKernels.RobertsCross, + KnownEdgeDetectorKernels.Scharr, + KnownEdgeDetectorKernels.Sobel + }; + + public static readonly TheoryData DetectEdgesCompassFilters + = new TheoryData + { + KnownEdgeDetectorKernels.Kirsch, + KnownEdgeDetectorKernels.Robinson, }; [Theory] @@ -53,7 +65,39 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution [Theory] [WithTestPatternImages(nameof(DetectEdgesFilters), 100, 100, PixelTypes.Rgba32)] [WithFileCollection(nameof(TestImages), nameof(DetectEdgesFilters), PixelTypes.Rgba32)] - public void DetectEdges_WorksWithAllFilters(TestImageProvider provider, KnownEdgeDetectionOperators detector) + public void DetectEdges_WorksWithAllFilters(TestImageProvider provider, EdgeDetectorKernel detector) + where TPixel : unmanaged, IPixel + { + bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern"); + ImageComparer comparer = hasAlpha ? TransparentComparer : OpaqueComparer; + using (Image image = provider.GetImage()) + { + image.Mutate(x => x.DetectEdges(detector)); + image.DebugSave(provider, detector.ToString()); + image.CompareToReferenceOutput(comparer, provider, detector.ToString()); + } + } + + [Theory] + [WithTestPatternImages(nameof(DetectEdgesFilters), 100, 100, PixelTypes.Rgba32)] + [WithFileCollection(nameof(TestImages), nameof(DetectEdges2DFilters), PixelTypes.Rgba32)] + public void DetectEdges2D_WorksWithAllFilters(TestImageProvider provider, EdgeDetector2DKernel detector) + where TPixel : unmanaged, IPixel + { + bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern"); + ImageComparer comparer = hasAlpha ? TransparentComparer : OpaqueComparer; + using (Image image = provider.GetImage()) + { + image.Mutate(x => x.DetectEdges(detector)); + image.DebugSave(provider, detector.ToString()); + image.CompareToReferenceOutput(comparer, provider, detector.ToString()); + } + } + + [Theory] + [WithTestPatternImages(nameof(DetectEdgesCompassFilters), 100, 100, PixelTypes.Rgba32)] + [WithFileCollection(nameof(TestImages), nameof(DetectEdgesFilters), PixelTypes.Rgba32)] + public void DetectEdgesCompass_WorksWithAllFilters(TestImageProvider provider, EdgeDetectorCompassKernel detector) where TPixel : unmanaged, IPixel { bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern"); @@ -115,7 +159,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution [Theory] [WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdgesFilters), PixelTypes.Rgba32)] - public void WorksWithDiscoBuffers(TestImageProvider provider, KnownEdgeDetectionOperators detector) + public void WorksWithDiscoBuffers(TestImageProvider provider, EdgeDetectorKernel detector) + where TPixel : unmanaged, IPixel + { + provider.RunBufferCapacityLimitProcessorTest( + 41, + c => c.DetectEdges(detector), + detector); + } + + [Theory] + [WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdges2DFilters), PixelTypes.Rgba32)] + public void WorksWithDiscoBuffers2D(TestImageProvider provider, EdgeDetector2DKernel detector) + where TPixel : unmanaged, IPixel + { + provider.RunBufferCapacityLimitProcessorTest( + 41, + c => c.DetectEdges(detector), + detector); + } + + [Theory] + [WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdgesCompassFilters), PixelTypes.Rgba32)] + public void WorksWithDiscoBuffersCompass(TestImageProvider provider, EdgeDetectorCompassKernel detector) where TPixel : unmanaged, IPixel { provider.RunBufferCapacityLimitProcessorTest(