我正在尝试使用 Flask 框架将简单的视频捕获流式传输到 Web 浏览器。
我正在使用来自 here 的代码流式传输相机源。
当我启动服务器时它显示这个错误:
[ WARN:0] global /io/opencv/modules/videoio/src/cap_v4l.cpp (887) open VIDEOIO(V4L2:/dev/video0): can't open camera by index
但是当我运行这样的示例代码时它工作正常:
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
有人知道解决这个问题的方法吗? 如果您还可以提供关于如何将这样的视频流发送到 Android 设备的替代方案,那将对我非常有帮助,因为这是我最初的目标。 谢谢!
最佳答案
简答:
确保您没有在运行 Werkzeug
的同一进程中打开设备文件,这是 Flask 使用的调试器。例如:
# 'Flask.debug is False' allows code execution in case debug mode is disabled
if os.environ.get('WERKZEUG_RUN_MAIN') or Flask.debug is False:
cap = cv2.VideoCapture(0)
长答案:
当您在 Debug模式下运行 Flask 时会发生这种情况:
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True) # debug=True
在 Debug模式下,当您更改代码时,默认情况下使用重新加载器 (use_reloader=True
) 重新加载应用程序。运行应用程序后,python 将执行代码,直到它命中运行 Flask 的 app.run()
。如果重新加载器已启用,它将在单独的进程 ( _reloader.py, line 166 ) 中重新加载您的应用程序,以便能够在需要时终止并重新启动它(由输出 * Restarting with stat
指示,其中stat
是 Werkzeug
在 v1.0.1 中使用的默认重新加载器。
这也可以通过 ps f
观察到,此时它应该输出一个类似这样的树结构:
PID TTY STAT TIME COMMAND
...
16052 pts/1 Ss 0:00 bash
16319 pts/1 S+ 0:01 \_ python app.py # or '/path/to/python /path/to/flask run'
16353 pts/1 Rl+ 0:00 \_ /path/to/python /path/to/app.py # spawned child process
...
话虽如此,您基本上运行了两次代码,因此 cap = cv2.VideoCapture(0)
尝试从两个不同的进程打开 /dev/video0
。首先是当您运行脚本/模块时,然后是调试器接管时 (app.run()
)。您提到的错误来自子进程,无法打开设备文件,因为它已被父进程打开(因此被阻止)。
您可以通过在调用 cv2.VideoCapture(0)
之前简单地打印出 PID 来看到这一点:
import cv2, os
...
print('[DEBUG] call cv2.VideoCapture(0) from PID', os.getpid())
cap = cv2.VideoCapture(0)
...
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
使用 watch -n 0,5 'sudo fuser/dev/video0'
您还可以查看当前正在使用该文件的进程。第一个 PID 应该匹配来自父进程的 PID,第二个应该匹配子进程的 PID。现在,当您通过修改代码强制重新加载时,第一个 PID 应该保持不变(因为这是运行重新加载程序的进程),第二个应该更改。
此处的解决方案是确保您不在运行重新加载程序的父进程中打开文件。这可以通过多种方式实现。
最方便的方法是检查环境变量 WERKZEUG_RUN_MAIN
,它由 Werkzeug
在启动重新加载程序时设置。这样您就可以确保您的代码在子进程中运行:
if os.environ.get('WERKZEUG_RUN_MAIN') or Flask.debug is False:
cap = cv2.VideoCapture(0)
注意:条件或 Flask.debug 为 False
是为了确保当您禁用 Debug模式并因此禁用重新加载程序时,您的代码仍将运行。但是,WERKZEUG_RUN_MAIN
仅在重新加载程序本身启用时设置 ( _reloader.py, line 165 ) 也就是说,您实际上可以在 Debug模式
下运行该应用reloader
被禁用:app.run(host='0.0.0.0', debug=True, use_reloader=False)
。在这种情况下,代码将永远不会执行,因为两个条件的计算结果都是 False
。所以请记住这一点。
关于python - OpenCV VideoCapture 在 Flask 项目中不起作用,但在基本示例中起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61047207/