Build a Streamlit app for real-time tuning of video smoothing parameters. Users should be able to upload a video, adjust parameters via sliders, and see a live preview of the processed output. Include functionality to save/load parameter presets, and save runs with associated parameters and output video. Add an A/B comparison mode to compare two saved runs side-by-side. Ensure the UI is clean, responsive, and user-friendly. Use WebSocket or Streamlit native features for real-time updates. Structure code with components like TuningInterface, ParameterPersistence, and RunComparison.
To upload files, please first save the app
import streamlit as st
import cv2
import numpy as np
import pandas as pd
from sqlalchemy import create_engine, Column, Integer, Float, String, DateTime, LargeBinary
from sqlalchemy.orm import DeclarativeBase, Session
from datetime import datetime
import io
import json
# Database setup
class Base(DeclarativeBase):
pass
class VideoRun(Base):
__tablename__ = 'video_runs'
id = Column(Integer, primary_key=True)
name = Column(String)
timestamp = Column(DateTime, default=datetime.utcnow)
parameters = Column(String) # JSON string
processed_video = Column(LargeBinary)
engine = create_engine('sqlite:///video_smoothing.db')
Base.metadata.create_all(engine)
def save_run(name, params, video_data):
run = VideoRun(
name=name,
parameters=json.dumps(params),
processed_video=video_data
)
with Session(engine) as session:
session.add(run)
session.commit()
return run.id
def load_runs():
with Session(engine) as session:
runs = session.query(VideoRun).all()
return {run.name: run for run in runs}
def process_frame(frame, blur_amount, brightness, contrast):
# Apply Gaussian blur
if blur_amount > 0:
frame = cv2.GaussianBlur(frame, (2*int(blur_amount) + 1, 2*int(blur_amount) + 1), 0)
# Adjust brightness and contrast
frame = cv2.convertScaleAbs(frame, alpha=contrast, beta=brightness)
return frame
def save_parameters(name, params):
if 'saved_presets' not in st.session_state:
st.session_state.saved_presets = {}
st.session_state.saved_presets[name] = params
def main():
st.title("Video Smoothing Studio")
# Initialize session state
if 'processed_frames' not in st.session_state:
st.session_state.processed_frames = None
if 'comparison_mode' not in st.session_state:
st.session_state.comparison_mode = False
# Sidebar for controls
with st.sidebar:
st.header("Controls")
# Video upload
uploaded_file = st.file_uploader("Upload Video", type=['mp4', 'avi', 'mov'])
# Parameter controls
st.subheader("Parameters")
blur = st.slider("Blur Amount", 0, 10, 0)
brightness = st.slider("Brightness", -50, 50, 0)
contrast = st.slider("Contrast", 0.5, 2.0, 1.0)
# Preset management
st.subheader("Presets")
preset_name = st.text_input("Preset Name")
col1, col2 = st.columns(2)
with col1:
if st.button("Save Preset"):
if preset_name:
params = {
'blur': blur,
'brightness': brightness,
'contrast': contrast
}
save_parameters(preset_name, params)
st.success(f"Saved preset: {preset_name}")
else:
st.error("Please enter a preset name")
with col2:
if 'saved_presets' in st.session_state and st.session_state.saved_presets:
selected_preset = st.selectbox(
"Load Preset",
options=list(st.session_state.saved_presets.keys())
)
if st.button("Load"):
params = st.session_state.saved_presets[selected_preset]
st.rerun()
# Main content area
col1, col2 = st.columns(2)
with col1:
st.subheader("Original Video")
if uploaded_file:
# Save video file to temporary file
video_bytes = uploaded_file.read()
with open("temp_video.mp4", "wb") as f:
f.write(video_bytes)
# Display original video
st.video(video_bytes)
with col2:
st.subheader("Processed Video")
if uploaded_file:
# Process video
cap = cv2.VideoCapture("temp_video.mp4")
processed_frames = []
# Get video properties
fps = int(cap.get(cv2.CAP_PROP_FPS))
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Create video writer
out = cv2.VideoWriter(
'processed_video.mp4',
cv2.VideoWriter_fourcc(*'mp4v'),
fps,
(frame_width, frame_height)
)
# Process frames
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# Process frame
processed_frame = process_frame(frame, blur, brightness, contrast)
out.write(processed_frame)
processed_frames.append(processed_frame)
cap.release()
out.release()
# Display processed video
with open("processed_video.mp4", "rb") as f:
processed_video_bytes = f.read()
st.video(processed_video_bytes)
# Save run
if st.button("Save Run"):
run_name = st.text_input("Run Name")
if run_name:
params = {
'blur': blur,
'brightness': brightness,
'contrast': contrast
}
save_run(run_name, params, processed_video_bytes)
st.success(f"Saved run: {run_name}")
# Comparison mode
st.subheader("Run Comparison")
if st.checkbox("Enable Comparison Mode"):
runs = load_runs()
if runs:
col1, col2 = st.columns(2)
with col1:
run1 = st.selectbox("Select First Run", options=list(runs.keys()), key="run1")
if run1:
st.video(runs[run1].processed_video)
st.json(json.loads(runs[run1].parameters))
with col2:
run2 = st.selectbox("Select Second Run", options=list(runs.keys()), key="run2")
if run2:
st.video(runs[run2].processed_video)
st.json(json.loads(runs[run2].parameters))
else:
st.info("No saved runs available for comparison")
if __name__ == "__main__":
main()
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?