Jupyter リモート サーバーはローカル カメラと WebRTC を使用してチャット ルームとリアルタイムのビデオ処理を実現します

Jupyter リモート使用カメラ、WebRTC チャット ルーム、リアルタイムビデオ処理

序文

ipywebrtcコンポーネントを使用してローカル ビデオ ストリームを取得し、リモート Jupyter サーバーに送信します。サーバーがビデオを処理した後、ビデオはローカルに送り返され、最終的にコンポーネントによって表示されますipywidgets.Image

効果体験

Chromeブラウザの使用を推奨します

結果を示す
公式の例に移動し、カメラが動作しているのを確認できるようにします。
デモ コードをより深く体験したい場合は、Binderに移動して任意のファイルを開いて.ipynb、段階的に実行できます。


準備

最初にコンポーネントをインストールする必要がありますipywebrtc。方法は 2 つあります。簡単な方法はpip直接インストールすることです (jupyter バージョン 5.3 以降が必要です):

pip install ipywebrtc

2 つ目は、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

何も事故がなければ、Chrome ブラウザは Web ページでのカメラの使用を許可するかどうかを尋ねるウィンドウを表示し、許可を選択すると、出力領域にカメラでキャプチャされたビデオが表示されます。

Chrome でプロンプトがポップアップ表示されずに表示される場合はError creating view for media stream: Only secure origins are allowed、ブラウザが現在の Web サイトが安全ではない (接続が使用されていない) と判断しているためhttps、カメラが無効になっていることを意味します。最も簡単な解決策は、Chrome ショートカットの「ターゲット」列の最後に追加して--unsafely-treat-insecure-origin-as-secure="http://host_ip:port"再起動することです (host_ip:port独自のサーバー アドレスに変更します)。

ただし、現時点では、ビデオはローカルでのみ表示され、Python カーネルが配置されているサーバー (リモート サーバーを使用していると仮定) にはアップロードされないため、Python コンテキストでビデオ コンテンツを取得する方法はありません。
次に、ImageRecorderストリームを記録し、画像としてサーバー上の Python カーネルに送信するためのストリームを作成する必要があります。

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

このコードを実行すると、コンポーネントが表示されますImageRecorder。コンポーネント上のカメラ アイコンをクリックしてstream画面をキャプチャします。
イメージレコーダー
その後、Python で画像にアクセスして形式image_recorder.image.valueに変換することで、Pillow画像を取得できます。

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

ビデオを処理する

ここまでは画像の取得、加工、表示方法のみを紹介しましたが、どれも公式ドキュメントで簡単に学ぶことができます。では、ビデオの各フレームを継続的にキャプチャし、処理して 1 つずつ表示するにはどうすればよいでしょうか? 以下に私がまとめたImageRecorder継続的なクローリングの方法を紹介します。

ImageRecorder代わりに連続キャプチャが依然として使用されている理由は、VideoRecorderキャプチャVideoRecorderされたビデオには開始と終了が必要であり、終了後にのみキャプチャされたビデオ クリップ全体が処理され、「リアルタイム」要件を満たさないためです。

著者のコードを分析したところ、や のような関数は存在せず、フロントエンドが画像の次のフレームを取得しrecorder.record()た後、属性を に設定するようにPython カーネルに通知し、画像を取得した後に属性を設定することがわかりました。に自動的に変わりますしたがって、毎回前のフレームの写真を処理した後、次のフレームを取得するように自動的に設定されるループ メカニズムを試してみたいと思います。ただし、実験した結果、ループやループを使用しても機能しません。これはおそらく、Jupyter のフロントエンドが Javascript によってレンダリングされているためです。フロントエンドに通知せずにバックエンドの Python 環境で属性を変更するだけでは、クロールを続行できません。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利用可能なストリーミング メディアは次のとおりです。

  • VideoStream:VideoStream.from_file(path)ローカルビデオを取得することも、VideoStream.from_url(url)ネットワークビデオを取得することもできます

  • CameraStream: ローカル カメラ デバイスまたは Web カメラ (Web カメラ) を通じてメディア ストリームを取得します。作成方法は 2 つあります。

    • 最初:
       	camera = CameraStream(constraints=
       	                      {
          
          'facing_mode': 'user',	# 'user表示前置摄像头,'environment'表示后置摄像头
       	                       'audio': False,	# 是否同时获取音频(需要硬件支持)
       	                       'video': {
          
           'width': 640, 'height': 480 }	# 获取视频的宽高
       	                       })
    
    • 2 番目のタイプ:
      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を参照してください最後に、にコンポーネントがあります。テスト後も、まだいくつかのバグがあります。Chatビデオ チャット ルームを参照してください。
ipywebrtc.webrtc


ipyvolumn今後、さらに多くのコンテンツ(シリーズなど)が更新される予定です。
元は CSDN で公開されたものです。転載する場合は出典を明記してください: https://qxsoftware.blog.csdn.net/article/details/89513815ご質問やアイデアがございましたら、以下にコメントを残してください~~

おすすめ

転載: blog.csdn.net/liuqixuan1994/article/details/89513815