見出し画像

DepthAI 入門 (2) - HelloWorld

「DepthAI API」で、はじめてのプログラムを作成する手順をまとめました。

前回

1. HelloWorld

今回は、はじめてのプログラムとして、カラー映像と物体検出のバウンディングボックスを表示するプログラムを作成します。

実行画面とコードは、次のとおりです。

画像2

・helloworld.py

from pathlib import Path
import blobconverter
import cv2
import depthai
import numpy as np

# 空のパイプラインの準備
pipeline = depthai.Pipeline()

# ColorCameraノードの生成
cam_rgb = pipeline.createColorCamera()
cam_rgb.setPreviewSize(300, 300)
cam_rgb.setInterleaved(False)

# MobileNetDetectionNetworkノードの準備
detection_nn = pipeline.createMobileNetDetectionNetwork()
detection_nn.setBlobPath(str(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6)))
detection_nn.setConfidenceThreshold(0.5)
cam_rgb.preview.link(detection_nn.input) # ColorCamera出力をMobileNetDetectionNetwork入力に接続

# ColorCameraのフレームをホストに転送するXLinkOutの準備
xout_rgb = pipeline.createXLinkOut()
xout_rgb.setStreamName("rgb")
cam_rgb.preview.link(xout_rgb.input) # ColorCamera出力をXLink入力に接続

# MobileNetDetectionNetworkの推論結果をホストに転送するXLinkOutの準備
xout_nn = pipeline.createXLinkOut()
xout_nn.setStreamName("nn")
detection_nn.out.link(xout_nn.input) # MobileNetDetectionNetwork出力をXLink入力に接続

# DepthAIデバイスでパイプラインを実行
with depthai.Device(pipeline) as device:
    # ホスト側の出力キューの準備
    q_rgb = device.getOutputQueue("rgb")
    q_nn = device.getOutputQueue("nn")

    # 出力を格納する変数
    frame = None # フレーム
    detections = [] # 推論結果

    # 推論結果のバウンディングボックスをピクセルサイズに変換
    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:
        # 出力キューからの最新の出力の取得
        in_rgb = q_rgb.tryGet()
        in_nn = q_nn.tryGet()
        if in_rgb is not None:
            frame = in_rgb.getCvFrame() # フレーム
        if in_nn is not None:
            detections = in_nn.detections # 推論結果

        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)

        # qキーでプログラム終了
        if cv2.waitKey(1) == ord('q'):
            break

2. 基本用語

はじめに、DepthAIで使う基本用語を紹介します。

◎ ホスト側
DepthAIデバイスが接続されているPCやRasPiを「ホスト側」と呼びます。

◎ デバイス側

DepthAIデバイス自身を「デバイス側」と呼びます。

◎ パイプライン

パイプラインはデバイス側の完全なワークフローで、ノード間接続で構成されます。

◎ ノード

DepthAIの単一の機能を「ノード」と呼びます。ノードは、入力と出力とプロパティを持ちます。

◎ コネクション
ノードの出力と別のノードの入力の間のリンクのことを「コネクション」と呼びます。

◎ XLink

デバイスとホストの間でデータ交換を行うミドルウェアです。

3. ソースコードの解説

◎ パッケージのインポート
はじめに、パッケージのインポートを行います。

from pathlib import Path
import blobconverter
import cv2
import depthai
import numpy as np


◎ パイプラインの定義
「ニューラル推論」や「カメラ出力」など、DepthAIからのアクションを処理するには、ニーズに対応するノード接続を含む「パイプライン」を定義する必要があります。

(1) 空のパイプラインの準備
空の「パイプライン」を準備します。

# 空のパイプラインの準備
pipeline = depthai.Pipeline()

(2) ColorCameraノードの準備
最初に準備するノードは「ColorCamera」です。 mobilenet-ssdの入力サイズに合わせて300x300に変更したのプレビュー出力を使用します

# ColorCameraノードの生成
cam_rgb = pipeline.createColorCamera()
cam_rgb.setPreviewSize(300, 300)
cam_rgb.setInterleaved(False)

(3) MobileNetDetectionNetworkノードの準備
次に、MobileNetDetectionNetworkノードを準備します。これは、mobilenet-ssdネットワークを使用したニューラルネットワークのノードです。

# MobileNetDetectionNetworkノードの準備
detection_nn = pipeline.createMobileNetDetectionNetwork()
detection_nn.setBlobPath(str(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6)))
detection_nn.setConfidenceThreshold(0.5)

そして、ColorCameraノードの出力をMobileNetDetectionNetworkノードの入力に接続します。

cam_rgb.preview.link(detection_nn.input) # ColorCamera出力をMobileNetDetectionNetwork入力に接続

(4) ColorCameraのフレームとMobileNetDetectionNetworkの推論結果をホストに転送するXLinkOutの準備
今回は、「カメラ映像のフレーム」と「ニューラルネットワークの推論結果」をホスト側に転送します。ホスト側に出力を転送するには、XLinkOutノードを使用します。

# ColorCameraのフレームをホストに転送するXLinkOutの準備
xout_rgb = pipeline.createXLinkOut()
xout_rgb.setStreamName("rgb")
cam_rgb.preview.link(xout_rgb.input) # ColorCamera出力をXLink入力に接続

# MobileNetDetectionNetworkの推論結果をホストに転送するXLinkOutの準備
xout_nn = pipeline.createXLinkOut()
xout_nn.setStreamName("nn")
detection_nn.out.link(xout_nn.input) # MobileNetDetectionNetwork出力をXLink入力に接続


◎ デバイス側でのパイプライン実行とホスト側での出力取得の準備

デバイス側でパイプラインを実行し、ホスト側で出力取得の準備を行います。

(1) DepthAIデバイスでパイプラインを実行
パイプラインを定義したら、DepthAIデバイスでパイプラインを実行します。

# DepthAIデバイスでパイプラインを実行
with depthai.Device(pipeline) as device:
デフォルトでは、DepthAIデバイスにはUSB3デバイスとしてアクセスします。USB2デバイスとしてアクセスしたい場合は、depthai.Device(pipeline, True) のように第2引数を指定してください。

(2) ホスト側の出力キューの準備
XLinkOutノードからの出力を取得するための、ホスト側に出力キューを作成します。

# ホスト側の出力キューの準備
q_rgb = device.getOutputQueue("rgb")
q_nn = device.getOutputQueue("nn")

(3) 出力を格納する変数の準備
出力を格納する変数を準備します。

# 出力を格納する変数の準備
frame = None # フレーム
detections = [] # 推論結果

(4) 推論結果をピクセルサイズに変換する関数の準備
推論結果のバウンディングボックスは、0〜1の範囲の浮動小数です。つまり、フレームの幅/高さを基準にしています。これを、ピクセルサイズに変換します。

# 推論結果(0〜1)をバウンディングボックス(ピクセル)に変換
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)


◎ ホスト側でのメインループの実行

ホスト側のメインループを実行し、出力取得と画面表示を繰り返します。

(1) メインループの開始
全ての準備が完了したら、メインループを開始します。

# メインループループの開始
while True:
        :

(2) 出力キューからの最新の出力の取得
出力キューからの最新の出力を取得します。出力がない場合は、Noneが返ります。

# 出力キューからの最新の出力の取得
in_rgb = q_rgb.tryGet()
in_nn = q_nn.tryGet()
if in_rgb is not None:
    frame = in_rgb.getCvFrame() # フレーム
if in_nn is not None:
    detections = in_nn.detections # 推論結果

(3) 推論結果をフレームに描画した後、フレームを画面表示
推論結果のバウンディングボックスをフレームに描画した後、フレームを画面表示します。

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)

(4) qキーでプログラム終了
最後に、qキーでプログラム終了するコードを追加します。

# qキーでプログラム終了
if cv2.waitKey(1) == ord('q'):
    break

4. 参考

次回



この記事が気に入ったらサポートをしてみませんか?