Browse Source

using Parallel.For

pull/673/head
popow 8 years ago
parent
commit
f04ac406e3
  1. 90
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs

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

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory; using SixLabors.Memory;
@ -28,6 +29,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
public AdaptiveHistEqualizationProcessor(int gridSize, int clipLimit, int luminanceLevels) public AdaptiveHistEqualizationProcessor(int gridSize, int clipLimit, int luminanceLevels)
: base(luminanceLevels) : base(luminanceLevels)
{ {
Guard.MustBeGreaterThan(gridSize, 8, nameof(gridSize));
Guard.MustBeGreaterThan(clipLimit, 1, nameof(clipLimit));
this.GridSize = gridSize; this.GridSize = gridSize;
this.ClipLimit = clipLimit; this.ClipLimit = clipLimit;
} }
@ -51,49 +55,55 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int pixelsInGrid = this.GridSize * this.GridSize; int pixelsInGrid = this.GridSize * this.GridSize;
int halfGridSize = this.GridSize / 2; int halfGridSize = this.GridSize / 2;
using (IBuffer<int> histogramBuffer = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
using (IBuffer<int> histogramBufferCopy = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
using (IBuffer<int> cdfBuffer = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Width, source.Height)) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Width, source.Height))
{ {
Span<int> histogram = histogramBuffer.GetSpan(); Parallel.For(
Span<int> histogramCopy = histogramBufferCopy.GetSpan(); 0,
Span<int> cdf = cdfBuffer.GetSpan(); source.Width,
configuration.ParallelOptions,
for (int x = 0; x < source.Width; x++) x =>
{
histogram.Clear();
// Build the histogram of grayscale values for the current grid.
for (int dy = -halfGridSize; dy < halfGridSize; dy++)
{ {
Span<TPixel> rowSpan = this.GetPixelRow(source, x - halfGridSize, dy, this.GridSize); using (IBuffer<int> histogramBuffer = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
this.AddPixelsTooHistogram(rowSpan, histogram, this.LuminanceLevels); using (IBuffer<int> histogramBufferCopy = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
} using (IBuffer<int> cdfBuffer = memoryAllocator.AllocateClean<int>(this.LuminanceLevels))
{
for (int y = 0; y < source.Height; y++) Span<int> histogram = histogramBuffer.GetSpan();
{ Span<int> histogramCopy = histogramBufferCopy.GetSpan();
// Clipping the histogram, but doing it on a copy to keep the original un-clipped values for the next iteration Span<int> cdf = cdfBuffer.GetSpan();
histogram.CopyTo(histogramCopy);
this.ClipHistogram(histogramCopy, this.ClipLimit); histogram.Clear();
cdf.Clear();
int cdfMin = this.CalculateCdf(cdf, histogramCopy); // Build the histogram of grayscale values for the current grid.
double numberOfPixelsMinusCdfMin = (double)(pixelsInGrid - cdfMin); for (int dy = -halfGridSize; dy < halfGridSize; dy++)
{
// Map the current pixel to the new equalized value Span<TPixel> rowSpan = this.GetPixelRow(source, x - halfGridSize, dy, this.GridSize);
int luminance = this.GetLuminance(pixels[(y * source.Width) + x], this.LuminanceLevels); this.AddPixelsTooHistogram(rowSpan, histogram, this.LuminanceLevels);
double luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin; }
targetPixels[x, y].PackFromVector4(new Vector4((float)luminanceEqualized));
for (int y = 0; y < source.Height; y++)
// Remove top most row from the histogram, mirroring rows which exceeds the borders {
Span<TPixel> rowSpan = this.GetPixelRow(source, x - halfGridSize, y - halfGridSize, this.GridSize); // Clipping the histogram, but doing it on a copy to keep the original un-clipped values for the next iteration
this.RemovePixelsFromHistogram(rowSpan, histogram, this.LuminanceLevels); histogram.CopyTo(histogramCopy);
this.ClipHistogram(histogramCopy, this.ClipLimit);
// Add new bottom row to the histogram, mirroring rows which exceeds the borders cdf.Clear();
rowSpan = this.GetPixelRow(source, x - halfGridSize, y + halfGridSize, this.GridSize); int cdfMin = this.CalculateCdf(cdf, histogramCopy);
this.AddPixelsTooHistogram(rowSpan, histogram, this.LuminanceLevels); double numberOfPixelsMinusCdfMin = (double)(pixelsInGrid - cdfMin);
}
} // Map the current pixel to the new equalized value
int luminance = this.GetLuminance(source[x, y], this.LuminanceLevels);
double luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin;
targetPixels[x, y].PackFromVector4(new Vector4((float)luminanceEqualized));
// Remove top most row from the histogram, mirroring rows which exceeds the borders
Span<TPixel> rowSpan = this.GetPixelRow(source, x - halfGridSize, y - halfGridSize, this.GridSize);
this.RemovePixelsFromHistogram(rowSpan, histogram, this.LuminanceLevels);
// Add new bottom row to the histogram, mirroring rows which exceeds the borders
rowSpan = this.GetPixelRow(source, x - halfGridSize, y + halfGridSize, this.GridSize);
this.AddPixelsTooHistogram(rowSpan, histogram, this.LuminanceLevels);
}
}
});
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }

Loading…
Cancel
Save