Browse Source

Moving sliding window from left to right instead of from top to bottom

pull/673/head
Brian Popow 7 years ago
parent
commit
8f19e5edd2
  1. 95
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs

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

@ -51,21 +51,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
Span<TPixel> pixels = source.GetPixelSpan(); Span<TPixel> pixels = source.GetPixelSpan();
var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = configuration.MaxDegreeOfParallelism }; var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = configuration.MaxDegreeOfParallelism };
int tileWidth = source.Width / this.Tiles; int tileHeight = source.Height / this.Tiles;
int pixeInTile = tileWidth * tileWidth; int pixeInTile = tileHeight * tileHeight;
int halfTileWith = tileWidth / 2; int halfTileHeight = tileHeight / 2;
int halfTileWidth = halfTileHeight;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Width, source.Height)) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Width, source.Height))
{ {
Parallel.For( Parallel.For(
0, 0,
source.Width, source.Height,
parallelOptions, parallelOptions,
x => y =>
{ {
using (IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean)) using (IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
using (IMemoryOwner<int> histogramBufferCopy = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean)) using (IMemoryOwner<int> histogramBufferCopy = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
using (IMemoryOwner<int> cdfBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean)) using (IMemoryOwner<int> cdfBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean))
using (IMemoryOwner<TPixel> pixelRowBuffer = memoryAllocator.Allocate<TPixel>(tileWidth, AllocationOptions.Clean)) using (IMemoryOwner<TPixel> pixelColumnBuffer = memoryAllocator.Allocate<TPixel>(tileHeight, AllocationOptions.Clean))
{ {
Span<int> histogram = histogramBuffer.GetSpan(); Span<int> histogram = histogramBuffer.GetSpan();
ref int histogramBase = ref MemoryMarshal.GetReference(histogram); ref int histogramBase = ref MemoryMarshal.GetReference(histogram);
@ -73,21 +74,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
ref int histogramCopyBase = ref MemoryMarshal.GetReference(histogramCopy); ref int histogramCopyBase = ref MemoryMarshal.GetReference(histogramCopy);
ref int cdfBase = ref MemoryMarshal.GetReference(cdfBuffer.GetSpan()); ref int cdfBase = ref MemoryMarshal.GetReference(cdfBuffer.GetSpan());
Span<TPixel> pixelRow = pixelRowBuffer.GetSpan(); Span<TPixel> pixelColumn = pixelColumnBuffer.GetSpan();
int maxHistIdx = 0; int maxHistIdx = 0;
// Build the histogram of grayscale values for the current tile. // Build the histogram of grayscale values for the current tile.
for (int dy = -halfTileWith; dy < halfTileWith; dy++) for (int dx = -halfTileWidth; dx < halfTileWidth; dx++)
{ {
Span<TPixel> rowSpan = this.GetPixelRow(source, pixelRow, x - halfTileWith, dy, tileWidth); Span<TPixel> columnSpan = this.GetPixelColumn(source, pixelColumn, dx, y - halfTileHeight, tileHeight);
int maxIdx = this.AddPixelsToHistogram(rowSpan, histogram, this.LuminanceLevels); int maxIdx = this.AddPixelsToHistogram(columnSpan, histogram, this.LuminanceLevels);
if (maxIdx > maxHistIdx) if (maxIdx > maxHistIdx)
{ {
maxHistIdx = maxIdx; maxHistIdx = maxIdx;
} }
} }
for (int y = 0; y < source.Height; y++) for (int x = 0; x < source.Width; x++)
{ {
if (this.ClipHistogramEnabled) if (this.ClipHistogramEnabled)
{ {
@ -103,18 +104,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
float numberOfPixelsMinusCdfMin = pixeInTile - cdfMin; float numberOfPixelsMinusCdfMin = pixeInTile - cdfMin;
// Map the current pixel to the new equalized value // Map the current pixel to the new equalized value.
int luminance = GetLuminance(source[x, y], this.LuminanceLevels); int luminance = GetLuminance(source[x, y], this.LuminanceLevels);
float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / numberOfPixelsMinusCdfMin; float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / numberOfPixelsMinusCdfMin;
targetPixels[x, y].FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, source[x, y].ToVector4().W)); targetPixels[x, y].FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, source[x, y].ToVector4().W));
// Remove top most row from the histogram, mirroring rows which exceeds the borders. // Remove left most column from the histogram, mirroring columns which exceeds the borders of the image.
Span<TPixel> rowSpan = this.GetPixelRow(source, pixelRow, x - halfTileWith, y - halfTileWith, tileWidth); Span<TPixel> columnSpan = this.GetPixelColumn(source, pixelColumn, x - halfTileWidth, y - halfTileHeight, tileHeight);
maxHistIdx = this.RemovePixelsFromHistogram(rowSpan, histogram, this.LuminanceLevels, maxHistIdx); maxHistIdx = this.RemovePixelsFromHistogram(columnSpan, histogram, this.LuminanceLevels, maxHistIdx);
// Add new bottom row to the histogram, mirroring rows which exceeds the borders. // Add new right column to the histogram, mirroring columns which exceeds the borders of the image.
rowSpan = this.GetPixelRow(source, pixelRow, x - halfTileWith, y + halfTileWith, tileWidth); columnSpan = this.GetPixelColumn(source, pixelColumn, x + halfTileWidth, y - halfTileHeight, tileHeight);
int maxIdx = this.AddPixelsToHistogram(rowSpan, histogram, this.LuminanceLevels); int maxIdx = this.AddPixelsToHistogram(columnSpan, histogram, this.LuminanceLevels);
if (maxIdx > maxHistIdx) if (maxIdx > maxHistIdx)
{ {
maxHistIdx = maxIdx; maxHistIdx = maxIdx;
@ -128,62 +129,64 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
} }
/// <summary> /// <summary>
/// Get the a pixel row at a given position with a length of the tile width. Mirrors pixels which exceeds the edges. /// Get the a pixel column at a given position with the size of the tile height. Mirrors pixels which exceeds the edges of the image.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
/// <param name="rowPixels">Pre-allocated pixel row span of the size of a tile width.</param> /// <param name="columnPixels">Pre-allocated pixel row span of the size of a tile height.</param>
/// <param name="x">The x position.</param> /// <param name="x">The x position.</param>
/// <param name="y">The y position.</param> /// <param name="y">The y position.</param>
/// <param name="tileWidth">The width in pixels of a tile.</param> /// <param name="tileHeight">The height in pixels of a tile.</param>
/// <returns>A pixel row of the length of the tile width.</returns> /// <returns>A pixel row of the length of the tile width.</returns>
private Span<TPixel> GetPixelRow(ImageFrame<TPixel> source, Span<TPixel> rowPixels, int x, int y, int tileWidth) private Span<TPixel> GetPixelColumn(ImageFrame<TPixel> source, Span<TPixel> columnPixels, int x, int y, int tileHeight)
{ {
if (y < 0) if (x < 0)
{ {
y = Math.Abs(y); x = Math.Abs(x);
} }
else if (y >= source.Height) else if (x >= source.Width)
{ {
int diff = y - source.Height; int diff = x - source.Width;
y = source.Height - diff - 1; x = source.Width - diff - 1;
} }
// Special cases for the left and the right border where GetPixelRowSpan can not be used int idx = 0;
if (x < 0) columnPixels.Clear();
if (y < 0)
{ {
rowPixels.Clear(); columnPixels.Clear();
int idx = 0; for (int dy = y; dy < y + tileHeight; dy++)
for (int dx = x; dx < x + tileWidth; dx++)
{ {
rowPixels[idx] = source[Math.Abs(dx), y]; columnPixels[idx] = source[x, Math.Abs(dy)];
idx++; idx++;
} }
return rowPixels;
} }
else if (x + tileWidth > source.Width) else if (y + tileHeight > source.Height)
{ {
rowPixels.Clear(); for (int dy = y; dy < y + tileHeight; dy++)
int idx = 0;
for (int dx = x; dx < x + tileWidth; dx++)
{ {
if (dx >= source.Width) if (dy >= source.Height)
{ {
int diff = dx - source.Width; int diff = dy - source.Height;
rowPixels[idx] = source[dx - diff - 1, y]; columnPixels[idx] = source[x, dy - diff - 1];
} }
else else
{ {
rowPixels[idx] = source[dx, y]; columnPixels[idx] = source[x, dy];
} }
idx++; idx++;
} }
}
return rowPixels; else
{
for (int dy = y; dy < y + tileHeight; dy++)
{
columnPixels[idx] = source[x, dy];
idx++;
}
} }
return source.GetPixelRowSpan(y).Slice(start: x, length: tileWidth); return columnPixels;
} }
/// <summary> /// <summary>

Loading…
Cancel
Save