|
|
|
@ -27,11 +27,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
/// The 'sigma' value representing the weight of the sharpening.
|
|
|
|
/// </param>
|
|
|
|
public GaussianSharpenProcessor(float sigma = 3F) |
|
|
|
: this(sigma, (int)MathF.Ceiling(sigma * 3)) |
|
|
|
{ |
|
|
|
this.kernelSize = ((int)Math.Ceiling(sigma) * 2) + 1; |
|
|
|
this.Sigma = sigma; |
|
|
|
this.KernelX = this.CreateGaussianKernel(true); |
|
|
|
this.KernelY = this.CreateGaussianKernel(false); |
|
|
|
// Kernel radius is calculated using the minimum viable value.
|
|
|
|
// http://chemaguerra.com/gaussian-filter-radius/
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -41,11 +40,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
/// The 'radius' value representing the size of the area to sample.
|
|
|
|
/// </param>
|
|
|
|
public GaussianSharpenProcessor(int radius) |
|
|
|
: this(radius / 3F, radius) |
|
|
|
{ |
|
|
|
this.kernelSize = (radius * 2) + 1; |
|
|
|
this.Sigma = radius; |
|
|
|
this.KernelX = this.CreateGaussianKernel(true); |
|
|
|
this.KernelY = this.CreateGaussianKernel(false); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -62,8 +58,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
{ |
|
|
|
this.kernelSize = (radius * 2) + 1; |
|
|
|
this.Sigma = sigma; |
|
|
|
this.KernelX = this.CreateGaussianKernel(true); |
|
|
|
this.KernelY = this.CreateGaussianKernel(false); |
|
|
|
this.KernelX = this.CreateGaussianKernel(); |
|
|
|
this.KernelY = this.KernelX.Transpose(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -83,91 +79,49 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|
|
|
{ |
|
|
|
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); |
|
|
|
} |
|
|
|
=> new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
|
|
|
|
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
|
|
|
|
private DenseMatrix<float> CreateGaussianKernel(bool horizontal) |
|
|
|
private DenseMatrix<float> CreateGaussianKernel() |
|
|
|
{ |
|
|
|
int size = this.kernelSize; |
|
|
|
float weight = this.Sigma; |
|
|
|
DenseMatrix<float> kernel = horizontal |
|
|
|
? new DenseMatrix<float>(size, 1) |
|
|
|
: new DenseMatrix<float>(1, size); |
|
|
|
var kernel = new DenseMatrix<float>(size, 1); |
|
|
|
|
|
|
|
float sum = 0; |
|
|
|
|
|
|
|
float midpoint = (size - 1) / 2f; |
|
|
|
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; |
|
|
|
} |
|
|
|
kernel[0, i] = gx; |
|
|
|
} |
|
|
|
|
|
|
|
// Invert the kernel for sharpening.
|
|
|
|
int midpointRounded = (int)midpoint; |
|
|
|
|
|
|
|
if (horizontal) |
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
{ |
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
if (i == midpointRounded) |
|
|
|
{ |
|
|
|
if (i == midpointRounded) |
|
|
|
{ |
|
|
|
// Calculate central value
|
|
|
|
kernel[0, i] = (2F * sum) - kernel[0, i]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// invert value
|
|
|
|
kernel[0, i] = -kernel[0, i]; |
|
|
|
} |
|
|
|
// Calculate central value
|
|
|
|
kernel[0, i] = (2F * sum) - kernel[0, i]; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
else |
|
|
|
{ |
|
|
|
if (i == midpointRounded) |
|
|
|
{ |
|
|
|
// Calculate central value
|
|
|
|
kernel[i, 0] = (2 * sum) - kernel[i, 0]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// invert value
|
|
|
|
kernel[i, 0] = -kernel[i, 0]; |
|
|
|
} |
|
|
|
// invert value
|
|
|
|
kernel[0, i] = -kernel[0, i]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Normalize kernel so that the sum of all weights equals 1
|
|
|
|
if (horizontal) |
|
|
|
{ |
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
{ |
|
|
|
kernel[0, i] /= sum; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
{ |
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
{ |
|
|
|
kernel[i, 0] /= sum; |
|
|
|
} |
|
|
|
kernel[0, i] /= sum; |
|
|
|
} |
|
|
|
|
|
|
|
return kernel; |
|
|
|
|