Python OpenCV 多处理适用于 MacOS 和 Windows,但不适用于 Ubuntu
Python OpenCV multiprocessing works on MacOS and Windows but not Ubuntu
以下代码 运行 在 MacOS Big Sur 和 Windows 3.8 和 Windows 10 上运行良好 运行:退出 'q' 并且可以重新 运行 很多次。
但是在 Ubuntu 20.04 上,它不会在 'q' 和随后的 运行 returns VIDIOC_QBUF: No buffer space available
上释放网络摄像头资源。系统需要硬重启才能解决这个问题。
如果我注释掉行 cam_process.terminate()
,则代码不会在 'q' 上退出,直到按下 CTRL-C
。
我应该如何:
- 使用
cam_process.terminate()
更正代码以在 Ubuntu 上释放网络摄像头资源?
- 更正代码以在没有
cam_process.terminate()
的情况下正确退出?
任何关于原因的技术见解都非常感谢。
编辑:修复 f 字符串拼写错误。
import multiprocessing
import cv2
# Notes:
# 0. Tested on python 3.8 on all platforms.
# 1. Code works fine on MacOS and Windows. Can quit and run many times.
# 2. Code does NOT release webcam on Ubuntu, needs hard reboot!
# Problem caused by line *: cam_process.terminate()
# Subsequent runs gets VIDIOC_QBUF: No buffer space available error
# 3. If comment out line *, then subprocess does not end, needs CTRL-C to break.
def cam_loop(cam_image_queue, msg_queue):
cap = cv2.VideoCapture(0)
while True:
hello, img = cap.read()
cam_image_queue.put(img)
if not msg_queue.empty():
print("got quit msg")
break
print(f"before cap release, isOpened={cap.isOpened()}")
cap.release()
print(f"after cap release, isOpened={cap.isOpened()}")
def main():
cam_image_queue = multiprocessing.Queue()
msg_queue = multiprocessing.Queue()
cam_process = multiprocessing.Process(
target=cam_loop,
args=(cam_image_queue, msg_queue,),
)
print("starting process...")
cam_process.start()
while True:
if cam_image_queue.empty():
continue
img = cam_image_queue.get()
cv2.imshow("from queue", img)
key = cv2.waitKey(1)
if key == ord("q"):
msg_queue.put("quit")
break
print("closing process...")
# using terminate() or close() will hang webcam resource on Ubuntu!
cam_process.terminate() # *
all_done = False
while not all_done:
cam_process.join(1)
if cam_process.exitcode is not None:
all_done = True
else:
print("code=", cam_process.exitcode)
print("after cam_process join")
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
好的,经过最后 2 个小时的努力,我终于得到了自己的答案 2,即在没有 cam_process.terminate()
的情况下正确退出。
代码无法正常退出(挂起),因为 cam_image_queue
不为空。它包含 cam_loop
放置的最后一帧。在我刷新 cam_image_queue
后,程序按预期正常退出并正确释放了网络摄像头资源。似乎 Ubuntu 比 MacOS 或 Windows.
更注重刷新队列
回答 1:不要调用 cam_process.terminate()
,因为它会在没有正确释放资源的情况下终止进程。
以下代码 运行 在 MacOS Big Sur 和 Windows 3.8 和 Windows 10 上运行良好 运行:退出 'q' 并且可以重新 运行 很多次。
但是在 Ubuntu 20.04 上,它不会在 'q' 和随后的 运行 returns VIDIOC_QBUF: No buffer space available
上释放网络摄像头资源。系统需要硬重启才能解决这个问题。
如果我注释掉行 cam_process.terminate()
,则代码不会在 'q' 上退出,直到按下 CTRL-C
。
我应该如何:
- 使用
cam_process.terminate()
更正代码以在 Ubuntu 上释放网络摄像头资源? - 更正代码以在没有
cam_process.terminate()
的情况下正确退出?
任何关于原因的技术见解都非常感谢。
编辑:修复 f 字符串拼写错误。
import multiprocessing
import cv2
# Notes:
# 0. Tested on python 3.8 on all platforms.
# 1. Code works fine on MacOS and Windows. Can quit and run many times.
# 2. Code does NOT release webcam on Ubuntu, needs hard reboot!
# Problem caused by line *: cam_process.terminate()
# Subsequent runs gets VIDIOC_QBUF: No buffer space available error
# 3. If comment out line *, then subprocess does not end, needs CTRL-C to break.
def cam_loop(cam_image_queue, msg_queue):
cap = cv2.VideoCapture(0)
while True:
hello, img = cap.read()
cam_image_queue.put(img)
if not msg_queue.empty():
print("got quit msg")
break
print(f"before cap release, isOpened={cap.isOpened()}")
cap.release()
print(f"after cap release, isOpened={cap.isOpened()}")
def main():
cam_image_queue = multiprocessing.Queue()
msg_queue = multiprocessing.Queue()
cam_process = multiprocessing.Process(
target=cam_loop,
args=(cam_image_queue, msg_queue,),
)
print("starting process...")
cam_process.start()
while True:
if cam_image_queue.empty():
continue
img = cam_image_queue.get()
cv2.imshow("from queue", img)
key = cv2.waitKey(1)
if key == ord("q"):
msg_queue.put("quit")
break
print("closing process...")
# using terminate() or close() will hang webcam resource on Ubuntu!
cam_process.terminate() # *
all_done = False
while not all_done:
cam_process.join(1)
if cam_process.exitcode is not None:
all_done = True
else:
print("code=", cam_process.exitcode)
print("after cam_process join")
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
好的,经过最后 2 个小时的努力,我终于得到了自己的答案 2,即在没有 cam_process.terminate()
的情况下正确退出。
代码无法正常退出(挂起),因为 cam_image_queue
不为空。它包含 cam_loop
放置的最后一帧。在我刷新 cam_image_queue
后,程序按预期正常退出并正确释放了网络摄像头资源。似乎 Ubuntu 比 MacOS 或 Windows.
回答 1:不要调用 cam_process.terminate()
,因为它会在没有正确释放资源的情况下终止进程。