PiCamera2+Flask仅生成20帧后停止流传输的问题排查
PiCamera2仅输出20帧后停止流的问题解决
问题根源
- 缓冲区配置错误:你设置了
buffer_count=20同时queue=False,这意味着相机只会分配20个缓冲区,且不会循环复用。当20个缓冲区都被消耗完后,相机无法生成新帧。 - 帧获取方式冲突:同时调用
picam2.capture_buffer("lores")和picam2.capture_request(),两种操作都会占用缓冲区,加速缓冲区耗尽。 - 异常处理过于激进:只要捕获到一次异常就执行
break终止生成器,导致流直接停止。
修复方案
- 启用队列机制:将配置中的
queue=False改为queue=True,让相机自动循环复用缓冲区。 - 统一帧获取逻辑:使用
capture_request()同时获取main和lores流的帧,避免重复占用缓冲区。 - 优化异常处理:移除异常块中的
break,仅在严重错误时退出,小错误跳过当前帧继续运行。
修改后的完整代码
#!/usr/bin/python3 from flask import Flask, render_template, Response import cv2 from picamera2 import Picamera2, MappedArray app = Flask(__name__) # Initialize the face detector face_detector = cv2.CascadeClassifier("/var/www/fullfacescanner.xml") # Initialize and configure the camera picam2 = Picamera2() # 启用队列,让缓冲区循环复用 config = picam2.create_preview_configuration(main={"size": (480, 480)}, lores={"size": (320, 240), "format": "YUV420"}, buffer_count=20, queue=True) picam2.configure(config) picam2.start(show_preview=False) (w0, h0) = picam2.stream_configuration("main")["size"] (w1, h1) = picam2.stream_configuration("lores")["size"] s1 = picam2.stream_configuration("lores")["stride"] def detect_faces(buffer): grey = buffer[:s1 * h1].reshape((h1, s1)) return face_detector.detectMultiScale(grey, 1.1, 3) def generate_frames(): while True: try: # 统一使用capture_request获取帧,同时处理两个流 with picam2.capture_request() as request: # 获取lores流用于人脸检测 lores_buffer = request.make_buffer("lores") detected_faces = detect_faces(lores_buffer) # 在main流上绘制人脸框 with MappedArray(request, "main") as m: for f in detected_faces: (x, y, w, h) = [c * n // d for c, n, d in zip(f, (w0, h0) * 2, (w1, h1) * 2)] cv2.rectangle(m.array, (x, y), (x + w, y + h), (0, 255, 0), 2) _, buffer = cv2.imencode('.jpg', m.array) frame = buffer.tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') except Exception as e: print(f"帧处理出错: {e}") # 仅打印错误,不终止生成器,继续尝试下一帧 continue @app.route('/') def index(): return render_template('index.html') @app.route('/video_feed') def video_feed(): return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='0.0.0.0', port=8000, threaded=True)
内容的提问来源于stack exchange,提问作者Blake Price
相关产品推荐
相关产品推荐

