動画で推論を実行する
YOLO26を動画ファイルやライブカメラで実行し、メモリ使用量を一定範囲内に保ちながら、オブジェクトを追跡してそれぞれを一度だけ数え、モデルがフレームレートに追いつけるか確認します。
デプロイされたビジョンシステムの多くは、コンベヤー、ドア、道路に設置されたカメラなどで動画を監視します。動画には、静止画像にはない問題が2つあります。メモリ: 長時間の録画をRAMに保持することはできません。ID: 検出器は同じ人物を60フレームで検出すると、60人として報告します。
このレッスンでは、Predictモードで動画をフレームごとにストリーミングし、オブジェクトトラッキングを追加して各人物を一度だけ数え、独自のカメラループを作成し、モデルが処理に追いつけるかを測定します。
実践的
実践例: 動画ファイルでのPredict#
動画にも画像と同じPredictモードを使用します。この62フレームのクリップには、アトリウムを横切る人々が映っています:
yolo predict model=yolo26n.pt source=https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4video 1/1 (frame 1/62) solutions_ci_demo.mp4: 384x640 22 persons, 27.3ms
...
video 1/1 (frame 62/62) solutions_ci_demo.mp4: 384x640 22 persons, 54.8ms
Results saved to runs/detect/predictframe 1/62: Ultralyticsが動画をデコードし、画像と同じように各フレームを処理します。22 persons: そのフレーム内の検出結果です。同じ歩行者が各フレームで再び数えられます。27.3ms...54.8ms: マシン上で他に何が動作しているかによって、フレームごとの処理時間は変わります。
注釈付き動画はruns/detect/predict/solutions_ci_demo.mp4です。独自のモデルも同じように動作します。yolo26n.ptをruns/detect/pills_v1/weights/best.ptに置き換えてください。
長時間のソースやライブソースをストリーミングする#
検出結果を処理するコードでは、ストリームをループします。各イテレーションで1フレーム分のResultsを生成し、その後破棄します:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
source = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
frames, people = 0, 0
for result in model(source, stream=True, classes=[0], verbose=False): # one Results object per frame
frames += 1
people += len(result.boxes)
print(f"{frames} frames, {people / frames:.1f} people per frame")62 frames, 22.2 people per frame同じループは、Webカメラのインデックス(source=0)やrtsp://camera.local/streamなどのカメラURLを受け付け、ストリームが終了するか停止するまで実行されます。フレームを1つおきに処理するには、vid_stride=2を追加してください。このループを使ったブラウザーUIを作成する場合は、Streamlitライブ推論ガイドでループをアプリに組み込む方法を確認できます。
実践例: 各人物を一度だけ数える#
「1フレームあたり22人」ではなく、知りたいのは「何人が通過したか」です。マルチオブジェクトトラッキングはフレーム間でボックスを関連付け、Trackモードは各オブジェクトにboxes.idのIDを付与します:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
source = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
seen = set()
for result in model.track(source, stream=True, persist=True, classes=[0], tracker="bytetrack.yaml", verbose=False):
if result.boxes.is_track:
seen.update(result.boxes.id.int().tolist())
print(f"{len(seen)} unique people tracked")32 unique people trackedis_trackは、トラックが確定する前のフレームではFalseであり、そのときboxes.idはNoneです。IDを使って数を数えたり、軌跡を記録したり、「このオブジェクトは3秒間ここにいる」といった処理を実装したりできます。

| トラッカー | 速度 | 堅牢性 |
|---|---|---|
bytetrack.yaml | 高速でシンプル | オブジェクトが一時的に見えなくなると、IDを失いやすいです |
botsort.yaml | 低速 | カメラが動いてもIDを維持しやすいです(動き補償を使用します。外観によるReIDはwith_reidでオプトインします) |
trackerを省略すると、Ultralyticsは現在のデフォルトであるtracktrack.yamlを使用します。Trackモードにはocsort.yaml、deepocsort.yaml、fasttrack.yamlも含まれています。トラッカーの選択と調整、さらにトラッカーを使ったオブジェクトカウント、ヒートマップ、速度推定の実装については、ByteTrack、BoT-SORT、TrackTrackでオブジェクトを追跡するで説明しています。
実践例: 独自のカメラループ#
実際のアプリケーションでは、フレームを独自に読み込んで、サイズ変更、クロップ、タイムスタンプ付与、他のコードとのカメラ共有などを行い、各フレームをモデルに渡すことがよくあります。この場合、呼び出し間でトラッカーを維持するのがpersist=Trueです:
import cv2
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
cap = cv2.VideoCapture("solutions_ci_demo.mp4") # saved locally by the commands above; or 0, or an rtsp:// URL
seen = set()
while cap.isOpened():
ok, frame = cap.read()
if not ok:
break
result = model.track(frame, persist=True, classes=[0], tracker="bytetrack.yaml", verbose=False)[0]
if result.boxes.is_track:
seen.update(result.boxes.id.int().tolist())
cap.release()
print(f"{len(seen)} unique people, highest ID {max(seen)}")32 unique people, highest ID 67track.pyと同じ32人です。最大IDは32ではなく67です。トラッカーは、確定されない仮トラックにもIDを割り当てるため、IDには欠番が生じます。
ソースの処理速度に追いつく#
30 FPSのカメラは33ミリ秒ごとにフレームを出力し、実効フレームレートはデコード、推論、書き込みのうち最も遅い処理によって決まります。ノートPCのCPUでは、実行ごとにマシン上で他に何が動作しているかによって、yolo26nの処理時間は384×640フレームあたり26~46ミリ秒でした。予算と同等か超過しており、余裕はありません。処理が追いつかない場合は、次の方法を順番に試してください:
| 調整方法 | 効果 |
|---|---|
小さいモデル(sではなくn) | 多くの場合、2~3倍高速になります |
imgszを小さくする(640ではなく480) | ピクセル数と計算量が減ります。小さいオブジェクトほど先に影響を受けます |
vid_stride=2 | 処理量が半分になります。動きの遅いシーンに適しています |
| GPUまたは最適化されたエクスポート | 最も大きな効果が得られます。NVIDIA上のTensorRTエンジン、またはINT8を使用してください。次のレッスンを参照してください |
複数のカメラを同時に扱う方法と、それに伴うスレッド処理については、マルチストリーム推論で説明しています。
次の間違いに注意する#
症状: 長時間の録画では、プロセスがクラッシュするまでメモリ使用量が増え続けるか、ライブカメラの呼び出しが戻らなくなります。 原因: これを指定しないと、Python の呼び出しは戻る前に各フレームの Results オブジェクトを収集します。 対処: stream=True を渡し、反復処理されるまで何も実行しないジェネレーターをループ処理します。
症状: persist=True を指定せずに cv2_loop.py を実行したところ、カウントが27に減り、最大IDも27になりました。IDがフレームごとにリセットされていたため、「ユニーク」カウントは最も混雑したフレームの数にすぎませんでした。対処: フレームごとに track を1回呼び出す場合は、persist=True を渡してください。
症状: 32人に対してカウントが67になります。原因: 未確定のトラックがあるため、IDに欠番が生じます。対処: track.py の例のように、IDのセットのサイズを数えてください。
デフォルトのトラッカーはリリースによって変わる場合があります。tracker="bytetrack.yaml"(または任意のトラッカー)を渡すと、バージョン間でカウントを比較できます。
解答を表示
import sys
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
seen, times = set(), []
for result in model.track(sys.argv[1], stream=True, persist=True, tracker="bytetrack.yaml", verbose=False):
times.append(result.speed["inference"])
if result.boxes.is_track:
seen.update(result.boxes.id.int().tolist())
print(f"{len(seen)} unique objects, {sum(times) / len(times):.1f} ms inference per frame")python track_any.py your_video.mp4を使って実行してください。
32 unique objects, 30.5 ms inference per frame (26-46 ms across runs on a laptop CPU)
Source is 30 FPS -> 33 ms budget: fits only on a quiet machine, with no headroom
First lever: export to OpenVINO or ONNX for this CPU, then vid_stride=2 if still short