diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 64a496141..41ecee503 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -20,7 +20,7 @@
-
+
diff --git a/src/ImageSharp/Processing/EdgeDetectionOperators.cs b/src/ImageSharp/Processing/EdgeDetectionOperators.cs
deleted file mode 100644
index 3e986f802..000000000
--- a/src/ImageSharp/Processing/EdgeDetectionOperators.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Processing
-{
- ///
- /// Enumerates the various types of defined edge detection filters.
- ///
- public enum EdgeDetectionOperators
- {
- ///
- /// The Kayyali operator filter.
- ///
- Kayyali,
-
- ///
- /// The Kirsch operator filter.
- ///
- Kirsch,
-
- ///
- /// The Laplacian3X3 operator filter.
- ///
- Laplacian3x3,
-
- ///
- /// The Laplacian5X5 operator filter.
- ///
- Laplacian5x5,
-
- ///
- /// The LaplacianOfGaussian operator filter.
- ///
- LaplacianOfGaussian,
-
- ///
- /// The Prewitt operator filter.
- ///
- Prewitt,
-
- ///
- /// The RobertsCross operator filter.
- ///
- RobertsCross,
-
- ///
- /// The Robinson operator filter.
- ///
- Robinson,
-
- ///
- /// The Scharr operator filter.
- ///
- Scharr,
-
- ///
- /// The Sobel operator filter.
- ///
- Sobel
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs
index 61b900848..f30d8ad57 100644
--- a/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Processors;
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing
/// The to allow chaining of operations.
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
- EdgeDetectionOperators filter) =>
+ KnownEdgeDetectionOperators filter) =>
DetectEdges(source, GetProcessor(filter, true));
///
@@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing
/// The to allow chaining of operations.
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
- EdgeDetectionOperators filter,
+ KnownEdgeDetectionOperators filter,
bool grayscale) =>
DetectEdges(source, GetProcessor(filter, grayscale));
@@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing
/// The to allow chaining of operations.
public static IImageProcessingContext DetectEdges(
this IImageProcessingContext source,
- EdgeDetectionOperators filter,
+ KnownEdgeDetectionOperators filter,
Rectangle rectangle,
bool grayscale = true) =>
DetectEdges(source, rectangle, GetProcessor(filter, grayscale));
@@ -102,45 +102,45 @@ namespace SixLabors.ImageSharp.Processing
return source;
}
- private static IImageProcessor GetProcessor(EdgeDetectionOperators filter, bool grayscale)
+ private static IImageProcessor GetProcessor(KnownEdgeDetectionOperators filter, bool grayscale)
{
IImageProcessor processor;
switch (filter)
{
- case EdgeDetectionOperators.Kayyali:
+ case KnownEdgeDetectionOperators.Kayyali:
processor = new KayyaliProcessor(grayscale);
break;
- case EdgeDetectionOperators.Kirsch:
+ case KnownEdgeDetectionOperators.Kirsch:
processor = new KirschProcessor(grayscale);
break;
- case EdgeDetectionOperators.Laplacian3x3:
+ case KnownEdgeDetectionOperators.Laplacian3x3:
processor = new Laplacian3x3Processor(grayscale);
break;
- case EdgeDetectionOperators.Laplacian5x5:
+ case KnownEdgeDetectionOperators.Laplacian5x5:
processor = new Laplacian5x5Processor(grayscale);
break;
- case EdgeDetectionOperators.LaplacianOfGaussian:
+ case KnownEdgeDetectionOperators.LaplacianOfGaussian:
processor = new LaplacianOfGaussianProcessor(grayscale);
break;
- case EdgeDetectionOperators.Prewitt:
+ case KnownEdgeDetectionOperators.Prewitt:
processor = new PrewittProcessor(grayscale);
break;
- case EdgeDetectionOperators.RobertsCross:
+ case KnownEdgeDetectionOperators.RobertsCross:
processor = new RobertsCrossProcessor(grayscale);
break;
- case EdgeDetectionOperators.Robinson:
+ case KnownEdgeDetectionOperators.Robinson:
processor = new RobinsonProcessor(grayscale);
break;
- case EdgeDetectionOperators.Scharr:
+ case KnownEdgeDetectionOperators.Scharr:
processor = new ScharrProcessor(grayscale);
break;
@@ -152,4 +152,4 @@ namespace SixLabors.ImageSharp.Processing
return processor;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs b/src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs
new file mode 100644
index 000000000..e41fb00ce
--- /dev/null
+++ b/src/ImageSharp/Processing/KnownEdgeDetectionOperators.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Processing.Processors.Convolution;
+
+namespace SixLabors.ImageSharp.Processing
+{
+ ///
+ /// Contains reusable static instances of known edge detection kernels.
+ ///
+ public static class KnownEdgeDetectionOperators
+ {
+ ///
+ /// Gets the Kayyali edge detector kernel.
+ ///
+ public static EdgeDetector2DKernel Kayyali { get; } = EdgeDetector2DKernel.KayyaliKernel;
+
+ ///
+ /// Gets the Kirsch edge detector kernel.
+ ///
+ public static EdgeDetectorCompassKernel Kirsch { get; } = EdgeDetectorCompassKernel.Kirsch;
+
+ ///
+ /// Gets the Laplacian 3x3 edge detector kernel.
+ ///
+ public static EdgeDetectorKernel Laplacian3x3 { get; } = EdgeDetectorKernel.Laplacian3x3;
+
+ ///
+ /// Gets the Laplacian 5x5 edge detector kernel.
+ ///
+ public static EdgeDetectorKernel Laplacian5x5 { get; } = EdgeDetectorKernel.Laplacian5x5;
+
+ ///
+ /// Gets the Laplacian of Gaussian edge detector kernel.
+ ///
+ public static EdgeDetectorKernel LaplacianOfGaussian { get; } = EdgeDetectorKernel.LaplacianOfGaussian;
+
+ ///
+ /// Gets the Prewitt edge detector kernel.
+ ///
+ public static EdgeDetector2DKernel Prewitt { get; } = EdgeDetector2DKernel.PrewittKernel;
+
+ ///
+ /// Gets the Roberts-Cross edge detector kernel.
+ ///
+ public static EdgeDetector2DKernel RobertsCross { get; } = EdgeDetector2DKernel.RobertsCrossKernel;
+
+ ///
+ /// Gets the Robinson edge detector kernel.
+ ///
+ public static EdgeDetectorCompassKernel Robinson { get; } = EdgeDetectorCompassKernel.Robinson;
+
+ ///
+ /// Gets the Scharr edge detector kernel.
+ ///
+ public static EdgeDetector2DKernel Scharr { get; } = EdgeDetector2DKernel.ScharrKernel;
+
+ ///
+ /// Gets the Sobel edge detector kernel.
+ ///
+ public static EdgeDetector2DKernel Sobel { get; } = EdgeDetector2DKernel.SobelKernel;
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
index 164488155..14d728814 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
@@ -18,25 +18,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
internal class EdgeDetectorCompassProcessor : ImageProcessor
where TPixel : unmanaged, IPixel
{
+ private readonly DenseMatrix[] kernels;
+ private readonly bool grayscale;
+
///
/// Initializes a new instance of the class.
///
/// The configuration which allows altering default behaviour or extending the library.
- /// Gets the kernels to use.
+ /// The kernels to use.
/// Whether to convert the image to grayscale before performing edge detection.
/// The source for the current processor instance.
/// The source area to process for the current processor instance.
- internal EdgeDetectorCompassProcessor(Configuration configuration, CompassKernels kernels, bool grayscale, Image source, Rectangle sourceRectangle)
+ internal EdgeDetectorCompassProcessor(Configuration configuration, in EdgeDetectorCompassKernel kernels, bool grayscale, Image source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
- this.Grayscale = grayscale;
- this.Kernels = kernels;
+ this.grayscale = grayscale;
+ this.kernels = kernels.Flatten();
}
- private CompassKernels Kernels { get; }
-
- private bool Grayscale { get; }
-
///
protected override void BeforeImageApply()
{
@@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
opaque.Execute();
}
- if (this.Grayscale)
+ if (this.grayscale)
{
new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle);
}
@@ -56,29 +55,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- DenseMatrix[] kernels = this.Kernels.Flatten();
-
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// We need a clean copy for each pass to start from
using ImageFrame cleanCopy = source.Clone();
- using (var processor = new ConvolutionProcessor(this.Configuration, kernels[0], true, this.Source, interest))
+ using (var processor = new ConvolutionProcessor(this.Configuration, in this.kernels[0], true, this.Source, interest))
{
processor.Apply(source);
}
- if (kernels.Length == 1)
+ if (this.kernels.Length == 1)
{
return;
}
// Additional runs
- for (int i = 1; i < kernels.Length; i++)
+ for (int i = 1; i < this.kernels.Length; i++)
{
using ImageFrame pass = cleanCopy.Clone();
- using (var processor = new ConvolutionProcessor(this.Configuration, kernels[i], true, this.Source, interest))
+ using (var processor = new ConvolutionProcessor(this.Configuration, in this.kernels[i], true, this.Source, interest))
{
processor.Apply(pass);
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs
index 45639d93a..e56e0d1a7 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs
@@ -13,6 +13,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
internal class EdgeDetectorProcessor : ImageProcessor
where TPixel : unmanaged, IPixel
{
+ private readonly bool grayscale;
+ private readonly DenseMatrix kernelXY;
+
///
/// Initializes a new instance of the class.
///
@@ -23,23 +26,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// The target area to process for the current processor instance.
public EdgeDetectorProcessor(
Configuration configuration,
- in DenseMatrix kernelXY,
+ in EdgeDetectorKernel kernelXY,
bool grayscale,
Image source,
Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
- this.KernelXY = kernelXY;
- this.Grayscale = grayscale;
+ this.kernelXY = kernelXY.KernelXY;
+ this.grayscale = grayscale;
}
- public bool Grayscale { get; }
-
- ///
- /// Gets the 2d gradient operator.
- ///
- public DenseMatrix KernelXY { get; }
-
///
protected override void BeforeImageApply()
{
@@ -48,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
opaque.Execute();
}
- if (this.Grayscale)
+ if (this.grayscale)
{
new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle);
}
@@ -59,10 +55,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new ConvolutionProcessor(this.Configuration, this.KernelXY, true, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new ConvolutionProcessor(this.Configuration, in this.kernelXY, true, this.Source, this.SourceRectangle);
+ processor.Apply(source);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs
deleted file mode 100644
index 24caa40f8..000000000
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Processing.Processors.Convolution
-{
- internal abstract class CompassKernels
- {
- ///
- /// Gets the North gradient operator.
- ///
- public abstract DenseMatrix North { get; }
-
- ///
- /// Gets the NorthWest gradient operator.
- ///
- public abstract DenseMatrix NorthWest { get; }
-
- ///
- /// Gets the West gradient operator.
- ///
- public abstract DenseMatrix West { get; }
-
- ///
- /// Gets the SouthWest gradient operator.
- ///
- public abstract DenseMatrix SouthWest { get; }
-
- ///
- /// Gets the South gradient operator.
- ///
- public abstract DenseMatrix South { get; }
-
- ///
- /// Gets the SouthEast gradient operator.
- ///
- public abstract DenseMatrix SouthEast { get; }
-
- ///
- /// Gets the East gradient operator.
- ///
- public abstract DenseMatrix East { get; }
-
- ///
- /// Gets the NorthEast gradient operator.
- ///
- public abstract DenseMatrix NorthEast { get; }
-
- public DenseMatrix[] Flatten() =>
- new[]
- {
- this.North, this.NorthWest, this.West, this.SouthWest,
- this.South, this.SouthEast, this.East, this.NorthEast
- };
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs
new file mode 100644
index 000000000..ed363595d
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs
@@ -0,0 +1,103 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Convolution
+{
+ ///
+ /// Represents an edge detection convolution kernel consisting of two 1D gradient operators.
+ ///
+ public readonly struct EdgeDetector2DKernel : IEquatable
+ {
+ ///
+ /// An edge detection kernel containing two Kayyali operators.
+ ///
+ public static EdgeDetector2DKernel KayyaliKernel = new EdgeDetector2DKernel(KayyaliKernels.KayyaliX, KayyaliKernels.KayyaliY);
+
+ ///
+ /// An edge detection kernel containing two Prewitt operators.
+ /// .
+ ///
+ public static EdgeDetector2DKernel PrewittKernel = new EdgeDetector2DKernel(PrewittKernels.PrewittX, PrewittKernels.PrewittY);
+
+ ///
+ /// An edge detection kernel containing two Roberts-Cross operators.
+ /// .
+ ///
+ public static EdgeDetector2DKernel RobertsCrossKernel = new EdgeDetector2DKernel(RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY);
+
+ ///
+ /// An edge detection kernel containing two Scharr operators.
+ ///
+ public static EdgeDetector2DKernel ScharrKernel = new EdgeDetector2DKernel(ScharrKernels.ScharrX, ScharrKernels.ScharrY);
+
+ ///
+ /// An edge detection kernel containing two Sobel operators.
+ /// .
+ ///
+ public static EdgeDetector2DKernel SobelKernel = new EdgeDetector2DKernel(SobelKernels.SobelX, SobelKernels.SobelY);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The horizontal gradient operator.
+ /// The vertical gradient operator.
+ public EdgeDetector2DKernel(DenseMatrix kernelX, DenseMatrix kernelY)
+ {
+ Guard.IsTrue(
+ kernelX.Size.Equals(kernelY.Size),
+ $"{nameof(kernelX)} {nameof(kernelY)}",
+ "Kernel sizes must be the same.");
+
+ this.KernelX = kernelX;
+ this.KernelY = kernelY;
+ }
+
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public DenseMatrix KernelX { get; }
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public DenseMatrix KernelY { get; }
+
+ ///
+ /// Checks whether two structures are equal.
+ ///
+ /// The left hand operand.
+ /// The right hand operand.
+ ///
+ /// True if the parameter is equal to the parameter;
+ /// otherwise, false.
+ ///
+ public static bool operator ==(EdgeDetector2DKernel left, EdgeDetector2DKernel right)
+ => left.Equals(right);
+
+ ///
+ /// Checks whether two structures are equal.
+ ///
+ /// The left hand operand.
+ /// The right hand operand.
+ ///
+ /// True if the parameter is not equal to the parameter;
+ /// otherwise, false.
+ ///
+ public static bool operator !=(EdgeDetector2DKernel left, EdgeDetector2DKernel right)
+ => !(left == right);
+
+ ///
+ public override bool Equals(object obj)
+ => obj is EdgeDetector2DKernel kernel && this.Equals(kernel);
+
+ ///
+ public bool Equals(EdgeDetector2DKernel other)
+ => this.KernelX.Equals(other.KernelX)
+ && this.KernelY.Equals(other.KernelY);
+
+ ///
+ public override int GetHashCode() => HashCode.Combine(this.KernelX, this.KernelY);
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs
new file mode 100644
index 000000000..34fca9192
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs
@@ -0,0 +1,161 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Convolution
+{
+ ///
+ /// Represents an edge detection convolution kernel consisting of eight gradient operators.
+ ///
+ public readonly struct EdgeDetectorCompassKernel : IEquatable
+ {
+ ///
+ /// An edge detection kenel comprised of Kirsch gradient operators.
+ ///
+ public static EdgeDetectorCompassKernel Kirsch =
+ new EdgeDetectorCompassKernel(
+ KirschKernels.North,
+ KirschKernels.NorthWest,
+ KirschKernels.West,
+ KirschKernels.SouthWest,
+ KirschKernels.South,
+ KirschKernels.SouthEast,
+ KirschKernels.East,
+ KirschKernels.NorthEast);
+
+ ///
+ /// An edge detection kenel comprised of Robinson gradient operators.
+ ///
+ public static EdgeDetectorCompassKernel Robinson =
+ new EdgeDetectorCompassKernel(
+ RobinsonKernels.North,
+ RobinsonKernels.NorthWest,
+ RobinsonKernels.West,
+ RobinsonKernels.SouthWest,
+ RobinsonKernels.South,
+ RobinsonKernels.SouthEast,
+ RobinsonKernels.East,
+ RobinsonKernels.NorthEast);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The north gradient operator.
+ /// The north-west gradient operator.
+ /// The west gradient operator.
+ /// The south-west gradient operator.
+ /// The south gradient operator.
+ /// The south-east gradient operator.
+ /// The east gradient operator.
+ /// The north-east gradient operator.
+ public EdgeDetectorCompassKernel(
+ DenseMatrix north,
+ DenseMatrix northWest,
+ DenseMatrix west,
+ DenseMatrix southWest,
+ DenseMatrix south,
+ DenseMatrix southEast,
+ DenseMatrix east,
+ DenseMatrix northEast)
+ {
+ this.North = north;
+ this.NorthWest = northWest;
+ this.West = west;
+ this.SouthWest = southWest;
+ this.South = south;
+ this.SouthEast = southEast;
+ this.East = east;
+ this.NorthEast = northEast;
+ }
+
+ ///
+ /// Gets the North gradient operator.
+ ///
+ public DenseMatrix North { get; }
+
+ ///
+ /// Gets the NorthWest gradient operator.
+ ///
+ public DenseMatrix NorthWest { get; }
+
+ ///
+ /// Gets the West gradient operator.
+ ///
+ public DenseMatrix West { get; }
+
+ ///
+ /// Gets the SouthWest gradient operator.
+ ///
+ public DenseMatrix SouthWest { get; }
+
+ ///
+ /// Gets the South gradient operator.
+ ///
+ public DenseMatrix South { get; }
+
+ ///
+ /// Gets the SouthEast gradient operator.
+ ///
+ public DenseMatrix SouthEast { get; }
+
+ ///
+ /// Gets the East gradient operator.
+ ///
+ public DenseMatrix East { get; }
+
+ ///
+ /// Gets the NorthEast gradient operator.
+ ///
+ public DenseMatrix NorthEast { get; }
+
+ ///
+ /// Checks whether two structures are equal.
+ ///
+ /// The left hand operand.
+ /// The right hand operand.
+ ///
+ /// True if the parameter is equal to the parameter;
+ /// otherwise, false.
+ ///
+ public static bool operator ==(EdgeDetectorCompassKernel left, EdgeDetectorCompassKernel right)
+ => left.Equals(right);
+
+ ///
+ /// Checks whether two structures are equal.
+ ///
+ /// The left hand operand.
+ /// The right hand operand.
+ ///
+ /// True if the parameter is not equal to the parameter;
+ /// otherwise, false.
+ ///
+ public static bool operator !=(EdgeDetectorCompassKernel left, EdgeDetectorCompassKernel right)
+ => !(left == right);
+
+ ///
+ public override bool Equals(object obj) => obj is EdgeDetectorCompassKernel kernel && this.Equals(kernel);
+
+ ///
+ public bool Equals(EdgeDetectorCompassKernel other) => this.North.Equals(other.North) && this.NorthWest.Equals(other.NorthWest) && this.West.Equals(other.West) && this.SouthWest.Equals(other.SouthWest) && this.South.Equals(other.South) && this.SouthEast.Equals(other.SouthEast) && this.East.Equals(other.East) && this.NorthEast.Equals(other.NorthEast);
+
+ ///
+ public override int GetHashCode()
+ => HashCode.Combine(
+ this.North,
+ this.NorthWest,
+ this.West,
+ this.SouthWest,
+ this.South,
+ this.SouthEast,
+ this.East,
+ this.NorthEast);
+
+ internal DenseMatrix[] Flatten() =>
+ new[]
+ {
+ this.North, this.NorthWest, this.West, this.SouthWest,
+ this.South, this.SouthEast, this.East, this.NorthEast
+ };
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs
new file mode 100644
index 000000000..7b1f91263
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs
@@ -0,0 +1,75 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Convolution
+{
+ ///
+ /// Represents an edge detection convolution kernel consisting of a single 2D gradient operator.
+ ///
+ public readonly struct EdgeDetectorKernel : IEquatable
+ {
+ ///
+ /// An edge detection kernel containing a 3x3 Laplacian operator.
+ ///
+ public static EdgeDetectorKernel Laplacian3x3 = new EdgeDetectorKernel(LaplacianKernels.Laplacian3x3);
+
+ ///
+ /// An edge detection kernel containing a 5x5 Laplacian operator.
+ ///
+ public static EdgeDetectorKernel Laplacian5x5 = new EdgeDetectorKernel(LaplacianKernels.Laplacian5x5);
+
+ ///
+ /// An edge detection kernel containing a Laplacian of Gaussian operator.
+ ///
+ public static EdgeDetectorKernel LaplacianOfGaussian = new EdgeDetectorKernel(LaplacianKernels.LaplacianOfGaussianXY);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The 2D gradient operator.
+ public EdgeDetectorKernel(DenseMatrix kernelXY)
+ => this.KernelXY = kernelXY;
+
+ ///
+ /// Gets the 2D gradient operator.
+ ///
+ public DenseMatrix KernelXY { get; }
+
+ ///
+ /// Checks whether two structures are equal.
+ ///
+ /// The left hand operand.
+ /// The right hand operand.
+ ///
+ /// True if the parameter is equal to the parameter;
+ /// otherwise, false.
+ ///
+ public static bool operator ==(EdgeDetectorKernel left, EdgeDetectorKernel right)
+ => left.Equals(right);
+
+ ///
+ /// Checks whether two structures are equal.
+ ///
+ /// The left hand operand.
+ /// The right hand operand.
+ ///
+ /// True if the parameter is not equal to the parameter;
+ /// otherwise, false.
+ ///
+ public static bool operator !=(EdgeDetectorKernel left, EdgeDetectorKernel right)
+ => !(left == right);
+
+ ///
+ public override bool Equals(object obj)
+ => obj is EdgeDetectorKernel kernel && this.Equals(kernel);
+
+ ///
+ public bool Equals(EdgeDetectorKernel other)
+ => this.KernelXY.Equals(other.KernelXY);
+
+ ///
+ public override int GetHashCode() => this.KernelXY.GetHashCode();
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/KayyaliKernels.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/KayyaliKernels.cs
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/KirschKernels.cs
similarity index 80%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/KirschKernels.cs
index 28c5590ef..ccd8a6c8d 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/KirschKernels.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
@@ -6,12 +6,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Contains the eight matrices used for Kirsch edge detection
///
- internal class KirschKernels : CompassKernels
+ internal static class KirschKernels
{
///
/// Gets the North gradient operator
///
- public override DenseMatrix North =>
+ public static DenseMatrix North =>
new float[,]
{
{ 5, 5, 5 },
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the NorthWest gradient operator
///
- public override DenseMatrix NorthWest =>
+ public static DenseMatrix NorthWest =>
new float[,]
{
{ 5, 5, -3 },
@@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the West gradient operator
///
- public override DenseMatrix West =>
+ public static DenseMatrix West =>
new float[,]
{
{ 5, -3, -3 },
@@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the SouthWest gradient operator
///
- public override DenseMatrix SouthWest =>
+ public static DenseMatrix SouthWest =>
new float[,]
{
{ -3, -3, -3 },
@@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the South gradient operator
///
- public override DenseMatrix South =>
+ public static DenseMatrix South =>
new float[,]
{
{ -3, -3, -3 },
@@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the SouthEast gradient operator
///
- public override DenseMatrix SouthEast =>
+ public static DenseMatrix SouthEast =>
new float[,]
{
{ -3, -3, -3 },
@@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the East gradient operator
///
- public override DenseMatrix East =>
+ public static DenseMatrix East =>
new float[,]
{
{ -3, -3, 5 },
@@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the NorthEast gradient operator
///
- public override DenseMatrix NorthEast =>
+ public static DenseMatrix NorthEast =>
new float[,]
{
{ -3, 5, 5 },
@@ -96,4 +96,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ -3, -3, -3 }
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernelFactory.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernelFactory.cs
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernels.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/LaplacianKernels.cs
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/PrewittKernels.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/PrewittKernels.cs
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobertsCrossKernels.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobertsCrossKernels.cs
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobinsonKernels.cs
similarity index 80%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobinsonKernels.cs
index 857c772b0..0dde36f02 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/RobinsonKernels.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
@@ -6,12 +6,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Contains the kernels used for Robinson edge detection.
///
- internal class RobinsonKernels : CompassKernels
+ internal static class RobinsonKernels
{
///
/// Gets the North gradient operator
///
- public override DenseMatrix North =>
+ public static DenseMatrix North =>
new float[,]
{
{ 1, 2, 1 },
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the NorthWest gradient operator
///
- public override DenseMatrix NorthWest =>
+ public static DenseMatrix NorthWest =>
new float[,]
{
{ 2, 1, 0 },
@@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the West gradient operator
///
- public override DenseMatrix West =>
+ public static DenseMatrix West =>
new float[,]
{
{ 1, 0, -1 },
@@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the SouthWest gradient operator
///
- public override DenseMatrix SouthWest =>
+ public static DenseMatrix SouthWest =>
new float[,]
{
{ 0, -1, -2 },
@@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the South gradient operator
///
- public override DenseMatrix South =>
+ public static DenseMatrix South =>
new float[,]
{
{ -1, -2, -1 },
@@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the SouthEast gradient operator
///
- public override DenseMatrix SouthEast =>
+ public static DenseMatrix SouthEast =>
new float[,]
{
{ -2, -1, 0 },
@@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the East gradient operator
///
- public override DenseMatrix East =>
+ public static DenseMatrix East =>
new float[,]
{
{ -1, 0, 1 },
@@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Gets the NorthEast gradient operator
///
- public override DenseMatrix NorthEast =>
+ public static DenseMatrix NorthEast =>
new float[,]
{
{ 0, 1, 2 },
@@ -96,4 +96,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{ -2, -1, 0 }
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/ScharrKernels.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/ScharrKernels.cs
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/SobelKernels.cs
similarity index 100%
rename from src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/Kernels/Implementation/SobelKernels.cs
diff --git a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs
index d40201bd8..cf46c4f52 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(EdgeDetectionOperators.Kayyali));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Kayyali));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Kirsch));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Laplacian3x3));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Laplacian5x5));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.LaplacianOfGaussian));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Prewitt));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.RobertsCross));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Robinson));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Scharr));
- this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Sobel));
+ 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));
}
}
}
diff --git a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs
index a0e9be110..fd41a04e2 100644
--- a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs
+++ b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs
@@ -35,21 +35,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Convolution
public static IEnumerable