From f1b2d2fce67ac052c3b9eb69697b1ca34ea4047a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Sep 2016 00:59:41 +1000 Subject: [PATCH] Fix convolution edge detection Former-commit-id: 7893263bbe8ae48c4c9868d53b4b8d83dacffab4 Former-commit-id: 6eb44d572463eb4d21bf7c5b26ea3836bb4a922e Former-commit-id: 0c17bfb0eef70231ed7f26bf5b7435ac5a895c88 --- .../Samplers/DetectEdges.cs | 22 +-- .../Processors/CompandingResizeProcessor.cs | 3 +- .../Convolution/Convolution2DFilter.cs | 19 ++- .../Convolution/Convolution2PassFilter.cs | 2 +- .../Convolution/ConvolutionFilter.cs | 17 ++- .../EdgeDetection/EdgeDetector2DFilter.cs | 35 ++++- .../EdgeDetectorCompassFilter.cs | 128 ++++++++++++++++++ .../EdgeDetection/EdgeDetectorFilter.cs | 15 +- .../EdgeDetection/IEdgeDetectorFilter.cs | 8 +- .../EdgeDetection/KayyaliProcessor.cs | 21 ++- .../EdgeDetection/KirschProcessor.cs | 96 +++++++++++-- .../EdgeDetection/Laplacian3X3Processor.cs | 15 +- .../EdgeDetection/Laplacian5X5Processor.cs | 17 ++- .../LaplacianOfGaussianProcessor.cs | 17 ++- .../EdgeDetection/PrewittProcessor.cs | 23 +++- .../EdgeDetection/RobertsCrossProcessor.cs | 21 ++- .../EdgeDetection/ScharrProcessor.cs | 23 +++- .../EdgeDetection/SobelProcessor.cs | 21 ++- .../Convolution/GuassianBlurProcessor.cs | 2 +- .../Samplers/Processors/CropProcessor.cs | 2 +- .../Processors/EntropyCropProcessor.cs | 4 +- .../Samplers/Processors/FlipProcessor.cs | 2 +- .../Samplers/Processors/ImageSampler.cs | 2 +- .../Processors/OilPaintingProcessor.cs | 2 +- .../Samplers/Processors/PixelateProcessor.cs | 2 +- .../Samplers/Processors/ResizeProcessor.cs | 2 +- .../Samplers/Processors/RotateProcessor.cs | 2 +- .../Samplers/Processors/SkewProcessor.cs | 2 +- 28 files changed, 443 insertions(+), 82 deletions(-) create mode 100644 src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorCompassFilter.cs diff --git a/src/ImageProcessorCore/Samplers/DetectEdges.cs b/src/ImageProcessorCore/Samplers/DetectEdges.cs index 60006ea72..cc45aa05a 100644 --- a/src/ImageProcessorCore/Samplers/DetectEdges.cs +++ b/src/ImageProcessorCore/Samplers/DetectEdges.cs @@ -25,7 +25,7 @@ namespace ImageProcessorCore where TColor : IPackedVector where TPacked : struct { - return DetectEdges(source, source.Bounds, new SobelProcessor { Grayscale = true }, progressHandler); + return DetectEdges(source, source.Bounds, new SobelProcessor(true), progressHandler); } /// @@ -44,7 +44,7 @@ namespace ImageProcessorCore where TColor : IPackedVector where TPacked : struct { - return DetectEdges(source, rectangle, new SobelProcessor { Grayscale = true }, progressHandler); + return DetectEdges(source, rectangle, new SobelProcessor(true), progressHandler); } /// @@ -86,39 +86,39 @@ namespace ImageProcessorCore switch (filter) { case EdgeDetection.Kayyali: - processor = new KayyaliProcessor { Grayscale = grayscale }; + processor = new KayyaliProcessor(grayscale); break; case EdgeDetection.Kirsch: - processor = new KirschProcessor { Grayscale = grayscale }; + processor = new KirschProcessor(grayscale); break; case EdgeDetection.Lapacian3X3: - processor = new Laplacian3X3Processor { Grayscale = grayscale }; + processor = new Laplacian3X3Processor(grayscale); break; case EdgeDetection.Lapacian5X5: - processor = new Laplacian5X5Processor { Grayscale = grayscale }; + processor = new Laplacian5X5Processor(grayscale); break; case EdgeDetection.LaplacianOfGaussian: - processor = new LaplacianOfGaussianProcessor { Grayscale = grayscale }; + processor = new LaplacianOfGaussianProcessor(grayscale); break; case EdgeDetection.Prewitt: - processor = new PrewittProcessor { Grayscale = grayscale }; + processor = new PrewittProcessor(grayscale); break; case EdgeDetection.RobertsCross: - processor = new RobertsCrossProcessor { Grayscale = grayscale }; + processor = new RobertsCrossProcessor(grayscale); break; case EdgeDetection.Scharr: - processor = new ScharrProcessor { Grayscale = grayscale }; + processor = new ScharrProcessor(grayscale); break; default: - processor = new SobelProcessor { Grayscale = grayscale }; + processor = new SobelProcessor(grayscale); break; } diff --git a/src/ImageProcessorCore/Samplers/Processors/CompandingResizeProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/CompandingResizeProcessor.cs index acbd7f5f0..50ad894bf 100644 --- a/src/ImageProcessorCore/Samplers/Processors/CompandingResizeProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/CompandingResizeProcessor.cs @@ -34,7 +34,7 @@ namespace ImageProcessorCore.Processors public override bool Compand { get; set; } = true; /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { // Jump out, we'll deal with that later. if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) @@ -157,7 +157,6 @@ namespace ImageProcessorCore.Processors this.OnRowProcessed(); }); - } } } diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs index a923c0bfc..307da4353 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs @@ -14,22 +14,33 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class Convolution2DFilter : ImageSampler + public class Convolution2DFilter : ImageSampler where TColor : IPackedVector where TPacked : struct { + /// + /// Initializes a new instance of the class. + /// + /// The horizontal gradient operator. + /// The vertical gradient operator. + public Convolution2DFilter(float[,] kernelX, float[,] kernelY) + { + this.KernelX = kernelX; + this.KernelY = kernelY; + } + /// /// Gets the horizontal gradient operator. /// - public abstract float[,] KernelX { get; } + public float[,] KernelX { get; } /// /// Gets the vertical gradient operator. /// - public abstract float[,] KernelY { get; } + public float[,] KernelY { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float[,] kernelX = this.KernelX; float[,] kernelY = this.KernelY; diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs index a73113554..5eb4155ff 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs @@ -28,7 +28,7 @@ namespace ImageProcessorCore.Processors public abstract float[,] KernelY { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float[,] kernelX = this.KernelX; float[,] kernelY = this.KernelY; diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs index 60c03218a..35229eb4f 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs @@ -13,17 +13,26 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class ConvolutionFilter : ImageSampler + public class ConvolutionFilter : ImageSampler where TColor : IPackedVector where TPacked : struct { + /// + /// Initializes a new instance of the class. + /// + /// The 2d gradient operator. + public ConvolutionFilter(float[,] kernelXY) + { + this.KernelXY = kernelXY; + } + /// /// Gets the 2d gradient operator. /// - public abstract float[,] KernelXY { get; } + public virtual float[,] KernelXY { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float[,] kernelX = this.KernelXY; int kernelLength = kernelX.GetLength(0); @@ -87,8 +96,8 @@ namespace ImageProcessorCore.Processors TColor packed = default(TColor); packed.PackFromVector4(new Vector4(red, green, blue, targetColor.Z)); targetPixels[x, y] = packed; - } + this.OnRowProcessed(); } }); diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs index 88414ca3a..e107f71a9 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs @@ -11,12 +11,41 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class EdgeDetector2DFilter : Convolution2DFilter, IEdgeDetectorFilter + public class EdgeDetector2DFilter : ImageSampler, IEdgeDetectorFilter where TColor : IPackedVector where TPacked : struct { + /// + /// Initializes a new instance of the class. + /// + /// The horizontal gradient operator. + /// The vertical gradient operator. + /// Whether to convert the image to grayscale before performing edge detection.. + public EdgeDetector2DFilter(float[,] kernelX, float[,] kernelY, bool grayscale) + { + this.KernelX = kernelX; + this.KernelY = kernelY; + this.Grayscale = grayscale; + } + + /// + /// Gets the horizontal gradient operator. + /// + public float[,] KernelX { get; } + + /// + /// Gets the vertical gradient operator. + /// + public float[,] KernelY { get; } + /// - public bool Grayscale { get; set; } + public bool Grayscale { get; } + + /// + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + new Convolution2DFilter(this.KernelX, this.KernelY).Apply(target, source, targetRectangle, sourceRectangle, startY, endY); + } /// protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) @@ -27,4 +56,4 @@ namespace ImageProcessorCore.Processors } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorCompassFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorCompassFilter.cs new file mode 100644 index 000000000..060fc837f --- /dev/null +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorCompassFilter.cs @@ -0,0 +1,128 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Processors +{ + using System; + using System.Numerics; + using System.Threading.Tasks; + + public class EdgeDetectorCompassFilter : ImageSampler, IEdgeDetectorFilter + where TColor : IPackedVector + where TPacked : struct + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The collection of 2d gradient operator. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public EdgeDetectorCompassFilter(float[][,] kernels, bool grayscale) + { + this.Kernels = kernels; + this.Grayscale = grayscale; + } + + /// + /// Gets the collection of 2d gradient operators. + /// + public float[][,] Kernels { get; } + + /// + public bool Grayscale { get; } + + /// + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + + // Align start/end positions. + int minX = Math.Max(0, startX); + int maxX = Math.Min(source.Width, endX); + int minY = Math.Max(0, startY); + int maxY = Math.Min(source.Height, endY); + + // Reset offset if necessary. + if (minX > 0) + { + startX = 0; + } + + if (minY > 0) + { + startY = 0; + } + + + new EdgeDetectorFilter(this.Kernels[0], this.Grayscale).Apply(target, source, sourceRectangle, targetRectangle, startY, endY); + + //this.ApplyConvolution(target, source, sourceRectangle, this.Grayscale, this.Kernels[0]); + + if (this.Kernels.Length == 1) + { + return; + } + + for (int i = 1; i < this.Kernels.Length; i++) + { + ImageBase pass = new Image(source.Width, source.Height); + new EdgeDetectorFilter(this.Kernels[0], false).Apply(pass, source, sourceRectangle, targetRectangle, startY, endY); + + + // this.ApplyConvolution(pass, source, sourceRectangle, false, this.Kernels[0]); + + using (PixelAccessor passPixels = pass.Lock()) + using (PixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + minY, + maxY, + this.ParallelOptions, + y => + { + int offsetY = y - startY; + for (int x = minX; x < maxX; x++) + { + int offsetX = x - startX; + Vector4 passColor = passPixels[offsetX, offsetY].ToVector4(); + Vector4 targetColor = targetPixels[offsetX, offsetY].ToVector4(); + + TColor packed = default(TColor); + packed.PackFromVector4(Vector4.Max(passColor, targetColor)); + targetPixels[offsetX, offsetY] = packed; + } + }); + } + } + } + + /// + protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + { + if (this.Grayscale) + { + new GrayscaleBt709Processor().Apply(source, sourceRectangle); + } + } + + /// + /// Applies the convolution process to the specified portion of the specified at the specified location + /// and with the specified size. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// Whether to convert the image to grayscale before performing edge detection. + /// The kernel operator. + private void ApplyConvolution(ImageBase target, ImageBase source, Rectangle sourceRectangle, bool grayScale, float[,] kernel) + { + new EdgeDetectorFilter(kernel, grayScale).Apply(target, source, sourceRectangle); + } + } +} diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs index 1c1a2cba7..8a43f26f2 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs @@ -11,12 +11,23 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class EdgeDetectorFilter : ConvolutionFilter, IEdgeDetectorFilter + public class EdgeDetectorFilter : ConvolutionFilter, IEdgeDetectorFilter where TColor : IPackedVector where TPacked : struct { + /// + /// Initializes a new instance of the class. + /// + /// The 2d gradient operator. + /// Whether to convert the image to grayscale before performing edge detection.. + public EdgeDetectorFilter(float[,] kernelXY, bool grayscale) + : base(kernelXY) + { + this.Grayscale = grayscale; + } + /// - public bool Grayscale { get; set; } + public bool Grayscale { get; } /// protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs index 0f0fedb8e..76039e5e6 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs @@ -22,9 +22,9 @@ namespace ImageProcessorCore.Processors public interface IEdgeDetectorFilter { /// - /// Gets or sets a value indicating whether to convert the - /// image to Grayscale before performing edge detection. + /// Gets a value indicating whether to convert the + /// image to grayscale before performing edge detection. /// - bool Grayscale { get; set; } + bool Grayscale { get; } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs index a7d31a607..60bebbce7 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs @@ -15,16 +15,29 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelX => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public KayyaliProcessor(bool grayscale) + : base(KernelA, KernelB, grayscale) + { + } + + /// + /// Gets the horizontal gradient operator. + /// + public static float[,] KernelA => new float[,] { { 6, 0, -6 }, { 0, 0, 0 }, { -6, 0, 6 } }; - /// - public override float[,] KernelY => new float[,] + /// + /// Gets the vertical gradient operator. + /// + public static float[,] KernelB => new float[,] { { -6, 0, 6 }, { 0, 0, 0 }, diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KirschProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KirschProcessor.cs index 0c06106e3..908a3781b 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KirschProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KirschProcessor.cs @@ -11,24 +11,100 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public class KirschProcessor : EdgeDetector2DFilter + public class KirschProcessor : EdgeDetectorCompassFilter where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelX => new float[,] + public KirschProcessor(bool grayscale) + : base(new[] { North, Northwest, West, Southwest, South, Southeast, East, Northeast }, grayscale) { - { 5, 5, 5 }, - { -3, 0, -3 }, + } + + /// + /// Gets the North direction Kirsch kernel mask. + /// + /// + public static float[,] North => new float[,] + { + { -3, -3, 5 }, + { -3, 0, 5 }, + { -3, -3, 5 } + }; + + /// + /// Gets the Northwest direction Kirsch kernel mask. + /// + /// + public static float[,] Northwest => new float[,] + { + { -3, 5, 5 }, + { -3, 0, 5 }, + { -3, -3, -3 } + }; + + /// + /// Gets the West direction Kirsch kernel mask. + /// + /// + public static float[,] West => new float[,] + { + { 5, 5, 5 }, + { -3, 0, -3 }, + { -3, -3, -3 } + }; + + /// + /// Gets the Southwest direction Kirsch kernel mask. + /// + /// + public static float[,] Southwest => new float[,] + { + { 5, 5, -3 }, + { 5, 0, -3 }, { -3, -3, -3 } }; - /// - public override float[,] KernelY => new float[,] + /// + /// Gets the South direction Kirsch kernel mask. + /// + /// + public static float[,] South => new float[,] + { + { 5, -3, -3 }, + { 5, 0, -3 }, + { 5, -3, -3 } + }; + + /// + /// Gets the Southeast direction Kirsch kernel mask. + /// + public static float[,] Southeast => new float[,] + { + { -3, -3, -3 }, + { 5, 0, -3 }, + { 5, 5, -3 } + }; + + /// + /// Gets the East direction Kirsch kernel mask. + /// + /// + public static float[,] East => new float[,] + { + { -3, -3, -3 }, + { -3, 0, -3 }, + { 5, 5, 5 } + }; + + /// + /// Gets the Northeast direction Kirsch kernel mask. + /// + /// + public static float[,] Northeast => new float[,] { - { 5, -3, -3 }, - { 5, 0, -3 }, - { 5, -3, -3 } + { -3, -3, -3 }, + { -3, 0, 5 }, + { -3, 5, 5 } }; } } diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs index 47eb02202..19d8a0b4e 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs @@ -15,8 +15,19 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelXY => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public Laplacian3X3Processor(bool grayscale) + : base(Kernel, grayscale) + { + } + + /// + /// Gets the 2d gradient operator. + /// + public static float[,] Kernel => new float[,] { { -1, -1, -1 }, { -1, 8, -1 }, diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs index 14a66348c..583c98993 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs @@ -15,8 +15,19 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelXY => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public Laplacian5X5Processor(bool grayscale) + : base(Kernel, grayscale) + { + } + + /// + /// Gets the 2d gradient operator. + /// + public static float[,] Kernel => new float[,] { { -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1 }, @@ -25,4 +36,4 @@ namespace ImageProcessorCore.Processors { -1, -1, -1, -1, -1 } }; } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs index 1899a68a0..cbbd7ac95 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs @@ -15,8 +15,19 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelXY => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public LaplacianOfGaussianProcessor(bool grayscale) + : base(Kernel, grayscale) + { + } + + /// + /// Gets the 2d gradient operator. + /// + public static float[,] Kernel => new float[,] { { 0, 0, -1, 0, 0 }, { 0, -1, -2, -1, 0 }, @@ -25,4 +36,4 @@ namespace ImageProcessorCore.Processors { 0, 0, -1, 0, 0 } }; } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/PrewittProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/PrewittProcessor.cs index 068660588..d883d376f 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/PrewittProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/PrewittProcessor.cs @@ -15,20 +15,33 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelX => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public PrewittProcessor(bool grayscale) + : base(KernelA, KernelB, grayscale) + { + } + + /// + /// Gets the horizontal gradient operator. + /// + public static float[,] KernelA => new float[,] { { -1, 0, 1 }, { -1, 0, 1 }, { -1, 0, 1 } }; - /// - public override float[,] KernelY => new float[,] + /// + /// Gets the vertical gradient operator. + /// + public static float[,] KernelB => new float[,] { { 1, 1, 1 }, { 0, 0, 0 }, { -1, -1, -1 } }; } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs index 69c5abe34..c21e18c9b 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs @@ -15,15 +15,28 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelX => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public RobertsCrossProcessor(bool grayscale) + : base(KernelA, KernelB, grayscale) + { + } + + /// + /// Gets the horizontal gradient operator. + /// + public static float[,] KernelA => new float[,] { { 1, 0 }, { 0, -1 } }; - /// - public override float[,] KernelY => new float[,] + /// + /// Gets the vertical gradient operator. + /// + public static float[,] KernelB => new float[,] { { 0, 1 }, { -1, 0 } diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/ScharrProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/ScharrProcessor.cs index 108e45579..ca7f584bc 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/ScharrProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/ScharrProcessor.cs @@ -15,20 +15,33 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelX => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public ScharrProcessor(bool grayscale) + : base(KernelA, KernelB, grayscale) + { + } + + /// + /// Gets the horizontal gradient operator. + /// + public static float[,] KernelA => new float[,] { { -3, 0, 3 }, { -10, 0, 10 }, { -3, 0, 3 } }; - /// - public override float[,] KernelY => new float[,] + /// + /// Gets the vertical gradient operator. + /// + public static float[,] KernelB => new float[,] { { 3, 10, 3 }, { 0, 0, 0 }, { -3, -10, -3 } }; } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/SobelProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/SobelProcessor.cs index 34b593015..be2281027 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/SobelProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/SobelProcessor.cs @@ -15,16 +15,29 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { - /// - public override float[,] KernelX => new float[,] + /// + /// Initializes a new instance of the class. + /// + /// Whether to convert the image to grayscale before performing edge detection.. + public SobelProcessor(bool grayscale) + : base(KernelA, KernelB, grayscale) + { + } + + /// + /// Gets the horizontal gradient operator. + /// + public static float[,] KernelA => new float[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; - /// - public override float[,] KernelY => new float[,] + /// + /// Gets the horizontal gradient operator. + /// + public static float[,] KernelB => new float[,] { { 1, 2, 1 }, { 0, 0, 0 }, diff --git a/src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianBlurProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianBlurProcessor.cs index 7a9b0137f..24dd01490 100644 --- a/src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianBlurProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianBlurProcessor.cs @@ -17,7 +17,7 @@ namespace ImageProcessorCore.Processors where TPacked : struct { /// - /// The maximum size of the kernal in either direction. + /// The maximum size of the kernel in either direction. /// private readonly int kernelSize; diff --git a/src/ImageProcessorCore/Samplers/Processors/CropProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/CropProcessor.cs index 573eb7042..80ec06d01 100644 --- a/src/ImageProcessorCore/Samplers/Processors/CropProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/CropProcessor.cs @@ -17,7 +17,7 @@ namespace ImageProcessorCore.Processors where TPacked : struct { /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int startX = targetRectangle.X; int endX = targetRectangle.Right; diff --git a/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs index 847c90d6e..ab097ce05 100644 --- a/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs @@ -47,7 +47,7 @@ namespace ImageProcessorCore.Processors ImageBase temp = new Image(source.Width, source.Height); // Detect the edges. - new SobelProcessor().Apply(temp, source, sourceRectangle); + new SobelProcessor(false).Apply(temp, source, sourceRectangle); // Apply threshold binarization filter. new BinaryThresholdProcessor(.5f).Apply(temp, sourceRectangle); @@ -61,7 +61,7 @@ namespace ImageProcessorCore.Processors } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { // Jump out, we'll deal with that later. if (source.Bounds == target.Bounds) diff --git a/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs index 5efc72b49..e178266a4 100644 --- a/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs @@ -32,7 +32,7 @@ namespace ImageProcessorCore.Processors public FlipType FlipType { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { target.ClonePixels(target.Width, target.Height, source.Pixels); diff --git a/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs b/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs index 956ce4df0..b2e4890f8 100644 --- a/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs +++ b/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs @@ -89,7 +89,7 @@ namespace ImageProcessorCore.Processors /// /// The method keeps the source image unchanged and returns the the result of image process as new image. /// - protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY); + public abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY); /// /// This method is called before the process is applied to prepare the processor. diff --git a/src/ImageProcessorCore/Samplers/Processors/OilPaintingProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/OilPaintingProcessor.cs index 8388bad30..b93468655 100644 --- a/src/ImageProcessorCore/Samplers/Processors/OilPaintingProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/OilPaintingProcessor.cs @@ -44,7 +44,7 @@ namespace ImageProcessorCore.Processors public int BrushSize { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; diff --git a/src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs index f0d75eb8a..5e5d1c09e 100644 --- a/src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs @@ -37,7 +37,7 @@ namespace ImageProcessorCore.Processors public int Value { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; diff --git a/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs index 21a0a3b11..eea31cea8 100644 --- a/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs @@ -33,7 +33,7 @@ namespace ImageProcessorCore.Processors } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { // Jump out, we'll deal with that later. if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) diff --git a/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs index be005f252..ba3ed8448 100644 --- a/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs @@ -52,7 +52,7 @@ namespace ImageProcessorCore.Processors } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { if (OptimizedApply(target, source)) { diff --git a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs index 6f3344f32..9a9adc4ed 100644 --- a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs @@ -49,7 +49,7 @@ namespace ImageProcessorCore.Processors } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int height = target.Height; int width = target.Width;