Hi, I just tried out Shiny for python yesterday and I'm wondering how can I render an individual video frame (basically an image) as it is being outputted by a for loop? I'm trying to make a web interface for the supervision library and I want the processed/annotated frames to be shown to the user while it's being processed but I can't figure out how to do it. In streamlit it's very easy I since I can simply render the frame to a st.empty() container, is there a similar way to do it in shiny?
I kind of managed to do it but only by using a button to get the next frame however that is not the behavior I want. I would like the frames to continuously render dynamically without any additional user input. I'm trying to use a reactive value to change the "src" of the image but the for loop seems to be blocking me from accessing the new reactive value while its looping hence I only get the last frame .
Rendering an tag does not help either since a new one gets created for each iteration of the loop.
This code below is the code with the 'Next frame' button. Please help me how to modify it so that the frames gets rendered after a successful video upload and not only after a button press.
import supervision as sv
from shiny.express import input, render, ui
from shiny import reactive
from cv2 import imwrite
TEMP_IMG_FILENAME = "temp_img.jpg"
ui.input_file("vid_input", "Upload")
img_obj = reactive.value({})
@reactive.calc
@reactive.event(input.vid_input)
def get_frames():
vid_path = input.vid_input()[0]['datapath']
for frame in sv.get_video_frames_generator(source_path=vid_path): # Returns every frame of a video
yield frame
ui.input_task_button("next_frame_button", "Next frame")
@reactive.event(input.next_frame_button)
def next_frame():
frame = next(get_frames()) # Get next frame from the generator
imwrite(TEMP_IMG_FILENAME, frame) # Write image to a file using opencv
img_obj.set({"src" : TEMP_IMG_FILENAME, "width": 500}) # Set new value for the img_ojb reactive value
return img_obj.get()
@render.image
def show_frames():
return next_frame()