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 aboutMarshal.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.
精彩评论