diff --git a/src/ImageProcessorCore/Filters/DetectEdges.cs b/src/ImageProcessorCore/Filters/DetectEdges.cs
new file mode 100644
index 000000000..2912e04f7
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/DetectEdges.cs
@@ -0,0 +1,131 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore
+{
+ using Processors;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Detects any edges within the image. Uses the filter
+ /// operating in greyscale mode.
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ /// The image this method extends.
+ /// A delegate which is called as progress is made processing the image.
+ /// The .
+ public static Image DetectEdges(this Image source, ProgressEventHandler progressHandler = null)
+ where T : IPackedVector
+ where TP : struct
+ {
+ return DetectEdges(source, source.Bounds, new SobelProcessor { Greyscale = true }, progressHandler);
+ }
+
+ ///
+ /// Detects any edges within the image.
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ /// The image this method extends.
+ /// The filter for detecting edges.
+ /// Whether to convert the image to greyscale first. Defaults to true.
+ /// A delegate which is called as progress is made processing the image.
+ /// The .
+ public static Image DetectEdges(this Image source, EdgeDetection filter, bool greyscale = true, ProgressEventHandler progressHandler = null)
+ where T : IPackedVector
+ where TP : struct
+ {
+ IEdgeDetectorFilter processor;
+
+ switch (filter)
+ {
+ case EdgeDetection.Kayyali:
+ processor = new KayyaliProcessor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.Kirsch:
+ processor = new KirschProcessor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.Lapacian3X3:
+ processor = new Laplacian3X3Processor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.Lapacian5X5:
+ processor = new Laplacian5X5Processor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.LaplacianOfGaussian:
+ processor = new LaplacianOfGaussianProcessor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.Prewitt:
+ processor = new PrewittProcessor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.RobertsCross:
+ processor = new RobertsCrossProcessor { Greyscale = greyscale };
+ break;
+
+ case EdgeDetection.Scharr:
+ processor = new ScharrProcessor { Greyscale = greyscale };
+ break;
+
+ default:
+ processor = new ScharrProcessor { Greyscale = greyscale };
+ break;
+ }
+
+ return DetectEdges(source, source.Bounds, processor, progressHandler);
+ }
+
+ ///
+ /// Detects any edges within the image.
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ /// The image this method extends.
+ /// The filter for detecting edges.
+ /// A delegate which is called as progress is made processing the image.
+ /// The .
+ public static Image DetectEdges(this Image source, IEdgeDetectorFilter filter, ProgressEventHandler progressHandler = null)
+ where T : IPackedVector
+ where TP : struct
+ {
+ return DetectEdges(source, source.Bounds, filter, progressHandler);
+ }
+
+ ///
+ /// Detects any edges within the image.
+ ///
+ /// The image this method extends.
+ ///
+ /// The structure that specifies the portion of the image object to alter.
+ ///
+ /// The filter for detecting edges.
+ /// A delegate which is called as progress is made processing the image.
+ /// The .
+ public static Image DetectEdges(this Image source, Rectangle rectangle, IEdgeDetectorFilter filter, ProgressEventHandler progressHandler = null)
+ where T : IPackedVector
+ where TP : struct
+ {
+ filter.OnProgress += progressHandler;
+
+ try
+ {
+ return source.Process(rectangle, filter);
+ }
+ finally
+ {
+ filter.OnProgress -= progressHandler;
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Options/ColorBlindness.cs b/src/ImageProcessorCore/Filters/Options/ColorBlindness.cs
index 6d7fe849b..e128044cd 100644
--- a/src/ImageProcessorCore/Filters/Options/ColorBlindness.cs
+++ b/src/ImageProcessorCore/Filters/Options/ColorBlindness.cs
@@ -6,7 +6,7 @@
namespace ImageProcessorCore
{
///
- /// Enumerates the various types of color blindness.
+ /// Enumerates the various types of defined color blindness filters.
///
public enum ColorBlindness
{
diff --git a/src/ImageProcessorCore/Filters/Options/EdgeDetection.cs b/src/ImageProcessorCore/Filters/Options/EdgeDetection.cs
new file mode 100644
index 000000000..f637e4573
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Options/EdgeDetection.cs
@@ -0,0 +1,58 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore
+{
+ ///
+ /// Enumerates the various types of defined edge detection filters.
+ ///
+ public enum EdgeDetection
+ {
+ ///
+ /// The Kayyali operator filter.
+ ///
+ Kayyali,
+
+ ///
+ /// The Kirsch operator filter.
+ ///
+ Kirsch,
+
+ ///
+ /// The Lapacian3X3 operator filter.
+ ///
+ Lapacian3X3,
+
+ ///
+ /// The Lapacian5X5 operator filter.
+ ///
+ Lapacian5X5,
+
+ ///
+ /// The LaplacianOfGaussian operator filter.
+ ///
+ LaplacianOfGaussian,
+
+ ///
+ /// The Prewitt operator filter.
+ ///
+ Prewitt,
+
+ ///
+ /// The RobertsCross operator filter.
+ ///
+ RobertsCross,
+
+ ///
+ /// The Scharr operator filter.
+ ///
+ Scharr,
+
+ ///
+ /// The Sobel operator filter.
+ ///
+ Sobel
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Options/GreyscaleMode.cs b/src/ImageProcessorCore/Filters/Options/GreyscaleMode.cs
index 269c1179e..e1cc5917e 100644
--- a/src/ImageProcessorCore/Filters/Options/GreyscaleMode.cs
+++ b/src/ImageProcessorCore/Filters/Options/GreyscaleMode.cs
@@ -3,10 +3,10 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageProcessorCore.Processors
+namespace ImageProcessorCore
{
///
- /// Provides enumeration over the various greyscale methods available.
+ /// Enumerates the various types of defined greyscale filters.
///
public enum GreyscaleMode
{
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs
index d2e2979f9..ef0ceea9b 100644
--- a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs
@@ -8,9 +8,16 @@ namespace ImageProcessorCore.Processors
///
/// Provides properties and methods allowing the detection of edges within an image.
///
- public interface IEdgeDetectorFilter : IImageProcessor
+ public interface IEdgeDetectorFilter : IImageProcessor, IEdgeDetectorFilter
where T : IPackedVector
where TP : struct
+ {
+ }
+
+ ///
+ /// Provides properties and methods allowing the detection of edges within an image.
+ ///
+ public interface IEdgeDetectorFilter
{
///
/// Gets or sets a value indicating whether to convert the
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
new file mode 100644
index 000000000..59327467e
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Kayyali operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class KayyaliProcessor : EdgeDetector2DFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { 6, 0, -6 },
+ { 0, 0, 0 },
+ { -6, 0, 6 }
+ };
+
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { -6, 0, 6 },
+ { 0, 0, 0 },
+ { 6, 0, -6 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs
new file mode 100644
index 000000000..aba7e26d2
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Kirsch operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class KirschProcessor : EdgeDetector2DFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { 5, 5, 5 },
+ { -3, 0, -3 },
+ { -3, -3, -3 }
+ };
+
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 5, -3, -3 },
+ { 5, 0, -3 },
+ { 5, -3, -3 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
new file mode 100644
index 000000000..31829a422
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Laplacian 3 x 3 operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class Laplacian3X3Processor : EdgeDetectorFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelXY => new float[,]
+ {
+ { -1, -1, -1 },
+ { -1, 8, -1 },
+ { -1, -1, -1 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
new file mode 100644
index 000000000..d43876b56
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Laplacian 5 x 5 operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class Laplacian5X5Processor : EdgeDetectorFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelXY => new float[,]
+ {
+ { -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1 },
+ { -1, -1, 24, -1, -1 },
+ { -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
new file mode 100644
index 000000000..e47013610
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Laplacian of Gaussian operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class LaplacianOfGaussianProcessor : EdgeDetectorFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelXY => new float[,]
+ {
+ { 0, 0, -1, 0, 0 },
+ { 0, -1, -2, -1, 0 },
+ { -1, -2, 16, -2, -1 },
+ { 0, -1, -2, -1, 0 },
+ { 0, 0, -1, 0, 0 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
new file mode 100644
index 000000000..4ce4c7675
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Prewitt operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class PrewittProcessor : EdgeDetector2DFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { -1, 0, 1 },
+ { -1, 0, 1 },
+ { -1, 0, 1 }
+ };
+
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 1, 1, 1 },
+ { 0, 0, 0 },
+ { -1, -1, -1 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
new file mode 100644
index 000000000..b933280c6
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Roberts Cross operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class RobertsCrossProcessor : EdgeDetector2DFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { 1, 0 },
+ { 0, -1 }
+ };
+
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 0, 1 },
+ { -1, 0 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
new file mode 100644
index 000000000..1dd4408a0
--- /dev/null
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Processors
+{
+ ///
+ /// The Scharr operator filter.
+ ///
+ ///
+ /// The pixel format.
+ /// The packed format. long, float.
+ public class ScharrProcessor : EdgeDetector2DFilter
+ where T : IPackedVector
+ where TP : struct
+ {
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { -3, 0, 3 },
+ { -10, 0, 10 },
+ { -3, 0, 3 }
+ };
+
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 3, 10, 3 },
+ { 0, 0, 0 },
+ { -3, -10, -3 }
+ };
+ }
+}
diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs
index a323b7cfe..9459e2ed8 100644
--- a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs
+++ b/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs
@@ -9,6 +9,8 @@ namespace ImageProcessorCore.Processors
/// The Sobel operator filter.
///
///
+ /// The pixel format.
+ /// The packed format. long, float.
public class SobelProcessor : EdgeDetector2DFilter
where T : IPackedVector
where TP : struct
diff --git a/tests/ImageProcessorCore.Tests/Processors/Filters/DetectEdgesTest.cs b/tests/ImageProcessorCore.Tests/Processors/Filters/DetectEdgesTest.cs
new file mode 100644
index 000000000..944413007
--- /dev/null
+++ b/tests/ImageProcessorCore.Tests/Processors/Filters/DetectEdgesTest.cs
@@ -0,0 +1,53 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Tests
+{
+ using System.IO;
+
+ using Xunit;
+
+ public class DetectEdgesTest : FileTestBase
+ {
+ public static readonly TheoryData DetectEdgesFilters
+ = new TheoryData
+ {
+ EdgeDetection.Kayyali,
+ EdgeDetection.Kirsch,
+ EdgeDetection.Lapacian3X3,
+ EdgeDetection.Lapacian5X5,
+ EdgeDetection.LaplacianOfGaussian,
+ EdgeDetection.Prewitt,
+ EdgeDetection.RobertsCross,
+ EdgeDetection.Scharr,
+ EdgeDetection.Sobel,
+ };
+
+ [Theory]
+ [MemberData("DetectEdgesFilters")]
+ public void ImageShouldApplyDetectEdgesFilter(EdgeDetection detector)
+ {
+ const string path = "TestOutput/DetectEdges";
+ if (!Directory.Exists(path))
+ {
+ Directory.CreateDirectory(path);
+ }
+
+ foreach (string file in Files)
+ {
+ using (FileStream stream = File.OpenRead(file))
+ {
+ string filename = Path.GetFileNameWithoutExtension(file) + "-" + detector + Path.GetExtension(file);
+ Image image = new Image(stream);
+ using (FileStream output = File.OpenWrite($"{path}/{filename}"))
+ {
+ image.DetectEdges(detector)
+ .Save(output);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file