I'm working on an application where the performance is very important. This application requires lots of image processing so, as most of us know that Bitmap's pixels accessing using GDI+ methods GetPixel and SetPixel is quite slow. To solve this issue we use Bitmap.LockBits and Bitmap.UnlockBits methods and i'm totally aware of how to access pixels using this method but my question is:
What is the performance of both Bitmap.LockBits and Bitmap.UnlockBits ? Do they perform any pixels copying or something that may have non-linear order?
I'm asking this question because I found a lots of calling for Bitmap.LockBits and Bitmap.UnlockBits methods in my code. I made a search but I didn't find anything
LockBits method returns BitmapData object, which is used to describe the memory sector.
BitmapData _bmd = _bmp.LockBits(new Rectangle(0, 0, _bmp.Width,_bmp.Height) , ImageLockMode ReadWrite, _bmp.PixelFormat);
Take a look here http://www.mfranc.com/programming/operacje-na-bitmapkach-net-1/
Update:
Lockbits will copy the bitmap data from a bitmap to a location in memory that is ready to be read/written to. The lockbits function will give you Scan0 that is a pointer to the start of this bitmap data.So it involves copying but even that would be much faster when compared to the Normal GDI+ Operation as per the comparison chart above.Also look out for out of bound memory .
Related
I have written some code to retrieve frames from a camera, along with information obtained from these frames, and to display them on a form.
All the data that I get is unmanaged as it comes form a library of my own written in c++ and working with OpenCv.
I prefer getting all the data at once with a single function call and not using a wrapper to OpenCv that would PInvoke several times to get the same result. Furthermore for me the code is easier to maintain and I have much more control on everything that is going on and I have many other reason to prefer this approach.
Everything is ok, (seemingly) perfectly working and I’m happy, but… there is something I would like to understand better with your help.
At a certain point I create a bitmap with the unmanaged pixel data with the method
public Bitmap(int width,int height,int stride,PixelFormat format, IntPtr scan0);
My question are the following (I have some idea, but just tell me if I’m right) :
1) I don’t release the data pointed by scan0 as I think that, once the data is owned by the bitmap object, it will do the job for me via its Garbage Collection. Am I right?
2) I don’t like the fact that a new instance of bitmap is created and allocated every time (apart from the pixel data), but I suppose that there is no better way of getting a Bitmap out of unmanaged data.
3) I think that there is no need to tell the Garbage Collector that there is a big amount of data to clean up with GC.AddMemoryPressure(…) as it knows it, estimating from the information provided with the initialization.
EDIT
I've found on the documentation
The caller is responsible for allocating and freeing the block of memory specified by the scan0 parameter. However, the memory should not be released until the related Bitmap is released.
The only way to do this is that the Bitmap object created in such a way leaves the data untouched and doesn't change its position in memory.
1) I don’t release the data pointed by scan0 as I think that, once the
data is owned by the bitmap object, it will do the job for me via its
Garbage Collection. Am I right?
No, the garbage collector knows nothing about the object, which you've initialized on the unmanaged side, that is why it is unmanaged. So you have to call delete in the unmanaged code to release the allocated memory.
2) I don’t like the fact that a new instance of bitmap is created and
allocated every time (apart from the pixel data), but I suppose that
there is no better way of getting a Bitmap out of unmanaged data.
There is a way and a keyword is unsafe. You can run the c++ code inside of the unsafe block, but you must allow this in the c# project settings. So you can reuse every pixel of once initialized bitmap
unsafe
{
byte stlThres = 115;
Bitmap myBmp = ...; // init the bitmap
var data = myBmp.LockBits(new Rectangle(0, 0, myBmp.Width, myBmp.Height), ImageLockMode.WriteOnly, myBmp.PixelFormat);
for (int y = 0; y < data.Height; y++)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
//...
}
3) I think that there is no need to tell the Garbage Collector that
there is a big amount of data to clean up with GC.AddMemoryPressure(…)
as it knows it, estimating from the information provided with the
initialization.
If you created a managed Bitmap object (with new), it will be released automatically after it gets out of scope or will not be referenced any longer.
How do you get a bitmap from a graphics object (or at least a pointer to it's Scan0)?
If a graphics object really always refers to a bitmap, then it IS possible to get to the bitmap data from the graphics object. (Think: the graphics object HAS TO have a pointer to the bmp data. I'd code it in C but I'm on a project that requires everyone be hobbled by .NET.)
Applications of this would include things like:
- using unsafe code to obtain faster screenshots
- modifying what's on a control using CreateGraphics
- (and the task I'm actually trying to accomplish which would take too long to explain)
Yes, this has been asked before but never answered. I'm not looking for how to get a graphics object from a bitmap (obviously trivial).
FAIL1, FAIL2, FAIL3, FAIL4, FAIL5, FAIL6, FAIL7
I don't think what you're trying to do is possible since your assumption that "a graphics object really always refers to a bitmap" is false.
There's a good article here that shows how to render a control to bitmap if you really want a bitmap and another one here that shows how to quickly update the screen at the WndProc level. If you're more familiar with C++ that might get you going the right direction.
I know, I know... there are many others posts like this. I didn't find what I was look for, let's move on.
I break a PDF into images using this GhostScript implementation for C# and then try to load each image into a Bitmap, sometimes it gives me a Parameter is not valid error on this line:
[...]new Bitmap((Image)Image.FromFile(imagePath))[...]
Image.FromFile(imagePath) successfully returns an Image (though I think it's returning a Bitmap) but then Bitmap's constructor gives me the error. What am I doing wrong?
P.S.
I'm casting the result to Image because when I quick watch the result of Image.FromFile(...) it shows it as a System.Drawing.Bitmap (either way, cast, no cast, yields the same result).
You shouldn't create a new bitmap from the bitmap, just cast the reference to the bitmap that you have already:
Bitmap b = (Bitmap)Image.FromFile(imagePath);
If you create a new bitmap from the bitmap that you load from the file, you don't get any reference to the bitmap that you loaded. As you can't dispose that bitmap you will leave them for the garbage collector to finalise, and if that doesn't happen fast enough you may run out of memory.
Try using the Bitmap constructor that receives a path to the image like so:
var b = new Bitmap(imagePath);
I'm trying to AND two bitmaps like this:
[DllImport("gdi32.dll")]
public static extern int SetROP2(IntPtr hDC, int nDrawMode);
const int SRCAND = 0x008800C6; // AND raster op.
lock (g.Clip)
{
IntPtr pDC = g.GetHdc ();
SetROP2 (pDC, SRCAND);
g.DrawImageUnscaled (currentBitmap, bound.Location);
g.ReleaseHdc (pDC);
}
But I get an "Object is currently in use elsewhere" exception from the Draw statement. Moving the ReleaseHdc statement before the Draw statement runs, but doesn't use the specified raster op.
The LockBits approach is too slow, since it copies the whole bitmap twice, one of the bitmaps is huge, and this has to happen many times per second.
Any ideas how I can trick .NET into ANDing bitmaps?
lock (g.Clip)
This cannot work. You are getting this exception because you use the bitmap in more than one thread. I'd guess at another thread that's drawing the bitmap. To make that work, you have to make sure that the two threads cannot use the bitmap at the same time. And that indeed requires the lock keyword. But on the same lock object. The Graphics instance you use won't be the same. The lock doesn't work.
Create a dedicated locking object that both threads use.
Though you found a workaround, it is worth noting the actual source of the exception. GDI and GDI+ operations cannot be interleaved - either one or the other can operate at once, but not both.
In your code, calling g.GetHdc() switches the Graphics object into a state where the newly created HDC can be used for GDI rendering. The Graphics object will then be "in use" until calling g.ReleaseHdc(). At this point, the HDC is destroyed, and the Graphics object can then be used again for rendering.
Noting that the HDC returned by the call to GetHdc() was ney created, and only exists until the call to ReleaseHdc(), where it is destroyed, it is apparent why the ROP is not applied to later operations performed by the Graphics object.
If you needed to use GDI ROPs, you would have to do all associated rendering in a pure GDI context - using Bitmap.GetHbitmap() to get the necessary handles. Be aware that similar to Graphics.GetHdc(), the HBITMAP is newly created from the Bitmap, but shares no state with it.
More details about GDI/GDI+ interop are given in KB 311221
I'm using the System.Drawing classes to generate thumbnails and watermarked images from user-uploaded photos. The users are also able to crop the images using jCrop after uploading the original. I've taken over this code from someone else, and am looking to simplify and optimize it (it's being used on a high-traffic website).
The previous guy had static methods that received a bitmap as a parameter and returned one as well, internally allocating and disposing a Graphics object. My understanding is that a Bitmap instance contains the entire image in memory, while Graphics is basically a queue of draw operations, and that it is idempotent.
The process currently works as follows:
Receive the image and store it in a temporary file.
Receive crop coordinates.
Load the original bitmap into memory.
Create a new bitmap from the original, applying the cropping.
Do some crazy-ass brightness adjusting on the new bitmap, maybe (?) returning a new bitmap (I'd rather not touch this; pointer arithmetics abound!), lets call this A.
Create another bitmap from the resulting one, applying the watermark (lets call this B1)
Create a 175x175 thumbnail bitmap from A.
Create a 45x45 thumbnail bitmap from A.
This seems like a lot of memory allocations; my question is this: is it a good idea to rewrite portions of the code and reuse the Graphics instances, in effect creating a pipeline? In effect, I only need 1 image in memory (the original upload), while the rest can be written directly to disk. All the generated images will need the crop and brightness transformations, and a single transformation that is unique to that version, effectively creating a tree of operations.
Any thought or ideas?
Oh, and I should probably mention that this is the first time I'm really working with .NET, so if something I say seems confused, please bear with me and give me some hints.
Reusing Graphics objects will probably not result in significant performance gain.
The underlying GDI code simple creates a device context for the bitmap you have loaded in RAM (a Memory DC).
The bottleneck of your operation appears to be in loading the image from disk.
Why reload the image from disk? If it is already in a byte array in RAM, which it should be when it is uploaded - you can just create a memory stream on the byte array and then create a bitmap from that memory stream.
In other words, save it to the disk, but don't reload it, just operate on it from RAM.
Also, you shouldn't need to create a new bitmap to apply the watermark (depending on how it'd done.)
You should profile the operation to see where it needs improvement (or even if it needs to be improved.)
The process seems reasonable. Each image has to exist in memory before it is saved to disk - so each version of your thumbnails will be in memory first. The key to making sure this works efficiently is to Dispose your Graphics and Bitmap objects. The easiest way to do that is with the using statement.
using( Bitmap b = new Bitmap( 175, 175 ) )
using( Graphics g = Graphics.FromBitmap( b ) )
{
...
}
I completed a similar project a while ago and did some practical testing to see if there was a difference in performance if I reused the Graphics object rather than spin up a new one for every image. In my case, I was working on a steady stream of large numbers of images (>10,000 in a "batch"). I found that I did get a slight performance increase by reusing the Graphics object.
I also found I got a slight increase by using GraphicsContainers in the Graphics object to easily swap different states into/out of the object as it was used to perform various actions. (Specifically, I had to apply a crop and draw some text and a box (rectangle) on each image.) I don't know if this makes sense for what you need to do. You might want to look at the BeginContainer and EndContainer methods in the Graphics object.
In my case, the difference was slight. I don't know if you would get more or less improvement in your implementation. But since you will incur a cost in rewriting your code, you might want to consider finishing the current design and doing some perf tests before rewriting. Just a thought.
Some links you might find useful:
Using Nested Graphics Containers
GraphicsContainer Class
I am only going to throw this out there casually, but if you wanted a quick 'guide' to best practices for working with images, look at the Paint.NET project. For free high-proformance tools for doing image manipulation, look at AForge.NET.
The benefit of AForge is to allow you to do alot of these steps without creating a new bitmap every time. If this is for a website, I can almost guarentee that the code you are working with will be the performance bottleneck for the application.