Home > database >  C# picturebox throws System.InvalidOperationException: : "Object is currently in use elsewhere.
C# picturebox throws System.InvalidOperationException: : "Object is currently in use elsewhere.

Time:09-22

I'm trying to take photos from my webcam every 3 seconds. But when I try to run the code I always get the above error. I searched through StackOverflow and found some solutions that suggested locking the resource. I thought I did it with a mutex but unfortunately, I still get the error. I think it has something to do with the bitmap but I don't know where and which bitmap.

This is the code:

//Here I declare global variables
FilterInfoCollection filterInfoCollection;
VideoCaptureDevice videoCaptureDevice;

Int16 INTERVAL;
string SAVESPACE;

private static Mutex mutex = new Mutex();

//Here I start the stream of my webcam from where I get my images
private void startNewCamera()
        {
            videoCaptureDevice = new VideoCaptureDevice(filterInfoCollection[comboBox_Cameras.SelectedIndex].MonikerString);
            videoCaptureDevice.NewFrame  = VideoCaptureDevice_NewFrame;
            videoCaptureDevice.Start();
        }

//from my understanding this is where the live stream is being generated
//I also locked this one with a mutex
private void VideoCaptureDevice_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            mutex.WaitOne();
            pictureBox_Preview.Image = (Bitmap)eventArgs.Frame.Clone();
            mutex.ReleaseMutex();
        }


//Here I start with the backgroundworker from which I want to take a photo every 3 seconds
private void btn_Start_Click(object sender, EventArgs e)
        {
            //start recording
            if (backgroundWorker_camera.IsBusy != true)
            {
                backgroundWorker_camera.RunWorkerAsync();
            }
        }


//This is where the magic happens
//I lock the whole function but the error occurs nevertheless
private void backgroundWorker_camera_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            while (!backgroundWorker_camera.CancellationPending)
            {
                System.Threading.Thread.Sleep(INTERVAL);
                mutex.WaitOne();
                
                //HERE THE ERROR ALWAYS OCCURS
                pictureBox_Capture.Image = pictureBox_Preview.Image;

                var bitmap = new Bitmap(pictureBox_Capture.Width, pictureBox_Capture.Height);
                pictureBox_Capture.Invoke(new Action(() =>
                    {
                        pictureBox_Capture.DrawToBitmap(bitmap, pictureBox_Capture.ClientRectangle);
                    }));

                System.Drawing.Imaging.ImageFormat imageFormat = null;
                imageFormat = System.Drawing.Imaging.ImageFormat.Png;
                mutex.ReleaseMutex();                
            }    
        }

If there is anything I can improve on my question please let me know. Thank you! :)

CodePudding user response:

I figured out the problem thanks to @NIRE GUPTAs' answer. Now I store the image in two separate variables for every thread. The updated functions look like this:

    //New global Image variables for every thread
    Image captureImageTH1;
    Image captureImageTH2;
    
    //The function where Livestream am commes from
    private void VideoCaptureDevice_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            captureImageTH1 = (Bitmap)eventArgs.Frame.Clone();
            captureImageTH2 = (Bitmap)eventArgs.Frame.Clone();

            pictureBox_Preview.Image = captureImageTH1;
        }  


     //The function where I capture the Image every 3 seconds
     private void backgroundWorker_camera_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            string time;

            while (!backgroundWorker_camera.CancellationPending)
            {
                System.Threading.Thread.Sleep(INTERVAL);
                time = DateTime.Now.ToString("yyyy:MM:dd:HH:mm:ss");

                pictureBox_Capture.Image = captureImageTH2;

                var bitmap = new Bitmap(pictureBox_Capture.Width, pictureBox_Capture.Height);
                pictureBox_Capture.Invoke(new Action(() =>
                    {
                        pictureBox_Capture.DrawToBitmap(bitmap, pictureBox_Capture.ClientRectangle);
                    }));

                System.Drawing.Imaging.ImageFormat imageFormat = null;
                imageFormat = System.Drawing.Imaging.ImageFormat.Png;
                

                captureImageTH2.Save(Path.Combine(SAVESPACE, time   ".png"));
            }  

As you can see I'm now trying to save the captured image. But every time I do It I get the following error:

System.Runtime.InteropServices.ExternalException: "A generic error occurred in GDI ."

What is it that I'm doing wrong now? This time as well the solutions from the internet didn't help.

CodePudding user response:

Images in GDI are not thread-safe. What it means, basically - you cannot use one image from 2 threads simultaneously without some additional changes to your code.

  • Related