I'm using EmguCV 3.4.3.3016 to grab frame from camera. Below is the code for simply grab a frame everytime button1 is clicked. My problem is that the program doesn't release resource so memory used for the program is increasing very fast (up to GBs) and lead to program not responding and then crash.
Anyone knows the reason and solution?
private void button1_Click(object sender, EventArgs e)
{
if (cap != null)
{
cap = new VideoCapture(0);
}
Mat img = new Mat();
cap.Grab();
cap.Retrieve(img);
pictureBox1.Image = img.Bitmap;
}
I encountered the same problem like you before. It's not because of your code or the EmguCV, but it related to debugging setting of your solution. Try removing checking at the Tools>Options>Debugging>Suppress JIT optimization on module load.
I can run your code normally. Do you have any other dependency? Which is your machine's window version, 32 or 64 bit? Try to debug it in the correct platform, Debug -> [your-project] Properties -> Build -> Platform target.
Turns out, EmguCV is just the wrapper of OpenCV, we need to clean it up manually by using GC.Collect().
private void button1_Click(object sender, EventArgs e)
{
if (cap != null) //Why... Are you sure? Not cap==null ???
{
cap.Dispose();
cap = new VideoCapture(0);
}
Mat img = new Mat();
cap.Grab();
cap.Retrieve(img);
if (pictureBox1.Image != null)
{
var tempImage = pictureBox1.Image;
pictureBox1.Image = null;
tempImage.Dispose();
}
pictureBox1.Image =new Bitmap( img.Bitmap);
img.Dispose();
}
Related
I have a program in which I use the Aforge library for viewing a webcam.
This works wonder:
LocalWebcamsCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
LocalScannerBarcode = new VideoCaptureDevice(LocalWebcamsCollection[WebcamNumber].MonikerString);
LocalScannerBarcode.NewFrame += LocalScannerBarcode_NewFrame;
LocalScannerBarcode.Start();
and in the new frame event I get the bitmap
System.Drawing.Bitmap frame;
void LocalScannerBarcode_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
{
frame = (System.Drawing.Bitmap)eventArgs.Frame.Clone();
}
now I have to decode what is seen. Basically I have to pass the bitmap to decode.
So global I have;
ZXing.BarcodeReader bcr;
and into the event LocalScannerBarcode_NewFrame
if (bcr == null)
bcr = new ZXing.BarcodeReader();
but as soon as I put the two lines above the event is not called anymore.
Please notice that in Windows forms that works but I have to do it in WPF.
Thanks
Not sure if this helps but have you tried putting the reference to the ZXing library in another project? Something an Helper.
So in you project you will have:
string strResult = Helper.ReadBarcode(frame);
if (strResult != null)
{
... do stuff with the string
}
and in the helper
static ZXing.BarcodeReader bcr;
public static string ReadBarcode(System.Drawing.Bitmap bmp)
{
if (bcr == null)
bcr = new ZXing.BarcodeReader();
return bcr.Decode(bmp).ToString();
}
everyone. I have been stuck here dealing with this bugs for days, but I still couldn't figure it out.
My guess: I think my code has some problem as I did not dispose the object properly after using it, (I'm not very familiar with these concepts of releasing resources, threading) .
I got these code by taking reference of what people did on youtube, but despite me doing exactly the same thing, my code didn't work out nicely.
SITUATION:
I have two picture boxes, left one can take video of me, right one take the snapshot, if you press button1 , you will start the video, clone_button will copy a image i.e. take a snapshot, and save_image should save it to the path reference, however, i get a generic error occured in GDI+ again and again while I'm trying to save it. Also, my debugger seemed to get crazy (i.e. failed to terminate the vshost.exe ) once I ran this program, I have to restart the computer to get my code running again, which is bleak and frustrating.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
//AForge.Video dll
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge;
namespace WebCameraCapture
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private FilterInfoCollection CaptureDevice; // list of webcam
private VideoCaptureDevice FinalFrame;
private void Form1_Load(object sender, EventArgs e)
{
CaptureDevice = new FilterInfoCollection(FilterCategory.VideoInputDevice);//constructor
foreach (FilterInfo Device in CaptureDevice)
{
comboBox1.Items.Add(Device.Name);
}
comboBox1.SelectedIndex = 0; // default
FinalFrame = new VideoCaptureDevice();
}
private void button1_Click(object sender, EventArgs e)
{
FinalFrame = new VideoCaptureDevice(CaptureDevice[comboBox1.SelectedIndex].MonikerString);// specified web cam and its filter moniker string
FinalFrame.NewFrame += new NewFrameEventHandler(FinalFrame_NewFrame);// click button event is fired,
FinalFrame.Start();
}
void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs) // must be void so that it can be accessed everywhere.
// New Frame Event Args is an constructor of a class
{
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();// clone the bitmap
}
private void From1_CLosing(object sender, EventArgs e)
{
if (FinalFrame.IsRunning==true) FinalFrame.Stop();
}
private void save_Click(object sender, EventArgs e)
{
if (pictureBox2.Image != null)
{
Bitmap varBmp = new Bitmap(pictureBox2.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Dispose();
varBmp = null;
varBmp.Save(#"C:\a.png", ImageFormat.Png);
}
else
{ MessageBox.Show("null exception"); }
}
private void clone_Click(object sender, EventArgs e)
{
pictureBox2.Image = (Bitmap)pictureBox1.Image.Clone();
}
}
}
Any AForge.net user can just PRESS the LINK below and try it out. Thanks!
SAMPLE
After having a look at your code, to me it appears that you are disposing of your image right before you save it. Meaning that your program can't save the image, because it doesn't exist anymore. Actually it reads that you've essentially removed the captured image twice, once on dispose, the second when you set it as null.
So if you move the two code segments after the save, it should be working. Granted without using a dialog box to change the name of the file, you'll surely receive an error unless you remove that file after each time it has been created.
private void save_Click(object sender, EventArgs e)
{
if (pictureBox2.Image != null)
{
//Save First
Bitmap varBmp = new Bitmap(pictureBox2.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Save(#"C:\a.png", ImageFormat.Png);
//Now Dispose to free the memory
varBmp.Dispose();
varBmp = null;
}
else
{ MessageBox.Show("null exception"); }
}
If you open the task manager, you can watch how much memory your program is soaking up.
Disposing of the memory after you're done using it, gives it back to the system.
You don't have a dispose inside your FinalFrame_NewFrame thread, so when the camera is reading images,
you should see the memory usage continue to climb until you stop the program.
I've added dispose to my thread, putting the memory usage under control, but now I'm debugging my image saves. Because I'm disposing, I can't save the image lol. My program ends up trying to save a null image file and throws the appropriate error.
I'm using a 2nd picurebox just as you are, but using for example, pbox2.image = pbox1.image, doesn't copy the data, it copies the memory location with the image data, so when I dispose pbox1 to free memory, the image data disappears with the memory location.
So, I had the same issue, and it was resolved one, by moving the dispose method, and two, I had to change the path, it didnt want to save to C:, so I put it on my desktop, you may not have had this issue if you were running as admin but I did so for anyone else who sees this, dont save to the root of C:.
Okay, I do not know what is causing the crash of my app and I simply do not understand what is happening. I will explain shortly what my app CAN do and what is my problem.
Furthermore I read barely any topic about that on here, and was clicking my way through different google sites.
I am not finding a solution, so I have to ask!
I have an image set as Background -> Works fine.
I have a TextBlock which displays different text every 15 seconds, controlled by a timer, each text is saved in a list! -> Works fine.
I have a fade in/fade out of that text -> Works fine.
I have an application bar at the bottom -> Works fine.
Chaing one explicit picture with that peace of code -> Works fine.
private void Appearance_Click(object sender, EventArgs e)
{
Hintergrund.Source = new BitmapImage(new Uri("/Pictures/StarsNight19.jpg", UriKind.Relative));
}
Well I have around 20 different Images, all have pretty the same names, saved in a folder in my project. The path is as shown in the code fragment: /Pictures/StarsNightXX.jpg
Build Action is set to: CONTENT (well tried everything basically..)
Copy To Output Directory is set to: Copy Always.
Now here is my problem.
I saved the names of my images in a List.
.....
pictures.Add("StarsNight4.jpg");
pictures.Add("StarsNight5.jpg");
pictures.Add("StarsNight6.jpg");
....
I use the same operation as before, wanting it to change the image when clicked on the nice little button in my application bar:
private void Appearance_Click(object sender, EventArgs e)
{
Random rnd = new Random();
int next = rnd.Next(0, pictures.Count - 1);
background.Source = new BitmapImage(new Uri("/Pictures/"+pictures.ElementAt(next), UriKind.RelativeOrAbsolute));
}
BOOM APP CRASHES
I just can not figure out where the problem is.
Changing it by writing an explicit name as shown at the beginning is working out fine...
Maybe someone can tell me if the list is causing a problem?
I just can not figure it out.
"looping it" does not work out either:
int i = 0;
private void Appearance_Click(object sender, EventArgs e)
{
if (i >= pictures.Count) i = 0;
background.Source = new BitmapImage(new Uri("/Pictures/" + pictures.ElementAt(i), UriKind.RelativeOrAbsolute));
i++;
}
Because I am testing my App directly on my WP I do not know what kind of exception I get.
No way compiling and testing it on my computer just to let you know.
...
Losing my mind right here.
Kindly try this source code, I've tried to dispose of the object which are created in the source below, use your list and other code such as loop as it is.
private static BitmapImage bi = null;//this line at the top, not in function
private static Image si = null;//this line at the top, not in function
if bi!=null)
{
bi.Dispose();
bi = null;
}
if si!=null)
{
si.Dispose();
si = null;
}
BitmapImage bi = new BitmapImage();
Image si = new Image();
bi.BeginInit();
bi.UriSource = new Uri(#"/img/img1.jpg",UriKind.RelativeOrAbsolute);
bi.EndInit();
si.Source = bi;
I want to show an image from Disk !
private void Button_Click_3(object sender, RoutedEventArgs e)
{
myImage.Source = new BitmapImage(
new Uri("images\\Countries\\dz.png",UriKind.Relative));
}
I'm sure that the filename is correct but
when I press the button, The image doesn't appear, I also made sure that the image is in the front of all other control and that myImage is its name .
Try this:
private void Button_Click_3(object sender, RoutedEventArgs e)
{
try
{
myImage.Source = new BitmapImage(
new Uri(#"images\Countries\dz.png",UriKind.Relative));
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Putting # makes it a literal string (you don't need to provide
escape sequence then)
If the above also doesn't work then it'll show the exception if any
occurs.
BitmapImage bitImg = new BitmapImage();
bitImg.BeginInit();
bitImg.UriSource = new Uri("images\\Countries\\dz.png", UriKind.Relative);
bitImg.EndInit();
myImage.Source = bitImg;
A few things that may help you:
Instead of:
myImage.Source = new BitmapImage(new Uri("images\\Countries\\dz.png",UriKind.Relative));
Try This:
BitmapImage ImageName = new BitmapImage;
ImageName.BeginInit();
ImageName.UriSource = new Uri(#"images\Countries\dz.png",UriKind.Relative);
ImageName.EndInit();
myImage.Source = ImageName;
See below link (examples section at the bottom of the page) for more info.
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx
If the above doesn't work, we will need you to post more code :). Also, it would help if you specify exactly what you are trying to achieve here.
Try to Debug it.
Put a break point on the line(F9) and hit F5 to start debugging. Check the value of myImage.Source after the line is executed (F10 to step).
You can also use the Immediate Window to test other statements while debugging is paused and see the results.
Also make sure that the images folder is in the same folder as the executable file (in Debug or Release folders, according to your build)
This seems like a serious bug :
private void LayoutRoot_Drop(object sender, DragEventArgs e)
{
if ((e.Data != null) && (e.Data.GetDataPresent(DataFormats.FileDrop)))
{
FileInfo[] files = (FileInfo[])e.Data.GetData(DataFormats.FileDrop);
using (FileStream fileStream = files[0].OpenRead())
{
//Code reaching this point.
BitmapImage bmpImg = new BitmapImage();
bmpImg.ImageOpened += new EventHandler<RoutedEventArgs>(bmpImg_ImageOpened);
bmpImg.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(bmpImg_ImageFailed);
try
{
bmpImg.SetSource(fileStream);
}
catch
{
//Code dosen't reach here.
}
}
}
}
void bmpImg_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
//Code dosen't reach here.
}
void bmpImg_ImageOpened(object sender, RoutedEventArgs e)
{
//Code dosen't reach here.
}
I am experiencing a very strange behivour. Running this code on my computer, it works - when you drag a JPG on the LayoutRoot I can break inside bmpImg_ImageOpened().
But on a different machine it won't work - when dragging a JPG, I can break in the drop event but after SetSource() nothing happens : no exceptions are thrown, and non of the callbacks are invoked.
I tried it on another machine and it also didn't work.
edit:
On all of the machines, when adding an Image class and setting it's Source property to the bitmapImage, the image is shown fine. so I guess it's an issue with the callbacks. This is not enough because I still need those events.
I am banging my head here, what could it be ?
This is simply how Silverlight has always behaved. ImageOpened only fires if the image is downloaded and decoded (i.e. using Source). It does not fire when using SetSource. If you need access to the dimensions after loading your image either use WriteableBitmap for the PixelWidth and PixelHeight properties (instead of BitmapImage) or do something like:
img.Source = bmpImg;
Dispatcher.BeginInvoke(() =>
{
FakeImageOpened(); // Do logic in here
});
You have to set
bitmapImage.CreateOptions = BitmapCreateOptions.None;
Then the ImageOpened event is fired. This is because the default Options are CreateDelayed
Greetings
Christian
http://www.wpftutorial.net