Short answer:
Make sure you don't open the device file in the same process as Werkzeug runs, which is the debugger used by Flask. For example:
# '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)
Long answer:
This happens when you run Flask in debug mode:
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True) # debug=True
In debug mode a reloader (use_reloader=True) is used by default to reload the application whenever you make changes to your code. Once you run your application, python will execute the code until it hits app.run(), which runs Flask. If the reloader is enabled, it will reload your app in a separate process (_reloader.py, line 166) in order to be able to kill and restart it when needed (indicated by the output * Restarting with stat, where stat is the default reloader Werkzeug uses in v1.0.1).
This can also be observed with ps f, which at this point should output a tree structure similar to this:
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
...
Having that said, you run your code basically twice and thus cap = cv2.VideoCapture(0) tries to open /dev/video0 from two different processes. First when you run your script/module and than when the debugger takes over (app.run()). The error you mentioned is comming from the child process, beeing unable to open the device file since it is already opened (and hence blocked) by the parent process.
You can see this by simply printing out the PID before calling cv2.VideoCapture(0):
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)
With watch -n 0,5 'sudo fuser /dev/video0' you can also see which process is currently using that file. The first PID should match the PID from the parent process and the second should match the childs PID. Now when you force a reload by modifying your code, the first PID should stay the same (since this is the process that runs the reloader) and the second one should change.
The solution here is to make sure, that you do not open the file in the parent process where the reloader runs. This can achieved by many ways.
The most convenient way is by checking the environment variable WERKZEUG_RUN_MAIN, which is set by Werkzeug when it starts the reloader. This way you make sure that your code runs in the child process:
if os.environ.get('WERKZEUG_RUN_MAIN') or Flask.debug is False:
cap = cv2.VideoCapture(0)
Note: The condition or Flask.debug is False is to make sure that your code will still run when you disable debug mode and thus the reloader. However, WERKZEUG_RUN_MAIN is only set if the reloader itself is enabled (_reloader.py, line 165) That said, you could actually run the app in debug mode with the reloader beeing disabled: app.run(host='0.0.0.0', debug=True, use_reloader=False). In this case the code will never get executed since both conditions will evaluate to False. So keep this in mind.