允许多个线程访问图像

Pin*_*kPR 6 c# multithreading image-processing

我正在尝试在C#中进行一些图像处理.我想使用一些线程在我的图像中的几个区域上进行并行计算.线程实际上是在Bitmap对象中获取和设置像素.2个线程绝对没有机会访问同一个像素,所以这不是问题所在.

问题是C#不允许我在同一个Bitmap对象上启动多个线程,即使我确定不会同时读取和修改相同的像素.

有没有办法避免C#引发此错误?或者只是不可能在我的Bitmap对象上运行多个线程?

谢谢,

皮埃尔 - 奥利维尔

L.B*_*L.B 16

使用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, 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输入图片:

在此输入图像描述

输出图像:

在此输入图像描述

一些粗略的测试:

双核2.1GHz机器上将(41兆像素,[7152x5368])图像转换为灰度

  • GetPixel/SetPixel - 单核 - 131秒.
  • LockBits - 单核 - 4.5秒
  • LockBits - 双核 - 3秒.

  • 非常感谢您的回答。那正是我最终所做的。我刚刚看到了您的消息,所以我已经自己找到了解决方案,但没有时间提早发布。再次感谢你 ! (2认同)