Home > Blockchain >  How to show webcam video stream into Picturebox using OpenCVSharp in winform?
How to show webcam video stream into Picturebox using OpenCVSharp in winform?

Time:10-06

I am using this class to record webcam videos successfully. But the problem with this code is, i am unable to show the live video into the picturebox

using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;

namespace Video_capture_23_08_2022
{
    public class Recorder : IDisposable
    {
        private readonly VideoCaptureAPIs _videoCaptureApi = VideoCaptureAPIs.DSHOW;
        private readonly ManualResetEventSlim _threadStopEvent = new ManualResetEventSlim(false);
        private readonly VideoCapture _videoCapture;
        private VideoWriter _videoWriter;

        private Mat _capturedFrame = new Mat();
        private Thread _captureThread;
        private Thread _writerThread;
        //private OutputArray frame;

        private bool IsVideoCaptureValid => _videoCapture is not null && _videoCapture.IsOpened();

        public Recorder(int deviceIndex, int frameWidth, int frameHeight, double fps, PictureBox pictureBox)
        {
            _videoCapture = VideoCapture.FromCamera(deviceIndex, _videoCaptureApi);
            _videoCapture.Open(deviceIndex, _videoCaptureApi);

            _videoCapture.FrameWidth = frameWidth;
            _videoCapture.FrameHeight = frameHeight;
            _videoCapture.Fps = fps;

             // Custom Function to show the webcam view into picturebox  
            _videoCapture.Read(_capturedFrame);
            if (!(_capturedFrame.Empty()))
            { 
            pictureBox.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(_capturedFrame);

            }

        }

        /// <inheritdoc />
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        ~Recorder()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                StopRecording();

                _videoCapture?.Release();
                _videoCapture?.Dispose();
            }
        }

        public void StartRecording(string path)
        {
            if (_writerThread is not null)
                return;

            if (!IsVideoCaptureValid)
                ThrowHelper.ThrowVideoCaptureNotReadyException();

            _videoWriter = new VideoWriter(path, FourCC.XVID, _videoCapture.Fps, new Size(_videoCapture.FrameWidth, _videoCapture.FrameHeight));

            _threadStopEvent.Reset();

            _captureThread = new Thread(CaptureFrameLoop);
            _captureThread.Start();

            _writerThread = new Thread(AddCameraFrameToRecordingThread);
            _writerThread.Start();
        }

        public void StopRecording()
        {
            _threadStopEvent.Set();

            _writerThread?.Join();
            _writerThread = null;

            _captureThread?.Join();
            _captureThread = null;

            _threadStopEvent.Reset();

            _videoWriter?.Release();
            _videoWriter?.Dispose();
            _videoWriter = null;
        }

        private void CaptureFrameLoop()
        {
            while (!_threadStopEvent.Wait(0))
            {
                _videoCapture.Read(_capturedFrame);
            }
        }

        private void AddCameraFrameToRecordingThread()
        {
            var waitTimeBetweenFrames = 1_000 / _videoCapture.Fps;
            var lastWrite = DateTime.Now;

            while (!_threadStopEvent.Wait(0))
            {
                if (DateTime.Now.Subtract(lastWrite).TotalMilliseconds < waitTimeBetweenFrames)
                    continue;
                lastWrite = DateTime.Now;
                _videoWriter.Write(_capturedFrame);
            }
        }

        public Bitmap GetFrameBitmap()
        {
            if (!IsVideoCaptureValid)
                ThrowHelper.ThrowVideoCaptureNotReadyException();

            using (Mat frame = new Mat())
                return !_videoCapture.Read(frame) ? null : frame.ToBitmap();
        }
    }
}

But I want to modify it a bit to show the webcam view into the picturebox but this custom section

 // Custom Function to show the webcam view into picturebox  
 _videoCapture.Read(_capturedFrame);
 if (!(_capturedFrame.Empty()))
  { 
   pictureBox.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(_capturedFrame); 
  }

is only showing a still image instead of a live video. Kindly help me to figure out the issue.

CodePudding user response:

The missing part in your implementation is that you capture the webcam image and display it in pictureBox in the constructor, only once rather than in CaptureFrameLoop(), repeatedly. Therefore, you need to move this block to CaptureFrameLoop().

_videoCapture.Read(_capturedFrame);
if (!(_capturedFrame.Empty()))
{ 
   pictureBox.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(_capturedFrame); 
}

Also, you should use Control.Invoke to modify the image of the PictureBox from a non-UI thread.

private void CaptureFrameLoop()
{
   while (!_threadStopEvent.Wait(0))
   {
        _videoCapture.Read(_capturedFrame);
        if (!(_capturedFrame.Empty()))
        { 
            pictureBox.Invoke(new Action(() => pictureBox.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(_capturedFrame))); 
        }
   }
}
  • Related