Browse Source

Edge detection

Former-commit-id: c2a7aaf6443e721d1ef18fff5a7c8e9cf91b962a
Former-commit-id: 5022db552fc42c6dabdc66b65e96e604f2222013
Former-commit-id: a9a34ac649b51cb6cedaabc13d7a31b1bb88aed3
af/merge-core
James Jackson-South 10 years ago
parent
commit
6856a26b4e
  1. 131
      src/ImageProcessorCore/Filters/DetectEdges.cs
  2. 2
      src/ImageProcessorCore/Filters/Options/ColorBlindness.cs
  3. 58
      src/ImageProcessorCore/Filters/Options/EdgeDetection.cs
  4. 4
      src/ImageProcessorCore/Filters/Options/GreyscaleMode.cs
  5. 9
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs
  6. 34
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
  7. 34
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs
  8. 26
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
  9. 28
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
  10. 28
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
  11. 34
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
  12. 32
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
  13. 34
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
  14. 2
      src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs
  15. 53
      tests/ImageProcessorCore.Tests/Processors/Filters/DetectEdgesTest.cs

131
src/ImageProcessorCore/Filters/DetectEdges.cs

@ -0,0 +1,131 @@
// <copyright file="DetectEdges.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Detects any edges within the image. Uses the <see cref="SobelProcessor"/> filter
/// operating in greyscale mode.
/// </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="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> DetectEdges<T, TP>(this Image<T, TP> source, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return DetectEdges(source, source.Bounds, new SobelProcessor<T, TP> { Greyscale = true }, progressHandler);
}
/// <summary>
/// Detects any edges within 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="filter">The filter for detecting edges.</param>
/// <param name="greyscale">Whether to convert the image to greyscale first. Defaults to true.</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> DetectEdges<T, TP>(this Image<T, TP> source, EdgeDetection filter, bool greyscale = true, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
IEdgeDetectorFilter<T, TP> processor;
switch (filter)
{
case EdgeDetection.Kayyali:
processor = new KayyaliProcessor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.Kirsch:
processor = new KirschProcessor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.Lapacian3X3:
processor = new Laplacian3X3Processor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.Lapacian5X5:
processor = new Laplacian5X5Processor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.LaplacianOfGaussian:
processor = new LaplacianOfGaussianProcessor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.Prewitt:
processor = new PrewittProcessor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.RobertsCross:
processor = new RobertsCrossProcessor<T, TP> { Greyscale = greyscale };
break;
case EdgeDetection.Scharr:
processor = new ScharrProcessor<T, TP> { Greyscale = greyscale };
break;
default:
processor = new ScharrProcessor<T, TP> { Greyscale = greyscale };
break;
}
return DetectEdges(source, source.Bounds, processor, progressHandler);
}
/// <summary>
/// Detects any edges within 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="filter">The filter for detecting edges.</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> DetectEdges<T, TP>(this Image<T, TP> source, IEdgeDetectorFilter<T, TP> filter, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return DetectEdges(source, source.Bounds, filter, progressHandler);
}
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="filter">The filter for detecting edges.</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> DetectEdges<T, TP>(this Image<T, TP> source, Rectangle rectangle, IEdgeDetectorFilter<T, TP> filter, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
filter.OnProgress += progressHandler;
try
{
return source.Process(rectangle, filter);
}
finally
{
filter.OnProgress -= progressHandler;
}
}
}
}

2
src/ImageProcessorCore/Filters/Options/ColorBlindness.cs

@ -6,7 +6,7 @@
namespace ImageProcessorCore
{
/// <summary>
/// Enumerates the various types of color blindness.
/// Enumerates the various types of defined color blindness filters.
/// </summary>
public enum ColorBlindness
{

58
src/ImageProcessorCore/Filters/Options/EdgeDetection.cs

@ -0,0 +1,58 @@
// <copyright file="EdgeDetection.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
/// <summary>
/// Enumerates the various types of defined edge detection filters.
/// </summary>
public enum EdgeDetection
{
/// <summary>
/// The Kayyali operator filter.
/// </summary>
Kayyali,
/// <summary>
/// The Kirsch operator filter.
/// </summary>
Kirsch,
/// <summary>
/// The Lapacian3X3 operator filter.
/// </summary>
Lapacian3X3,
/// <summary>
/// The Lapacian5X5 operator filter.
/// </summary>
Lapacian5X5,
/// <summary>
/// The LaplacianOfGaussian operator filter.
/// </summary>
LaplacianOfGaussian,
/// <summary>
/// The Prewitt operator filter.
/// </summary>
Prewitt,
/// <summary>
/// The RobertsCross operator filter.
/// </summary>
RobertsCross,
/// <summary>
/// The Scharr operator filter.
/// </summary>
Scharr,
/// <summary>
/// The Sobel operator filter.
/// </summary>
Sobel
}
}

4
src/ImageProcessorCore/Filters/Options/GreyscaleMode.cs

@ -3,10 +3,10 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
namespace ImageProcessorCore
{
/// <summary>
/// Provides enumeration over the various greyscale methods available.
/// Enumerates the various types of defined greyscale filters.
/// </summary>
public enum GreyscaleMode
{

9
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs

@ -8,9 +8,16 @@ namespace ImageProcessorCore.Processors
/// <summary>
/// Provides properties and methods allowing the detection of edges within an image.
/// </summary>
public interface IEdgeDetectorFilter<T, TP> : IImageProcessor<T, TP>
public interface IEdgeDetectorFilter<T, TP> : IImageProcessor<T, TP>, IEdgeDetectorFilter
where T : IPackedVector<TP>
where TP : struct
{
}
/// <summary>
/// Provides properties and methods allowing the detection of edges within an image.
/// </summary>
public interface IEdgeDetectorFilter
{
/// <summary>
/// Gets or sets a value indicating whether to convert the

34
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs

@ -0,0 +1,34 @@
// <copyright file="KayyaliProcessor.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>
/// The Kayyali operator filter.
/// <see href="http://edgedetection.webs.com/"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class KayyaliProcessor<T, TP> : EdgeDetector2DFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelX => new float[,]
{
{ 6, 0, -6 },
{ 0, 0, 0 },
{ -6, 0, 6 }
};
/// <inheritdoc/>
public override float[,] KernelY => new float[,]
{
{ -6, 0, 6 },
{ 0, 0, 0 },
{ 6, 0, -6 }
};
}
}

34
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs

@ -0,0 +1,34 @@
// <copyright file="KirschProcessor.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>
/// The Kirsch operator filter.
/// <see href="http://en.wikipedia.org/wiki/Kirsch_operator"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class KirschProcessor<T, TP> : EdgeDetector2DFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelX => new float[,]
{
{ 5, 5, 5 },
{ -3, 0, -3 },
{ -3, -3, -3 }
};
/// <inheritdoc/>
public override float[,] KernelY => new float[,]
{
{ 5, -3, -3 },
{ 5, 0, -3 },
{ 5, -3, -3 }
};
}
}

26
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs

@ -0,0 +1,26 @@
// <copyright file="Laplacian3X3Processor.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>
/// The Laplacian 3 x 3 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class Laplacian3X3Processor<T, TP> : EdgeDetectorFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelXY => new float[,]
{
{ -1, -1, -1 },
{ -1, 8, -1 },
{ -1, -1, -1 }
};
}
}

28
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs

@ -0,0 +1,28 @@
// <copyright file="Laplacian5X5Processor.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>
/// The Laplacian 5 x 5 operator filter.
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class Laplacian5X5Processor<T, TP> : EdgeDetectorFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelXY => 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 }
};
}
}

28
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs

@ -0,0 +1,28 @@
// <copyright file="LaplacianOfGaussianProcessor.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>
/// The Laplacian of Gaussian operator filter.
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class LaplacianOfGaussianProcessor<T, TP> : EdgeDetectorFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelXY => 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/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs

@ -0,0 +1,34 @@
// <copyright file="PrewittProcessor.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>
/// The Prewitt operator filter.
/// <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class PrewittProcessor<T, TP> : EdgeDetector2DFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelX => new float[,]
{
{ -1, 0, 1 },
{ -1, 0, 1 },
{ -1, 0, 1 }
};
/// <inheritdoc/>
public override float[,] KernelY => new float[,]
{
{ 1, 1, 1 },
{ 0, 0, 0 },
{ -1, -1, -1 }
};
}
}

32
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs

@ -0,0 +1,32 @@
// <copyright file="RobertsCrossProcessor.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>
/// The Roberts Cross operator filter.
/// <see href="http://en.wikipedia.org/wiki/Roberts_cross"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class RobertsCrossProcessor<T, TP> : EdgeDetector2DFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelX => new float[,]
{
{ 1, 0 },
{ 0, -1 }
};
/// <inheritdoc/>
public override float[,] KernelY => new float[,]
{
{ 0, 1 },
{ -1, 0 }
};
}
}

34
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs

@ -0,0 +1,34 @@
// <copyright file="ScharrProcessor.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>
/// The Scharr operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class ScharrProcessor<T, TP> : EdgeDetector2DFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override float[,] KernelX => new float[,]
{
{ -3, 0, 3 },
{ -10, 0, 10 },
{ -3, 0, 3 }
};
/// <inheritdoc/>
public override float[,] KernelY => new float[,]
{
{ 3, 10, 3 },
{ 0, 0, 0 },
{ -3, -10, -3 }
};
}
}

2
src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs

@ -9,6 +9,8 @@ namespace ImageProcessorCore.Processors
/// The Sobel operator filter.
/// <see href="http://en.wikipedia.org/wiki/Sobel_operator"/>
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class SobelProcessor<T, TP> : EdgeDetector2DFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct

53
tests/ImageProcessorCore.Tests/Processors/Filters/DetectEdgesTest.cs

@ -0,0 +1,53 @@
// <copyright file="DetectEdgesTest.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 DetectEdgesTest : FileTestBase
{
public static readonly TheoryData<EdgeDetection> DetectEdgesFilters
= new TheoryData<EdgeDetection>
{
EdgeDetection.Kayyali,
EdgeDetection.Kirsch,
EdgeDetection.Lapacian3X3,
EdgeDetection.Lapacian5X5,
EdgeDetection.LaplacianOfGaussian,
EdgeDetection.Prewitt,
EdgeDetection.RobertsCross,
EdgeDetection.Scharr,
EdgeDetection.Sobel,
};
[Theory]
[MemberData("DetectEdgesFilters")]
public void ImageShouldApplyDetectEdgesFilter(EdgeDetection detector)
{
const string path = "TestOutput/DetectEdges";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + detector + Path.GetExtension(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.DetectEdges(detector)
.Save(output);
}
}
}
}
}
}
Loading…
Cancel
Save