Search code examples
opencvc++-cliwindows-forms-designer

OpenCV using Windows Form keeps on throwing exceptions about stack overflowing


I've been writing a program and every time I close my form it throws an exception saying my stack overflowed on the line which closes the background worker...
I have faced this problem for some time now, I've tried googling the problem but I haven't come up with any desired solution yet...

My troubleshooting guesses are as follows :

  1. Pictures in picturebox takes up resources and are not cleared when aborting program
  2. Background Worker is still busy

Here is my code, thanks in advance !


Elements

Picturebox called videobox
Button called btnOpenCamera_Click
Button called btnCloseCamera_Click
Label called backgroundworkerStatus


Variables

Global

Mat videoFrame;
VideoCapture video(0);

Private

bool flag_cameraStatus = true;
bool flag_backgroundworkerStatus = false;


Functions

private: System::Void MainForm_FormClosing

// this event is triggered when application is closing

video.release();

/* Exception is thrown here "System.StackOverflowException" */
backgroundWorker->CancelAsync();

if (backgroundWorker->IsBusy == false) {
    checkBackgroundworkerStatus();
    this->Close();
}
else {
    MessageBox::Show("Backgroundworker not aborted");
    e->Cancel = true;
}

private: System::Void btnOpenCamera_Click

// this is a button for turning on camera

flag_cameraStatus = true;
backgroundWorker->RunWorkerAsync();

private: System::Void btnCloseCamera_Click

// this is a button for turning off camera

flag_cameraStatus = false;
videoBox->Image = nullptr;

int openCamera()

// this is a button for turning off camera

if (!video.isOpened()) {
    MessageBox::Show("Cannot Find Camera!");
    return -1;
}

while (flag_camera) {

  video >> videoFrame;
  if (videoFrame.empty()) {
        break;
  }

  /* These lines of code converts Opencv mat to bitmap for picturebox to display */
  System::Drawing::Graphics^ graphics = videoBox->CreateGraphics();
  System::IntPtr ptr(videoFrame.ptr());
  System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(videoFrame.cols, videoFrame.rows, videoFrame.step, System::Drawing::Imaging::PixelFormat::Format24bppRgb, ptr);
  System::Drawing::RectangleF rect(0, 0, videoBox->Width, videoBox->Height);
  graphics->DrawImage(b, rect);

  /* Was wondering if I need these lines of code below */
  /* delete graphics;                                  */

if (flag_camera == false) {
    videoBox->Image = nullptr;
    return 0;
}

void checkBackgroundworkerStatus()

// this function is used to check if backgroundworker is busy
// it will identify the status via the backcolor of label backgroundworkerStatus

if(backgroundWorker->IsBusy==true)
backgroundworkerStatus->BackColor = Color::Green;
else
backgroundworkerStatus->BackColor = SystemColors::Control;

private: System::Void backgroundWorker_DoWork

// this event is triggered when background worker is working

if (backgroundWorker->CancellationPending == false) {
    checkBackgroundworkerStatus();
    openCamera();
}
else {
    this->backgroundWorker->CancelAsync();
}

private: System::Void backgroundWorker_RunWorkerCompleted

// this event is triggered when background worker is done working

checkBackgroundworkerStatus();


Some Last Notes...

I did set my

WorkerSupportsCancellation = true
WorkerReportsProgress = true

Solution

  • To solve this problem,add a delay to DoWork

    private: System::Void backgroundWorker1_DoWork

    using namespace System::Threading
    /* your DoWork tasks */
    Thread::Sleep(50)

    Note
    Thread::Sleep counts in milliseconds, you can change to the number you want according to your cameras fps. My laptop webcam is approx. 15 fps, which is 66.66 ms per frames, the sleep time should be >= this ms/frame but I have no problems running it with a delay of only 50ms.