.../Binarization/BinaryThresholdExtensions.cs | 35 +++++++++++++++-------
.../Binarization/BinaryThresholdProcessor.cs | 20 ++++++++++---
.../BinaryThresholdProcessor{TPixel}.cs | 22 +++++++++++---
tests/Images/External | 0
4 files changed, 59 insertions(+), 18 deletions(-)
diff --git a/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs
index d21429589..02d5dab41 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,9 +16,12 @@ public static class BinaryThresholdExtensions
///
/// The image this method extends.
/// The threshold to apply binarization of the image. Must be between 0 and 1.
+ ///
+ /// Use saturation value instead of luminance.
+ ///
/// The to allow chaining of operations.
- public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold));
+ public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold, bool useSaturationNotLuminance = false) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, useSaturationNotLuminance));
///
/// Applies binarization to the image splitting the pixels at the given threshold.
@@ -28,12 +31,16 @@ public static class BinaryThresholdExtensions
///
/// The structure that specifies the portion of the image object to alter.
///
+ ///
+ /// Use saturation value instead of luminance.
+ ///
/// The to allow chaining of operations.
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
- Rectangle rectangle) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle);
+ Rectangle rectangle,
+ bool useSaturationNotLuminance = false) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, useSaturationNotLuminance), rectangle);
///
/// Applies binarization to the image splitting the pixels at the given threshold.
@@ -42,13 +49,17 @@ public static class BinaryThresholdExtensions
/// 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
+ ///
+ /// Use saturation value instead of luminance.
+ ///
/// 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));
+ Color lowerColor,
+ bool useSaturationNotLuminance = false) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, useSaturationNotLuminance));
///
/// Applies binarization to the image splitting the pixels at the given threshold.
@@ -60,13 +71,17 @@ public static class BinaryThresholdExtensions
///
/// The structure that specifies the portion of the image object to alter.
///
+ ///
+ /// Use saturation value instead of luminance.
+ ///
/// The to allow chaining of operations.
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Color upperColor,
Color lowerColor,
- Rectangle rectangle) =>
- source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor), rectangle);
+ Rectangle rectangle,
+ bool useSaturationNotLuminance = false) =>
+ source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor, useSaturationNotLuminance), 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..cc61efbf1 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
@@ -14,8 +14,11 @@ public class BinaryThresholdProcessor : IImageProcessor
/// Initializes a new instance of the class.
///
/// The threshold to split the image. Must be between 0 and 1.
- public BinaryThresholdProcessor(float threshold)
- : this(threshold, Color.White, Color.Black)
+ ///
+ /// Use saturation value instead of luminance.
+ ///
+ public BinaryThresholdProcessor(float threshold,bool useSaturationNotLuminance = false)
+ : this(threshold, Color.White, Color.Black,useSaturationNotLuminance)
{
}
@@ -25,12 +28,16 @@ public BinaryThresholdProcessor(float 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)
+ ///
+ /// Use saturation value instead of luminance.
+ ///
+ public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor,bool useSaturationNotLuminance = false)
{
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold));
this.Threshold = threshold;
this.UpperColor = upperColor;
this.LowerColor = lowerColor;
+ this.UseSaturationNotLuminance = useSaturationNotLuminance;
}
///
@@ -48,7 +55,12 @@ public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerCo
///
public Color LowerColor { get; }
- ///
+ ///
+ /// Gets a value indicating whether to use saturation value instead of luminance.
+ ///
+ public bool UseSaturationNotLuminance { 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..26c051b64 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
@@ -44,7 +44,7 @@ protected override void OnFrameApply(ImageFrame source)
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.UseSaturationNotLuminance, isAlphaOnly);
ParallelRowIterator.IterateRows(
configuration,
interest,
@@ -60,9 +60,11 @@ protected override void OnFrameApply(ImageFrame source)
private readonly TPixel upper;
private readonly TPixel lower;
private readonly byte threshold;
+ private readonly bool useSaturationNotLuminance;
private readonly int minX;
private readonly int maxX;
private readonly bool isAlphaOnly;
+ private readonly ColorSpaces.Conversion.ColorSpaceConverter colorSpaceConverter;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
@@ -71,15 +73,18 @@ protected override void OnFrameApply(ImageFrame source)
TPixel upper,
TPixel lower,
byte threshold,
+ bool useSaturationNotLuminance,
bool isAlphaOnly)
{
this.source = source;
this.upper = upper;
this.lower = lower;
this.threshold = threshold;
+ this.useSaturationNotLuminance = useSaturationNotLuminance;
this.minX = bounds.X;
this.maxX = bounds.Right;
this.isAlphaOnly = isAlphaOnly;
+ this.colorSpaceConverter = new ColorSpaces.Conversion.ColorSpaceConverter();
}
///
@@ -95,9 +100,18 @@ public void Invoke(int y)
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;
+ if (this.useSaturationNotLuminance)
+ {
+ float sat = this.colorSpaceConverter.ToHsl(rgba).S;
+ byte val = (byte)(sat * 255);
+ color = val >= this.threshold ? this.upper : this.lower;
+ }
+ else
+ {
+ // 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;
+ }
}
}
}
diff --git a/tests/Images/External b/tests/Images/External
--- a/tests/Images/External
+++ b/tests/Images/External
@@ -1 +1 @@
-Subproject commit 1df65162448996332449387a46da942e181043c8
+Subproject commit 1df65162448996332449387a46da942e181043c8-dirty