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.Image
mostrará el componente.
Experiencia de efecto
Se recomienda utilizar el navegador Chrome
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 .ipynb
archivo y ejecutarlo paso a paso.
Preparación
Los componentes deben instalarse primero ipywebrtc
. Hay dos métodos. La forma más sencilla es instalar pip
directamente (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 ipywebrtc
a 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 CameraStream
ejemplo 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 (https
no 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:port
cá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 ImageRecorder
para 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 stream
la pantalla. Después de eso, puede obtener la imagen en Python
accediendo image_recorder.image.value
y 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.image
un ipywidgets.Image
componente que tiene la función de mostrar imágenes.
Si necesita usar opencv-python
el procesamiento de imágenes, puede canvas = numpy.array(im)[..., :3]
obtener cv2
una matriz de imágenes que se pueda procesar y matplotlib
mostrar la imagen después del procesamiento, pero recomiendo usar ipywidgets.Image
componentes:
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? ImageRecorder
A 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
ImageRecorder
en lugar deVideoRecorder
es porqueVideoRecorder
el 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()
ImageRecorder
ImageRecorder
recording
True
recording
False
recording
True
while
for
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 ImageRecorder
cuadro de captura, un botón rojo Detener y un Image
componente sin imagen todavía.
Al hacer clic en ImageRecorder
el botón de la cámara de arriba, se activará cap_image
la función, y luego la imagen procesada se Image
mostrará 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.image
funció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.observer
image_recorder.recording = True
cap_image
Image
cap_image
cap_image
Introducción de componentes
ipywebrtc
, los medios de transmisión disponibles son:
-
VideoStream
: PuedeVideoStream.from_file(path)
obtener video local uVideoStream.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,VideoStream
creado de la misma manera que para -
WidgetStream
: alWidgetStream(widget=target)
especificar , la salida de cualquier instancia sewidget
puede crear como un flujo de mediosipywidget
Todos estos flujos de medios heredan de
MediaStream
la 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 ImageRecorder
el VideoRecorder
uso es similar, consulte el documento oficial .
Finalmente, están ipywebrtc.webrtc
los 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 ipyvolumn
series) 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 ~~