Allow an Image to be accessed by several threads

前端 未结 2 1932
说谎
说谎 2021-01-05 02:13

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

2条回答
  •  温柔的废话
    2021-01-05 02:42

    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.

    Here is a working example.

    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;
            }
        }
    }
    

    Input Image:

    enter image description here

    Output Image:

    enter image description here

    Some rough tests:

    Converting a (41 MegaPixel, [7152x5368]) image to a gray scale on a dual core 2.1GHz machine

    • GetPixel/SetPixel - Single Core - 131 sec.
    • LockBits - Single Core - 4.5 sec.
    • LockBits - Dual Core - 3 sec.

提交回复
热议问题