3

私は数週間、ウェブカメラの画像を取得して Windows フォームにレンダリングする作業を行ってきましたが、ずっと速度の問題に苦しんでいました。バックグラウンド プロセスを更新するには、少なくとも 10 Hz のフレーム レートが必要です。

私はpictureBoxの使用を開始しましたが、最終的な解決策は、フォーム内にXNAパネルを作成し、ここで見つけたスクリプトを使用してビットマップをTexture2Dに変換することにより、画像を背景スプライトとしてレンダリングすることです。

私が今遭遇し、解決できなかった問題は次のとおりです。以下のようにビットマップコンストラクターを呼び出してコードにビットマップをロードすると、すべてがスムーズに実行され、高い fps が得られます。これは私がテスト中に行ったことであり、結果には非常に満足しています。

Bitmap image = new Bitmap(320, 240);

しかし、ウェブカメラから取得したビットマップを送信するとすぐに、何らかの理由でレンダリングに時間がかかります。ビットマップに関する私の知る限り、画像は同じ形式であり、異なるのはピクセルの色だけです。フォーマットを確認したのは、サイズ (320*240)、解像度 (96)、ピクセル フォーマット (Format32bppArgb) です。何か不足していますか?

これは、ウェブカメラから画像を取得する方法です。

VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

        FinalVideoSource = new VideoCaptureDevice(VideoCaptureDevices[0].MonikerString);
        FinalVideoSource.DesiredFrameSize = new Size(320, 240);
        FinalVideoSource.DesiredFrameRate = fps;
        FinalVideoSource.NewFrame += new NewFrameEventHandler(FinalVideoSource_NewFrame);

void FinalVideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
        // create bitmap from frame
        image = eventArgs.Frame.Clone(new Rectangle(0, 0, 320, 240), PixelFormat.Format32bppArgb);
...

これは、XNA での私の描画関数です。

protected override void Draw()
    {
        backTexture = GetTexture(GraphicsDevice, image);                

        GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CornflowerBlue);

        // TODO: Add your drawing code here
        sprites.Begin();
        Vector2 pos = new Vector2(0, 0);
        sprites.Draw(backTexture, pos, Microsoft.Xna.Framework.Color.White);
        sprites.End();
    }


private Texture2D GetTexture(GraphicsDevice dev, System.Drawing.Bitmap bmp)
    {
        int[] imgData = new int[bmp.Width * bmp.Height];
        Texture2D texture = new Texture2D(dev, bmp.Width, bmp.Height);

        unsafe
        {
            // lock bitmap
            System.Drawing.Imaging.BitmapData origdata =
                bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);

            uint* byteData = (uint*)origdata.Scan0;

            // Switch bgra -> rgba
            for (int i = 0; i < imgData.Length; i++)
            {
                byteData[i] = (byteData[i] & 0x000000ff) << 16 | (byteData[i] & 0x0000FF00) | (byteData[i] & 0x00FF0000) >> 16 | (byteData[i] & 0xFF000000);
            }

            // copy data
            System.Runtime.InteropServices.Marshal.Copy(origdata.Scan0, imgData, 0, bmp.Width * bmp.Height);

            byteData = null;

            // unlock bitmap
            bmp.UnlockBits(origdata);
        }

        texture.SetData(imgData);

        return texture;
    }

私は今立ち往生しているので、誰かがこれを手伝ってくれたらとてもありがたいです。ここのコミュニティは素晴らしく、事前に尋ねることなくここまでたどり着くことができました。C# や XNA の経験がなかったので、これは驚くべきことです。それを念頭に置いて、何か単純なものを見逃しているか、これに間違った方法でアプローチしている可能性があることに気付きました.

ビットマップ画像の読み込みに絞り込みました。新しく構築されたビットマップを使用するときに変更する唯一のことは、XNA で処理する前に Web カメラからのビットマップを単純に上書きすることです。

今の私の質問は、レンダリング速度の大きな違いを説明できるビットマップの構築方法に何か欠けているのでしょうか? Texture2D への変換はここで問題ですか? しかし、別の画像がその変換速度にどのように影響するかはわかりません。

4

1 に答える 1

1

Ok。何が問題なのか正確にはわかりません。しかし、私はあなたにいくつかのコメントを与えることができます。
-まず、XNA ゲームのフレーム レートを Web カメラの fps 以下に設定します。デフォルトでは、XNA は 60 fps で実行されるため、30 fps を使用している場合は、Web カメラのフレームごとに GetTexture() メソッドを 2 回呼び出すことになります。初期化コードでは:

TargetElapsedTime = TimeSpan.FromSeconds(1f/webcam fps)

それでもうまくいかない場合は、このコードを試して、ビットマップからテクスチャに変換できます。

protected override void Draw()
{
    //Unset the texture from the GraphicsDevice
    for (int i = 0; i < 16; i++)
            {
                if (Game.GraphicsDevice.Textures[i] == backTexture)
                {
                    Game.GraphicsDevice.Textures[i] = null;
                    break;
                }
            }

    backTexture.SetData<byte>(image.GetBytes());                

    GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CornflowerBlue);

    // TODO: Add your drawing code here
    sprites.Begin();
    Vector2 pos = new Vector2(0, 0);
    sprites.Draw(backTexture, pos, Microsoft.Xna.Framework.Color.White);
    sprites.End();

}


public static byte[] GetBytes(this Bitmap bitmap)
{
    var data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), 
        System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);

    // calculate the byte size: for PixelFormat.Format32bppArgb (standard for GDI bitmaps) it's the hight * stride
    int bufferSize = data.Height * data.Stride; // stride already incorporates 4 bytes per pixel

    // create buffer
    byte[] bytes = new byte[bufferSize];

    // copy bitmap data into buffer
    Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

    // unlock the bitmap data
    bitmap.UnlockBits(data);

    return bytes;

}

私はこのコードをテストしていて、正常に動作します。この助けを願っています。

于 2012-08-31T05:35:29.087 に答える