You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现图片模糊:Bitmap拆分RGB数组后3×3矩阵处理求助

实现C#图片模糊效果的具体方案

嘿,你的这个思路完全没问题——这其实就是**均值模糊(Mean Blur)**的一种变体实现,针对3x3矩阵只取外围8个像素的平均值赋值给中心像素。下面我来帮你把这个思路落地成可运行的C#代码,同时给你一些关键的注意事项:

一、高效操作Bitmap的前提:使用LockBits

直接用Bitmap.GetPixel()和SetPixel()会非常慢,尤其是处理大图片时。建议用LockBits方法直接获取像素内存的指针,这样能大幅提升性能。

二、核心模糊逻辑实现步骤

  1. 锁定位图内存,获取像素数据的起始指针和每行的字节数(stride)
  2. 遍历图像像素:注意要跳过边缘像素(因为边缘的3x3矩阵会超出图像范围,你可以选择保留原像素,或者用边缘复制的方式填充)
  3. 计算外围8个像素的RGB平均值:对每个非边缘像素,找到它周围的8个Z位置像素,分别累加红、绿、蓝通道的值,再除以8得到平均值
  4. 赋值给中心像素:把计算出的平均值赋值给当前的中心X像素
  5. 解锁位图内存,保存或返回处理后的图片

三、完整代码示例

using System;
using System.Drawing;
using System.Drawing.Imaging;

public class ImageBlurProcessor
{
    public static Bitmap ApplyPeripheralMeanBlur(Bitmap originalBitmap)
    {
        // 创建副本避免修改原图
        Bitmap blurredBitmap = new Bitmap(originalBitmap.Width, originalBitmap.Height);
        
        Rectangle rect = new Rectangle(0, 0, originalBitmap.Width, originalBitmap.Height);
        BitmapData originalData = originalBitmap.LockBits(rect, ImageLockMode.ReadOnly, originalBitmap.PixelFormat);
        BitmapData blurredData = blurredBitmap.LockBits(rect, ImageLockMode.WriteOnly, blurredBitmap.PixelFormat);

        // 获取像素格式的字节数(24位=3字节,32位=4字节)
        int bytesPerPixel = Image.GetPixelFormatSize(originalBitmap.PixelFormat) / 8;
        int stride = originalData.Stride;
        IntPtr originalPtr = originalData.Scan0;
        IntPtr blurredPtr = blurredData.Scan0;

        // 分配数组存储像素数据
        int totalBytes = stride * originalBitmap.Height;
        byte[] originalPixels = new byte[totalBytes];
        byte[] blurredPixels = new byte[totalBytes];

        // 把像素数据复制到数组
        System.Runtime.InteropServices.Marshal.Copy(originalPtr, originalPixels, 0, totalBytes);

        // 遍历每个非边缘像素
        for (int y = 1; y < originalBitmap.Height - 1; y++)
        {
            for (int x = 1; x < originalBitmap.Width - 1; x++)
            {
                int currentIndex = y * stride + x * bytesPerPixel;
                int blueSum = 0, greenSum = 0, redSum = 0;
                int count = 0;

                // 遍历3x3矩阵外围(跳过中心X)
                for (int dy = -1; dy <= 1; dy++)
                {
                    for (int dx = -1; dx <= 1; dx++)
                    {
                        if (dy == 0 && dx == 0) continue;

                        int neighborIndex = (y + dy) * stride + (x + dx) * bytesPerPixel;
                        blueSum += originalPixels[neighborIndex];
                        greenSum += originalPixels[neighborIndex + 1];
                        redSum += originalPixels[neighborIndex + 2];
                        count++;
                    }
                }

                // 赋值并确保颜色值在0-255范围内
                blurredPixels[currentIndex] = (byte)Math.Clamp(blueSum / count, 0, 255);
                blurredPixels[currentIndex + 1] = (byte)Math.Clamp(greenSum / count, 0, 255);
                blurredPixels[currentIndex + 2] = (byte)Math.Clamp(redSum / count, 0, 255);

                // 32位带Alpha通道的图片保留原Alpha值
                if (bytesPerPixel == 4)
                {
                    blurredPixels[currentIndex + 3] = originalPixels[currentIndex + 3];
                }
            }
        }

        // 复制边缘像素(保持原图边缘不变)
        // 复制第一行和最后一行
        for (int x = 0; x < originalBitmap.Width; x++)
        {
            int topIndex = 0 * stride + x * bytesPerPixel;
            int bottomIndex = (originalBitmap.Height - 1) * stride + x * bytesPerPixel;
            Array.Copy(originalPixels, topIndex, blurredPixels, topIndex, bytesPerPixel);
            Array.Copy(originalPixels, bottomIndex, blurredPixels, bottomIndex, bytesPerPixel);
        }
        // 复制第一列和最后一列(排除已复制的首尾行)
        for (int y = 1; y < originalBitmap.Height - 1; y++)
        {
            int leftIndex = y * stride + 0 * bytesPerPixel;
            int rightIndex = y * stride + (originalBitmap.Width - 1) * bytesPerPixel;
            Array.Copy(originalPixels, leftIndex, blurredPixels, leftIndex, bytesPerPixel);
            Array.Copy(originalPixels, rightIndex, blurredPixels, rightIndex, bytesPerPixel);
        }

        // 把处理后的数据复制回位图
        System.Runtime.InteropServices.Marshal.Copy(blurredPixels, 0, blurredPtr, totalBytes);

        // 解锁内存
        originalBitmap.UnlockBits(originalData);
        blurredBitmap.UnlockBits(blurredData);

        return blurredBitmap;
    }

    // 测试用例
    public static void Main()
    {
        using (Bitmap original = new Bitmap("input.jpg"))
        {
            using (Bitmap blurred = ApplyPeripheralMeanBlur(original))
            {
                blurred.Save("output_blurred.jpg", ImageFormat.Jpeg);
            }
        }
    }
}

四、关键注意事项

  • Bitmap通道顺序:.NET的Bitmap默认用BGR顺序存储像素,而非RGB,所以代码中要注意通道索引(blue是第一个字节,green第二个,red第三个)
  • 边缘处理:代码选择保留原边缘像素,你也可以改成边缘复制、镜像填充等方式,让模糊效果覆盖到边缘
  • 性能优化:处理超大图片时,可用Parallel.For并行遍历行,提升处理速度
  • 像素格式兼容:代码兼容24位(RGB)和32位(ARGB)位图,其他格式建议先转换为这两种格式再处理

内容的提问来源于stack exchange,提问作者FSmith94

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:02:44