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

C#并行实现Box模糊、高斯模糊时出现图像异常偏色的问题排查

C# 并行图像模糊实现色彩异常问题

问题描述

开发中需要实现基础盒模糊算法完成图像平滑效果,无额外定制需求。行索引逻辑已排查无误,但编写的并行版本实现会导致输出图像颜色异常,呈现类似红绿滤镜的错位偏色效果。
相关参考素材说明:

  • 输入为待处理的原始测试图像
  • 并行盒模糊算法运行输出为带偏色的异常图像
  • 非并行实现的盒模糊算法运行输出为色彩正常的平滑模糊图像
  • 参考实现的高斯模糊算法与并行盒模糊逻辑同源,运行同样出现偏色问题,仅偏色表现与盒模糊并行版存在差异

并行盒模糊实现代码

private void boxblur(object sender, EventArgs e)
{
  Bitmap image = new Bitmap(pictureBox.Image);
  BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat); 
  int height = bitmapData.Height;
  int bPP = System.Drawing.Bitmap.GetPixelFormatSize(image.PixelFormat) / 8; 
  int width = bitmapData.Width * bPP;

  Bitmap bitmap2 = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
  unsafe 
  {
    byte* firstPixel = (byte*)bitmapData.Scan0; 
    Parallel.For(1, height - 1, j =>{
          byte* line1 = firstPixel + ((j - 1) * bitmapData.Stride); // 上一行像素起始指针
          byte* line2 = firstPixel + (j * bitmapData.Stride); // 当前行像素起始指针
          byte* line3 = firstPixel + ((j + 1) * bitmapData.Stride); // 下一行像素起始指针
          int idx = 0;
          
          for (int i = 1; i < width-1; i = i + bPP) // 逐像素遍历,步长为单像素占用字节数
          {
            int oldB = line1[i-1] + line1[i+2] + line1[i+5] +
            line2[i-1] + line2[i+2] + line2[i+5] +
            line3[i-1] + line3[i+2] + line3[i+5];

            int oldG = line1[i] + line1[i + 3] + line1[i + 6] +
            line2[i] + line2[i + 3] + line2[i + 6] +
            line3[i] + line3[i + 3] + line3[i + 6];

            int oldR = line1[i+1] + line1[i + 4] + line1[i + 7] +
            line2[i+1] + line2[i + 4] + line2[i + 7] +
            line3[i+1] + line3[i + 4] + line3[i + 7]; ;

            oldB = oldB/9;
            oldG = oldG/9;
            oldR = oldR/9;

            lock (bitmap2)
            {
              bitmap2.SetPixel(idx, j, Color.FromArgb(oldR, oldG, oldB));
            }
            idx++;
          }
          });
    image.UnlockBits(bitmapData);
  }

  pictureBox.Image = bitmap2;           
}

正常运行的非并行盒模糊实现代码

private void boxblur(object sender, EventArgs e)
{
        Bitmap bitmap = new Bitmap(pictureBox.Image);
        int width = bitmap.Width;
        int height = bitmap.Height;
        Bitmap bitmap2 = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat);
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                if (i > 1 && j > 1 && i + 1 != width && j + 1 != height)
                {
                    int newRValue = bitmap.GetPixel(i, j + 1).R +
                                    bitmap.GetPixel(i + 1, j + 1).R +
                                    bitmap.GetPixel(i - 1, j).R +
                                    bitmap.GetPixel(i, j).R +
                                    bitmap.GetPixel(i + 1, j).R +
                                    bitmap.GetPixel(i - 1, j - 1).R +
                                    bitmap.GetPixel(i, j - 1).R +
                                    bitmap.GetPixel(i + 1, j - 1).R;
                    newRValue = Convert.ToInt32(newRValue / 9);

                    int newGValue = bitmap.GetPixel(i, j + 1).G +
                                    bitmap.GetPixel(i + 1, j + 1).G +
                                    bitmap.GetPixel(i - 1, j).G +
                                    bitmap.GetPixel(i, j).G +
                                    bitmap.GetPixel(i + 1, j).G +
                                    bitmap.GetPixel(i - 1, j - 1).G +
                                    bitmap.GetPixel(i, j - 1).G +
                                    bitmap.GetPixel(i + 1, j - 1).G;
                    newGValue = Convert.ToInt32(newGValue / 9);

                    int newBValue = bitmap.GetPixel(i, j + 1).B +
                                    bitmap.GetPixel(i + 1, j + 1).B +
                                    bitmap.GetPixel(i - 1, j).B +
                                    bitmap.GetPixel(i, j).B +
                                    bitmap.GetPixel(i + 1, j).B +
                                    bitmap.GetPixel(i - 1, j - 1).B +
                                    bitmap.GetPixel(i, j - 1).B +
                                    bitmap.GetPixel(i + 1, j - 1).B;
                    newBValue = Convert.ToInt32(newBValue / 9);

                    bitmap2.SetPixel(i, j, Color.FromArgb(newRValue, newGValue, newBValue));
                }
            }
        }
        pictureBox.Image = bitmap2;
}

并行高斯模糊实现代码

算法逻辑与并行盒模糊实现同源,运行后同样出现偏色问题,仅偏色表现存在差异。

private void gaussianblur(object sender, EventArgs e)
{
    Bitmap image = new Bitmap(pictureBox.Image);
    BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat); 
    int height = bitmapData.Height;
    int bPP = System.Drawing.Bitmap.GetPixelFormatSize(image.PixelFormat) / 8; 
    int width = bitmapData.Width * bPP;

    Bitmap bitmap2 = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
    unsafe 
    {
        byte* firstPixel = (byte*)bitmapData.Scan0; 
        Parallel.For(1, height - 1, j =>{
            byte* line1 = firstPixel + ((j - 1) * bitmapData.Stride); 
            byte* line2 = firstPixel + (j * bitmapData.Stride); 
            byte* line3 = firstPixel + ((j + 1) * bitmapData.Stride);
            int idx = 0;

            for (int i = 1; i < width - 1; i = i + bPP)
            {
                int oldB = line1[i - 1] + line1[i + 2] * 2 + line1[i + 5] +
                           line2[i - 1] *2 + line2[i + 2] *4 + line2[i + 5] * 2 +
                           line3[i - 1] + line3[i + 2] *2+ line3[i + 5];

                int oldG = line1[i] + line1[i + 3] *2 + line1[i + 6] +
                           line2[i] *2+ line2[i + 3] *4+ line2[i + 6] *2+
                           line3[i] + line3[i + 3] *2+ line3[i + 6];

                int oldR = line1[i + 1] + line1[i + 4] *2 + line1[i + 7] +
                           line2[i + 1] *2 + line2[i + 4] *4 + line2[i + 7] *2+
                           line3[i + 1] + line3[i + 4] *2+ line3[i + 7];

                oldB = oldB / 16;
                oldG = oldG / 16;
                oldR = oldR / 16;

                lock (bitmap2)
                {
                    bitmap2.SetPixel(idx, j, Color.FromArgb(oldR, oldG, oldB));
                }
                idx++;
            }
        });
        image.UnlockBits(bitmapData);
    }

    pictureBox.Image = bitmap2;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 10:36:04