El servidor remoto Jupyter utiliza una cámara local y WebRTC para realizar salas de chat y procesamiento de video en tiempo real

Cámara de uso remoto Jupyter, sala de chat WebRTC, procesamiento de video en tiempo real

prefacio

Utilice el componente ipywebrtc para obtener la transmisión de video local y transmitirla al servidor remoto de Jupyter. Después de que el servidor procese el video, se enviará de vuelta al local y finalmente lo ipywidgets.Imagemostrará el componente.

Experiencia de efecto

Se recomienda utilizar el navegador Chrome

Mostrar resultados
Vaya al ejemplo oficial y habilite la cámara para verlo en acción.
Si desea experimentar el código de demostración con mayor profundidad, puede ir a Binder para abrir cualquier .ipynbarchivo y ejecutarlo paso a paso.


Preparación

Los componentes deben instalarse primero ipywebrtc. Hay dos métodos. La forma más sencilla es instalar pipdirectamente (requiere la versión 5.3 de jupyter y superior):

pip install ipywebrtc

El segundo es instalar la última versión de vista previa a través de github:

git clone https://github.com/maartenbreddels/ipywebrtc
cd ipywebrtc
pip install -e .
jupyter nbextension install --py --symlink --sys-prefix ipywebrtc
jupyter nbextension enable --py --sys-prefix ipywebrtc

Si está utilizando jupyter lab, simplemente ejecute la siguiente declaración en la terminal:

jupyter labextension install jupyter-webrtc

Instrucciones

Después de completar los preparativos, primero debe hacer referencia ipywebrtca la biblioteca en el archivo Jupyter y luego crear una transmisión. Para ver las transmisiones disponibles, consulte la sección de introducción del componente a continuación. Aquí hay un CameraStreamejemplo para usar la cámara frontal local:

from ipywebrtc import CameraStream
camera = CameraStream.facing_user(audio=False)
camera

Si no hay ningún accidente, el navegador Chrome abrirá una ventana emergente que le preguntará si permite que la página web use la cámara. Después de elegir permitir, puede ver el video capturado por la cámara en el área de salida.

Si Chrome no muestra un aviso, pero lo muestra Error creating view for media stream: Only secure origins are allowed, significa que el navegador cree que el sitio web actual no es seguro ( httpsno se usa la conexión), por lo que la cámara está desactivada. La solución más fácil es agregarlo al final de la columna "Objetivo" del acceso directo de Chrome --unsafely-treat-insecure-origin-as-secure="http://host_ip:port"y reiniciarlo ( host_ip:portcámbielo a la dirección de su propio servidor)

Pero en este momento, el video solo se muestra localmente y no se carga en el servidor donde se encuentra el kernel de Python (suponiendo que esté utilizando un servidor remoto), por lo que no hay forma de obtener el contenido del video en el contexto de Python.
Entonces, a continuación, debemos crear uno ImageRecorderpara grabar la transmisión y enviarla como una imagen al kernel de Python en el servidor:

from ipywebrtc import ImageRecorder
image_recorder = ImageRecorder(stream=camera)
image_recorder

Ejecute este código, se mostrará el componente ImageRecorder, haga clic en el ícono de la cámara en el componente, puede capturar streamla pantalla. Después de eso, puede obtener la imagen en Python
Grabador de imágenes
accediendo image_recorder.image.valuey convirtiéndola a un formato:Pillow

import PIL.Image
import io
im = PIL.Image.open(io.BytesIO(image_recorder.image.value))

Si no necesita procesarlo y solo necesita obtener una vista previa, puede mostrarlo directamente.Es image_recorder.imageun ipywidgets.Imagecomponente que tiene la función de mostrar imágenes.
Si necesita usar opencv-pythonel procesamiento de imágenes, puede canvas = numpy.array(im)[..., :3]obtener cv2una matriz de imágenes que se pueda procesar y matplotlibmostrar la imagen después del procesamiento, pero recomiendo usar ipywidgets.Imagecomponentes:

from ipywidgets import Image
out = Image()
out.value = cv2.imencode('.jpg', cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB))[1].tobytes() # canvas出处见上文说明部分
out

O si no quieres volver a presentarlo cv2, también puedes seguir el camino oficial:

from ipywidgets import Image
out = Image()
im_out = PIL.Image.fromarray(canvas)
f = io.BytesIO()
im_out.save(f, format='png')
out.value = f.getvalue()
out

proceso de vídeo

Hasta ahora solo hemos presentado cómo capturar una imagen, procesarla y mostrarla, todo lo cual se puede aprender fácilmente a través de documentos oficiales. Entonces, ¿cómo podemos capturar continuamente cada cuadro en un video, procesarlo y luego mostrarlo uno por uno? ImageRecorderA continuación se presentará el método de rastreo continuo que he resumido .

La razón por la que todavía se usa la captura continua ImageRecorderen lugar de VideoRecorderes porque VideoRecorderel video capturado debe tener un comienzo y un final, y solo después del final se puede procesar todo el videoclip capturado, lo que no cumple con el requisito de "tiempo real".

Después de analizar el código del autor, descubrí que no existe una función como o , y recorder.record()después de que el front-end tome el siguiente cuadro de la imagen, notificará al kernel de Python que establezca el atributo en , y luego, después de tomar una imagen, el atributo cambiará automáticamente a . Así que quiero probar un mecanismo de bucle, que se configura automáticamente para capturar el siguiente cuadro de imágenes después de procesar el cuadro anterior cada vez . Sin embargo, después de la experimentación, el uso de bucles o bucles no funciona. Esto probablemente se deba a que el front-end de Jupyter está representado por Javascript. Simplemente cambiando los atributos en el entorno de Python del back-end sin notificar al front-end no puede seguir rastreando.recorder.take_photo()ImageRecorderImageRecorderrecordingTruerecordingFalserecordingTrue
whilefor

Esta razón es solo mi suposición personal. Debido a razones de tiempo, no miré detenidamente los archivos front-end y la lógica subyacente, por lo que mi comprensión puede ser incorrecta. Corríjame en el área de comentarios.

Finalmente, haciendo referencia a la publicación de martin Renou en Github , pensé en el siguiente modo para completar el procesamiento continuo de video en tiempo real:

import io
import PIL.Image
import numpy as np
from ipywidgets import Image, VBox, HBox, Widget, Button
from IPython.display import display
from ipywebrtc import CameraStream, ImageRecorder

VIDEO_WIDTH = 640 # 窗口宽度,按需调整
VIDEO_HEIGHT = 480 # 窗口高度,按需调整

camera = CameraStream(constraints=
                      {
    
    'facing_mode': 'user',	
                       'audio': False,	
                       'video': {
    
     'width': VIDEO_WIDTH, 'height': VIDEO_HEIGHT}	
                       })	# 另一种CameraStream创建方式,参考下文组件介绍部分
image_recorder = ImageRecorder(stream=camera)
out = Image(width=VIDEO_WIDTH, height=VIDEO_HEIGHT)

FLAG_STOP = False	# 终止标记

def cap_image(_):	# 处理ImageRecord抓取到的图片的过程
    if FLAG_STOP:
        return	# 停止处理
    im_in = PIL.Image.open(io.BytesIO(image_recorder.image.value))
    im_array = np.array(im_in)[..., :3]
    canvas = process(im_array)	# process是处理图像数组的函数,这里没写出来,各位按处理需要自己写即可
    im_out = PIL.Image.fromarray(canvas)
    f = io.BytesIO()
    im_out.save(f, format='png')
    out.value = f.getvalue()
    image_recorder.recording = True	# 重新设置属性,使ImageRecorder继续抓取

# 注册抓取事件,参考我另一篇Blog:https://qxsoftware.blog.csdn.net/article/details/86708381
image_recorder.image.observe(cap_image, names=['value'])

# 用于停止抓取的按钮
btn_stop = Button(description="Stop",
                  tooltip='click this to stop webcam',
                  button_style='danger')
# btn_stop的处理函数
def close_cam(_):
    FLAG_STOP= True
    Widget.close_all()
btn_stop.on_click(close_cam) # 注册单击事件
# Run this section and Press the Camera button to display demo
display(VBox([HBox([camera, image_recorder, btn_stop]), out]))

Después de ejecutar este código en Jupyter, habrá un cuadro de vista previa de la cámara local, un ImageRecordercuadro de captura, un botón rojo Detener y un Imagecomponente sin imagen todavía.
Al hacer clic en ImageRecorderel botón de la cámara de arriba, se activará cap_imagela función, y luego la imagen procesada se Imagemostrará en el componente, y el proceso se repetirá hasta que se haga clic en Detener.
Solo después de hacer clic en la cámara, se puede acceder normalmente a las celdas Jupyter adicionales image_recorder.image; de lo contrario, se informará un error OSError: cannot identify image file.

La parte más crítica aquí es la declaración agregada en la ImageRecorder.imagefunción de registro de eventos . En cuanto a por qué no es válido agregar esta oración fuera de la función de registro, debemos estudiar la conexión entre los extremos frontal y posterior. Cabe señalar que el error en la función de registro no provocará una interrupción, por lo que si el componente no muestra la imagen después de ejecutarse , puede tratarse de un error, que se puede verificar extrayendo el contenido en la nueva celda.observerimage_recorder.recording = True
cap_imageImagecap_imagecap_image


Introducción de componentes

ipywebrtc, los medios de transmisión disponibles son:

  • VideoStream: Puede VideoStream.from_file(path)obtener video local u VideoStream.from_url(url)obtener video en red

  • CameraStream: obtenga el flujo de medios a través del dispositivo de cámara local o cámara web (cámara web). Hay dos formas de crearlo:

    • La primera:
       	camera = CameraStream(constraints=
       	                      {
          
          'facing_mode': 'user',	# 'user表示前置摄像头,'environment'表示后置摄像头
       	                       'audio': False,	# 是否同时获取音频(需要硬件支持)
       	                       'video': {
          
           'width': 640, 'height': 480 }	# 获取视频的宽高
       	                       })
    
    • El segundo tipo:
      front_camera = CameraStream.facing_user(audio=False): Cámara frontal
      back_camera = CameraStream.facing_environment(audio=False): Cámara trasera
  • AudioStream: flujo de audio, VideoStreamcreado de la misma manera que para

  • WidgetStream: al WidgetStream(widget=target)especificar , la salida de cualquier instancia se widgetpuede crear como un flujo de mediosipywidget

Todos estos flujos de medios heredan de MediaStreamla clase

Además del componente de transmisión de medios, también hay un componente de grabadora, que se usa para registrar la transmisión obtenida por el Javascript front-end y enviarla al kernel de Python, que se presentó en detalle en el ejemplo, y ImageRecorderel VideoRecorderuso es similar, consulte el documento oficial .
Finalmente, están ipywebrtc.webrtclos componentes en . Después de la prueba, todavía hay algunos errores. Puede consultar la sala de chat de video Chat .


Más contenido (como ipyvolumnseries) se actualizará en el futuro.
Publicado originalmente en CSDN, indique la fuente para la reimpresión: https://qxsoftware.blog.csdn.net/article/details/89513815 . Si tiene alguna pregunta o idea, deje un comentario a continuación ~~

Supongo que te gusta

Origin blog.csdn.net/liuqixuan1994/article/details/89513815
Recomendado
Clasificación