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
相关产品推荐
相关产品推荐

