Jupyter 원격 서버는 로컬 카메라와 WebRTC를 사용하여 대화방 및 실시간 비디오 처리를 실현합니다.

Jupyter 원격 사용 카메라, WebRTC 채팅방, 실시간 영상 처리

머리말

ipywebrtc 구성 요소를 사용하여 로컬 비디오 스트림을 가져와 원격 Jupyter 서버로 전송합니다. 서버가 비디오를 처리한 후 로컬로 다시 전송되고 최종적으로 구성 요소에 ipywidgets.Image의해 표시됩니다.

효과 경험

Chrome 브라우저 사용을 권장합니다.

결과 보여줘
공식 예제 로 이동하여 카메라가 실제로 작동하는지 확인하십시오.
데모 코드를 더 깊이 경험하고 싶다면 Binder 로 이동하여 파일을 열고 .ipynb단계별로 실행할 수 있습니다.


준비

구성 요소를 먼저 설치해야 합니다 ipywebrtc.두 가지 방법이 있습니다.간단한 방법은 pip직접 설치하는 것입니다(jupyter 버전 5.3 이상 필요).

pip install ipywebrtc

두 번째는 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

jupyter lab을 사용하는 경우 터미널에서 다음 명령문을 실행하십시오.

jupyter labextension install jupyter-webrtc

지침

준비가 완료되면 먼저 ipywebrtcJupyter 파일에서 라이브러리를 참조한 다음 스트림을 생성해야 합니다. 사용 가능한 스트림은 아래 구성 요소 소개 섹션을 참조하십시오. 다음은 CameraStream로컬 전면 카메라를 사용하는 예입니다.

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

이상이 없으면 크롬 브라우저에서 해당 웹페이지의 카메라 사용 허용 여부를 묻는 팝업창을 띄우고 허용을 선택하면 출력 영역에서 카메라가 촬영한 영상을 볼 수 있다.

크롬에서 프롬프트가 팝업되지 않고 표시된다면 Error creating view for media stream: Only secure origins are allowed브라우저에서 현재 웹사이트가 안전하지 않다고 판단하여( https연결이 사용되지 않음) 카메라가 비활성화된 것입니다. 가장 쉬운 해결 방법은 Chrome 바로가기의 "대상" 열 끝에 추가 --unsafely-treat-insecure-origin-as-secure="http://host_ip:port"하고 다시 시작하는 것입니다( host_ip:port자신의 서버 주소로 변경).

하지만 이때 비디오는 로컬에서만 표시되고 Python 커널이 있는 서버에 업로드되지 않으므로(원격 서버를 사용한다고 가정) Python 컨텍스트에서 비디오 콘텐츠를 가져올 방법이 없습니다. 다음으로 스트림을 기록하고 서버의 Python 커널에 사진으로 보낼
스트림을 만들어야 합니다 .ImageRecorder

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

이 코드를 실행하면 구성 요소가 표시됩니다 ImageRecorder. 구성 요소의 카메라 아이콘을 클릭하여 stream화면을 캡처합니다.
이미지 레코더
그런 다음, 그림 에 액세스 image_recorder.image.value하고 형식으로 변환하여 PillowPython에서 그림을 얻을 수 있습니다 .

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

처리할 필요 없이 미리 보기만 하면 바로 표시할 수 있으며, 자체적으로 사진을 표시하는 기능이 있는 컴포넌트 image_recorder.image입니다 . 이미지 처리를 사용해야 하는 경우 처리할 수 있는 이미지 배열을 얻고 처리 후 이미지를 표시할 수 있지만 구성 요소를 사용하는 것이 좋습니다.ipywidgets.Image
opencv-pythoncanvas = numpy.array(im)[..., :3]cv2matplotlibipywidgets.Image

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

또는 다시 소개하고 싶지 않다면 cv2공식적인 방법을 따를 수도 있습니다.

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

프로세스 비디오

지금까지 우리는 사진을 캡처하고 처리하고 표시하는 방법에 대해서만 소개했습니다. 이 모든 것은 공식 문서를 통해 쉽게 배울 수 있습니다. 그렇다면 비디오의 각 프레임을 지속적으로 캡처하고 처리한 다음 하나씩 표시하려면 어떻게 해야 할까요? 다음은 내가 요약한 ImageRecorder연속 크롤링 방법을 소개합니다.

ImageRecorder대신 연속 캡처가 계속 사용되는 이유는 VideoRecorder캡처 VideoRecorder된 비디오에 시작과 끝이 있어야 하고 종료 후에만 캡처된 전체 비디오 클립을 처리할 수 있기 때문에 "실시간" 요구 사항을 충족하지 않습니다.

작성자의 코드를 분석한 결과 or 와 같은 함수가 없다는 것을 알았고 프론트 엔드가 이미지의 다음 프레임을 잡은 recorder.record()후 Python 커널 에 속성을 로 설정 하도록 알리고 그림을 잡은 후 속성 로 자동 변경됩니다 . 따라서 매번 이전 사진 프레임을 처리한 후 자동으로 다음 사진 프레임을 가져오도록 설정 되는 루프 메커니즘을 시도하고 싶습니다. 그러나 실험을 해보니 루프나 루프를 사용하는 것은 잘 되지 않는데 이는 아마도 Jupyter의 프론트엔드가 자바스크립트로 랜더링되었기 때문일 것이다.recorder.take_photo()ImageRecorderImageRecorderrecordingTruerecordingFalserecordingTrue
whilefor

이 이유는 제 개인적인 추측일 뿐이며, 시간상의 이유로 프론트엔드 파일과 기본 로직을 주의 깊게 살펴보지 못하여 제 이해가 정확하지 않을 수 있습니다. 댓글란에 정정 부탁드립니다.

마지막으로, Github에 있는 martin Renou의 게시물을 참조하여 지속적인 실시간 비디오 처리를 완료하기 위해 다음과 같은 모드를 생각했습니다.

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]))

ImageRecorderJupyter에서 이 코드를 실행하면 로컬 카메라 미리보기 상자, 잡기 상자, 빨간색 중지 버튼 및 Image아직 이미지가 없는 구성 요소가 있습니다 . 위의 카메라 버튼을
클릭하면 기능이 활성화되고 처리된 이미지가 컴포넌트에 표시되며 중지를 클릭할 때까지 프로세스가 반복됩니다. 카메라를 클릭한 후에만 추가 Jupyter 셀에 정상적으로 액세스할 수 있습니다 . 그렇지 않으면 오류가 보고됩니다 .ImageRecordercap_imageImage
image_recorder.imageOSError: cannot identify image file

여기서 가장 중요한 부분은 이벤트 등록 ImageRecorder.image기능 에 추가된 문장입니다 . 등록 기능 외에 이 문장을 추가하는 것이 왜 무효인지에 대해서는 프런트 엔드와 백엔드 간의 연결을 연구해야 합니다. 등록 기능 의 오류는 중단을 일으키지 않으므로 구성 요소가 실행 후 이미지를 표시하지 않으면 오류 일 수 있으며 새 셀에서 내용을 추출하여 확인할 수 있습니다 .observerimage_recorder.recording = True
cap_imageImagecap_imagecap_image


구성 요소 소개

ipywebrtc, 사용 가능한 스트리밍 미디어는 다음과 같습니다.

  • VideoStreamVideoStream.from_file(path): 로컬 영상을 받을 수도 있고, VideoStream.from_url(url)네트워크 영상을 받을 수도 있습니다.

  • CameraStream: 로컬 카메라 장치 또는 웹캠(웹캠)을 통해 미디어 스트림을 얻습니다. 만드는 방법에는 두 가지가 있습니다.

    • 첫번째:
       	camera = CameraStream(constraints=
       	                      {
          
          'facing_mode': 'user',	# 'user表示前置摄像头,'environment'表示后置摄像头
       	                       'audio': False,	# 是否同时获取音频(需要硬件支持)
       	                       'video': {
          
           'width': 640, 'height': 480 }	# 获取视频的宽高
       	                       })
    
    • 두 번째 유형:
      front_camera = CameraStream.facing_user(audio=False): 전면 카메라
      back_camera = CameraStream.facing_environment(audio=False): 후면 카메라
  • AudioStream: 오디오 스트림, VideoStream동일한 방식으로 생성됨

  • WidgetStream: 를 WidgetStream(widget=target)지정 하면 모든 인스턴스의 출력을 미디어 스트림으로 생성 widget할 수 있습니다 .ipywidget

이 미디어 스트림은 모두 MediaStream클래스 에서 상속됩니다.

스트리밍 미디어 구성 요소 외에도 프런트 엔드 Javascript에서 얻은 스트림을 기록하고 Python 커널로 보내는 데 사용되는 레코더 구성 요소도 있으며 예제에서 자세히 소개 ImageRecorder했으며 VideoRecorder사용법 유사하므로 공식 문서를 참조하십시오 .
마지막으로 에 컴포넌트가 있습니다 ipywebrtc.webrtc.테스트 후에도 여전히 버그가 있습니다. 채팅 비디오 대화방을 참조할 수 있습니다 .


ipyvolumn앞으로 더 많은 콘텐츠(예: 시리즈)가 업데이트될 예정입니다.
원래 CSDN에 게시되었으므로 재인쇄할 출처를 명시하십시오: https://qxsoftware.blog.csdn.net/article/details/89513815 . 질문이나 아이디어가 있으면 아래에 의견을 남겨주세요~~

추천

출처blog.csdn.net/liuqixuan1994/article/details/89513815