Jetson NanoでYOLOをPythonからリアルタイム表示する方法(Docker+TensorRT+USBカメラ)

Jetson NanoでYOLOをPythonからリアルタイム表示する方法(Docker+TensorRT+USBカメラ)

Jetson NanoでYOLOのリアルタイム検出をやろうとすると、次の壁に当たりがちです。

  • Jetson本体のUbuntu(ホスト)にPythonスクリプトを置いたけど、ホストのPython環境では動かない
  • YOLO/TensorRTが動くのはDocker内なのに、どうやってPythonを編集しながら実行するの?
  • cv2.imshow() が出ない(GUIがない)問題で止まる

この記事では、Jetson上でコマンド1発で起動して、映像(bbox付き)を表示しながらPythonを修正→再実行できる開発ループを作ります。

ゴールはこれです:

  • ~/yolo_dev/run.sh を叩くだけで起動できる
  • Jetsonホスト上の ~/yolo_dev にPythonコードを置く
  • 実行はDocker内Pythonで行う(YOLO/TensorRT環境をそのまま利用)
  • USBカメラの映像にbboxを描画して、Jetsonの画面にリアルタイム表示できる

環境構築の記事と、yolo特有のコマンドだけで動かすリアルタイム処理の実行の記事は以下を参照してください。

前提(重要):なぜ「Jetsonホストでpython実行」じゃなく「Docker内python実行」なのか

Jetson NanoはJetPackの制約が強く、PyTorch/TensorRT/OpenCVなどの組み合わせが崩れやすいです。
そのため「動く環境」をDockerに閉じ込めるのが現実的です。

ただし、Pythonを開発するには毎回Dockerに入って編集するのは面倒。
そこで、

  • コードはホストに置く
  • Dockerからそのフォルダをマウントして実行する

という形にします。これが一番ストレスがありません。

全体像(開発ループ)

  1. Jetsonホストで ~/yolo_dev にコードを置く
  2. run.shdocker run ... python3 cam_predict_opencv.py を起動
  3. Jetsonの画面にリアルタイム表示される
  4. コード修正 → run.sh 再実行

1. 作業フォルダを作る(ホスト側)

mkdir -p ~/yolo_dev
mkdir -p ~/yolo_out

2. TensorRT engine(.engine)を作業フォルダへ置く(ホスト側)

今回は手元にある yolo11n.engine を使います(すでに作成済みの前提)。

cp /home/ai/jetson_yolo_artifacts/yolo11n.engine ~/yolo_dev/yolo11n.engine
ls -lh ~/yolo_dev/yolo11n.engine

ポイント:Dockerから見える場所(マウントする場所)にモデルファイルを置くこと。
ホストにファイルがあっても、Dockerにマウントしない限りDockerからは見えません。

3. リアルタイム表示するPython(OpenCV+Ultralytics)を作る

~/yolo_dev/cam_predict_opencv.py を作ります。
nano がない環境でもOKなように cat で作成します)

cat > ~/yolo_dev/cam_predict_opencv.py <<'EOF'
import os
import time
import cv2
import numpy as np

# TensorRTがnp.bool参照で落ちる環境の回避
if not hasattr(np, "bool"):
    np.bool = bool

from ultralytics import YOLO

def open_cam(dev="/dev/video0", w=640, h=480, fps=30):
    cap = cv2.VideoCapture(dev, cv2.CAP_V4L2)
    if not cap.isOpened():
        raise RuntimeError(f"Camera open failed: {dev}")
    cap.set(cv2.CAP_PROP_FRAME_WIDTH,  w)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
    cap.set(cv2.CAP_PROP_FPS,          fps)
    return cap

def main():
    model_path = os.getenv("MODEL", "yolo11n.engine")
    imgsz = int(os.getenv("IMGSZ", "320"))
    conf  = float(os.getenv("CONF", "0.25"))
    show  = (os.getenv("SHOW", "1") == "1")  # デフォルト表示ON

    model = YOLO(model_path)
    cap = open_cam()

    t0 = time.time()
    frames = 0

    try:
        while True:
            ok, frame = cap.read()
            if not ok:
                continue

            results = model.predict(
                source=frame,
                imgsz=imgsz,
                conf=conf,
                device=0,
                half=True,
                verbose=False,
            )
            annotated = results[0].plot()

            if show:
                cv2.imshow("YOLO Live (press q to quit)", annotated)
                if cv2.waitKey(1) & 0xFF == ord("q"):
                    break

            frames += 1
            if frames % 30 == 0:
                dt = time.time() - t0
                print(f"FPS ~ {frames/dt:.2f}")

    except KeyboardInterrupt:
        print("Interrupted (Ctrl+C)")
    finally:
        cap.release()
        if show:
            cv2.destroyAllWindows()

if __name__ == "__main__":
    main()
EOF

このコードのポイント

  • model = YOLO("yolo11n.engine") で TensorRT engine を使う(速い)
  • cv2.imshow() で bbox付き映像をリアルタイム表示
  • np.bool 問題(TensorRT×NumPyの相性)を回避

4. Jetsonでコマンド1発起動できる run.sh を作る(重要)

毎回長い docker run ... を打ちたくないので、起動用のシェルを作ります。
これがあると開発体験が一気に良くなります。

cat > ~/yolo_dev/run.sh <<'EOF'
#!/usr/bin/env bash
set -e

# Jetson本体の画面に出す(モニタ直結想定)
export DISPLAY=:0
xhost +local:root >/dev/null 2>&1 || true

sudo docker run -it --rm \
  --runtime nvidia \
  --network host \
  --device /dev/video0:/dev/video0 \
  -e DISPLAY=:0 \
  -e SHOW=1 \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -v "$HOME/yolo_dev:/work" -w /work \
  ultralytics/ultralytics:jetpack4-gui \
  env MODEL=yolo11n.engine IMGSZ=320 CONF=0.25 \
  python3 cam_predict_opencv.py
EOF

chmod +x ~/yolo_dev/run.sh

ultralytics/ultralytics:jetpack4-guiGUI対応のOpenCV入りイメージです。
もしあなたの環境でタグ名が違う場合は、ここだけ置き換えてください。

5. 起動する(ホスト側でこれだけ)

~/yolo_dev/run.sh
  • Jetsonの画面に bbox付きの映像が表示されます
  • 終了は q または Ctrl+C

6. 開発のやり方(Pythonをいじってすぐ試す)

開発ループはこれだけです。

  1. ~/yolo_dev/cam_predict_opencv.py を修正
  2. ~/yolo_dev/run.sh を実行
  3. 表示を見ながら調整
  4. また修正 → 実行

Docker内に入って編集する必要はありません。
ホストで編集 → Dockerで実行が最強です。

よくある詰まりポイント

1) FileNotFoundError: 'xxx.engine' does not exist

モデルファイルが /work(= ~/yolo_dev)に無いと起きます。
engineを ~/yolo_dev に置く(マウント対象に置く)が正解。

2) cv2.imshow() が出ない / destroyAllWindows() で落ちる

OpenCVがGUI無し(headless)だと起きます。
GUI対応イメージ(jetpack4-gui) を使うのが正解。

3) np.bool エラーで落ちる(TensorRT絡み)

環境によって tensorrtnp.bool を参照して落ちます。
→ スクリプト先頭の回避コード(np.bool = bool)で通ることが多いです。

YOLO12にするには?

この記事は動作確認済みの yolo11n.engine で説明しました。
YOLO12にしたい場合は、

  • yolo12n.engine を用意して ~/yolo_dev に置く
  • run.shMODEL=yolo11n.engineMODEL=yolo12n.engine に変える

これだけです。Python側はそのまま使えます。

まとめ

run.sh 化すれば、開発が爆速になる

  • コードはホストに置く
  • 実行はDocker内で行う
  • X11を渡してJetson画面にリアルタイム表示する
  • run.sh 化すれば、開発が爆速になる

TensorRTで動かす一連の流れは次の記事で紹介します。

それではまた。

About The Author

Hideki
東京大学発AIスタートアップ企業でロボット開発室室長、画像解析室室長、動画解析室室長を務め、AIエンジニアとしても画像認識関連の特許を在籍中に3つ取得。その後、KDDIグループ内でプロダクトリーダーとして自然言語処理パッケージの自社開発を経て、現在はAGRISTのテックリードとして農業の人手不足の解決に向けた収穫ロボットの開発にチャレンジしている。ロボットは技術の総合格闘技との考え方から、AIだけでなく、ハードやエレキ、通信からクラウド、IOTまで幅広く手掛けることができる。最近では人とロボットの共存を目指すべく、性能だけを追い求める開発から「感動やワクワク体験」をデザインできるロボットの研究を進めており、人とロボットがうまく共存できる世界を作り出したいと日々行動している。

LEAVE A REPLY

*
*
* (公開されません)