Flask+OpenCV多进程摄像头推流全局变量及imencode报错问题咨询
问题根因
- 多进程内存隔离:
multiprocessing.Process创建的子进程拥有独立的虚拟地址空间,子进程gen_frames中修改的全局frame变量,和主进程中 Flask 路由访问的frame完全不属于同一个内存区域,主进程拿到的frame永远是初始的None值,无法传入cv2.imencode进行编码,因此触发参数错误。 - 启动逻辑阻塞:代码中
p.join()会让主进程一直阻塞等待帧采集子进程退出,永远不会执行到app.run()启动 Flask 服务。 - Flask Debug 模式重载问题:默认开启
debug=True时 Flask 会启动重载进程,会重复创建帧采集子进程,引发设备占用冲突。
解决方案
使用 multiprocessing.Queue 实现进程间的帧数据传递,用长度为1的队列存储最新帧,避免内存占用过高;同时删除阻塞的 join 调用,调整 Flask 启动参数避免重复加载。
修正后完整代码
from flask import Flask, render_template, Response from multiprocessing import Process, Queue import cv2 import numpy as np app = Flask(__name__) # 初始化长度为1的队列,仅存储最新的摄像头帧 frame_queue = Queue(maxsize=1) def gen_frames(queue): # Windows系统请删除第二个参数cv2.CAP_V4L2,该参数仅适配Linux环境 camera = cv2.VideoCapture(0, cv2.CAP_V4L2) # 可按需调整摄像头分辨率参数 camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: success, frame = camera.read() if not success: break # 队列满时先取出旧帧再放入新帧,保证永远存储最新帧 if queue.full(): try: queue.get_nowait() except: pass queue.put(frame) camera.release() def get_frames(queue): while True: # 等待获取最新帧 frame = queue.get() ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80]) if not ret: continue frame_bytes = buffer.tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n') @app.route('/') def index(): return render_template('index.html') @app.route('/video_feed') def video_feed(): return Response(get_frames(frame_queue), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == "__main__": # 启动帧采集子进程,将队列作为参数传入 p = Process(target=gen_frames, args=(frame_queue,)) p.daemon = True # 设置为守护进程,主进程退出时自动结束子进程 p.start() # 如需开启调试可修改为 debug=True, use_reloader=False,避免重复启动采集进程 app.run(host='0.0.0.0', port=80, debug=False)
注意事项
- 需提前在项目根目录的
templates文件夹下创建对应的index.html文件,嵌入<img src="/video_feed">标签即可正常播放推流 - 多客户端同时访问时,所有客户端共享同一采集进程的帧数据,不会重复打开摄像头,解决了原单函数版本的多客户端兼容问题
内容的提问来源于stack exchange,提问作者CY83
相关产品推荐
相关产品推荐

