Flask结合OpenCV实现Jetson Nano摄像头网页直播存快照页面卡死问题求助
问题解决方法
核心根因
你遇到的问题本质是摄像头资源竞争+Flask单线程阻塞+请求逻辑设计缺陷,具体分为4点:
- Flask默认单线程运行,视频流请求、按钮POST请求、页面刷新请求互相阻塞,摄像头被占用后新的视频流请求无法获取资源,导致无限加载
- 全局快照标记变量没有线程锁,多线程并发修改时状态异常,会卡住帧生成逻辑
- 按钮用form表单提交,每次点击都会刷新页面,旧的视频流连接未正常释放,重复请求摄像头导致设备锁死
- 多个视频流请求会同时调用
camera.read()抢同一设备资源,导致读取失败率极高,前端收不到新帧就会停留在最后一张快照
具体修复步骤
1. 开启Flask多线程模式
修改启动代码,允许多请求并行处理:
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, threaded=True, debug=False)
关闭debug模式避免调试模式的重复启动问题,同时支持多客户端同时访问。
2. 新增后台帧采集线程,避免资源竞争
单独开一个线程持续读摄像头,把最新帧存在全局变量,所有视频流请求直接读缓存的帧,不再直接访问摄像头:
import threading global latest_frame, frame_lock, Polluted, Clear, Treated, OutOfService latest_frame = None frame_lock = threading.Lock() Polluted=0 Clear=0 Treated=0 OutOfService=0 def capture_frame(): global latest_frame, camera while True: success, frame = camera.read() if success: with frame_lock: latest_frame = frame.copy() time.sleep(0.01) # 控制采集帧率,避免占用过高资源 # 启动后台采集线程,放在app初始化之后 capture_thread = threading.Thread(target=capture_frame, daemon=True) capture_thread.start()
3. 重写帧生成逻辑,从缓存读帧
def gen_frames(): global latest_frame, frame_lock, Polluted,Clear,Treated,OutOfService while True: with frame_lock: if latest_frame is None: continue frame = latest_frame.copy() # 处理快照逻辑 if Polluted: snapshot(frame,"Polluted Water") Polluted = 0 if Clear: snapshot(frame,"Cleared Water") Clear = 0 if Treated: snapshot(frame,"Treated Water") Treated = 0 if OutOfService: snapshot(frame,"Out of Service") OutOfService = 0 # 编码返回 try: ret, buffer = cv2.imencode('.jpg', cv2.flip(frame,1)) 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('encode error', e) continue
4. 修改按钮请求逻辑,避免页面刷新
要么给按钮加AJAX异步提交,不用form表单刷新页面;要么修改POST处理完之后重定向回首页,避免重复提交:
from flask import redirect @app.route('/requests',methods=['POST','GET']) def tasks(): if request.method == 'POST': if request.form.get('Polluted') == 'Polluted': global Polluted Polluted=1 print('in polluted') elif request.form.get('Clear') == 'Clear': global Clear Clear = 1 elif request.form.get('Treated') == 'Treated': global Treated Treated = 1 elif request.form.get('OutOfService') == 'OutOfService': global OutOfService OutOfService = 1 return redirect('/') # 重定向避免重复提交 return render_template('index.html')
5. 前置检查&小问题修复
- 启动时先创建四个存储文件夹,避免cv2.imwrite写入失败阻塞逻辑:
save_base = "/home/ava/Documents/AVA/Get pictures/" for folder in ["Polluted Water", "Cleared Water", "Treated Water", "Out of Service"]: os.makedirs(os.path.join(save_base, folder), exist_ok=True)
- 修复快照颜色错误:cv2读出来的帧本身是BGR格式,不需要再做
cv2.COLOR_RGB2BGR转换,直接保存即可,否则会颜色偏蓝。
内容的提问来源于stack exchange,提问作者tomilie
相关产品推荐
相关产品推荐

