How do I display 2 videos side by side in Plotly Dash when I'm doing OpenCV pose detection on them?

I have done this project where I am doing pose detection on two videos, and displaying how correctly the user is moving with respect to the benchmark movement.

Now, I want to make this a web app for people to be able to use widely by uploading videos of their own. For that, I have made this minimum viable dash app that can currently display the two videos uploaded by the user as it is:

import dash
from dash.dependencies import Output, Input, State
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()
server = app.server

app.layout = html.Div(children = [

    html.Div([
        html.Div([
            dcc.Upload(id='upload_file_1', children=[html.Button('Upload File 1', id='file_upload_btn_1', n_clicks=0, style={'width': '240px', 'height':'40px'})]
        )], style={'display': 'inline-block'}),
        html.Div(id='file_upload_success_1', style={'display': 'inline-block'}),
    ]),

    html.Div([
        html.Div([
            dcc.Upload(id='upload_file_2', children=[html.Button('Upload File 2', id='file_upload_btn_2', n_clicks=0, style={'width': '240px', 'height':'40px'})]
        )], style={'display': 'inline-block'}),
        html.Div(id='file_upload_success_2', style={'display': 'inline-block'}),
    ]),

    html.Button('Submit', id='submit_btn', n_clicks=0, style={'width': '300px', 'height':'60px'}),

    html.Div(id='display_output')
])

@app.callback(Output('file_upload_success_1', 'children'),
              Input('file_upload_btn_1', 'n_clicks'),
              Input('upload_file_1', 'contents'),
              State('upload_file_1', 'filename'))
def update_success_message(n_clicks, contents, filename):
    if n_clicks and contents:
        return "File '{}' uploaded".format(filename)

@app.callback(Output('file_upload_success_2', 'children'),
              Input('file_upload_btn_2', 'n_clicks'),
              Input('upload_file_2', 'contents'),
              State('upload_file_2', 'filename'))
def update_success_message(n_clicks, contents, filename):
    if n_clicks and contents:
        return "File '{}' uploaded".format(filename)

@app.callback(Output('display_output', 'children'),
              Input('submit_btn', 'n_clicks'),
              Input('upload_file_1', 'contents'),
              Input('upload_file_2', 'contents'))
def update_output(n_clicks, video_1, video_2):
    if n_clicks:
        if video_1 and video_2:
            return [
                html.Video(
                    controls = True,
                    id = 'movie_player_1',
                    src = video_1,
                    autoPlay=True
                ), 

                html.Video(
                    controls = True,
                    id = 'movie_player_2',
                    src = video_2,
                    autoPlay=True
                )
            ]
    else:
        dash.no_update

if __name__ == '__main__':
    app.run_server(debug=True)

The only thing remaining is to display the pose detected videos in place of the videos directly. How do I do that? I realize that I need to modify the two cv2.imshow() lines in the move_comparison module of my project to display the results in the browser. But Iā€™m not able to find a way to do that in dash. Please advise, any help is appreciated. Thanks!

The solution using threading, asyncio and websockets seems to be too complicated. Is there any way to do this in Dash in a less convoluted manner?

1 Like