示例#1
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);
            }
        }
示例#2
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);
            }
        }
示例#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
        /// <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;
            TPixel  glowColor   = this.GlowColor;
            Vector2 centre      = Rectangle.Center(sourceRectangle);
            float   maxDistance = this.Radius > 0 ? MathF.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;

            // 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;
            }

            int width = maxX - minX;

            using (var rowColors = new Buffer <TPixel>(width))
            {
                for (int i = 0; i < width; i++)
                {
                    rowColors[i] = glowColor;
                }

                Parallel.For(
                    minY,
                    maxY,
                    this.ParallelOptions,
                    y =>
                {
                    using (var amounts = new Buffer <float>(width))
                    {
                        int offsetY = y - startY;
                        int offsetX = minX - startX;
                        for (int i = 0; i < width; i++)
                        {
                            float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY));
                            amounts[i]     = (this.options.BlendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1);
                        }

                        Span <TPixel> destination = source.GetRowSpan(offsetY).Slice(offsetX, width);

                        this.blender.Blend(destination, destination, rowColors, amounts);
                    }
                });
            }
        }
        /// <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;

            // 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;
            }

            Matrix4x4 matrix  = this.Matrix;
            bool      compand = this.Compand;

            using (PixelAccessor <TPixel> sourcePixels = source.Lock())
            {
                Parallel.For(
                    minY,
                    maxY,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> row = source.GetRowSpan(y - startY);

                    for (int x = minX; x < maxX; x++)
                    {
                        ref TPixel pixel = ref row[x - startX];
                        var vector       = pixel.ToVector4();

                        if (compand)
                        {
                            vector = vector.Expand();
                        }

                        vector = Vector4.Transform(vector, matrix);
                        pixel.PackFromVector4(compand ? vector.Compress() : vector);
                    }
                });
            }
        }
        /// <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;

            // 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;
            }

            int width = maxX - minX;

            using (var colors = new Buffer <TPixel>(width))
                using (var amount = new Buffer <float>(width))
                {
                    for (int i = 0; i < width; i++)
                    {
                        colors[i] = this.Value;
                        amount[i] = this.options.BlendPercentage;
                    }

                    PixelBlender <TPixel> blender = PixelOperations <TPixel> .Instance.GetPixelBlender(this.options.BlenderMode);

                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        Span <TPixel> destination = source.GetRowSpan(y - startY).Slice(minX - startX, width);

                        // This switched color & destination in the 2nd and 3rd places because we are applying the target colour under the current one
                        blender.Blend(destination, colors, destination, amount);
                    });
                }
        }
示例#8
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            float contrast = (100F + this.Value) / 100F;

            int startY         = sourceRectangle.Y;
            int endY           = sourceRectangle.Bottom;
            int startX         = sourceRectangle.X;
            int endX           = sourceRectangle.Right;
            var contrastVector = new Vector4(contrast, contrast, contrast, 1);
            var shiftVector    = new Vector4(.5F, .5F, .5F, 1);

            // 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;
            }

            Parallel.For(
                minY,
                maxY,
                this.ParallelOptions,
                y =>
            {
                Span <TPixel> row = source.GetRowSpan(y - startY);

                for (int x = minX; x < maxX; x++)
                {
                    ref TPixel pixel = ref row[x - startX];

                    Vector4 vector = pixel.ToVector4().Expand();
                    vector        -= shiftVector;
                    vector        *= contrastVector;
                    vector        += shiftVector;

                    pixel.PackFromVector4(vector.Compress());
                }
            });
        }
示例#9
0
        /// <summary>
        /// Execute the first pass through the pixels in the image
        /// </summary>
        /// <param name="source">The source data</param>
        /// <param name="width">The width in pixels of the image.</param>
        /// <param name="height">The height in pixels of the image.</param>
        protected virtual void FirstPass(ImageBase <TPixel> source, int width, int height)
        {
            // Loop through each row
            for (int y = 0; y < height; y++)
            {
                Span <TPixel> row = source.GetRowSpan(y);

                // And loop through each column
                for (int x = 0; x < width; x++)
                {
                    // Now I have the pixel, call the FirstPassQuantize function...
                    this.InitialQuantizePixel(row[x]);
                }
            }
        }
        /// <inheritdoc/>
        protected override void SecondPass(ImageBase <TPixel> source, byte[] output, int width, int height)
        {
            // Load up the values for the first pixel. We can use these to speed up the second
            // pass of the algorithm by avoiding transforming rows of identical color.
            TPixel sourcePixel   = source[0, 0];
            TPixel previousPixel = sourcePixel;
            byte   pixelValue    = this.QuantizePixel(sourcePixel);

            TPixel[] colorPalette     = this.GetPalette();
            TPixel   transformedPixel = colorPalette[pixelValue];

            for (int y = 0; y < height; y++)
            {
                Span <TPixel> row = source.GetRowSpan(y);

                // And loop through each column
                for (int x = 0; x < width; x++)
                {
                    // Get the pixel.
                    sourcePixel = row[x];

                    // Check if this is the same as the last pixel. If so use that value
                    // rather than calculating it again. This is an inexpensive optimization.
                    if (!previousPixel.Equals(sourcePixel))
                    {
                        // Quantize the pixel
                        pixelValue = this.QuantizePixel(sourcePixel);

                        // And setup the previous pointer
                        previousPixel = sourcePixel;

                        if (this.Dither)
                        {
                            transformedPixel = colorPalette[pixelValue];
                        }
                    }

                    if (this.Dither)
                    {
                        // Apply the dithering matrix. We have to reapply the value now as the original has changed.
                        this.DitherType.Dither(source, sourcePixel, transformedPixel, x, y, width, height, false);
                    }

                    output[(y * source.Width) + x] = pixelValue;
                }
            }
        }
示例#11
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            float brightness = this.Value / 100F;

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;

            // 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;
            }

            Parallel.For(
                minY,
                maxY,
                this.ParallelOptions,
                y =>
            {
                Span <TPixel> row = source.GetRowSpan(y - startY);

                for (int x = minX; x < maxX; x++)
                {
                    ref TPixel pixel = ref row[x - startX];

                    // TODO: Check this with other formats.
                    Vector4 vector      = pixel.ToVector4().Expand();
                    Vector3 transformed = new Vector3(vector.X, vector.Y, vector.Z) + new Vector3(brightness);
                    vector = new Vector4(transformed, vector.W);

                    pixel.PackFromVector4(vector.Compress());
                }
            });
        }
示例#12
0
        public void Dither <TPixel>(ImageBase <TPixel> image, TPixel source, TPixel transformed, int x, int y, int width, int height, bool replacePixel)
            where TPixel : struct, IPixel <TPixel>
        {
            if (replacePixel)
            {
                // Assign the transformed pixel to the array.
                image[x, y] = transformed;
            }

            // Calculate the error
            Vector4 error = source.ToVector4() - transformed.ToVector4();

            // Loop through and distribute the error amongst neighbouring pixels.
            for (int row = 0; row < this.matrixHeight; row++)
            {
                int matrixY = y + row;
                if (matrixY > 0 && matrixY < height)
                {
                    Span <TPixel> rowSpan = image.GetRowSpan(matrixY);

                    for (int col = 0; col < this.matrixWidth; col++)
                    {
                        int matrixX = x + (col - this.startingOffset);

                        if (matrixX > 0 && matrixX < width)
                        {
                            float coefficient = this.matrix[row, col];

                            // Good to disable here as we are not comparing mathematical output.
                            // ReSharper disable once CompareOfFloatsByEqualityOperator
                            if (coefficient == 0)
                            {
                                continue;
                            }

                            ref TPixel pixel             = ref rowSpan[matrixX];
                            var        offsetColor       = pixel.ToVector4();
                            var        coefficientVector = new Vector4(coefficient);

                            Vector4 result = ((error * coefficientVector) / this.divisorVector) + offsetColor;
                            result.W = offsetColor.W;
                            pixel.PackFromVector4(result);
                        }
                    }
                }
            }
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            float  threshold = this.Threshold;
            TPixel upper     = this.UpperColor;
            TPixel lower     = this.LowerColor;

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;

            // 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;
            }

            Parallel.For(
                minY,
                maxY,
                this.ParallelOptions,
                y =>
            {
                Span <TPixel> row = source.GetRowSpan(y - startY);

                for (int x = minX; x < maxX; x++)
                {
                    ref TPixel color = ref row[x - startX];

                    // Any channel will do since it's Grayscale.
                    color = color.ToVector4().X >= threshold ? upper : lower;
                }
            });
        }
示例#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;
            Vector3 inverseVector = Vector3.One;

            // 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;
            }

            Parallel.For(
                minY,
                maxY,
                this.ParallelOptions,
                y =>
            {
                Span <TPixel> row = source.GetRowSpan(y - startY);

                for (int x = minX; x < maxX; x++)
                {
                    ref TPixel pixel = ref row[x - startX];

                    var vector      = pixel.ToVector4();
                    Vector3 vector3 = inverseVector - new Vector3(vector.X, vector.Y, vector.Z);

                    pixel.PackFromVector4(new Vector4(vector3, vector.W));
                }
            });
        }
示例#15
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;

            // 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;
            }

            var alphaVector = new Vector4(1, 1, 1, this.Value);

            Parallel.For(
                minY,
                maxY,
                this.ParallelOptions,
                y =>
            {
                Span <TPixel> row = source.GetRowSpan(y - startY);

                for (int x = minX; x < maxX; x++)
                {
                    ref TPixel pixel = ref row[x - startX];
                    pixel.PackFromVector4(pixel.ToVector4() * alphaVector);
                }
            });
        }
        /// <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;

            // 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;
            }

            byte[] bytes = new byte[4];
            for (int y = minY; y < maxY; y++)
            {
                int           offsetY = y - startY;
                Span <TPixel> row     = source.GetRowSpan(offsetY);

                for (int x = minX; x < maxX; x++)
                {
                    int    offsetX     = x - startX;
                    TPixel sourceColor = row[offsetX];
                    this.Dither.Dither(source, sourceColor, this.UpperColor, this.LowerColor, bytes, this.Index, offsetX, offsetY, maxX, maxY);
                }
            }
        }
        /// <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;

            // 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;
            }

            for (int y = minY; y < maxY; y++)
            {
                int           offsetY = y - startY;
                Span <TPixel> row     = source.GetRowSpan(offsetY);

                for (int x = minX; x < maxX; x++)
                {
                    int    offsetX          = x - startX;
                    TPixel sourceColor      = row[offsetX];
                    TPixel transformedColor = sourceColor.ToVector4().X >= this.Threshold ? this.UpperColor : this.LowerColor;
                    this.Diffuser.Dither(source, sourceColor, transformedColor, offsetX, offsetY, maxX, maxY);
                }
            }
        }
示例#18
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 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);

            Parallel.ForEach(
                range,
                this.ParallelOptions,
                y =>
            {
                int offsetY  = y - startY;
                int offsetPy = offset;

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

                Span <TPixel> row = source.GetRowSpan(offsetY + offsetPy);

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

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

                    // Get the pixel color in the centre of the soon to be pixelated area.
                    TPixel pixel = row[offsetX + offsetPx];

                    // 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++)
                        {
                            source[k, l] = pixel;
                        }
                    }
                }
            });
        }
示例#19
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);
            }
        }
示例#20
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);
            }
        }
示例#21
0
        /// <inheritdoc/>
        protected override unsafe void OnApply(ImageBase <TPixel> 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 (var targetPixels = new PixelAccessor <TPixel>(width, height))
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        // Y coordinates of source points
                        Span <TPixel> sourceRow = source.GetRowSpan((int)(((y - startY) * heightFactor) + sourceY));
                        Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                        for (int x = minX; x < maxX; x++)
                        {
                            // X coordinates of source points
                            targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
                        }
                    });

                    // 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 (var targetPixels = new PixelAccessor <TPixel>(width, height))
            {
                using (var 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 (var tempRowBuffer = new Buffer <Vector4>(source.Width))
                        {
                            Span <Vector4> firstPassRow = firstPassPixels.GetRowSpan(y);
                            Span <TPixel> sourceRow     = source.GetRowSpan(y);
                            PixelOperations <TPixel> .Instance.ToVector4(sourceRow, tempRowBuffer, sourceRow.Length);

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

                    // 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];
                        Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                        if (this.Compand)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                // Destination color components
                                Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY);
                                destination         = destination.Compress();

                                ref TPixel pixel = ref targetRow[x];
                                pixel.PackFromVector4(destination);
                            }
                        }
                        else
                        {
                            for (int x = 0; x < width; x++)
                            {
                                // Destination color components
                                Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY);

                                ref TPixel pixel = ref targetRow[x];
                                pixel.PackFromVector4(destination);
                            }
                        }
                    });
示例#22
0
        /// <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 (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 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.GetRowSpan(offsetY);

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

                                offsetX          = offsetX.Clamp(0, maxX);
                                var currentColor = sourceOffsetRow[offsetX].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));

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

                source.SwapPixelsBuffers(targetPixels);
            }
        }