基于Streamlit的表情识别系统仅显示视频静态帧,无法播放完整视频
问题分析
你的代码核心问题是仅读取并处理了视频的第一帧,没有循环遍历视频的所有帧,所以只能显示静态图像,无法播放完整视频。此外,模型和人脸检测器在每次处理帧时重复加载,会导致性能严重下降。
修复后的代码
import tempfile import cv2 import numpy as np from tensorflow.keras.models import model_from_json import streamlit as st # 提前加载模型和检测器,避免重复加载 emotion_dict = {0: "Angry", 1: "Disgusted", 2: "Fearful", 3: "Happy", 4: "Neutral", 5: "Sad", 6: "Surprised"} # load json and create model json_file = open('./model/model4.json', 'r') loaded_model_json = json_file.read() json_file.close() emotion_model = model_from_json(loaded_model_json) # load weights into new model emotion_model.load_weights("./model/model4.h5") face_detector = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml') FRAME_WINDOW = st.image([]) uploaded_video = st.file_uploader("Upload Video") if uploaded_video is not None: tfile = tempfile.NamedTemporaryFile(delete=False) tfile.write(uploaded_video.read()) tfile.close() # 关闭临时文件,避免占用 camera = cv2.VideoCapture(tfile.name) # 循环读取视频的每一帧 while camera.isOpened(): ret, frame = camera.read() if not ret: break # 视频读取完毕,退出循环 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 检测人脸 num_faces = face_detector.detectMultiScale(gray_frame, scaleFactor=1.3, minNeighbors=5) # 处理每一张检测到的人脸 for (x, y, w, h) in num_faces: cv2.rectangle(frame, (x, y-50), (x+w, y+h+10), (0, 255, 0), 4) roi_gray_frame = gray_frame[y:y + h, x:x + w] cropped_img = np.expand_dims(np.expand_dims(cv2.resize(roi_gray_frame, (48, 48)), -1), 0) # 预测表情 emotion_prediction = emotion_model.predict(cropped_img, verbose=0) # verbose=0关闭预测日志 maxindex = int(np.argmax(emotion_prediction)) cv2.putText(frame, emotion_dict[maxindex], (x+5, y-20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2, cv2.LINE_AA) # 更新图像组件,实现视频播放效果 FRAME_WINDOW.image(frame) camera.release() # 释放视频捕获资源
关键修改点
- 添加帧循环:使用
while camera.isOpened()循环读取视频的每一帧,直到视频结束。 - 提前加载模型:将模型、权重和人脸检测器的加载代码移到文件上传逻辑之外,避免每次处理帧都重复加载,大幅提升性能。
- 关闭临时文件:添加
tfile.close()确保临时文件可以被正常读取。 - 关闭预测日志:在
emotion_model.predict()中添加verbose=0,避免控制台输出大量预测信息干扰Streamlit界面。 - 释放资源:循环结束后调用
camera.release()释放视频捕获对象,避免资源泄漏。
额外优化建议
- 可以添加帧率控制,比如用
time.sleep(1/30)来匹配视频原帧率,避免播放速度过快。 - 对于长视频,考虑添加暂停/播放按钮,提升用户体验,可使用Streamlit的
st.button()结合状态变量实现。 - 如果视频处理速度较慢,可以考虑多线程处理,将帧处理逻辑放到单独线程中,避免界面卡顿。
内容的提问来源于stack exchange,提问作者isme_
相关产品推荐
相关产品推荐

