VB.NET でカメラ (この場合はモノクロ) を使用しています。カメラの API は C++ であり、メーカーはラッパーを提供します。Byte
このような場合によくあることですが、画像は配列として返されます。私の特定のケースでは、ピクセルあたり 8 ビットであるため、元に戻す派手なビットパッキングはありません。
私は、.NET がこの種のことをほとんどサポートしていないことに驚きました。オンラインで検索すると、さまざまなトピックが見つかりましたが、多くの場合、人々が画像データに対応するバイト配列を持っていることは役に立ちません (つまり、画像ファイルをバイト配列に読み取ってから、.NET にその配列をファイルとして解釈させ、ヘッダーとすべてを含む)。
この場合、生のピクセル値の配列を、特に画面上に表示できるものに変換する必要があります。
.NET に組み込まれている 8bpp 形式はインデックス化されている (パレットが必要) ため、これを行う組み込みの方法はないようですが、パレットの設定がサポートされているようには見えません。繰り返しますが、これには本当に驚きました。これは私が見つけた最も有望なトピックです。
したがって、これを行う唯一の方法は、を作成しBitmap
、ピクセル値をピクセルごとにコピーすることです。私の場合、最速の i7 を使用した場合、8 MPixel の画像に数秒かかりSetPixel
ました。
私が見つけた代替手段SetPixel
は ですLockBits
。これにより、イメージを構成する (管理されていない) バイト配列にアクセスできます。.NET で配列を操作してから、管理されていない領域にコピーして戻さなければならないので、無駄に思えます。私はすでに元の画像データを 1 回コピーしています (そのため、元の画像は残りの部分で再利用または破棄できます) 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 MPixel イメージの場合、シーケンシャル バージョンでは、作成からTheBitmap
への呼び出しまで (および呼び出しを含む) に約 220 ミリ秒かかりますTheBitmap.UnlockBits()
。並列バージョンはより一貫性がありませんが、60 ~ 80 ミリ秒の範囲です。4 台のカメラから同時に取得し、十分な時間に余裕を持ってディスクにストリーミングしていることを考えると、これはかなり残念です。API には C++ のサンプル コードが付属しており、4 台のカメラすべてから同時にフル フレーム レート (17 fps) で表示できます。Bitmap
もちろん、GDI は生のピクセル値の配列にアクセスするため、 を処理することはありません。
Bitmap
要約すると、ピクセル値の配列を取得してインスタンスに「詰め込む」直接的な方法がないという理由だけで、マネージド/アンマネージド バリアを越えて移動する必要があります。この場合Bitmap
、インデックス付きイメージでパレットを「設定」できないため、ピクセル値も 24bpp にコピーしているため、8bpp は表示用の実行可能な形式ではありません。
もっと良い方法はありませんか?