示例#1
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            if (this.CropRectangle == sourceRectangle)
            {
                return;
            }

            int minY = Math.Max(this.CropRectangle.Y, sourceRectangle.Y);
            int maxY = Math.Min(this.CropRectangle.Bottom, sourceRectangle.Bottom);
            int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X);
            int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right);

            using (var targetPixels = new PixelAccessor <TPixel>(this.CropRectangle.Width, this.CropRectangle.Height))
            {
                Parallel.For(
                    minY,
                    maxY,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetRowSpan(minX, y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y - minY);
                    SpanHelper.Copy(sourceRow, targetRow, maxX - minX);
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#2
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            if (this.OptimizedApply(source))
            {
                return;
            }

            int       height = this.CanvasRectangle.Height;
            int       width  = this.CanvasRectangle.Width;
            Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix);

            using (var targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                Parallel.For(
                    0,
                    height,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = 0; x < width; x++)
                    {
                        var transformedPoint = Point.Rotate(new Point(x, y), matrix);

                        if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
                        {
                            targetRow[x] = source[transformedPoint.X, transformedPoint.Y];
                        }
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#3
0
        /// <summary>
        /// Rotates the image 180 degrees clockwise at the centre point.
        /// </summary>
        /// <param name="source">The source image.</param>
        private void Rotate180(ImageBase <TPixel> source)
        {
            int width  = source.Width;
            int height = source.Height;

            using (var targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                Parallel.For(
                    0,
                    height,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(height - y - 1);

                    for (int x = 0; x < width; x++)
                    {
                        targetRow[width - x - 1] = sourceRow[x];
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#4
0
        /// <summary>
        /// Swaps the image at the Y-axis, which goes vertically through the middle
        /// at half of the width of the image.
        /// </summary>
        /// <param name="source">The source image to apply the process to.</param>
        private void FlipY(ImageBase <TPixel> source)
        {
            int width     = source.Width;
            int height    = source.Height;
            int halfWidth = (int)Math.Ceiling(width * .5F);

            using (var targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                Parallel.For(
                    0,
                    height,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = 0; x < halfWidth; x++)
                    {
                        int newX        = width - x - 1;
                        targetRow[x]    = sourceRow[newX];
                        targetRow[newX] = sourceRow[x];
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#5
0
        /// <summary>
        /// Rotates the image 270 degrees clockwise at the centre point.
        /// </summary>
        /// <param name="source">The source image.</param>
        private void Rotate270(ImageBase <TPixel> source)
        {
            int width  = source.Width;
            int height = source.Height;

            using (var targetPixels = new PixelAccessor <TPixel>(height, width))
            {
                using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < width; x++)
                        {
                            int newX = height - y - 1;
                            newX     = height - newX - 1;
                            int newY = width - x - 1;
                            targetPixels[newX, newY] = sourcePixels[x, y];
                        }
                    });
                }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#6
0
        /// <summary>
        /// Swaps the image at the X-axis, which goes horizontally through the middle
        /// at half the height of the image.
        /// </summary>
        /// <param name="source">The source image to apply the process to.</param>
        private void FlipX(ImageBase <TPixel> source)
        {
            int width      = source.Width;
            int height     = source.Height;
            int halfHeight = (int)Math.Ceiling(source.Height * .5F);

            using (PixelAccessor <TPixel> targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                {
                    Parallel.For(
                        0,
                        halfHeight,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < width; x++)
                        {
                            int newY              = height - y - 1;
                            targetPixels[x, y]    = sourcePixels[x, newY];
                            targetPixels[x, newY] = sourcePixels[x, y];
                        }
                    });
                }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#7
0
        /// <summary>
        /// Swaps the image at the Y-axis, which goes vertically through the middle
        /// at half of the width of the image.
        /// </summary>
        /// <param name="source">The source image to apply the process to.</param>
        private void FlipY(ImageBase <TColor> source)
        {
            int width     = source.Width;
            int height    = source.Height;
            int halfWidth = (int)Math.Ceiling(width * .5F);

            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < halfWidth; x++)
                        {
                            int newX              = width - x - 1;
                            targetPixels[x, y]    = sourcePixels[newX, y];
                            targetPixels[newX, y] = sourcePixels[x, y];
                        }
                    });
                }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#8
0
        /// <summary>
        /// Swaps the image at the X-axis, which goes horizontally through the middle
        /// at half the height of the image.
        /// </summary>
        /// <param name="source">The source image to apply the process to.</param>
        private void FlipX(ImageBase <TPixel> source)
        {
            int width      = source.Width;
            int height     = source.Height;
            int halfHeight = (int)Math.Ceiling(source.Height * .5F);

            using (var targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                Parallel.For(
                    0,
                    halfHeight,
                    this.ParallelOptions,
                    y =>
                {
                    int newY = height - y - 1;
                    Span <TPixel> sourceRow    = source.GetRowSpan(y);
                    Span <TPixel> altSourceRow = source.GetRowSpan(newY);
                    Span <TPixel> targetRow    = targetPixels.GetRowSpan(y);
                    Span <TPixel> altTargetRow = targetPixels.GetRowSpan(newY);

                    sourceRow.CopyTo(altTargetRow);
                    altSourceRow.CopyTo(targetRow);
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#9
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            if (this.CropRectangle == sourceRectangle)
            {
                return;
            }

            int minY = Math.Max(this.CropRectangle.Y, sourceRectangle.Y);
            int maxY = Math.Min(this.CropRectangle.Bottom, sourceRectangle.Bottom);
            int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X);
            int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right);

            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(this.CropRectangle.Width, this.CropRectangle.Height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = minX; x < maxX; x++)
                        {
                            targetPixels[x - minX, y - minY] = sourcePixels[x, y];
                        }
                    });
                }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#10
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            int       height = this.CanvasRectangle.Height;
            int       width  = this.CanvasRectangle.Width;
            Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix);

            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < width; x++)
                        {
                            Point transformedPoint = Point.Skew(new Point(x, y), matrix);
                            if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
                            {
                                targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
                            }
                        }
                    });
                }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#11
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            int width  = source.Width;
            int height = source.Height;

            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
            {
                using (PixelAccessor <TColor> firstPassPixels = new PixelAccessor <TColor>(width, height))
                    using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    {
                        this.ApplyConvolution(firstPassPixels, sourcePixels, sourceRectangle, this.KernelX);
                        this.ApplyConvolution(targetPixels, firstPassPixels, sourceRectangle, this.KernelY);
                    }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            int kernelLength = this.KernelXY.Height;
            int radius       = kernelLength >> 1;

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int maxY   = endY - 1;
            int maxX   = endX - 1;

            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(source.Width, source.Height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                {
                    Parallel.For(
                        startY,
                        endY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = startX; x < endX; x++)
                        {
                            float red   = 0;
                            float green = 0;
                            float blue  = 0;

                            // Apply each matrix multiplier to the color components for each pixel.
                            for (int fy = 0; fy < kernelLength; fy++)
                            {
                                int fyr     = fy - radius;
                                int offsetY = y + fyr;

                                offsetY = offsetY.Clamp(0, maxY);

                                for (int fx = 0; fx < kernelLength; fx++)
                                {
                                    int fxr     = fx - radius;
                                    int offsetX = x + fxr;

                                    offsetX = offsetX.Clamp(0, maxX);

                                    Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
                                    currentColor        *= this.KernelXY[fy, fx];

                                    red   += currentColor.X;
                                    green += currentColor.Y;
                                    blue  += currentColor.Z;
                                }
                            }

                            TColor packed = default(TColor);
                            packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
                            targetPixels[x, y] = packed;
                        }
                    });
                }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            int kernelYHeight = this.KernelY.Height;
            int kernelYWidth  = this.KernelY.Width;
            int kernelXHeight = this.KernelX.Height;
            int kernelXWidth  = this.KernelX.Width;
            int radiusY       = kernelYHeight >> 1;
            int radiusX       = kernelXWidth >> 1;

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int maxY   = endY - 1;
            int maxX   = endX - 1;

            using (PixelAccessor <TPixel> targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
                using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                {
                    sourcePixels.CopyTo(targetPixels);

                    Parallel.For(
                        startY,
                        endY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = startX; x < endX; x++)
                        {
                            float rX = 0;
                            float gX = 0;
                            float bX = 0;
                            float rY = 0;
                            float gY = 0;
                            float bY = 0;

                            // Apply each matrix multiplier to the color components for each pixel.
                            for (int fy = 0; fy < kernelYHeight; fy++)
                            {
                                int fyr     = fy - radiusY;
                                int offsetY = y + fyr;

                                offsetY = offsetY.Clamp(0, maxY);

                                for (int fx = 0; fx < kernelXWidth; fx++)
                                {
                                    int fxr     = fx - radiusX;
                                    int offsetX = x + fxr;

                                    offsetX = offsetX.Clamp(0, maxX);

                                    Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();

                                    if (fy < kernelXHeight)
                                    {
                                        Vector4 kx = this.KernelX[fy, fx] * currentColor;
                                        rX        += kx.X;
                                        gX        += kx.Y;
                                        bX        += kx.Z;
                                    }

                                    if (fx < kernelYWidth)
                                    {
                                        Vector4 ky = this.KernelY[fy, fx] * currentColor;
                                        rY        += ky.X;
                                        gY        += ky.Y;
                                        bY        += ky.Z;
                                    }
                                }
                            }

                            float red   = MathF.Sqrt((rX * rX) + (rY * rY));
                            float green = MathF.Sqrt((gX * gX) + (gY * gY));
                            float blue  = MathF.Sqrt((bX * bX) + (bY * bY));

                            TPixel packed = default(TPixel);
                            packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
                            targetPixels[x, y] = packed;
                        }
                    });

                    source.SwapPixelsBuffers(targetPixels);
                }
        }
示例#14
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int radius = this.BrushSize >> 1;
            int levels = this.Levels;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            using (PixelAccessor <TPixel> targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
                using (PixelAccessor <TPixel> sourcePixels = source.Lock())
                {
                    sourcePixels.CopyTo(targetPixels);

                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = startX; x < endX; x++)
                        {
                            int maxIntensity = 0;
                            int maxIndex     = 0;

                            int[] intensityBin = new int[levels];
                            float[] redBin     = new float[levels];
                            float[] blueBin    = new float[levels];
                            float[] greenBin   = new float[levels];

                            for (int fy = 0; fy <= radius; fy++)
                            {
                                int fyr     = fy - radius;
                                int offsetY = y + fyr;

                                // Skip the current row
                                if (offsetY < minY)
                                {
                                    continue;
                                }

                                // Outwith the current bounds so break.
                                if (offsetY >= maxY)
                                {
                                    break;
                                }

                                for (int fx = 0; fx <= radius; fx++)
                                {
                                    int fxr     = fx - radius;
                                    int offsetX = x + fxr;

                                    // Skip the column
                                    if (offsetX < 0)
                                    {
                                        continue;
                                    }

                                    if (offsetX < maxX)
                                    {
                                        // ReSharper disable once AccessToDisposedClosure
                                        Vector4 color = sourcePixels[offsetX, offsetY].ToVector4();

                                        float sourceRed   = color.X;
                                        float sourceBlue  = color.Z;
                                        float sourceGreen = color.Y;

                                        int currentIntensity = (int)Math.Round((sourceBlue + sourceGreen + sourceRed) / 3.0 * (levels - 1));

                                        intensityBin[currentIntensity] += 1;
                                        blueBin[currentIntensity]      += sourceBlue;
                                        greenBin[currentIntensity]     += sourceGreen;
                                        redBin[currentIntensity]       += sourceRed;

                                        if (intensityBin[currentIntensity] > maxIntensity)
                                        {
                                            maxIntensity = intensityBin[currentIntensity];
                                            maxIndex     = currentIntensity;
                                        }
                                    }
                                }

                                float red   = MathF.Abs(redBin[maxIndex] / maxIntensity);
                                float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
                                float blue  = MathF.Abs(blueBin[maxIndex] / maxIntensity);

                                TPixel packed = default(TPixel);
                                packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
                                targetPixels[x, y] = packed;
                            }
                        }
                    });

                    source.SwapPixelsBuffers(targetPixels);
                }
        }
示例#15
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int size   = this.Value;
            int offset = this.Value / 2;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            // Get the range on the y-plane to choose from.
            IEnumerable <int> range = EnumerableExtensions.SteppedRange(minY, i => i < maxY, size);

            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(source.Width, source.Height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                {
                    Parallel.ForEach(
                        range,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY  = y - startY;
                        int offsetPy = offset;

                        for (int x = minX; x < maxX; x += size)
                        {
                            int offsetX  = x - startX;
                            int offsetPx = offset;

                            // Make sure that the offset is within the boundary of the image.
                            while (offsetY + offsetPy >= maxY)
                            {
                                offsetPy--;
                            }

                            while (x + offsetPx >= maxX)
                            {
                                offsetPx--;
                            }

                            // Get the pixel color in the centre of the soon to be pixelated area.
                            // ReSharper disable AccessToDisposedClosure
                            TColor pixel = sourcePixels[offsetX + offsetPx, offsetY + offsetPy];

                            // For each pixel in the pixelate size, set it to the centre color.
                            for (int l = offsetY; l < offsetY + size && l < maxY; l++)
                            {
                                for (int k = offsetX; k < offsetX + size && k < maxX; k++)
                                {
                                    targetPixels[k, l] = pixel;
                                }
                            }
                        }
                    });

                    source.SwapPixelsBuffers(targetPixels);
                }
            }
        }
示例#16
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int radius = this.BrushSize >> 1;
            int levels = this.Levels;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    minY,
                    maxY,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        int maxIntensity = 0;
                        int maxIndex     = 0;

                        int[] intensityBin = new int[levels];
                        float[] redBin     = new float[levels];
                        float[] blueBin    = new float[levels];
                        float[] greenBin   = new float[levels];

                        for (int fy = 0; fy <= radius; fy++)
                        {
                            int fyr     = fy - radius;
                            int offsetY = y + fyr;

                            offsetY = offsetY.Clamp(0, maxY);

                            Span <TPixel> sourceOffsetRow = source.GetRowSpan(offsetY);

                            for (int fx = 0; fx <= radius; fx++)
                            {
                                int fxr     = fx - radius;
                                int offsetX = x + fxr;
                                offsetX     = offsetX.Clamp(0, maxX);

                                var vector = sourceOffsetRow[offsetX].ToVector4();

                                float sourceRed   = vector.X;
                                float sourceBlue  = vector.Z;
                                float sourceGreen = vector.Y;

                                int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));

                                intensityBin[currentIntensity] += 1;
                                blueBin[currentIntensity]      += sourceBlue;
                                greenBin[currentIntensity]     += sourceGreen;
                                redBin[currentIntensity]       += sourceRed;

                                if (intensityBin[currentIntensity] > maxIntensity)
                                {
                                    maxIntensity = intensityBin[currentIntensity];
                                    maxIndex     = currentIntensity;
                                }
                            }

                            float red   = MathF.Abs(redBin[maxIndex] / maxIntensity);
                            float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
                            float blue  = MathF.Abs(blueBin[maxIndex] / maxIntensity);

                            ref TPixel pixel = ref targetRow[x];
                            pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                        }
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#17
0
        /// <inheritdoc/>
        protected override unsafe void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            // Jump out, we'll deal with that later.
            if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
            {
                return;
            }

            int width   = this.Width;
            int height  = this.Height;
            int sourceX = sourceRectangle.X;
            int sourceY = sourceRectangle.Y;
            int startY  = this.ResizeRectangle.Y;
            int endY    = this.ResizeRectangle.Bottom;
            int startX  = this.ResizeRectangle.X;
            int endX    = this.ResizeRectangle.Right;

            int minX = Math.Max(0, startX);
            int maxX = Math.Min(width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(height, endY);

            if (this.Sampler is NearestNeighborResampler)
            {
                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;

                using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
                {
                    using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    {
                        Parallel.For(
                            minY,
                            maxY,
                            this.ParallelOptions,
                            y =>
                        {
                            // Y coordinates of source points
                            int originY = (int)(((y - startY) * heightFactor) + sourceY);

                            for (int x = minX; x < maxX; x++)
                            {
                                // X coordinates of source points
                                targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY];
                            }
                        });
                    }

                    // Break out now.
                    source.SwapPixelsBuffers(targetPixels);
                    return;
                }
            }

            // Interpolate the image using the calculated weights.
            // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
            // First process the columns. Since we are not using multiple threads startY and endY
            // are the upper and lower bounds of the source rectangle.

            // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    using (Buffer2D <Vector4> firstPassPixels = new Buffer2D <Vector4>(width, source.Height))
                    {
                        firstPassPixels.Clear();

                        Parallel.For(
                            0,
                            sourceRectangle.Bottom,
                            this.ParallelOptions,
                            y =>
                        {
                            // TODO: Without Parallel.For() this buffer object could be reused:
                            using (Buffer <Vector4> tempRowBuffer = new Buffer <Vector4>(sourcePixels.Width))
                            {
                                BufferSpan <TColor> sourceRow = sourcePixels.GetRowSpan(y);

                                BulkPixelOperations <TColor> .Instance.ToVector4(
                                    sourceRow,
                                    tempRowBuffer,
                                    sourceRow.Length);

                                if (this.Compand)
                                {
                                    for (int x = minX; x < maxX; x++)
                                    {
                                        WeightsWindow window  = this.HorizontalWeights.Weights[x - startX];
                                        firstPassPixels[x, y] = window.ComputeExpandedWeightedRowSum(tempRowBuffer);
                                    }
                                }
                                else
                                {
                                    for (int x = minX; x < maxX; x++)
                                    {
                                        WeightsWindow window  = this.HorizontalWeights.Weights[x - startX];
                                        firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer);
                                    }
                                }
                            }
                        });

                        // Now process the rows.
                        Parallel.For(
                            minY,
                            maxY,
                            this.ParallelOptions,
                            y =>
                        {
                            // Ensure offsets are normalised for cropping and padding.
                            WeightsWindow window = this.VerticalWeights.Weights[y - startY];

                            if (this.Compand)
                            {
                                for (int x = 0; x < width; x++)
                                {
                                    // Destination color components
                                    Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);
                                    destination         = destination.Compress();
                                    TColor d            = default(TColor);
                                    d.PackFromVector4(destination);
                                    targetPixels[x, y] = d;
                                }
                            }
                            else
                            {
                                for (int x = 0; x < width; x++)
                                {
                                    // Destination color components
                                    Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);

                                    TColor d = default(TColor);
                                    d.PackFromVector4(destination);
                                    targetPixels[x, y] = d;
                                }
                            }
                        });
                    }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#18
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle)
        {
            // Jump out, we'll deal with that later.
            if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
            {
                return;
            }

            int width  = this.Width;
            int height = this.Height;
            int startY = this.ResizeRectangle.Y;
            int endY   = this.ResizeRectangle.Bottom;
            int startX = this.ResizeRectangle.X;
            int endX   = this.ResizeRectangle.Right;

            int minX = Math.Max(0, startX);
            int maxX = Math.Min(width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(height, endY);

            if (this.Sampler is NearestNeighborResampler)
            {
                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;

                using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
                {
                    using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    {
                        Parallel.For(
                            minY,
                            maxY,
                            this.ParallelOptions,
                            y =>
                        {
                            // Y coordinates of source points
                            int originY = (int)((y - startY) * heightFactor);

                            for (int x = minX; x < maxX; x++)
                            {
                                // X coordinates of source points
                                targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
                            }
                        });
                    }

                    // Break out now.
                    source.SwapPixelsBuffers(targetPixels);
                    return;
                }
            }

            // Interpolate the image using the calculated weights.
            // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
            // First process the columns. Since we are not using multiple threads startY and endY
            // are the upper and lower bounds of the source rectangle.
            using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height))
            {
                using (PixelAccessor <TColor> sourcePixels = source.Lock())
                    using (PixelAccessor <TColor> firstPassPixels = new PixelAccessor <TColor>(width, source.Height))
                    {
                        Parallel.For(
                            0,
                            sourceRectangle.Height,
                            this.ParallelOptions,
                            y =>
                        {
                            for (int x = minX; x < maxX; x++)
                            {
                                // Ensure offsets are normalised for cropping and padding.
                                Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;

                                // Destination color components
                                Vector4 destination = Vector4.Zero;

                                for (int i = 0; i < horizontalValues.Length; i++)
                                {
                                    Weight xw    = horizontalValues[i];
                                    destination += sourcePixels[xw.Index, y].ToVector4() * xw.Value;
                                }

                                TColor d = default(TColor);
                                d.PackFromVector4(destination);
                                firstPassPixels[x, y] = d;
                            }
                        });

                        // Now process the rows.
                        Parallel.For(
                            minY,
                            maxY,
                            this.ParallelOptions,
                            y =>
                        {
                            // Ensure offsets are normalised for cropping and padding.
                            Weight[] verticalValues = this.VerticalWeights[y - startY].Values;

                            for (int x = 0; x < width; x++)
                            {
                                // Destination color components
                                Vector4 destination = Vector4.Zero;

                                for (int i = 0; i < verticalValues.Length; i++)
                                {
                                    Weight yw    = verticalValues[i];
                                    destination += firstPassPixels[x, yw.Index].ToVector4() * yw.Value;
                                }

                                TColor d = default(TColor);
                                d.PackFromVector4(destination);
                                targetPixels[x, y] = d;
                            }
                        });
                    }

                source.SwapPixelsBuffers(targetPixels);
            }
        }
示例#19
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
        {
            int kernelLength = this.KernelXY.Height;
            int radius = kernelLength >> 1;

            int startY = sourceRectangle.Y;
            int endY = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX = sourceRectangle.Right;
            int maxY = endY - 1;
            int maxX = endX - 1;

            using (var targetPixels = new PixelAccessor<TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                 startY,
                 endY,
                 this.ParallelOptions,
                 y =>
                 {
                     Span<TPixel> sourceRow = source.GetRowSpan(y);
                     Span<TPixel> targetRow = targetPixels.GetRowSpan(y);

                     for (int x = startX; x < endX; x++)
                     {
                         float red = 0;
                         float green = 0;
                         float blue = 0;

                         // Apply each matrix multiplier to the color components for each pixel.
                         for (int fy = 0; fy < kernelLength; fy++)
                         {
                             int fyr = fy - radius;
                             int offsetY = y + fyr;

                             offsetY = offsetY.Clamp(0, maxY);
                             Span<TPixel> sourceOffsetRow = source.GetRowSpan(offsetY);

                             for (int fx = 0; fx < kernelLength; fx++)
                             {
                                 int fxr = fx - radius;
                                 int offsetX = x + fxr;

                                 offsetX = offsetX.Clamp(0, maxX);

                                 var currentColor = sourceOffsetRow[offsetX].ToVector4();
                                 currentColor *= this.KernelXY[fy, fx];

                                 red += currentColor.X;
                                 green += currentColor.Y;
                                 blue += currentColor.Z;
                             }
                         }

                         ref TPixel pixel = ref targetRow[x];
                         pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                     }
                 });

                source.SwapPixelsBuffers(targetPixels);
            }
        }