ipywebrtc icon indicating copy to clipboard operation
ipywebrtc copied to clipboard

image.value is empty byte string

Open mgreenbe opened this issue 6 years ago • 9 comments

I'm having a strange issue. When I capture an image from the image recorder, it's value ends up being the empty byte string. If I then ask for the value in the subsequent cell, I get the bytes. What's causing this asynchrony? I tried to "fix" it by adding a delay between defining image and asking for its value, but that didn't work. What's the "correct" way of reliably grabbing the current camera frame's value?

Screen Shot 2019-09-17 at 12 25 32 PM

mgreenbe avatar Sep 17 '19 18:09 mgreenbe

This is actually the correct behavior. This asynchronicity is due to the communication between the Python back-end and the JavaScript front-end.

Another way of dealing with it is to define a callback function that will be called when the image value has changed:

def on_value_changed(*args, **kwargs):
    # The value has changed! (Note that the following print won't show up in JupyterLab, 
    # it only shows up in the classical Jupyter Notebook. You need to use the Output 
    # widget if you want to capture streams in JLab)
    print(image_recorder.image.value)
    print(args, kwargs)
    # Do whatever you want with your newly received image

image_recorder.image.observe(on_value_changed, 'value')

image_recorder.recording = True

The Ouptut widget I mention in the comment: https://ipywidgets.readthedocs.io/en/stable/examples/Output%20Widget.html

This observe method comes from traitlets https://traitlets.readthedocs.io/en/stable/using_traitlets.html#observe (All interactive widgets are HasTraits classes internally)

martinRenou avatar Sep 18 '19 06:09 martinRenou

The callback doesn't seem to running. I would have expected to see an infinite sequence of "The callback ran." strings printed (once for each frame?) and the did_callback_run changed to True.

Screen Shot 2019-09-18 at 8 33 28 AM

mgreenbe avatar Sep 18 '19 14:09 mgreenbe

Try defining did_the_callback_run as being a global variable in your callback. Otherwise, it is seen as a local variable by Python if I'm correct.

def on_value_changed(_):
    global did_the_callback_run

    did_the_callback_run = True

Also, I suggest using the Output widget for capturing the stdout and stderr of your callbacks. Because sometimes the Notebook does not know where to put the output of the streams and simply discard them, that is why you don't see anything printed.

from ipywidgets import Output

out = Output()
out.layout.border = 'solid'
display(out)

@out.capture()
def on_value_changed(_):
    global did_the_callback_run
    print("It works!!")
    did_the_callback_run = True

I would have expected to see an infinite sequence of "The callback ran.

It will print it infinitely only if you set recording to True at the end of the callback, that will create an infinite callback loop.

from ipywidgets import Output

out = Output()
out.layout.border = 'solid'
display(out)

@out.capture()
def on_value_changed(_):
    global did_the_callback_run
    print("It works!!")
    did_the_callback_run = True

    image_recorder.recording = True

I would agree that recording is a bad name, it should be something like a capture_frame() method.

martinRenou avatar Sep 18 '19 15:09 martinRenou

Also, it might be super slow to capture frames infinitely... ipywebrtc needs some love in terms of optimization (PRs welcome!).

So try using the sleep function from Python in your callback to reduce the capture framerate.

martinRenou avatar Sep 18 '19 15:09 martinRenou

@martinRenou Your suggestions for the infinite loop does not work (at least not for ipywebrtc==0.6.0):

finite_loop

Every time I execute the last cell again, it will add a line to the output

finite_loop2

but the point was to not needing to do that.

pmeier avatar Jul 02 '21 19:07 pmeier

I found if you display the recorder and hit the camera icon, this actually triggers an infinite loop. Looking at the code, I have no idea what is executed by pressing the camera icon. Does someone have some pointers for me to check what is happening besides setting recorder.recording = True?

pmeier avatar Jul 06 '21 07:07 pmeier

I am running into a similar problem.

If the value recorder.recording is set to True manually then the callback is called once, by the recorder.recording is still True during the callback. Since it is already True, there is no effect in changing it to True again. However, when you click the camera icon, the recorder.recording is False during the callback and thus setting it to True has an effect.

However, I have noticed that if the callback takes just a bit too long to complete, it will still fail to be called again, even if set to True.

coderforlife avatar Nov 18 '21 04:11 coderforlife

Same here... Still buggy... Magic webrtc .... I can display live camera, but if I do any process, the resultant image won't be able to show live in another window. How?? I mean:

  • The FIRST window shows original images captured from camera
  • The SECOND window shows the filtered captured images in live

jiapei100 avatar Sep 14 '22 01:09 jiapei100

Hi! Was this ever resolved? Also in our case the on_value_changed callback is never called and the image returned is empty (empty byte array).

gino-m avatar Dec 27 '23 15:12 gino-m