Skip to content

Instantly share code, notes, and snippets.

@maulikmadhavi
Created September 29, 2024 16:07
Show Gist options
  • Select an option

  • Save maulikmadhavi/a3ab05b67cf39ca15c588d2f26998688 to your computer and use it in GitHub Desktop.

Select an option

Save maulikmadhavi/a3ab05b67cf39ca15c588d2f26998688 to your computer and use it in GitHub Desktop.
video rendering and confidence visualization
"""
This code sets up a Dash web application that displays a video player and a confidence plot.
The `get_concatenated_image` function takes a center frame index and returns a base64-encoded image string and a list of frame indices. The image is created by concatenating 11 frames (5 before and 5 after the center frame) horizontally, with each frame downsampled to 320x320 pixels.
The Dash layout includes a slider to select the center frame, an image display, and a confidence plot. The `update_image` callback function is triggered when the slider value changes, and it updates the image and confidence plot based on the selected center frame.
The confidence scores for "Yes" and "No" are randomly generated for each frame, and the confidence plot shows the scores for the frames around the selected center frame.
"""
from dash import Dash, html, dcc, Input, Output
import decord
import numpy as np
from decord import VideoReader, cpu
import base64
from PIL import Image
from io import BytesIO
import plotly.graph_objs as go
from functools import lru_cache
app = Dash(__name__)
video_path = "/home/maulik/Videos/2015-10-21 at 16-51-09.mp4"
# Open the video using decord
decord.bridge.set_bridge("native") # To use native decoding
vr = VideoReader(video_path, ctx=cpu(0)) # or gpu(0) if you want GPU support
num_frames = vr._num_frame
# Generate random confidence scores for num_frames
yes_conf_scores = np.random.rand(num_frames)
no_conf_scores = np.random.rand(num_frames)
@lru_cache(maxsize=100)
def get_concatenated_image(center_frame: int) -> tuple:
"""
Generate a concatenated image from a sequence of video frames centered around a specified frame.
This function extracts a sequence of frames from a video, downsamples each frame to 320x320 pixels,
concatenates them horizontally, and returns the concatenated image as a base64-encoded PNG string.
Args:
center_frame (int): The index of the central frame around which the sequence is extracted.
Returns:
tuple: A tuple containing:
- str: The base64-encoded PNG string of the concatenated image.
- list: A list of frame indices used in the concatenation.
Raises:
ValueError: If the center_frame is out of bounds.
"""
# Extract frames
start_frame = max(0, center_frame - 5)
end_frame = min(num_frames, center_frame + 6)
frame_indices = list(range(start_frame, end_frame))
# Initialize an empty list to store the concatenated image parts
concatenated_frame_parts = []
for i in frame_indices:
frame = vr[i].asnumpy()
# Downsample the frame to 320x320
frame_image = Image.fromarray(frame)
frame_image = frame_image.resize((320, 320), Image.LANCZOS)
frame = np.array(frame_image)
concatenated_frame_parts.append(frame)
# Concatenate frames horizontally
concatenated_frame = np.concatenate(concatenated_frame_parts, axis=1)
# Convert concatenated frame to image
image = Image.fromarray(concatenated_frame)
buffered = BytesIO()
image.save(buffered, format="PNG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return img_str, frame_indices
# Create Dash layout
app.layout = html.Div([
html.Img(id='image-display'), # Image first
dcc.Graph(id='confidence-plot'), # Plot below
dcc.Slider(
id='frame-slider',
min=0,
max=num_frames - 1,
value=0,
marks={i: str(i) for i in range(0, num_frames, max(1, num_frames))},
step=1
),
])
@app.callback(
[Output('image-display', 'src'),
Output('confidence-plot', 'figure')],
Input('frame-slider', 'value')
)
def update_image(center_frame: int) -> tuple:
img_str, frame_indices = get_concatenated_image(center_frame)
yes_scores = [yes_conf_scores[i] for i in frame_indices]
no_scores = [no_conf_scores[i] for i in frame_indices]
# Create the plot
fig = go.Figure()
fig.add_trace(go.Scatter(
x=frame_indices,
y=yes_scores,
mode='lines+markers',
name='Yes Confidence',
line=dict(color='blue')
))
fig.add_trace(go.Scatter(
x=frame_indices,
y=no_scores,
mode='lines+markers',
name='No Confidence',
line=dict(color='red')
))
fig.update_layout(
title='Confidence Scores',
xaxis_title='Frame',
yaxis_title='Confidence'
)
return f"data:image/png;base64,{img_str}", fig
if __name__ == '__main__':
app.run_server(debug=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment