问题描述
我的照相机在VB.NET工作(在这种情况下,黑白)。摄像机的API是用C ++和制造商提供包装。作为典型在这些情况下,图像被返回作为一个字节数组。在我的特殊情况下,它每像素8位,所以没有花哨的bitpacking撤消。
I am working with cameras (in this case monochrome) in VB.NET. The API of the cameras is in C++ and the manufacturer provides wrappers. As is typical in these cases, the image is returned as a byte array. In my particular case it's 8 bits per pixel so there's no fancy bitpacking to undo.
我是大吃一惊的.NET具有这种类型的东西这么少的支持。在网上搜索,我发现不同的主题,但它并不能帮助,在许多情况下,人们都对应图像数据(一个字节数组,它是,读取的图像文件转换为字节数组,然后让.NET跨preT数组作为一个文件,用头和一切)。
I was flabbergasted that .NET has so little support for this type of thing. Searching online I found various topics, but it doesn't help that in many cases people have a byte array corresponding to image data (that is, read an image file into a byte array and then have .NET interpret the array as a file, with header and everything).
在这种情况下,我需要原始像素值的数组转换为,特别是,这是我可以显示在屏幕上。
In this case I need to convert an array of raw pixel values into, particularly, something I can display on-screen.
目前似乎没有任何内置的方式做到这一点,因为内置了.NET的8bpp格式索引(需要一个调色板),但它似乎并没有在设定调色板支持。再次,这真的让我感到惊讶。 This是最有前途的话题,我发现。
There doesn't seem to be any built-in way to do this, because the 8bpp format built into .NET is indexed (needs a palette) but it doesn't seem that setting the palette is supported. Again, this really surprised me. This is the most promising topic I found.
所以,我发现做到这一点的唯一方法是创建一个位图,然后复制像素值逐像素。在我的情况下,8兆像素图像花的几秒钟的上最快的i7处理器使用SetPixel时。
So the only way I found to do this is to create a Bitmap and then copy the pixel values pixel by pixel. In my case an 8 MPixel image took several seconds on the fastest i7 when using SetPixel.
我发现用SetPixel的选择是LockBits,然后,您可以访问字节[非托管]数组构成的图像。这似乎浪费了,因为我有操纵在.NET中的数组,然后将其复制回unmananaged空间。我已经一次复制原始图像数据(使原来可以被重复使用或正在发生的事情在其他地方丢弃),这样虽然比用SetPixel这似乎仍然浪费显著更快。
The alternative I found to using SetPixel is LockBits, which then gives you access to the [unmanaged] array of bytes that constitutes the image. It seems wasteful, because I have to manipulate the array in .NET and then copy it back to unmananaged space. I'm already copying the original image data once (so the original can be reused or discarded by the rest of what's going on) so although significantly faster than using SetPixel this still seems wasteful.
下面是VB code,我有:
Here is the VB code I have:
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
有关的8兆像素图像的顺序版本从创建TheBitmap高达(包括)消耗大约220毫秒调用TheBitmap.UnlockBits()。水货版本更加稳定。但60和80毫秒之间。考虑到我是同时从四台摄像机采集和流盘用大量的空余时间,这是pretty的失望。这个API引入了样品code在C ++中,可以从四个摄像机同时以全帧速率(17 fps)的速度显示。它从来没有涉及,当然与位图,因为GDI访问原始像素值的数组。
For an 8 MPixel image the sequential version consumes about 220 milliseconds from creating TheBitmap up to (and including) the call to TheBitmap.UnlockBits(). The parallel version is much more inconsistent but ranges between 60 and 80 milliseconds. Considering I'm acquiring from four cameras simultaneously and streaming to disk with plenty of time to spare, this is pretty disappointing. The API comes with sample code in C++ which can display from all four cameras simultaneously at full frame rate (17 fps). It never deals with Bitmap, of course, since GDI accesses arrays of raw pixel values.
总之,我必须跨越托管/非托管屏障旅行,只是因为没有直接的方式,采取的像素值的数组,东西到一个位图实例。在这种情况下,我也复制了像素值转换为24 bpp的位图,因为我不能集的调色板索引图像所以8bpp不是显示一个可行的格式。
In summary, I have to travel across the managed/unmanaged barrier simply because there is no direct way to take an array of pixel values and "stuff" it into a Bitmap instance. In this case I'm also copying the pixel values into an 24bpp bitmap because I cannot "set" the palette in an indexed image so 8bpp is not a viable format for display.
请问有没有什么更好的办法?
Is there no better way?
推荐答案
创建有效的位图头和preappend它的字节数组。您只需要手动创建56-128字节的数据。
Create a valid bitmap header, and preappend it to the byte array. You'll only need to manually create 56-128 bytes of data.
接下来,创建使用Image.FromStream图像或位图类()/ Bitmap.FromStream()
我无法想象有任何形式的在.net中的原始影像学特征。有这么多需要的信息的图像,这将是接受原始字节,并创建一个想象的(它是一个位图,JPEG,GIF,PNG等方法极其冗长的参数列表,以及所有附加的每个数据这需要建立一个有效的图片),这是没有意义的。
I wouldn't imagine that there is any sort of raw imaging features in .Net. There is so much needed information for an image, it would be an extremely lengthy parameter list for a method to accept raw bytes and create an imagine (is it a bitmap, jpeg, gif, png, etc, and all the additional data each of those requires to create a valid image) it wouldn't make sense.
这篇关于你如何转换成字节数组Bitmap实例(.NET)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!