From ece2da8328fb0a93ea82fcab6a096051e5dfbb5d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 7 Nov 2015 19:22:16 +1100 Subject: [PATCH] Add Gaussian sharpen Former-commit-id: f8e9680318aedca08d2c7787106ba030174fcc2e Former-commit-id: e48f8ed39f2a5b883c2cd8696c17b281b41654ec Former-commit-id: ca8ee29dc48c97aa14274dbbaa6f60bc3fa0b358 --- .../Filters/Convolution/GuassianBlur.cs | 2 +- .../Filters/Convolution/GuassianSharpen.cs | 153 ++++++++++++++++++ src/ImageProcessor/ImageProcessor.csproj | 1 + .../Processors/Filters/FilterTests.cs | 3 +- 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs diff --git a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs index c142b62cd..0532e7b7f 100644 --- a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs +++ b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs @@ -8,7 +8,7 @@ namespace ImageProcessor.Filters using System; /// - /// Applies a Gaussian blur to the image. + /// Applies a Gaussian blur filter to the image. /// public class GuassianBlur : Convolution2PassFilter { diff --git a/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs b/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs new file mode 100644 index 000000000..fd7befdad --- /dev/null +++ b/src/ImageProcessor/Filters/Convolution/GuassianSharpen.cs @@ -0,0 +1,153 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + using System; + + /// + /// Applies a Gaussian sharpening filter to the image. + /// + public class GuassianSharpen : Convolution2PassFilter + { + /// + /// The maximum size of the kernal in either direction. + /// + private readonly int kernelSize; + + /// + /// The spread of the blur. + /// + private readonly float sigma; + + /// + /// The vertical kernel + /// + private float[,] kernelY; + + /// + /// The horizontal kernel + /// + private float[,] kernelX; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The 'sigma' value representing the weight of the sharpening. + /// + public GuassianSharpen(float sigma = 3f) + { + this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; + this.sigma = sigma; + } + + /// + public override float[,] KernelX => this.kernelX; + + /// + public override float[,] KernelY => this.kernelY; + + /// + public override int Parallelism => 1; + + /// + protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle) + { + if (this.kernelY == null) + { + this.kernelY = this.CreateGaussianKernel(false); + } + + if (this.kernelX == null) + { + this.kernelX = this.CreateGaussianKernel(true); + } + } + + /// + /// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function + /// + /// Whether to calculate a horizontal kernel. + /// The + private float[,] CreateGaussianKernel(bool horizontal) + { + int size = this.kernelSize; + float weight = this.sigma; + float[,] kernel = horizontal ? new float[1, size] : new float[size, 1]; + float sum = 0; + + float midpoint = (size - 1) / 2f; + for (int i = 0; i < size; i++) + { + float x = i - midpoint; + float gx = ImageMaths.Gaussian(x, weight); + sum += gx; + if (horizontal) + { + kernel[0, i] = gx; + } + else + { + kernel[i, 0] = gx; + } + } + + // Invert the kernel for sharpening. + int midpointRounded = (int)midpoint; + + if (horizontal) + { + for (int i = 0; i < size; i++) + { + if (i == midpointRounded) + { + // Calculate central value + kernel[0, i] = (2f * sum) - kernel[0, i]; + } + else + { + // invert value + kernel[0, i] = -kernel[0, i]; + } + } + } + else + { + for (int i = 0; i < size; i++) + { + if (i == midpointRounded) + { + // Calculate central value + kernel[i, 0] = (2 * sum) - kernel[i, 0]; + } + else + { + // invert value + kernel[i, 0] = -kernel[i, 0]; + } + } + } + + // 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/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 19f6584e8..8e9ef8c0a 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -66,6 +66,7 @@ + diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index 4db94c522..98102f9b1 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs @@ -38,7 +38,8 @@ namespace ImageProcessor.Tests //{ "RobertsCross", new RobertsCross() }, //{ "Scharr", new Scharr() }, //{ "Sobel", new Sobel() }, - { "GuassianBlur", new GuassianBlur(10) } + //{ "GuassianBlur", new GuassianBlur() }, + { "GuassianSharpen", new GuassianSharpen() } }; [Theory]