Browse Source

luminance levels is now a parameter of the constructor, defaults to 65536

af/merge-core
popow 8 years ago
parent
commit
d5cc405212
  1. 6
      src/ImageSharp/Processing/Normalization/HistogramEqualizationExtension.cs
  2. 28
      src/ImageSharp/Processing/Normalization/HistogramEqualizationProcessor.cs
  3. 8
      tests/ImageSharp.Tests/Processing/Normalization/HistogramEqualizationTests.cs

6
src/ImageSharp/Processing/Normalization/HistogramEqualizationExtension.cs

@ -15,9 +15,11 @@ namespace SixLabors.ImageSharp.Processing.Normalization
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="luminanceLevels">The number of different luminance levels. Typical values are 256 for 8-bit grayscale images
/// or 65536 for 16-bit grayscale images.Defaults to 65536.</param>
/// <returns>A histogram equalized grayscale image.</returns> /// <returns>A histogram equalized grayscale image.</returns>
public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source) public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source, int luminanceLevels = 65536)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new HistogramEqualizationProcessor<TPixel>()); => source.ApplyProcessor(new HistogramEqualizationProcessor<TPixel>(luminanceLevels));
} }
} }

28
src/ImageSharp/Processing/Normalization/HistogramEqualizationProcessor.cs

@ -18,25 +18,39 @@ namespace SixLabors.ImageSharp.Processing.Normalization
internal class HistogramEqualizationProcessor<TPixel> : ImageProcessor<TPixel> internal class HistogramEqualizationProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary>
/// Initializes a new instance of the <see cref="HistogramEqualizationProcessor{TPixel}"/> class.
/// </summary>
/// <param name="luminanceLevels">The number of different luminance levels. Typical values are 256 for 8-bit grayscale images
/// or 65536 for 16-bit grayscale images.Defaults to 65536.</param>
public HistogramEqualizationProcessor(int luminanceLevels = 65536)
{
Guard.MustBeGreaterThan(luminanceLevels, 0, nameof(luminanceLevels));
this.LuminanceLevels = luminanceLevels;
}
/// <summary>
/// Gets the luminance levels.
/// </summary>
public int LuminanceLevels { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
MemoryAllocator memoryAllocator = configuration.MemoryAllocator; MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
int numberOfPixels = source.Width * source.Height; int numberOfPixels = source.Width * source.Height;
bool is16bitPerChannel = typeof(TPixel) == typeof(Rgb48) || typeof(TPixel) == typeof(Rgba64);
Span<TPixel> pixels = source.GetPixelSpan(); Span<TPixel> pixels = source.GetPixelSpan();
// build the histogram of the grayscale levels // build the histogram of the grayscale levels
int luminanceLevels = is16bitPerChannel ? 65536 : 256; using (IBuffer<int> histogramBuffer = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
using (IBuffer<int> histogramBuffer = memoryAllocator.AllocateClean<int>(luminanceLevels)) using (IBuffer<int> cdfBuffer = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
using (IBuffer<int> cdfBuffer = memoryAllocator.AllocateClean<int>(luminanceLevels))
{ {
Span<int> histogram = histogramBuffer.GetSpan(); Span<int> histogram = histogramBuffer.GetSpan();
for (int i = 0; i < pixels.Length; i++) for (int i = 0; i < pixels.Length; i++)
{ {
TPixel sourcePixel = pixels[i]; TPixel sourcePixel = pixels[i];
int luminance = this.GetLuminance(sourcePixel, luminanceLevels); int luminance = this.GetLuminance(sourcePixel, this.LuminanceLevels);
histogram[luminance]++; histogram[luminance]++;
} }
@ -50,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Normalization
{ {
TPixel sourcePixel = pixels[i]; TPixel sourcePixel = pixels[i];
int luminance = this.GetLuminance(sourcePixel, luminanceLevels); int luminance = this.GetLuminance(sourcePixel, this.LuminanceLevels);
double luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin; double luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin;
pixels[i].PackFromVector4(new Vector4((float)luminanceEqualized)); pixels[i].PackFromVector4(new Vector4((float)luminanceEqualized));

8
tests/ImageSharp.Tests/Processing/Normalization/HistogramEqualizationTests.cs

@ -10,8 +10,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Normalization
{ {
public class HistogramEqualizationTests public class HistogramEqualizationTests
{ {
[Fact] [Theory]
public void HistogramEqualizationTest() [InlineData(256)]
[InlineData(65536)]
public void HistogramEqualizationTest(int luminanceLevels)
{ {
// arrange // arrange
byte[] pixels = new byte[] byte[] pixels = new byte[]
@ -48,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Normalization
}; };
// act // act
image.Mutate(x => x.HistogramEqualization()); image.Mutate(x => x.HistogramEqualization(luminanceLevels));
// assert // assert
for (int y = 0; y < 8; y++) for (int y = 0; y < 8; y++)

Loading…
Cancel
Save