Browse Source

Update tests

pull/1574/head
James Jackson-South 6 years ago
parent
commit
a9aa3e5ef6
  1. 245
      src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs
  2. 2
      src/ImageSharp/Processing/KnownEdgeDetectorKernels.cs
  3. 2
      src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs
  4. 22
      tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs
  5. 196
      tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs
  6. 92
      tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs

245
src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Convolution; using SixLabors.ImageSharp.Processing.Processors.Convolution;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
@ -12,144 +11,230 @@ namespace SixLabors.ImageSharp.Processing
public static class DetectEdgesExtensions public static class DetectEdgesExtensions
{ {
/// <summary> /// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter /// Detects any edges within the image.
/// operating in grayscale mode. /// Uses the <see cref="KnownEdgeDetectorKernels.Sobel"/> kernel operating in grayscale mode.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(this IImageProcessingContext source) => public static IImageProcessingContext DetectEdges(this IImageProcessingContext source) =>
DetectEdges(source, new SobelProcessor(true)); DetectEdges(source, KnownEdgeDetectorKernels.Sobel);
/// <summary> /// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter /// Detects any edges within the image.
/// operating in grayscale mode. /// Uses the <see cref="KnownEdgeDetectorKernels.Sobel"/> kernel operating in grayscale mode.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="rectangle"> /// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param> /// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(this IImageProcessingContext source, Rectangle rectangle) => public static IImageProcessingContext DetectEdges(
DetectEdges(source, rectangle, new SobelProcessor(true)); this IImageProcessingContext source,
Rectangle rectangle) =>
DetectEdges(source, KnownEdgeDetectorKernels.Sobel, rectangle);
/// <summary> /// <summary>
/// Detects any edges within the image. /// Detects any edges within the image operating in grayscale mode.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param> /// <param name="kernel">The 2D edge detector kernel.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges( public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source, this IImageProcessingContext source,
KnownEdgeDetectionOperators filter) => EdgeDetector2DKernel kernel) =>
DetectEdges(source, GetProcessor(filter, true)); DetectEdges(source, kernel, true);
/// <summary> /// <summary>
/// Detects any edges within the image. /// Detects any edges within the image using a <see cref="EdgeDetector2DKernel"/>.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param> /// <param name="kernel">The 2D edge detector kernel.</param>
/// <param name="grayscale">Whether to convert the image to grayscale first. Defaults to true.</param> /// <param name="grayscale">
/// Whether to convert the image to grayscale before performing edge detection.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges( public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source, this IImageProcessingContext source,
KnownEdgeDetectionOperators filter, EdgeDetector2DKernel kernel,
bool grayscale) => bool grayscale)
DetectEdges(source, GetProcessor(filter, grayscale)); {
var processor = new EdgeDetector2DProcessor(kernel, grayscale);
source.ApplyProcessor(processor);
return source;
}
/// <summary> /// <summary>
/// Detects any edges within the image. /// Detects any edges within the image operating in grayscale mode.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param> /// <param name="kernel">The 2D edge detector kernel.</param>
/// <param name="rectangle"> /// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param> /// </param>
/// <param name="grayscale">Whether to convert the image to grayscale first. Defaults to true.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges( public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source, this IImageProcessingContext source,
KnownEdgeDetectionOperators filter, EdgeDetector2DKernel kernel,
Rectangle rectangle, Rectangle rectangle) =>
bool grayscale = true) => DetectEdges(source, kernel, true, rectangle);
DetectEdges(source, rectangle, GetProcessor(filter, grayscale));
/// <summary> /// <summary>
/// Detects any edges within the image. /// Detects any edges within the image using a <see cref="EdgeDetector2DKernel"/>.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param> /// <param name="kernel">The 2D edge detector kernel.</param>
/// <param name="grayscale">
/// Whether to convert the image to grayscale before performing edge detection.
/// </param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
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;
} }
/// <summary> /// <summary>
/// Detects any edges within the image. /// Detects any edges within the image operating in grayscale mode.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="rectangle"> /// <param name="kernel">The edge detector kernel.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectorKernel kernel) =>
DetectEdges(source, kernel, true);
/// <summary>
/// Detects any edges within the image using a <see cref="EdgeDetectorKernel"/>.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="kernel">The edge detector kernel.</param>
/// <param name="grayscale">
/// Whether to convert the image to grayscale before performing edge detection.
/// </param> /// </param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext DetectEdges( public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source, this IImageProcessingContext source,
Rectangle rectangle, EdgeDetectorKernel kernel,
IImageProcessor filter) bool grayscale)
{ {
source.ApplyProcessor(filter, rectangle); var processor = new EdgeDetectorProcessor(kernel, grayscale);
source.ApplyProcessor(processor);
return source; return source;
} }
private static IImageProcessor GetProcessor(KnownEdgeDetectionOperators filter, bool grayscale) /// <summary>
{ /// Detects any edges within the image operating in grayscale mode.
IImageProcessor processor; /// </summary>
/// <param name="source">The image this method extends.</param>
switch (filter) /// <param name="kernel">The edge detector kernel.</param>
{ /// <param name="rectangle">
case KnownEdgeDetectionOperators.Kayyali: /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
processor = new KayyaliProcessor(grayscale); /// </param>
break; /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
case KnownEdgeDetectionOperators.Kirsch: this IImageProcessingContext source,
processor = new KirschProcessor(grayscale); EdgeDetectorKernel kernel,
break; Rectangle rectangle) =>
DetectEdges(source, kernel, true, rectangle);
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;
case KnownEdgeDetectionOperators.RobertsCross: /// <summary>
processor = new RobertsCrossProcessor(grayscale); /// Detects any edges within the image using a <see cref="EdgeDetectorKernel"/>.
break; /// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="kernel">The edge detector kernel.</param>
/// <param name="grayscale">
/// Whether to convert the image to grayscale before performing edge detection.
/// </param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
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: /// <summary>
processor = new RobinsonProcessor(grayscale); /// Detects any edges within the image operating in grayscale mode.
break; /// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="kernel">Thecompass edge detector kernel.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectorCompassKernel kernel) =>
DetectEdges(source, kernel, true);
case KnownEdgeDetectionOperators.Scharr: /// <summary>
processor = new ScharrProcessor(grayscale); /// Detects any edges within the image using a <see cref="EdgeDetectorCompassKernel"/>.
break; /// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="kernel">Thecompass edge detector kernel.</param>
/// <param name="grayscale">
/// Whether to convert the image to grayscale before performing edge detection.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectorCompassKernel kernel,
bool grayscale)
{
var processor = new EdgeDetectorCompassProcessor(kernel, grayscale);
source.ApplyProcessor(processor);
return source;
}
default: /// <summary>
processor = new SobelProcessor(grayscale); /// Detects any edges within the image operating in grayscale mode.
break; /// </summary>
} /// <param name="source">The image this method extends.</param>
/// <param name="kernel">Thecompass edge detector kernel.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectorCompassKernel kernel,
Rectangle rectangle) =>
DetectEdges(source, kernel, true, rectangle);
return processor; /// <summary>
/// Detects any edges within the image using a <see cref="EdgeDetectorCompassKernel"/>.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="kernel">Thecompass edge detector kernel.</param>
/// <param name="grayscale">
/// Whether to convert the image to grayscale before performing edge detection.
/// </param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
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;
} }
} }
} }

2
src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs → src/ImageSharp/Processing/KnownEdgeDetectorKernels.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing
/// <summary> /// <summary>
/// Contains reusable static instances of known edge detection kernels. /// Contains reusable static instances of known edge detection kernels.
/// </summary> /// </summary>
public static class KnownEdgeDetectionOperators public static class KnownEdgeDetectorKernels
{ {
/// <summary> /// <summary>
/// Gets the Kayyali edge detector kernel. /// Gets the Kayyali edge detector kernel.

2
src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Configuration configuration = this.Source.GetConfiguration(); Configuration configuration = this.Source.GetConfiguration();
// Detect the edges. // 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. // Apply threshold binarization filter.
new BinaryThresholdProcessor(this.definition.Threshold).Execute(this.Configuration, temp, this.SourceRectangle); new BinaryThresholdProcessor(this.definition.Threshold).Execute(this.Configuration, temp, this.SourceRectangle);

22
tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs

@ -37,17 +37,17 @@ namespace SixLabors.ImageSharp.Benchmarks
[Benchmark(Description = "ImageSharp DetectEdges")] [Benchmark(Description = "ImageSharp DetectEdges")]
public void ImageProcessorCoreDetectEdges() public void ImageProcessorCoreDetectEdges()
{ {
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Kayyali)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Kayyali));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Kayyali)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Kayyali));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Kirsch)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Kirsch));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Laplacian3x3)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Laplacian3x3));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Laplacian5x5)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Laplacian5x5));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.LaplacianOfGaussian)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.LaplacianOfGaussian));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Prewitt)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Prewitt));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.RobertsCross)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.RobertsCross));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Robinson)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Robinson));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Scharr)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Scharr));
this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectionOperators.Sobel)); this.image.Mutate(x => x.DetectEdges(KnownEdgeDetectorKernels.Sobel));
} }
} }
} }

196
tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs

@ -1,12 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Convolution; using SixLabors.ImageSharp.Processing.Processors.Convolution;
using SixLabors.ImageSharp.Tests.TestUtilities;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Processing.Convolution namespace SixLabors.ImageSharp.Tests.Processing.Convolution
@ -14,62 +10,190 @@ namespace SixLabors.ImageSharp.Tests.Processing.Convolution
public class DetectEdgesTest : BaseImageOperationsExtensionTest public class DetectEdgesTest : BaseImageOperationsExtensionTest
{ {
[Fact] [Fact]
public void DetectEdges_SobelProcessorDefaultsSet() public void DetectEdges_EdgeDetector2DProcessorDefaultsSet()
{ {
this.operations.DetectEdges(); this.operations.DetectEdges();
EdgeDetector2DProcessor processor = this.Verify<EdgeDetector2DProcessor>();
// TODO: Enable once we have updated the images
SobelProcessor processor = this.Verify<SobelProcessor>();
Assert.True(processor.Grayscale); Assert.True(processor.Grayscale);
Assert.Equal(KnownEdgeDetectorKernels.Sobel, processor.Kernel);
} }
[Fact] [Fact]
public void DetectEdges_Rect_SobelProcessorDefaultsSet() public void DetectEdges_Rect_EdgeDetector2DProcessorDefaultsSet()
{ {
this.operations.DetectEdges(this.rect); this.operations.DetectEdges(this.rect);
EdgeDetector2DProcessor processor = this.Verify<EdgeDetector2DProcessor>(this.rect);
Assert.True(processor.Grayscale);
Assert.Equal(KnownEdgeDetectorKernels.Sobel, processor.Kernel);
}
public static TheoryData<EdgeDetector2DKernel, bool> EdgeDetector2DKernelData =
new TheoryData<EdgeDetector2DKernel, bool>
{
{ 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<EdgeDetector2DProcessor>();
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<EdgeDetector2DProcessor>(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<EdgeDetector2DProcessor>();
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<EdgeDetector2DProcessor>(this.rect);
Assert.Equal(grayscale, processor.Grayscale);
Assert.Equal(kernel, processor.Kernel);
}
public static TheoryData<EdgeDetectorKernel, bool> EdgeDetectorKernelData =
new TheoryData<EdgeDetectorKernel, bool>
{
{ 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<EdgeDetectorProcessor>();
// TODO: Enable once we have updated the images
SobelProcessor processor = this.Verify<SobelProcessor>(this.rect);
Assert.True(processor.Grayscale); Assert.True(processor.Grayscale);
Assert.Equal(kernel, processor.Kernel);
} }
public static IEnumerable<object[]> EdgeDetectionTheoryData => new[] [Theory]
[MemberData(nameof(EdgeDetectorKernelData))]
public void DetectEdges_Rect_EdgeDetectorProcessor_DefaultGrayScale_Set(EdgeDetectorKernel kernel, bool _)
{ {
new object[] { new TestType<KayyaliProcessor>(), KnownEdgeDetectionOperators.Kayyali }, this.operations.DetectEdges(kernel, this.rect);
new object[] { new TestType<KirschProcessor>(), KnownEdgeDetectionOperators.Kirsch }, EdgeDetectorProcessor processor = this.Verify<EdgeDetectorProcessor>(this.rect);
new object[] { new TestType<Laplacian3x3Processor>(), KnownEdgeDetectionOperators.Laplacian3x3 },
new object[] { new TestType<Laplacian5x5Processor>(), KnownEdgeDetectionOperators.Laplacian5x5 }, Assert.True(processor.Grayscale);
new object[] { new TestType<LaplacianOfGaussianProcessor>(), KnownEdgeDetectionOperators.LaplacianOfGaussian }, Assert.Equal(kernel, processor.Kernel);
new object[] { new TestType<PrewittProcessor>(), KnownEdgeDetectionOperators.Prewitt }, }
new object[] { new TestType<RobertsCrossProcessor>(), KnownEdgeDetectionOperators.RobertsCross },
new object[] { new TestType<RobinsonProcessor>(), KnownEdgeDetectionOperators.Robinson },
new object[] { new TestType<ScharrProcessor>(), KnownEdgeDetectionOperators.Scharr },
new object[] { new TestType<SobelProcessor>(), KnownEdgeDetectionOperators.Sobel },
};
[Theory] [Theory]
[MemberData(nameof(EdgeDetectionTheoryData))] [MemberData(nameof(EdgeDetectorKernelData))]
public void DetectEdges_filter_SobelProcessorDefaultsSet<TProcessor>(TestType<TProcessor> type, KnownEdgeDetectionOperators filter) public void DetectEdges_EdgeDetectorProcessorSet(EdgeDetectorKernel kernel, bool grayscale)
where TProcessor : EdgeDetectorProcessor
{ {
this.operations.DetectEdges(filter); this.operations.DetectEdges(kernel, grayscale);
EdgeDetectorProcessor processor = this.Verify<EdgeDetectorProcessor>();
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<EdgeDetectorProcessor>(this.rect);
Assert.Equal(grayscale, processor.Grayscale);
Assert.Equal(kernel, processor.Kernel);
}
public static TheoryData<EdgeDetectorCompassKernel, bool> EdgeDetectorCompassKernelData =
new TheoryData<EdgeDetectorCompassKernel, bool>
{
{ 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<EdgeDetectorCompassProcessor>();
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<EdgeDetectorCompassProcessor>(this.rect);
// TODO: Enable once we have updated the images
var processor = this.Verify<TProcessor>();
Assert.True(processor.Grayscale); 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<EdgeDetectorCompassProcessor>();
Assert.Equal(grayscale, processor.Grayscale);
Assert.Equal(kernel, processor.Kernel);
} }
[Theory] [Theory]
[MemberData(nameof(EdgeDetectionTheoryData))] [MemberData(nameof(EdgeDetectorCompassKernelData))]
public void DetectEdges_filter_grayscale_SobelProcessorDefaultsSet<TProcessor>(TestType<TProcessor> type, KnownEdgeDetectionOperators filter) public void DetectEdges_Rect_EdgeDetectorCompassProcessorSet(EdgeDetectorCompassKernel kernel, bool grayscale)
where TProcessor : EdgeDetectorProcessor
{ {
bool grey = (int)filter % 2 == 0; this.operations.DetectEdges(kernel, grayscale, this.rect);
this.operations.DetectEdges(filter, grey); EdgeDetectorCompassProcessor processor = this.Verify<EdgeDetectorCompassProcessor>(this.rect);
// TODO: Enable once we have updated the images Assert.Equal(grayscale, processor.Grayscale);
var processor = this.Verify<TProcessor>(); Assert.Equal(kernel, processor.Kernel);
Assert.Equal(grey, processor.Grayscale);
} }
} }
} }

92
tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs

@ -3,6 +3,7 @@
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Convolution;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit; using Xunit;
@ -20,18 +21,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector; public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector;
public static readonly TheoryData<KnownEdgeDetectionOperators> DetectEdgesFilters = new TheoryData<KnownEdgeDetectionOperators> public static readonly TheoryData<EdgeDetectorKernel> DetectEdgesFilters
= new TheoryData<EdgeDetectorKernel>
{ {
KnownEdgeDetectionOperators.Kayyali, KnownEdgeDetectorKernels.Laplacian3x3,
KnownEdgeDetectionOperators.Kirsch, KnownEdgeDetectorKernels.Laplacian5x5,
KnownEdgeDetectionOperators.Laplacian3x3, KnownEdgeDetectorKernels.LaplacianOfGaussian,
KnownEdgeDetectionOperators.Laplacian5x5, };
KnownEdgeDetectionOperators.LaplacianOfGaussian,
KnownEdgeDetectionOperators.Prewitt, public static readonly TheoryData<EdgeDetector2DKernel> DetectEdges2DFilters
KnownEdgeDetectionOperators.RobertsCross, = new TheoryData<EdgeDetector2DKernel>
KnownEdgeDetectionOperators.Robinson, {
KnownEdgeDetectionOperators.Scharr, KnownEdgeDetectorKernels.Kayyali,
KnownEdgeDetectionOperators.Sobel KnownEdgeDetectorKernels.Prewitt,
KnownEdgeDetectorKernels.RobertsCross,
KnownEdgeDetectorKernels.Scharr,
KnownEdgeDetectorKernels.Sobel
};
public static readonly TheoryData<EdgeDetectorCompassKernel> DetectEdgesCompassFilters
= new TheoryData<EdgeDetectorCompassKernel>
{
KnownEdgeDetectorKernels.Kirsch,
KnownEdgeDetectorKernels.Robinson,
}; };
[Theory] [Theory]
@ -53,7 +65,39 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
[Theory] [Theory]
[WithTestPatternImages(nameof(DetectEdgesFilters), 100, 100, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(DetectEdgesFilters), 100, 100, PixelTypes.Rgba32)]
[WithFileCollection(nameof(TestImages), nameof(DetectEdgesFilters), PixelTypes.Rgba32)] [WithFileCollection(nameof(TestImages), nameof(DetectEdgesFilters), PixelTypes.Rgba32)]
public void DetectEdges_WorksWithAllFilters<TPixel>(TestImageProvider<TPixel> provider, KnownEdgeDetectionOperators detector) public void DetectEdges_WorksWithAllFilters<TPixel>(TestImageProvider<TPixel> provider, EdgeDetectorKernel detector)
where TPixel : unmanaged, IPixel<TPixel>
{
bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern");
ImageComparer comparer = hasAlpha ? TransparentComparer : OpaqueComparer;
using (Image<TPixel> 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<TPixel>(TestImageProvider<TPixel> provider, EdgeDetector2DKernel detector)
where TPixel : unmanaged, IPixel<TPixel>
{
bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern");
ImageComparer comparer = hasAlpha ? TransparentComparer : OpaqueComparer;
using (Image<TPixel> 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<TPixel>(TestImageProvider<TPixel> provider, EdgeDetectorCompassKernel detector)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern"); bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern");
@ -115,7 +159,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
[Theory] [Theory]
[WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdgesFilters), PixelTypes.Rgba32)] [WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdgesFilters), PixelTypes.Rgba32)]
public void WorksWithDiscoBuffers<TPixel>(TestImageProvider<TPixel> provider, KnownEdgeDetectionOperators detector) public void WorksWithDiscoBuffers<TPixel>(TestImageProvider<TPixel> provider, EdgeDetectorKernel detector)
where TPixel : unmanaged, IPixel<TPixel>
{
provider.RunBufferCapacityLimitProcessorTest(
41,
c => c.DetectEdges(detector),
detector);
}
[Theory]
[WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdges2DFilters), PixelTypes.Rgba32)]
public void WorksWithDiscoBuffers2D<TPixel>(TestImageProvider<TPixel> provider, EdgeDetector2DKernel detector)
where TPixel : unmanaged, IPixel<TPixel>
{
provider.RunBufferCapacityLimitProcessorTest(
41,
c => c.DetectEdges(detector),
detector);
}
[Theory]
[WithFile(Tests.TestImages.Png.Bike, nameof(DetectEdgesCompassFilters), PixelTypes.Rgba32)]
public void WorksWithDiscoBuffersCompass<TPixel>(TestImageProvider<TPixel> provider, EdgeDetectorCompassKernel detector)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
provider.RunBufferCapacityLimitProcessorTest( provider.RunBufferCapacityLimitProcessorTest(

Loading…
Cancel
Save