Created
September 29, 2024 16:07
-
-
Save maulikmadhavi/a3ab05b67cf39ca15c588d2f26998688 to your computer and use it in GitHub Desktop.
video rendering and confidence visualization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 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