I am using the AForge.NET library to acquire image data from my webcam periodically. For debugging reasons, I have to draw out the filtered images to the screen.
Currently I have 6 WPF Images on my main form, and on every second I handle an event which gives me an UnmanagedImage which I convert into System.Drawing.Bitmap and then to BitmapSource - my code looks something like this:
private void OnImageFiltered(object sender, FilterEventArgs e)
{
var bitmapSource = e.UnmanagedImage.ToManagedImage().ToBitmapSource();
pictureBox.Source = bitmapSource;
}
But as I said before, I have 6 Images, and it slows the whole program down.
How can I make it faster?
My ToBitmapSource extension method is here:
public static BitmapSource ToBitmapSource(this System.Drawing.Image source)
{
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(source);
var bitSrc = bitmap.ToBitmapSource();
bitmap.Dispose();
bitmap = null;
return bitSrc;
}
Sorry for writing an answer, but I can't comment yet because of my low reputation.
If the problem still persists, use the Freeze method to make the BitmapSource readonly and therefor passable to a different thread.
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 need to know how to properly dispose of Bitmaps so that I don't have a memory leak.
I am grabbing video in a BackgroundWorker and assigning it to a PictureBox as such:
private void bwVideo_ReadCamera(object sender, DoWorkEventArgs e)
{
Bitmap temp = null;
while (true)
{
Image<Bgr, Byte> frame = logitec.QueryFrame();
if (temp != null)
temp.Dispose();
temp = frame.ToBitmap();
pictureBox2.Image = temp;
}
}
The problem is that I still get a "Out of Memory Exception" with this code. I have tried freeing the pictureBox2.Image variable by using a BackgroundWorker ReportProgress and waiting in the above code for the dispose to finish (you need to be synched with the gui to call dispose on the PictureBox image). I have also tried to use the "Bitmap" property of the Image class which shares data between the Image and Bitmap.
So my questions is, in this situation, what is the proper way to dispose of my image?
You should probably have a using statement for your Image<Bgr, Byte> declaration. See the documentation.
My program has a lot of small images (Image controls are small, not the images themselves) and by saying a lot I mean more than 500. These images are generated asynchronously and then assigned to the Image controls, which were initialized before.
Basically my code does the following:
filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}.JPG", Guid.NewGuid().GetHashCode().ToString("x2")));
converter.ConvertPdfPageToImage(filename, i);
//Fire the ThumbnailCreated event
onThumbnailCreated(filename, (i - 1));
There is no memory leak in code that creates the images, I have the following code:
string[] files = Directory.GetFiles("C:\\Users\\Daniel\\Pictures", "*.jpg");
for(int i=0; i<files.Length; i++){
onThumbnailCreated(files[i], i);
}
Still the problem persists.
This happens in the event handler method:
void Thumbnails_ThumbnailCreated(ThumbnailCreatedEventArgs e, object sender)
{
//Since we generate the images async, we need to use Invoke
this.parent.Dispatcher.Invoke(new SetImageDelegate(SetImage), e.Filename, e.PageNumber);
}
private void SetImage(string filename, int pageNumber)
{
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
//I am trying to make the Image control use as less memory as possible
//so I prevent caching
bitmap.CacheOption = BitmapCacheOption.None;
bitmap.UriSource = new Uri(filename);
bitmap.EndInit();
//We set the bitmap as the source for the Image control
//and show it to the user
this.images[pageNumber].Source = bitmap;
}
With 468 images the program uses about 1Gb of memory and then runs out of it at all. Is my task even possible to achieve using WPF or is the number of images too high? Maybe there is something wrong with my code?
Thanks in advance
You should freeze these images and set their width (or height) to that will be actually used in the application if possible:
// ...
bitmap.DecodePixelWidth = 64; // "displayed" width, this improves memory usage
bitmap.EndInit();
bitmap.Freeze();
this.images[pageNumber].Source = bitmap;
Try this:
private void SetImage(string filename, int pageNumber)
{
using (BitmapImage bitmap = new BitmapImage())
{
bitmap.BeginInit();
//I am trying to make the Image control use as less memory as possible
//so I prevent caching
bitmap.CacheOption = BitmapCacheOption.None;
bitmap.UriSource = new Uri(filename);
bitmap.EndInit();
this.images[pageNumber].Source = bitmap;
}
}
That will dispose of your bitmaps when you're done with them.
It may be the event handlers that are causing your memory leaks.
See this SO question:
Why and How to avoid Event Handler memory leaks?
I need to process (change brightness, contrast etc) very large high-quality bitmaps (often over 10MPx) several times per second and need to update it on screen every time ( on Image control in WPF). Currently I'm using AForge.NET library for unmanaged image processing, but there are some problems I cannot solve. First of all, one operation takes ~300ms (without updating the screen) which is not acceptable for me. Here's sample code:
UnmanagedImage _img;
BrightnessCorrection _brightness = new BrightnessCorrection();
void Load()
{
_img = UnmanagedImage.FromManagedImage((Bitmap)Bitmap.FromFile("image.jpg"));
}
void ChangeBrightness(int val) // this method is invoked by changing Slider value - several times per second
{
_brightness.AdjustValue = val;
_brightness.ApplyInPlace(_img); // it takes ~300ms for image 22MPx, no screen update - just change brightness "in background"
}
I have no experience in image processing, but I think it cannot be much faster since it is very high resolution. Am I right?
Another problem - how to efficiently update the screen? At the moment I have the following (ofc very bad) solution:
void ChangeBrightness(int val)
{
_brightness.AdjustValue = val;
_brightness.ApplyInPlace(_img);
using (MemoryStream ms = new MemoryStream())
{
using (Bitmap b = _img.ToManagedImage())
{
b.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = ms;
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
MyImageControl.Source = new WriteableBitmap(bmp); // !!!
}
}
}
As you can see, every time new WriteableBitmap is created (you can imagine what is happenin). Instead of these "usings" I tried that way:
WriteableBitmapSource.Lock(); // this object (of type WriteableBitmap) is just MVVM ViewModel's property which is binded to MyImageControl.Source
WriteableBitmapSource.Source.WritePixels(new Int32Rect(0, 0, _img.Width, _img.Height), _img.ImageData, _img.Stride * _img.Height * 3, _img.Stride, 0, 0); // image's PixelFormat is 24bppRgb
... but WritePixels method throws "Value does not fall within the expected range." Any ideas why?
Any help will be much appreciated :)
P.S.
Is AForge.NET a good choice at all? Maybe there is better image processing lib?
sorry for my english ;P
~300ms for image 22MPx is about 20 ns per pixel. That should be about right.
You need to consider CPU cost and memory access cost.
If you want to improve this further, consider:
1) Use multiple threads, each responsible for a section of the bitmap.
2) Write your own implementation, using SIMD instructions.
3) Do not pre-process the bitmap, transform bitmap scanline when they're needed.
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.