Esempio n. 1
0
 public SlidingWindowOperation(
     Configuration configuration,
     AdaptiveHistogramEqualizationSlidingWindowProcessor <TPixel> processor,
     ImageFrame <TPixel> source,
     MemoryAllocator memoryAllocator,
     Buffer2D <TPixel> targetPixels,
     SlidingWindowInfos swInfos,
     int yStart,
     int yEnd,
     bool useFastPath)
 {
     this.configuration   = configuration;
     this.processor       = processor;
     this.source          = source;
     this.memoryAllocator = memoryAllocator;
     this.targetPixels    = targetPixels;
     this.swInfos         = swInfos;
     this.yStart          = yStart;
     this.yEnd            = yEnd;
     this.useFastPath     = useFastPath;
 }
        /// <summary>
        /// Applies the sliding window equalization to one column of the image. The window is moved from top to bottom.
        /// Moving the window one pixel down requires to remove one row from the top of the window from the histogram and
        /// adding a new row at the bottom.
        /// </summary>
        /// <param name="source">The source image.</param>
        /// <param name="memoryAllocator">The memory allocator.</param>
        /// <param name="targetPixels">The target pixels.</param>
        /// <param name="swInfos"><see cref="SlidingWindowInfos"/> about the sliding window dimensions.</param>
        /// <param name="yStart">The y start position.</param>
        /// <param name="yEnd">The y end position.</param>
        /// <param name="useFastPath">if set to true the borders of the image will not be checked.</param>
        /// <param name="configuration">The configuration.</param>
        /// <returns>Action Delegate.</returns>
        private Action <int> ProcessSlidingWindow(
            ImageFrame <TPixel> source,
            MemoryAllocator memoryAllocator,
            Buffer2D <TPixel> targetPixels,
            SlidingWindowInfos swInfos,
            int yStart,
            int yEnd,
            bool useFastPath,
            Configuration configuration)
        {
            return(x =>
            {
                using (IMemoryOwner <int> histogramBuffer = memoryAllocator.Allocate <int>(this.LuminanceLevels, AllocationOptions.Clean))
                    using (IMemoryOwner <int> histogramBufferCopy = memoryAllocator.Allocate <int>(this.LuminanceLevels, AllocationOptions.Clean))
                        using (IMemoryOwner <int> cdfBuffer = memoryAllocator.Allocate <int>(this.LuminanceLevels, AllocationOptions.Clean))
                            using (IMemoryOwner <Vector4> pixelRowBuffer = memoryAllocator.Allocate <Vector4>(swInfos.TileWidth, AllocationOptions.Clean))
                            {
                                Span <int> histogram = histogramBuffer.GetSpan();
                                ref int histogramBase = ref MemoryMarshal.GetReference(histogram);

                                Span <int> histogramCopy = histogramBufferCopy.GetSpan();
                                ref int histogramCopyBase = ref MemoryMarshal.GetReference(histogramCopy);

                                ref int cdfBase = ref MemoryMarshal.GetReference(cdfBuffer.GetSpan());
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            MemoryAllocator memoryAllocator = this.Configuration.MemoryAllocator;

            var parallelOptions = new ParallelOptions {
                MaxDegreeOfParallelism = this.Configuration.MaxDegreeOfParallelism
            };
            int tileWidth          = source.Width / this.Tiles;
            int tileHeight         = tileWidth;
            int pixelInTile        = tileWidth * tileHeight;
            int halfTileHeight     = tileHeight / 2;
            int halfTileWidth      = halfTileHeight;
            var slidingWindowInfos = new SlidingWindowInfos(tileWidth, tileHeight, halfTileWidth, halfTileHeight, pixelInTile);

            using (Buffer2D <TPixel> targetPixels = this.Configuration.MemoryAllocator.Allocate2D <TPixel>(source.Width, source.Height))
            {
                // Process the inner tiles, which do not require to check the borders.
                Parallel.For(
                    halfTileWidth,
                    source.Width - halfTileWidth,
                    parallelOptions,
                    this.ProcessSlidingWindow(
                        source,
                        memoryAllocator,
                        targetPixels,
                        slidingWindowInfos,
                        yStart: halfTileHeight,
                        yEnd: source.Height - halfTileHeight,
                        useFastPath: true,
                        this.Configuration));

                // Process the left border of the image.
                Parallel.For(
                    0,
                    halfTileWidth,
                    parallelOptions,
                    this.ProcessSlidingWindow(
                        source,
                        memoryAllocator,
                        targetPixels,
                        slidingWindowInfos,
                        yStart: 0,
                        yEnd: source.Height,
                        useFastPath: false,
                        this.Configuration));

                // Process the right border of the image.
                Parallel.For(
                    source.Width - halfTileWidth,
                    source.Width,
                    parallelOptions,
                    this.ProcessSlidingWindow(
                        source,
                        memoryAllocator,
                        targetPixels,
                        slidingWindowInfos,
                        yStart: 0,
                        yEnd: source.Height,
                        useFastPath: false,
                        this.Configuration));

                // Process the top border of the image.
                Parallel.For(
                    halfTileWidth,
                    source.Width - halfTileWidth,
                    parallelOptions,
                    this.ProcessSlidingWindow(
                        source,
                        memoryAllocator,
                        targetPixels,
                        slidingWindowInfos,
                        yStart: 0,
                        yEnd: halfTileHeight,
                        useFastPath: false,
                        this.Configuration));

                // Process the bottom border of the image.
                Parallel.For(
                    halfTileWidth,
                    source.Width - halfTileWidth,
                    parallelOptions,
                    this.ProcessSlidingWindow(
                        source,
                        memoryAllocator,
                        targetPixels,
                        slidingWindowInfos,
                        yStart: source.Height - halfTileHeight,
                        yEnd: source.Height,
                        useFastPath: false,
                        this.Configuration));

                Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels);
            }
        }
Esempio n. 4
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            MemoryAllocator memoryAllocator = this.Configuration.MemoryAllocator;

            var parallelOptions = new ParallelOptions {
                MaxDegreeOfParallelism = this.Configuration.MaxDegreeOfParallelism
            };
            int tileWidth          = source.Width / this.Tiles;
            int tileHeight         = tileWidth;
            int pixelInTile        = tileWidth * tileHeight;
            int halfTileHeight     = tileHeight / 2;
            int halfTileWidth      = halfTileHeight;
            var slidingWindowInfos = new SlidingWindowInfos(tileWidth, tileHeight, halfTileWidth, halfTileHeight, pixelInTile);

            // TODO: If the process was able to be switched to operate in parallel rows instead of columns
            // then we could take advantage of batching and allocate per-row buffers only once per batch.
            using Buffer2D <TPixel> targetPixels = this.Configuration.MemoryAllocator.Allocate2D <TPixel>(source.Width, source.Height);

            // Process the inner tiles, which do not require to check the borders.
            var innerOperation = new SlidingWindowOperation(
                this.Configuration,
                this,
                source,
                memoryAllocator,
                targetPixels,
                slidingWindowInfos,
                yStart: halfTileHeight,
                yEnd: source.Height - halfTileHeight,
                useFastPath: true);

            Parallel.For(
                halfTileWidth,
                source.Width - halfTileWidth,
                parallelOptions,
                innerOperation.Invoke);

            // Process the left border of the image.
            var leftBorderOperation = new SlidingWindowOperation(
                this.Configuration,
                this,
                source,
                memoryAllocator,
                targetPixels,
                slidingWindowInfos,
                yStart: 0,
                yEnd: source.Height,
                useFastPath: false);

            Parallel.For(
                0,
                halfTileWidth,
                parallelOptions,
                leftBorderOperation.Invoke);

            // Process the right border of the image.
            var rightBorderOperation = new SlidingWindowOperation(
                this.Configuration,
                this,
                source,
                memoryAllocator,
                targetPixels,
                slidingWindowInfos,
                yStart: 0,
                yEnd: source.Height,
                useFastPath: false);

            Parallel.For(
                source.Width - halfTileWidth,
                source.Width,
                parallelOptions,
                rightBorderOperation.Invoke);

            // Process the top border of the image.
            var topBorderOperation = new SlidingWindowOperation(
                this.Configuration,
                this,
                source,
                memoryAllocator,
                targetPixels,
                slidingWindowInfos,
                yStart: 0,
                yEnd: halfTileHeight,
                useFastPath: false);

            Parallel.For(
                halfTileWidth,
                source.Width - halfTileWidth,
                parallelOptions,
                topBorderOperation.Invoke);

            // Process the bottom border of the image.
            var bottomBorderOperation = new SlidingWindowOperation(
                this.Configuration,
                this,
                source,
                memoryAllocator,
                targetPixels,
                slidingWindowInfos,
                yStart: source.Height - halfTileHeight,
                yEnd: source.Height,
                useFastPath: false);

            Parallel.For(
                halfTileWidth,
                source.Width - halfTileWidth,
                parallelOptions,
                bottomBorderOperation.Invoke);

            Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels);
        }