简体   繁体   English

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

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

在C#.NET中对图像进行像素化的好算法是什么?

A simple, yet unefficient solution would be to resize to a smaller size, then resize back using pixel duplication. 一个简单而又无效的解决方案是调整大小,然后使用像素复制调整大小。

A better solution would be (pseudo-code): 更好的解决方案是(伪代码):
(Time O(n), Additional space (besides mutable source image): O(1)) (时间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.

The guy over at this forum has a pretty good algorithm. 这个论坛上的人有一个非常好的算法。 It works by taking the average of all of the colors in each "block." 它的工作原理是取每个“块”中所有颜色的平均值。

I just used his implementation in C#/GDI+ today: 我今天刚刚在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;
        }
    }
}

Caveat emptor, works on my machine, & etc. 注意事项,在我的机器上工作,等等。

While I don't know of a well know algorithm for this, I did have to write something similar. 虽然我不知道一个众所周知的算法,但我确实要写类似的东西。 The technique I used was pretty simple, but I am thinking not very efficient for large images. 我使用的技术非常简单,但我认为对于大图像效率不高。 Basically I would take the image and do color averaging in 5 (or howerver big you want) pixel blocks and then make all those pixels the same color. 基本上我会拍摄图像并在5个(或者你想要的更大)像素块中进行颜色平均,然后使所有这些像素的颜色相同。 You could speed this up by doing the average on just the diagonal pixels which would save a lot of cycles but be less accurate. 您可以通过仅对角线像素进行平均来加快速度,这样可以节省大量周期但不太准确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 什么是C#中的错误操作符? - What's the false operator in C# good for? 在C#中,有什么好的算法可以找到是否存在I,J,K,使得对于某些S来说8 * I + J * 12 + K * 15 = S? - What is a good algorithm in C# to find if there exists I,J,K such that 8*I+J*12+K*15=S for some S? 在C#中编写批处理脚本的好方法是什么? - What's a good way to write batch scripts in C#? 在C#项目中存储不变变量的好方法是什么? - What's a good way to store unchanging variables in a C# project? 从C#生成JavaScript的良好架构是什么? - What's a good architecture for generating JavaScript from C#? C# 中什么是好的线程安全 singleton 通用模板模式 - What's a good threadsafe singleton generic template pattern in C# 什么是 c# 和 .net 的良好商业 tar stream lib? - What is a good commercial tar stream lib for c# and .net? 从Windows服务器上的ASP.NET C#脚本发送的每小时电子邮件数量是多少? - What's a good number of emails per hour sent from an ASP.NET C# script on a Windows server? 在C#中捕获StackOverflow异常的一般方法是什么? - What's a good general way of catching a StackOverflow exception in C#? 在C#中,什么是显示可缩放,可平移视频的好方法? - In C#, what's a good way for displaying zoomable, pannable video?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM