mirror of https://github.com/SixLabors/ImageSharp
2 changed files with 162 additions and 0 deletions
@ -0,0 +1,47 @@ |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Extensions to perform AdaptiveThreshold through Mutator
|
|||
/// </summary>
|
|||
public static class AdaptiveThresholdExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies Bradley Adaptive Threshold to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> AdaptiveThreshold<TPixel>(this IImageProcessingContext<TPixel> source) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new AdaptiveThresholdProcessor<TPixel>()); |
|||
|
|||
/// <summary>
|
|||
/// Applies Bradley Adaptive Threshold to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="upper">Upper (white) color for thresholding.</param>
|
|||
/// <param name="lower">Lower (black) color for thresholding</param>
|
|||
/// /// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> AdaptiveThreshold<TPixel>(this IImageProcessingContext<TPixel> source, TPixel upper, TPixel lower) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new AdaptiveThresholdProcessor<TPixel>(upper, lower)); |
|||
|
|||
/// <summary>
|
|||
/// Applies Bradley Adaptive Threshold to the image.
|
|||
/// </summary>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="upper">Upper (white) color for thresholding.</param>
|
|||
/// <param name="lower">Lower (black) color for thresholding</param>
|
|||
/// <param name="rectangle">Rectangle region to apply the processor on.</param>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> AdaptiveThreshold<TPixel>(this IImageProcessingContext<TPixel> source, TPixel upper, TPixel lower, Rectangle rectangle) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new AdaptiveThresholdProcessor<TPixel>(upper, lower), rectangle); |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
using System; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Performs Bradley Adaptive Threshold filter against an image
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format of the image</typeparam>
|
|||
internal class AdaptiveThresholdProcessor<TPixel> : IImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
public AdaptiveThresholdProcessor() |
|||
: this(NamedColors<TPixel>.White, NamedColors<TPixel>.Black) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="upper">Color for upper threshold</param>
|
|||
/// <param name="lower">Color for lower threshold</param>
|
|||
public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) |
|||
{ |
|||
this.Upper = upper; |
|||
this.Lower = lower; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets upper color limit for thresholding
|
|||
/// </summary>
|
|||
public TPixel Upper { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets lower color limit for threshold
|
|||
/// </summary>
|
|||
public TPixel Lower { get; set; } |
|||
|
|||
public unsafe void Apply(Image<TPixel> source, Rectangle sourceRectangle) |
|||
{ |
|||
ushort xStart = (ushort)Math.Max(0, sourceRectangle.X); |
|||
ushort yStart = (ushort)Math.Max(0, sourceRectangle.Y); |
|||
ushort xEnd = (ushort)Math.Min(xStart + sourceRectangle.Width, source.Width); |
|||
ushort yEnd = (ushort)Math.Min(yStart + sourceRectangle.Height, source.Height); |
|||
|
|||
// Algorithm variables
|
|||
uint sum, count; |
|||
ushort s = (ushort)Math.Truncate((xEnd / 16f) - 1); |
|||
uint[,] intImage = new uint[yEnd, xEnd]; |
|||
|
|||
// Trying to figure out how to do this
|
|||
// Using (Buffer2D<ulong> intImg = source.GetConfiguration().MemoryAllocator.Allocate2D<ulong>)
|
|||
Rgb24 rgb = default; |
|||
|
|||
for (ushort i = yStart; i < yEnd; i++) |
|||
{ |
|||
Span<TPixel> span = source.GetPixelRowSpan(i); |
|||
|
|||
sum = 0; |
|||
|
|||
for (ushort j = xStart; j < xEnd; j++) |
|||
{ |
|||
span[j].ToRgb24(ref rgb); |
|||
|
|||
sum += (uint)(rgb.R + rgb.G + rgb.B); |
|||
|
|||
if (i != 0) |
|||
{ |
|||
intImage[i, j] = intImage[i - 1, j] + sum; |
|||
} |
|||
else |
|||
{ |
|||
intImage[i, j] = sum; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// How can I parallelize this?
|
|||
ushort x1, x2, y1, y2; |
|||
|
|||
for (ushort i = yStart; i < yEnd; i++) |
|||
{ |
|||
Span<TPixel> span = source.GetPixelRowSpan(i); |
|||
|
|||
for (ushort j = xStart; j < xEnd; j++) |
|||
{ |
|||
x1 = (ushort)Math.Max(i - s + 1, 0); |
|||
x2 = (ushort)Math.Min(i + s + 1, yEnd - 1); |
|||
y1 = (ushort)Math.Max(j - s + 1, 0); |
|||
y2 = (ushort)Math.Min(j + s + 1, xEnd - 1); |
|||
|
|||
count = (ushort)((x2 - x1) * (y2 - y1)); |
|||
|
|||
sum = intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]; |
|||
|
|||
span[j].ToRgb24(ref rgb); |
|||
|
|||
if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) |
|||
{ |
|||
span[j] = this.Lower; |
|||
} |
|||
else |
|||
{ |
|||
span[j] = this.Upper; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue