Browse Source

Merge branch 'master' into webp

pull/1552/head
James Jackson-South 5 years ago
committed by GitHub
parent
commit
fd4355ccea
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      .gitattributes
  2. 2
      shared-infrastructure
  3. 4
      src/ImageSharp/ColorSpaces/YCbCr.cs
  4. 26
      src/ImageSharp/Processing/BinaryThresholdColorComponent.cs
  5. 90
      src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs
  6. 36
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
  7. 137
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
  8. 96
      tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs
  9. 92
      tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs
  10. 1
      tests/ImageSharp.Tests/TestImages.cs
  11. 13
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
  12. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png
  13. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png
  14. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.25.png
  15. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.75.png
  16. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png
  17. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png
  18. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.25.png
  19. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.75.png
  20. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png
  21. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png
  22. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.25.png
  23. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.75.png
  24. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png
  25. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png
  26. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.25.png
  27. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.75.png
  28. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png
  29. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png
  30. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.25.png
  31. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.75.png
  32. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png
  33. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png
  34. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.25.png
  35. 3
      tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.75.png
  36. 3
      tests/Images/Input/Png/colors-saturation-lightness.png

35
.gitattributes

@ -2,9 +2,13 @@
# Set default behavior to: # Set default behavior to:
# treat as text and # treat as text and
# normalize to Unix-style line endings # normalize to Unix-style line endings
###############################################################################
* text eol=lf * text eol=lf
###############################################################################
# Set explicit file behavior to: # Set explicit file behavior to:
# treat as text and
# normalize to Unix-style line endings
###############################################################################
*.asm text eol=lf *.asm text eol=lf
*.c text eol=lf *.c text eol=lf
*.clj text eol=lf *.clj text eol=lf
@ -49,19 +53,35 @@
*.txt text eol=lf *.txt text eol=lf
*.vb text eol=lf *.vb text eol=lf
*.yml text eol=lf *.yml text eol=lf
###############################################################################
# Set explicit file behavior to:
# treat as text # treat as text
# normalize to Unix-style line endings and # normalize to Unix-style line endings and
# diff as csharp # diff as csharp
###############################################################################
*.cs text eol=lf diff=csharp *.cs text eol=lf diff=csharp
###############################################################################
# Set explicit file behavior to:
# treat as text
# normalize to Unix-style line endings and
# use a union merge when resoling conflicts # use a union merge when resoling conflicts
###############################################################################
*.csproj text eol=lf merge=union *.csproj text eol=lf merge=union
*.dbproj text eol=lf merge=union *.dbproj text eol=lf merge=union
*.fsproj text eol=lf merge=union *.fsproj text eol=lf merge=union
*.ncrunchproject text eol=lf merge=union *.ncrunchproject text eol=lf merge=union
*.vbproj text eol=lf merge=union *.vbproj text eol=lf merge=union
###############################################################################
# Set explicit file behavior to:
# treat as text
# normalize to Windows-style line endings and # normalize to Windows-style line endings and
# use a union merge when resoling conflicts
###############################################################################
*.sln text eol=crlf merge=union *.sln text eol=crlf merge=union
###############################################################################
# Set explicit file behavior to:
# treat as binary # treat as binary
###############################################################################
*.basis binary *.basis binary
*.bmp binary *.bmp binary
*.dds binary *.dds binary
@ -90,7 +110,10 @@
*.woff2 binary *.woff2 binary
*.xls binary *.xls binary
*.xlsx binary *.xlsx binary
###############################################################################
# Set explicit file behavior to:
# diff as plain text # diff as plain text
###############################################################################
*.doc diff=astextplain *.doc diff=astextplain
*.docx diff=astextplain *.docx diff=astextplain
*.dot diff=astextplain *.dot diff=astextplain
@ -98,12 +121,4 @@
*.pptx diff=astextplain *.pptx diff=astextplain
*.rtf diff=astextplain *.rtf diff=astextplain
*.svg diff=astextplain *.svg diff=astextplain
*.jpg filter=lfs diff=lfs merge=lfs -text *.jpg,*.jpeg,*.bmp,*.gif,*.png,*.tif,*.tiff,*.tga,*.webp filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 9f515595ee8a4c3282fc88113f7f46c676fa3e9d Subproject commit 649bdbe6050722b030d9292d3fc083cd6ffe87ba

4
src/ImageSharp/ColorSpaces/YCbCr.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -100,4 +100,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.Cr.Equals(other.Cr); && this.Cr.Equals(other.Cr);
} }
} }
} }

26
src/ImageSharp/Processing/BinaryThresholdColorComponent.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// The color component to be compared to threshold.
/// </summary>
public enum BinaryThresholdColorComponent : int
{
/// <summary>
/// Luminance color component according to ITU-R Recommendation BT.709.
/// </summary>
Luminance = 0,
/// <summary>
/// HSL saturation color component.
/// </summary>
Saturation = 1,
/// <summary>
/// Maximum of YCbCr chroma value, i.e. Cb and Cr distance from achromatic value.
/// </summary>
MaxChroma = 2,
}
}

90
src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing.Processors.Binarization; using SixLabors.ImageSharp.Processing.Processors.Binarization;
@ -11,20 +11,51 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
public static class BinaryThresholdExtensions public static class BinaryThresholdExtensions
{ {
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold with
/// Luminance as the color component to be compared to threshold.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, BinaryThresholdColorComponent.Luminance));
/// <summary> /// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold. /// Applies binarization to the image splitting the pixels at the given threshold.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param> /// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="colorComponent">The color component to be compared to threshold.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
BinaryThresholdColorComponent colorComponent)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, colorComponent));
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold with
/// Luminance as the color component to be compared to threshold.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold) => public static IImageProcessingContext BinaryThreshold(
source.ApplyProcessor(new BinaryThresholdProcessor(threshold)); this IImageProcessingContext source,
float threshold,
Rectangle rectangle)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, BinaryThresholdColorComponent.Luminance), rectangle);
/// <summary> /// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold. /// Applies binarization to the image splitting the pixels at the given threshold.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param> /// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="colorComponent">The color component to be compared to threshold.</param>
/// <param name="rectangle"> /// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param> /// </param>
@ -32,8 +63,25 @@ namespace SixLabors.ImageSharp.Processing
public static IImageProcessingContext BinaryThreshold( public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source, this IImageProcessingContext source,
float threshold, float threshold,
Rectangle rectangle) => BinaryThresholdColorComponent colorComponent,
source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle); Rectangle rectangle)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, colorComponent), rectangle);
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold with
/// Luminance as the color component to be compared to threshold.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Color upperColor,
Color lowerColor)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, BinaryThresholdColorComponent.Luminance));
/// <summary> /// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold. /// Applies binarization to the image splitting the pixels at the given threshold.
@ -42,13 +90,35 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param> /// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param> /// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param> /// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <param name="colorComponent">The color component to be compared to threshold.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold( public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source, this IImageProcessingContext source,
float threshold, float threshold,
Color upperColor, Color upperColor,
Color lowerColor) => Color lowerColor,
source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor)); BinaryThresholdColorComponent colorComponent)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, colorComponent));
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold with
/// Luminance as the color component to be compared to threshold.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Color upperColor,
Color lowerColor,
Rectangle rectangle)
=> source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, BinaryThresholdColorComponent.Luminance), rectangle);
/// <summary> /// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold. /// Applies binarization to the image splitting the pixels at the given threshold.
@ -57,6 +127,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param> /// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param> /// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param> /// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <param name="colorComponent">The color component to be compared to threshold.</param>
/// <param name="rectangle"> /// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param> /// </param>
@ -66,7 +137,8 @@ namespace SixLabors.ImageSharp.Processing
float threshold, float threshold,
Color upperColor, Color upperColor,
Color lowerColor, Color lowerColor,
BinaryThresholdColorComponent colorComponent,
Rectangle rectangle) => Rectangle rectangle) =>
source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor), rectangle); source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, colorComponent), rectangle);
} }
} }

36
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs

@ -14,8 +14,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor"/> class. /// Initializes a new instance of the <see cref="BinaryThresholdProcessor"/> class.
/// </summary> /// </summary>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param> /// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
/// <param name="colorComponent">The color component to be compared to threshold.</param>
public BinaryThresholdProcessor(float threshold, BinaryThresholdColorComponent colorComponent)
: this(threshold, Color.White, Color.Black, colorComponent)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor"/> class with
/// Luminance as color component to be compared to threshold.
/// </summary>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
public BinaryThresholdProcessor(float threshold) public BinaryThresholdProcessor(float threshold)
: this(threshold, Color.White, Color.Black) : this(threshold, Color.White, Color.Black, BinaryThresholdColorComponent.Luminance)
{ {
} }
@ -25,12 +36,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param> /// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param> /// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold.</param> /// <param name="lowerColor">The color to use for pixels that are below the threshold.</param>
public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor) /// <param name="colorComponent">The color component to be compared to threshold.</param>
public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor, BinaryThresholdColorComponent colorComponent)
{ {
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold)); Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold));
this.Threshold = threshold; this.Threshold = threshold;
this.UpperColor = upperColor; this.UpperColor = upperColor;
this.LowerColor = lowerColor; this.LowerColor = lowerColor;
this.ColorComponent = colorComponent;
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor"/> class with
/// Luminance as color component to be compared to threshold.
/// </summary>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold.</param>
public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor)
: this(threshold, upperColor, lowerColor, BinaryThresholdColorComponent.Luminance)
{
} }
/// <summary> /// <summary>
@ -48,7 +73,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// </summary> /// </summary>
public Color LowerColor { get; } public Color LowerColor { get; }
/// <inheritdoc /> /// <summary>
/// Gets a value indicating whether to use saturation value instead of luminance.
/// </summary>
public BinaryThresholdColorComponent ColorComponent { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle) public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> new BinaryThresholdProcessor<TPixel>(configuration, this, source, sourceRectangle); => new BinaryThresholdProcessor<TPixel>(configuration, this, source, sourceRectangle);

137
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs

@ -3,7 +3,6 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -27,9 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param> /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
public BinaryThresholdProcessor(Configuration configuration, BinaryThresholdProcessor definition, Image<TPixel> source, Rectangle sourceRectangle) public BinaryThresholdProcessor(Configuration configuration, BinaryThresholdProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle) : base(configuration, source, sourceRectangle)
{ => this.definition = definition;
this.definition = definition;
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source) protected override void OnFrameApply(ImageFrame<TPixel> source)
@ -42,10 +39,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
Configuration configuration = this.Configuration; Configuration configuration = this.Configuration;
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
bool isAlphaOnly = typeof(TPixel) == typeof(A8); var operation = new RowOperation(
interest.X,
source,
upper,
lower,
threshold,
this.definition.ColorComponent,
configuration);
var operation = new RowOperation(interest, source, upper, lower, threshold, isAlphaOnly); ParallelRowIterator.IterateRows<RowOperation, Rgb24>(
ParallelRowIterator.IterateRows(
configuration, configuration,
interest, interest,
in operation); in operation);
@ -54,51 +57,131 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the clone logic for <see cref="BinaryThresholdProcessor{TPixel}"/>. /// A <see langword="struct"/> implementing the clone logic for <see cref="BinaryThresholdProcessor{TPixel}"/>.
/// </summary> /// </summary>
private readonly struct RowOperation : IRowOperation private readonly struct RowOperation : IRowOperation<Rgb24>
{ {
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
private readonly TPixel upper; private readonly TPixel upper;
private readonly TPixel lower; private readonly TPixel lower;
private readonly byte threshold; private readonly byte threshold;
private readonly int minX; private readonly BinaryThresholdColorComponent colorComponent;
private readonly int maxX; private readonly int startX;
private readonly bool isAlphaOnly; private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowOperation( public RowOperation(
Rectangle bounds, int startX,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
TPixel upper, TPixel upper,
TPixel lower, TPixel lower,
byte threshold, byte threshold,
bool isAlphaOnly) BinaryThresholdColorComponent colorComponent,
Configuration configuration)
{ {
this.startX = startX;
this.source = source; this.source = source;
this.upper = upper; this.upper = upper;
this.lower = lower; this.lower = lower;
this.threshold = threshold; this.threshold = threshold;
this.minX = bounds.X; this.colorComponent = colorComponent;
this.maxX = bounds.Right; this.configuration = configuration;
this.isAlphaOnly = isAlphaOnly;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Invoke(int y) public void Invoke(int y, Span<Rgb24> span)
{
TPixel upper = this.upper;
TPixel lower = this.lower;
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToRgb24(this.configuration, rowSpan, span);
switch (this.colorComponent)
{
case BinaryThresholdColorComponent.Luminance:
{
byte threshold = this.threshold;
for (int x = 0; x < rowSpan.Length; x++)
{
Rgb24 rgb = span[x];
byte luminance = ColorNumerics.Get8BitBT709Luminance(rgb.R, rgb.G, rgb.B);
ref TPixel color = ref rowSpan[x];
color = luminance >= threshold ? upper : lower;
}
break;
}
case BinaryThresholdColorComponent.Saturation:
{
float threshold = this.threshold / 255F;
for (int x = 0; x < rowSpan.Length; x++)
{
float saturation = GetSaturation(span[x]);
ref TPixel color = ref rowSpan[x];
color = saturation >= threshold ? upper : lower;
}
break;
}
case BinaryThresholdColorComponent.MaxChroma:
{
float threshold = this.threshold / 2F;
for (int x = 0; x < rowSpan.Length; x++)
{
float chroma = GetMaxChroma(span[x]);
ref TPixel color = ref rowSpan[x];
color = chroma >= threshold ? upper : lower;
}
break;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float GetSaturation(Rgb24 rgb)
{ {
Rgba32 rgba = default; // Slimmed down RGB => HSL formula. See HslAndRgbConverter.
Span<TPixel> row = this.source.GetPixelRowSpan(y); float r = rgb.R / 255F;
ref TPixel rowRef = ref MemoryMarshal.GetReference(row); float g = rgb.G / 255F;
float b = rgb.B / 255F;
for (int x = this.minX; x < this.maxX; x++) float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
if (MathF.Abs(chroma) < Constants.Epsilon)
{ {
ref TPixel color = ref Unsafe.Add(ref rowRef, x); return 0F;
color.ToRgba32(ref rgba); }
// Convert to grayscale using ITU-R Recommendation BT.709 if required float l = (max + min) / 2F;
byte luminance = this.isAlphaOnly ? rgba.A : ColorNumerics.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
color = luminance >= this.threshold ? this.upper : this.lower; if (l <= .5F)
{
return chroma / (max + min);
} }
else
{
return chroma / (2F - max - min);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float GetMaxChroma(Rgb24 rgb)
{
// Slimmed down RGB => YCbCr formula. See YCbCrAndRgbConverter.
float r = rgb.R;
float g = rgb.G;
float b = rgb.B;
const float achromatic = 127.5F;
float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b));
float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b));
return MathF.Max(MathF.Abs(cb - achromatic), MathF.Abs(cr - achromatic));
} }
} }
} }

96
tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
@ -16,6 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
this.operations.BinaryThreshold(.23f); this.operations.BinaryThreshold(.23f);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(); BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>();
Assert.Equal(.23f, p.Threshold); Assert.Equal(.23f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor); Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor); Assert.Equal(Color.Black, p.LowerColor);
} }
@ -26,6 +27,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
this.operations.BinaryThreshold(.93f, this.rect); this.operations.BinaryThreshold(.93f, this.rect);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect); BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect);
Assert.Equal(.93f, p.Threshold); Assert.Equal(.93f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor); Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor); Assert.Equal(Color.Black, p.LowerColor);
} }
@ -36,6 +38,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
this.operations.BinaryThreshold(.23f, Color.HotPink, Color.Yellow); this.operations.BinaryThreshold(.23f, Color.HotPink, Color.Yellow);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(); BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>();
Assert.Equal(.23f, p.Threshold); Assert.Equal(.23f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(Color.HotPink, p.UpperColor); Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor); Assert.Equal(Color.Yellow, p.LowerColor);
} }
@ -45,9 +48,98 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
{ {
this.operations.BinaryThreshold(.93f, Color.HotPink, Color.Yellow, this.rect); this.operations.BinaryThreshold(.93f, Color.HotPink, Color.Yellow, this.rect);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect); BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect);
Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(.93f, p.Threshold); Assert.Equal(.93f, p.Threshold);
Assert.Equal(Color.HotPink, p.UpperColor); Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor); Assert.Equal(Color.Yellow, p.LowerColor);
} }
[Fact]
public void BinarySaturationThreshold_CorrectProcessor()
{
this.operations.BinaryThreshold(.23f, BinaryThresholdColorComponent.Saturation);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>();
Assert.Equal(.23f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Saturation, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor);
}
[Fact]
public void BinarySaturationThreshold_rect_CorrectProcessor()
{
this.operations.BinaryThreshold(.93f, BinaryThresholdColorComponent.Saturation, this.rect);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect);
Assert.Equal(.93f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Saturation, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor);
}
[Fact]
public void BinarySaturationThreshold_CorrectProcessorWithUpperLower()
{
this.operations.BinaryThreshold(.23f, Color.HotPink, Color.Yellow, BinaryThresholdColorComponent.Saturation);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>();
Assert.Equal(.23f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Saturation, p.ColorComponent);
Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor);
}
[Fact]
public void BinarySaturationThreshold_rect_CorrectProcessorWithUpperLower()
{
this.operations.BinaryThreshold(.93f, Color.HotPink, Color.Yellow, BinaryThresholdColorComponent.Saturation, this.rect);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect);
Assert.Equal(.93f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.Saturation, p.ColorComponent);
Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor);
}
[Fact]
public void BinaryMaxChromaThreshold_CorrectProcessor()
{
this.operations.BinaryThreshold(.23f, BinaryThresholdColorComponent.MaxChroma);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>();
Assert.Equal(.23f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.MaxChroma, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor);
}
[Fact]
public void BinaryMaxChromaThreshold_rect_CorrectProcessor()
{
this.operations.BinaryThreshold(.93f, BinaryThresholdColorComponent.MaxChroma, this.rect);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect);
Assert.Equal(.93f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.MaxChroma, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor);
}
[Fact]
public void BinaryMaxChromaThreshold_CorrectProcessorWithUpperLower()
{
this.operations.BinaryThreshold(.23f, Color.HotPink, Color.Yellow, BinaryThresholdColorComponent.MaxChroma);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>();
Assert.Equal(.23f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.MaxChroma, p.ColorComponent);
Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor);
}
[Fact]
public void BinaryMaxChromaThreshold_rect_CorrectProcessorWithUpperLower()
{
this.operations.BinaryThreshold(.93f, Color.HotPink, Color.Yellow, BinaryThresholdColorComponent.MaxChroma, this.rect);
BinaryThresholdProcessor p = this.Verify<BinaryThresholdProcessor>(this.rect);
Assert.Equal(.93f, p.Threshold);
Assert.Equal(BinaryThresholdColorComponent.MaxChroma, p.ColorComponent);
Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor);
}
} }
} }

92
tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs

@ -1,14 +1,15 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Globalization;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Binarization;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
{ {
using SixLabors.ImageSharp.Processing;
public class BinaryThresholdTest public class BinaryThresholdTest
{ {
public static readonly TheoryData<float> BinaryThresholdValues public static readonly TheoryData<float> BinaryThresholdValues
@ -19,9 +20,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
}; };
public static readonly string[] CommonTestImages = public static readonly string[] CommonTestImages =
{ {
TestImages.Png.CalliphoraPartial, TestImages.Png.Bike TestImages.Png.Rgb48Bpp,
}; TestImages.Png.ColorsSaturationLightness,
};
public const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24; public const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24;
@ -43,9 +45,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> source = provider.GetImage()) using (Image<TPixel> source = provider.GetImage())
using (var image = source.Clone()) using (Image<TPixel> image = source.Clone())
{ {
var bounds = new Rectangle(10, 10, image.Width / 2, image.Height / 2); var bounds = new Rectangle(image.Width / 8, image.Height / 8, 6 * image.Width / 8, 6 * image.Width / 8);
image.Mutate(x => x.BinaryThreshold(value, bounds)); image.Mutate(x => x.BinaryThreshold(value, bounds));
image.DebugSave(provider, value); image.DebugSave(provider, value);
@ -53,5 +55,81 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
ImageComparer.Tolerant().VerifySimilarityIgnoreRegion(source, image, bounds); ImageComparer.Tolerant().VerifySimilarityIgnoreRegion(source, image, bounds);
} }
} }
[Theory]
[WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
public void ImageShouldApplyBinarySaturationThresholdFilter<TPixel>(TestImageProvider<TPixel> provider, float value)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.Saturation));
image.DebugSave(provider, value);
image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo));
}
}
[Theory]
[WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
public void ImageShouldApplyBinarySaturationThresholdInBox<TPixel>(TestImageProvider<TPixel> provider, float value)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> source = provider.GetImage())
using (Image<TPixel> image = source.Clone())
{
var bounds = new Rectangle(image.Width / 8, image.Height / 8, 6 * image.Width / 8, 6 * image.Width / 8);
image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.Saturation, bounds));
image.DebugSave(provider, value);
image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo));
}
}
[Theory]
[WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
public void ImageShouldApplyBinaryMaxChromaThresholdFilter<TPixel>(TestImageProvider<TPixel> provider, float value)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.MaxChroma));
image.DebugSave(provider, value);
if (!TestEnvironment.Is64BitProcess && TestEnvironment.IsFramework)
{
var comparer = ImageComparer.TolerantPercentage(0.0004F);
image.CompareToReferenceOutput(comparer, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo));
}
else
{
image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo));
}
}
}
[Theory]
[WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
public void ImageShouldApplyBinaryMaxChromaThresholdInBox<TPixel>(TestImageProvider<TPixel> provider, float value)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> source = provider.GetImage())
using (Image<TPixel> image = source.Clone())
{
var bounds = new Rectangle(image.Width / 8, image.Height / 8, 6 * image.Width / 8, 6 * image.Width / 8);
image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.MaxChroma, bounds));
image.DebugSave(provider, value);
if (!TestEnvironment.Is64BitProcess && TestEnvironment.IsFramework)
{
var comparer = ImageComparer.TolerantPercentage(0.0004F);
image.CompareToReferenceOutput(comparer, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo));
}
else
{
image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo));
}
}
}
} }
} }

1
tests/ImageSharp.Tests/TestImages.cs

@ -40,6 +40,7 @@ namespace SixLabors.ImageSharp.Tests
public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png"; public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png";
public const string Rgb48BppTrans = "Png/rgb-16-tRNS.png"; public const string Rgb48BppTrans = "Png/rgb-16-tRNS.png";
public const string Rgba64Bpp = "Png/rgb-16-alpha.png"; public const string Rgba64Bpp = "Png/rgb-16-alpha.png";
public const string ColorsSaturationLightness = "Png/colors-saturation-lightness.png";
public const string CalliphoraPartial = "Png/CalliphoraPartial.png"; public const string CalliphoraPartial = "Png/CalliphoraPartial.png";
public const string CalliphoraPartialGrayscale = "Png/CalliphoraPartialGrayscale.png"; public const string CalliphoraPartialGrayscale = "Png/CalliphoraPartialGrayscale.png";
public const string Bike = "Png/Bike.png"; public const string Bike = "Png/Bike.png";

13
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs

@ -7,7 +7,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Tests namespace SixLabors.ImageSharp.Tests
{ {
@ -25,19 +24,11 @@ namespace SixLabors.ImageSharp.Tests
private static readonly Lazy<string> SolutionDirectoryFullPathLazy = new Lazy<string>(GetSolutionDirectoryFullPathImpl); private static readonly Lazy<string> SolutionDirectoryFullPathLazy = new Lazy<string>(GetSolutionDirectoryFullPathImpl);
private static readonly Lazy<bool> RunsOnCiLazy = new Lazy<bool>( private static readonly Lazy<bool> RunsOnCiLazy = new Lazy<bool>(() => bool.TryParse(Environment.GetEnvironmentVariable("CI"), out bool isCi) && isCi);
() =>
{
bool isCi;
return bool.TryParse(Environment.GetEnvironmentVariable("CI"), out isCi) && isCi;
});
private static readonly Lazy<string> NetCoreVersionLazy = new Lazy<string>(GetNetCoreVersion); private static readonly Lazy<string> NetCoreVersionLazy = new Lazy<string>(GetNetCoreVersion);
static TestEnvironment() static TestEnvironment() => PrepareRemoteExecutor();
{
PrepareRemoteExecutor();
}
/// <summary> /// <summary>
/// Gets the .NET Core version, if running on .NET Core, otherwise returns an empty string. /// Gets the .NET Core version, if running on .NET Core, otherwise returns an empty string.

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.25.png

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

3
tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.75.png

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

3
tests/Images/Input/Png/colors-saturation-lightness.png

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