diff --git a/ImageProcessor.sln.DotSettings b/ImageProcessor.sln.DotSettings
new file mode 100644
index 000000000..39e42e16e
--- /dev/null
+++ b/ImageProcessor.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ XY
\ No newline at end of file
diff --git a/src/ImageProcessor/Filters/ColorMatrix/IColorMatrixFilter.cs b/src/ImageProcessor/Filters/ColorMatrix/IColorMatrixFilter.cs
index fdc0fcafa..b85f2eee9 100644
--- a/src/ImageProcessor/Filters/ColorMatrix/IColorMatrixFilter.cs
+++ b/src/ImageProcessor/Filters/ColorMatrix/IColorMatrixFilter.cs
@@ -11,7 +11,7 @@ namespace ImageProcessor.Filters
/// Encapsulates properties and methods for creating processors that utilize a matrix to
/// alter the image pixels.
///
- public interface IColorMatrixFilter
+ public interface IColorMatrixFilter : IImageProcessor
{
///
/// Gets the used to alter the image.
diff --git a/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs b/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs
index 385d7a949..32c4defc6 100644
--- a/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs
+++ b/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs
@@ -40,7 +40,7 @@ namespace ImageProcessor.Filters
public override Matrix4x4 Matrix => this.matrix;
///
- protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle)
+ protected override void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
float saturationFactor = this.saturation / 100f;
diff --git a/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs b/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs
index b9852b804..4fae35f81 100644
--- a/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs
+++ b/src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs
@@ -9,7 +9,7 @@ namespace ImageProcessor.Filters
using System.Threading.Tasks;
///
- /// Defines a filter that uses a matrix to perform convolution across two dimensions against an image.
+ /// Defines a filter that uses two one-dimensional matrices to perform convolution against an image.
///
public abstract class Convolution2DFilter : ParallelImageProcessor
{
diff --git a/src/ImageProcessor/Filters/Convolution/Convolution2PassFilter.cs b/src/ImageProcessor/Filters/Convolution/Convolution2PassFilter.cs
index 6218414cb..cf75520ed 100644
--- a/src/ImageProcessor/Filters/Convolution/Convolution2PassFilter.cs
+++ b/src/ImageProcessor/Filters/Convolution/Convolution2PassFilter.cs
@@ -8,7 +8,7 @@ namespace ImageProcessor.Filters
using System.Threading.Tasks;
///
- /// Defines a filter that uses a matrix to perform convolution across two dimensions against an image.
+ /// Defines a filter that uses two one-dimensional matrices to perform two-pass convolution against an image.
///
public abstract class Convolution2PassFilter : ParallelImageProcessor
{
diff --git a/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs b/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs
index 9ee763e6a..6d114adab 100644
--- a/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs
+++ b/src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs
@@ -8,19 +8,19 @@ namespace ImageProcessor.Filters
using System.Threading.Tasks;
///
- /// Defines a filter that uses a matrix to perform convolution across a single dimension against an image.
+ /// Defines a filter that uses a 2 dimensional matrix to perform convolution against an image.
///
public abstract class ConvolutionFilter : ParallelImageProcessor
{
///
- /// Gets the horizontal gradient operator.
+ /// Gets the 2d gradient operator.
///
- public abstract float[,] KernelX { get; }
+ public abstract float[,] KernelXY { get; }
///
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
- float[,] kernelX = this.KernelX;
+ float[,] kernelX = this.KernelXY;
int kernelLength = kernelX.GetLength(0);
int radius = kernelLength >> 1;
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/EdgeDetector2DFilter.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/EdgeDetector2DFilter.cs
new file mode 100644
index 000000000..94990b839
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/EdgeDetector2DFilter.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// Defines a filter that detects edges within an image using two
+ /// one-dimensional matrices.
+ ///
+ public abstract class EdgeDetector2DFilter : Convolution2DFilter, IEdgeDetectorFilter
+ {
+ ///
+ public bool Greyscale { get; set; }
+
+ ///
+ protected override void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
+ {
+ if (this.Greyscale)
+ {
+ new GreyscaleBt709().Apply(source, source, sourceRectangle);
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/EdgeDetectorFilter.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/EdgeDetectorFilter.cs
new file mode 100644
index 000000000..b2cb1bbb8
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/EdgeDetectorFilter.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// Defines a filter that detects edges within an image using a single
+ /// two dimensional matrix.
+ ///
+ public abstract class EdgeDetectorFilter : ConvolutionFilter, IEdgeDetectorFilter
+ {
+ ///
+ public bool Greyscale { get; set; }
+
+ ///
+ protected override void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
+ {
+ if (this.Greyscale)
+ {
+ new GreyscaleBt709().Apply(source, source, sourceRectangle);
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/IEdgeDetectorFilter.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/IEdgeDetectorFilter.cs
new file mode 100644
index 000000000..714dffac2
--- /dev/null
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/IEdgeDetectorFilter.cs
@@ -0,0 +1,19 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ ///
+ /// Provides properties and methods allowing the detection of edges within an image.
+ ///
+ public interface IEdgeDetectorFilter : IImageProcessor
+ {
+ ///
+ /// Gets or sets a value indicating whether to convert the
+ /// image to greyscale before performing edge detection.
+ ///
+ bool Greyscale { get; set; }
+ }
+}
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kayyali.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kayyali.cs
index f32260883..1f2deb287 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kayyali.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kayyali.cs
@@ -9,11 +9,9 @@ namespace ImageProcessor.Filters
/// The Kayyali operator filter.
///
///
- public class Kayyali : Convolution2DFilter
+ public class Kayyali : EdgeDetector2DFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
+ ///
public override float[,] KernelX => new float[,]
{
{ 6, 0, -6 },
@@ -21,9 +19,7 @@ namespace ImageProcessor.Filters
{ -6, 0, 6 }
};
- ///
- /// Gets the vertical gradient operator.
- ///
+ ///
public override float[,] KernelY => new float[,]
{
{ -6, 0, 6 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kirsch.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kirsch.cs
index e38572bbb..1fac19272 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kirsch.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Kirsch.cs
@@ -9,11 +9,9 @@ namespace ImageProcessor.Filters
/// The Kirsch operator filter.
///
///
- public class Kirsch : Convolution2DFilter
+ public class Kirsch : EdgeDetector2DFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
+ ///
public override float[,] KernelX => new float[,]
{
{ 5, 5, 5 },
@@ -21,9 +19,7 @@ namespace ImageProcessor.Filters
{ -3, -3, -3 }
};
- ///
- /// Gets the vertical gradient operator.
- ///
+ ///
public override float[,] KernelY => new float[,]
{
{ 5, -3, -3 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian3X3.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian3X3.cs
index e3a170da5..18ea3da19 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian3X3.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian3X3.cs
@@ -9,12 +9,10 @@ namespace ImageProcessor.Filters
/// The Laplacian 3 x 3 operator filter.
///
///
- public class Laplacian3X3 : ConvolutionFilter
+ public class Laplacian3X3 : EdgeDetectorFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
- public override float[,] KernelX => new float[,]
+ ///
+ public override float[,] KernelXY => new float[,]
{
{ -1, -1, -1 },
{ -1, 8, -1 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian5X5.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian5X5.cs
index 7ee2a93ed..6fc83cd8e 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian5X5.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Laplacian5X5.cs
@@ -9,12 +9,10 @@ namespace ImageProcessor.Filters
/// The Laplacian 5 x 5 operator filter.
///
///
- public class Laplacian5X5 : ConvolutionFilter
+ public class Laplacian5X5 : EdgeDetectorFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
- public override float[,] KernelX => new float[,]
+ ///
+ public override float[,] KernelXY => new float[,]
{
{ -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/LaplacianOfGaussian.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/LaplacianOfGaussian.cs
index 9a7883ce8..9033ac285 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/LaplacianOfGaussian.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/LaplacianOfGaussian.cs
@@ -7,14 +7,12 @@ namespace ImageProcessor.Filters
{
///
/// The Laplacian of Gaussian operator filter.
- ///
+ ///
///
- public class LaplacianOfGaussian : ConvolutionFilter
+ public class LaplacianOfGaussian : EdgeDetectorFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
- public override float[,] KernelX => new float[,]
+ ///
+ public override float[,] KernelXY => new float[,]
{
{ 0, 0, -1, 0, 0 },
{ 0, -1, -2, -1, 0 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Prewitt.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Prewitt.cs
index c246ece0d..13415a1c1 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Prewitt.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Prewitt.cs
@@ -9,11 +9,9 @@ namespace ImageProcessor.Filters
/// The Prewitt operator filter.
///
///
- public class Prewitt : Convolution2DFilter
+ public class Prewitt : EdgeDetector2DFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
+ ///
public override float[,] KernelX => new float[,]
{
{ -1, 0, 1 },
@@ -21,14 +19,15 @@ namespace ImageProcessor.Filters
{ -1, 0, 1 }
};
- ///
- /// Gets the vertical gradient operator.
- ///
+ ///
public override float[,] KernelY => new float[,]
{
{ 1, 1, 1 },
{ 0, 0, 0 },
{ -1, -1, -1 }
};
+
+ ///
+ public bool Greyscale { get; set; }
}
}
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/RobertsCross.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/RobertsCross.cs
index 9af29b3ec..a8f85cee1 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/RobertsCross.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/RobertsCross.cs
@@ -9,20 +9,16 @@ namespace ImageProcessor.Filters
/// The Roberts Cross operator filter.
///
///
- public class RobertsCross : Convolution2DFilter
+ public class RobertsCross : EdgeDetector2DFilter
{
- ///
- /// 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 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Scharr.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Scharr.cs
index 3ec8a8630..523648a64 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Scharr.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Scharr.cs
@@ -9,11 +9,9 @@ namespace ImageProcessor.Filters
/// The Scharr operator filter.
///
///
- public class Scharr : Convolution2DFilter
+ public class Scharr : EdgeDetector2DFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
+ ///
public override float[,] KernelX => new float[,]
{
{ -3, 0, 3 },
@@ -21,9 +19,7 @@ namespace ImageProcessor.Filters
{ -3, 0, 3 }
};
- ///
- /// Gets the vertical gradient operator.
- ///
+ ///
public override float[,] KernelY => new float[,]
{
{ 3, 10, 3 },
diff --git a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Sobel.cs b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Sobel.cs
index a1a450cf3..a9fb820e5 100644
--- a/src/ImageProcessor/Filters/Convolution/EdgeDetection/Sobel.cs
+++ b/src/ImageProcessor/Filters/Convolution/EdgeDetection/Sobel.cs
@@ -9,11 +9,9 @@ namespace ImageProcessor.Filters
/// The Sobel operator filter.
///
///
- public class Sobel : Convolution2DFilter
+ public class Sobel : EdgeDetector2DFilter
{
- ///
- /// Gets the horizontal gradient operator.
- ///
+ ///
public override float[,] KernelX => new float[,]
{
{ -1, 0, 1 },
@@ -21,9 +19,7 @@ namespace ImageProcessor.Filters
{ -1, 0, 1 }
};
- ///
- /// Gets the vertical gradient operator.
- ///
+ ///
public override float[,] KernelY => new float[,]
{
{ 1, 2, 1 },
diff --git a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs
index 0973b1a61..3b64bc153 100644
--- a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs
+++ b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs
@@ -82,7 +82,7 @@ namespace ImageProcessor.Filters
public override int Parallelism => 1;
///
- protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle)
+ protected override void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
if (this.kernelY == null)
{
diff --git a/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs b/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs
index 1e45c09de..75eda001f 100644
--- a/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs
+++ b/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs
@@ -82,7 +82,7 @@ namespace ImageProcessor.Filters
public override int Parallelism => 1;
///
- protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle)
+ protected override void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
if (this.kernelY == null)
{
diff --git a/src/ImageProcessor/Filters/ImageFilterExtensions.cs b/src/ImageProcessor/Filters/ImageFilterExtensions.cs
index 343454e7a..f9a91e0f3 100644
--- a/src/ImageProcessor/Filters/ImageFilterExtensions.cs
+++ b/src/ImageProcessor/Filters/ImageFilterExtensions.cs
@@ -135,6 +135,42 @@ namespace ImageProcessor.Filters
return source.Process(rectangle, new Contrast(amount));
}
+ ///
+ /// Detects any edges within the image. Uses the filter
+ /// operating in greyscale mode.
+ ///
+ /// The image this method extends.
+ /// The .
+ public static Image DetectEdges(this Image source)
+ {
+ return DetectEdges(source, source.Bounds, new Sobel { Greyscale = true });
+ }
+
+ ///
+ /// Detects any edges within the image.
+ ///
+ /// The image this method extends.
+ /// The filter for detecting edges.
+ /// The .
+ public static Image DetectEdges(this Image source, IEdgeDetectorFilter filter)
+ {
+ return DetectEdges(source, source.Bounds, filter);
+ }
+
+ ///
+ /// 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.
+ /// The .
+ public static Image DetectEdges(this Image source, Rectangle rectangle, IEdgeDetectorFilter filter)
+ {
+ return source.Process(rectangle, filter);
+ }
+
///
/// Applies greyscale toning to the image.
///
diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs b/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
index 3d82fb71f..2ae1ea4b2 100644
--- a/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
+++ b/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
@@ -8,8 +8,6 @@ namespace ImageProcessor.Formats
using System;
using System.Collections.Generic;
- using ImageProcessor.Common.Extensions;
-
///
/// Encapsulates methods to calculate the colour palette if an image using an Octree pattern.
///
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 9ce6dc4bd..14ec5b965 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -57,6 +57,9 @@
+
+
+
diff --git a/src/ImageProcessor/ParallelImageProcessor.cs b/src/ImageProcessor/ParallelImageProcessor.cs
index 843f40b9e..200b6b183 100644
--- a/src/ImageProcessor/ParallelImageProcessor.cs
+++ b/src/ImageProcessor/ParallelImageProcessor.cs
@@ -21,7 +21,7 @@ namespace ImageProcessor
///
public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
{
- this.OnApply(target.Bounds, sourceRectangle);
+ this.OnApply(source, target.Bounds, sourceRectangle);
if (this.Parallelism > 1)
{
@@ -66,7 +66,7 @@ namespace ImageProcessor
sourceRectangle = source.Bounds;
}
- this.OnApply(target.Bounds, sourceRectangle);
+ this.OnApply(source, target.Bounds, sourceRectangle);
if (this.Parallelism > 1)
{
@@ -98,6 +98,7 @@ namespace ImageProcessor
///
/// This method is called before the process is applied to prepare the processor.
///
+ /// The source image. Cannot be null.
///
/// The structure that specifies the location and size of the drawn image.
/// The image is scaled to fit the rectangle.
@@ -105,7 +106,7 @@ namespace ImageProcessor
///
/// The structure that specifies the portion of the image object to draw.
///
- protected virtual void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle)
+ protected virtual void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
}
diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs
index 1d1484417..f43463efc 100644
--- a/src/ImageProcessor/Samplers/Resize.cs
+++ b/src/ImageProcessor/Samplers/Resize.cs
@@ -48,7 +48,7 @@ namespace ImageProcessor.Samplers
public IResampler Sampler { get; }
///
- protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle)
+ protected override void OnApply(ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
this.horizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width);
this.verticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height);
diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
index c65f2381c..76b0bfdaa 100644
--- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
+++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
@@ -37,7 +37,7 @@ namespace ImageProcessor.Tests
{ "Prewitt", new Prewitt() },
{ "RobertsCross", new RobertsCross() },
{ "Scharr", new Scharr() },
- { "Sobel", new Sobel() },
+ { "Sobel", new Sobel {Greyscale = true} },
{ "GuassianBlur", new GuassianBlur(10) },
{ "GuassianSharpen", new GuassianSharpen(10) }
};