From 895cecfe0d659bdd48eb90c98f8da361e04fe1e1 Mon Sep 17 00:00:00 2001 From: popow Date: Sun, 2 Dec 2018 20:53:16 +0100 Subject: [PATCH] refactoring to improve readability --- .../HistogramEqualizationExtension.cs | 2 +- .../AdaptiveHistEqualizationProcessor.cs | 122 +++++++++--------- .../HistogramEqualizationMethod.cs | 4 +- 3 files changed, 65 insertions(+), 63 deletions(-) diff --git a/src/ImageSharp/Processing/HistogramEqualizationExtension.cs b/src/ImageSharp/Processing/HistogramEqualizationExtension.cs index 460681d871..ceae4a1ed4 100644 --- a/src/ImageSharp/Processing/HistogramEqualizationExtension.cs +++ b/src/ImageSharp/Processing/HistogramEqualizationExtension.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Processing processor = new GlobalHistogramEqualizationProcessor(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage); break; - case HistogramEqualizationMethod.Adaptive: + case HistogramEqualizationMethod.AdaptiveTileInterpolation: processor = new AdaptiveHistEqualizationProcessor(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles); break; diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs index 8a660306db..5b659fa322 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistEqualizationProcessor.cs @@ -62,153 +62,155 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization // 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); + int cdfX = 0; + int cdfY = 0; int tileX = 0; int tileY = 0; for (int y = halfTileHeight; y < source.Height - halfTileHeight; y += tileHeight) { - tileX = 0; + cdfX = 0; for (int x = halfTileWidth; x < source.Width - halfTileWidth; x += tileWidth) { - int tilePosX = 0; - int tilePosY = 0; + tileY = 0; int yEnd = Math.Min(y + tileHeight, source.Height); int xEnd = Math.Min(x + tileWidth, source.Width); for (int dy = y; dy < yEnd; dy++) { - tilePosX = 0; - float ty = tilePosY / (float)(tileHeight - 1); - int yTop = tileY; - int yBottom = yTop + 1; + tileX = 0; for (int dx = x; dx < xEnd; dx++) { - TPixel sourcePixel = source[dx, dy]; - int luminace = this.GetLuminance(sourcePixel, this.LuminanceLevels); - - int xLeft = tileX; - int xRight = tileX + 1; - - float cdfLeftTopLuminance = cdfData[xLeft, yTop].RemapGreyValue(luminace, pixelsInTile); - float cdfRightTopLuminance = cdfData[xRight, yTop].RemapGreyValue(luminace, pixelsInTile); - float cdfLeftBottomLuminance = cdfData[xLeft, yBottom].RemapGreyValue(luminace, pixelsInTile); - float cdfRightBottomLuminance = cdfData[xRight, yBottom].RemapGreyValue(luminace, pixelsInTile); - float luminanceEqualized = this.BilinearInterpolation(tilePosX / (float)(tileWidth - 1), ty, cdfLeftTopLuminance, cdfRightTopLuminance, cdfLeftBottomLuminance, cdfRightBottomLuminance); - + float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tileX, tileY, cdfX, cdfY, tileWidth, tileHeight, pixelsInTile); pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); - tilePosX++; + tileX++; } - tilePosY++; + tileY++; } - tileX++; + cdfX++; } - tileY++; + cdfY++; } // fix left column - tileX = 0; - tileY = 0; + cdfX = 0; + cdfY = 0; for (int y = 0; y < source.Height; y += tileHeight) { int yLimit = Math.Min(y + tileHeight, source.Height - 1); - int tilePosY = 0; + tileY = 0; for (int dy = y; dy < yLimit; dy++) { - int tilePosX = 0; + tileX = 0; for (int dx = 0; dx < halfTileWidth; dx++) { - float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tilePosX, tilePosY, tileX, tileY, tileWidth, tileHeight, pixelsInTile); + float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tileX, tileY, cdfX, cdfY, tileWidth, tileHeight, pixelsInTile); pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); - tilePosX++; + tileX++; } - tilePosY++; + tileY++; } - tileY++; + cdfY++; } // fix right column - tileX = this.Tiles - 2; - tileY = 0; + cdfX = this.Tiles - 2; + cdfY = 0; for (int y = 0; y < source.Height; y += tileHeight) { int yLimit = Math.Min(y + tileHeight, source.Height - 1); - int tilePosY = 0; + tileY = 0; for (int dy = y; dy < yLimit; dy++) { - int tilePosX = halfTileWidth; + tileX = halfTileWidth; for (int dx = source.Width - halfTileWidth; dx < source.Width; dx++) { - float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tilePosX, tilePosY, tileX, tileY, tileWidth, tileHeight, pixelsInTile); + float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tileX, tileY, cdfX, cdfY, tileWidth, tileHeight, pixelsInTile); pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); - tilePosX++; + tileX++; } - tilePosY++; + tileY++; } - tileY++; + cdfY++; } // fix top row - tileX = 0; - tileY = 0; + cdfX = 0; + cdfY = 0; for (int x = 0; x < source.Width; x += tileWidth) { - int tilePosY = 0; + tileY = 0; for (int dy = 0; dy < halfTileHeight; dy++) { - int tilePosX = 0; + tileX = 0; int xLimit = Math.Min(x + tileWidth, source.Width - 1); for (int dx = x; dx < xLimit; dx++) { - float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tilePosX, tilePosY, tileX, tileY, tileWidth, tileHeight, pixelsInTile); + float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tileX, tileY, cdfX, cdfY, tileWidth, tileHeight, pixelsInTile); pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); - tilePosX++; + tileX++; } - tilePosY++; + tileY++; } - tileX++; + cdfX++; } // fix bottom row - tileX = 0; - tileY = 0; + cdfX = 0; + cdfY = 0; for (int x = 0; x < source.Width; x += tileWidth) { - int tilePosY = 0; + tileY = 0; for (int dy = source.Height - halfTileHeight; dy < source.Height; dy++) { - int tilePosX = 0; + tileX = 0; int xLimit = Math.Min(x + tileWidth, source.Width - 1); for (int dx = x; dx < xLimit; dx++) { - float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tilePosX, tilePosY, tileX, tileY, tileWidth, tileHeight, pixelsInTile); + float luminanceEqualized = this.InterpolateBetweenTiles(source[dx, dy], cdfData, dx, dy, tileX, tileY, cdfX, cdfY, tileWidth, tileHeight, pixelsInTile); pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); - tilePosX++; + tileX++; } - tilePosY++; + tileY++; } - tileX++; + cdfX++; } } } - private float InterpolateBetweenTiles(TPixel sourcePixel, CdfData[,] cdfData, int dx, int dy, int tilePosX, int tilePosY, int tileX, int tileY, int tileWidth, int tileHeight, int pixelsInTile) + /// + /// Interpolates between four adjacent tiles. + /// + /// The pixel to remap the grey value from. + /// The pre-computed lookup tables to remap the grey values for each tiles. + /// X index in the image. + /// Y index in the image. + /// X position inside the tile. + /// Y position inside the tile. + /// X index of the top left lookup table to use. + /// Y index of the top left lookup table to use. + /// Width of one tile in pixels. + /// Height of one tile in pixels. + /// Amount of pixels in one tile. + /// A re-mapped grey value. + private float InterpolateBetweenTiles(TPixel sourcePixel, CdfData[,] cdfData, int dx, int dy, int tileX, int tileY, int cdfX, int cdfY, int tileWidth, int tileHeight, int pixelsInTile) { int luminace = this.GetLuminance(sourcePixel, this.LuminanceLevels); - float tx = tilePosX / (float)(tileWidth - 1); - float ty = tilePosY / (float)(tileHeight - 1); + float tx = tileX / (float)(tileWidth - 1); + float ty = tileY / (float)(tileHeight - 1); - int yTop = tileY; + int yTop = cdfY; int yBottom = Math.Min(this.Tiles - 1, yTop + 1); - int xLeft = tileX; + int xLeft = cdfX; int xRight = Math.Min(this.Tiles - 1, xLeft + 1); float cdfLeftTopLuminance = cdfData[xLeft, yTop].RemapGreyValue(luminace, pixelsInTile); diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs index 63546c744d..5226e3f88e 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs @@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization Global, /// - /// Adaptive histogram equalization. + /// Adaptive histogram equalization using a tile interpolation approach. /// - Adaptive, + AdaptiveTileInterpolation, /// /// Adaptive sliding window histogram equalization.