4

我正在构建一个应用程序,它从相机(30fps @ 640x480)捕获视频帧,处理它们,然后在 Windows 窗体上显示它们。我最初使用的是 DrawImage(见下面的代码),但性能很糟糕。即使禁用了处理步骤,在 2.8GHz Core 2 Duo 机器上我能得到的最好效果也是 20fps。在 Windows 窗体上启用了双缓冲,否则我会撕裂。

注意:使用的图像是格式 Format24bppRgb 的位图。我知道 DrawImage 应该使用 Format32bppArgb 格式的图像更快,但我受到来自图像采集卡的格式的限制。

private void CameraViewForm_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;

    // Maximize performance
    g.CompositingMode = CompositingMode.SourceOver;
    g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
    g.CompositingQuality = CompositingQuality.HighSpeed;
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.SmoothingMode = SmoothingMode.None;

    g.DrawImage(currentFrame, displayRectangle);
}

我尝试将 Managed DirectX 9 与 Textures 和 Spites 一起使用(见下文),但性能更差。我对 DirectX 编程非常陌生,所以这可能不是最好的 DirectX 代码。

private void CameraViewForm_Paint(object sender, PaintEventArgs e)
{
    device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);

    device.BeginScene();

    Texture texture = new Texture(device, currentFrame, Usage.None, Pool.Managed);
    Rectangle textureSize;

    using (Surface surface = texture.GetSurfaceLevel(0))
    {
        SurfaceDescription surfaceDescription = surface.Description;
        textureSize = new Rectangle(0, 0, surfaceDescription.Width, surfaceDescription.Height);
    }
    Sprite sprite = new Sprite(device);

    sprite.Begin(SpriteFlags.None);
    sprite.Draw(texture, textureSize, new Vector3(0, 0, 0), new Vector3(0, 0, 0), Color.White);
    sprite.End();

    device.EndScene();

    device.Present();

    sprite.Dispose();
    texture.Dispose();
}

我需要它才能在 XP、Vista 和 Windows 7 上工作。我不知道是否值得尝试 XNA 或 OpenGL。这似乎应该是一件非常简单的事情。

4

2 回答 2

3

答案就在你面前。这是一个旧问题的迟到答案,但有人可能需要答案,所以......

与其在你的绘制循环中声明新的纹理和矩形(这对资源来说非常密集),为什么不在范围之外创建一个纹理呢?例如,请尝试以下操作,而不是您的:

Texture texture;
Rectangle textureSize;
private void InitiateTexture()
{
    texture = new Texture(device, new Bitmap("CAR.jpg"), Usage.None, Pool.Managed);

    using (Surface surface = texture.GetSurfaceLevel(0))
    {
        SurfaceDescription surfaceDescription = surface.Description;
        textureSize = new Rectangle(0, 0, 
                          surfaceDescription.Width, 
                          surfaceDescription.Height);
    }
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);
    device.BeginScene();

    Sprite sprite = new Sprite(device);

    sprite.Begin(SpriteFlags.None);
    sprite.Draw(texture, textureSize, 
    new Vector3(0, 0, 0), 
    new Vector3(0, 0, 0), Color.White);
    sprite.End();
    device.EndScene();
    device.Present();
}

然后如果您需要启动多个纹理,请将其放入列表中,然后从该列表中绘制。它节省了必须使用资源,然后在每次绘画中释放它们。

于 2012-01-10T04:51:33.983 回答
0

CameraViewForm 是您的整个查看器窗口吗?如果是这样,那么在 Paint 上,整个窗口都会被重绘,包括所有按钮、进度条等。这将或多或少取决于表单上控件的数量,以及您为桌面启用的视觉 doo-dads各种操作系统中的元素(例如窗口栏透明度)。

尝试对整个表单进行单缓冲,但通过在调用 GreateGraphics() 或在 Panel 上调用 Invalidate() 之前声明一个新的,为面板(我假设您从中获得 displayRectangle)提供自己的 BufferedGraphicsContext。这允许面板与表单分开双重缓冲。

于 2010-10-01T18:21:17.540 回答