Пример #1
0
        /// <inheritdoc />
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            QuantizedFrame <TPixel> quantized = this.Quantizer.Quantize(source, this.MaxColors);
            int paletteCount = quantized.Palette.Length - 1;

            using (Buffer2D <TPixel> pixels = source.MemoryManager.Allocate2D <TPixel>(quantized.Width, quantized.Height))
            {
                Parallel.For(
                    0,
                    pixels.Height,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> row = pixels.GetRowSpan(y);
                    int yy            = y * pixels.Width;
                    for (int x = 0; x < pixels.Width; x++)
                    {
                        int i        = x + yy;
                        TPixel color = quantized.Palette[Math.Min(paletteCount, quantized.Pixels[i])];
                        row[x]       = color;
                    }
                });

                Buffer2D <TPixel> .SwapContents(source.PixelBuffer, pixels);
            }
        }
Пример #2
0
        /// <summary>
        /// Applies quantization to the image.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="source">The image this method extends.</param>
        /// <param name="quantizer">The quantizer to apply to perform the operation.</param>
        /// <param name="maxColors">The maximum number of colors to return.</param>
        /// <returns>The <see cref="Image{TPixel}"/>.</returns>
        public static IImageProcessingContext <TPixel> Quantize <TPixel>(this IImageProcessingContext <TPixel> source, IQuantizer <TPixel> quantizer, int maxColors)
            where TPixel : struct, IPixel <TPixel>
        {
            return(source.Apply(img =>
            {
                // TODO : move helper logic into the processor
                QuantizedImage <TPixel> quantized = quantizer.Quantize(img.Frames.RootFrame, maxColors);
                int palleteCount = quantized.Palette.Length - 1;

                using (Buffer2D <TPixel> pixels = source.MemoryManager.Allocate2D <TPixel>(quantized.Width, quantized.Height))
                {
                    Parallel.For(
                        0,
                        pixels.Height,
                        img.GetConfiguration().ParallelOptions,
                        y =>
                    {
                        Span <TPixel> row = pixels.GetRowSpan(y);
                        int yy = y * pixels.Width;
                        for (int x = 0; x < pixels.Width; x++)
                        {
                            int i = x + yy;
                            TPixel color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])];
                            row[x] = color;
                        }
                    });

                    Buffer2D <TPixel> .SwapContents(img.Frames[0].PixelBuffer, pixels);
                }
            }));
        }
Пример #3
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>
        /// <param name="configuration">The configuration.</param>
        private void FlipY(ImageFrame <TPixel> source, Configuration configuration)
        {
            int width     = source.Width;
            int height    = source.Height;
            int halfWidth = (int)Math.Ceiling(width * .5F);

            using (Buffer2D <TPixel> targetPixels = configuration.MemoryManager.Allocate2D <TPixel>(source.Size()))
            {
                Parallel.For(
                    0,
                    height,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(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];
                    }
                });

                Buffer2D <TPixel> .SwapContents(source.PixelBuffer, targetPixels);
            }
        }
Пример #4
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>
        /// <param name="configuration">The configuration.</param>
        private void FlipX(ImageFrame <TPixel> source, Configuration configuration)
        {
            int height     = source.Height;
            int halfHeight = (int)Math.Ceiling(source.Height * .5F);

            using (Buffer2D <TPixel> targetPixels = configuration.MemoryManager.Allocate2D <TPixel>(source.Size()))
            {
                Parallel.For(
                    0,
                    halfHeight,
                    configuration.ParallelOptions,
                    y =>
                {
                    int newY = height - y - 1;
                    Span <TPixel> sourceRow    = source.GetPixelRowSpan(y);
                    Span <TPixel> altSourceRow = source.GetPixelRowSpan(newY);
                    Span <TPixel> targetRow    = targetPixels.GetRowSpan(y);
                    Span <TPixel> altTargetRow = targetPixels.GetRowSpan(newY);

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

                Buffer2D <TPixel> .SwapContents(source.PixelBuffer, targetPixels);
            }
        }
Пример #5
0
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            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 (Buffer2D <TPixel> targetPixels = configuration.MemoryManager.Allocate2D <TPixel>(this.CropRectangle.Size))
            {
                Parallel.For(
                    minY,
                    maxY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(minX);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y - minY);
                    SpanHelper.Copy(sourceRow, targetRow, maxX - minX);
                });

                Buffer2D <TPixel> .SwapContents(source.PixelBuffer, targetPixels);
            }
        }
Пример #6
0
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            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 (Buffer2D <TPixel> targetPixels = configuration.MemoryManager.Allocate2D <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    startY,
                    endY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(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);
                            Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);

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

                                offsetX = offsetX.Clamp(0, maxX);
                                Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply();

                                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));

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

                Buffer2D <TPixel> .SwapContents(source.PixelBuffer, targetPixels);
            }
        }
Пример #7
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            int kernelLength = this.KernelXY.Rows;
            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 (Buffer2D <TPixel> targetPixels = configuration.MemoryManager.Allocate2D <TPixel>(source.Size()))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    startY,
                    endY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(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.GetPixelRowSpan(offsetY);

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

                                offsetX = offsetX.Clamp(0, maxX);

                                Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply();
                                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).UnPremultiply());
                    }
                });

                Buffer2D <TPixel> .SwapContents(source.PixelBuffer, targetPixels);
            }
        }
Пример #8
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration)
        {
            if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width)
            {
                throw new ArgumentOutOfRangeException(nameof(this.BrushSize));
            }

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

            int radius = this.BrushSize >> 1;
            int levels = this.Levels;

            using (Buffer2D <TPixel> targetPixels = configuration.MemoryManager.Allocate2D <TPixel>(source.Size()))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    startY,
                    maxY,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetPixelRowSpan(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.GetPixelRowSpan(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));
                        }
                    }
                });

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