I was trying to build a Jupyter notebook solution for outlier analysis of video dataset. I wanted to use Video
widget for that purpose, but I didn't find in the documentation how to get a current video frame and/or scroll to needed position by calling some widget's method. My problem is very similar (virtually the same) to these unanswered questions one and two.
I managed to implement the idea by saving the video frames to numpy array and employing matplotlib's imshow
function, but video playing is very jittering. I used blitting technique to get some extra fps, but it didn't help much, and in comparison, Video
widget produces a smoother experience. It looks like Video
widget is essentially a wrapper for browser's built-in video player.
Question: How can I get control of widget's playing programmatically so I can synchronize multiple widgets? Could some %%javascript
magic help with a IPython.display
interaction?
Here below is a Python code snippet just for illustration purposes, to give you an idea of what I want to achieve.
%matplotlib widget
from videoreader import VideoReader # nice pithonic wrapper for video reading with opencv
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import IntSlider, Play, link, HBox, VBox
# prepare buffered video frames
vr = VideoReader('Big.Buck.Bunny.mp4')
fps = vr.frame_rate
frames = []
for frame in vr[0:300:1]:
frames.append(frame[:,:,::-1]) # brg2rgb
del vr
vi_buff = np.stack(frames, axis=0) # dimensions (T, H, W, C)
# simulate random signal for demonstration purposes
t = np.linspace(0.0, vi_buff.shape[0], num=vi_buff.shape[0]*10)
s = np.sin(2*np.pi*t)*np.random.randn(vi_buff.shape[0]*10)
plt.ioff()
fig = plt.figure(figsize=(11, 8))
ax1 = plt.subplot2grid((6, 6), (0, 0), rowspan=2, colspan=3)
ax2 = plt.subplot2grid((6, 6), (0, 3), colspan=3)
ax3 = plt.subplot2grid((6, 6), (1, 3), colspan=3)
plt.ion()
# initial plots
img = ax1.imshow(vi_buff[0,...])
l0 = ax2.plot(t, s)
l1 = ax3.plot(t, -s)
# initial scene
lo_y, hi_y = ax2.get_ybound()
ax2.set_xbound(lower=-12., upper=2.)
ax3.set_xbound(lower=-12., upper=2.)
def update_plot(change):
val = change.new
img.set_data(vi_buff[val,...])
ax2.axis([val - 12, val + 2, lo_y, hi_y])
ax3.axis([val - 12, val + 2, lo_y, hi_y])
fig.canvas.draw_idle()
player = Play(
value=0, #intial frame index
min=0,
max=vi_buff.shape[0]-1,
step=1,
interval=int(1/round(fps)*1000) #referesh interval in ms
)
fr_slider = IntSlider(
value=0,
min=0,
max=vi_buff.shape[0]-1
)
fr_slider.observe(update_plot, names='value')
link((player,"value"), (fr_slider,"value"))
VBox([HBox([player, fr_slider]), fig.canvas])