opencv videocapture hangs/freeze when camera disco

2019-05-28 14:01发布

问题:

I'm using OpenCV-Python 3.1 Following the example code from here: http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_gui/py_video_display/py_video_display.html and using a http camera stream instead of the default camera, the read function in videocapture never returns "False" (or anything for that matter) when the camera is physically disconnected, thus hanging/freezing the program entirely. Does anyone know how to fix this?

import numpy as np
import cv2

cap = cv2.VideoCapture('http://url')

ret = True

while(ret):
    # Capture frame-by-frame
    ret, frame = cap.read()
    print(ret)
    # Our operations on the frame come here
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resulting frame
    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

回答1:

I'm experiencing the same issue with the webcam of my MacBook, when the lid is closed (i.e. cam not available). After a quick look at the doc, the VideoCapture constructor doesn't seem to have any timeout parameter. So the solution has to involve forcibly interrupting this call from Python.

After yet more readings about Python's asyncio then threading in general, I couldn't come up with any clue on how to interrupt a method which is busy outside the interpreter. So I resorted to creating a daemon per VideoCapture call, and let them die on their own.

import threading, queue

class VideoCaptureDaemon(threading.Thread):

    def __init__(self, video, result_queue):
        super().__init__()
        self.daemon = True
        self.video = video
        self.result_queue = result_queue

    def run(self):
        self.result_queue.put(cv2.VideoCapture(self.video))


def get_video_capture(video, timeout=5):
    res_queue = queue.Queue()
    VideoCaptureDaemon(video, res_queue).start()
    try:
        return res_queue.get(block=True, timeout=timeout)
    except queue.Empty:
        print('cv2.VideoCapture: could not grab input ({}). Timeout occurred after {:.2f}s'.format(video, timeout))

If anyone has better, I'm all ears.