Hello World

DepthAI Python APIを使用してカラービデオストリームを表示する方法を学びましょう。

デモ動画

YouTubeへのリンク

依存関係

まずは開発環境を整えましょう。このチュートリアルでは以下を用いています。

  • Python 3.6以上
  • DepthAI Python API
  • cv2blobconverternumpy Pythonモジュール

コードの概要

Depthai Pythonモジュールによって、4K 60Hzカラーカメラへアクセスでき、このカメラからのビデオストリームをデスクトップに表示します。このチュートリアルの完全なソースコードはGitHubにあります。

ファイルのセットアップ

以下のファイル構造をコンピューターにセットアップします:

cd ~
mkdir -p depthai-tutorials-practice/1-hello-world
touch depthai-tutorials-practice/1-hello-world/hello_world.py
cd depthai-tutorials-practice/1-hello-world

※親ディレクトリ名の接尾辞-practiceについて

チュートリアルはGitHubのdepthai-tutorialsリポジトリで公開されています。あなたの作業と私たちの完成したチュートリアルを区別できるように-practiceを付けています(ダウンロードすることを選択した場合)。

pipの依存関係をインストールする

DepthAIのカラービデオストリームを表示するには、いくつかのパッケージをインポートする必要があります。 このチュートリアルに必要なものをダウンロードしてインストールします:

python3 -m pip install numpy opencv-python depthai blobconverter --user

環境をテストする

全ての依存関係をロードできることを確認しましょう。先ほど作成したhello_world.pyファイルをコードエディタで開きます。以下をコピーしてhello_world.pyに貼り付けます:

import numpy as np # numpy - depthaiが返すパケットデータを操作する
import cv2 # opencv - ビデオストリームを表示する
import depthai # depthai - カメラとそのデータパケットにアクセスする
import blobconverter # blobconverter - MyriadXニューラルネットワークのブロブをコンパイルしてダウンロードする

スクリプトを実行してみて、以下のように、エラーなしで実行されることを確認してください:

python3 hello_world.py

もし、以下のエラーが表示されたら、トラブルシューティングセクションの手順に従ってください。

ModuleNotFoundError: No module named 'depthai'

パイプラインの定義

DepthAIからのアクションは、ニューラルな推論であれ、カラーカメラの出力であれ、DepthAIのニーズに対応するノードと接続を含むパイプラインを定義する必要があります。 このケースでは、カラーカメラからのフレームと、その上で実行される単純なニューラルネットワークについて見てみましょう。

まずは空のPipelineオブジェクトから始めます。

pipeline = depthai.Pipeline()

さて、最初に追加するノードはColorCameraです。mobilenet-ssdの入力サイズ(後で定義します)に合うように300x300に再調整されたpreview出力を使用します。

cam_rgb = pipeline.create(depthai.node.ColorCamera)
cam_rgb.setPreviewSize(300, 300)
cam_rgb.setInterleaved(False)

次に、MobileNetDetectionNetworkノードをmobilenet-ssdネットワークで定義します。 blobファイルは、blobconverterツールを使用して自動的にコンパイルされ、ダウンロードされます。blobconverter.from_zoo()関数はモデルへのパスを返すので、detection_nn.setBlobPath()関数内に直接置くことができます。このノードでは、NNからの出力がデバイス側で解析され、すぐに使える検出オブジェクトを受け取ることができます。これが正しく動作するためには、不正な結果をフィルタリングするために信頼度のしきい値を設定する必要もあります。

detection_nn = pipeline.create(depthai.node.MobileNetDetectionNetwork)
# ブロブ(NNモデル)のパスを設定し、blobconverterを使ってモデルを変換&ダウンロードする
# detection_nn.setBlobPath("/path/to/model.blob")
detection_nn.setBlobPath(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6))
detection_nn.setConfidenceThreshold(0.5)

次に、カラーカメラのプレビュー出力をニューラルネットワークの入力に接続します。

cam_rgb.preview.link(detection_nn.input)

最後に、カラーカメラのフレームとニューラルネットワークの推論結果の両方を受け取ります。これらはデバイス上で生成されるため、私たちのマシン(ホスト)に転送する必要があります。デバイスとホストの間の通信はXLinkによって処理されます。今回のケースでは、デバイスからホストへデータを受け取りたいので、XLinkOutノードを使います。

xout_rgb = pipeline.create(depthai.node.XLinkOut)
xout_rgb.setStreamName("rgb")
cam_rgb.preview.link(xout_rgb.input)

xout_nn = pipeline.create(depthai.node.XLinkOut)
xout_nn.setStreamName("nn")
検出_nn.out.link(xout_nn.input)

DepthAIデバイスを初期化する

パイプラインが定義されたので、パイプラインでデバイスを初期化し、起動します。

with depthai.Device(pipeline) as device:

この時点から、パイプラインはデバイス上で実行され、要求した結果を生成します。結果を取得してみましょう。

注意:デフォルトでは、DepthAIはUSB3デバイスとしてアクセスされます。これにはいくつかの制限があります。 USB2で通信したい場合は、以下のコードでDepthAIを初期化してください。

device = depthai.Device(pipeline, usb2Mode=True)

ヘルパーの追加

 XLinkOutノードがパイプラインで定義されたので、ホスト側の出力キューを定義して、生成された結果にアクセスします。

q_rgb = device.getOutputQueue("rgb")
q_nn = device.getOutputQueue("nn")

これらは結果でいっぱいになるので、次に、結果を処理しましょう。rgbフレーム用とnn結果用の2つのプレースホルダーが必要です。

frame = None
detections = []

また、ニューラルネットワークの実装の関係上、推論結果のバウンディングボックスの座標は<0..1>の範囲の浮動小数点数として表現されます。そのため、フレームの幅と高さに対して相対的になります(例えば、画像の幅が200pxで、nnが0.2に等しいx_min座標を返した場合、これは実際の(正規化された)x_min座標が40pxであることを意味します)。 そのため、これらの<0..1>値を実際のピクセル位置に変換するヘルパー関数 frameNorm を定義する必要があります。

def frameNorm(frame, bbox):
    normVals = np.full(len(bbox), frame.shape[0])
    normVals[::2] = frame.shape[1]
    return (np.clip(np.array(bbox), 0, 1) * normVals).astype(int)

結果を処理する

すべての準備が整ったので、メイン・プログラムのループを開始する準備ができました。

while True:
  # ...

このループの中で、最初に行うことはnnノードとカラーカメラの両方から最新の結果を取得することです。

in_rgb = q_rgb.tryGet()
in_nn = q_nn.tryGet()

tryGetメソッドは最新の結果を返すか、キューが空の場合はNoneを返します。

rgbカメラからの結果もニューラルネットワークからの結果も、1次元配列として配信されるため、表示するためにはどちらも変換が必要になります(必要な変換の1つである frameNorm 関数はすでに定義済みです)。

まず最初に、 getCvFrame コマンドを用いてrgbカメラからフレームを受け取ったとします。

if in_rgb is not None:
    frame = in_rgb.getCvFrame()

次に、ニューラルネットワークの結果を受け取ります。デフォルトのMobileNetSSDの結果には7つのフィールドがあり、それぞれ image_id、label、confidence、x_min、y_min、x_max、y_max です。 detections 配列にアクセスすることで、それらのフィールドにアクセスできる検出オブジェクトを受け取ります。

if in_nn is not None:
    detections = in_nn.detections

結果を表示する

ここまでで、DepthAIデバイスからすべての結果が取得されたので、あとは実際に結果を表示するだけです。

if frame is not None:
    for detection in detections:
        bbox = frameNorm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax))
        cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (255, 0, 0), 2)
    cv2.imshow("preview", frame)

ここでは、バウンディングボックスの座標を正規化するために、先ほど定義した  frameNorm の使い方が示されています。 cv2.rectangle を用いて、顔の位置を示す四角形をrgbフレーム上に描画し、 cv2.imshow を用いてそのフレームを表示します。

最後に、(無限ループ内で動作している)プログラムを終了させる方法を追加します。ここでは、ユーザが q キーを押したときにループから抜け出すようにします。

if cv2.waitKey(1) == ord('q'):
    break

デモの実行

このチュートリアルで用意したファイルを実行し、結果を見るだけです。

python3 hello_world.py

これで完了です!このチュートリアルの完全なコードはGitHubにあります。

質問がありますか? 技術サポートやその他の質問については、ディスカッションフォーラムへどうぞ。


出典 : Luxonisの資料 - Hello World

https://docs.luxonis.com/projects/api/en/latest/tutorials/hello_world/

*このガイドはLuxonis社の許可を得て、スイッチサイエンスが翻訳しています。


◀︎一覧に戻る