【问题标题】:How to apply blur effect on a bitmap image in C#? [closed]如何在 C# 中对位图图像应用模糊效果? [关闭]
【发布时间】:2017-12-03 06:29:42
【问题描述】:

如何在不使用库的情况下在 C# 中对图像应用模糊效果?

【问题讨论】:

  • 这不是个好主意,因为 WriteableBitmap 需要 4 个参数,而不是 2 个。我已经尝试过这个示例。
  • 作为一个快速的技巧,您可以将全尺寸位图渲染为尺寸的一小部分,然后将其渲染回全尺寸位图。为此,您只需要Graphics.FromImageGraphics.DrawImage
  • Add blur effect on image的可能重复

标签: c# image bitmap blur effect


【解决方案1】:

更新代码(现在更快,需要使用 UNSAFE 关键字)

static void Main(string[] args)
{
    Bitmap bitmap = new Bitmap("C:\\Users\\erik\\test.png");
    bitmap = Blur(bitmap, 10);
    bitmap.Save("C:\\Users\\erik\\test2.png");
}

private static Bitmap Blur(Bitmap image, Int32 blurSize)
{
    return Blur(image, new Rectangle(0, 0, image.Width, image.Height), blurSize);
}

private unsafe static Bitmap Blur(Bitmap image, Rectangle rectangle, Int32 blurSize)
{
    Bitmap blurred = new Bitmap(image.Width, image.Height);

    // make an exact copy of the bitmap provided
    using (Graphics graphics = Graphics.FromImage(blurred))
        graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
            new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

    // Lock the bitmap's bits
    BitmapData blurredData = blurred.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, blurred.PixelFormat);

    // Get bits per pixel for current PixelFormat
    int bitsPerPixel = Image.GetPixelFormatSize(blurred.PixelFormat);

    // Get pointer to first line
    byte* scan0 = (byte*)blurredData.Scan0.ToPointer();

    // look at every pixel in the blur rectangle
    for (int xx = rectangle.X; xx < rectangle.X + rectangle.Width; xx++)
    {
        for (int yy = rectangle.Y; yy < rectangle.Y + rectangle.Height; yy++)
        {
            int avgR = 0, avgG = 0, avgB = 0;
            int blurPixelCount = 0;

            // average the color of the red, green and blue for each pixel in the
            // blur size while making sure you don't go outside the image bounds
            for (int x = xx; (x < xx + blurSize && x < image.Width); x++)
            {
                for (int y = yy; (y < yy + blurSize && y < image.Height); y++)
                {
                    // Get pointer to RGB
                    byte* data = scan0 + y * blurredData.Stride + x * bitsPerPixel / 8;

                    avgB += data[0]; // Blue
                    avgG += data[1]; // Green
                    avgR += data[2]; // Red

                    blurPixelCount++;
                }
            }

            avgR = avgR / blurPixelCount;
            avgG = avgG / blurPixelCount;
            avgB = avgB / blurPixelCount;

            // now that we know the average for the blur size, set each pixel to that color
            for (int x = xx; x < xx + blurSize && x < image.Width && x < rectangle.Width; x++)
            {
                for (int y = yy; y < yy + blurSize && y < image.Height && y < rectangle.Height; y++)
                {
                    // Get pointer to RGB
                    byte* data = scan0 + y * blurredData.Stride + x * bitsPerPixel / 8;

                    // Change values
                    data[0] = (byte)avgB;
                    data[1] = (byte)avgG;
                    data[2] = (byte)avgR;
                }
            }
        }
    }

    // Unlock the bits
    blurred.UnlockBits(blurredData);

    return blurred;
}

2.356 seconds处理256x256模糊值10的图像。

原始代码(来自Github - 略有改动)

static void Main(string[] args)
{
    Bitmap bitmap = new Bitmap("C:\\Users\\erik\\test.png");

    bitmap = Blur(bitmap, 10);

    bitmap.Save("C:\\Users\\erik\\test2.png");
}

private static Bitmap Blur(Bitmap image, Int32 blurSize)
{
    return Blur(image, new Rectangle(0, 0, image.Width, image.Height), blurSize);
}

private static Bitmap Blur(Bitmap image, Rectangle rectangle, Int32 blurSize)
{
    Bitmap blurred = new Bitmap(image.Width, image.Height);

    // make an exact copy of the bitmap provided
    using (Graphics graphics = Graphics.FromImage(blurred))
        graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
            new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

    // look at every pixel in the blur rectangle
    for (int xx = rectangle.X; xx < rectangle.X + rectangle.Width; xx++)
    {
        for (int yy = rectangle.Y; yy < rectangle.Y + rectangle.Height; yy++)
        {
            int avgR = 0, avgG = 0, avgB = 0;
            int blurPixelCount = 0;

            // average the color of the red, green and blue for each pixel in the
            // blur size while making sure you don't go outside the image bounds
            for (int x = xx; (x < xx + blurSize && x < image.Width); x++)
            {
                for (int y = yy; (y < yy + blurSize && y < image.Height); y++)
                {
                    Color pixel = blurred.GetPixel(x, y);

                    avgR += pixel.R;
                    avgG += pixel.G;
                    avgB += pixel.B;

                    blurPixelCount++;
                }
            }

            avgR = avgR / blurPixelCount;
            avgG = avgG / blurPixelCount;
            avgB = avgB / blurPixelCount;

            // now that we know the average for the blur size, set each pixel to that color
            for (int x = xx; x < xx + blurSize && x < image.Width && x < rectangle.Width; x++)
                for (int y = yy; y < yy + blurSize && y < image.Height && y < rectangle.Height; y++)
                    blurred.SetPixel(x, y, Color.FromArgb(avgR, avgG, avgB));
        }
    }

    return blurred;
}

7.594 seconds处理256x256模糊值10的图像。

原图

模糊图像(模糊级别 10)

图片来自:https://www.pexels.com/search/landscape/

【讨论】:

  • 太好了 :) 谢谢
  • 简单高效。由于OP没有提供太多细节,因此可能没问题。但我担心这种实现有点慢,尤其是“blurSize”值很高:)
  • 事实上我刚刚测试过它,它不能用于高于 10 的值。慢,它会产生一些带有奇怪垂直条纹的伪影。对于高值,高斯模糊(可能就像您可以在 AForge 之类的库中找到的那样?)可能更适合。
  • 我同意。但是OP没有任何具体要求。我相信这就足够了。
  • 嘿嘿,我刚刚明白了为什么会这样。算法确实有bug!颜色像素 = blurred.GetPixel(x, y);应该是 Color pixel = image.GetPixel(x, y); :)。修好后效果更佳!我刚刚在原始 github 页面上发表了评论。
【解决方案2】:

如果您使用的是来自 Microsoft 的 XAML check。也学习this code你的问题可以解决。

【讨论】:

  • 没有 XAML - 我需要它作为脚本
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-13
相关资源
最近更新 更多