You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 14:45:05