Hello World
Hello World
DepthAI Python APIを使用してカラービデオストリームを表示する方法を学びましょう。
デモ動画
依存関係
まずは開発環境を整えましょう。このチュートリアルでは以下を用いています。
- Python 3.6以上
- DepthAI Python API
cv2
、blobconverter
、numpy
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社の許可を得て、スイッチサイエンスが翻訳しています。