简体   繁体   中英

How to convert Bitmap to byte[,,] faster?

I wrote function:

    public static byte[, ,] Bitmap2Byte(Bitmap image)
    {
        int h = image.Height;
        int w = image.Width;

        byte[, ,] result= new byte[w, h, 3];

        for (int i = 0; i < w; i++)
        {
            for (int j = 0; j < h; j++)
            {
                Color c= image.GetPixel(i, j);
                result[i, j, 0] = c.R;
                result[i, j, 1] = c.G;
                result[i, j, 2] = c.B;
            }
        }

        return result;
    }

But it takes almost 6 seconds to convert 1800x1800 image. Can I do this faster?

EDIT:
OK, I found this: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx
There is nice example. Only question I have is about Marshal.Copy . Can I make it copy data directly into byte[,,] ?

EDIT 2: OK, sometimes I got strange values of pixels and they do not seem to follow r0 g0 b0 r1 g1 b1 rule. Why? Never mind. Figured it out.

EDIT 3: Made it. 0,13s vs 5,35s :)

You can speed this up considerably by using a BitmapData object which is returned from Bitmap.LockBits . Google "C# Bitmap LockBits" for a bunch of examples.

GetPixel is painfully, painfully slow, making it (ironically) completely unsuitable for the manipulation of individual pixels.

I've been wondering this for a while.

In .NET 4.0 Microsoft introduced the Parallel library. Basically what this does is there is a Parallel.For method that will automatically spawn off numerous threads to help with the work. For instance if you originally had a For(int i =0;i<3;i++){ code...}, A parallel.For loop would probably create 3 threads and each thread would have a different value for i running through the inner code. So the best thing i can suggest is a Parallel.For loop with a

Color c
 lock(obraz) 
{
  c =  obraz.GetPixel(..)
}
...

when getting the pixel.

If you need any more explanation on parallelism I can't really assist you before you take some time to study it as it is a huge area of study.

I just tried parallel For .
It doesn't work without SyncLock on the bitmap.
It says the object is in use.
So it pretty much just works, in serial lol... what a mess.

    For xx As Integer = 0 To 319
        pq.ForAll(Sub(yy)
                      Dim Depth = getDepthValue(Image, xx, yy) / 2047
                      Dim NewColor = Depth * 128
                      Dim Pixel = Color.FromArgb(NewColor, NewColor, NewColor)
                      SyncLock Bmp2
                          Bmp2.SetPixel(xx, yy, Pixel)
                      End SyncLock
                  End Sub)
    Next

In case you're wondering, this is converting kinect's depth map -> bitmap .
Kinect's depth range is from 11bit(0-2047) and represents distance not color.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM