添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
老实的梨子  ·  ActiveX For ...·  2 月前    · 
爱吹牛的青蛙  ·  Oracle ...·  1 年前    · 

OpenCV VideoCapture在Flask项目中不工作,但在基本例子中工作

2 人关注

我试图用Flask框架将一个简单的视频捕获流到网络浏览器上。

我使用 这里 的代码来流式传输相机信号。

当我启动服务器时,它显示了这个错误。

[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()

有人知道如何解决这个问题吗? 如果你能提供一个替代方案,说明如何将这样的视频流发送到安卓设备上,这将对我有很大帮助,因为这是我最初的目标。

python
opencv
flask
computer-vision
video-streaming
Tsuri
Tsuri
发布于 2020-04-06
1 个回答
Don Foumare
Don Foumare
发布于 2020-05-23
0 人赞同

简单回答。

确保你不要在运行 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)

在调试模式下,默认使用一个重载器(use_reloader=True),每当你对代码进行修改时,都会重新加载应用程序。一旦你运行了你的应用程序,python将执行代码,直到碰到app.run() ,从而运行Flask。如果重载器被启用,它将在一个单独的进程中重载你的应用程序(_reloader.py,第166行),以便能够在需要时杀死并重新启动它(由输出* Restarting with 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来看到这一点。

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匹配。现在,当你通过修改你的代码强制重载时,第一个PID应该保持不变(因为这是运行重载程序的进程),第二个PID应该改变。

这里的解决方案是确保你不在重载器运行的父进程中打开文件。这可以通过许多方法实现。

最方便的方法是检查环境变量WERKZEUG_RUN_MAIN ,这个变量是由Werkzeug 在启动重载程序时设置的。这种方式可以确保你的代码在子进程中运行。