Browse Source

Add convolution filters

Former-commit-id: 604e3759aba908e0614162aeeb1342fc8bbea41f
Former-commit-id: 4ffda848ba0286e0dda46fb65c0c187a99a9481b
Former-commit-id: 00ae35f7a65252bccd9a52adce6b26183d4a8a01
pull/17/head
James Jackson-South 11 years ago
parent
commit
e52ddf1bf9
  1. 97
      src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs
  2. 83
      src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs
  3. 34
      src/ImageProcessor/Filters/Convolution/Kayyali.cs
  4. 34
      src/ImageProcessor/Filters/Convolution/Kirsch.cs
  5. 24
      src/ImageProcessor/Filters/Convolution/Laplacian3X3.cs
  6. 26
      src/ImageProcessor/Filters/Convolution/Laplacian5X5.cs
  7. 26
      src/ImageProcessor/Filters/Convolution/LaplacianOfGaussian.cs
  8. 34
      src/ImageProcessor/Filters/Convolution/Prewitt.cs
  9. 32
      src/ImageProcessor/Filters/Convolution/RobertsCross.cs
  10. 34
      src/ImageProcessor/Filters/Convolution/Scharr.cs
  11. 34
      src/ImageProcessor/Filters/Convolution/Sobel.cs
  12. 12
      src/ImageProcessor/ImageProcessor.csproj
  13. 1
      src/ImageProcessor/ImageProcessor.csproj.DotSettings
  14. 2
      src/ImageProcessor/project.lock.json.REMOVED.git-id
  15. 13
      tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

97
src/ImageProcessor/Filters/Convolution/Convolution2DFilter.cs

@ -0,0 +1,97 @@
// <copyright file="Convolution2DFilter.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
using System;
using System.Threading.Tasks;
/// <summary>
/// Defines a filter that uses a matrix to perform convolution across two dimensions against an image.
/// </summary>
public abstract class Convolution2DFilter : ParallelImageProcessor
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public abstract float[,] KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public abstract float[,] KernelY { get; }
/// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
float[,] kernelX = this.KernelX;
float[,] kernelY = this.KernelY;
int kernelLength = kernelX.GetLength(0);
int radius = kernelLength >> 1;
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int maxY = sourceBottom - 1;
int maxX = endX - 1;
Parallel.For(
startY,
endY,
y =>
{
if (y >= sourceY && y < sourceBottom)
{
for (int x = startX; x < endX; x++)
{
float rX = 0;
float gX = 0;
float bX = 0;
float rY = 0;
float gY = 0;
float bY = 0;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelLength; fy++)
{
int fyr = fy - radius;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
for (int fx = 0; fx < kernelLength; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
Color currentColor = source[offsetX, offsetY];
float r = currentColor.R;
float g = currentColor.G;
float b = currentColor.B;
rX += kernelX[fy, fx] * r;
gX += kernelX[fy, fx] * g;
bX += kernelX[fy, fx] * b;
rY += kernelY[fy, fx] * r;
gY += kernelY[fy, fx] * g;
bY += kernelY[fy, fx] * b;
}
}
float red = (float)Math.Sqrt((rX * rX) + (rY * rY));
float green = (float)Math.Sqrt((gX * gX) + (gY * gY));
float blue = (float)Math.Sqrt((bX * bX) + (bY * bY));
target[x, y] = new Color(red, green, blue);
}
}
});
}
}
}

83
src/ImageProcessor/Filters/Convolution/ConvolutionFilter.cs

@ -0,0 +1,83 @@
// <copyright file="ConvolutionFilter.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
using System.Threading.Tasks;
/// <summary>
/// Defines a filter that uses a matrix to perform convolution across a single dimension against an image.
/// </summary>
public abstract class ConvolutionFilter : ParallelImageProcessor
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public abstract float[,] KernelX { get; }
/// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
float[,] kernelX = this.KernelX;
int kernelLength = kernelX.GetLength(0);
int radius = kernelLength >> 1;
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int maxY = sourceBottom - 1;
int maxX = endX - 1;
Parallel.For(
startY,
endY,
y =>
{
if (y >= sourceY && y < sourceBottom)
{
for (int x = startX; x < endX; x++)
{
float rX = 0;
float gX = 0;
float bX = 0;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelLength; fy++)
{
int fyr = fy - radius;
int offsetY = y + fyr;
offsetY = offsetY.Clamp(0, maxY);
for (int fx = 0; fx < kernelLength; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
Color currentColor = source[offsetX, offsetY];
float r = currentColor.R;
float g = currentColor.G;
float b = currentColor.B;
rX += kernelX[fy, fx] * r;
gX += kernelX[fy, fx] * g;
bX += kernelX[fy, fx] * b;
}
}
float red = rX;
float green = gX;
float blue = bX;
target[x, y] = new Color(red, green, blue);
}
}
});
}
}
}

34
src/ImageProcessor/Filters/Convolution/Kayyali.cs

@ -0,0 +1,34 @@
// <copyright file="Kayyali.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Kayyali operator filter.
/// <see href="http://edgedetection.webs.com/"/>
/// </summary>
public class Kayyali : Convolution2DFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ 6, 0, -6 },
{ 0, 0, 0 },
{ -6, 0, 6 }
};
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public override float[,] KernelY => new float[,]
{
{ -6, 0, 6 },
{ 0, 0, 0 },
{ 6, 0, -6 }
};
}
}

34
src/ImageProcessor/Filters/Convolution/Kirsch.cs

@ -0,0 +1,34 @@
// <copyright file="Kirsch.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Kirsch operator filter.
/// <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>
/// </summary>
public class Kirsch : Convolution2DFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ 5, 5, 5 },
{ -3, 0, -3 },
{ -3, -3, -3 }
};
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public override float[,] KernelY => new float[,]
{
{ 5, -3, -3 },
{ 5, 0, -3 },
{ 5, -3, -3 }
};
}
}

24
src/ImageProcessor/Filters/Convolution/Laplacian3X3.cs

@ -0,0 +1,24 @@
// <copyright file="Laplacian3X3.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Laplacian 3 x 3 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
public class Laplacian3X3 : ConvolutionFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ -1, -1, -1 },
{ -1, 8, -1 },
{ -1, -1, -1 }
};
}
}

26
src/ImageProcessor/Filters/Convolution/Laplacian5X5.cs

@ -0,0 +1,26 @@
// <copyright file="Laplacian5X5.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Laplacian 5 x 5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
public class Laplacian5X5 : ConvolutionFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1 },
{ -1, -1, 24, -1, -1 },
{ -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1 }
};
}
}

26
src/ImageProcessor/Filters/Convolution/LaplacianOfGaussian.cs

@ -0,0 +1,26 @@
// <copyright file="LaplacianOfGaussian.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Laplacian of Gaussian operator filter.
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node9.html"/>
/// </summary>
public class LaplacianOfGaussian : ConvolutionFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ 0, 0, -1, 0, 0 },
{ 0, -1, -2, -1, 0 },
{ -1, -2, 16, -2, -1 },
{ 0, -1, -2, -1, 0 },
{ 0, 0, -1, 0, 0 }
};
}
}

34
src/ImageProcessor/Filters/Convolution/Prewitt.cs

@ -0,0 +1,34 @@
// <copyright file="Prewitt.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Prewitt operator filter.
/// <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>
/// </summary>
public class Prewitt : Convolution2DFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ -1, 0, 1 },
{ -1, 0, 1 },
{ -1, 0, 1 }
};
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public override float[,] KernelY => new float[,]
{
{ 1, 1, 1 },
{ 0, 0, 0 },
{ -1, -1, -1 }
};
}
}

32
src/ImageProcessor/Filters/Convolution/RobertsCross.cs

@ -0,0 +1,32 @@
// <copyright file="RobertsCross.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Roberts Cross operator filter.
/// <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>
/// </summary>
public class RobertsCross : Convolution2DFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ 1, 0 },
{ 0, -1 }
};
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public override float[,] KernelY => new float[,]
{
{ 0, 1 },
{ -1, 0 }
};
}
}

34
src/ImageProcessor/Filters/Convolution/Scharr.cs

@ -0,0 +1,34 @@
// <copyright file="Scharr.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Scharr operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators"/>
/// </summary>
public class Scharr : Convolution2DFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ -3, 0, 3 },
{ -10, 0, 10 },
{ -3, 0, 3 }
};
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public override float[,] KernelY => new float[,]
{
{ 3, 10, 3 },
{ 0, 0, 0 },
{ -3, -10, -3 }
};
}
}

34
src/ImageProcessor/Filters/Convolution/Sobel.cs

@ -0,0 +1,34 @@
// <copyright file="Sobel.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
/// <summary>
/// The Sobel operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>
/// </summary>
public class Sobel : Convolution2DFilter
{
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public override float[,] KernelX => new float[,]
{
{ -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 }
};
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public override float[,] KernelY => new float[,]
{
{ 1, 2, 1 },
{ 0, 0, 0 },
{ -1, -2, -1 }
};
}
}

12
src/ImageProcessor/ImageProcessor.csproj

@ -49,11 +49,21 @@
<Compile Include="Common\Helpers\ImageMaths.cs" />
<Compile Include="Common\Helpers\PixelOperations.cs" />
<Compile Include="Filters\Blend.cs" />
<Compile Include="Filters\Convolution\Convolution2DFilter.cs" />
<Compile Include="Filters\ColorMatrix\ColorMatrixFilter.cs" />
<Compile Include="Filters\ColorMatrix\Kodachrome.cs" />
<Compile Include="Filters\ColorMatrix\Saturation.cs" />
<Compile Include="Filters\ColorMatrix\GreyscaleMode.cs" />
<Compile Include="Filters\Brightness.cs" />
<Compile Include="Filters\Convolution\Scharr.cs" />
<Compile Include="Filters\Convolution\RobertsCross.cs" />
<Compile Include="Filters\Convolution\Prewitt.cs" />
<Compile Include="Filters\Convolution\LaplacianOfGaussian.cs" />
<Compile Include="Filters\Convolution\Laplacian3X3.cs" />
<Compile Include="Filters\Convolution\Laplacian5X5.cs" />
<Compile Include="Filters\Convolution\Kirsch.cs" />
<Compile Include="Filters\Convolution\Kayyali.cs" />
<Compile Include="Filters\Convolution\Sobel.cs" />
<Compile Include="Filters\Invert.cs" />
<Compile Include="Filters\Alpha.cs" />
<Compile Include="Filters\ColorMatrix\GreyscaleBt601.cs" />
@ -220,6 +230,7 @@
<Compile Include="Numerics\Point.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Numerics\Size.cs" />
<Compile Include="Filters\Convolution\ConvolutionFilter.cs" />
<Compile Include="Samplers\Resamplers\Lanczos5Resampler.cs" />
<Compile Include="Samplers\Resamplers\Lanczos8Resampler.cs" />
<Compile Include="Samplers\Resamplers\WelchResampler.cs" />
@ -251,6 +262,7 @@
<ItemGroup>
<AdditionalFiles Include="stylecop.json" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

1
src/ImageProcessor/ImageProcessor.csproj.DotSettings

@ -8,6 +8,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=common_005Chelpers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=encoders_005Cgif/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=filters_005Ccolormatrix/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=filters_005Cconvolution/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=formats_005Cbmp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=formats_005Cgif/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=formats_005Cgif_005Cquantizer/@EntryIndexedValue">True</s:Boolean>

2
src/ImageProcessor/project.lock.json.REMOVED.git-id

@ -1 +1 @@
eb00c54ee74016c2b70f81963e7e8f83cb2dd54b
3f05708641eb3ed085d4689aae4a960eb067fd16

13
tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

@ -16,7 +16,7 @@ namespace ImageProcessor.Tests
//{ "Brightness--50", new Brightness(-50) },
//{ "Contrast-50", new Contrast(50) },
//{ "Contrast--50", new Contrast(-50) },
{ "Blend", new Blend(new Image(File.OpenRead("../../TestImages/Formats/Bmp/Car.bmp")),75)},
//{ "Blend", new Blend(new Image(File.OpenRead("../../TestImages/Formats/Bmp/Car.bmp")),15)},
//{ "Saturation-50", new Saturation(50) },
//{ "Saturation--50", new Saturation(-50) },
//{ "Alpha--50", new Alpha(50) },
@ -27,7 +27,16 @@ namespace ImageProcessor.Tests
//{ "Polaroid", new Polaroid() },
//{ "Kodachrome", new Kodachrome() },
//{ "GreyscaleBt709", new GreyscaleBt709() },
//{ "GreyscaleBt601", new GreyscaleBt601() },
//{ "GreyscaleBt601", new GreyscaleBt601() },`
{ "Kayyali", new Kayyali() },
{ "Kirsch", new Kirsch() },
{ "Laplacian3X3", new Laplacian3X3() },
{ "Laplacian5X5", new Laplacian5X5() },
{ "LaplacianOfGaussian", new LaplacianOfGaussian() },
{ "Prewitt", new Prewitt() },
{ "RobertsCross", new RobertsCross() },
{ "Scharr", new Scharr() },
{ "Sobel", new Sobel() }
};
[Theory]

Loading…
Cancel
Save