stremlit+fastapi处理视频

本文介绍了两种方法利用Streamlit和FastAPI处理上传的视频文件。第一种方法是在Streamlit前端实时处理每一帧并展示,通过opencv读取视频,处理后返回结果。第二种方法是将整个视频发送到后端,处理完成后返回处理好的视频,再由Streamlit展示。FastAPI部分涉及接收视频数据,处理后以文件形式返回。opencv处理过程中需要注意编码格式以确保Streamlit能正确播放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用stremalit以及fastapi来处理视频

  • 思路1

在steamlit中通过opencv打开视频中的每一帧,再将图片发送到后端进行相关处理,最后返回处理好的图片,将其显示在同一位置连续展示达到视频效果。这样可以实现实时返回结果,关键代码如下。

# 使用opencv读取视频帧并展示 来达到视频的效果
image_placeholder = st.empty()  # 创建空白块使得展示原图
result_place = st.empty()  # 创建空白块使得展示处理好的结果

import tempfile

f = st.file_uploader("Upload file")  # 上传本地视频 数据以二进制写入内存无法直接用opencv打开

if f is not None:
    tfile = tempfile.NamedTemporaryFile(delete=False)  # 创建临时文件
    tfile.write(f.read())  # 视频数据写入临时文件

    cap = cv2.VideoCapture(tfile.name)  # opencv打开临时文件
    if (cap.isOpened() == False):
        st.write("Error opening video stream or file")

    while (cap.isOpened()):
        success, frame = cap.read()
        if success:
            to_show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 读取当前帧图片数据
            to_show = Image.fromarray(np.uint8(to_show))  # numpy.ndarray 转 PIL.Image.Image
            bytes_io = io.BytesIO()  
            to_show.save(bytes_io, format="PNG")  # 将数据以二进制写入内存

            estimate = process(bytes_io.getvalue(), backend)  # 发送二进制图片数据 返回处理好的图片二进制数据
            estimated_image = Image.open(io.BytesIO(estimate.content)).convert("RGB") # 得到处理好的结果图片
            image_placeholder.image(to_show, caption='Video')  # 原图片 将图片帧展示在同一位置得到视频效果
            result_place.image(estimated_image, caption='Video')  # 结果图片 将图片帧展示在同一位置得到视频效果

        else:
            break
    cap.release()
  • 思路2

将整个视频作为数据发送到后端,在后台将整个视频处理好后,再发送回前端。

streamlit

使用st.file_uploader读取本地视频,再使用st.video展示处理完的视频,代码如下。

f = st.file_uploader("Upload file")  # 上传本地视频   数据为二进制存在内存中 可通过f.getvalue读取

if f is not None:
    estimate = process(f, backend)  # 返回response需要用response.content读取其中内容
    estimate = io.BytesIO(estimate.content)  # 往内存中写入estimate.content数据
    st.video(estimate, format="video/mp4", start_time=0)  # 展示视频

fastapi

采用response文件的方式将我们处理好的视频发送至前端,代码如下。

@app.post("/estimation", response_class=FileResponse)
def main(file: bytes = File(...)):
    out_video = video_process(file)  # 使用response文件方式 video_process返回值为文件名
    return out_video

opencv处理前端发送过来的数据

仍然采用创建临时文件的方式打开前端传过来的二进制数据,代码如下。
注意,opencv保存视频时需选择avc1编码方式,streamlit不支持显示MP4V的编码视频。
以及streamlit可能不支持显示avi文件,建议保存文件统一为MP4格式。

def video_process(binary_video):
    import tempfile
    
     outfile_name = 'output.mp4'  # 输出结果文件名
    
    binary_video = io.BytesIO(binary_video)  # 将前端传来binary_video写入内存
    tfile = tempfile.NamedTemporaryFile(delete=False)  # 创建临时文件
    tfile.write(binary_video.read())  # 写入临时文件

    cap = cv2.VideoCapture(tfile.name)  # 打开文件
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 获取视频图像宽
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # 获取视频图像高
    fps = cap.get(cv2.CAP_PROP_FPS)  # 读取图像显示帧率
    fourcc = int(cv2.VideoWriter_fourcc(*'avc1'))  # 选择编码方式 streamlit不支持显示MPV4编码方式
    out = cv2.VideoWriter(outfile_name, fourcc, fps, (width, height))  # 创建输出视频
我是用stremlit开发的,现在我已经有工作清单表格以dataframe的形式显示在外面了,我想加一个功能,如果完成了,那么直接点击一个按钮,然后就修改数据库中的是否完成列,然后把它标记为1. 怎么增加:st.set_page_config(page_title='工作清单概览', layout='wide') menu_with_redirect() st.title('📄 工作清单概览') @st.cache_data def load_data(): df = pd.read_excel('数据库.xlsx', sheet_name='Sheet1') # 转换日期列 df['日期'] = pd.to_datetime(df['日期'], unit='D') return df df = load_data() # 加载数据效果 page_progress = st.progress(text='加载数据中,请稍后', value=50) for percent_complete in range(100): time.sleep(0.005) page_progress.progress(percent_complete + 1, text='加载数据中,请稍后') with st.sidebar: st.subheader('数据筛选器', divider='rainbow') min_date, max_date = '2024-01-01', '2025-12-31' min_date = pd.to_datetime(min_date) max_date = pd.to_datetime(max_date) # 是否完成工作筛选器 completion_options = ['所有'] + df['是否完成'].unique().tolist() completion_selection = st.selectbox( label='是否完成', options=completion_options, index=0 ) # 工作类别筛选器 category_options = ['所有'] + df['类别'].unique().tolist() category_selection = st.selectbox( label='类别', options=category_options, index=0 ) # 日期筛选器 date_selection = st.date_input( label='日期范围', value=(min_date, max_date), min_value=min_date, max_value=max_date ) filtered_df = df.copy() if completion_selection != '所有': filtered_df = filtered_df[filtered_df['是否完成'] == completion_selection] if category_selection != '所有': filtered_df = filtered_df[filtered_df['类别'] == category_selection] start_date, end_date = date_selection filtered_df = filtered_df[ (filtered_df['日期'] >= pd.Timestamp(start_date)) & (filtered_df['日期'] <= pd.Timestamp(end_date))] # ============================================================== st.divider() cols1, cols2, cols3,cols4 = st.columns(4) # ============================================================== with cols1: st.write(' ') st.write('#### :grey[工作清单统计:]') with cols2: st.metric('**总任务数**', f'{len(df)} 条') with cols3: st.metric('**已完成任务数**', f'{len(df[df["是否完成"]==1])} 条') with cols4: st.metric('**未完成任务数**', f'{len(df[df["是否完成"]==0])} 条') # configUtil.model_result_analyze(tb_feature) st.subheader('工作清单内容') # with st.container(height=1700): filtered_df = filtered_df.fillna('/') st.dataframe(filtered_df,height=2000,hide_index=True) page_progress.empty() # ================================================================
05-31
<think>嗯,用户想在Streamlit应用里添加一个按钮,点击后能更新数据库中的“是否完成”列为1。首先,我需要回忆一下Streamlit的组件,特别是按钮相关的。记得Streamlit有st.button组件,可以创建按钮,然后通过回调函数执行操作。接下来,用户提到要更新数据库,所以需要连接数据库。可能需要使用Python的数据库库,比如sqlite3或者SQLAlchemy,具体取决于用户使用的数据库类型。假设用户使用的是SQLite,那么例子中可以用sqlite3模块来连接和更新。然后,数据框的交互部分。用户点击按钮时,需要确定是哪一行需要更新。可能需要为每一行添加一个按钮,或者通过某种方式选择行。比如,在数据框中每一行旁边放一个按钮,或者使用st.session_state来跟踪选中的行。另外,要考虑如何将按钮的点击事件与数据库更新结合起来。可能需要使用会话状态来保持数据的一致性,确保每次点击按钮后,前端的数据框和后端数据库都能同步更新。比如,在按钮的回调函数中,执行SQLUPDATE语句,并更新session_state中的DataFrame。 还需要注意,每次点击按钮后,Streamlit应用会重新运行整个脚本,所以需要确保数据库连接和会话状态能正确保持更新后的数据。可能需要使用st.experimental_rerun或者在回调函数中处理状态更新。然后,安全问题,比如防止SQL注入,应该使用参数化查询,而不是拼接字符串。例如,在sqlite3中使用问号作为占位符,传递参数元组。最后,测试代码是否正常工作,确保按钮点击后数据库确实更新,并且前端显示也同步变化。可能需要打印成功信息或者使用st.success来提示用户操作成功。总结步骤:创建按钮,编写回调函数连接数据库并执行更新,更新session_state中的DataFrame,处理重新运行和状态保持,确保安全性和用户反馈。</think>在Streamlit中实现按钮更新数据库功能需结合前端交互与后端数据库操作,以下是分步实现方案: ### 一、基础功能实现 1. **创建交互按钮** ```python import streamlit as st import pandas as pd import sqlite3 if st.button('标记完成'): # 回调函数逻辑将在此处添加 ``` 2. **数据库更新核心逻辑** ```python def update_database(selected_index): """更新数据库的原子操作""" conn = sqlite3.connect('your_database.db') cursor = conn.cursor() try: # 参数化查询防止SQL注入 cursor.execute('''UPDATE tasks SET is_completed = 1 WHERE rowid = ?''', (selected_index+1,)) conn.commit() st.success("数据库更新成功!") except Exception as e: st.error(f"更新失败: {str(e)}") finally: conn.close() ``` ### 二、完整实现方案 ```python import streamlit as st import pandas as pd import sqlite3 # 初始化会话状态 if 'data' not in st.session_state: st.session_state.data = pd.DataFrame({ '任务': ['任务1', '任务2', '任务3'], '是否完成': [0, 0, 0] }) def update_record(index): """更新指定记录的回调函数""" # 更新数据库 with sqlite3.connect('tasks.db') as conn: cursor = conn.cursor() cursor.execute('''UPDATE tasks SET is_completed = 1 WHERE rowid = ?''', (index+1,)) conn.commit() # 更新前端显示 st.session_state.data.at[index, '是否完成'] = 1 st.rerun() # 显示数据表格 st.dataframe(st.session_state.data) # 为每行创建按钮 for idx, row in st.session_state.data.iterrows(): if row['是否完成'] == 0: if st.button(f"标记任务{idx+1}完成", key=f"btn_{idx}"): update_record(idx) ``` ### 三、关键实现细节 1. **状态管理**:使用`st.session_state`保持数据一致性[^2] 2. **数据库连接**:推荐使用上下文管理器确保连接释放 3. **原子操作**:数据库事务确保操作的完整性 4. **安全防护**:参数化查询防范SQL注入攻击 ### 四、优化建议 1. 添加加载状态提示: ```python with st.spinner('更新中...'): update_record(index) ``` 2. 实现批量更新功能: ```python selected_indices = st.multiselect('选择要标记的任务', options=df.index) if st.button('批量标记完成'): for idx in selected_indices: update_record(idx) ``` 3. 添加实时数据刷新: ```python if st.button('强制刷新数据'): st.session_state.data = load_from_database() st.rerun() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值