2012-03-09 4 views
3

저는 웹캠 이미지를 잡고 Windows 형식으로 렌더링하는 데 몇 주 동안 노력했지만 속도 문제로 인해 어려움을 겪어 왔습니다. 내 백그라운드 프로세스를 업데이트하려면 적어도 10 Hz의 프레임 속도가 필요합니다.웹캠에서 이미지를 잡을 때 XNA로 비트 맵 렌더링 속도가 느려지는 이유는 무엇입니까?

필자는 pictureBox를 사용하기 시작했으나, 결국 Form을 사용하여 XNA 패널을 만든 다음 스크립트를 사용하여 비트 맵을 Texture2D로 변환하여 이미지를 배경 스프라이트로 렌더링합니다 나는 여기에서 찾았다.

지금 발생하여 해결할 수 없었던 문제가 있습니다. 아래의 비트 맵 생성자를 호출하여 코드에서 비트 맵을로드하면 모든 것이 원활하게 실행되고 높은 fps를 얻을 수 있습니다. 이것은 테스트 도중 수행 한 결과로 매우 만족했습니다.

Bitmap image = new Bitmap(320, 240); 

하지만 곧 나는 그것이 내가 추측 할 수없는 어떤 이유로 렌더링하기 위해 많은 오래 걸립니다 웹캠에서 잡아 비트 맵을 전송한다. 비트 맵에 대한 내 지식은 이미지가 같은 형식이며, 픽셀의 색상 만 다릅니다. 내가 포맷을 확인한 것은 크기 (320 * 240), 해상도 (96) 및 픽셀 포맷 (Format32bppArgb)입니다. 내가 놓친 게 있니? 나는 사람이 있기 때문에이 좀 도와 수 있다면 매우 감사하게 될 것입니다

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; 
    } 

: 이것은 XNA 내 그리기 기능이

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); 
... 

입니다 :

내가 웹캠에서 이미지를 잡아하는 방법입니다 나는 지금 붙어있다. 여기에있는 커뮤니티는 훌륭했으며 이전에 묻지도 않고이 내용을 얻을 수있었습니다. C# 또는 XNA에 대한 이전 경험이 없으므로 놀라웠습니다. 그 점을 염두에두고 나는 단순한 무언가를 놓치거나 잘못 접근하고있을 수도 있다는 것을 깨닫습니다.

비트 맵 이미지 로딩 범위를 좁혔습니다. 새로 구성된 비트 맵을 사용할 때 변경된 유일한 사항은 XNA에서 처리하기 전에 웹캠에서 해당 비트 맵을 덮어 쓰는 것입니다.

지금 내 질문에 정말 속도가 렌더링의 큰 차이를 설명 할 수있는 비트 맵이 어떻게 구성되어 있습니까? Texture2D 로의 변환이 문제입니까? 그러나 나는 다른 이미지가 그 변환의 속도에 어떻게 영향을 미칠 수 있는지 보지 못한다.

답변

1

확인. 나는 그 문제가 정확히 무엇인지 모른다. 하지만 몇 가지 의견을 드릴 수 있습니다.
- 먼저 XNA 게임의 프레임 속도를 웹캠 fps와 같거나 낮게 설정하십시오. 기본적으로 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

LOL, 나는이 질문이 3 월에 물었다는 것을 알아 차릴 것이다. – EdgarT