diff --git a/src/ImageProcessor/Filters/Convolution/BoxBlur.cs b/src/ImageProcessor/Filters/Convolution/BoxBlur.cs new file mode 100644 index 000000000..0de41f22f --- /dev/null +++ b/src/ImageProcessor/Filters/Convolution/BoxBlur.cs @@ -0,0 +1,106 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + /// + /// Applies a Box blur filter to the image. + /// + public class BoxBlur : Convolution2PassFilter + { + /// + /// The maximum size of the kernal in either direction. + /// + private readonly int kernelSize; + + /// + /// The vertical kernel + /// + private float[,] kernelY; + + /// + /// The horizontal kernel + /// + private float[,] kernelX; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The 'radius' value representing the size of the area to sample. + /// + public BoxBlur(int radius = 7) + { + this.kernelSize = (radius * 2) + 1; + } + + /// + public override float[,] KernelX => this.kernelX; + + /// + public override float[,] KernelY => this.kernelY; + + /// + public override int Parallelism => 1; + + /// + protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) + { + if (this.kernelY == null) + { + this.kernelY = this.CreateBoxKernel(false); + } + + if (this.kernelX == null) + { + this.kernelX = this.CreateBoxKernel(true); + } + } + + /// + /// Create a 1 dimensional Box kernel. + /// + /// Whether to calculate a horizontal kernel. + /// The + private float[,] CreateBoxKernel(bool horizontal) + { + int size = this.kernelSize; + float[,] kernel = horizontal ? new float[1, size] : new float[size, 1]; + float sum = 0.0f; + + for (int i = 0; i < size; i++) + { + float x = 1; + sum += x; + if (horizontal) + { + kernel[0, i] = x; + } + else + { + kernel[i, 0] = x; + } + } + + // Normalise kernel so that the sum of all weights equals 1 + if (horizontal) + { + for (int i = 0; i < size; i++) + { + kernel[0, i] = kernel[0, i] / sum; + } + } + else + { + for (int i = 0; i < size; i++) + { + kernel[i, 0] = kernel[i, 0] / sum; + } + } + + return kernel; + } + } +} diff --git a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs index 41dec9d1c..66c4ff4b1 100644 --- a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs +++ b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs @@ -35,9 +35,7 @@ namespace ImageProcessor.Filters /// /// Initializes a new instance of the class. /// - /// - /// The 'sigma' value representing the weight of the blur. - /// + /// The 'sigma' value representing the weight of the blur. public GuassianBlur(float sigma = 3f) { this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; diff --git a/src/ImageProcessor/Filters/ImageFilterExtensions.cs b/src/ImageProcessor/Filters/ImageFilterExtensions.cs index 5651934b5..83d0edaa0 100644 --- a/src/ImageProcessor/Filters/ImageFilterExtensions.cs +++ b/src/ImageProcessor/Filters/ImageFilterExtensions.cs @@ -96,6 +96,31 @@ namespace ImageProcessor.Filters return source.Process(rectangle, new BlackWhite()); } + /// + /// Applies a box blur to the image. + /// + /// The image this method extends. + /// The 'radius' value representing the size of the area to sample. + /// The . + public static Image BoxBlur(this Image source, int radius = 7) + { + return BoxBlur(source, radius, source.Bounds); + } + + /// + /// Applies a box blur to the image. + /// + /// The image this method extends. + /// The 'radius' value representing the size of the area to sample. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The . + public static Image BoxBlur(this Image source, int radius, Rectangle rectangle) + { + return source.Process(rectangle, new BoxBlur(radius)); + } + /// /// Alters the brightness component of the image. /// @@ -209,6 +234,56 @@ namespace ImageProcessor.Filters : source.Process(rectangle, new GreyscaleBt601()); } + /// + /// Applies a Guassian blur to the image. + /// + /// The image this method extends. + /// The 'sigma' value representing the weight of the blur. + /// The . + public static Image GuassianBlur(this Image source, float sigma = 3f) + { + return GuassianBlur(source, sigma, source.Bounds); + } + + /// + /// Applies a Guassian blur to the image. + /// + /// The image this method extends. + /// The 'sigma' value representing the weight of the blur. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The . + public static Image GuassianBlur(this Image source, float sigma, Rectangle rectangle) + { + return source.Process(rectangle, new GuassianBlur(sigma)); + } + + /// + /// Applies a Guassian sharpening filter to the image. + /// + /// The image this method extends. + /// The 'sigma' value representing the weight of the blur. + /// The . + public static Image GuassianSharpen(this Image source, float sigma = 3f) + { + return GuassianSharpen(source, sigma, source.Bounds); + } + + /// + /// Applies a Guassian sharpening filter to the image. + /// + /// The image this method extends. + /// The 'sigma' value representing the weight of the blur. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The . + public static Image GuassianSharpen(this Image source, float sigma, Rectangle rectangle) + { + return source.Process(rectangle, new GuassianSharpen(sigma)); + } + /// /// Alters the hue component of the image. /// diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index e5a0c1a07..d4e0d610e 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs @@ -43,7 +43,8 @@ namespace ImageProcessor.Tests { "GuassianBlur", new GuassianBlur(10) }, { "GuassianSharpen", new GuassianSharpen(10) }, { "Hue-180", new Hue(180) }, - { "Hue--180", new Hue(-180) } + { "Hue--180", new Hue(-180) }, + { "BoxBlur", new BoxBlur(10) }, }; [Theory]