如何将字节数组转换为Bitmap实例(.NET)?

dar*_*rda 12 .net vb.net imaging

我在VB.NET中使用相机(在这种情况下是单色).相机的API使用C++,制造商提供包装.在这些情况下通常,图像作为Byte数组返回.在我的特定情况下,它是每像素8位,所以没有花哨的比特包撤消.

惊讶于.NET对这类事物的支持很少.网上搜索,我发现不同的主题,但它并不能帮助,在许多情况下,人们都对应图像数据的字节数组(即,读取图像文件转换成字节数组,然后让.NET数组解释为一个文件,标题和一切).

在这种情况下,我需要将原始像素值数组转换为特别是我可以在屏幕上显示的内容.

似乎没有被任何内置的方式做到这一点,因为内置到.NET的8bpp的格式索引(需要一个调色板),但它似乎并不设置调色板支持.再次,这真的让我感到惊讶.是我发现的最有希望的话题.

所以我发现这样做的唯一方法是创建一个Bitmap然后逐个像素地复制像素值.在我的情况下,使用时,最快的i7上的8 MPixel图像需要几秒钟SetPixel.

我发现使用的替代方法SetPixelLockBits,它允许您访问构成图像的(非托管)字节数组.这似乎很浪费,因为我必须在.NET中操作数组,然后将其复制回非管理空间.我已经复制了原始图像数据一次(因此原始图像可以重复使用或被其余部分丢弃),所以虽然比使用SetPixel它还要快得多但仍然看起来很浪费.

这是我的VB代码:

Public Function GetBitmap(ByRef TheBitmap As System.Drawing.Bitmap) As Integer
    Dim ImageData() As Byte
    Dim TheWidth, TheHeight As Integer
    'I've omitted the code here (too specific for this question) which allocates
    'ImageData and then uses Array.Copy to store a copy of the pixel values
    'in it. It also assigns the proper values to TheWidth and TheHeight.

    TheBitmap = New System.Drawing.Bitmap(TheWidth, TheHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
    Dim TheData As System.Drawing.Imaging.BitmapData = TheBitmap.LockBits(
        New System.Drawing.Rectangle(0, 0, TheWidth, TheHeight), Drawing.Imaging.ImageLockMode.ReadWrite, TheBitmap.PixelFormat)
    Dim Image24(Math.Abs(TheData.Stride) * TheHeight) As Byte
    'Then we have two choices: to do it in parallel or not. I tried both; the sequential version is commented out below.
    System.Threading.Tasks.Parallel.For(0, ImageData.Length, Sub(i)
                                                                 Image24(i * 3 + 0) = ImageData(i)
                                                                 Image24(i * 3 + 1) = ImageData(i)
                                                                 Image24(i * 3 + 2) = ImageData(i)
                                                             End Sub)
    'Dim i As Integer
    'For i = 0 To ImageData.Length - 1
    '    Image24(i * 3 + 0) = ImageData(i)
    '    Image24(i * 3 + 1) = ImageData(i)
    '    Image24(i * 3 + 2) = ImageData(i)
    'Next
    System.Runtime.InteropServices.Marshal.Copy(Image24, 0, TheData.Scan0, Image24.Length)
    TheBitmap.UnlockBits(TheData)

    'The above based on
    'http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx

    Return 1

End Function
Run Code Online (Sandbox Code Playgroud)

对于8 MPixel图像,顺序版本从创建TheBitmap到(包括)呼叫到消耗大约220毫秒TheBitmap.UnlockBits().并行版本更不一致,但范围在60到80毫秒之间.考虑到我同时从四台摄像机中获取并且有足够的时间流式传输到磁盘,这非常令人失望.该API带有C++示例代码,可以全帧速率(17 fps)同时显示所有四个摄像机.Bitmap当然,它从不处理,因为GDI访问原始像素值的数组.

总之,我必须跨越托管/非托管屏障,因为没有直接的方法来获取像素值数组并将其"填充"到Bitmap实例中.在这种情况下,我也将像素值复制到24bpp,Bitmap因为我无法在索引图像中"设置"调色板,因此8bpp不是可行的显示格式.

有没有更好的方法?

Eri*_*ips 10

创建一个有效的位图标,并将其预先添加到字节数组中.您只需手动创建56-128字节的数据.

其次,从字节数组创建流.

接下来,使用Image.FromStream()/ Bitmap.FromStream()创建一个图像或位图类

我不认为.Net中有任何原始的成像功能.对于图像来说,有太多需要的信息,对于接受原始字节并创建想象的方法来说,它将是一个非常冗长的参数列表(它是位图,jpeg,gif,png等,以及每个的所有附加数据)那些需要创建一个有效的图像)它没有意义.

  • 更新时参考了bmp标题信息.预先附加大约128个字节然后使用fromstream应该基本上更快. (3认同)

Che*_*rek 7

试试这个

var img = new Bitmap(new MemoryStream(yourByteArray));
Run Code Online (Sandbox Code Playgroud)