Browse Source

Adding detect edges to web and moar unit tests

Former-commit-id: a73c74f036b0137963147d593d1d0118c7d867d1
pull/17/head
James South 12 years ago
parent
commit
b47aa8e2cf
  1. 138
      src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
  2. 1
      src/ImageProcessor.Web/Configuration/Resources/processing.config
  3. 1
      src/ImageProcessor.Web/ImageProcessor.Web.csproj
  4. 166
      src/ImageProcessor.Web/Processors/DetectEdges.cs
  5. 6
      src/ImageProcessor.Web/Processors/Filter.cs
  6. 39
      src/ImageProcessor.Web/Processors/Resize.cs
  7. 2
      src/ImageProcessor.sln
  8. 6
      src/ImageProcessor/ImageProcessor.csproj
  9. 2
      src/ImageProcessor/Imaging/Filters/EdgeDetection/I2DEdgeFilter.cs
  10. 4
      src/ImageProcessor/Imaging/Filters/EdgeDetection/Laplacian3X3EdgeFilter.cs
  11. 4
      src/ImageProcessor/Imaging/Filters/EdgeDetection/Laplacian5X5EdgeFilter.cs
  12. 4
      src/ImageProcessor/Imaging/Filters/EdgeDetection/LaplacianOfGaussianEdgeFilter.cs
  13. 0
      src/ImageProcessorConsole/Program.cs
  14. 1
      src/TestWebsites/MVC/config/imageprocessor/processing.config

138
src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs

@ -13,6 +13,7 @@ namespace ImageProcessor.UnitTests
using System.Linq;
using ImageProcessor.Imaging;
using ImageProcessor.Imaging.Filters.EdgeDetection;
using ImageProcessor.Imaging.Filters.Photo;
using NUnit.Framework;
@ -246,9 +247,9 @@ namespace ImageProcessor.UnitTests
Image original = (Image)imageFactory.Image.Clone();
imageFactory.Watermark(new TextLayer
{
FontFamily = new FontFamily("Arial"),
FontSize = 10,
Position = new Point(10, 10),
FontFamily = new FontFamily("Arial"),
FontSize = 10,
Position = new Point(10, 10),
Text = "Lorem ipsum dolor"
});
Assert.AreNotEqual(original, imageFactory.Image);
@ -546,6 +547,137 @@ namespace ImageProcessor.UnitTests
}
}
/// <summary>
/// Tests that the images hue has been altered.
/// </summary>
[Test]
public void TestHue()
{
foreach (FileInfo file in this.ListInputFiles())
{
using (ImageFactory imageFactory = new ImageFactory())
{
imageFactory.Load(file.FullName);
Image original = (Image)imageFactory.Image.Clone();
imageFactory.Hue(90);
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.Hue(116, true);
Assert.AreNotEqual(original, imageFactory.Image);
}
}
}
/// <summary>
/// Tests that the image has been pixelated.
/// </summary>
[Test]
public void TestPixelate()
{
foreach (FileInfo file in this.ListInputFiles())
{
using (ImageFactory imageFactory = new ImageFactory())
{
imageFactory.Load(file.FullName);
Image original = (Image)imageFactory.Image.Clone();
imageFactory.Pixelate(8);
Assert.AreNotEqual(original, imageFactory.Image);
}
}
}
/// <summary>
/// Tests that the images quality has been set.
/// </summary>
[Test]
public void TestQuality()
{
foreach (FileInfo file in this.ListInputFiles())
{
using (ImageFactory imageFactory = new ImageFactory())
{
imageFactory.Load(file.FullName);
int original = imageFactory.CurrentImageFormat.Quality;
imageFactory.Quality(69);
int updated = imageFactory.CurrentImageFormat.Quality;
Assert.AreNotEqual(original, updated);
}
}
}
/// <summary>
/// Tests that the image has had a color replaced.
/// </summary>
[Test]
public void TestReplaceColor()
{
foreach (FileInfo file in this.ListInputFiles())
{
using (ImageFactory imageFactory = new ImageFactory())
{
imageFactory.Load(file.FullName);
Image original = (Image)imageFactory.Image.Clone();
imageFactory.ReplaceColor(Color.White, Color.Black, 90);
Assert.AreNotEqual(original, imageFactory.Image);
}
}
}
/// <summary>
/// Tests that the various edge detection algorithms are applied.
/// </summary>
[Test]
public void TestEdgeDetection()
{
foreach (FileInfo file in this.ListInputFiles())
{
using (ImageFactory imageFactory = new ImageFactory())
{
imageFactory.Load(file.FullName);
Image original = (Image)imageFactory.Image.Clone();
imageFactory.DetectEdges(new KayyaliEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new KirschEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new Laplacian3X3EdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new Laplacian5X5EdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new LaplacianOfGaussianEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new PrewittEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new RobertsCrossEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new ScharrEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
imageFactory.DetectEdges(new SobelEdgeFilter());
Assert.AreNotEqual(original, imageFactory.Image);
imageFactory.Reset();
}
}
}
/// <summary>
/// Gets the files matching the given extensions.
/// </summary>

1
src/ImageProcessor.Web/Configuration/Resources/processing.config

@ -7,6 +7,7 @@
<plugin name="BackgroundColor" type="ImageProcessor.Web.Processors.BackgroundColor, ImageProcessor.Web"/>
<plugin name="Brightness" type="ImageProcessor.Web.Processors.Brightness, ImageProcessor.Web"/>
<plugin name="Contrast" type="ImageProcessor.Web.Processors.Contrast, ImageProcessor.Web"/>
<plugin name="DetectEdges" type="ImageProcessor.Web.Processors.DetectEdges, ImageProcessor.Web"/>
<plugin name="Crop" type="ImageProcessor.Web.Processors.Crop, ImageProcessor.Web"/>
<plugin name="Filter" type="ImageProcessor.Web.Processors.Filter, ImageProcessor.Web"/>
<plugin name="Flip" type="ImageProcessor.Web.Processors.Flip, ImageProcessor.Web"/>

1
src/ImageProcessor.Web/ImageProcessor.Web.csproj

@ -46,6 +46,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Caching\CachedImage.cs" />
<Compile Include="Processors\DetectEdges.cs" />
<Compile Include="Services\IImageService.cs" />
<Compile Include="Caching\MemCache.cs" />
<Compile Include="Caching\DiskCache.cs" />

166
src/ImageProcessor.Web/Processors/DetectEdges.cs

@ -0,0 +1,166 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DetectEdges.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Produces an image with the detected edges highlighted.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Processors
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Compilation;
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging.Filters.EdgeDetection;
using ImageProcessor.Processors;
/// <summary>
/// Produces an image with the detected edges highlighted.
/// </summary>
public class DetectEdges : IWebGraphicsProcessor
{
/// <summary>
/// The regular expression to search strings for.
/// </summary>
private static readonly Regex QueryRegex = BuildRegex();
/// <summary>
/// The regular expression to search strings for the greyscale attribute.
/// </summary>
private static readonly Regex GreyscaleRegex = new Regex(@"greyscale=false", RegexOptions.Compiled);
/// <summary>
/// The edge detectors.
/// </summary>
private static Dictionary<string, object> detectors;
/// <summary>
/// Initializes a new instance of the <see cref="DetectEdges"/> class.
/// </summary>
public DetectEdges()
{
this.Processor = new ImageProcessor.Processors.DetectEdges();
}
/// <summary>
/// Gets the regular expression to search strings for.
/// </summary>
public Regex RegexPattern
{
get
{
return QueryRegex;
}
}
/// <summary>
/// Gets the order in which this processor is to be used in a chain.
/// </summary>
public int SortOrder { get; private set; }
/// <summary>
/// Gets the processor.
/// </summary>
/// <value>
/// The processor.
/// </value>
public IGraphicsProcessor Processor { get; private set; }
/// <summary>
/// The position in the original string where the first character of the captured substring was found.
/// </summary>
/// <param name="queryString">
/// The query string to search.
/// </param>
/// <returns>
/// The zero-based starting position in the original string where the captured substring was found.
/// </returns>
public int MatchRegexIndex(string queryString)
{
int index = 0;
// Set the sort order to max to allow filtering.
this.SortOrder = int.MaxValue;
// First merge the matches so we can parse .
StringBuilder stringBuilder = new StringBuilder();
foreach (Match match in this.RegexPattern.Matches(queryString))
{
if (match.Success)
{
if (index == 0)
{
// Set the index on the first instance only.
this.SortOrder = match.Index;
stringBuilder.Append(queryString);
}
index += 1;
}
}
if (this.SortOrder < int.MaxValue)
{
// Match syntax
string toParse = stringBuilder.ToString();
IEdgeFilter filter = this.ParseFilter(toParse);
bool greyscale = !GreyscaleRegex.IsMatch(toParse);
this.Processor.DynamicParameter = new Tuple<IEdgeFilter, bool>(filter, greyscale);
}
return this.SortOrder;
}
/// <summary>
/// Builds a regular expression from the <see cref="IEdgeFilter"/> type, this allows extensibility.
/// </summary>
/// <returns>
/// The <see cref="Regex"/> to match matrix filters.
/// </returns>
private static Regex BuildRegex()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("detectedges=(");
Type type = typeof(IEdgeFilter);
// Build a list of native IEdgeFilter instances.
detectors = BuildManager.GetReferencedAssemblies()
.Cast<Assembly>()
.SelectMany(s => s.GetLoadableTypes())
.Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract)
.ToDictionary(t => t.Name.ToLowerInvariant().Replace("edgefilter", string.Empty), Activator.CreateInstance);
stringBuilder.Append(string.Join("|", detectors.Keys.ToList()));
stringBuilder.Append(")");
return new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase);
}
/// <summary>
/// Parses the input string to return the correct <see cref="IEdgeFilter"/>.
/// </summary>
/// <param name="identifier">
/// The identifier.
/// </param>
/// <returns>
/// The <see cref="IEdgeFilter"/>.
/// </returns>
private IEdgeFilter ParseFilter(string identifier)
{
return (IEdgeFilter)detectors[this.RegexPattern.Match(identifier).Value.Split('=')[1]];
}
}
}

6
src/ImageProcessor.Web/Processors/Filter.cs

@ -51,11 +51,7 @@ namespace ImageProcessor.Web.Processors
/// <summary>
/// Gets the order in which this processor is to be used in a chain.
/// </summary>
public int SortOrder
{
get;
private set;
}
public int SortOrder { get; private set; }
/// <summary>
/// Gets the processor.

39
src/ImageProcessor.Web/Processors/Resize.cs

@ -128,24 +128,29 @@ namespace ImageProcessor.Web.Processors
}
}
// Match syntax
string toParse = stringBuilder.ToString();
Size size = this.ParseSize(toParse);
ResizeLayer resizeLayer = new ResizeLayer(size)
if (this.SortOrder < int.MaxValue)
{
ResizeMode = this.ParseMode(toParse),
AnchorPosition = this.ParsePosition(toParse),
Upscale = !UpscaleRegex.IsMatch(toParse),
CenterCoordinates = this.ParseCoordinates(toParse),
};
this.Processor.DynamicParameter = resizeLayer;
// Correctly parse any restrictions.
string restrictions;
this.Processor.Settings.TryGetValue("RestrictTo", out restrictions);
((ImageProcessor.Processors.Resize)this.Processor).RestrictedSizes = this.ParseRestrictions(restrictions);
// Match syntax
string toParse = stringBuilder.ToString();
Size size = this.ParseSize(toParse);
ResizeLayer resizeLayer = new ResizeLayer(size)
{
ResizeMode = this.ParseMode(toParse),
AnchorPosition = this.ParsePosition(toParse),
Upscale = !UpscaleRegex.IsMatch(toParse),
CenterCoordinates = this.ParseCoordinates(toParse),
};
this.Processor.DynamicParameter = resizeLayer;
// Correctly parse any restrictions.
string restrictions;
this.Processor.Settings.TryGetValue("RestrictTo", out restrictions);
((ImageProcessor.Processors.Resize)this.Processor).RestrictedSizes = this.ParseRestrictions(
restrictions);
}
return this.SortOrder;
}

2
src/ImageProcessor.sln

@ -22,7 +22,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web", "Image
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Plugins.WebP", "Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj", "{2CF69699-959A-44DC-A281-4E2596C25043}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Playground", "ImageProcessor.Playground\ImageProcessor.Playground.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Playground", "ImageProcessorConsole\ImageProcessor.Playground.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web.UnitTests", "ImageProcessor.Web.UnitTests\ImageProcessor.Web.UnitTests.csproj", "{961340C8-8C93-401D-A0A2-FF9EC61E5260}"
EndProject

6
src/ImageProcessor/ImageProcessor.csproj

@ -81,9 +81,9 @@
<Compile Include="Imaging\Filters\EdgeDetection\I2DEdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\IEdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\KirschEdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\Laplacian5X5Filter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\Laplacian3x3Filter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\LaplacianOfGaussianFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\Laplacian5X5EdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\Laplacian3X3EdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\LaplacianOfGaussianEdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\ScharrEdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\RobertsCrossEdgeFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\PrewittEdgeFilter.cs" />

2
src/ImageProcessor/Imaging/Filters/EdgeDetection/I2DEdgeFilter.cs

@ -1,5 +1,5 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IEdgeFilter.cs" company="James South">
// <copyright file="I2DEdgeFilter.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>

4
src/ImageProcessor/Imaging/Filters/EdgeDetection/Laplacian3x3Filter.cs → src/ImageProcessor/Imaging/Filters/EdgeDetection/Laplacian3X3EdgeFilter.cs

@ -1,5 +1,5 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Laplacian3x3Filter.cs" company="James South">
// <copyright file="Laplacian3X3EdgeFilter.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
/// The Laplacian 3 x 3 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
public class Laplacian3X3Filter : IEdgeFilter
public class Laplacian3X3EdgeFilter : IEdgeFilter
{
/// <summary>
/// Gets the horizontal gradient operator.

4
src/ImageProcessor/Imaging/Filters/EdgeDetection/Laplacian5X5Filter.cs → src/ImageProcessor/Imaging/Filters/EdgeDetection/Laplacian5X5EdgeFilter.cs

@ -1,5 +1,5 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Laplacian5X5Filter.cs" company="James South">
// <copyright file="Laplacian5X5EdgeFilter.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
/// The Laplacian 5 x 5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
public class Laplacian5X5Filter : IEdgeFilter
public class Laplacian5X5EdgeFilter : IEdgeFilter
{
/// <summary>
/// Gets the horizontal gradient operator.

4
src/ImageProcessor/Imaging/Filters/EdgeDetection/LaplacianOfGaussianFilter.cs → src/ImageProcessor/Imaging/Filters/EdgeDetection/LaplacianOfGaussianEdgeFilter.cs

@ -1,5 +1,5 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="LaplacianOfGaussianFilter.cs" company="James South">
// <copyright file="LaplacianOfGaussianEdgeFilter.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
/// The Laplacian of Gaussian operator filter.
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node9.html"/>
/// </summary>
public class LaplacianOfGaussianFilter : IEdgeFilter
public class LaplacianOfGaussianEdgeFilter : IEdgeFilter
{
/// <summary>
/// Gets the horizontal gradient operator.

0
src/ImageProcessorConsole/Program.cs

1
src/TestWebsites/MVC/config/imageprocessor/processing.config

@ -8,6 +8,7 @@
<plugin name="Brightness" type="ImageProcessor.Web.Processors.Brightness, ImageProcessor.Web"/>
<plugin name="Contrast" type="ImageProcessor.Web.Processors.Contrast, ImageProcessor.Web"/>
<plugin name="Crop" type="ImageProcessor.Web.Processors.Crop, ImageProcessor.Web"/>
<plugin name="DetectEdges" type="ImageProcessor.Web.Processors.DetectEdges, ImageProcessor.Web"/>
<plugin name="Filter" type="ImageProcessor.Web.Processors.Filter, ImageProcessor.Web"/>
<plugin name="Flip" type="ImageProcessor.Web.Processors.Flip, ImageProcessor.Web"/>
<plugin name="Format" type="ImageProcessor.Web.Processors.Format, ImageProcessor.Web"/>

Loading…
Cancel
Save