I'm creating a cad viewer which deals with very large image files and I am trying to optimise it for as high a framerate and low a memory footprint as possible.
It uses GDI+ for rendering onto a panel.
It's current flaw is with image rendering. Some of the files I'm using reference images which are particularly big (8000x8000 pixels). I've optimised the memory usage by only loading them when they become visible and disposing of them when they're not. This reduces the chance of the program running out of memory but prevents the images from being loaded and unloaded too often; however rendering the images themselves (context.DrawImage) still carries a very large overhead.
I'm now exploring ways of blitting the images into a smaller buffer of some sort, rendering this (generally much smaller) buffer, and then refreshing/rebuilding it when the zoom level changes significantly.
The problem is, I can't find any provision for this in GDI whatsoever. Can anyone suggest how I could achieve it?
I don't think GDI is designed for such high-speed updates of images. If you are trying to scroll the image, and tracking the mouse with each move, try to shift sections of the image and fill in the space opened up by the shift. Essentially reuse the tricks that programmers used when smoothly scrolling/panning graphics at a time when CPU's are slow and RAM is small.
If you're creating a new graphics application that needs a high framerate and are looking for suggestions, then I suggest abandoning GDI+ and using WPF. WPF uses hardware acceleration and supports retained-mode graphics; this has much better performance for less work than GDI+.
If there is some limitation that forbids WPF, please explain it in your question. This is relevant because such limitations can also impact GDI+ drawing.
GDI Binned in favour of Direct3D as 3D elements came into the equation anyway. Images turned into single thumbnails and larger tiles that are loaded in/out as required.
I faced a similar problem when developing my own GIS application. The best solution I found for this (even when using WPF) is to tile big images and display only the portions that are visible. This is being said, I would switch to WPF not only for the reasons given in the above answers but also for the good imaging support offered. See this link for more information
Related
I need to speed up my image viewer, and wondering if I should be looking into creating my own DirectX control to do so.
My image viewer displays medical images. They can be pretty large. We're talking 55mb when it comes to mammography. The pixel data is 16bit greyscale stored in a ushort array. Without getting into the gory details, my current approach is loading the pixel data into an ImageSource, and using the WPF Image control.
I've never done anything with DirectX. Is it worth diving into it? Would it be any faster than the native WPF stuff? If so how significantly? Or, should I just forget about DirectX and look into areas where I can improve my current approach?
Before somebody says so, I know WPF utilize DirectX. I'm wondering If removing the WPF layer and writing the DirectX myself will improve performance.
I have some experience drawing multi-gigabyte satellite and chart imagery. Working with imagery around 55MB should probably work okay even without trying to optimize it too much. You haven't really given enough detail to recommend one alternative over the other, so I will give my opinion on the pros and cons.
Using 2D windows APIs will be the simplest to implement and should always be fast enough if you don't need to rotate and simply want to display an image and zoom and pan around. If you treat it as one large image the performance will not be as good when you zoom out if you are drawing with halftoning to give a nice smooth image. This is because it will effectively have to read all 55mb of image every time it draws.
To get around this performance issue you can make multiple bitmaps, effectively mip-mapping your image. As you zoom out you can pick the reduced resolution image closest to the resolution you are trying to draw . If you are not familiar with mip-mapping here is a Wikipedia link:
http://en.wikipedia.org/wiki/Mipmap
Implementing it with DirectX will be 10x as difficult. Different graphics hardware has different maximum texture sizes. Most likely you will need to break your image up in to multiple textures to draw and you will also have to keep track of render states, viewing matrices, etc.
However, if you do use DirectX, you can implement lots of real-time photo adjustments You can do real-time rotation by simply adjusting view matrices. You can do real-time contrast, brightness, gamma, and sharpness easily in a pixel shader.
There are two other API's I might suggest. If you are willing to limit yourself to Vista or later then Direct2D would be a little simpler than Direct3D. Also if you ever will need to implement it on a non-windows platform I would suggest using OpenGL instead. My current project is in Direct3D because a few years ago when we started it OpenGL was falling behind and I didn't forsee the popularity of Android devices. I now wish we had used OpenGL instead.
Try profiling to see where WPF is spending its time. Are you displaying the images at their native resolution? If not it might be worthwhile to do some preprocessing and create 1/2 resolution versions.
I'm currently working on an application with the need to display large engineering drawings that can be 8800x6800 or larger. The requirements state that the user should be able to pan and zoom the image. Ideally, they'd like to be able to annotate the images as well. If you look at the Windows Photo Viewer, you'll see the performance and features I'm looking to emulate, minus the annotation part.
So far, I've tried a couple different approaches for displaying the images and none seem to offer the performance that I'm looking for. Either they take up a lot of memory or they're slow. These are the approaches I've taken:
Viewbox with the Image as a child. Memory usage is OK, but re-sizing the Viewbox is slow. I haven't tried zooming/panning with this approach yet because of that.
InkCanvas with the Image set either as the background or as a child. With this approach zooming/panning by way of ScaleTransform and TranslateTransform seemed so-so, but memory usage could be up in the 450-600 MB range.
This is my first foray into image manipulation with .NET/WPF and my knowledge on the subject is fairly limited. What are some best-practices for dealing with large images, especially with WPF? I've read that tiling the image (like deep zoom) can help, but was unsure on how to do this or if it's the best idea in my situation. Do you know of any resources that might help me understand this better?
By "tiling" if you mean splitting the image up into separate pieces and only displaying a small subset at once to improve performance, this would be called "virtualisation".
Microsoft has an excellent blog about virtualising items and even provides a reference implementation of a VirtualCanvas which you can use as the starting point for a virtualised control.
Link here: https://learn.microsoft.com/en-us/archive/blogs/jgoldb/virtualized-wpf-canvas
Note that this blog includes zoom and scale as part of the discussion as well as a discussion about smooth scrolling and pre-emptive loading of tiles for best UI responsiveness.
my current code is normal WPF with a custom image view. I need to pan and zoom a very high resolution picture but of course it needs a lot of CPU-Power to do this.
My question is: if I change the control from a image view to something like directX will this increase my zoom and panning expirience a lot or isnt there such a big difference?
(The graphic card we use is a Nvidia ion2 and the CPU is a intel atom with up to 2 Ghz)
2D acceleration is not as perfected as 3D is. See benchmarks here.
I believe using the picture as a texture and controlling the camera for pan and zoom should increase performance a lot.
From my knowledge WPF uses DirectX to render its content, so I wouldn't think that would give you a high performance boost.
If you're having performance issues I would think the answer is in looking through your caching algorythm.
WPF graphics isn't very powerful. We have made all graphics rendering in Direct3D9, and only displaying the 3D scene in D3DImage control.
When talking about large bitmap rendering, we've found the best way is to create a Direct3D texture. The creating of it reasonably fast, and rendering itself is very fast when the image dimensions is less than natively supported by the GPU (caps.MaxTextureWidth, caps.MaxTextureHeight). That typically is 8k x 8k or 16k x 16k. Talking about bitmaps of hundreds of MB, and should be sufficient for your use too.
To see the performance that can be obtained with it, you can download our Chart control, set a large bitmap to background image to a Geographic map. Then you see also how fast is it too zoom & pan etc. Beats WPF built-in image handling for sure :-)
(I'm one of LightningChart developers at Arction)
I am stumped by this very simple problem. I am making a tile-based game engine and need to be able to allow a user to edit the map using a WPF User Interface. Naively, I had assumed that I could simply constantly update a good old fashioned "buffered" System.Drawing.Graphics.Bitmap using Graphics.FromImage. I would draw onto the bitmap the tiles that make up the map, and then blit the buffer Bitmap to the screen. However, from my thorough research I now believe that it isn't that easy at all.
Rather than bore you with what I've found out so far (that either doesn't work, or is incredibly slow), may I ask very simply, what is the best way for continuously drawing large numbers of bitmaps efficiently via a WPF UI?
I will accept such suggestions as "go back to Windows Forms". If that's the case, then I am going to be very dissapointed with WPF!
The WriteableBitmap class is a high-performance WPF-compatible bitmap that allows direct access to its bits. This MSDN documentation page contains a fairly thorough example of using it.
Freezable can make a big difference to performance when dealing with Bitmaps, you can then also load the buffer using a background thread to stop the UI locking up.
This tutorial covers the basics
I'm trying to visualise a graph and allow people to play with it. I found the excellent Graph# library that can create an initial layout so that part is covered. Now I need to make a control that actually draws it and provides the necessary interactivity.
Graph# comes with a nice visualiser itself, however I don't like it because it is written in WPF (while my app is WinForms), and because I want to add some more interactivity options, which would require quite a remake of it anyway.
The graphs I'm drawing will routinely be pretty large, at about 100 vertices and the same amount of edges (the graphs will be trees 99% of time). That means that the resulting rendering can be up to 2000px by 2000px and even more. The users should be able to zoom in and out, scroll, highlight and drag vertices and edges, and get some popups with additional info when hovering the cursor above a vertex.
I'm worried that the standard System.Drawing might not be able to deliver a decent speed for this. I would like the dragging/zooming/scrolling operations to be smooth, and the popups should open with a little animation as well. Something like 20fps should be a necessity.
I know I can try to speed things up by pre-rendering a lot of the elements and keeping them as bitmaps in memory - but that would probably take up lots of RAM, and I'm still not sure if it would deliver the necessary performance.
What are your thoughts?
"Premature optimization is the root of all evil"
GDI+ can be great for your needs. Don't go and buy 3rd party libraries before you know you even need them.
I've done a thousand polygons on a 1000x800 pixel bitmap and redrawn it completely at over 100 frames per second, using just GDI+
That being said, if you have a lot of drawing to do, and your resolution is big.. Some of the 3rd party drawing libraries can go WAY beyond what managed GDI is capable of.
I recommend leaving Graph# alone, and just hosting it in your Windows Forms application.
The performance you will receive will be much better than trying to reimplement it in System.Drawing.
GDI+ will be plenty fast enough for what you're doing, especially if (as it sounds from your description) everything you're drawing is rectangles and vertical/horizontal lines. Polygons and non-linear shapes are a bit slower, but not much (the speed difference is partially dependent on the SmoothingMode of your Graphics object). Drawing cached Bitmaps with resizing is also quite fast, although it can slow down significantly if you use a high-quality InterpolationMode setting.
As a benchmark, I wrote a .Net Compact Framework GPS application for Windows Mobile that rendered about 10,000 lines on the screen in realtime. This only achieved a frame rate of a few frames per second, but the processing power on a Smartphone is, of course, way less than a modern PC.