C# Fast load Bitmap into PictureBox - c#

I receve Bitmap image from a camera at 30 fps, and I need to display all images in a pictureBox.
The problem is that the PictureBox is very slow!
I have try to implement a custom PictureBox with DoubleBuffer enabled but the problem is not resolved.
Do you have a custom PictureBox or an user control or a solution that can display the image faster?
Additional information:
The image resolution is 2048x1088 with 256 graylevel (8bit image).
I use AForge.NET for elaborate the images.
Thank you

That image gets expensive to draw when it has to be resized to fit the PB's client area. Which is very likely in your case because your images are pretty large. It uses a high-quality bi-cubic filter to make the resized image look good. That's pretty expensive, albeit that the result is good.
To avoid that expense, resize the image yourself before assigning it to the Image property. Make it just as large as the PB's ClientSize.
That's going to make a big difference in itself. The next thing you can do is to create the scaled bitmap with the 32bppPArgb pixel format. It's the format that's about 10 times faster then any other because it matches the video adapter on most machines so no pixel format conversions are necessary.

Related

Why does GetThumbnailImage create blurry images

I am creating thumbnails of images. I've implemented the thumbnail display in two ways
1 - given an image, create a new thumbnail using the above method.
2 - given an image, grab the dimensions, calculate the resized dimensions and then set that as the dimensions of the PictureBox. The PictureBox is set to auto-zoom mode, so it will scale the image down to 1/4.
Both methods generate thumbs that are 1/4 the original size of the input image (display only, I am not worried about saving or working with the image), but the second method produces a much clearer thumbnail, although I guess it would use more memory since I don't think zooming the control actually affects the image.
Why is the resulting thumbnail very blurry when GetThumbnailImage is used?
See the remarks in the documentation:
If the Image contains an embedded thumbnail image, this method retrieves the embedded thumbnail and scales it to the requested size. If the Image does not contain an embedded thumbnail image, this method creates a thumbnail image by scaling the main image.
The GetThumbnailImage method works well when the requested thumbnail image has a size of about 120 x 120 pixels. If you request a large thumbnail image (for example, 300 x 300) from an Image that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image. It might be better to scale the main image (instead of scaling the embedded thumbnail) by calling the DrawImage method.
So it can happen that you get an up-scaled embedded thumbnail.

Factors Affecting Time to Render Image using GDI+

This is a follow on to my previous question Speeding Up Image Handling
Apologies if I should have amended that question in some way rather than starting a new one.
I have tried all sorts of different things to speed up the drawing of an image on screen.
I thought that compressing the image until it is smaller would have an effect. However while this might save memory for the object I do not think it has any effect on how long it takes to draw. I tried converting the image to jpeg and using 100% compression. However while this creates a blocky image it does not affect the drawing time. I now think this is because the number of pixels that get rendered is not changed by this
I tried reducing the color palette to 256 colors. This makes the size smaller since it uses less bytes per pixel but does not seem to affect drawing on screen. I had thought that reducing the bytes per pixel GDI+ has to handle might save some time but it is not enough for me to see so far.
So am I wasting my time looking at compression and palette?
I assume that time taken will be affected by the number of pixels to be drawn (width x height) and I have resized the image to match the pixel size as displayed on screen. I think this is the one thing that does have an effect....
I have looked at how to stop autoscaling of the image - does my resize stop that or can the image still be autoscaled when it is rendered?
I am wondering if I can replace the DrawImage call with something using p/Invoke or other API call (which I admit I don't really understand).
You could use the Bitblt P/Invoke, which copies image data directly. It does require some initialisation to convert the image data to something the display device understands, but this copy operation is lightning fast. If you would like to know what exactly is happening in DrawImage btw, use a tool like ILSpy or Reflector.NET to inspect the method.
See BitBlt code not working for an example. For some information about Bitblt see http://www.codeproject.com/KB/GDI-plus/flicker_free.aspx.

Draw a bitmap from a control taller than the screen

I am having quite a few problems saving a C# control to a bitmap file. The control in question is a kind of drawing surface on which the user can write text, draw pictures and paint boxes. The control is resizable and draggable. What happen is, when the control is really big and is not totally visible on the screen, the parts of the control not visible are saved half-drawn on the bitmap. The code used to generate the bitmap is quite simple:
Bitmap bitmap = new Bitmap(myControl.Width, myControl.Height);
myControl.DrawToBitmap(bitmap);
I have tried the following methods to try to have a fully painted bitmap, without any success:
myControl.Invalidate(myControl.ClientRectangle, true);
myControl.Refresh();
myControl.Update();
Application.DoEvents();
I cannot scale the control down to make it fully visible since resolution and image quality are very important for that project. In fact, I am actually trying to scale the image up to increase it's quality. Are there ways I am not aware of generating an image from a control ?
Tank you.
DrawToBitmap has limitations and dont always work as expected. Try instead work with native GDI+
Here is example
Maybe my answer here Capturing a Window that is hidden or minimized can help you?

How can I resize an image in C# while retaining high quality?

I found an article on image processing from here: http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing Everything works fine.
I want to keep the high quality when resizing the image. I think if I can increase the DPI value I can achieve this. Does anyone know if this is possible? And if so, how can I implement it in C#?
For starters, it's worth pointing out that there are two general categories of images; vector [e.g. SVG, WMF, Adobe Illustrator and Corel Draw Graphics] and bitmap (also called raster) images [e.g. Bitmap, JPEG and PNG Images].
Vector images are formed from a series of mathematical equations and/or calculations. Bitmap images, on the other hand, are made up of individual dots (pixels) each corresponding to a particular feature on the object the image is taken of.
If it should happen that you want to resize an image, the first thing to consider is if it is a bitmap or vector image. By virtue of the fact that vector images are obtained from calculations, they can be perfectly resized without losing any detail. The case is different for bitmap images. Since each pixel is independent of the other, when you desire to resize it, you are simply increasing or decreasing the source to target pixel ratio.
So in order to double the size of a vector image, simply multiply the target dimensions by two and everything comes out all right. If you should apply the same effect on a bitmap, you are actually increasing each source pixel to cover four pixels (two rows of two horizontal pixels).
Of course, by applying interpolation and filtering, the computer can "smooth" out the edges of the target pixels so they seem to blend into each other and give the appearance of a reasonably resized image but this output is never the same as resizing a vector image; vector images resize perfectly.
You also mentioned DPI in your question. DPI is essentially the number of pixels that correspond to an inch when the image is printed not when it is viewed on a screen. Therefore by increasing the DPI of the image, you do not increase the size of the image on the screen. You only increase the quality of print [which needless to say depends on the maximum resolution of the printer].
If you really desire to resize the image and the image is a bitmap, as a rule of thumb, do not increase the size beyond 200% of the original image's size else you'll lose the quality.
You can see this answer for code to resize bitmap images.
To see a sample vector image, go to this link.
Note Try zooming in and out of the image to see how well it resizes.
A typical bitmap are the StackOverflow sprites. They do not keep their quality resized.
Further Reading
Vector Graphics: http://en.wikipedia.org/wiki/Vector_image
Bitmap Graphics: http://en.wikipedia.org/wiki/Bitmap_image
Simply If the original image is smaller then the re-sized image then there is hardly anything you can do. Rest is a research problem.
This would only be possible if it's a vector graphic. Look into SVG. Otherwise, I think you might need Silverlight or Flex for that part.
What you're asking isn't really possible. You can't enlarge an image while maintaining the same quality.
If you think about an image as a mapped array of pixels (literally, a "bit-map"), this makes sense. The image is saved with a fixed amount of data, and that's all you have to work with when you resize it. Any examples to the contrary (like TV shows, as suggested by one of the comments) are purely fictional.
The best that you can do is set the InterpolationMode property of the Graphics object you're using to do the resizing to "HighQualityBicubic", which is the highest quality smoothing algorithm supported by GDI+ and in fact by every major graphics package on the market. It's the best that even Adobe Photoshop has to offer. Essentially, interpolation means that the computer is calculating the approximate value of the new pixels you're adding to make the image larger from the relative values of neighboring pixels. It's a "best guess" method, but it's the best compromise we've come up with yet.
At the very least, the resulting images won't have "jaggies" or rough, pixelated lines.
Sample code:
Graphics g;
g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
// ... insert the rest of your code here
Beyond that, it's worth noting that GDI+ (which the .NET Framework uses internally for graphics routines) works best with image sizes that are multiples of 16. So if it all possible, you should try and make the width and height of your resized images a multiple of 16. This will preserve as much of the original image quality as possible.
The ideal solution is to switch to vector graphics that can be resized at will. Instead of pixel information, they contain mathematical information used to draw or "render" the image. Read more on Wikipedia.
let's try metadata in GDI+, may be it can suit your request

How can you draw 32bppargb images with the Win32 AlphaBlend function?

I've been fussing with this for the better part of the night, so maybe one of you can give me a hand.
I have found GDI+ DrawImage in C# to be far too slow for what I'm trying to render, and from the looks of forums, it's the same for other people as well.
I decided I would try using AlphaBlend or BitBlt from the Win32 API to get better performance. Anyway, I've gotten my images to display just fine except for one small detail—no matter what image format I use, I can't get the white background to disappear from my (transparent) graphics.
I've tried BMP and PNG formats so far, and verified that they get loaded as 32bppargb images in C#.
Here's the call I'm making:
// Draw the tile to the screen.
Win32GraphicsInterop.AlphaBlend(graphicsCanvas, destination.X, destination.Y, this.TileSize, this.TileSize,
this.imageGraphicsPointer, tile.UpperLeftCorner.X, tile.UpperLeftCorner.Y,
this.TileSize, this.TileSize,
new Win32GraphicsInterop.BLENDFUNCTION(Win32GraphicsInterop.AC_SRC_OVER, 0,
Convert.ToByte(opacity * 255),
Win32GraphicsInterop.AC_SRC_ALPHA));
For the record, AC_SRC_OVER is 0x00 and AC_SRC_ALPHA is 0x01 which is consistent with what MSDN says they ought to be.
Do any of you guys have a good solution to this problem or know a better (but still fast) way I can do this?
Graphics.DrawImage() speed is critically dependent on the pixel format. Format32bppPArgb is 10 times faster than any other one on any recent machine I've tried.
Also make sure you the image doesn't get resized, be sure to use a DrawImage() overload that sets the destination size equal to the bitmap size. Very important if the video adapter's DPI setting doesn't match the resolution of the bitmap.
Have you tried an opacity of just 255 rather than a calculated one?
This blog post describes what you're trying to do:-
http://blogs.msdn.com/andreww/archive/2007/10/10/preserving-the-alpha-channel-when-converting-images.aspx
Critical thing is that he carries out a conversion of the image to make the alpha channel compatible..
Ok. From a pure Win32 perspective:
In order for AlphaBlend to actually alpha blend... it needs the source device context to contain a selected HBITMAP representing an image with 32bpp bitmap with a pre-multiplied alpha channel.
To get a device bitmap with 32bpp you can either call one of the many functions that will create a screen compatible device bitmap and hope like hell the user has selected 32bpp as the desktop bitdepth. OR, ensure that the source bitmap is a DIBSection. Well, the library or framework that is creating it from the loaded image for you.
So, C# is loading your images with 32bpp argb, BUT, how are you converting that C# representation of the bitmap into a HBITMAP? You need to ensure that a DIB Section is being created, not a DDB (or device dependent bitmap), and that the DIB Section is 32bpp.

Categories

Resources