I am trying to capture webcam frames from AForge.Net in C#. Unfortunetaly I get an ArgumentException at _CurrentFrame.LockBits. I suppose there is a problem with my event writing to the locked Bitmap!? Sometimes I also get "A generic error occurred in GDI+" at UnlockBits.
public bool GetFrame(ref Draw.STexture Frame)
{
BitmapData bd = _CurrentFrame.LockBits(new Rectangle(0, 0, _CurrentFrame.Width, _CurrentFrame.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] data = new byte[4 * _CurrentFrame.Width * _CurrentFrame.Height];
Marshal.Copy(bd.Scan0, data, 0, data.Length);
//Do something with data here
_CurrentFrame.UnlockBits(bd);
_CurrentFrame.Dispose();
}
private void OnFrame(object sender, NewFrameEventArgs e)
{
if (_CurrentFrame != null)
_CurrentFrame.Dispose();
_CurrentFrame = (Bitmap)e.Frame.Clone();
}
The Bitmap.Clone() method is dangerous, it creates a shallow copy of the bitmap. That copy stores the pointer to the pixel data instead of copying the pixels. In most camera drivers, that pointer will only be valid while the callback (event) runs. If you try to use it later then you'll be accessing invalid pixel data, making an exception on LockBits highly likely.
Either do the processing while the event runs or create a deep copy with the Bitmap(Image) constructor. That copy tends to be expensive of course.
Related
I'm a newby in C#. I have to repeatedly refresh a GUI picture box in a worker thread. The image is acquired from a camera polling a driver with a GetImage method that retrives the image to be displayed. Even if I allocate the bitmap using directive "using" and explicitly call G.C, memory seems to be never deallocated.
The worker thread is something like this:
while (true)
{
// request image with IR signal values (array of UInt16)
image = axLVCam.GetImage(0);
lut = axLVCam.GetLUT(1);
DrawPicture(image, lut);
//GC.Collect();
}
While the DrawPicture method is something like
public void DrawPicture(object image, object lut)
{
[...]
// We have an image - cast it to proper type
System.UInt16[,] im = image as System.UInt16[,];
float[] lutTempConversion = lut as float[];
int lngWidthIrImage = im.GetLength(0);
int lngHeightIrImage = im.GetLength(1);
using (Bitmap bmp = new Bitmap(lngWidthIrImage, lngHeightIrImage)) {
[...many operation on bitmap pixel...]
// Bitmap is ready - update image control
//SetControlPropertyThreadSafe(tempTxtBox, "Text", string.Format("{0:0.#}", lutTempConversion[im[160, 100]]));
//tempTxtBox.Text = string.Format("{0:00000}", im[160, 100]);
//System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
}
}
Problems arises with the
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
In fact commenting that line of code, garbage collection works as it would.
Better, the problem seems to be with
System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())
Any advice to solve this memory leak?
Thanks a lot!
Image implements IDisposable, so you should call Dispose on each Image instance that you create, when it is no longer needed. You could try to replace this line in your code:
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
With this:
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
This will dispose the previous image (if any) before the new one is assigned.
The thing is, you're making a GDI bitmap of bmp with GetHbitmap, which according to msdn:
You are responsible for calling the
GDI DeleteObject method to free the
memory used by the GDI bitmap object.
Then the FromHbitmap method makes a copy of the GDI bitmap; so you can release the incoming GDI bitmap using the GDI DeleteObject method immediately after creating the new Image.
So basically I would add:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
...
IntPtr gdiBitmap = bmp.GetHbitmap();
// Release the copied GDI bitmap
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(gdiBitmap);
// Release the current GDI bitmap
DeleteObject(gdiBitmap);
I am unsure if you need the GDI bitmap to perform some kind of transformation. In case you don't you can just assign the bitmap to the Image property of your PictureBox, and ignore the former solution:
// Since we're not using unmanaged resources anymore, explicitly disposing
// the Image only results in more immediate garbage collection, there wouldn't
// actually be a memory leak if you forget to dispose.
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = bmp;
There are several ways to release an image from pbox. I strongly recommend the way is that do not use pbox.Image = Image.FromFile.... If you do not use FileStream and you want to read it from file use BitMap class. Like this:
Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.
... and then you want to release the image file bmp.Dispose();
Now you can delete, move or whatever you want to the file.
I have a method in c# that the only thing it does its LockBits, and then UnlockBits, and the images(input/output, transformed to byte arrays) are different. The one from output has less 100 and something bytes than the one from the input. This happens only with .jpg files. And checking the files in HxD I came to the understanding that it´s removing a part of the header, the exif signature to be exact. But I don't know how and why.
Does someone know what this is doing?
Here's the code:
public Image Validate (image){
BitmapData original = null;
Bitmap originalBMP = null;
try{
originalBMP = image as Bitmap;
original = originalBMP.LockBits(new Rectangle(0, 0,
originalBMP.Width, originalBMP.Height),
ImageLockMode.ReadWrite,
originalBMP.PixelFormat);
originalBMP.UnlockBits(original);
}catch{}
return image;
}
Calling Bitmap.LockBits() followed by Bitmap.UnlockBits() does nothing.
The behavior you observe is because of loading a JPEG image, and then saving it again. JPEG uses a lossy algorithm. So what happens:
You load the JPEG from disk
The JPEG data gets decoded into individual pixels with color information, i.e. a bitmap
You save the bitmap again in the JPEG format, resulting in a different file than #1
You also potentially lose metadata that was present in the JPEG file in doing so. So yes, the file is different and probably smaller, because every time you do this, you lose some pixel data or metadata.
Lockbits/Unlockbits are used to allow the program to manipulate the image data in memory. Nothing more, nothing less. See also the documentation for those methods.
Use the LockBits method to lock an existing bitmap in system memory so that it can be changed programmatically. You can change the color of an image with the SetPixel method, although the LockBits method offers better performance for large-scale changes.
A Rectangle structure that specifies the portion of the Bitmap to lock.
Example:
private void LockUnlockBitsExample(PaintEventArgs e)
{
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}
I am new here.
In my application i assign Bitmap image to picturebox. But after some time my application crash. I also maintan try catch and logs but application is just crash.
Here is my code:
System.Drawing.Bitmap ImageBMP = new System.Drawing.Bitmap(ImageWidth, ImageHeight, stride, PixelFormat.Format8bppIndexed, new IntPtr(scan0));
if (Picturebox1!= null && Picturebox1.Image != null)
{
Picturebox1.Image.Dispose();
Picturebox1.InitialImage = null;
}
Picturebox1.Image =ImageBMP;
Thanks in advance.
Because you disposed the object inside if block. Remove that and it won't give error.
Picturebox1.Image.Dispose();
Hope helps,
You are using a raw pointer there. Where does that come from? It is advised to use managed arrays, unless you can be 100% sure that that pointer will remain valid.
If it comes from a LockBits operation on another image, it will not remain valid; it will stop being reliable from the moment the other image is unlocked.
If you are planning to clone or edit an 8bpp image, it is much safer to copy the contents of the images you're manipulating into normal managed Byte[] arrays, using LockBits and Marshal.Copy, and to copy them back into Bitmap objects the same way, rather than using pointers directly.
These pieces of code should set you on your way:
Get the backing byte array from an image:
/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <param name="stride">Stride of the retrieved image data.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageData(Bitmap sourceImage, out Int32 stride)
{
BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
stride = sourceData.Stride;
Byte[] data = new Byte[stride * sourceImage.Height];
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
sourceImage.UnlockBits(sourceData);
return data;
}
Create an image from a byte array: (rather than from a pointer)
A: Why must “stride” in the System.Drawing.Bitmap constructor be a multiple of 4?
And, combined and optimised:
Make a deep clone of an image to load it without any linked resources
A: Free file locked by new Bitmap(filePath)
Note, as for your disposing... you should never dispose an image still linked to the UI, since the next repaint of the UI will attempt to use the disposed image, which will inevitably cause a crash. The correct way to do this is to store the image reference in a variable, then make it null on the UI, and then dispose it:
if (Picturebox1 != null && Picturebox1.Image != null)
{
Image img = Picturebox1.Image;
Picturebox1.Image = null;
img.Dispose();
}
I need to include a camera image in my UI. The solution that I came up with for the View and ViewModel is given below. In the ViewModel I am using a BitmapSource which hold the camera image and that is continuously update, whenever the camera signals a new frame. To this BitmapSource I bind the View.
This code works find for the most part. However I have the issue that the application periodically consumes very large amounts of memory. When the video has not started up yet, the consumption is ~245MB. But when the video starts, it will quickly climb to ~1GB within ~4 seconds, which is when the Garbage-Collector kicks in and reduces that value back down to ~245MB. At this point the video will briefly stutter (I suspect due to CPU taxation). This happens periodically, every 4 seconds or so. Sometime, when the GC does not kick in after 4 seconds, memory usage can even reach 2GB and has also caused an out-of-memory exception.
The way I found to remedy this, is to explicitly call the GC each time a the frame is updated. See the two commented lines. When doing this, the memory will continue to hover at ~245MB after the video starts.
However this causes a significant increase in CPU usage from ~20% to ~35%.
I do not understand very well how the GC works, but I suspect, the reason that the GC kicks in so late, is that the thread that updates the BitmapSource is busy with updating the video (which runs at 25FPS) and therefore does not have time to run GC unless it explicitly told to do so.
So my question is: What is the reason for this behavior and is there a better way to achieve, what I am trying to do, while avoiding the explicit call to the GC?
I have tried wrapping this in a using-statement, but BitmapSource does not implement IDisponsable and from what I understand using is not created for this case, but for when you are accessing external/unmanaged resources.
Here is the code:
CameraImageView:
<Image Source="{Binding CameraImageSource}"/>
CameraImageViewModel:
public class CameraImageViewModel : ViewModelBase
{
private ICamera camera;
private UMat currentImage;
public BitmapSource CameraImageSource
{
get { return cameraImageSource; }
set
{
cameraImageSource = value;
RaisePropertyChanged("CameraImageSource");
}
}
private BitmapSource cameraImageSource;
public CameraImageViewModel(ICamera camera)
{
this.camera = camera;
camera.EventFrame += new EventHandler(UpdateCameraImage);
}
private void UpdateCameraImage(object s, EventArgs e)
{
camera.GetMatImage(out currentImage);
// commenting from here on downward, will also remove the described memory usage, but then we do not have an image anymore
BitmapSource tmpBitmap = ImageProcessing.UMatToBitmapSource(currentImage);
tmpBitmap.Freeze();
DispatcherHelper.CheckBeginInvokeOnUI(() => CameraImageSource = tmpBitmap);
//GC.Collect(); // without these lines I have the memory issue
//GC.WaitForPendingFinalizers();
}
}
ImageProcessing.UMatToBitmapSource:
public static BitmapSource UMatToBitmapSource(UMat image)
{
using (System.Drawing.Bitmap source = image.Bitmap)
{
return Convert(source);
}
}
/*
* REF for implementation of 'Convert': http://stackoverflow.com/questions/30727343/fast-converting-bitmap-to-bitmapsource-wpf/30729291#30729291
*/
public static BitmapSource Convert(System.Drawing.Bitmap bitmap)
{
var bitmapData = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
var bitmapSource = BitmapSource.Create(
bitmapData.Width, bitmapData.Height, 96, 96, PixelFormats.Gray8, null,
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
bitmap.UnlockBits(bitmapData);
return bitmapSource;
}
Replace creating new BitmapSource every UpdateCameraImage with with usage of single WriteableBitmap that you create once and update frequently. This way you will avoid creating copies of image in memory.
This code assumes that ImageWidth and ImageHeight do not change with time and are known in advance. If that is not the case, you will have to recreate the image dynamically when dimensions change.
Replace your cameraImageSource with:
private cameraImageSource = new WriteableBitmap(
ImageWidth,
ImageHeight,
96,
96,
PixelFormats.Gray8,
null);
Change your UpdateCameraImage to:
private void UpdateCameraImage(object s, EventArgs e)
{
camera.GetMatImage(out currentImage);
System.Drawing.Bitmap bitmap = currentImage.Bitmap;
var bitmapData = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, ImageWidth, ImageHeight),
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
cameraImageSource.CopyPixels(new Int32Rect(0, 0, ImageWidth,
ImageHeight), bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
bitmap.UnlockBits(bitmapData);
}
It's also possible that calling currentImage.Bitmap on UMat is not necessary. I don't know EmguCV library which you seem to be using, but UMat has also other properties like Ptr that could be passed directly to CopyPixels.
I'm a newby in C#. I have to repeatedly refresh a GUI picture box in a worker thread. The image is acquired from a camera polling a driver with a GetImage method that retrives the image to be displayed. Even if I allocate the bitmap using directive "using" and explicitly call G.C, memory seems to be never deallocated.
The worker thread is something like this:
while (true)
{
// request image with IR signal values (array of UInt16)
image = axLVCam.GetImage(0);
lut = axLVCam.GetLUT(1);
DrawPicture(image, lut);
//GC.Collect();
}
While the DrawPicture method is something like
public void DrawPicture(object image, object lut)
{
[...]
// We have an image - cast it to proper type
System.UInt16[,] im = image as System.UInt16[,];
float[] lutTempConversion = lut as float[];
int lngWidthIrImage = im.GetLength(0);
int lngHeightIrImage = im.GetLength(1);
using (Bitmap bmp = new Bitmap(lngWidthIrImage, lngHeightIrImage)) {
[...many operation on bitmap pixel...]
// Bitmap is ready - update image control
//SetControlPropertyThreadSafe(tempTxtBox, "Text", string.Format("{0:0.#}", lutTempConversion[im[160, 100]]));
//tempTxtBox.Text = string.Format("{0:00000}", im[160, 100]);
//System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
}
}
Problems arises with the
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
In fact commenting that line of code, garbage collection works as it would.
Better, the problem seems to be with
System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())
Any advice to solve this memory leak?
Thanks a lot!
Image implements IDisposable, so you should call Dispose on each Image instance that you create, when it is no longer needed. You could try to replace this line in your code:
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
With this:
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
This will dispose the previous image (if any) before the new one is assigned.
The thing is, you're making a GDI bitmap of bmp with GetHbitmap, which according to msdn:
You are responsible for calling the
GDI DeleteObject method to free the
memory used by the GDI bitmap object.
Then the FromHbitmap method makes a copy of the GDI bitmap; so you can release the incoming GDI bitmap using the GDI DeleteObject method immediately after creating the new Image.
So basically I would add:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
...
IntPtr gdiBitmap = bmp.GetHbitmap();
// Release the copied GDI bitmap
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(gdiBitmap);
// Release the current GDI bitmap
DeleteObject(gdiBitmap);
I am unsure if you need the GDI bitmap to perform some kind of transformation. In case you don't you can just assign the bitmap to the Image property of your PictureBox, and ignore the former solution:
// Since we're not using unmanaged resources anymore, explicitly disposing
// the Image only results in more immediate garbage collection, there wouldn't
// actually be a memory leak if you forget to dispose.
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = bmp;
There are several ways to release an image from pbox. I strongly recommend the way is that do not use pbox.Image = Image.FromFile.... If you do not use FileStream and you want to read it from file use BitMap class. Like this:
Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.
... and then you want to release the image file bmp.Dispose();
Now you can delete, move or whatever you want to the file.