在 C# 中,即使不依赖 OpenCV(如 EmguCV)或第三方图像库,也可以通过 纯 .NET 代码(System.Drawing 或ImageSharp) + 自定义算法 实现基础但高效的图像处理功能,包括均值/高斯滤波、锐化、Sobel/Canny 边缘检测等。这在轻量级部署、嵌入式场景或规避 GPL 许可限制时尤为重要。

以下提供一套完整、可运行、无外部依赖的实现方案(基于 System.Drawing,适用于 .NET Framework / .NET 6+ Windows;若需跨平台,可轻松迁移到 ImageSharp 的像素操作)。


✅ 前提:获取像素数据

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

public static byte[] LockBitmap(Bitmap bitmap, out int width, out int height, out int stride)
{
    var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    var bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
    width = bmpData.Width;
    height = bmpData.Height;
    stride = bmpData.Stride;
    var bytes = new byte[Math.Abs(stride) * height];
    System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, bytes, 0, bytes.Length);
    bitmap.UnlockBits(bmpData);
    return bytes;
}

💡 注意:Format24bppRgb 每像素 3 字节(BGR 顺序),stride 可能含 padding。


1️⃣ 均值滤波(Mean Filter)

用于降噪、平滑。

public static byte[] MeanFilter(byte[] src, int width, int height, int kernelSize = 3)
{
    var dst = new byte[src.Length];
    int half = kernelSize / 2;
    for (int y = half; y < height - half; y++)
    {
        for (int x = half; x < width - half; x++)
        {
            int r = 0, g = 0, b = 0;
            for (int ky = -half; ky <= half; ky++)
            {
                for (int kx = -half; kx <= half; kx++)
                {
                    int idx = ((y + ky) * width + (x + kx)) * 3;
                    b += src[idx];     // B
                    g += src[idx + 1]; // G
                    r += src[idx + 2]; // R
                }
            }
            int area = kernelSize * kernelSize;
            int dstIdx = (y * width + x) * 3;
            dst[dstIdx] = (byte)(b / area);
            dst[dstIdx + 1] = (byte)(g / area);
            dst[dstIdx + 2] = (byte)(r / area);
        }
    }
    return dst;
}

2️⃣ 高斯滤波(Gaussian Filter)

更自然的平滑,保留边缘。

public static byte[] GaussianFilter(byte[] src, int width, int height)
{
    // 5x5 高斯核(σ=1)
    float[,] kernel = {
        {1, 4, 6, 4, 1},
        {4, 16, 24, 16, 4},
        {6, 24, 36, 24, 6},
        {4, 16, 24, 16, 4},
        {1, 4, 6, 4, 1}
    };
    float sum = 256f; // 核总和

    var dst = new byte[src.Length];
    for (int y = 2; y < height - 2; y++)
    {
        for (int x = 2; x < width - 2; x++)
        {
            float r = 0, g = 0, b = 0;
            for (int ky = -2; ky <= 2; ky++)
            {
                for (int kx = -2; kx <= 2; kx++)
                {
                    int idx = ((y + ky) * width + (x + kx)) * 3;
                    float weight = kernel[ky + 2, kx + 2] / sum;
                    b += src[idx] * weight;
                    g += src[idx + 1] * weight;
                    r += src[idx + 2] * weight;
                }
            }
            int dstIdx = (y * width + x) * 3;
            dst[dstIdx] = (byte)Math.Clamp(b, 0, 255);
            dst[dstIdx + 1] = (byte)Math.Clamp(g, 0, 255);
            dst[dstIdx + 2] = (byte)Math.Clamp(r, 0, 255);
        }
    }
    return dst;
}

3️⃣ 锐化(Unsharp Masking)

增强边缘细节。

public static byte[] Sharpen(byte[] src, int width, int height)
{
    // 拉普拉斯锐化核
    int[,] kernel = {
        {0, -1, 0},
        {-1, 5, -1},
        {0, -1, 0}
    };

    var dst = new byte[src.Length];
    for (int y = 1; y < height - 1; y++)
    {
        for (int x = 1; x < width - 1; x++)
        {
            int r = 0, g = 0, b = 0;
            for (int ky = -1; ky <= 1; ky++)
            {
                for (int kx = -1; kx <= 1; kx++)
                {
                    int idx = ((y + ky) * width + (x + kx)) * 3;
                    int k = kernel[ky + 1, kx + 1];
                    b += src[idx] * k;
                    g += src[idx + 1] * k;
                    r += src[idx + 2] * k;
                }
            }
            int dstIdx = (y * width + x) * 3;
            dst[dstIdx] = (byte)Math.Clamp(b, 0, 255);
            dst[dstIdx + 1] = (byte)Math.Clamp(g, 0, 255);
            dst[dstIdx + 2] = (byte)Math.Clamp(r, 0, 255);
        }
    }
    return dst;
}

4️⃣ Sobel 边缘检测

计算梯度幅值。

public static byte[] SobelEdge(byte[] src, int width, int height)
{
    // 先转灰度(简化)
    var gray = ToGrayscale(src, width, height);

    var gx = new int[width * height];
    var gy = new int[width * height];

    // Sobel 算子
    int[,] sobelX = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
    int[,] sobelY = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};

    for (int y = 1; y < height - 1; y++)
    {
        for (int x = 1; x < width - 1; x++)
        {
            int sumX = 0, sumY = 0;
            for (int ky = -1; ky <= 1; ky++)
            {
                for (int kx = -1; kx <= 1; kx++)
                {
                    int val = gray;
                    sumX += val * sobelX[ky + 1, kx + 1];
                    sumY += val * sobelY[ky + 1, kx + 1];
                }
            }
            gx[y * width + x] = sumX;
            gy[y * width + x] = sumY;
        }
    }

    // 合成梯度幅值
    var edge = new byte[src.Length];
    for (int i = 0; i < width * height; i++)
    {
        byte mag = (byte)Math.Min(255, Math.Sqrt(gx[i] * gx[i] + gy[i] * gy[i]) / 4);
        int idx = i * 3;
        edge[idx] = edge[idx + 1] = edge[idx + 2] = mag;
    }
    return edge;
}

private static byte[] ToGrayscale(byte[] rgb, int width, int height)
{
    var gray = new byte[width * height];
    for (int i = 0; i < width * height; i++)
    {
        int rgbIdx = i * 3;
        // Y = 0.299R + 0.587G + 0.114B
        gray[i] = (byte)(0.299 * rgb[rgbIdx + 2] + 0.587 * rgb[rgbIdx + 1] + 0.114 * rgb[rgbIdx]);
    }
    return gray;
}

🖼 保存结果图像

public static void SaveBitmap(byte[] pixels, int width, int height, string path)
{
    using var bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
    var rect = new Rectangle(0, 0, width, height);
    var bmpData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
    System.Runtime.InteropServices.Marshal.Copy(pixels, 0, bmpData.Scan0, pixels.Length);
    bitmap.UnlockBits(bmpData);
    bitmap.Save(path, System.Drawing.Imaging.ImageFormat.Png);
}

⚠️ 注意事项

  • 性能优化:上述代码未向量化,大数据量建议用 Span<T>、并行循环(Parallel.For);
  • 边界处理:当前简单忽略边缘,可扩展为镜像/复制边界;
  • 跨平台替代:在 Linux/macOS 上,可用 SixLabors.ImageSharp 替代 System.Drawing,其 PixelAccessor 提供类似像素访问能力;
  • 精度:使用 float 中间计算避免溢出。

✅ 总结

算法 是否依赖 OpenCV 特点
均值滤波 简单快速,适合去噪
高斯滤波 更自然平滑
锐化 增强细节
Sobel 边缘 经典边缘检测

无需 OpenCV,C# 也能做扎实的图像处理——
掌握底层原理,方能在资源受限或合规敏感场景中游刃有余。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐