tags:

views:

30

answers:

2

I'm attempting to detect if my capture camera gets unplugged. My assumption was that a call to cvQueryFrame would return NULL, however it continues to return the last valid frame.

Does anyone know of how to detect camera plug/unplug events with OpenCV? This seems so rudimentary...what am I missing?

+1  A: 

There is no API function to do that, unfortunately.

However, my suggestion is that you create another thread that simply calls cvCaptureFromCAM() and check it's result (inside a loop). If the camera get's disconnected then it should return NULL.

I'll paste some code just to illustrate my idea:

// This code should be executed on another thread!
while (1)
{
  CvCapture* capture = NULL;
  capture = cvCaptureFromCAM(-1); // or whatever parameter you are already using
  if (!capture)
  {
    std::cout << "!!! Camera got disconnected !!!!" << std::endl;
    break;
  }

  // I'm not sure if releasing it will have any affect on the other thread
  cvReleaseCapture(&capture); 
}
karlphillip
Thanks, that really helped point me in the right direction. It appears that `cvCaptureFromCAM` is not thread-safe. I posted my full solution below which uses a mutex to block on calls to `cvCaptureFromCAM`
zourtney
+1  A: 

Thanks @karlphillip for pointing me in the right direction. Running calls to cvCaptureFromCAM in a separate thread works. When the camera gets unplugged, the return value is NULL.

However, it appears that this function is not thread-safe. But a simple mutex to lock simultaneous calls to cvCaptureFromCAM seems to do the trick. I used boost::thread, for this example, but one could tweak this easily.

At global scope:

// Create a mutex used to prevent simultaneous calls to cvCaptureFromCAM
boost::shared_mutex mtxCapture;

// Flag to notify when we're done.
// NOTE: not bothering w/mutex for this example for simplicity's sake
bool done = false;

Entry point goes something like this:

int main()
{
  // Create the work and the capture monitoring threads
  boost::thread workThread(&Work);
  boost::thread camMonitorThread(&CamMonitor);

  while (! done)
  {
    // Do whatever
  }

  // Wait for threads to close themselves
  workThread.join();
  camMonitorThread.join();

  return 0;
}

The work thread is simple. The only caveat is that you need to lock the mutex so you don't get simultaneous calls to cvCaptureFromCAM.

// Work Thread
void Work()
{
  Capture * capture = NULL;

  mtxCapture.lock();              // Lock calls to cvCaptureFromCAM   
  capture = cvCaptureFromCAM(-1); // Get the capture object
  mtxCapture.unlock();            // Release lock on calls to cvCaptureFromCAM

  //TODO: check capture != NULL...
  while (! done)
  {
    // Do work
  }

  // Release capture
  cvReleaseCapture(&capture);
}

And finally, the capture monitoring thread, as suggested by @karlphillip, except with a locked call to cvCaptureFromCAM. In my tests, the calls to cvReleaseCapture were quite slow. I put a call to cvWaitKey at the end of the loop because I don't want the overheard of constantly checking.

void CamMonitor()
{
  while (! done)
  {
    CvCapture * capture = NULL;

    mtxCapture.lock();              // Lock calls to cvCaptureFromCAM   
    capture = cvCaptureFromCAM(-1); // Get the capture object
    mtxCapture.unlock();           // Release lock on calls to cvCaptureFromCAM

    if (capture == NULL)
        done = true;                // NOTE: not a thread-safe write...
    else
        cvReleaseCapture(&capture);

    // Wait a while, we don't need to be constantly checking.
    cvWaitKey(2500);
}

I will probably end up implementing a ready-state flag which will be able to detect if the camera gets plugged back in. But that's out of the scope of this example. Hope someone finds this useful. Thanks again, @karlphillip.

zourtney
@zourtney Good.
karlphillip
Well, it turns out this is not quite a perfect solution. When implementing this into a larger project, I am still getting thread-related crashes. Additionally, it seems that releasing/regaining the capture in one thread causes the capture in the other thread to switch back to the default frame size. I'm abandoning this issue, at least for this week, but I'd be happy to help others out in the future, if it's of any benefit.
zourtney