允许多个线程访问图像 [英] Allow an Image to be accessed by several threads
问题描述
我正在尝试在C#中进行一些图像处理。
我想使用一些线程在我的图像中的几个区域上进行并行计算。
线程实际上是在Bitmap对象中获取和设置像素。 2个线程绝对没有机会访问同一像素,所以这不是问题。
I'm trying to do some image processing in C#. I want to use some threads to do parallel computations on several zones in my image. Threads are actually getting and setting pixels in a Bitmap object. There is absolutely no chance for 2 threads to access the same pixel, so that's not the problem.
问题是C#不允许我在同一个线程上启动多个线程Bitmap对象,即使我确定不会同时读取和修改相同的像素。
The problem is that C# doesnt allow me to start several threads on the same Bitmap object, even if i'm sure that the same pixel won't be read and modified simultaneously.
有没有办法避免C#引发此错误?或者在我的Bitmap对象上运行多个线程是不可能的?
Is there any way to avoid C# to raise this error ? Or is it just impossible to run several threads on my Bitmap object ?
谢谢,
Pierre-Olivier
Pierre-Olivier
推荐答案
使用 LockBits
(也比 GetPixel快得多
& SetPixel
)您可以将图像的像素复制到缓冲区,在其上运行并行线程,然后将缓冲区复制回来。
Using LockBits
(which is also much faster than GetPixel
& SetPixel
) you can copy the image's pixels to a buffer, run parallel threads on it, and then copy the buffer back.
这是一个有效的例子。
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, 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, 0, buffer.Length);
Parallel.Invoke(
() => {
//upper-left
Process(buffer, 0, 0, data.Width / 2, data.Height / 2, data.Width, depth);
},
() => {
//lower-right
Process(buffer, data.Width / 2, data.Height / 2, data.Width, data.Height, data.Width, depth);
}
);
//Copy the buffer back to image
Marshal.Copy(buffer, 0, 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兆像素,[7152x5368] )图像转换为灰度
Converting a (41 MegaPixel, [7152x5368]) image to a gray scale on a dual core 2.1GHz machine
- GetPixel / SetPixel - 单核 - 131秒。
- LockBits - 单核 - 4.5秒。
- LockBits - 双核 - 3秒
这篇关于允许多个线程访问图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!