Browse Source

added first attempt of histogram equalization

pull/644/head
popow 8 years ago
parent
commit
d41ece1432
  1. 23
      src/ImageSharp/Processing/Contrast/HistogramEqualizationExtension.cs
  2. 64
      src/ImageSharp/Processing/Contrast/HistogramEqualizationProcessor.cs

23
src/ImageSharp/Processing/Contrast/HistogramEqualizationExtension.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Contrast
{
/// <summary>
/// Adds extension that allows applying an HistogramEqualization to the image.
/// </summary>
public static class HistogramEqualizationExtension
{
/// <summary>
/// Equalizes the histogram of an image to increases the global contrast.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new HistogramEqualizationProcessor<TPixel>());
}
}

64
src/ImageSharp/Processing/Contrast/HistogramEqualizationProcessor.cs

@ -0,0 +1,64 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Contrast
{
internal class HistogramEqualizationProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
var rgb = default(Rgb24);
int numberOfPixels = source.Width * source.Height;
// build the histogram of the grayscale levels
int luminanceLevels = 256;
int[] histogram = new int[luminanceLevels];
for (int y = 0; y < source.Height; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
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));
histogram[luminance]++;
}
}
// calculate the cumulative distribution function
double[] cdf = new double[luminanceLevels];
double sum = 0.0d;
for (int i = 0; i < histogram.Length; i++)
{
double p = (double)histogram[i] / numberOfPixels;
sum += p;
cdf[i] = sum;
}
// apply the cdf to each pixel of the image
for (int y = 0; y < source.Height; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
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));
byte luminanceEqualized = (byte)(cdf[luminance] * luminance);
row[x].PackFromRgba32(new Rgba32(luminanceEqualized, luminanceEqualized, luminanceEqualized));
}
}
}
}
}
Loading…
Cancel
Save