|
|
@ -94,96 +94,94 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// fix left column
|
|
|
// fix left column
|
|
|
cdfX = 0; |
|
|
this.ProcessBorderColumn(source, pixels, cdfData, 0, tileWidth, tileHeight, xStart: 0, xEnd: halfTileWidth); |
|
|
cdfY = 0; |
|
|
|
|
|
for (int y = halfTileWidth; y < source.Height - halfTileWidth; y += tileHeight) |
|
|
|
|
|
{ |
|
|
|
|
|
int yLimit = Math.Min(y + tileHeight, source.Height - 1); |
|
|
|
|
|
tileY = 0; |
|
|
|
|
|
for (int dy = y; dy < yLimit; dy++) |
|
|
|
|
|
{ |
|
|
|
|
|
tileX = 0; |
|
|
|
|
|
for (int dx = 0; dx < halfTileWidth; dx++) |
|
|
|
|
|
{ |
|
|
|
|
|
float luminanceEqualized = this.InterpolateBetweenTwoTiles(source[dx, dy], cdfData[cdfX, cdfY], cdfData[cdfX, cdfY + 1], tileY, tileHeight, pixelsInTile); |
|
|
|
|
|
pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); |
|
|
|
|
|
tileX++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tileY++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cdfY++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// fix right column
|
|
|
// fix right column
|
|
|
cdfX = this.Tiles - 1; |
|
|
this.ProcessBorderColumn(source, pixels, cdfData, this.Tiles - 1, tileWidth, tileHeight, xStart: source.Width - halfTileWidth, xEnd: source.Width); |
|
|
cdfY = 0; |
|
|
|
|
|
for (int y = halfTileWidth; y < source.Height - halfTileWidth; y += tileHeight) |
|
|
|
|
|
{ |
|
|
|
|
|
int yLimit = Math.Min(y + tileHeight, source.Height - 1); |
|
|
|
|
|
tileY = 0; |
|
|
|
|
|
for (int dy = y; dy < yLimit; dy++) |
|
|
|
|
|
{ |
|
|
|
|
|
tileX = halfTileWidth; |
|
|
|
|
|
for (int dx = source.Width - halfTileWidth; dx < source.Width; dx++) |
|
|
|
|
|
{ |
|
|
|
|
|
float luminanceEqualized = this.InterpolateBetweenTwoTiles(source[dx, dy], cdfData[cdfX, cdfY], cdfData[cdfX, cdfY + 1], tileY, tileHeight, pixelsInTile); |
|
|
|
|
|
pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); |
|
|
|
|
|
tileX++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tileY++; |
|
|
// fix top row
|
|
|
} |
|
|
this.ProcessBorderRow(source, pixels, cdfData, 0, tileWidth, tileHeight, yStart: 0, yEnd: halfTileHeight); |
|
|
|
|
|
|
|
|
cdfY++; |
|
|
// fix bottom row
|
|
|
} |
|
|
this.ProcessBorderRow(source, pixels, cdfData, this.Tiles - 1, tileWidth, tileHeight, yStart: source.Height - halfTileHeight, yEnd: source.Height); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// fix top row
|
|
|
/// <summary>
|
|
|
cdfX = 0; |
|
|
/// Processes a border column of the image which is half the size of the tile width.
|
|
|
cdfY = 0; |
|
|
/// </summary>
|
|
|
for (int x = halfTileWidth; x < source.Width - halfTileWidth; x += tileWidth) |
|
|
/// <param name="source">The source image.</param>
|
|
|
|
|
|
/// <param name="pixels">The output pixels.</param>
|
|
|
|
|
|
/// <param name="cdfData">The pre-computed lookup tables to remap the grey values for each tiles.</param>
|
|
|
|
|
|
/// <param name="cdfX">The X index of the lookup table to use.</param>
|
|
|
|
|
|
/// <param name="tileWidth">The width of a tile.</param>
|
|
|
|
|
|
/// <param name="tileHeight">The height of a tile.</param>
|
|
|
|
|
|
/// <param name="xStart">X start position in the image.</param>
|
|
|
|
|
|
/// <param name="xEnd">X end position of the image.</param>
|
|
|
|
|
|
private void ProcessBorderColumn(ImageFrame<TPixel> source, Span<TPixel> pixels, CdfData[,] cdfData, int cdfX, int tileWidth, int tileHeight, int xStart, int xEnd) |
|
|
|
|
|
{ |
|
|
|
|
|
int halfTileWidth = tileWidth / 2; |
|
|
|
|
|
int halfTileHeight = tileHeight / 2; |
|
|
|
|
|
int pixelsInTile = tileWidth * tileHeight; |
|
|
|
|
|
|
|
|
|
|
|
int cdfY = 0; |
|
|
|
|
|
for (int y = halfTileWidth; y < source.Height - halfTileWidth; y += tileHeight) |
|
|
|
|
|
{ |
|
|
|
|
|
int yLimit = Math.Min(y + tileHeight, source.Height - 1); |
|
|
|
|
|
int tileY = 0; |
|
|
|
|
|
for (int dy = y; dy < yLimit; dy++) |
|
|
{ |
|
|
{ |
|
|
tileY = 0; |
|
|
int tileX = halfTileWidth; |
|
|
for (int dy = 0; dy < halfTileHeight; dy++) |
|
|
for (int dx = xStart; dx < xEnd; dx++) |
|
|
{ |
|
|
{ |
|
|
tileX = 0; |
|
|
float luminanceEqualized = this.InterpolateBetweenTwoTiles(source[dx, dy], cdfData[cdfX, cdfY], cdfData[cdfX, cdfY + 1], tileY, tileHeight, pixelsInTile); |
|
|
int xLimit = Math.Min(x + tileWidth, source.Width - 1); |
|
|
pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); |
|
|
for (int dx = x; dx < xLimit; dx++) |
|
|
tileX++; |
|
|
{ |
|
|
|
|
|
float luminanceEqualized = this.InterpolateBetweenTwoTiles(source[dx, dy], cdfData[cdfX, cdfY], cdfData[cdfX + 1, cdfY], tileX, tileWidth, pixelsInTile); |
|
|
|
|
|
pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); |
|
|
|
|
|
tileX++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tileY++; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
cdfX++; |
|
|
tileY++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// fix bottom row
|
|
|
cdfY++; |
|
|
cdfX = 0; |
|
|
} |
|
|
cdfY = this.Tiles - 1; |
|
|
} |
|
|
for (int x = halfTileWidth; x < source.Width - halfTileWidth; x += tileWidth) |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Processes a border row of the image which is half of the size of the tile height.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="source">The source image.</param>
|
|
|
|
|
|
/// <param name="pixels">The output pixels.</param>
|
|
|
|
|
|
/// <param name="cdfData">The pre-computed lookup tables to remap the grey values for each tiles.</param>
|
|
|
|
|
|
/// <param name="cdfY">The Y index of the lookup table to use.</param>
|
|
|
|
|
|
/// <param name="tileWidth">The width of a tile.</param>
|
|
|
|
|
|
/// <param name="tileHeight">The height of a tile.</param>
|
|
|
|
|
|
/// <param name="yStart">Y start position in the image.</param>
|
|
|
|
|
|
/// <param name="yEnd">Y end position of the image.</param>
|
|
|
|
|
|
private void ProcessBorderRow(ImageFrame<TPixel> source, Span<TPixel> pixels, CdfData[,] cdfData, int cdfY, int tileWidth, int tileHeight, int yStart, int yEnd) |
|
|
|
|
|
{ |
|
|
|
|
|
int halfTileWidth = tileWidth / 2; |
|
|
|
|
|
int halfTileHeight = tileHeight / 2; |
|
|
|
|
|
int pixelsInTile = tileWidth * tileHeight; |
|
|
|
|
|
|
|
|
|
|
|
int cdfX = 0; |
|
|
|
|
|
for (int x = halfTileWidth; x < source.Width - halfTileWidth; x += tileWidth) |
|
|
|
|
|
{ |
|
|
|
|
|
int tileY = 0; |
|
|
|
|
|
for (int dy = yStart; dy < yEnd; dy++) |
|
|
{ |
|
|
{ |
|
|
tileY = 0; |
|
|
int tileX = 0; |
|
|
for (int dy = source.Height - halfTileHeight; dy < source.Height; dy++) |
|
|
int xLimit = Math.Min(x + tileWidth, source.Width - 1); |
|
|
|
|
|
for (int dx = x; dx < xLimit; dx++) |
|
|
{ |
|
|
{ |
|
|
tileX = 0; |
|
|
float luminanceEqualized = this.InterpolateBetweenTwoTiles(source[dx, dy], cdfData[cdfX, cdfY], cdfData[cdfX + 1, cdfY], tileX, tileWidth, pixelsInTile); |
|
|
int xLimit = Math.Min(x + tileWidth, source.Width - 1); |
|
|
pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); |
|
|
for (int dx = x; dx < xLimit; dx++) |
|
|
tileX++; |
|
|
{ |
|
|
|
|
|
float luminanceEqualized = this.InterpolateBetweenTwoTiles(source[dx, dy], cdfData[cdfX, cdfY], cdfData[cdfX + 1, cdfY], tileX, tileWidth, pixelsInTile); |
|
|
|
|
|
pixels[(dy * source.Width) + dx].PackFromVector4(new Vector4(luminanceEqualized)); |
|
|
|
|
|
tileX++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tileY++; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
cdfX++; |
|
|
tileY++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cdfX++; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|