我在VB.NET中使用攝像頭(在這種情況下是單色)。相機的API使用C++,製造商提供包裝。正如在這些情況下通常那樣,圖像以Byte
陣列的形式返回。在我的具體情況下,它是每像素8位,所以沒有花哨的可以撤消的bitpacking。如何將字節數組轉換爲位圖實例(.NET)?
我是大驚小怪 .NET對此類事物的支持很少。在線搜索我發現了各種主題,但在許多情況下,人們都沒有對應於圖像數據的字節數組(即將圖像文件讀入字節數組,然後讓.NET將數組解釋爲文件,與標題和一切)。
在這種情況下,我需要將原始像素值的數組轉換爲,特別是我可以在屏幕上顯示的東西。
似乎沒有任何內置的方法來做到這一點,因爲內置到.NET中的8bpp格式被索引(需要調色板),但似乎並不支持設置調色板。再次,這真的讓我感到驚訝。 This是我發現的最有希望的主題。
所以我發現要做到這一點的唯一方法是創建一個Bitmap
,然後逐個像素地複製像素值。在我的情況下,使用SetPixel
時,800萬像素的圖像以最快的i7拍攝幾秒。
我發現使用SetPixel
的替代方法是LockBits
,然後您可以訪問構成圖像的(非託管)字節數組。這看起來很浪費,因爲我必須在.NET中操縱數組,然後將其複製回unmananaged空間。我已經複製了一次原始圖像數據(因此原始圖像可以被重複使用或被剩餘的部分丟棄),所以雖然比使用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
對於8百萬像素圖像的順序版本從創建TheBitmap
到(幷包括)調用TheBitmap.UnlockBits()
消耗大約220毫秒。並行版本更不一致,但範圍在60到80毫秒之間。考慮到我從四臺攝像機中同時購買,並有充足的時間備份到磁盤,這是非常令人失望的。該API帶有C++中的示例代碼,可以全幀速率(17 fps)同時顯示所有四臺攝像機。當然,它從不處理Bitmap
,因爲GDI訪問原始像素值的數組。
總之,我必須跨越託管/非託管屏障,因爲沒有直接的方法來獲取像素值數組並將其「填充」到Bitmap
實例中。在這種情況下,我還將像素值複製到24bpp Bitmap
中,因爲我無法在索引圖像中「設置」調色板,因此8bpp不是用於顯示的可行格式。
有沒有更好的方法?
FromStream要求流包含一個「滿」位圖(有頭信息),不只是像素值---我想在我的問題來解釋這一點。 – pelesl 2012-04-18 17:02:42
參考bmp標題信息更新。預先附加大約128個字節,然後使用fromstream應該實質上更快。 – 2012-04-18 17:12:09
這是值得一試的,特別是如果它可以讓我在灰度調色板的前面添加一個位圖標題,所以我不必複製像素值3次即可獲得24 bpp。 – pelesl 2012-04-19 01:21:14