diff --git a/.gitattributes b/.gitattributes
index 7c648c077..01a3825f8 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,9 +2,14 @@
# Set default behavior to:
# treat as text and
# normalize to Unix-style line endings
+###############################################################################
* text eol=lf
+###############################################################################
# Set explicit file behavior to:
+# treat as text and
+# normalize to Unix-style line endings
+###############################################################################
*.asm text eol=lf
*.c text eol=lf
*.clj text eol=lf
@@ -49,19 +54,39 @@
*.txt text eol=lf
*.vb text eol=lf
*.yml text eol=lf
+
+###############################################################################
+# Set explicit file behavior to:
# treat as text
# normalize to Unix-style line endings and
# diff as 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
+###############################################################################
*.csproj text eol=lf merge=union
*.dbproj text eol=lf merge=union
*.fsproj text eol=lf merge=union
*.ncrunchproject 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
+# use a union merge when resoling conflicts
+###############################################################################
*.sln text eol=crlf merge=union
+
+###############################################################################
+# Set explicit file behavior to:
# treat as binary
+###############################################################################
*.basis binary
*.bmp binary
*.dds binary
@@ -90,7 +115,11 @@
*.woff2 binary
*.xls binary
*.xlsx binary
+
+###############################################################################
+# Set explicit file behavior to:
# diff as plain text
+###############################################################################
*.doc diff=astextplain
*.docx diff=astextplain
*.dot diff=astextplain
@@ -98,12 +127,3 @@
*.pptx diff=astextplain
*.rtf diff=astextplain
*.svg diff=astextplain
-*.jpg 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
diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs
index eaaf7f58f..49c5e57ed 100644
--- a/src/ImageSharp/ColorSpaces/YCbCr.cs
+++ b/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.
using System;
@@ -17,6 +17,11 @@ namespace SixLabors.ImageSharp.ColorSpaces
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new Vector3(255);
+ ///
+ /// The medium luminance achromatic color.
+ ///
+ public static readonly YCbCr Achromatic = new YCbCr(127.5F, 127.5F, 127.5F);
+
///
/// Gets the Y luminance component.
/// A value ranging between 0 and 255.
@@ -100,4 +105,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.Cr.Equals(other.Cr);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs
index d21429589..375c787db 100644
--- a/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs
+++ b/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.
using SixLabors.ImageSharp.Processing.Processors.Binarization;
@@ -16,15 +16,44 @@ namespace SixLabors.ImageSharp.Processing
///
/// The image this method extends.
/// The threshold to apply binarization of the image. Must be between 0 and 1.
+ /// The color component to be compared to threshold.
+ /// The to allow chaining of operations.
+ public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold, BinaryThresholdColorComponent colorComponent) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, colorComponent));
+
+ ///
+ /// Applies binarization to the image splitting the pixels at the given threshold with
+ /// Luminance as color component to be compared to threshold.
+ ///
+ /// The image this method extends.
+ /// The threshold to apply binarization of the image. Must be between 0 and 1.
/// The to allow chaining of operations.
public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold));
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, BinaryThresholdColorComponent.Luminance));
///
/// Applies binarization to the image splitting the pixels at the given threshold.
///
/// The image this method extends.
/// The threshold to apply binarization of the image. Must be between 0 and 1.
+ /// The color component to be compared to threshold.
+ ///
+ /// The structure that specifies the portion of the image object to alter.
+ ///
+ /// The to allow chaining of operations.
+ public static IImageProcessingContext BinaryThreshold(
+ this IImageProcessingContext source,
+ float threshold,
+ BinaryThresholdColorComponent colorComponent,
+ Rectangle rectangle) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, colorComponent), rectangle);
+
+ ///
+ /// Applies binarization to the image splitting the pixels at the given threshold with
+ /// Luminance as color component to be compared to threshold.
+ ///
+ /// The image this method extends.
+ /// The threshold to apply binarization of the image. Must be between 0 and 1.
///
/// The structure that specifies the portion of the image object to alter.
///
@@ -33,7 +62,7 @@ namespace SixLabors.ImageSharp.Processing
this IImageProcessingContext source,
float threshold,
Rectangle rectangle) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle);
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, BinaryThresholdColorComponent.Luminance), rectangle);
///
/// Applies binarization to the image splitting the pixels at the given threshold.
@@ -42,21 +71,61 @@ namespace SixLabors.ImageSharp.Processing
/// The threshold to apply binarization of the image. Must be between 0 and 1.
/// The color to use for pixels that are above the threshold.
/// The color to use for pixels that are below the threshold
+ /// The color component to be compared to threshold.
+ /// The to allow chaining of operations.
+ public static IImageProcessingContext BinaryThreshold(
+ this IImageProcessingContext source,
+ float threshold,
+ Color upperColor,
+ Color lowerColor,
+ BinaryThresholdColorComponent colorComponent) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, colorComponent));
+
+ ///
+ /// Applies binarization to the image splitting the pixels at the given threshold with
+ /// Luminance as color component to be compared to threshold.
+ ///
+ /// The image this method extends.
+ /// The threshold to apply binarization of the image. Must be between 0 and 1.
+ /// The color to use for pixels that are above the threshold.
+ /// The color to use for pixels that are below the threshold
/// The to allow chaining of operations.
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Color upperColor,
Color lowerColor) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor));
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, BinaryThresholdColorComponent.Luminance));
- ///
+ ///
/// Applies binarization to the image splitting the pixels at the given threshold.
///
/// The image this method extends.
/// The threshold to apply binarization of the image. Must be between 0 and 1.
/// The color to use for pixels that are above the threshold.
/// The color to use for pixels that are below the threshold
+ /// The color component to be compared to threshold.
+ ///
+ /// The structure that specifies the portion of the image object to alter.
+ ///
+ /// The to allow chaining of operations.
+ public static IImageProcessingContext BinaryThreshold(
+ this IImageProcessingContext source,
+ float threshold,
+ Color upperColor,
+ Color lowerColor,
+ BinaryThresholdColorComponent colorComponent,
+ Rectangle rectangle) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, colorComponent), rectangle);
+
+ ///
+ /// Applies binarization to the image splitting the pixels at the given threshold with
+ /// Luminance as color component to be compared to threshold.
+ ///
+ /// The image this method extends.
+ /// The threshold to apply binarization of the image. Must be between 0 and 1.
+ /// The color to use for pixels that are above the threshold.
+ /// The color to use for pixels that are below the threshold
///
/// The structure that specifies the portion of the image object to alter.
///
@@ -67,6 +136,6 @@ namespace SixLabors.ImageSharp.Processing
Color upperColor,
Color lowerColor,
Rectangle rectangle) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor), rectangle);
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, BinaryThresholdColorComponent.Luminance), rectangle);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
index 460a82f0a..992852499 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
@@ -5,6 +5,27 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
+ ///
+ /// The color component to be compared to threshold.
+ ///
+ public enum BinaryThresholdColorComponent : int
+ {
+ ///
+ /// Luminance color component according to ITU-R Recommendation BT.709.
+ ///
+ Luminance = 0,
+
+ ///
+ /// HSL saturation color component.
+ ///
+ Saturation = 1,
+
+ ///
+ /// Maximum of YCbCr chroma value, i.e. Cb and Cr distance from achromatic value.
+ ///
+ MaxChroma = 2,
+ }
+
///
/// Performs simple binary threshold filtering against an image.
///
@@ -14,8 +35,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// Initializes a new instance of the class.
///
/// The threshold to split the image. Must be between 0 and 1.
+ /// The color component to be compared to threshold.
+ public BinaryThresholdProcessor(float threshold, BinaryThresholdColorComponent colorComponent)
+ : this(threshold, Color.White, Color.Black, colorComponent)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with
+ /// Luminance as color component to be compared to threshold.
+ ///
+ /// The threshold to split the image. Must be between 0 and 1.
public BinaryThresholdProcessor(float threshold)
- : this(threshold, Color.White, Color.Black)
+ : this(threshold, Color.White, Color.Black, BinaryThresholdColorComponent.Luminance)
{
}
@@ -25,12 +57,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// The threshold to split the image. Must be between 0 and 1.
/// The color to use for pixels that are above the threshold.
/// The color to use for pixels that are below the threshold.
- public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor)
+ /// The color component to be compared to threshold.
+ public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor, BinaryThresholdColorComponent colorComponent)
{
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold));
this.Threshold = threshold;
this.UpperColor = upperColor;
this.LowerColor = lowerColor;
+ this.ColorComponent = colorComponent;
+ }
+
+ ///
+ /// Initializes a new instance of the class with
+ /// Luminance as color component to be compared to threshold.
+ ///
+ /// The threshold to split the image. Must be between 0 and 1.
+ /// The color to use for pixels that are above the threshold.
+ /// The color to use for pixels that are below the threshold.
+ public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor)
+ : this(threshold, upperColor, lowerColor, BinaryThresholdColorComponent.Luminance)
+ {
}
///
@@ -48,7 +94,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
///
public Color LowerColor { get; }
- ///
+ ///
+ /// Gets a value indicating whether to use saturation value instead of luminance.
+ ///
+ public BinaryThresholdColorComponent ColorComponent { get; }
+
+ ///
public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle)
where TPixel : unmanaged, IPixel
=> new BinaryThresholdProcessor(configuration, this, source, sourceRectangle);
diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
index df95b6f1b..b33098e57 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
@@ -5,6 +5,8 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.ColorSpaces;
+using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
@@ -44,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
bool isAlphaOnly = typeof(TPixel) == typeof(A8);
- var operation = new RowOperation(interest, source, upper, lower, threshold, isAlphaOnly);
+ var operation = new RowOperation(interest, source, upper, lower, threshold, this.definition.ColorComponent, isAlphaOnly);
ParallelRowIterator.IterateRows(
configuration,
interest,
@@ -60,9 +62,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
private readonly TPixel upper;
private readonly TPixel lower;
private readonly byte threshold;
+ private readonly BinaryThresholdColorComponent colorComponent;
private readonly int minX;
private readonly int maxX;
private readonly bool isAlphaOnly;
+ private readonly ColorSpaceConverter colorSpaceConverter;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
@@ -71,15 +75,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
TPixel upper,
TPixel lower,
byte threshold,
+ BinaryThresholdColorComponent colorComponent,
bool isAlphaOnly)
{
this.source = source;
this.upper = upper;
this.lower = lower;
this.threshold = threshold;
+ this.colorComponent = colorComponent;
this.minX = bounds.X;
this.maxX = bounds.Right;
this.isAlphaOnly = isAlphaOnly;
+ this.colorSpaceConverter = new ColorSpaceConverter();
}
///
@@ -90,14 +97,55 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
Span row = this.source.GetPixelRowSpan(y);
ref TPixel rowRef = ref MemoryMarshal.GetReference(row);
- for (int x = this.minX; x < this.maxX; x++)
+ if (this.colorComponent == BinaryThresholdColorComponent.Luminance)
{
- ref TPixel color = ref Unsafe.Add(ref rowRef, x);
- color.ToRgba32(ref rgba);
+ for (int x = this.minX; x < this.maxX; x++)
+ {
+ ref TPixel color = ref Unsafe.Add(ref rowRef, x);
+ color.ToRgba32(ref rgba);
- // Convert to grayscale using ITU-R Recommendation BT.709 if required
- byte luminance = this.isAlphaOnly ? rgba.A : ColorNumerics.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
- color = luminance >= this.threshold ? this.upper : this.lower;
+ // Convert to grayscale using ITU-R Recommendation BT.709 if required
+ byte luminance = this.isAlphaOnly ? rgba.A : ColorNumerics.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
+ color = luminance >= this.threshold ? this.upper : this.lower;
+ }
+ }
+ else if (this.colorComponent == BinaryThresholdColorComponent.Saturation)
+ {
+ float fThreshold = this.threshold / 255F;
+
+ for (int x = this.minX; x < this.maxX; x++)
+ {
+ ref TPixel color = ref Unsafe.Add(ref rowRef, x);
+ color.ToRgba32(ref rgba);
+
+ // Extract saturation and compare to threshold.
+ float sat = this.colorSpaceConverter.ToHsl(rgba).S;
+ color = (sat >= fThreshold) ? this.upper : this.lower;
+ }
+ }
+ else if (this.colorComponent == BinaryThresholdColorComponent.MaxChroma)
+ {
+ float fThreshold = this.threshold / 2F;
+ for (int x = this.minX; x < this.maxX; x++)
+ {
+ ref TPixel color = ref Unsafe.Add(ref rowRef, x);
+ color.ToRgba32(ref rgba);
+
+ // Calculate YCbCr value and compare to threshold.
+ var yCbCr = this.colorSpaceConverter.ToYCbCr(rgba);
+ if (MathF.Max(MathF.Abs(yCbCr.Cb - YCbCr.Achromatic.Cb), MathF.Abs(yCbCr.Cr - YCbCr.Achromatic.Cr)) >= fThreshold)
+ {
+ color = this.upper;
+ }
+ else
+ {
+ color = this.lower;
+ }
+ }
+ }
+ else
+ {
+ throw new NotImplementedException("Unknown BinaryThresholdColorComponent value " + this.colorComponent);
}
}
}
diff --git a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs
index 5bdfda02e..a02ca36ee 100644
--- a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs
+++ b/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.
using SixLabors.ImageSharp.Processing;
@@ -16,6 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
this.operations.BinaryThreshold(.23f);
BinaryThresholdProcessor p = this.Verify();
Assert.Equal(.23f, p.Threshold);
+ Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor);
}
@@ -26,6 +27,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
this.operations.BinaryThreshold(.93f, this.rect);
BinaryThresholdProcessor p = this.Verify(this.rect);
Assert.Equal(.93f, p.Threshold);
+ Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(Color.White, p.UpperColor);
Assert.Equal(Color.Black, p.LowerColor);
}
@@ -36,6 +38,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization
this.operations.BinaryThreshold(.23f, Color.HotPink, Color.Yellow);
BinaryThresholdProcessor p = this.Verify();
Assert.Equal(.23f, p.Threshold);
+ Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(Color.HotPink, p.UpperColor);
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);
BinaryThresholdProcessor p = this.Verify(this.rect);
+ Assert.Equal(BinaryThresholdColorComponent.Luminance, p.ColorComponent);
Assert.Equal(.93f, p.Threshold);
Assert.Equal(Color.HotPink, p.UpperColor);
Assert.Equal(Color.Yellow, p.LowerColor);
}
+
+ [Fact]
+ public void BinarySaturationThreshold_CorrectProcessor()
+ {
+ this.operations.BinaryThreshold(.23f, BinaryThresholdColorComponent.Saturation);
+ BinaryThresholdProcessor p = this.Verify();
+ 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(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();
+ 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(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();
+ 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(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();
+ 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(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);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs
index c5b7808cc..2a0696356 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs
@@ -2,13 +2,13 @@
// 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.Processors.Binarization
{
- using SixLabors.ImageSharp.Processing;
-
public class BinaryThresholdTest
{
public static readonly TheoryData BinaryThresholdValues
@@ -19,9 +19,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
};
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;
@@ -43,9 +44,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
where TPixel : unmanaged, IPixel
{
using (Image source = provider.GetImage())
- using (var image = source.Clone())
+ using (Image 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.DebugSave(provider, value);
@@ -53,5 +54,63 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization
ImageComparer.Tolerant().VerifySimilarityIgnoreRegion(source, image, bounds);
}
}
+
+ [Theory]
+ [WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
+ public void ImageShouldApplyBinarySaturationThresholdFilter(TestImageProvider provider, float value)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image image = provider.GetImage())
+ {
+ image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.Saturation));
+ image.DebugSave(provider, value);
+ image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", System.Globalization.NumberFormatInfo.InvariantInfo));
+ }
+ }
+
+ [Theory]
+ [WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
+ public void ImageShouldApplyBinarySaturationThresholdInBox(TestImageProvider provider, float value)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image source = provider.GetImage())
+ using (Image 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", System.Globalization.NumberFormatInfo.InvariantInfo));
+ }
+ }
+
+ [Theory]
+ [WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
+ public void ImageShouldApplyBinaryMaxChromaThresholdFilter(TestImageProvider provider, float value)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image image = provider.GetImage())
+ {
+ image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.MaxChroma));
+ image.DebugSave(provider, value);
+ image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", System.Globalization.NumberFormatInfo.InvariantInfo));
+ }
+ }
+
+ [Theory]
+ [WithFileCollection(nameof(CommonTestImages), nameof(BinaryThresholdValues), PixelTypes.Rgba32)]
+ public void ImageShouldApplyBinaryMaxChromaThresholdInBox(TestImageProvider provider, float value)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image source = provider.GetImage())
+ using (Image 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);
+ image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", System.Globalization.NumberFormatInfo.InvariantInfo));
+ }
+ }
}
}
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index ac9d6422a..c15327e0d 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/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 Rgb48BppTrans = "Png/rgb-16-tRNS.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 CalliphoraPartialGrayscale = "Png/CalliphoraPartialGrayscale.png";
public const string Bike = "Png/Bike.png";
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png
new file mode 100644
index 000000000..0cf2d9b99
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png
new file mode 100644
index 000000000..029ec4c31
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.25.png
new file mode 100644
index 000000000..48e24d0c5
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.75.png
new file mode 100644
index 000000000..00f971df4
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdFilter_Rgba32_rgb-48bpp_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png
new file mode 100644
index 000000000..8be07a4bb
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png
new file mode 100644
index 000000000..88029f1e1
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.25.png
new file mode 100644
index 000000000..05ead8ee1
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.75.png
new file mode 100644
index 000000000..b9d36892e
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryMaxChromaThresholdInBox_Rgba32_rgb-48bpp_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png
new file mode 100644
index 000000000..241a312ba
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png
new file mode 100644
index 000000000..9ab0bd25c
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.25.png
new file mode 100644
index 000000000..c162e16ed
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.75.png
new file mode 100644
index 000000000..c09359c88
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdFilter_Rgba32_rgb-48bpp_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png
new file mode 100644
index 000000000..e5b136185
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png
new file mode 100644
index 000000000..036dda663
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.25.png
new file mode 100644
index 000000000..fb58f606d
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.75.png
new file mode 100644
index 000000000..a06aa0d6e
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinarySaturationThresholdInBox_Rgba32_rgb-48bpp_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png
new file mode 100644
index 000000000..726786111
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png
new file mode 100644
index 000000000..a5286f956
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_colors-saturation-lightness_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.25.png
new file mode 100644
index 000000000..ee5f95451
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.75.png
new file mode 100644
index 000000000..0d528245e
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdFilter_Rgba32_rgb-48bpp_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png
new file mode 100644
index 000000000..1dbf895df
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png
new file mode 100644
index 000000000..7e4300a2e
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_colors-saturation-lightness_0.75.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.25.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.25.png
new file mode 100644
index 000000000..6a4568ea7
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.25.png differ
diff --git a/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.75.png b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.75.png
new file mode 100644
index 000000000..129ee82cc
Binary files /dev/null and b/tests/Images/External/ReferenceOutput/BinaryThresholdTest/ImageShouldApplyBinaryThresholdInBox_Rgba32_rgb-48bpp_0.75.png differ
diff --git a/tests/Images/Input/Png/colors-saturation-lightness.png b/tests/Images/Input/Png/colors-saturation-lightness.png
new file mode 100644
index 000000000..59069002d
Binary files /dev/null and b/tests/Images/Input/Png/colors-saturation-lightness.png differ