From 198123152870b24c1a12959117146c7fc00f1f96 Mon Sep 17 00:00:00 2001 From: popow Date: Sat, 22 Sep 2018 18:44:32 +0200 Subject: [PATCH] number of tiles is now part of the options and will be used with the sliding window approach also, so both methods are comparable --- .../HistogramEqualizationExtension.cs | 4 +- .../AdaptiveHistEqualizationProcessor.cs | 21 ++++----- .../AdaptiveHistEqualizationSWProcessor.cs | 45 ++++++++++--------- .../HistogramEqualizationOptions.cs | 4 +- .../HistogramEqualizationProcessor.cs | 1 + 5 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Processing/HistogramEqualizationExtension.cs b/src/ImageSharp/Processing/HistogramEqualizationExtension.cs index cbc96d5c3f..460681d871 100644 --- a/src/ImageSharp/Processing/HistogramEqualizationExtension.cs +++ b/src/ImageSharp/Processing/HistogramEqualizationExtension.cs @@ -44,11 +44,11 @@ namespace SixLabors.ImageSharp.Processing break; case HistogramEqualizationMethod.Adaptive: - processor = new AdaptiveHistEqualizationProcessor(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.GridSize); + processor = new AdaptiveHistEqualizationProcessor(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles); break; case HistogramEqualizationMethod.AdaptiveSlidingWindow: - processor = new AdaptiveHistEqualizationSWProcessor(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.GridSize); + processor = new AdaptiveHistEqualizationSWProcessor(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles); break; default: diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs index eb6da5d043..012899ec37 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs @@ -26,19 +26,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// or 65536 for 16-bit grayscale images. /// Indicating whether to clip the histogram bins at a specific value. /// Histogram clip limit in percent of the total pixels in the grid. Histogram bins which exceed this limit, will be capped at this value. - /// The grid size of the adaptive histogram equalization. Minimum value is 4. - public AdaptiveHistEqualizationProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage, int gridSize) + /// The number of tiles the image is split into (horizontal and vertically). + public AdaptiveHistEqualizationProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage, int tiles) : base(luminanceLevels, clipHistogram, clipLimitPercentage) { - Guard.MustBeGreaterThanOrEqualTo(gridSize, 4, nameof(gridSize)); + Guard.MustBeGreaterThanOrEqualTo(tiles, 0, nameof(tiles)); - this.GridSize = gridSize; + this.Tiles = tiles; } /// - /// Gets the size of the grid for the adaptive histogram equalization. + /// Gets the number of tiles the image is split into (horizontal and vertically) for the adaptive histogram equalization. /// - public int GridSize { get; } + private int Tiles { get; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) @@ -47,11 +47,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int numberOfPixels = source.Width * source.Height; Span pixels = source.GetPixelSpan(); - int numTilesX = 20; - int numTilesY = 20; - - int tileWidth = Convert.ToInt32(Math.Ceiling(source.Width / (double)numTilesX)); - int tileHeight = Convert.ToInt32(Math.Ceiling(source.Height / (double)numTilesY)); + int tileWidth = Convert.ToInt32(Math.Ceiling(source.Width / (double)this.Tiles)); + int tileHeight = Convert.ToInt32(Math.Ceiling(source.Height / (double)this.Tiles)); int pixelsInTile = tileWidth * tileHeight; int halfTileWidth = tileWidth / 2; int halfTileHeight = tileHeight / 2; @@ -63,7 +60,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization Span cdf = cdfBuffer.GetSpan(); // The image is split up into tiles. For each tile the cumulative distribution function will be calculated. - CdfData[,] cdfData = this.CalculateLookupTables(source, histogram, cdf, numTilesX, numTilesY, tileWidth, tileHeight); + CdfData[,] cdfData = this.CalculateLookupTables(source, histogram, cdf, this.Tiles, this.Tiles, tileWidth, tileHeight); int tileX = 0; int tileY = 0; diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs index 03db1d00db..b9fe2d0aec 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationSWProcessor.cs @@ -25,19 +25,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// or 65536 for 16-bit grayscale images. /// Indicating whether to clip the histogram bins at a specific value. /// Histogram clip limit in percent of the total pixels in the grid. Histogram bins which exceed this limit, will be capped at this value. - /// The grid size of the adaptive histogram equalization. Minimum value is 4. - public AdaptiveHistEqualizationSWProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage, int gridSize) + /// The number of tiles the image is split into (horizontal and vertically). + public AdaptiveHistEqualizationSWProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage, int tiles) : base(luminanceLevels, clipHistogram, clipLimitPercentage) { - Guard.MustBeGreaterThanOrEqualTo(gridSize, 4, nameof(gridSize)); + Guard.MustBeGreaterThanOrEqualTo(tiles, 0, nameof(tiles)); - this.GridSize = gridSize; + this.Tiles = tiles; } /// - /// Gets the size of the grid for the adaptive histogram equalization. + /// Gets the number of tiles the image is split into (horizontal and vertically) for the adaptive histogram equalization. /// - public int GridSize { get; } + private int Tiles { get; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) @@ -46,8 +46,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int numberOfPixels = source.Width * source.Height; Span pixels = source.GetPixelSpan(); - int pixelsInGrid = this.GridSize * this.GridSize; - int halfGridSize = this.GridSize / 2; + int tileWidth = source.Width / this.Tiles; + int pixeInTile = tileWidth * tileWidth; + int halfTileWith = tileWidth / 2; using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) { ParallelFor.WithConfiguration( @@ -66,9 +67,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int maxHistIdx = 0; // Build the histogram of grayscale values for the current grid. - for (int dy = -halfGridSize; dy < halfGridSize; dy++) + for (int dy = -halfTileWith; dy < halfTileWith; dy++) { - Span rowSpan = this.GetPixelRow(source, (int)x - halfGridSize, dy, this.GridSize); + Span rowSpan = this.GetPixelRow(source, (int)x - halfTileWith, dy, tileWidth); int maxIdx = this.AddPixelsToHistogram(rowSpan, histogram, this.LuminanceLevels); if (maxIdx > maxHistIdx) { @@ -82,12 +83,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization { // Clipping the histogram, but doing it on a copy to keep the original un-clipped values for the next iteration. histogram.Slice(0, maxHistIdx).CopyTo(histogramCopy); - this.ClipHistogram(histogramCopy, this.ClipLimitPercentage, pixelsInGrid); + this.ClipHistogram(histogramCopy, this.ClipLimitPercentage, pixeInTile); } // Calculate the cumulative distribution function, which will map each input pixel in the current grid to a new value. int cdfMin = this.ClipHistogramEnabled ? this.CalculateCdf(cdf, histogramCopy, maxHistIdx) : this.CalculateCdf(cdf, histogram, maxHistIdx); - float numberOfPixelsMinusCdfMin = pixelsInGrid - cdfMin; + float numberOfPixelsMinusCdfMin = pixeInTile - cdfMin; // Map the current pixel to the new equalized value int luminance = this.GetLuminance(source[x, y], this.LuminanceLevels); @@ -95,11 +96,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization targetPixels[x, y].PackFromVector4(new Vector4(luminanceEqualized)); // Remove top most row from the histogram, mirroring rows which exceeds the borders. - Span rowSpan = this.GetPixelRow(source, x - halfGridSize, y - halfGridSize, this.GridSize); + Span rowSpan = this.GetPixelRow(source, x - halfTileWith, y - halfTileWith, tileWidth); maxHistIdx = this.RemovePixelsFromHistogram(rowSpan, histogram, this.LuminanceLevels, maxHistIdx); // Add new bottom row to the histogram, mirroring rows which exceeds the borders. - rowSpan = this.GetPixelRow(source, x - halfGridSize, y + halfGridSize, this.GridSize); + rowSpan = this.GetPixelRow(source, x - halfTileWith, y + halfTileWith, tileWidth); int maxIdx = this.AddPixelsToHistogram(rowSpan, histogram, this.LuminanceLevels); if (maxIdx > maxHistIdx) { @@ -119,9 +120,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// The source image. /// The x position. /// The y position. - /// The grid size. + /// The width in pixels of a tile. /// A pixel row of the length of the grid size. - private Span GetPixelRow(ImageFrame source, int x, int y, int gridSize) + private Span GetPixelRow(ImageFrame source, int x, int y, int tileWidth) { if (y < 0) { @@ -136,9 +137,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization // Special cases for the left and the right border where GetPixelRowSpan can not be used if (x < 0) { - var rowPixels = new TPixel[gridSize]; + var rowPixels = new TPixel[tileWidth]; int idx = 0; - for (int dx = x; dx < x + gridSize; dx++) + for (int dx = x; dx < x + tileWidth; dx++) { rowPixels[idx] = source[Math.Abs(dx), y]; idx++; @@ -146,11 +147,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization return rowPixels; } - else if (x + gridSize > source.Width) + else if (x + tileWidth > source.Width) { - var rowPixels = new TPixel[gridSize]; + var rowPixels = new TPixel[tileWidth]; int idx = 0; - for (int dx = x; dx < x + gridSize; dx++) + for (int dx = x; dx < x + tileWidth; dx++) { if (dx >= source.Width) { @@ -168,7 +169,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization return rowPixels; } - return source.GetPixelRowSpan(y).Slice(start: x, length: gridSize); + return source.GetPixelRowSpan(y).Slice(start: x, length: tileWidth); } /// diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs index 6708a36998..afc887db55 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs @@ -31,8 +31,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization public float ClipLimitPercentage { get; set; } = 0.035f; /// - /// Gets or sets the size of the grid for the adaptive histogram equalization. Defaults to 32. + /// Gets or sets the number of tiles the image is split into (horizontal and vertically) for the adaptive histogram equalization. Defaults to 8. /// - public int GridSize { get; set; } = 32; + public int Tiles { get; set; } = 8; } } diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index e52aff1e76..ec5e69e3ff 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -20,6 +20,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// or 65536 for 16-bit grayscale images. /// Indicates, if histogram bins should be clipped. /// Histogram clip limit in percent of the total pixels in the grid. Histogram bins which exceed this limit, will be capped at this value. + /// The number of tiles the image is split into (horizontal and vertically) for the adaptive histogram equalization. Defaults to 8. protected HistogramEqualizationProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage) { Guard.MustBeGreaterThan(luminanceLevels, 0, nameof(luminanceLevels));