簡體   English   中英

C#.NET中有什么好的像素化算法?

[英]What's a good pixelation algorithm in C# .NET?

在C#.NET中對圖像進行像素化的好算法是什么?

一個簡單而又無效的解決方案是調整大小,然后使用像素復制調整大小。

更好的解決方案是(偽代碼):
(時間O(n),附加空間(除了可變源圖像):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.

這個論壇上的人有一個非常好的算法。 它的工作原理是取每個“塊”中所有顏色的平均值。

我今天剛剛在C#/ 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;
        }
    }
}

注意事項,在我的機器上工作,等等。

雖然我不知道一個眾所周知的算法,但我確實要寫類似的東西。 我使用的技術非常簡單,但我認為對於大圖像效率不高。 基本上我會拍攝圖像並在5個(或者你想要的更大)像素塊中進行顏色平均,然后使所有這些像素的顏色相同。 您可以通過僅對角線像素進行平均來加快速度,這樣可以節省大量周期但不太准確。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM