aptpod Advent Calendar 2024 12月19日の記事を担当します、intdashグループの野本です。
普段からエッジデバイスでのコンテナ化やAIモデルの利用に携わっており、その調査を兼ねてIntel® Deep Learning Streamer(以下、DL Streamer)を試してみました。 特に、最近Dockerでのインストールがサポートされたとのことで、手軽に始められるようになった点にも注目しています。*1
本記事では、このDL Streamerを使った映像推論の手順や実践例をご紹介します。
Intel® Deep Learning Streamerとは
Intel® Deep Learning Streamerは、GStreamerをベースとしたオープンソースのストリーミングメディア分析フレームワークで、ディープラーニング(深層学習)アプリケーションの開発、デプロイ、および最適化を容易にするためのフレームワークです。基本的には、IntelのCPU、GPU、NPUで使用することができます。
アプリケーションとしてはGstreamerのプラグインで提供されており、内部ではVA-API、oneAPI、OpenVINO、OpenCVなどの依存ライブラリなどが使用されています。
DL Streamerを使ってみる
今回は映像推論の中でも代表的な物体検知を試します。
HDMI-USBキャプチャーから映像を入力し、車検知モデルを使用したgstreamerパイプラインを動作させ、検知結果の重畳映像をUDPで出力します。 また、検知結果の後処理として、フィルター処理をPythonスクリプトで実装します(詳細は後述します)。
ホストマシン構成
- CPU: Intel(R) Core(TM) i7-10510U
- GPU: Intel UHD Graphics (iGPU)
- OS: Ubuntu 22.04
※ 以下の手順は、2024/12 時点の情報となります。最新の情報については公式ドキュメントを参照ください。
事前準備
ホストに、あらかじめ前提条件のドライバをインストールします。
スクリプトをダウンロード
mkdir -p ~/intel/dlstreamer_gst cd ~/intel/dlstreamer_gst/ wget https://github.com/dlstreamer/dlstreamer/raw/master/scripts/DLS_install_prerequisites.sh
実行権限をつけて実行
sudo chmod +x DLS_install_prerequisites.sh ./DLS_install_prerequisites.sh
インストール完了後、ディレクトリを削除
rm -rf ~/intel/dlstreamer_gst
インストール
DL Streamerは、aptリポジトリからインストールする方法と、Dockerイメージでインストールする方法があります。 今回はDockerイメージでインストールします。
Ubuntuのバージョンによって使用するイメージが異なります。今回は Ubuntu 22.04ですので、22.04向けのイメージを選択します。
docker pull intel/dlstreamer:2024.1.2-ubuntu22
コンテナ内で、DL Streamerのgstreamerのエレメントが認識されていれば、インストール完了です。
docker run -it --rm intel/dlstreamer:2024.1.2-ubuntu22
$ gst-inspect-1.0 gvadetect ... Factory Details: Rank none (0) Long-name Object detection (generates GstVideoRegionOfInterestMeta) Klass Video Description Performs object detection using SSD-like (including MobileNet-V1/V2 and ResNet), YoloV2/YoloV3/YoloV2-tiny/YoloV3-tiny and FasterRCNN-like object detection models. Author Intel Corporation ...
モデルのダウンロード
推論に使用するモデルを、ホストにダウンロードします。取得したモデルは後でコンテナにマウントして使用します。
ホストで、ツールをインストール
sudo apt-get install python3-pip python3 -m pip install openvino-dev[onnx,tensorflow,pytorch]
DL Streamerリポジトリをクローン
mkdir -p ~/intel git clone --recursive https://github.com/dlstreamer/dlstreamer.git ~/intel/dlstreamer_gst
モデルの格納場所を環境変数に設定
export MODELS_PATH=/home/${USER}/models
モデルのダウンロード ※ 時間がかかります
cd ~/intel/dlstreamer_gst/samples
./download_omz_models.sh
上記はsamples/models_omz_samples.lstに掲載されているモデルしかダウンロードしないため、これら以外のモデルを利用したい場合は個別でダウンロードする必要があります。
例: vehicle-detection-0200 (FP16-INT8)
omz_downloader --name vehicle-detection-0200 --precisions FP16-INT8 -o $MODELS_PATH
利用可能なモデルの一覧は以下を参照してください。
参考: Supported Models — Intel® Deep Learning Streamer (Intel® DL Streamer) documentation
コンテナの起動
ダウンロードしたモデルをマウントして、コンテナを起動します。今回は簡易検証のため、特権/rootかつホストのネットワーク設定で起動します。
docker run -it --rm --net host --user 0:0 --privileged \ -v /dev:/dev \ -v ${MODELS_PATH}:/home/dlstreamer/models \ --env MODELS_PATH=/home/dlstreamer/models \ intel/dlstreamer:2024.1.2-ubuntu22
物体検知の実行
準備ができたので物体検知を実行します。 今回は、vehicle-detection-0200モデルを利用して、車を検知します。
物体検知は gvadetect
エレメントで行い、model
およびmodel_proc
プロパティでモデルを指定します。
gvawatermark
で推論結果を映像に重畳します。gvafpscounter
は、標準出力にFPS情報を表示します。
例:
- カメラ映像入力(MJPEG 1280x720 30fps)
- モデル: vehicle-detection-0200 FP16-INT8
- GPU推論
- 推論映像はH.264に変換して127.0.0.1:5000に配信
#!/bin/bash -eu CAMERA_PATH=${CAMERA_PATH:-/dev/video0} CAMERA_WIDTH=${CAMERA_WIDTH:-1280} CAMERA_HEIGHT=${CAMERA_HEIGHT:-720} CAMERA_FPS=${CAMERA_FPS:-30} CAMERA_BITRATE=${CAMERA_BITRATE:-2000} DETECTION_MODEL_NAME=${DETECTION_MODEL_NAME:-vehicle-detection-0200} DETECTION_MODEL=${MODELS_PATH}/intel/${DETECTION_MODEL_NAME}/FP16-INT8/${DETECTION_MODEL_NAME}.xml DETECTION_MODEL_PROC=/opt/intel/dlstreamer/samples/gstreamer/model_proc/intel/${DETECTION_MODEL_NAME}.json INFERENCE_DEVICE=${INFERENCE_DEVICE:-GPU} DETECTION_THRESHOLD=${DETECTION_THRESHOLD:-0.4} OUT_PORT=${OUT_PORT:-5000} gst-launch-1.0 \ v4l2src device=${CAMERA_PATH} ! \ videorate ! \ image/jpeg,width=${CAMERA_WIDTH},height=${CAMERA_HEIGHT},framerate=${CAMERA_FPS}/1 ! \ vaapijpegdec ! \ video/x-raw\(memory:VASurface\),width=${CAMERA_WIDTH},height=${CAMERA_HEIGHT},framerate=${CAMERA_FPS}/1 ! \ queue ! \ gvadetect model=${DETECTION_MODEL} \ model-proc=${DETECTION_MODEL_PROC} \ device=${INFERENCE_DEVICE} \ threshold=${DETECTION_THRESHOLD} \ pre-process-backend=vaapi-surface-sharing ! \ queue ! \ gvawatermark ! \ gvafpscounter ! \ vaapih264enc rate-control=2 bitrate=${CAMERA_BITRATE} max-bframes=0 keyframe-period=${CAMERA_FPS} ! \ video/x-h264,stream-format=byte-stream ! \ queue ! \ h264parse ! \ queue ! \ rtph264pay ! udpsink host=127.0.0.1 port=${OUT_PORT}
以下のコマンドでUDPで送信された映像を表示します。
gst-launch-1.0 -q \ udpsrc \ port=5000 \ caps='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264' ! \ rtph264depay ! \ avdec_h264 ! \ videoconvert \ ! autovideosink
DL Streamerを利用して、車を検知できました!
Pythonで後処理する
以下のような動画では車ではない物体を誤検知してしまっています。
gvapython
エレメントで、推論結果を利用した後処理をPythonで記述可能です。
今回は、各フレームの物体検知結果の矩形領域(関心領域=Region of Interest、ROI)を取得し、一定以上のサイズのROIを削除する処理を追加してみます。
gstreamerパイプラインで、gvadetect
で物体検知した後に、gvapython
エレメントを追加します。
module
プロパティでPythonスクリプトのパスを、kwarg
プロパティで設定ファイルを渡します。
+ PYTHON_SCRIPT_ROI_FILTER=/usr/bin/roi_filter.py + PYTHON_SCRIPT_ROI_FILTER_CONFIG=/etc/roi_filter.ini ...略... gvadetect model=${DETECTION_MODEL} \ model-proc=${DETECTION_MODEL_PROC} \ device=${INFERENCE_DEVICE} \ threshold=${DETECTION_THRESHOLD} \ pre-process-backend=vaapi-surface-sharing ! \ queue ! \ + gvapython module=${PYTHON_SCRIPT_ROI_FILTER} class=ROIFilter function=process_frame kwarg={\"config_file_path\":\"${PYTHON_SCRIPT_ROI_FILTER_CONFIG}\"} ! \ gvawatermark ! \
Pythonスクリプトでは、設定ファイルからROIの設定を読み込み、一定以上のサイズのROIを削除します。
roi_filter.py
from gstgva import VideoFrame import configparser class ROIFilter: def __init__(self, config_file_path): self.config = configparser.ConfigParser() self.config.read(config_file_path, encoding="utf-8") self.roi_max_width = int(self.config["roi"]["max_width"]) self.roi_max_height = int(self.config["roi"]["max_height"]) self.log_interval = int(self.config["log"]["interval"]) self.frame_count = 0 def process_frame(self, frame: VideoFrame) -> bool: roi_to_be_removed = [] for roi in frame.regions(): rect = roi.rect() if rect.w > self.roi_max_width or rect.h > self.roi_max_height: roi_to_be_removed.append(roi) for roi in roi_to_be_removed: rect = roi.rect() if self.frame_count % self.log_interval == 0: print( f"ROI removed: " f"{roi.label()} " f"({rect.x},{rect.y}) {rect.w}x{rect.h}" ) frame.remove_region(roi) self.frame_count += 1 return True
roi_filter.ini
[roi] max_width = 640 max_height = 360 [log] interval = 60
上記を適用して実行します。
Pythonスクリプトで記述した処理が実行され、一定サイズ以上のROIが削除されて正しく車を検知することができました!
その他のできること
DL Streamerには、今回紹介した物体検知の他にも、姿勢推定、セグメンテーションなどにも対応しており、以下のGstreamerエレメントが含まれています。
例えば、gvametapublish
は、推論結果のメタデータをファイル出力することができます。
エレメント名 | 説明 |
---|---|
gvadetect | オブジェクト検出を実行します。 |
gvaclassify | オブジェクトの分類を実行します。 |
gvainference | 任意の推論モデルを実行し、生の結果を出力します(データの解釈やメタデータの生成は行いません)。 |
gvaaudiodetect | オーディオイベント検出を実行します。 |
gvatrack | ビデオフレーム間でオブジェクトを追跡します。 |
gvametaconvert | メタデータ構造をJSONまたは生テキスト形式に変換します。 |
gvametapublish | JSONメタデータを出力します。 |
gvametaaggregate | 複数のパイプラインブランチからの推論結果を集約します。 |
gvapython | 各フレームでユーザー定義のPython関数を実行するコールバックを提供し、メタデータの変換や推論後処理などに使用されます。 |
gvawatermark | メタデータをビデオフレームに重畳し、推論結果を可視化します。 |
gvafpscounter | ビデオストリームのフレーム毎秒(FPS)を測定します。 |
gvaattachroi | ユーザー定義の関心領域(ROI)を追加し、その領域で推論を実行します。 |
python_object_association | ROIに一意のIDを割り当てます。 |
参考: Elements — Intel® Deep Learning Streamer (Intel® DL Streamer) documentation
まとめ
本記事では、Intel® Deep Learning Streamerを使った映像推論の導入から実践までをご紹介しました。手順を追いながら、物体検知や誤検知への対応、Pythonでの後処理といった具体的な例も交えて解説しましたが、いかがでしたでしょうか?
DL Streamerは、Intelのハードウェアを活用した映像処理にとても便利なツールで、柔軟性や拡張性にも優れています。特に、GStreamerエレメントを組み合わせることで、自分のニーズに合ったパイプラインを構築できる点が魅力的です。
また、今回はUbuntu 22.04での確認でしたが、Docker上で動作しますので、弊社がYoctoで作成したLinuxディストリビューションTerminal System OS 2 のDocker環境にもサクッと組み込むことが可能です。
この記事が、DL Streamerを使ってみるきっかけになれば幸いです。少しでも興味を持たれた方は、サンプルも豊富ですので、ぜひ公式ドキュメントなどを参考にして、独自の映像分析パイプラインを作ってみてください!最後まで読んでいただき、ありがとうございました!
*1:2024/5頃にはDockerイメージでインストールする方法が無かったと思うのですが、最近サポートされたようです。