Browse Source

Merge branch 'master' into js/faster-deflate

pull/1574/head
James Jackson-South 6 years ago
committed by GitHub
parent
commit
9a9a78d21e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 43
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  2. 74
      src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs
  3. 77
      src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs
  4. 160
      src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs
  5. 97
      tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
  6. 127
      tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs
  7. 13
      tests/ImageSharp.Tests/TestImages.cs
  8. 2
      tests/Images/External
  9. 3
      tests/Images/Input/Png/Bradley01.png
  10. 3
      tests/Images/Input/Png/Bradley02.png
  11. 3
      tests/Images/Input/Tga/indexed_a_rle_LL.tga
  12. 3
      tests/Images/Input/Tga/indexed_a_rle_LR.tga
  13. 3
      tests/Images/Input/Tga/indexed_a_rle_UL.tga
  14. 3
      tests/Images/Input/Tga/indexed_a_rle_UR.tga
  15. 3
      tests/Images/Input/Tga/indexed_rle_LL.tga
  16. 3
      tests/Images/Input/Tga/indexed_rle_LR.tga
  17. 3
      tests/Images/Input/Tga/indexed_rle_UL.tga
  18. 3
      tests/Images/Input/Tga/indexed_rle_UR.tga

43
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -252,14 +252,14 @@ namespace SixLabors.ImageSharp.Formats.Tga
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
@ -321,7 +321,6 @@ namespace SixLabors.ImageSharp.Formats.Tga
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * bytesPerPixel, AllocationOptions.Clean))
{
TPixel color = default;
var alphaBits = this.tgaMetadata.AlphaChannelBits;
Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle(width, height, bufferSpan, bytesPerPixel: 1);
@ -339,30 +338,13 @@ namespace SixLabors.ImageSharp.Formats.Tga
color.FromL8(Unsafe.As<byte, L8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 2:
Bgra5551 bgra = Unsafe.As<byte, Bgra5551>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]);
if (!this.hasAlpha)
{
// Set alpha value to 1, to treat it as opaque for Bgra5551.
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
}
color.FromBgra5551(bgra);
this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color);
break;
case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 4:
if (this.hasAlpha)
{
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
}
else
{
var alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3];
color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha));
}
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
}
@ -737,20 +719,29 @@ namespace SixLabors.ImageSharp.Formats.Tga
PixelOperations<TPixel>.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
private void ReadPalettedBgr16Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes, ref color);
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Bgra5551 bgra = default;
bgra.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
bgra.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[index * colorMapPixelSizeInBytes]));
if (!this.hasAlpha)
{
// Set alpha value to 1, to treat it as opaque for Bgra5551.
// Set alpha value to 1, to treat it as opaque.
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
}
color.FromBgra5551(bgra);
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

74
src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs

@ -0,0 +1,74 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Processors.Binarization;
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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source)
=> source.ApplyProcessor(new AdaptiveThresholdProcessor());
/// <summary>
/// Applies Bradley Adaptive Threshold to the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="thresholdLimit">Threshold limit (0.0-1.0) to consider for binarization.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, float thresholdLimit)
=> source.ApplyProcessor(new AdaptiveThresholdProcessor(thresholdLimit));
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower)
=> source.ApplyProcessor(new AdaptiveThresholdProcessor(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="thresholdLimit">Threshold limit (0.0-1.0) to consider for binarization.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, float thresholdLimit)
=> source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit));
/// <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>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, Rectangle rectangle)
=> source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower), rectangle);
/// <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="thresholdLimit">Threshold limit (0.0-1.0) to consider for binarization.</param>
/// <param name="rectangle">Rectangle region to apply the processor on.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, float thresholdLimit, Rectangle rectangle)
=> source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit), rectangle);
}
}

77
src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs

@ -0,0 +1,77 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs Bradley Adaptive Threshold filter against an image.
/// </summary>
/// <remarks>
/// Implements "Adaptive Thresholding Using the Integral Image",
/// see paper: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.420.7883&amp;rep=rep1&amp;type=pdf
/// </remarks>
public class AdaptiveThresholdProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor"/> class.
/// </summary>
public AdaptiveThresholdProcessor()
: this(Color.White, Color.Black, 0.85f)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor"/> class.
/// </summary>
/// <param name="thresholdLimit">Threshold limit.</param>
public AdaptiveThresholdProcessor(float thresholdLimit)
: this(Color.White, Color.Black, thresholdLimit)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor"/> class.
/// </summary>
/// <param name="upper">Color for upper threshold.</param>
/// <param name="lower">Color for lower threshold.</param>
public AdaptiveThresholdProcessor(Color upper, Color lower)
: this(upper, lower, 0.85f)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor"/> class.
/// </summary>
/// <param name="upper">Color for upper threshold.</param>
/// <param name="lower">Color for lower threshold.</param>
/// <param name="thresholdLimit">Threshold limit.</param>
public AdaptiveThresholdProcessor(Color upper, Color lower, float thresholdLimit)
{
this.Upper = upper;
this.Lower = lower;
this.ThresholdLimit = thresholdLimit;
}
/// <summary>
/// Gets or sets upper color limit for thresholding.
/// </summary>
public Color Upper { get; set; }
/// <summary>
/// Gets or sets lower color limit for threshold.
/// </summary>
public Color Lower { get; set; }
/// <summary>
/// Gets or sets the value for threshold limit.
/// </summary>
public float ThresholdLimit { get; set; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : unmanaged, IPixel<TPixel>
=> new AdaptiveThresholdProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

160
src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs

@ -0,0 +1,160 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs Bradley Adaptive Threshold filter against an image.
/// </summary>
internal class AdaptiveThresholdProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly AdaptiveThresholdProcessor definition;
/// <summary>
/// Initializes a new instance of the <see cref="AdaptiveThresholdProcessor{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="definition">The <see cref="AdaptiveThresholdProcessor"/> defining the processor parameters.</param>
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
public AdaptiveThresholdProcessor(Configuration configuration, AdaptiveThresholdProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
var intersect = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
Configuration configuration = this.Configuration;
TPixel upper = this.definition.Upper.ToPixel<TPixel>();
TPixel lower = this.definition.Lower.ToPixel<TPixel>();
float thresholdLimit = this.definition.ThresholdLimit;
int startY = intersect.Y;
int endY = intersect.Bottom;
int startX = intersect.X;
int endX = intersect.Right;
int width = intersect.Width;
int height = intersect.Height;
// ClusterSize defines the size of cluster to used to check for average. Tweaked to support up to 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1'
byte clusterSize = (byte)Math.Truncate((width / 16f) - 1);
// Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data.
using (Buffer2D<ulong> intImage = this.Configuration.MemoryAllocator.Allocate2D<ulong>(width, height))
{
Rgba32 rgb = default;
for (int x = startX; x < endX; x++)
{
ulong sum = 0;
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
ref TPixel rowRef = ref MemoryMarshal.GetReference(row);
ref TPixel color = ref Unsafe.Add(ref rowRef, x);
color.ToRgba32(ref rgb);
sum += (ulong)(rgb.R + rgb.G + rgb.G);
if (x - startX != 0)
{
intImage[x - startX, y - startY] = intImage[x - startX - 1, y - startY] + sum;
}
else
{
intImage[x - startX, y - startY] = sum;
}
}
}
var operation = new RowOperation(intersect, source, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY);
ParallelRowIterator.IterateRows(
configuration,
intersect,
in operation);
}
}
private readonly struct RowOperation : IRowOperation
{
private readonly Rectangle bounds;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<ulong> intImage;
private readonly TPixel upper;
private readonly TPixel lower;
private readonly float thresholdLimit;
private readonly int startX;
private readonly int endX;
private readonly int startY;
private readonly byte clusterSize;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
Rectangle bounds,
ImageFrame<TPixel> source,
Buffer2D<ulong> intImage,
TPixel upper,
TPixel lower,
float thresholdLimit,
byte clusterSize,
int startX,
int endX,
int startY)
{
this.bounds = bounds;
this.source = source;
this.intImage = intImage;
this.upper = upper;
this.lower = lower;
this.thresholdLimit = thresholdLimit;
this.startX = startX;
this.endX = endX;
this.startY = startY;
this.clusterSize = clusterSize;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Rgba32 rgb = default;
Span<TPixel> pixelRow = this.source.GetPixelRowSpan(y);
for (int x = this.startX; x < this.endX; x++)
{
TPixel pixel = pixelRow[x];
pixel.ToRgba32(ref rgb);
var x1 = Math.Max(x - this.startX - this.clusterSize + 1, 0);
var x2 = Math.Min(x - this.startX + this.clusterSize + 1, this.bounds.Width - 1);
var y1 = Math.Max(y - this.startY - this.clusterSize + 1, 0);
var y2 = Math.Min(y - this.startY + this.clusterSize + 1, this.bounds.Height - 1);
var count = (uint)((x2 - x1) * (y2 - y1));
var sum = (long)Math.Min(this.intImage[x2, y2] - this.intImage[x1, y2] - this.intImage[x2, y1] + this.intImage[x1, y1], long.MaxValue);
if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.thresholdLimit)
{
this.source[x, y] = this.lower;
}
else
{
this.source[x, y] = this.upper;
}
}
}
}
}
}

97
tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs

@ -6,6 +6,7 @@ using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
@ -499,6 +500,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
}
[Theory]
[WithFile(Bit32PalRleTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_Paletted_WithTopLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32PalRleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_Paletted_WithBottomLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32PalRleTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_WithTopRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32PalRleBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_Paletted_WithBottomRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit16PalBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPaletteBottomLeftOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
@ -559,6 +608,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
}
[Theory]
[WithFile(Bit24PalRleTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_WithPaletteTopLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24PalRleTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_WithPaletteTopRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24PalRleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_WithPaletteBottomLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24PalRleBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RLE_WithPaletteBottomRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32PalTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_32Bit<TPixel>(TestImageProvider<TPixel> provider)

127
tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs

@ -0,0 +1,127 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Binarization;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Processing.Binarization
{
public class AdaptiveThresholdTests : BaseImageOperationsExtensionTest
{
[Fact]
public void AdaptiveThreshold_UsesDefaults_Works()
{
// arrange
var expectedThresholdLimit = .85f;
Color expectedUpper = Color.White;
Color expectedLower = Color.Black;
// act
this.operations.AdaptiveThreshold();
// assert
AdaptiveThresholdProcessor p = this.Verify<AdaptiveThresholdProcessor>();
Assert.Equal(expectedThresholdLimit, p.ThresholdLimit);
Assert.Equal(expectedUpper, p.Upper);
Assert.Equal(expectedLower, p.Lower);
}
[Fact]
public void AdaptiveThreshold_SettingThresholdLimit_Works()
{
// arrange
var expectedThresholdLimit = .65f;
// act
this.operations.AdaptiveThreshold(expectedThresholdLimit);
// assert
AdaptiveThresholdProcessor p = this.Verify<AdaptiveThresholdProcessor>();
Assert.Equal(expectedThresholdLimit, p.ThresholdLimit);
Assert.Equal(Color.White, p.Upper);
Assert.Equal(Color.Black, p.Lower);
}
[Fact]
public void AdaptiveThreshold_SettingUpperLowerThresholds_Works()
{
// arrange
Color expectedUpper = Color.HotPink;
Color expectedLower = Color.Yellow;
// act
this.operations.AdaptiveThreshold(expectedUpper, expectedLower);
// assert
AdaptiveThresholdProcessor p = this.Verify<AdaptiveThresholdProcessor>();
Assert.Equal(expectedUpper, p.Upper);
Assert.Equal(expectedLower, p.Lower);
}
[Fact]
public void AdaptiveThreshold_SettingUpperLowerWithThresholdLimit_Works()
{
// arrange
var expectedThresholdLimit = .77f;
Color expectedUpper = Color.HotPink;
Color expectedLower = Color.Yellow;
// act
this.operations.AdaptiveThreshold(expectedUpper, expectedLower, expectedThresholdLimit);
// assert
AdaptiveThresholdProcessor p = this.Verify<AdaptiveThresholdProcessor>();
Assert.Equal(expectedThresholdLimit, p.ThresholdLimit);
Assert.Equal(expectedUpper, p.Upper);
Assert.Equal(expectedLower, p.Lower);
}
[Fact]
public void AdaptiveThreshold_SettingUpperLowerWithThresholdLimit_WithRectangle_Works()
{
// arrange
var expectedThresholdLimit = .77f;
Color expectedUpper = Color.HotPink;
Color expectedLower = Color.Yellow;
// act
this.operations.AdaptiveThreshold(expectedUpper, expectedLower, expectedThresholdLimit, this.rect);
// assert
AdaptiveThresholdProcessor p = this.Verify<AdaptiveThresholdProcessor>(this.rect);
Assert.Equal(expectedThresholdLimit, p.ThresholdLimit);
Assert.Equal(expectedUpper, p.Upper);
Assert.Equal(expectedLower, p.Lower);
}
[Theory]
[WithFile(TestImages.Png.Bradley01, PixelTypes.Rgba32)]
[WithFile(TestImages.Png.Bradley02, PixelTypes.Rgba32)]
public void AdaptiveThreshold_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(img => img.AdaptiveThreshold());
image.DebugSave(provider);
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(TestImages.Png.Bradley02, PixelTypes.Rgba32)]
public void AdaptiveThreshold_WithRectangle_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(img => img.AdaptiveThreshold(Color.White, Color.Black, new Rectangle(60, 90, 200, 30)));
image.DebugSave(provider);
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
}
}

13
tests/ImageSharp.Tests/TestImages.cs

@ -83,6 +83,9 @@ namespace SixLabors.ImageSharp.Tests
public const string Ducky = "Png/ducky.png";
public const string Rainbow = "Png/rainbow.png";
public const string Bradley01 = "Png/Bradley01.png";
public const string Bradley02 = "Png/Bradley02.png";
// Issue 1014: https://github.com/SixLabors/ImageSharp/issues/1014
public const string Issue1014_1 = "Png/issues/Issue_1014_1.png";
public const string Issue1014_2 = "Png/issues/Issue_1014_2.png";
@ -417,6 +420,11 @@ namespace SixLabors.ImageSharp.Tests
public const string Bit24PalBottomLeft = "Tga/targa_24bit_pal.tga";
public const string Bit24PalBottomRight = "Tga/indexed_LR.tga";
public const string Bit24PalRleTopLeft = "Tga/indexed_rle_UL.tga";
public const string Bit24PalRleBottomLeft = "Tga/indexed_rle_LL.tga";
public const string Bit24PalRleTopRight = "Tga/indexed_rle_UR.tga";
public const string Bit24PalRleBottomRight = "Tga/indexed_rle_LR.tga";
public const string Bit32TopLeft = "Tga/rgb_a_UL.tga";
public const string Bit32BottomLeft = "Tga/targa_32bit.tga";
public const string Bit32TopRight = "Tga/rgb_a_UR.tga";
@ -432,6 +440,11 @@ namespace SixLabors.ImageSharp.Tests
public const string Bit32RleBottomRight = "Tga/rgb_a_rle_LR.tga";
public const string Bit32RleBottomLeft = "Tga/targa_32bit_rle.tga";
public const string Bit32PalRleTopLeft = "Tga/indexed_a_rle_UL.tga";
public const string Bit32PalRleBottomLeft = "Tga/indexed_a_rle_LL.tga";
public const string Bit32PalRleTopRight = "Tga/indexed_a_rle_UR.tga";
public const string Bit32PalRleBottomRight = "Tga/indexed_a_rle_LR.tga";
public const string NoAlphaBits16Bit = "Tga/16bit_noalphabits.tga";
public const string NoAlphaBits16BitRle = "Tga/16bit_rle_noalphabits.tga";
public const string NoAlphaBits32Bit = "Tga/32bit_no_alphabits.tga";

2
tests/Images/External

@ -1 +1 @@
Subproject commit fe694a3938bea3565071a96cb1c90c4cbc586ff9
Subproject commit 6fdc6d19b101dc1c00a297d3e92257df60c413d0

3
tests/Images/Input/Png/Bradley01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d7eddc690c9d50fcaca3b0045d225b08c2fb172ceff5eead1d476c4df0354d02
size 25266

3
tests/Images/Input/Png/Bradley02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a73ebf6e35d5336bdf194d5098bcbe0ad240bbd09cd357816aacb1e0e7e6a614
size 26467

3
tests/Images/Input/Tga/indexed_a_rle_LL.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2be79621e93dfdbd3ec9bea5085675719429cb264b1f9bbafa4ab2c9da28f677
size 31665

3
tests/Images/Input/Tga/indexed_a_rle_LR.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:419d28012037d85794d6839fc8bdaa4b830daf8d078b536a655dc65370c15a38
size 31776

3
tests/Images/Input/Tga/indexed_a_rle_UL.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:892b19c5e4da9ba4b96d3458d2ee35e1f64ca65e8f8f8b6eebb284e83a6bceab
size 31765

3
tests/Images/Input/Tga/indexed_a_rle_UR.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:42586d5d45bb922671755d019fe8d5f76c10ab856fcf6521fb7d114fba118c71
size 31666

3
tests/Images/Input/Tga/indexed_rle_LL.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e3dbf4ae9566e00d2165d74f3c17208853954b4c1f1cbc4ebc321fe3adb29676
size 30549

3
tests/Images/Input/Tga/indexed_rle_LR.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:32461dcf64ec2f6ccf6e17a7209c769a5594b8c94a31de7cc693d6abe6ba2081
size 30610

3
tests/Images/Input/Tga/indexed_rle_UL.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:841f05e9f8ecdade8c992b830b9bf5893494f41accb0f0fec30f4692866c1675
size 30640

3
tests/Images/Input/Tga/indexed_rle_UR.tga

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a709594fd475dbe042c16671959bfbc0031e64db8e74375f01c29685d2e384ec
size 30500
Loading…
Cancel
Save