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

树莓派Flask内存捕获摄像头图像并提供服务报错排查

解决方案:Flask+Waitress内存处理树莓派摄像头图像重复请求报错

问题根源

Flask的send_file默认会关闭传入的文件/流对象(包括BytesIO),如果复用同一个全局BytesIO实例,第一次请求后它就会被关闭,后续请求调用时就会触发ValueError: I/O operation on closed file。另外Waitress是多线程服务器,多请求同时操作摄像头也会导致冲突。

核心解决思路

  • 每次请求生成新的BytesIO流,避免复用已关闭的对象
  • 用线程锁保护摄像头操作,防止多线程并发访问冲突
  • 禁用缓存,避免浏览器或Flask缓存旧图像

完整代码示例(基于Picamera2,树莓派OS新版)

from flask import Flask, send_file
from io import BytesIO
from picamera2 import Picamera2
import threading

app = Flask(__name__)

# 全局初始化摄像头,避免每次请求重新启动,提升性能
camera = Picamera2()
camera.configure(camera.create_still_configuration(main={"size": (640, 480)}))
camera.start()

# 线程锁,解决Waitress多线程并发访问摄像头的冲突
camera_lock = threading.Lock()

@app.route('/image.jpg')
def get_image():
    with camera_lock:
        # 每次请求创建新的BytesIO流
        img_stream = BytesIO()
        # 将摄像头图像直接写入内存流
        camera.capture_file(img_stream, format='jpeg')
        # 将流指针移到起始位置,确保send_file能完整读取
        img_stream.seek(0)
        # 返回流时禁用缓存,避免浏览器或Flask复用旧资源
        return send_file(
            img_stream,
            mimetype='image/jpeg',
            cache_timeout=0,
            add_etag=False
        )

@app.route('/')
def status_json():
    return {"status": "running", "service": "camera-stream"}

if __name__ == '__main__':
    from waitress import serve
    # 绑定所有网卡,允许外部访问
    serve(app, host='0.0.0.0', port=5000)

兼容旧版Picamera的代码

如果你的树莓派使用的是旧版picamera库,替换摄像头部分代码即可:

from flask import Flask, send_file
from io import BytesIO
import picamera
import threading

app = Flask(__name__)

camera = picamera.PiCamera()
camera.resolution = (640, 480)
camera_lock = threading.Lock()

@app.route('/image.jpg')
def get_image():
    with camera_lock:
        img_stream = BytesIO()
        camera.capture(img_stream, format='jpeg')
        img_stream.seek(0)
        return send_file(
            img_stream,
            mimetype='image/jpeg',
            cache_timeout=0,
            add_etag=False
        )

# 其余代码同上

关键细节说明

  • 线程锁的必要性:Waitress默认是多线程模式,多个请求同时调用摄像头会导致图像捕获失败或硬件冲突,camera_lock确保同一时间只有一个请求操作摄像头。
  • 禁用缓存的参数:cache_timeout=0告诉浏览器不要缓存图像,add_etag=False避免Flask生成ETag标识导致的缓存复用问题。
  • 不要复用BytesIO:每次请求创建新的BytesIO实例,彻底避免"已关闭文件"的报错,因为send_file处理完当前流后会自动关闭它,不影响后续请求。

内容的提问来源于stack exchange,提问作者user898082

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:18:20