Browse Source

Refactor edge detection

pull/904/head
Anton Firszov 7 years ago
parent
commit
d8bdac61a0
  1. 1
      src/ImageSharp/ImageSharp.csproj.DotSettings
  2. 96
      src/ImageSharp/Processing/DetectEdgesExtensions.cs
  3. 2
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs
  4. 5
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs
  5. 54
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs
  6. 37
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs
  7. 49
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs
  8. 22
      src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs
  9. 57
      src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs
  10. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs
  11. 18
      src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs
  12. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs
  13. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs
  14. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs
  15. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs
  16. 20
      src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs
  17. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs
  18. 0
      src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs
  19. 40
      src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs
  20. 14
      src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs
  21. 20
      src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs
  22. 18
      src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs
  23. 20
      src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs
  24. 18
      src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs
  25. 38
      src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs
  26. 16
      src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs
  27. 27
      src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs
  28. 2
      src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs
  29. 40
      tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs

1
src/ImageSharp/ImageSharp.csproj.DotSettings

@ -6,5 +6,6 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixelimplementations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixeltypes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cutils/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Cconvolution_005Ckernels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresamplers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresize/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

96
src/ImageSharp/Processing/DetectEdgesExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Convolution;
using SixLabors.Primitives;
@ -9,82 +8,79 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Adds edge detection extensions to the <see cref="Image{TPixel}"/> type.
/// Adds edge detection extensions to the <see cref="Image"/> type.
/// </summary>
public static class DetectEdgesExtensions
{
/// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor{TPixel}"/> filter
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter
/// operating in grayscale mode.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, new SobelProcessor<TPixel>(true));
/// <returns>The <see cref="Image"/>.</returns>
public static IImageProcessingContext DetectEdges(this IImageProcessingContext source) =>
DetectEdges(source, new SobelProcessor(true));
/// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor{TPixel}"/> filter
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter
/// operating in grayscale mode.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, rectangle, new SobelProcessor<TPixel>(true));
/// <returns>The <see cref="Image"/>.</returns>
public static IImageProcessingContext DetectEdges(this IImageProcessingContext source, Rectangle rectangle) =>
DetectEdges(source, rectangle, new SobelProcessor(true));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetectionOperators filter)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, GetProcessor<TPixel>(filter, true));
/// <returns>The <see cref="Image"/>.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectionOperators filter) =>
DetectEdges(source, GetProcessor(filter, true));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="grayscale">Whether to convert the image to grayscale first. Defaults to true.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetectionOperators filter, bool grayscale)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, GetProcessor<TPixel>(filter, grayscale));
/// <returns>The <see cref="Image"/>.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectionOperators filter,
bool grayscale) =>
DetectEdges(source, GetProcessor(filter, grayscale));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="grayscale">Whether to convert the image to grayscale first. Defaults to true.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetectionOperators filter, Rectangle rectangle, bool grayscale = true)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, rectangle, GetProcessor<TPixel>(filter, grayscale));
/// <returns>The <see cref="Image"/>.</returns>
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
EdgeDetectionOperators filter,
Rectangle rectangle,
bool grayscale = true) =>
DetectEdges(source, rectangle, GetProcessor(filter, grayscale));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
private static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, IImageProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="Image"/>.</returns>
private static IImageProcessingContext DetectEdges(this IImageProcessingContext source, IImageProcessor filter)
{
return source.ApplyProcessor(filter);
}
@ -92,65 +88,65 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
private static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, IImageProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
/// <returns>The <see cref="Image"/>.</returns>
private static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
Rectangle rectangle,
IImageProcessor filter)
{
source.ApplyProcessor(filter, rectangle);
return source;
}
private static IImageProcessor<TPixel> GetProcessor<TPixel>(EdgeDetectionOperators filter, bool grayscale)
where TPixel : struct, IPixel<TPixel>
private static IImageProcessor GetProcessor(EdgeDetectionOperators filter, bool grayscale)
{
IImageProcessor<TPixel> processor;
IImageProcessor processor;
switch (filter)
{
case EdgeDetectionOperators.Kayyali:
processor = new KayyaliProcessor<TPixel>(grayscale);
processor = new KayyaliProcessor(grayscale);
break;
case EdgeDetectionOperators.Kirsch:
processor = new KirschProcessor<TPixel>(grayscale);
processor = new KirschProcessor(grayscale);
break;
case EdgeDetectionOperators.Laplacian3x3:
processor = new Laplacian3x3Processor<TPixel>(grayscale);
processor = new Laplacian3x3Processor(grayscale);
break;
case EdgeDetectionOperators.Laplacian5x5:
processor = new Laplacian5x5Processor<TPixel>(grayscale);
processor = new Laplacian5x5Processor(grayscale);
break;
case EdgeDetectionOperators.LaplacianOfGaussian:
processor = new LaplacianOfGaussianProcessor<TPixel>(grayscale);
processor = new LaplacianOfGaussianProcessor(grayscale);
break;
case EdgeDetectionOperators.Prewitt:
processor = new PrewittProcessor<TPixel>(grayscale);
processor = new PrewittProcessor(grayscale);
break;
case EdgeDetectionOperators.RobertsCross:
processor = new RobertsCrossProcessor<TPixel>(grayscale);
processor = new RobertsCrossProcessor(grayscale);
break;
case EdgeDetectionOperators.Robinson:
processor = new RobinsonProcessor<TPixel>(grayscale);
processor = new RobinsonProcessor(grayscale);
break;
case EdgeDetectionOperators.Scharr:
processor = new ScharrProcessor<TPixel>(grayscale);
processor = new ScharrProcessor(grayscale);
break;
default:
processor = new SobelProcessor<TPixel>(grayscale);
processor = new SobelProcessor(grayscale);
break;
}

2
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Kernel radius is calculated using the minimum viable value.
/// See http://chemaguerra.com/gaussian-filter-radius/ .
/// See <see href="http://chemaguerra.com/gaussian-filter-radius/"/>.
/// </summary>
internal static int GetDefaultGaussianRadius(float sigma)
{

5
src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Defines a processor that detects edges within an image using two one-dimensional matrices.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class EdgeDetector2DProcessor<TPixel> : ImageProcessor<TPixel>
internal class EdgeDetector2DProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <param name="kernelX">The horizontal gradient operator.</param>
/// <param name="kernelY">The vertical gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetector2DProcessor(in DenseMatrix<float> kernelX, in DenseMatrix<float> kernelY, bool grayscale)
internal EdgeDetector2DProcessor(in DenseMatrix<float> kernelX, in DenseMatrix<float> kernelY, bool grayscale)
{
Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same.");
this.KernelX = kernelX;
@ -39,7 +39,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// </summary>
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
public bool Grayscale { get; }
/// <inheritdoc />

54
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs

@ -19,57 +19,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Defines a processor that detects edges within an image using a eight two dimensional matrices.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>
internal class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="EdgeDetectorCompassProcessor{TPixel}"/> class.
/// </summary>
/// <param name="kernels">Gets the kernels to use.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorCompassProcessor(bool grayscale) => this.Grayscale = grayscale;
/// <summary>
/// Gets the North gradient operator
/// </summary>
public abstract DenseMatrix<float> North { get; }
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public abstract DenseMatrix<float> NorthWest { get; }
/// <summary>
/// Gets the West gradient operator
/// </summary>
public abstract DenseMatrix<float> West { get; }
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public abstract DenseMatrix<float> SouthWest { get; }
/// <summary>
/// Gets the South gradient operator
/// </summary>
public abstract DenseMatrix<float> South { get; }
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public abstract DenseMatrix<float> SouthEast { get; }
/// <summary>
/// Gets the East gradient operator
/// </summary>
public abstract DenseMatrix<float> East { get; }
internal EdgeDetectorCompassProcessor(CompassKernels kernels, bool grayscale)
{
this.Grayscale = grayscale;
this.Kernels = kernels;
}
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public abstract DenseMatrix<float> NorthEast { get; }
private CompassKernels Kernels { get; }
/// <inheritdoc/>
public bool Grayscale { get; }
private bool Grayscale { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
@ -83,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
DenseMatrix<float>[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
DenseMatrix<float>[] kernels = this.Kernels.Flatten();
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;

37
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs

@ -2,49 +2,30 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Filters;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Defines a processor that detects edges within an image using a single two dimensional matrix.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class EdgeDetectorProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public abstract class EdgeDetectorProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor"/> class.
/// </summary>
/// <param name="kernelXY">The 2d gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorProcessor(in DenseMatrix<float> kernelXY, bool grayscale)
/// <param name="grayscale">A value indicating whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorProcessor(bool grayscale)
{
this.KernelXY = kernelXY;
this.Grayscale = grayscale;
}
/// <inheritdoc/>
public bool Grayscale { get; }
/// <summary>
/// Gets the 2d gradient operator.
/// Gets a value indicating whether to convert the image to grayscale before performing edge detection.
/// </summary>
public DenseMatrix<float> KernelXY { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
}
}
public bool Grayscale { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new ConvolutionProcessor<TPixel>(this.KernelXY, true).Apply(source, sourceRectangle, configuration);
/// <inheritdoc />
public abstract IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>;
}
}

49
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs

@ -0,0 +1,49 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Filters;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Defines a processor that detects edges within an image using a single two dimensional matrix.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class EdgeDetectorProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor{TPixel}"/> class.
/// </summary>
/// <param name="kernelXY">The 2d gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public EdgeDetectorProcessor(in DenseMatrix<float> kernelXY, bool grayscale)
{
this.KernelXY = kernelXY;
this.Grayscale = grayscale;
}
public bool Grayscale { get; }
/// <summary>
/// Gets the 2d gradient operator.
/// </summary>
public DenseMatrix<float> KernelXY { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
}
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
=> new ConvolutionProcessor<TPixel>(this.KernelXY, true).Apply(source, sourceRectangle, configuration);
}
}

22
src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs

@ -1,24 +1,30 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Kayyali operator filter. <see href="http://edgedetection.webs.com/"/>
/// Defines edge detection processing using the Kayyali operator filter.
/// See <see href="http://edgedetection.webs.com/"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class KayyaliProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class KayyaliProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="KayyaliProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="KayyaliProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public KayyaliProcessor(bool grayscale)
: base(KayyaliKernels.KayyaliX, KayyaliKernels.KayyaliY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(
KayyaliKernels.KayyaliX,
KayyaliKernels.KayyaliY,
this.Grayscale);
}
}
}

57
src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
internal abstract class CompassKernels
{
/// <summary>
/// Gets the North gradient operator.
/// </summary>
public abstract DenseMatrix<float> North { get; }
/// <summary>
/// Gets the NorthWest gradient operator.
/// </summary>
public abstract DenseMatrix<float> NorthWest { get; }
/// <summary>
/// Gets the West gradient operator.
/// </summary>
public abstract DenseMatrix<float> West { get; }
/// <summary>
/// Gets the SouthWest gradient operator.
/// </summary>
public abstract DenseMatrix<float> SouthWest { get; }
/// <summary>
/// Gets the South gradient operator.
/// </summary>
public abstract DenseMatrix<float> South { get; }
/// <summary>
/// Gets the SouthEast gradient operator.
/// </summary>
public abstract DenseMatrix<float> SouthEast { get; }
/// <summary>
/// Gets the East gradient operator.
/// </summary>
public abstract DenseMatrix<float> East { get; }
/// <summary>
/// Gets the NorthEast gradient operator.
/// </summary>
public abstract DenseMatrix<float> NorthEast { get; }
public DenseMatrix<float>[] Flatten() =>
new[]
{
this.North, this.NorthWest, this.West, this.SouthWest,
this.South, this.SouthEast, this.East, this.NorthEast
};
}
}

0
src/ImageSharp/Processing/Processors/Convolution/KayyaliKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs

18
src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs

@ -8,12 +8,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Contains the eight matrices used for Kirsch edge detection
/// </summary>
internal static class KirschKernels
internal class KirschKernels : CompassKernels
{
/// <summary>
/// Gets the North gradient operator
/// </summary>
public static DenseMatrix<float> KirschNorth =>
public override DenseMatrix<float> North =>
new float[,]
{
{ 5, 5, 5 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public static DenseMatrix<float> KirschNorthWest =>
public override DenseMatrix<float> NorthWest =>
new float[,]
{
{ 5, 5, -3 },
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the West gradient operator
/// </summary>
public static DenseMatrix<float> KirschWest =>
public override DenseMatrix<float> West =>
new float[,]
{
{ 5, -3, -3 },
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public static DenseMatrix<float> KirschSouthWest =>
public override DenseMatrix<float> SouthWest =>
new float[,]
{
{ -3, -3, -3 },
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the South gradient operator
/// </summary>
public static DenseMatrix<float> KirschSouth =>
public override DenseMatrix<float> South =>
new float[,]
{
{ -3, -3, -3 },
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public static DenseMatrix<float> KirschSouthEast =>
public override DenseMatrix<float> SouthEast =>
new float[,]
{
{ -3, -3, -3 },
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the East gradient operator
/// </summary>
public static DenseMatrix<float> KirschEast =>
public override DenseMatrix<float> East =>
new float[,]
{
{ -3, -3, 5 },
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public static DenseMatrix<float> KirschNorthEast =>
public override DenseMatrix<float> NorthEast =>
new float[,]
{
{ -3, 5, 5 },

0
src/ImageSharp/Processing/Processors/Convolution/LaplacianKernelFactory.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs

0
src/ImageSharp/Processing/Processors/Convolution/LaplacianKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs

0
src/ImageSharp/Processing/Processors/Convolution/PrewittKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs

0
src/ImageSharp/Processing/Processors/Convolution/RobertsCrossKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs

20
src/ImageSharp/Processing/Processors/Convolution/RobinsonKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs

@ -6,14 +6,14 @@ using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Contains the kernels used for Robinson edge detection
/// Contains the kernels used for Robinson edge detection.
/// </summary>
internal static class RobinsonKernels
internal class RobinsonKernels : CompassKernels
{
/// <summary>
/// Gets the North gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonNorth =>
public override DenseMatrix<float> North =>
new float[,]
{
{ 1, 2, 1 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonNorthWest =>
public override DenseMatrix<float> NorthWest =>
new float[,]
{
{ 2, 1, 0 },
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the West gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonWest =>
public override DenseMatrix<float> West =>
new float[,]
{
{ 1, 0, -1 },
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonSouthWest =>
public override DenseMatrix<float> SouthWest =>
new float[,]
{
{ 0, -1, -2 },
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the South gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonSouth =>
public override DenseMatrix<float> South =>
new float[,]
{
{ -1, -2, -1 },
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonSouthEast =>
public override DenseMatrix<float> SouthEast =>
new float[,]
{
{ -2, -1, 0 },
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the East gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonEast =>
public override DenseMatrix<float> East =>
new float[,]
{
{ -1, 0, 1 },
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public static DenseMatrix<float> RobinsonNorthEast =>
public override DenseMatrix<float> NorthEast =>
new float[,]
{
{ 0, 1, 2 },

0
src/ImageSharp/Processing/Processors/Convolution/ScharrKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs

0
src/ImageSharp/Processing/Processors/Convolution/SobelKernels.cs → src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs

40
src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs

@ -1,20 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Kirsch operator filter. <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>
/// Defines edge detection using the Kirsch operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class KirschProcessor<TPixel> : EdgeDetectorCompassProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class KirschProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="KirschProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="KirschProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public KirschProcessor(bool grayscale)
@ -22,28 +18,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
}
/// <inheritdoc/>
public override DenseMatrix<float> North => KirschKernels.KirschNorth;
/// <inheritdoc/>
public override DenseMatrix<float> NorthWest => KirschKernels.KirschNorthWest;
/// <inheritdoc/>
public override DenseMatrix<float> West => KirschKernels.KirschWest;
/// <inheritdoc/>
public override DenseMatrix<float> SouthWest => KirschKernels.KirschSouthWest;
/// <inheritdoc/>
public override DenseMatrix<float> South => KirschKernels.KirschSouth;
/// <inheritdoc/>
public override DenseMatrix<float> SouthEast => KirschKernels.KirschSouthEast;
/// <inheritdoc/>
public override DenseMatrix<float> East => KirschKernels.KirschEast;
/// <inheritdoc/>
public override DenseMatrix<float> NorthEast => KirschKernels.KirschNorthEast;
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorCompassProcessor<TPixel>(new KirschKernels(), this.Grayscale);
}
}
}

14
src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs

@ -9,17 +9,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// Applies edge detection processing to the image using the Laplacian 3x3 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class Laplacian3x3Processor<TPixel> : EdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class Laplacian3x3Processor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="Laplacian3x3Processor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Laplacian3x3Processor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public Laplacian3x3Processor(bool grayscale)
: base(LaplacianKernels.Laplacian3x3, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.Laplacian3x3, this.Grayscale);
}
}
}

20
src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs

@ -1,25 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Laplacian 5x5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// Defines edge detection processing using the Laplacian 5x5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class Laplacian5x5Processor<TPixel> : EdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class Laplacian5x5Processor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="Laplacian5x5Processor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="Laplacian5x5Processor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public Laplacian5x5Processor(bool grayscale)
: base(LaplacianKernels.Laplacian5x5, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.Laplacian5x5, this.Grayscale);
}
}
}

18
src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs

@ -1,25 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Laplacian of Gaussian operator filter.
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>
/// See <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class LaplacianOfGaussianProcessor<TPixel> : EdgeDetectorProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class LaplacianOfGaussianProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="LaplacianOfGaussianProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="LaplacianOfGaussianProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public LaplacianOfGaussianProcessor(bool grayscale)
: base(LaplacianKernels.LaplacianOfGaussianXY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale);
}
}
}

20
src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs

@ -1,25 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Prewitt operator filter.
/// <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>
/// Defines edge detection using the Prewitt operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class PrewittProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class PrewittProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="PrewittProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="PrewittProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public PrewittProcessor(bool grayscale)
: base(PrewittKernels.PrewittX, PrewittKernels.PrewittY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(PrewittKernels.PrewittX, PrewittKernels.PrewittY, this.Grayscale);
}
}
}

18
src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs

@ -6,20 +6,24 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Roberts Cross operator filter.
/// <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>
/// Defines edge detection processing using the Roberts Cross operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class RobertsCrossProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class RobertsCrossProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="RobertsCrossProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="RobertsCrossProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public RobertsCrossProcessor(bool grayscale)
: base(RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY, this.Grayscale);
}
}
}

38
src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs

@ -7,15 +7,13 @@ using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Robinson operator filter.
/// <see href="http://www.tutorialspoint.com/dip/Robinson_Compass_Mask.htm"/>
/// Defines edge detection using the Robinson operator filter.
/// See <see href="http://www.tutorialspoint.com/dip/Robinson_Compass_Mask.htm"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class RobinsonProcessor<TPixel> : EdgeDetectorCompassProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
internal class RobinsonProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="RobinsonProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="RobinsonProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public RobinsonProcessor(bool grayscale)
@ -23,28 +21,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
}
/// <inheritdoc/>
public override DenseMatrix<float> North => RobinsonKernels.RobinsonNorth;
/// <inheritdoc/>
public override DenseMatrix<float> NorthWest => RobinsonKernels.RobinsonNorthWest;
/// <inheritdoc/>
public override DenseMatrix<float> West => RobinsonKernels.RobinsonWest;
/// <inheritdoc/>
public override DenseMatrix<float> SouthWest => RobinsonKernels.RobinsonSouthWest;
/// <inheritdoc/>
public override DenseMatrix<float> South => RobinsonKernels.RobinsonSouth;
/// <inheritdoc/>
public override DenseMatrix<float> SouthEast => RobinsonKernels.RobinsonSouthEast;
/// <inheritdoc/>
public override DenseMatrix<float> East => RobinsonKernels.RobinsonEast;
/// <inheritdoc/>
public override DenseMatrix<float> NorthEast => RobinsonKernels.RobinsonNorthEast;
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetectorCompassProcessor<TPixel>(new RobinsonKernels(), this.Grayscale);
}
}
}

16
src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs

@ -6,20 +6,24 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// Applies edge detection processing to the image using the Scharr operator filter.
/// Defines edge detection processing using the Scharr operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class ScharrProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class ScharrProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="ScharrProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="ScharrProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public ScharrProcessor(bool grayscale)
: base(ScharrKernels.ScharrX, ScharrKernels.ScharrY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(ScharrKernels.ScharrX, ScharrKernels.ScharrY, this.Grayscale);
}
}
}

27
src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs

@ -2,24 +2,37 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
/// <summary>
/// The Sobel operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>
/// Defines edge detection using the Sobel operator filter.
/// See <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class SobelProcessor<TPixel> : EdgeDetector2DProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class SobelProcessor : EdgeDetectorProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="SobelProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="SobelProcessor"/> class.
/// </summary>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
public SobelProcessor(bool grayscale)
: base(SobelKernels.SobelX, SobelKernels.SobelY, grayscale)
: base(grayscale)
{
}
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
return new EdgeDetector2DProcessor<TPixel>(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale);
}
// TODO: Move this to an appropriate extension method if possible.
internal void ApplyToFrame<TPixel>(ImageFrame<TPixel> frame, Rectangle sourceRectangle, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
var processorImpl = new EdgeDetector2DProcessor<TPixel>(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale);
processorImpl.Apply(frame, sourceRectangle, configuration);
}
}
}

2
src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs

@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Configuration configuration = source.GetConfiguration();
// Detect the edges.
new SobelProcessor<TPixel>(false).Apply(temp, sourceRectangle, configuration);
new SobelProcessor(false).ApplyToFrame(temp, sourceRectangle, configuration);
// Apply threshold binarization filter.
new BinaryThresholdProcessor<TPixel>(this.Threshold).Apply(temp, sourceRectangle, configuration);

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

@ -21,8 +21,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Convolution
this.operations.DetectEdges();
// TODO: Enable once we have updated the images
// SobelProcessor<Rgba32> processor = this.Verify<SobelProcessor<Rgba32>>();
// Assert.True(processor.Grayscale);
SobelProcessor processor = this.Verify<SobelProcessor>();
Assert.True(processor.Grayscale);
}
[Fact]
@ -31,45 +31,45 @@ namespace SixLabors.ImageSharp.Tests.Processing.Convolution
this.operations.DetectEdges(this.rect);
// TODO: Enable once we have updated the images
// SobelProcessor<Rgba32> processor = this.Verify<SobelProcessor<Rgba32>>(this.rect);
// Assert.True(processor.Grayscale);
SobelProcessor processor = this.Verify<SobelProcessor>(this.rect);
Assert.True(processor.Grayscale);
}
public static IEnumerable<object[]> EdgeDetectionTheoryData => new[] {
new object[]{ new TestType<KayyaliProcessor<Rgba32>>(), EdgeDetectionOperators.Kayyali },
new object[]{ new TestType<KirschProcessor<Rgba32>>(), EdgeDetectionOperators.Kirsch },
new object[]{ new TestType<Laplacian3x3Processor<Rgba32>>(), EdgeDetectionOperators.Laplacian3x3 },
new object[]{ new TestType<Laplacian5x5Processor<Rgba32>>(), EdgeDetectionOperators.Laplacian5x5 },
new object[]{ new TestType<LaplacianOfGaussianProcessor<Rgba32>>(), EdgeDetectionOperators.LaplacianOfGaussian },
new object[]{ new TestType<PrewittProcessor<Rgba32>>(), EdgeDetectionOperators.Prewitt },
new object[]{ new TestType<RobertsCrossProcessor<Rgba32>>(), EdgeDetectionOperators.RobertsCross },
new object[]{ new TestType<RobinsonProcessor<Rgba32>>(), EdgeDetectionOperators.Robinson },
new object[]{ new TestType<ScharrProcessor<Rgba32>>(), EdgeDetectionOperators.Scharr },
new object[]{ new TestType<SobelProcessor<Rgba32>>(), EdgeDetectionOperators.Sobel },
new object[]{ new TestType<KayyaliProcessor>(), EdgeDetectionOperators.Kayyali },
new object[]{ new TestType<KirschProcessor>(), EdgeDetectionOperators.Kirsch },
new object[]{ new TestType<Laplacian3x3Processor>(), EdgeDetectionOperators.Laplacian3x3 },
new object[]{ new TestType<Laplacian5x5Processor>(), EdgeDetectionOperators.Laplacian5x5 },
new object[]{ new TestType<LaplacianOfGaussianProcessor>(), EdgeDetectionOperators.LaplacianOfGaussian },
new object[]{ new TestType<PrewittProcessor>(), EdgeDetectionOperators.Prewitt },
new object[]{ new TestType<RobertsCrossProcessor>(), EdgeDetectionOperators.RobertsCross },
new object[]{ new TestType<RobinsonProcessor>(), EdgeDetectionOperators.Robinson },
new object[]{ new TestType<ScharrProcessor>(), EdgeDetectionOperators.Scharr },
new object[]{ new TestType<SobelProcessor>(), EdgeDetectionOperators.Sobel },
};
[Theory]
[MemberData(nameof(EdgeDetectionTheoryData))]
public void DetectEdges_filter_SobelProcessorDefaultsSet<TProcessor>(TestType<TProcessor> type, EdgeDetectionOperators filter)
where TProcessor : IImageProcessor<Rgba32>
where TProcessor : EdgeDetectorProcessor
{
this.operations.DetectEdges(filter);
// TODO: Enable once we have updated the images
// var processor = this.Verify<TProcessor>();
// Assert.True(processor.Grayscale);
var processor = this.Verify<TProcessor>();
Assert.True(processor.Grayscale);
}
[Theory]
[MemberData(nameof(EdgeDetectionTheoryData))]
public void DetectEdges_filter_grayscale_SobelProcessorDefaultsSet<TProcessor>(TestType<TProcessor> type, EdgeDetectionOperators filter)
where TProcessor : IImageProcessor<Rgba32>
where TProcessor : EdgeDetectorProcessor
{
bool grey = (int)filter % 2 == 0;
this.operations.DetectEdges(filter, grey);
// TODO: Enable once we have updated the images
// var processor = this.Verify<TProcessor>()
// Assert.Equal(grey, processor.Grayscale);
var processor = this.Verify<TProcessor>();
Assert.Equal(grey, processor.Grayscale);
}
}
}
Loading…
Cancel
Save