在OpenCV中使用with()语句读取VideoCapture的方法?

7

我喜欢使用 with 语句来访问文件和数据库连接,因为它会自动帮我关闭连接,以防出现错误或文件关闭。

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

对比

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

以下有没有读取相机缓冲区的等效重述方式?
c = cv.VideoCapture(0)    
while(1):
    _,f = c.read()
    cv.imshow('e2',f)
    if cv.waitKey(5)==27:
        cv.waitKey()
        break
c.release()

我尝试过:

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

——但是没有成功。看起来拆除/释放是一种不同的功能。这里是否可以使用该习语?

2个回答

12

使用contextlib.contextmanager的另一种方法:

from contextlib import contextmanager

@contextmanager
def VideoCapture(*args, **kwargs):
    cap = cv2.VideoCapture(*args, **kwargs)
    try:
        yield cap
    finally:
        cap.release()

(注意:已接受的答案已被编辑以包括此建议)


为什么要使用yield而不是return? - Enes
因为这就是context_manager的工作原理。如果你使用return代替yield,那么cap.release()将会立即被调用,而不是在with语句结束时才被调用。 - Eric

9

我不了解 OpenCV,所以可能有更好的答案 - 但是你可以通过定义 __enter____exit__ 钩子来自己实现 上下文管理器

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

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

当你使用break语句时,资源将会被释放。

根据你的评论,看起来opencv在这里做了一些奇怪的事情。你也可以创建一个自定义类来包装VideoCapture实例。在今天的世界中,我可能会使用contextlib

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

这里的使用方法是:

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

这看起来非常像我正在寻找的东西。抱歉,我以前没有使用过上下文管理器——在我上面的内容中,我应该如何调用它? - Mittenchops
@Mittenchops -- 添加了一些示例用法。在这种情况下,重写__iter__以在读取数据(f)时使用yield可能也很不错...但这取决于您的实际用例。 - mgilson
这绝对是我想到的东西。但是在类定义中,我遇到了这个错误:File "./main.py", line 7, in <module> class MyVideoCapture(cv.VideoCapture): TypeError: Error when calling the metaclass bases cannot create 'builtin_function_or_method' instances 不过我猜这已经足够让我开始并告诉我可能性了。 - Mittenchops
嗯,我尝试过这个,似乎可能存在更深层次的问题。 - Mittenchops
@Mittenchops -- 真遗憾。不过,我已经更新了一个解决方案,我们使用组合而不是继承。我看不出任何可能失败的方式;-) - mgilson
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接