从网络摄像头获取图像时,使用XNA渲染位图的速度较慢,原因是什么

本文关键字:速度 位图 是什么 获取 摄像头 网络 图像 XNA 使用 | 更新日期: 2023-09-27 18:27:10

我已经花了几个星期的时间来获取网络摄像头图像并将其呈现在windows窗体上,但一直在处理速度问题。我需要至少10赫兹的帧速率才能更新我的背景进程。

我开始使用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是这里的问题吗?但我看不出不同的图像会如何影响转换的速度。

从网络摄像头获取图像时,使用XNA渲染位图的速度较慢,原因是什么

好的。我不知道到底是什么问题。但我可以给你一些意见
-首先,将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;
}

我正在测试这个代码,并且运行良好。希望得到帮助。