Beispiel #1
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            int sourceWidth     = source.Width;
            int sourceHeight    = source.Height;
            int tileWidth       = (int)MathF.Ceiling(sourceWidth / (float)this.Tiles);
            int tileHeight      = (int)MathF.Ceiling(sourceHeight / (float)this.Tiles);
            int tileCount       = this.Tiles;
            int halfTileWidth   = tileWidth / 2;
            int halfTileHeight  = tileHeight / 2;
            int luminanceLevels = this.LuminanceLevels;

            // The image is split up into tiles. For each tile the cumulative distribution function will be calculated.
            using (var cdfData = new CdfTileData(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels))
            {
                cdfData.CalculateLookupTables(source, this);

                var tileYStartPositions = new List <(int y, int cdfY)>();
                int cdfY   = 0;
                int yStart = halfTileHeight;
                for (int tile = 0; tile < tileCount - 1; tile++)
                {
                    tileYStartPositions.Add((yStart, cdfY));
                    cdfY++;
                    yStart += tileHeight;
                }

                var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source);
                ParallelRowIterator.IterateRowIntervals(
                    this.Configuration,
                    new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count),
                    in operation);

                ref TPixel pixelsBase = ref source.GetPixelReference(0, 0);

                // Fix left column
                ProcessBorderColumn(ref pixelsBase, cdfData, 0, sourceWidth, sourceHeight, this.Tiles, tileHeight, xStart: 0, xEnd: halfTileWidth, luminanceLevels);

                // Fix right column
                int rightBorderStartX = ((this.Tiles - 1) * tileWidth) + halfTileWidth;
                ProcessBorderColumn(ref pixelsBase, cdfData, this.Tiles - 1, sourceWidth, sourceHeight, this.Tiles, tileHeight, xStart: rightBorderStartX, xEnd: sourceWidth, luminanceLevels);

                // Fix top row
                ProcessBorderRow(ref pixelsBase, cdfData, 0, sourceWidth, this.Tiles, tileWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);

                // Fix bottom row
                int bottomBorderStartY = ((this.Tiles - 1) * tileHeight) + halfTileHeight;
                ProcessBorderRow(ref pixelsBase, cdfData, this.Tiles - 1, sourceWidth, this.Tiles, tileWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);

                // Left top corner
                ProcessCornerTile(ref pixelsBase, cdfData, sourceWidth, 0, 0, xStart: 0, xEnd: halfTileWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);

                // Left bottom corner
                ProcessCornerTile(ref pixelsBase, cdfData, sourceWidth, 0, this.Tiles - 1, xStart: 0, xEnd: halfTileWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);

                // Right top corner
                ProcessCornerTile(ref pixelsBase, cdfData, sourceWidth, this.Tiles - 1, 0, xStart: rightBorderStartX, xEnd: sourceWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);

                // Right bottom corner
                ProcessCornerTile(ref pixelsBase, cdfData, sourceWidth, this.Tiles - 1, this.Tiles - 1, xStart: rightBorderStartX, xEnd: sourceWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
            }
 /// <summary>
 /// Processes the part of a corner tile which was previously left out. It consists of 1 / 4 of a tile and does not need interpolation.
 /// </summary>
 /// <param name="source">The source image.</param>
 /// <param name="cdfData">The lookup table to remap the grey values.</param>
 /// <param name="cdfX">The x-position in the CDF lookup map.</param>
 /// <param name="cdfY">The y-position in the CDF lookup map.</param>
 /// <param name="xStart">X start position.</param>
 /// <param name="xEnd">X end position.</param>
 /// <param name="yStart">Y start position.</param>
 /// <param name="yEnd">Y end position.</param>
 /// <param name="luminanceLevels">
 /// The number of different luminance levels. Typical values are 256 for 8-bit grayscale images
 /// or 65536 for 16-bit grayscale images.
 /// </param>
 private static void ProcessCornerTile(
     ImageFrame <TPixel> source,
     CdfTileData cdfData,
     int cdfX,
     int cdfY,
     int xStart,
     int xEnd,
     int yStart,
     int yEnd,
     int luminanceLevels)
 {
     for (int dy = yStart; dy < yEnd; dy++)
     {
         Span <TPixel> rowSpan = source.GetPixelRowSpan(dy);
         for (int dx = xStart; dx < xEnd; dx++)
         {
             ref TPixel pixel = ref rowSpan[dx];
             float      luminanceEqualized = cdfData.RemapGreyValue(cdfX, cdfY, GetLuminance(pixel, luminanceLevels));
             pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W));
         }
     }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            int sourceWidth     = source.Width;
            int sourceHeight    = source.Height;
            int tileWidth       = (int)MathF.Ceiling(sourceWidth / (float)this.Tiles);
            int tileHeight      = (int)MathF.Ceiling(sourceHeight / (float)this.Tiles);
            int tileCount       = this.Tiles;
            int halfTileWidth   = tileWidth / 2;
            int halfTileHeight  = tileHeight / 2;
            int luminanceLevels = this.LuminanceLevels;

            // The image is split up into tiles. For each tile the cumulative distribution function will be calculated.
            using (var cdfData = new CdfTileData(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels))
            {
                cdfData.CalculateLookupTables(source, this);

                var tileYStartPositions = new List <(int y, int cdfY)>();
                int cdfY   = 0;
                int yStart = halfTileHeight;
                for (int tile = 0; tile < tileCount - 1; tile++)
                {
                    tileYStartPositions.Add((yStart, cdfY));
                    cdfY++;
                    yStart += tileHeight;
                }

                Parallel.For(
                    0,
                    tileYStartPositions.Count,
                    new ParallelOptions {
                    MaxDegreeOfParallelism = this.Configuration.MaxDegreeOfParallelism
                },
                    index =>
                {
                    int y     = tileYStartPositions[index].y;
                    int cdfYY = tileYStartPositions[index].cdfY;

                    // It's unfortunate that we have to do this per iteration.
                    ref TPixel sourceBase = ref source.GetPixelReference(0, 0);

                    int cdfX = 0;
                    int x    = halfTileWidth;
                    for (int tile = 0; tile < tileCount - 1; tile++)
                    {
                        int tileY = 0;
                        int yEnd  = Math.Min(y + tileHeight, sourceHeight);
                        int xEnd  = Math.Min(x + tileWidth, sourceWidth);
                        for (int dy = y; dy < yEnd; dy++)
                        {
                            int dyOffSet = dy * sourceWidth;
                            int tileX    = 0;
                            for (int dx = x; dx < xEnd; dx++)
                            {
                                ref TPixel pixel         = ref Unsafe.Add(ref sourceBase, dyOffSet + dx);
                                float luminanceEqualized = InterpolateBetweenFourTiles(
                                    pixel,
                                    cdfData,
                                    tileCount,
                                    tileCount,
                                    tileX,
                                    tileY,
                                    cdfX,
                                    cdfYY,
                                    tileWidth,
                                    tileHeight,
                                    luminanceLevels);

                                pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W));
                                tileX++;
                            }

                            tileY++;
                        }

                        cdfX++;
                        x += tileWidth;
                    }
                });