我正在尝试在C#中进行一些图像处理.
我想使用一些线程在我的图像中的几个区域上进行并行计算.
线程实际上是在Bitmap对象中获取和设置像素. 2个线程绝对没有机会访问同一个像素,所以这不是问题所在.
我想使用一些线程在我的图像中的几个区域上进行并行计算.
线程实际上是在Bitmap对象中获取和设置像素. 2个线程绝对没有机会访问同一个像素,所以这不是问题所在.
问题是C#不允许我在同一个Bitmap对象上启动多个线程,即使我确定不会同时读取和修改相同的像素.
有没有办法避免C#引发此错误?或者只是不可能在我的Bitmap对象上运行多个线程?
谢谢,
皮埃尔 – 奥利维尔
解决方法
使用
LockBits(也比GetPixel和SetPixel快得多),您可以将图像的像素复制到缓冲区,在其上运行并行线程,然后将缓冲区复制回来.
这是一个有效的例子.
void test()
{
string inputFile = @"e:\temp\a.jpg";
string outputFile = @"e:\temp\b.jpg";
Bitmap bmp = Bitmap.FromFile(inputFile) as Bitmap;
var rect = new Rectangle(0,bmp.Width,bmp.Height);
var data = bmp.LockBits(rect,ImageLockMode.ReadWrite,bmp.PixelFormat);
var depth = Bitmap.GetPixelFormatSize(data.PixelFormat) / 8; //bytes per pixel
var buffer = new byte[data.Width * data.Height * depth];
//copy pixels to buffer
Marshal.copy(data.Scan0,buffer,buffer.Length);
Parallel.Invoke(
() => {
//upper-left
Process(buffer,data.Width / 2,data.Height / 2,data.Width,depth);
},() => {
//lower-right
Process(buffer,data.Height,depth);
}
);
//copy the buffer back to image
Marshal.copy(buffer,data.Scan0,buffer.Length);
bmp.UnlockBits(data);
bmp.Save(outputFile,ImageFormat.Jpeg);
}
void Process(byte[] buffer,int x,int y,int endx,int endy,int width,int depth)
{
for (int i = x; i < endx; i++)
{
for (int j = y; j < endy; j++)
{
var offset = ((j * width) + i) * depth;
// Dummy work
// To grayscale (0.2126 R + 0.7152 G + 0.0722 B)
var b = 0.2126 * buffer[offset + 0] + 0.7152 * buffer[offset + 1] + 0.0722 * buffer[offset + 2];
buffer[offset + 0] = buffer[offset + 1] = buffer[offset + 2] = (byte)b;
}
}
}
输入图片:
输出图像:
一些粗略的测试:
在双核2.1GHz机器上将(41兆像素,[7152×5368])图像转换为灰度
> GetPixel / SetPixel – 单核 – 131秒.> LockBits – 单核 – 4.5秒.> LockBits – 双核 – 3秒.