aptpod Tech Blog

株式会社アプトポッドのテクノロジーブログです

Intel® Deep Learning Streamerで映像推論やってみた

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で使用することができます。

DL Streamer ソフトウェアスタック

アプリケーションとしては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を利用して、車を検知できました!

vehicle-detection-0200で車を検知(動画素材

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

上記を適用して実行します。

ROIフィルターで一定サイズ以上の検知結果を削除(動画素材

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イメージでインストールする方法が無かったと思うのですが、最近サポートされたようです。