What is a good pixelization algorithm in C # .NET?

What is a good algorithm for pixelizing an image in C # .NET?

+3
source share
3 answers

A simple but ineffective solution would be to resize to a smaller size and then resize using duplicate pixels.

The best solution would be (pseudo-code):
(O (n) time, extra space (besides the modified source image): O (1))

// Pixelize in x axis (choose a whole k s.t. 1 <= k <= Width)
var sum = Pixel[0, 0];
for (y = 0; y < Height; y++)
{
    for (x = 0; x < Width + 1; x++)
    {
        if (x % k == 0)
        {
            sum /= k;
            for (xl = Max(0, x-k); xl < x; xl++)
                Pixel[y, xl] = sum;
            sum = 0;
        }
        if (x == Width)
            break;
        sum += Pixel[y, x];
    }
}

// Now do the same in the y axis
// (make sure to keep y the outer loop - for better performance)

// If your image has more than one channel, then then Pixel should be a struct.
+3
source

The guy in this forum has a pretty good algorithm. It works by taking the average of all colors in each “block”.

#/GDI + :

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Linq;
using System.Text;

/// <summary>
/// Applies a pixelation effect to an image.
/// </summary>
[SuppressMessage(
    "Microsoft.Naming",
    "CA1704",
    Justification = "'Pixelate' is a word in my book.")]
public class PixelateEffect : EffectBase
{
    /// <summary>
    /// Gets or sets the block size, in pixels.
    /// </summary>
    private int blockSize = 10;

    /// <summary>
    /// Gets or sets the block size, in pixels.
    /// </summary>
    public int BlockSize
    {
        get
        {
            return this.blockSize;
        }

        set
        {
            if (value <= 1)
            {
                throw new ArgumentOutOfRangeException("value");
            }

            this.blockSize = value;
        }
    }

    /// <summary>
    /// Applies the effect by rendering it onto the target bitmap.
    /// </summary>
    /// <param name="source">The source bitmap.</param>
    /// <param name="target">The target bitmap.</param>
    public override void DrawImage(Bitmap source, Bitmap target)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }

        if (target == null)
        {
            throw new ArgumentNullException("target");
        }

        if (source.Size != target.Size)
        {
            throw new ArgumentException("The source bitmap and the target bitmap must be the same size.");
        }

        using (var graphics = Graphics.FromImage(target))
        {
            graphics.PageUnit = GraphicsUnit.Pixel;

            for (int x = 0; x < source.Width; x += this.BlockSize)
            {
                for (int y = 0; y < source.Height; y += this.BlockSize)
                {
                    var sums = new Sums();

                    for (int xx = 0; xx < this.BlockSize; ++xx)
                    {
                        for (int yy = 0; yy < this.BlockSize; ++yy)
                        {
                            if (x + xx >= source.Width || y + yy >= source.Height)
                            {
                                continue;
                            }

                            var color = source.GetPixel(x + xx, y + yy);
                            sums.A += color.A;
                            sums.R += color.R;
                            sums.G += color.G;
                            sums.B += color.B;
                            sums.T++;
                        }
                    }

                    var average = Color.FromArgb(
                        sums.A / sums.T,
                        sums.R / sums.T,
                        sums.G / sums.T,
                        sums.B / sums.T);

                    using (var brush = new SolidBrush(average))
                    {
                        graphics.FillRectangle(brush, x, y, (x + this.BlockSize), (y + this.BlockSize));
                    }
                }
            }
        }
    }

    /// <summary>
    /// A structure that holds sums for color averaging.
    /// </summary>
    private struct Sums
    {
        /// <summary>
        /// Gets or sets the alpha component.
        /// </summary>
        public int A
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the red component.
        /// </summary>
        public int R
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the blue component.
        /// </summary>
        public int B
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the green component.
        /// </summary>
        public int G
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the total count.
        /// </summary>
        public int T
        {
            get;
            set;
        }
    }
}

emptor, ..

+1

While I do not know the well-known algorithm for this, I had to write something like this. The technique I used was pretty simple, but I think it’s not very effective for large images. Basically I would take an image and do color averaging in 5 (or howerver big you want) pixel blocks, and then do all these pixels in the same color. You could speed this up by running the average over diagonal pixels only, which would save a lot of cycles but be less accurate.

0
source

Source: https://habr.com/ru/post/1727003/


All Articles