2012-04-18 5 views
12

私はVB.NETのカメラ(この場合はモノクローム)で作業しています。カメラのAPIはC++で、メーカーはラッパーを提供しています。これらの場合に典型的なように、画像はByte配列として返されます。私の場合は、1ピクセルあたり8ビットなので、元に戻すためのビットパックはありません。バイト配列をビットマップインスタンス(.NET)に変換するにはどうすればよいですか?

私はflabbergastedでしたが、このタイプのものはほとんどサポートしていません。オンラインでの検索私はさまざまなトピックを見つけましたが、多くの場合、画像データに対応するバイト配列を持つ人がいます(つまり、イメージファイルをバイト配列に読み込んだ後、ヘッダーとすべてを含む)。

この場合、生のピクセル値の配列を、特に画面上に表示できるものに変換する必要があります。

.NETに組み込まれている8bpp形式のインデックスが作成されているため(パレットが必要です)、パレットの設定がサポートされていないため、これを行うための組み込み方法はありません。再び、これは本当に私を驚かせました。私が見つけた最も有望な話題はThisです。

これを行うために私が見つけた唯一の方法は、Bitmapを作成し、ピクセル値をピクセル単位でコピーすることです。私の場合は、SetPixelを使用すると、8 MPixelの画像が秒になりました。が最も速いi7になりました。

SetPixelの代わりにLockBitsを使用して、イメージを構成する(アンマネージド)バイト配列にアクセスすることができます。 .NETで配列を操作し、それを管理されていない空間にコピーする必要があるので、無駄に思えます。私はすでに元の画像データを1回コピーしていますので(元の画像は再利用できるようになります)、SetPixelを使用するよりもはるかに高速ですが、これはまだ無駄です。ここで

私はVBのコードは次のとおりです。

8メガピクセルの画像の場合
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 

シーケンシャルバージョンは、最大TheBitmapを作成(および含む)TheBitmap.UnlockBits()への呼び出しから約220ミリ秒を消費します。パラレルバージョンはずっと矛盾していますが、60〜80ミリ秒の範囲です。私は4台のカメラから同時に取得し、余裕を持ってディスクにストリーミングすることを考慮して、これはかなり残念です。 APIにはC++のサンプルコードが付属しており、4つのカメラすべてからフルフレームレート(17fps)で同時に表示できます。もちろん、を扱うことはありません。GDIは生のピクセル値の配列にアクセスするからです。

要約すると、単にピクセル値の配列を取得してBitmapインスタンスに「埋め込む」直接の方法がないため、管理対象/非管理バリアを渡る必要があります。この場合、8bppは表示可能な形式ではないため、インデックス付きイメージでパレットを「設定」できないため、ピクセル値を24bpp Bitmapにコピーしています。

良い方法はありますか?

答えて

10

valid bitmap headerを作成し、それをバイト配列にあらかじめ添付します。 56-128バイトのデータを手動で作成するだけで済みます。

第2、create a stream from a byte array

次に、create an image or bitmap class by using Image.FromStream()/Bitmap.FromStream()

私はネットで生のイメージング機能の任意の並べ替えがあることは想像できないでしょう。イメージには非常に必要な情報があります。それは、生のバイトを受け取り、イメージを作成するメソッドのための非常に長いパラメータリストです(ビットマップ、JPEG、GIF、PNGなどです)。有効な画像を作成する必要がある場合)、それは意味をなさないでしょう。

+0

FROMSTREAMを試してみては、ストリームは、私は私の質問でこれを説明しようとした---だけではなく、ピクセル値、(ヘッダ情報付き)「完全な」ビットマップが含まれている必要があります。 – pelesl

+3

bmpヘッダー情報を参照して更新されました。 fromstreamを使用して128バイトをあらかじめ追加しておくと、処理速度が大幅に向上します。 –

+1

これは試してみる価値があります。特に、ビットマップヘッダーの前にグレースケールパレットを追加すると、ピクセル値を3回コピーして24 bppにする必要はありません。 – pelesl

4

あなたのすべてのカメラが同じタイプであるように見えるので、画像データです。私はこれがあなたの場合に可能かどうかは分かりませんが、任意のイメージからこの「フルビットマップ」を作成してから、ヘッダーをテンプレートとして使用できます(すべてのイメージで同じになるため)。

+1

+1それは素晴らしいアイデアです! –

6

この

var img = new Bitmap(new MemoryStream(yourByteArray)); 
+1

"var"と宣言する必要はないと思います。代わりにそれを "ビットマップ"として宣言できますか?しかし、答えは素晴らしいです! – tmighty

+0

もちろん可能です。 RTM https://msdn.microsoft.com/ru-ru/library/bb383973.aspx – Cheburek

関連する問題