【问题标题】:Python opencv cv2.VideoCapture.read() getting stuck indefinitely after running the first timePython opencv cv2.VideoCapture.read() 第一次运行后无限期卡住
【发布时间】:2020-03-24 22:27:36
【问题描述】:

我在 python 上使用 opencv,我遇到了cv2.VideoCapture.read() 函数卡住的问题。这是一些原型代码:

requirements.txt

opencv-contrib-python==4.1.1.26

应用程序.py

import cv2

def run_analysis(path_to_video):
    vs = cv2.VideoCapture(path_to_video)

    while True:
         frame = vs.read()
         if frame is None:
             break
         do_stuff_with_frame(frame)

    vs.release()

这段代码在我的 Mac 上一直有效。它仅在我将其作为 Flask 应用程序部署到 Elastic Beanstalk(在 Red Hat Linux 上运行)时才第一次工作。 我在 github 问题中看到了一些内容,这些内容可能表明 vs.release() 无法释放文件指针,或者存在内存泄漏,但我对这些概念不太熟悉。

即使我无法得到原因的答案,我也会很高兴以蛮力的方式让它发挥作用。

【问题讨论】:

  • 首先您应该尝试自己重现问题,方法是镜像客户的环境。然后,确定错误,它发生在哪里。如果您无法反映环境,您应该尝试让您的客户为您测试,通过给他代码,您可以通过简单的打印(或类似的)替换do_stuff_with_frame(frame),以确保它在您的处理中没有问题,但实际上与文件或捕获功能有关。还是您已经知道它在 vs.release 调用中冻结了?
  • 它不会在发布时冻结。它在后续调用 vs.read 时冻结。其他消息来源表明 vs.release 之前失败了。重置它的唯一方法是杀死烧瓶应用程序并重新启动它。无论如何,我从 Elastic Beanstalk 切换到了我相信使用 ubuntu 的 Heroku。我没有这个问题了,所以我真的不需要答案。 (但仍会因解决该问题的答案而获奖)

标签: python opencv video video-streaming streaming


【解决方案1】:

您可以添加保护以确保cv2.VideoCapture() 处理程序对象对isOpened() 有效。此外,您可以检查read() 中的status 返回值,以确保帧有效。还要确保提供给处理程序的路径是有效的。

import cv2

def run_analysis(path_to_video):
    cap = cv2.VideoCapture(path_to_video)

    if not cap.isOpened():
        print("Error opening video")

    while(cap.isOpened()):
        status, frame = cap.read()
        if status:
            cv2.imshow('frame', frame)
            # do_stuff_with_frame(frame)
        key = cv2.waitKey(25)
        if key == ord('q'):
            break

if __name__ == "__main__":
    run_analysis('video.mp4')

【讨论】:

  • 谢谢,虽然我不确定这如何解决我的问题。我假设它会继续打印错误声明。我想我可以试试看我是否对问题有误解。
  • 为什么会“一直打印错误声明”?在此代码上打印的唯一错误是文件加载本身失败,否则,如果加载正常,它将在按下键盘上的q 时中断 while 循环。在编程中,While 循环无限重复,直到满足停止条件。按q 是否给出了停止(退出)While 循环的预期结果?
  • 由于捕获处理程序损坏或帧无效,您可能会无限期地卡住。通过这个提议的更改,我们在每个帧的每次迭代中添加保护,以确保捕获对象是有效的,此外还要检查我们是否有一个有效的帧。如果捕获对象已损坏,它将仅在第一次迭代时打印错误。也许您的视频文件路径不正确?
  • @VC.One 我想也许我没有很好地解释我的问题。我知道它在哪里断裂以及在什么条件下断裂。无需进一步诊断。它冻结在 vs.read() 上,仅此而已。如果我运行您的代码,我想我只会打印出错误消息。然后如果我再次运行它,它会再次打印。
  • @nathancy 谢谢。我知道两件事表明它与损坏的框架无关。 1)它在我第一次运行时工作。第二次,我使用相同的视频文件。 2) 它每次都可以在我的 Mac 上运行。
【解决方案2】:

根据openCVweb site

如果没有抓到帧(相机已经断开,或者视频文件中没有更多帧),方法返回false,函数返回NULL指针。

您可以在测试“无”后测试“框架”是否为假。 如果有疑问,'print(frame)'

编辑:
我刚刚意识到您在打开文件时跳过了最重要的一步。 需要检查它是否用 isOpened() 打开

    vs = cv2.VideoCapture(path_to_video)
    if not vs.isOpened():
        print("Error: Could not open file: %s" % (path_to_video))
        return
    ........

编辑: 试试这个代码。通过扩展vs.read(),它返回的内容变得更加清晰。

import cv2
def do_stuff_with_frame(image):
    pass

def run_analysis(path_to_video):
    vs = cv2.VideoCapture(path_to_video)
    if not vs.isOpened():
        print("Error: Could not open file: %s" % (path_to_video))
        return

    while True:
        retval, image = vs.read()
        if not retval:
            print("Video file finished. Total Frames: %d" % (vs.get(cv2.CAP_PROP_FRAME_COUNT)))
            break
        do_stuff_with_frame(image)

    vs.release()

# START OF PROGRAM
if __name__ == "__main__":
    run_analysis("test.mov")

【讨论】:

  • 感谢您的回复。我认为我的问题不在于我检查frame is None 的方式。代码实际上卡在frame = vs.read() 行,并没有继续到下一行。
  • 我还读到 frame 对象不应被更改,如果您在 do_stuff_with_frame() 期间更改其中的任何内容,则有一个克隆函数将返回一个可编辑的帧。
  • 是的,实际上我每次都复制框架,但使用 list.copy() 代替。也许它正在尝试切换到内置的克隆功能
  • 您可以注释掉您的 do_stuff 方法并查看循环是否完成。这将缩小错误范围
  • 我的做法是在每行之间插入日志语句(可能有更好的方法,但我不知道如何在生产中进行调试)。 vs.read() 之后的日志语句永远不会触发。如果我在这里错了,请告诉我。
猜你喜欢
  • 2022-01-24
  • 1970-01-01
  • 2021-01-20
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
  • 1970-01-01
相关资源
最近更新 更多