使用C#绘制一系列位图的最快方法

时间:2010-10-01 18:08:38

标签: c# .net video directx drawimage

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

注意:使用的图像是Format24bppRgb格式的位图。我知道使用Format32bppArgb格式化的图像时,DrawImage应该更快,但我受到帧抓取器格式的限制。

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 with Textures and 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。这似乎应该是一件非常简单的事情。

2 个答案:

答案 0 :(得分: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();
}

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

答案 1 :(得分:0)

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

尝试单缓冲整个表单,但是给Panel(我假设你得到displayRectangle)它自己的BufferedGraphicsContext,通过在调用GreateGraphics()或在Panel上调用Invalidate()之前声明一个新的。这允许Panel与表单分开进行双重缓冲。