C# – Fastest way to draw a series of Bitmaps with C#

cdirectxdrawimagenetvideo

I'm building an application that captures video frames from a camera (30fps @ 640×480), processes them, and then displays them on a Windows Form. I was initially using DrawImage (see code below) but the performance was terrible. Even with the processing step disabled the best I can get is 20fps on a 2.8GHz Core 2 Duo machine. Double buffering is enabled on the Windows form otherwise I get tearing.

Note: The image used is a Bitmap of format Format24bppRgb. I know that DrawImage is supposed to be faster with a Format32bppArgb formatted image but I am restricted by the format that comes out of the frame grabber.

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

I tried using Managed DirectX 9 with Textures and Spites (see below) but the performance was even worse. I'm very new to DirectX programming so this may not be the best DirectX code.

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

I need this to work on XP, Vista and Windows 7. I don't know if it's worth trying XNA or OpenGL. This seems like it should be a very simple thing to accomplish.

Best Answer

The answer is right in front of you. This is a late answer to an old question, but someone might need the answer so...

Instead of declaring new textures and rectangles inside your draw loop (which is quite intense on the resources) why not create a texture outside the scope? Instead of your one, for example, try this:

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

and then if you need to initiate multiple textures, do it into a list, then paint from that list. It saves having to use resources then free them each paint.