开发者

Fastest way to draw a series of Bitmaps with C#

开发者_JAVA百科

I'm building an application that captures video frames from a camera (30fps @ 640x480), 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.


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.


Is CameraViewForm your entire viewer window? If so, then on Paint, the entire window is redrawn, including all buttons, progress bars, etc. This will be more or less expensive depending on the number of controls on your form, and the visual doo-dads you have enabled for desktop elements in various OSes (e.g. window bar transparency).

Try single-buffering the entire form, but giving the Panel (from which I assume you get displayRectangle) its own BufferedGraphicsContext, by declaring a new one when you call GreateGraphics() or before calling Invalidate() on the Panel. This allows the Panel to be double-buffered separately from the Form.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜