15

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 は表示用の実行可能な形式ではありません。

もっと良い方法はありませんか?

4

3 に答える 3

11

有効なビットマップ ヘッダーを作成し、それをバイト配列に事前に追加します。56 ~ 128 バイトのデータを手動で作成するだけで済みます。

次に、バイト配列からストリームを作成します

次に、Image.FromStream()/Bitmap.FromStream() を使用してイメージまたはビットマップ クラスを作成します。

.Net に生の画像処理機能があるとは思えません。画像には非常に多くの必要な情報があり、生のバイトを受け入れてイメージを作成するメソッドのパラメータ リストは非常に長くなります (ビットマップ、jpeg、gif、png など、およびそれぞれのすべての追加データ)。それらは有効な画像を作成する必要があります)それは意味がありません。

于 2012-04-18T17:01:04.547 に答える
7

これを試して

var img = new Bitmap(new MemoryStream(yourByteArray));
于 2013-02-15T15:09:50.813 に答える
4

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

于 2012-04-18T17:13:26.507 に答える