2012-03-09 3 views
3

Я работаю в течение нескольких недель, захватывая изображение веб-камеры и визуализируя его на форме окна, но все время боролся с проблемами скорости. Мне нужно, по крайней мере, частоту кадров 10 Гц, чтобы обновлять фоновый процесс.Рендеринг растрового изображения с XNA медленно при захвате изображения с веб-камеры, почему?

Я начал использовать pictureBox, но решение, с которым я столкнулся, заключается в создании XNA-панели внутри моей Формы, а затем рендеринг изображения в качестве фонового-спрайта путем преобразования растрового изображения в Texture2D с использованием сценария Я нашел здесь.

Проблема, с которой я столкнулся сейчас, и не смог ее решить; когда я загружаю Bitmap в код, вызывая конструктор растрового изображения, как показано ниже, все выполняется гладко, и я могу получить высокий 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 равной или меньшей, чем ваша веб-камера fps. По умолчанию XNA работает со скоростью 60 кадров в секунду, поэтому вы дважды вызываете метод GetTexture() для каждого фрейма вашей веб-камеры, если используете 30 кадров в секунду. В коде инициализации:

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

LOL, я просто заметил, что этот вопрос задавали в марте. – EdgarT