diff --git a/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs b/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs
new file mode 100644
index 0000000000..47cf25a7c3
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs
@@ -0,0 +1,97 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ using System;
+ using System.Threading.Tasks;
+
+ ///
+ /// Defines a filter that uses a matrix to perform convolution across two dimensions against an image.
+ ///
+ public abstract class Convolution2DFilter : ParallelImageProcessor
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public abstract float[,] KernelX { get; }
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public abstract float[,] KernelY { get; }
+
+ ///
+ protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
+ {
+ float[,] kernelX = this.KernelX;
+ float[,] kernelY = this.KernelY;
+ int kernelLength = kernelX.GetLength(0);
+ int radius = kernelLength >> 1;
+
+ int sourceY = sourceRectangle.Y;
+ int sourceBottom = sourceRectangle.Bottom;
+ int startX = sourceRectangle.X;
+ int endX = sourceRectangle.Right;
+ int maxY = sourceBottom - 1;
+ int maxX = endX - 1;
+
+ Parallel.For(
+ startY,
+ endY,
+ y =>
+ {
+ if (y >= sourceY && y < sourceBottom)
+ {
+ for (int x = startX; x < endX; x++)
+ {
+ float rX = 0;
+ float gX = 0;
+ float bX = 0;
+ float rY = 0;
+ float gY = 0;
+ float bY = 0;
+
+ // Apply each matrix multiplier to the color components for each pixel.
+ for (int fy = 0; fy < kernelLength; fy++)
+ {
+ int fyr = fy - radius;
+ int offsetY = y + fyr;
+
+ offsetY = offsetY.Clamp(0, maxY);
+
+ for (int fx = 0; fx < kernelLength; fx++)
+ {
+ int fxr = fx - radius;
+ int offsetX = x + fxr;
+
+ offsetX = offsetX.Clamp(0, maxX);
+
+ Color currentColor = source[offsetX, offsetY];
+ float r = currentColor.R;
+ float g = currentColor.G;
+ float b = currentColor.B;
+
+ rX += kernelX[fy, fx] * r;
+ gX += kernelX[fy, fx] * g;
+ bX += kernelX[fy, fx] * b;
+
+ rY += kernelY[fy, fx] * r;
+ gY += kernelY[fy, fx] * g;
+ bY += kernelY[fy, fx] * b;
+ }
+ }
+
+ float red = (float)Math.Sqrt((rX * rX) + (rY * rY));
+ float green = (float)Math.Sqrt((gX * gX) + (gY * gY));
+ float blue = (float)Math.Sqrt((bX * bX) + (bY * bY));
+
+ target[x, y] = new Color(red, green, blue);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs b/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs
new file mode 100644
index 0000000000..9ee763e6a4
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs
@@ -0,0 +1,83 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ using System.Threading.Tasks;
+
+ ///
+ /// Defines a filter that uses a matrix to perform convolution across a single dimension against an image.
+ ///
+ public abstract class ConvolutionFilter : ParallelImageProcessor
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public abstract float[,] KernelX { get; }
+
+ ///
+ protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
+ {
+ float[,] kernelX = this.KernelX;
+ int kernelLength = kernelX.GetLength(0);
+ int radius = kernelLength >> 1;
+
+ int sourceY = sourceRectangle.Y;
+ int sourceBottom = sourceRectangle.Bottom;
+ int startX = sourceRectangle.X;
+ int endX = sourceRectangle.Right;
+ int maxY = sourceBottom - 1;
+ int maxX = endX - 1;
+
+ Parallel.For(
+ startY,
+ endY,
+ y =>
+ {
+ if (y >= sourceY && y < sourceBottom)
+ {
+ for (int x = startX; x < endX; x++)
+ {
+ float rX = 0;
+ float gX = 0;
+ float bX = 0;
+
+ // Apply each matrix multiplier to the color components for each pixel.
+ for (int fy = 0; fy < kernelLength; fy++)
+ {
+ int fyr = fy - radius;
+ int offsetY = y + fyr;
+
+ offsetY = offsetY.Clamp(0, maxY);
+
+ for (int fx = 0; fx < kernelLength; fx++)
+ {
+ int fxr = fx - radius;
+ int offsetX = x + fxr;
+
+ offsetX = offsetX.Clamp(0, maxX);
+
+ Color currentColor = source[offsetX, offsetY];
+ float r = currentColor.R;
+ float g = currentColor.G;
+ float b = currentColor.B;
+
+ rX += kernelX[fy, fx] * r;
+ gX += kernelX[fy, fx] * g;
+ bX += kernelX[fy, fx] * b;
+ }
+ }
+
+ float red = rX;
+ float green = gX;
+ float blue = bX;
+
+ target[x, y] = new Color(red, green, blue);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/Kayyali.cs b/src/ImageProcessor/Filters/Convolution/Kayyali.cs
new file mode 100644
index 0000000000..f322608832
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Kayyali.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Kayyali operator filter.
+ ///
+ ///
+ public class Kayyali : Convolution2DFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { 6, 0, -6 },
+ { 0, 0, 0 },
+ { -6, 0, 6 }
+ };
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { -6, 0, 6 },
+ { 0, 0, 0 },
+ { 6, 0, -6 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/Kirsch.cs b/src/ImageProcessor/Filters/Convolution/Kirsch.cs
new file mode 100644
index 0000000000..e38572bbb2
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Kirsch.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Kirsch operator filter.
+ ///
+ ///
+ public class Kirsch : Convolution2DFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { 5, 5, 5 },
+ { -3, 0, -3 },
+ { -3, -3, -3 }
+ };
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 5, -3, -3 },
+ { 5, 0, -3 },
+ { 5, -3, -3 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/Laplacian3X3.cs b/src/ImageProcessor/Filters/Convolution/Laplacian3X3.cs
new file mode 100644
index 0000000000..e3a170da55
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Laplacian3X3.cs
@@ -0,0 +1,24 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Laplacian 3 x 3 operator filter.
+ ///
+ ///
+ public class Laplacian3X3 : ConvolutionFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { -1, -1, -1 },
+ { -1, 8, -1 },
+ { -1, -1, -1 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/Laplacian5X5.cs b/src/ImageProcessor/Filters/Convolution/Laplacian5X5.cs
new file mode 100644
index 0000000000..7ee2a93edd
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Laplacian5X5.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Laplacian 5 x 5 operator filter.
+ ///
+ ///
+ public class Laplacian5X5 : ConvolutionFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => 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/ImageProcessor/Filters/Convolution/LaplacianOfGaussian.cs b/src/ImageProcessor/Filters/Convolution/LaplacianOfGaussian.cs
new file mode 100644
index 0000000000..9a7883ce8b
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/LaplacianOfGaussian.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Laplacian of Gaussian operator filter.
+ ///
+ ///
+ public class LaplacianOfGaussian : ConvolutionFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => 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/ImageProcessor/Filters/Convolution/Prewitt.cs b/src/ImageProcessor/Filters/Convolution/Prewitt.cs
new file mode 100644
index 0000000000..c246ece0d1
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Prewitt.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Prewitt operator filter.
+ ///
+ ///
+ public class Prewitt : Convolution2DFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { -1, 0, 1 },
+ { -1, 0, 1 },
+ { -1, 0, 1 }
+ };
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 1, 1, 1 },
+ { 0, 0, 0 },
+ { -1, -1, -1 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/RobertsCross.cs b/src/ImageProcessor/Filters/Convolution/RobertsCross.cs
new file mode 100644
index 0000000000..9af29b3ec7
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/RobertsCross.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Roberts Cross operator filter.
+ ///
+ ///
+ public class RobertsCross : Convolution2DFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { 1, 0 },
+ { 0, -1 }
+ };
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 0, 1 },
+ { -1, 0 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/Scharr.cs b/src/ImageProcessor/Filters/Convolution/Scharr.cs
new file mode 100644
index 0000000000..3ec8a8630e
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Scharr.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Scharr operator filter.
+ ///
+ ///
+ public class Scharr : Convolution2DFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { -3, 0, 3 },
+ { -10, 0, 10 },
+ { -3, 0, 3 }
+ };
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 3, 10, 3 },
+ { 0, 0, 0 },
+ { -3, -10, -3 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/Sobel.cs b/src/ImageProcessor/Filters/Convolution/Sobel.cs
new file mode 100644
index 0000000000..a1a450cf33
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/Sobel.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// The Sobel operator filter.
+ ///
+ ///
+ public class Sobel : Convolution2DFilter
+ {
+ ///
+ /// Gets the horizontal gradient operator.
+ ///
+ public override float[,] KernelX => new float[,]
+ {
+ { -1, 0, 1 },
+ { -2, 0, 2 },
+ { -1, 0, 1 }
+ };
+
+ ///
+ /// Gets the vertical gradient operator.
+ ///
+ public override float[,] KernelY => new float[,]
+ {
+ { 1, 2, 1 },
+ { 0, 0, 0 },
+ { -1, -2, -1 }
+ };
+ }
+}
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 3560f88b2d..d5076b03e1 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -49,11 +49,21 @@
+
+
+
+
+
+
+
+
+
+
@@ -220,6 +230,7 @@
+
@@ -251,6 +262,7 @@
+