2012-03-09 34 views
3

我一直在爲抓住攝像頭圖像工作了幾個星期,並將它呈現在Windows窗體上,但整個過程中一直都是速度問題。我需要至少10 Hz的幀速率才能更新我的後臺進程。使用XNA渲染位圖時,從網絡攝像頭抓取圖像時速度慢,爲什麼?

我開始使用pictureBox,但我最終的解決方案是在我的Form中創建一個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中處理它之前,簡單地覆蓋網絡攝像頭中的一個。

我現在的問題是真的,我錯過了如何構建位圖來解釋渲染速度的巨大差異嗎?在這裏轉換到Texture2D的問題?但我不明白不同的圖像會如何影響轉換的速度。

回答

1

好的。我不知道究竟是什麼問題。但我可以給你一些意見。
- 首先,將XNA遊戲的幀頻設置爲等於或小於網絡攝像頭的幀率。 默認情況下,XNA以60fps運行,所以如果您使用的是30fps,則您要爲網絡攝像頭的每幀調用GetTexture()方法兩次。 在初始化代碼:

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; 

} 

我正在測試這段代碼,工作正常。希望這個幫助。

+0

大聲笑,我只是注意到這個問題是在3月份提出的。 – EdgarT 2012-08-31 05:38:25

相關問題