Browse Source

using Parallel.ForEach to calculate the lookup tables

pull/673/head
popow 8 years ago
parent
commit
09955daa33
  1. 99
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs
  2. 8
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs

99
src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs

@ -45,23 +45,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <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;
int numberOfPixels = source.Width * source.Height; int numberOfPixels = source.Width * source.Height;
int tileWidth = Convert.ToInt32(Math.Ceiling(source.Width / (double)this.Tiles)); int tileWidth = Convert.ToInt32(Math.Ceiling(source.Width / (double)this.Tiles));
int tileHeight = Convert.ToInt32(Math.Ceiling(source.Height / (double)this.Tiles)); int tileHeight = Convert.ToInt32(Math.Ceiling(source.Height / (double)this.Tiles));
int pixelsInTile = tileWidth * tileHeight; int pixelsInTile = tileWidth * tileHeight;
int halfTileWidth = tileWidth / 2; int halfTileWidth = tileWidth / 2;
int halfTileHeight = tileHeight / 2; int halfTileHeight = tileHeight / 2;
using (System.Buffers.IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
using (System.Buffers.IMemoryOwner<int> cdfBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
{
Span<int> histogram = histogramBuffer.GetSpan();
Span<int> cdf = cdfBuffer.GetSpan();
// The image is split up into tiles. For each tile the cumulative distribution function will be calculated. // The image is split up into tiles. For each tile the cumulative distribution function will be calculated.
CdfData[,] cdfData = this.CalculateLookupTables(source, histogram, cdf, this.Tiles, this.Tiles, tileWidth, tileHeight); CdfData[,] cdfData = this.CalculateLookupTables(source, configuration, this.Tiles, this.Tiles, tileWidth, tileHeight);
var tileYStartPositions = new List<(int y, int cdfY)>(); var tileYStartPositions = new List<(int y, int cdfY)>();
int cdfY = 0; int cdfY = 0;
@ -128,7 +120,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
// right bottom corner // right bottom corner
this.ProcessCornerTile(source, pixels, cdfData[this.Tiles - 1, this.Tiles - 1], xStart: source.Width - halfTileWidth, xEnd: source.Width, yStart: source.Height - halfTileHeight, yEnd: source.Height, pixelsInTile: pixelsInTile); this.ProcessCornerTile(source, pixels, cdfData[this.Tiles - 1, this.Tiles - 1], xStart: source.Width - halfTileWidth, xEnd: source.Width, yStart: source.Height - halfTileHeight, yEnd: source.Height, pixelsInTile: pixelsInTile);
} }
}
/// <summary> /// <summary>
/// Processes the part of a corner tile which was previously left out. It consists of 1 / 4 of a tile and does not need interpolation. /// Processes the part of a corner tile which was previously left out. It consists of 1 / 4 of a tile and does not need interpolation.
@ -286,28 +277,68 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
return luminanceEqualized; return luminanceEqualized;
} }
/// <summary>
/// Bilinear interpolation between four tiles.
/// </summary>
/// <param name="tx">The interpolation value in x direction in the range of [0, 1].</param>
/// <param name="ty">The interpolation value in y direction in the range of [0, 1].</param>
/// <param name="lt">Luminance from top left tile.</param>
/// <param name="rt">Luminance from right top tile.</param>
/// <param name="lb">Luminance from left bottom tile.</param>
/// <param name="rb">Luminance from right bottom tile.</param>
/// <returns>Interpolated Luminance.</returns>
private float BilinearInterpolation(float tx, float ty, float lt, float rt, float lb, float rb)
{
return this.LinearInterpolation(this.LinearInterpolation(lt, rt, tx), this.LinearInterpolation(lb, rb, tx), ty);
}
/// <summary>
/// Linear interpolation between two grey values.
/// </summary>
/// <param name="left">The left value.</param>
/// <param name="right">The right value.</param>
/// <param name="t">The interpolation value between the two values in the range of [0, 1].</param>
/// <returns>The interpolated value.</returns>
private float LinearInterpolation(float left, float right, float t)
{
return left + ((right - left) * t);
}
/// <summary> /// <summary>
/// Calculates the lookup tables for each tile of the image. /// Calculates the lookup tables for each tile of the image.
/// </summary> /// </summary>
/// <param name="source">The input image for which the tiles will be calculated.</param> /// <param name="source">The input image for which the tiles will be calculated.</param>
/// <param name="histogram">Histogram buffer.</param> /// <param name="configuration">The configuration.</param>
/// <param name="cdf">Buffer for calculating the cumulative distribution function.</param>
/// <param name="numTilesX">Number of tiles in the X Direction.</param> /// <param name="numTilesX">Number of tiles in the X Direction.</param>
/// <param name="numTilesY">Number of tiles in Y Direction</param> /// <param name="numTilesY">Number of tiles in Y Direction.</param>
/// <param name="tileWidth">Width in pixels of one tile.</param> /// <param name="tileWidth">Width in pixels of one tile.</param>
/// <param name="tileHeight">Height in pixels of one tile.</param> /// <param name="tileHeight">Height in pixels of one tile.</param>
/// <returns>All lookup tables for each tile in the image.</returns> /// <returns>All lookup tables for each tile in the image.</returns>
private CdfData[,] CalculateLookupTables(ImageFrame<TPixel> source, Span<int> histogram, Span<int> cdf, int numTilesX, int numTilesY, int tileWidth, int tileHeight) private CdfData[,] CalculateLookupTables(ImageFrame<TPixel> source, Configuration configuration, int numTilesX, int numTilesY, int tileWidth, int tileHeight)
{ {
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
var cdfData = new CdfData[numTilesX, numTilesY]; var cdfData = new CdfData[numTilesX, numTilesY];
int pixelsInTile = tileWidth * tileHeight; int pixelsInTile = tileWidth * tileHeight;
int tileX = 0;
int tileY = 0; var tileYStartPositions = new List<(int y, int cdfY)>();
int cdfY = 0;
for (int y = 0; y < source.Height; y += tileHeight) for (int y = 0; y < source.Height; y += tileHeight)
{ {
tileX = 0; tileYStartPositions.Add((y, cdfY));
cdfY++;
}
Parallel.ForEach(tileYStartPositions, new ParallelOptions() { MaxDegreeOfParallelism = configuration.MaxDegreeOfParallelism }, (tileYStartPosition) =>
{
using (System.Buffers.IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
using (System.Buffers.IMemoryOwner<int> cdfBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
{
int cdfX = 0;
int y = tileYStartPosition.y;
for (int x = 0; x < source.Width; x += tileWidth) for (int x = 0; x < source.Width; x += tileWidth)
{ {
Span<int> histogram = histogramBuffer.GetSpan();
Span<int> cdf = cdfBuffer.GetSpan();
histogram.Clear(); histogram.Clear();
cdf.Clear(); cdf.Clear();
int ylimit = Math.Min(y + tileHeight, source.Height); int ylimit = Math.Min(y + tileHeight, source.Height);
@ -328,44 +359,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int cdfMin = this.CalculateCdf(cdf, histogram, histogram.Length - 1); int cdfMin = this.CalculateCdf(cdf, histogram, histogram.Length - 1);
var currentCdf = new CdfData(cdf.ToArray(), cdfMin); var currentCdf = new CdfData(cdf.ToArray(), cdfMin);
cdfData[tileX, tileY] = currentCdf; cdfData[cdfX, tileYStartPosition.cdfY] = currentCdf;
tileX++; cdfX++;
} }
tileY++; cdfY++;
} }
});
return cdfData; return cdfData;
} }
/// <summary>
/// Bilinear interpolation between four tiles.
/// </summary>
/// <param name="tx">The interpolation value in x direction in the range of [0, 1].</param>
/// <param name="ty">The interpolation value in y direction in the range of [0, 1].</param>
/// <param name="lt">Luminance from top left tile.</param>
/// <param name="rt">Luminance from right top tile.</param>
/// <param name="lb">Luminance from left bottom tile.</param>
/// <param name="rb">Luminance from right bottom tile.</param>
/// <returns>Interpolated Luminance.</returns>
private float BilinearInterpolation(float tx, float ty, float lt, float rt, float lb, float rb)
{
return this.LinearInterpolation(this.LinearInterpolation(lt, rt, tx), this.LinearInterpolation(lb, rb, tx), ty);
}
/// <summary>
/// Linear interpolation between two grey values.
/// </summary>
/// <param name="left">The left value.</param>
/// <param name="right">The right value.</param>
/// <param name="t">The interpolation value between the two values in the range of [0, 1].</param>
/// <returns>The interpolated value.</returns>
private float LinearInterpolation(float left, float right, float t)
{
return left + ((right - left) * t);
}
/// <summary> /// <summary>
/// Lookup table for remapping the grey values of one tile. /// Lookup table for remapping the grey values of one tile.
/// </summary> /// </summary>

8
src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs

@ -178,8 +178,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <summary> /// <summary>
/// Adds a row of grey values to the histogram. /// Adds a row of grey values to the histogram.
/// </summary> /// </summary>
/// <param name="greyValues">The grey values to add</param> /// <param name="greyValues">The grey values to add.</param>
/// <param name="histogram">The histogram</param> /// <param name="histogram">The histogram.</param>
/// <param name="luminanceLevels">The number of different luminance levels.</param> /// <param name="luminanceLevels">The number of different luminance levels.</param>
/// <returns>The maximum index where a value was changed.</returns> /// <returns>The maximum index where a value was changed.</returns>
private int AddPixelsToHistogram(Span<TPixel> greyValues, Span<int> histogram, int luminanceLevels) private int AddPixelsToHistogram(Span<TPixel> greyValues, Span<int> histogram, int luminanceLevels)
@ -201,8 +201,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <summary> /// <summary>
/// Removes a row of grey values from the histogram. /// Removes a row of grey values from the histogram.
/// </summary> /// </summary>
/// <param name="greyValues">The grey values to remove</param> /// <param name="greyValues">The grey values to remove.</param>
/// <param name="histogram">The histogram</param> /// <param name="histogram">The histogram.</param>
/// <param name="luminanceLevels">The number of different luminance levels.</param> /// <param name="luminanceLevels">The number of different luminance levels.</param>
/// <param name="maxHistIdx">The current maximum index of the histogram.</param> /// <param name="maxHistIdx">The current maximum index of the histogram.</param>
/// <returns>The (maybe changed) maximum index of the histogram.</returns> /// <returns>The (maybe changed) maximum index of the histogram.</returns>

Loading…
Cancel
Save