Search code examples
pythonopencvwith-statement

with() statement to read from VideoCapture in opencv?


I like using a with statement for accessing files and database connections because it automatically tears down the connection for me, in the event of error or file close.

f = open('file.txt', 'r')
for i in f():
   print(i)
f.close()

versus

with open('file.txt', 'r') as f:
   for i in f:
       print(i)

Is there an equivalent rephrasing for reading from the camera buffer in the following?:

c = cv.VideoCapture(0)    
while(1):
    _,f = c.read()
    cv.imshow('e2',f)
    if cv.waitKey(5)==27:
        cv.waitKey()
        break
c.release()

I've tried:

c = cv.VideoCapture(0)    
while(1):
   with c.read() as _,f:
       cv.imshow('e2',f)
       if cv.waitKey(5)==27:
           cv.waitKey()
           break

---with no luck. It looks like the tear-down/release is a different kind of function. Is this idiom possible here?


Solution

  • I don't know opencv, so there may be a better answer - but you can always implement the context manager yourself by defining the __enter__ and __exit__ hooks:

    class MyVideoCapture(cv.VideoCapture):
        def __enter__(self):
            return self
        def __exit__(self, *args):
            self.release()
    

    The usage would then look like:

    with MyVideoCapture(0) as c:    
        while(True):
            _, f = c.read()
            cv.imshow('e2', f)
            if cv.waitKey(5) == 27:
                cv.waitKey()
                break
    

    and the resource will be released after you hit the break statement.

    Based on your comment, it looks like opencv is doing something funky here. You can also create a custom class to wrap the VideoCapture instance. In today's world, I'd probably use contextlib

    @contextlib.contextmanager
    def video_capture_wrapper(*args, **kwargs):
        try:
            vid_stream = VideoCapture(*args, **kwargs)
            yield vid_stream
        finally:
             vid_stream.release()
    

    and the usage here would be:

    with video_capture_wrapper(0) as vid_stream:    
        while(True):
            _, f = vid_stream.read()
            cv.imshow('e2', f)
            if cv.waitKey(5) == 27:
                cv.waitKey()
                break