Browse Source

Box Blur

Former-commit-id: 5ac93d8e7ce1bb397a8ee7a68307aa423a85882a
Former-commit-id: 7b8b0c704f7f272867516203133bb1c3fbbbf5a5
Former-commit-id: e495b72e24e1f723023cc537749e03a987b9eb8c
af/merge-core
James Jackson-South 10 years ago
parent
commit
400b62f964
  1. 59
      src/ImageProcessorCore/Filters/BoxBlur.cs
  2. 107
      src/ImageProcessorCore/Filters/Processors/Convolution/BoxBlurProcessor.cs
  3. 47
      tests/ImageProcessorCore.Tests/Processors/Filters/BoxBlurTest.cs

59
src/ImageProcessorCore/Filters/BoxBlur.cs

@ -0,0 +1,59 @@
// <copyright file="BoxBlur.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
namespace ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies a box blur to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> BoxBlur<T, TP>(this Image<T, TP> source, int radius = 7, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return BoxBlur(source, radius, source.Bounds, progressHandler);
}
/// <summary>
/// Applies a box blur to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> BoxBlur<T, TP>(this Image<T, TP> source, int radius, Rectangle rectangle, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
BoxBlurProcessor<T, TP> processor = new BoxBlurProcessor<T, TP>(radius);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
}
}

107
src/ImageProcessorCore/Filters/Processors/Convolution/BoxBlurProcessor.cs

@ -0,0 +1,107 @@
// <copyright file="BoxBlurProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
/// <summary>
/// Applies a Box blur filter to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class BoxBlurProcessor<T, TP> : Convolution2PassFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <summary>
/// The maximum size of the kernal in either direction.
/// </summary>
private readonly int kernelSize;
/// <summary>
/// The vertical kernel
/// </summary>
private float[,] kernelY;
/// <summary>
/// The horizontal kernel
/// </summary>
private float[,] kernelX;
/// <summary>
/// Initializes a new instance of the <see cref="GuassianBlurProcessor"/> class.
/// </summary>
/// <param name="radius">
/// The 'radius' value representing the size of the area to sample.
/// </param>
public BoxBlurProcessor(int radius = 7)
{
this.kernelSize = (radius * 2) + 1;
}
/// <inheritdoc/>
public override float[,] KernelX => this.kernelX;
/// <inheritdoc/>
public override float[,] KernelY => this.kernelY;
/// <inheritdoc/>
protected override void OnApply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
if (this.kernelY == null)
{
this.kernelY = this.CreateBoxKernel(false);
}
if (this.kernelX == null)
{
this.kernelX = this.CreateBoxKernel(true);
}
}
/// <summary>
/// Create a 1 dimensional Box kernel.
/// </summary>
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
/// <returns>The <see cref="T:float[,]"/></returns>
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;
}
}
}

47
tests/ImageProcessorCore.Tests/Processors/Filters/BoxBlurTest.cs

@ -0,0 +1,47 @@
// <copyright file="BoxBlurTest.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Xunit;
public class BoxBlurTest : FileTestBase
{
public static readonly TheoryData<int> BoxBlurValues
= new TheoryData<int>
{
3 ,
5 ,
};
[Theory]
[MemberData("BoxBlurValues")]
public void ImageShouldApplyBoxBlurFilter(int value)
{
const string path = "TestOutput/BoxBlur";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + value + Path.GetExtension(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.BoxBlur(value)
.Save(output);
}
}
}
}
}
}
Loading…
Cancel
Save