From 72a4ee48281263ef342cb980bc10ddaf95f5b214 Mon Sep 17 00:00:00 2001 From: popow Date: Sun, 1 Jul 2018 19:09:00 +0200 Subject: [PATCH] added support for 16 bit greyscale --- .../HistogramEqualizationExtension.cs | 2 +- .../HistogramEqualizationProcessor.cs | 56 +++++++++++++++---- .../Contrast/HistogramEqualizationTests.cs | 17 +++--- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Processing/Contrast/HistogramEqualizationExtension.cs b/src/ImageSharp/Processing/Contrast/HistogramEqualizationExtension.cs index 1cd29f8b4..a7b59cedd 100644 --- a/src/ImageSharp/Processing/Contrast/HistogramEqualizationExtension.cs +++ b/src/ImageSharp/Processing/Contrast/HistogramEqualizationExtension.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Contrast /// /// The pixel format. /// The image this method extends. - /// The . + /// A histogram equalized grayscale image. public static IImageProcessingContext HistogramEqualization(this IImageProcessingContext source) where TPixel : struct, IPixel => source.ApplyProcessor(new HistogramEqualizationProcessor()); diff --git a/src/ImageSharp/Processing/Contrast/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Contrast/HistogramEqualizationProcessor.cs index f23382d20..df1737455 100644 --- a/src/ImageSharp/Processing/Contrast/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Contrast/HistogramEqualizationProcessor.cs @@ -9,17 +9,23 @@ using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Contrast { + /// + /// Applies a global histogram equalization to the image. + /// + /// The pixel format. internal class HistogramEqualizationProcessor : ImageProcessor where TPixel : struct, IPixel { /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - var rgb = default(Rgb24); + var rgb48 = default(Rgb48); + var rgb24 = default(Rgb24); int numberOfPixels = source.Width * source.Height; + bool is16bitPerChannel = typeof(TPixel) == typeof(Rgb48) || typeof(TPixel) == typeof(Rgba64); // build the histogram of the grayscale levels - int luminanceLevels = 256; + int luminanceLevels = is16bitPerChannel ? 65536 : 256; int[] histogram = new int[luminanceLevels]; for (int y = 0; y < source.Height; y++) { @@ -27,15 +33,12 @@ namespace SixLabors.ImageSharp.Processing.Contrast for (int x = 0; x < source.Width; x++) { TPixel sourcePixel = row[x]; - sourcePixel.ToRgb24(ref rgb); - - // Convert to grayscale using ITU-R Recommendation BT.709 if required - int luminance = (int)((.2126F * rgb.R) + (.7152F * rgb.G) + (.0722F * rgb.B)); + int luminance = this.GetLuminance(sourcePixel, is16bitPerChannel, ref rgb24, ref rgb48); histogram[luminance]++; } } - // calculate the cumulative distribution function which will be the cumulative histogram + // calculate the cumulative distribution function (which will be the cumulative histogram) int[] cdf = new int[luminanceLevels]; int histSum = 0; for (int i = 0; i < histogram.Length; i++) @@ -69,13 +72,46 @@ namespace SixLabors.ImageSharp.Processing.Contrast for (int x = 0; x < source.Width; x++) { TPixel sourcePixel = row[x]; - sourcePixel.ToRgb24(ref rgb); - int luminance = (int)((.2126F * rgb.R) + (.7152F * rgb.G) + (.0722F * rgb.B)); + + int luminance = this.GetLuminance(sourcePixel, is16bitPerChannel, ref rgb24, ref rgb48); double luminanceEqualized = (lut[luminance] / numberOfPixelsMinusCdfMin) * luminanceLevelsMinusOne; luminanceEqualized = Math.Round(luminanceEqualized); - row[x].PackFromRgba32(new Rgba32((byte)luminanceEqualized, (byte)luminanceEqualized, (byte)luminanceEqualized)); + + if (is16bitPerChannel) + { + row[x].PackFromRgb48(new Rgb48((ushort)luminanceEqualized, (ushort)luminanceEqualized, (ushort)luminanceEqualized)); + } + else + { + row[x].PackFromRgba32(new Rgba32((byte)luminanceEqualized, (byte)luminanceEqualized, (byte)luminanceEqualized)); + } } } } + + /// + /// Convert the pixel values to grayscale using ITU-R Recommendation BT.709. + /// + /// The pixel to get the luminance from + /// Flag indicates, if its 16 bits per channel, otherwise its 8 + /// Will store the pixel values in case of 8 bit per channel + /// Will store the pixel values in case of 16 bit per channel + private int GetLuminance(TPixel sourcePixel, bool is16bitPerChannel, ref Rgb24 rgb24, ref Rgb48 rgb48) + { + // Convert to grayscale using ITU-R Recommendation BT.709 + int luminance; + if (is16bitPerChannel) + { + sourcePixel.ToRgb48(ref rgb48); + luminance = (int)((.2126F * rgb48.R) + (.7152F * rgb48.G) + (.0722F * rgb48.B)); + } + else + { + sourcePixel.ToRgb24(ref rgb24); + luminance = (int)((.2126F * rgb24.R) + (.7152F * rgb24.G) + (.0722F * rgb24.B)); + } + + return luminance; + } } } diff --git a/tests/ImageSharp.Tests/Processing/Contrast/HistogramEqualizationTests.cs b/tests/ImageSharp.Tests/Processing/Contrast/HistogramEqualizationTests.cs index b5c584a55..db2282ccd 100644 --- a/tests/ImageSharp.Tests/Processing/Contrast/HistogramEqualizationTests.cs +++ b/tests/ImageSharp.Tests/Processing/Contrast/HistogramEqualizationTests.cs @@ -37,14 +37,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Contrast byte[] expected = new byte[] { - 0, 12, 53, 32, 146, 53, 174, 53, - 57, 32, 12, 227, 219, 202, 32, 154, - 65, 85, 93, 239, 251, 227, 65, 158, - 73, 146, 146, 247, 255, 235, 154, 130, - 97, 166, 117, 231, 243, 210, 117, 117, - 117, 190, 36, 190, 178, 93, 20, 170, - 130, 202, 73, 20, 12, 53, 85, 194, - 146, 206, 130, 117, 85, 166, 182, 215 + 0, 12, 53, 32, 146, 53, 174, 53, + 57, 32, 12, 227, 219, 202, 32, 154, + 65, 85, 93, 239, 251, 227, 65, 158, + 73, 146, 146, 247, 255, 235, 154, 130, + 97, 166, 117, 231, 243, 210, 117, 117, + 117, 190, 36, 190, 178, 93, 20, 170, + 130, 202, 73, 20, 12, 53, 85, 194, + 146, 206, 130, 117, 85, 166, 182, 215 }; // act @@ -58,7 +58,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Contrast Rgba32 actual = image[x, y]; int diff = expected[y * 8 + x] - actual.R; Assert.True(diff == 0); - int foo = 2; } } }