我已经工作了几周,抓住网络摄像头图像并将其渲染到Windows窗体上,但是整个过程中都遇到了速度问题。我需要至少10 Hz的帧速率才能更新我的后台进程。
我开始使用pictureBox,但我最终得到的解决方案是在我的Form中创建一个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这里的问题是什么?但我没有看到不同的图像如何影响转换的速度。
答案 0 :(得分:1)
确定。我不知道究竟是什么问题。但我可以给你一些评论 - 首先,将XNA游戏的帧速率设置为与网络摄像头fps相等或更低。 默认情况下,XNA以60fps运行,因此如果使用30fps,则为网络摄像头的每一帧调用两次GetTexture()方法。 在Initialize代码中:
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;
}
我正在测试此代码并且工作正常。希望这有帮助。