Python OpenCV VideoCapture在Flask项目中不起作用,但在基本示例中起作用
我正在尝试用Flask框架将一个简单的视频捕获流式传输到Web浏览器 我正在使用来自的代码来流式传输摄影机提要 启动服务器时,会显示以下错误: [警告:0]全局/io/opencv/modules/videoio/src/cap_v4l.cpp(887)打开videoio(V4L2:/dev/video0):无法按索引打开相机 但当我运行这样的示例代码时,它工作得很好:Python OpenCV VideoCapture在Flask项目中不起作用,但在基本示例中起作用,python,opencv,flask,computer-vision,video-streaming,Python,Opencv,Flask,Computer Vision,Video Streaming,我正在尝试用Flask框架将一个简单的视频捕获流式传输到Web浏览器 我正在使用来自的代码来流式传输摄影机提要 启动服务器时,会显示以下错误: [警告:0]全局/io/opencv/modules/videoio/src/cap_v4l.cpp(887)打开videoio(V4L2:/dev/video0):无法按索引打开相机 但当我运行这样的示例代码时,它工作得很好: import cv2 cap = cv2.VideoCapture(0) while True: ret, frame =
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)
长答案: 在调试模式下运行Flask时会发生这种情况:
如果uuuu name_uuuu=='\uuuuuuu main\uuuuuu':
app.run(host='0.0.0.0',debug=True)#debug=True
在调试模式下,每当您对代码进行更改时,默认情况下会使用重新加载程序(use\u reloader=True
)重新加载应用程序。运行应用程序后,python将执行代码,直到它点击运行Flask的app.run()
。如果重新加载程序被启用,它将在一个单独的进程()中重新加载您的应用程序,以便能够在需要时终止并重新启动它(由输出*重新启动stat
指示,其中stat
是v1.0.1中使用的默认重新加载程序Werkzeug
)
这也可以通过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即可看到这一点:
导入cv2,操作系统
...
打印('[DEBUG]从PID',os.getpid()调用cv2.VideoCapture(0))
cap=cv2.视频捕获(0)
...
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app.run(host='0.0.0.0',debug=True)
使用watch-n0,5'sudofuser/dev/video0'
您还可以查看当前正在使用该文件的进程。第一个PID应与父进程的PID匹配,第二个PID应与子进程的PID匹配。现在,当您通过修改代码强制重新加载时,第一个PID应该保持不变(因为这是运行重新加载程序的进程),第二个PID应该更改
这里的解决方案是确保不在重载程序运行的父进程中打开文件。这可以通过多种方式实现
最方便的方法是检查环境变量WERKZEUG\u RUN\u MAIN
,该变量在重新装载机启动时由WERKZEUG
设置。这样可以确保代码在子进程中运行:
如果os.environ.get('WERKZEUG\u RUN\u MAIN')或Flask.debug为False:
cap=cv2.视频捕获(0)
注意:条件或Flask.debug为False
是为了确保在禁用调试模式并因此禁用重新加载程序时代码仍将运行。但是,WERKZEUG_RUN_MAIN
只有在重新加载程序本身启用时才设置,也就是说,您可以在禁用重新加载程序的情况下,在调试模式下运行应用程序:app.RUN(host='0.0.0',debug=True,use_reloader=False)
。在这种情况下,代码将永远不会执行,因为这两个条件的计算结果都将为False
。所以请记住这一点