我正在尝试使用 C# 使用相同的旧 GDI 技术进行一些图像处理,使用嵌套的 for 循环迭代每个像素,然后对该(位图)图像使用 GetPixel 和 SetPixel 方法。
我已经使用指针方法得到了相同的结果(使用不安全的上下文),但我现在正在尝试使用老式的获取/设置像素方法来处理我的位图...
Bitmap ToGrayscale(Bitmap source)
{
for (int y = 0; y < source.Height;y++ )
{
for (int x = 0; x < source.Width; x++)
{
Color current = source.GetPixel(x, y);
int avg = (current.R + current.B + current.G) / 3;
Color output = Color.FromArgb(avg, avg, avg);
source.SetPixel(x, y, output);
}
}
return source;
}
考虑到上面代码的性能......需要太多时间才能完成,同时让用户等待 1800x1600 图像完成处理。
所以我认为我可以使用我们使用 HLSL 的技术,为每个像素运行一个单独的函数(像素着色器引擎(正如我所认为的)在 GPU 上复制返回 float4(颜色)的函数数千次进行并行处理)。
因此,我尝试为每个像素运行一个单独的任务(函数),将这些任务变量放入列表中,并将“等待”放入 List.ToArray() 中。但我未能做到这一点,因为每个新任务都“等待”在下一个任务运行之前完成。
我想为每个像素调用一个新任务来运行它:
Color current = source.GetPixel(x, y);
int avg = (current.R + current.B + current.G) / 3;
Color output = Color.FromArgb(avg, avg, avg);
source.SetPixel(x, y, output);
最终我得到了一个异步非阻塞代码,但不是并行的...... 大家有什么建议吗?
最佳答案
GetPixel
和 SetPixel
可能是这里的主要瓶颈。
我建议使用Bitmap.LockBits
,而不是尝试并行化它。更有效地处理解析。
话虽如此,您可以通过以下方式并行化当前版本:
Bitmap ToGrayscale(Bitmap source)
{
Parallel.For(0, source.Height, y =>
{
for (int x = 0; x < source.Width; x++)
{
Color current = source.GetPixel(x, y);
int avg = (current.R + current.B + current.G) / 3;
Color output = Color.FromArgb(avg, avg, avg);
source.SetPixel(x, y, output);
}
});
return source;
}
但是,Bitmap
类不是线程安全的,因此这可能会导致问题。
更好的方法是使用 LockBits,然后直接并行处理原始数据(如上所述)。请注意,我仅并行化外循环(有意),因为这将防止工作项的核心过度饱和。
关于c# - 使用 C# 5.0 进行并行图像处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18369823/