Ultralytics YOLO27: ウェイトリストに登録する。
Get Started
コンピュータービジョンの基礎·タスクを選ぶ·レッスン 5/10
レッスン初級

姿勢推定とOBB

YOLO26のキーポイントと回転ボックスを読み取り、それぞれにルールを適用して、姿勢や角度が本当に重要な手掛かりとなる状況を見分けます。

介護施設では人が転倒したかどうかを把握する必要があり、港ではドローン画像で隣り合って密集する船を数える必要があります。通常のボックスでは、どちらの問題も解決できません。人物が直立しているかどうかはボックスから分からず、斜めの船を囲む直立したボックスには水面が大部分含まれます。姿勢推定とOBBは、まさにこの2つの問題を解決するためのものです。

成果

YOLO26のキーポイントから姿勢判定ルールを作成し、航空画像で回転ボックスによってどれだけ改善するかを測定します。

短期集中コース
すでに使い方をご存じの方は、こちらをご覧ください。
  1. 姿勢推定:人物ごとにボックスと17個のキーポイント(COCOの順序:0は鼻、5~6は肩、11~12は腰、15~16は足首)を出力します。

  2. キーポイントを使う前に信頼度でフィルタリングしてください。隠れている関節にも座標は割り当てられます。

  3. OBB:中心、サイズ、角度(xywhr、角度の単位はラジアン)です。

  4. 姿勢が手掛かりとなる場合は姿勢推定を使います。上空からの画像で物体が斜めに配置されている場合はOBBを使い、それ以外では検出を使います。

実践的

姿勢推定:姿勢が手掛かりとなる場合#

水辺の遊歩道を走る3人のランナー。それぞれに人物ボックスと、Ultralytics YOLOの姿勢推定による17個のキーポイントの骨格が表示されています

姿勢推定モデルは、人物ごとにボックスと固定リストのキーポイントを出力します。COCO-Poseで学習したモデルは、人物ごとに17個のキーポイントを予測します。鼻、目、耳、肩、肘、手首、腰、膝、足首が常に同じ順序で並ぶため、インデックス0は鼻、11は左腰、15は左足首です。各キーポイントには信頼度も付与されます。

最も簡単で実用的なルールは、立っている身体は幅より高さがあり、床に横たわっている身体は高さより幅がある、というものです。モデルが十分な信頼度を示したキーポイントだけを使い、バスの画像に適用した例を示します。

from ultralytics import YOLO

model = YOLO("yolo26n-pose.pt")
result = model("https://ultralytics.com/images/bus.jpg", verbose=False)[0]

for xy, conf in zip(result.keypoints.xy, result.keypoints.conf):
    visible = xy[conf > 0.5]  # drop keypoints the model couldn't see
    width = float(visible[:, 0].max() - visible[:, 0].min())
    height = float(visible[:, 1].max() - visible[:, 1].min())
    posture = "unknown" if len(visible) < 5 else "lying" if width > height else "upright"
    print(f"{len(visible):2d}/17 keypoints visible, body {width:3.0f} px wide x {height:3.0f} px tall -> {posture}")
16/17 keypoints visible, body 117 px wide x 427 px tall -> upright
 6/17 keypoints visible, body  80 px wide x 359 px tall -> upright
16/17 keypoints visible, body  91 px wide x 384 px tall -> upright
 1/17 keypoints visible, body   0 px wide x   0 px tall -> unknown
 2/17 keypoints visible, body   3 px wide x   6 px tall -> unknown

3人が明らかに直立しています。最後の2行は、左端で一部が切れている人物と、信頼度の低い重複検出です。キーポイントが1つか2つしか見えない場合は判断できないため、このルールは推測せず「不明」とします。本番環境の転倒検出では、トラッキングを通じて、急速に倒れた後に数秒以上横たわっているかどうかも判定します。

見えない関節にも座標はある

症状: 手首が宙に浮いたスケルトンや、半分しか見えていない人物にも反応する姿勢ルールが発生します。原因: keypoints.xyは、モデルから見えなかったものも含めて17個すべてのキーポイントの位置を返します。対処法: 前述のようにkeypoints.confでフィルタリングし、何かを判断する前に、見えているキーポイントが最低数以上あることを条件にします。

身体の動きによって答えが変わる場合、姿勢推定が役立ちます。たとえば、安全管理における転倒や背中を曲げた状態での持ち上げ動作、ワークアウトのモニタリングのようなスポーツでの関節角度や反復回数、家畜の姿勢、カスタムのキーポイント配置を使った部品上の固定ランドマークなどです。「ここに人物がいるか」を知りたい場合は、通常の検出を使ってください。

OBB:角度が重要な場合#

航空画像で斜めに係留された3隻のヨット。それぞれがUltralytics YOLO OBBのタイトな回転ボックスで囲まれています

通常のボックスの辺は画像の辺と平行です。回転バウンディングボックスには回転が加わり、中心、幅、高さ、角度(xywhr)として保存されます。衛星、ドローン、頭上のコンベヤーカメラなどの上空からの画像では、物体はさまざまな角度で配置されます。斜めの物体を囲む直立したボックスには背景が大部分含まれ、上のヨットがその例です。マリーナを撮影したドローン画像で、その差を測定します。

from ultralytics import YOLO

model = YOLO("yolo26n-obb.pt")
result = model("https://ultralytics.com/images/boats.jpg", verbose=False)[0]

obb = result.obb
rotated_area = obb.xywhr[:, 2] * obb.xywhr[:, 3]  # width x height of each rotated box
x1, y1, x2, y2 = obb.xyxy.T  # the axis-aligned box that would enclose the same object
upright_area = (x2 - x1) * (y2 - y1)

print(f"{len(obb)} objects, classes: {sorted({result.names[int(c)] for c in obb.cls})}")
cx, cy, w, h, angle = obb.xywhr[0].tolist()
print(f"first box: center=({cx:.0f}, {cy:.0f}) size={w:.0f}x{h:.0f} angle={angle:.2f} rad")
ratio = float((upright_area / rotated_area).median())
print(f"an axis-aligned box would be {ratio:.1f}x larger (median)")
173 objects, classes: ['harbor', 'ship']
first box: center=(619, 850) size=33x108 angle=-0.25 rad
an axis-aligned box would be 2.1x larger (median)

直立したボックスは、同じ船を囲む回転ボックスの約2倍の面積を占め、その余分な部分は水面です。これは2つの問題を引き起こします。NMSでは隣り合う船の直立ボックスが重なって見えるため、実際の検出が抑制される可能性があります。また、サイズの推定値も過大になります。DOTAなどの航空画像データセットで学習したOBBモデルは、こうした場面を直接処理できます。角度の単位はラジアンです。-0.25 radは約-14°です。

検出、姿勢推定、OBBの選び方#

シナリオ最適なタスク理由
歩道を歩く人の数を数える検出必要な答えは人物の存在と位置です
介護施設での転倒を検出する姿勢推定身体の向きが手掛かりです
ジムでスクワットの回数を数える姿勢推定膝と腰の角度が手掛かりです
ドローンから係留中の船を数えるOBB船は斜めに並び、密集しています
上空から見たコンベヤー上の荷物OBB向きがさまざまで、隣り合う物体が接しています
地上から見た車検出車はフレーム内でおおむね直立して見えます
PoseとOBBは検出に要素を1つ追加したもの

Poseは各ボックスにキーポイントを追加し、OBBは角度を追加します。コードでキーポイントや角度を一度も読み取らないのであれば、通常の検出器のほうがラベル付けも実行も速く、デバッグも簡単です。

試してみる

マリーナ画像で、解決策にある比較を実行します。COCOで事前学習した検出モデルとOBBモデルを比較してください。両方の検出数を記録し、その差のうち、ボックスの形状と各モデルの学習データに起因する割合について1文で説明します。最後に、自分の業務で通常の検出より姿勢推定またはOBBが適している問題を1つ挙げ、コードで適用するルールを説明してください。

完了条件
以下のすべてを満たすと、レッスンは完了です。
  • boats.jpgの船の検出数を両方とも記録し、差について1文で説明できています。

  • 姿勢判定ルールで隠れたキーポイントをフィルタリングする行を示し、その必要性を説明できます。

  • 自分の業務で姿勢推定またはOBBが適した問題を1つ挙げ、コードで適用するルールを説明できています。

解答を表示
from ultralytics import YOLO

image = "https://ultralytics.com/images/boats.jpg"
upright = YOLO("yolo26n.pt")(image, verbose=False)[0]
rotated = YOLO("yolo26n-obb.pt")(image, verbose=False)[0]
print(f"axis-aligned detector: {len(upright.boxes)} boxes")
print(f"OBB model: {len(rotated.obb)} rotated boxes")
axis-aligned detector: 0 boxes
OBB model: 173 rotated boxes

差の大部分は形状ではなく、学習データに起因します。yolo26n.ptはCOCOで学習しており、COCOでは船の大半が側面から撮影されています。そのため、上空からの画像ではデフォルトのしきい値で何も検出されません(confを0.05に下げると、いくつかをボトルとして検出します)。OBBモデルは航空画像で学習しています。形状も依然として重要です。航空画像の船で学習した検出モデルであっても、ボックスのサイズは約2倍になり、密集した列ではNMSの問題が起きます。タスクと学習データの両方を、実際の運用環境での見え方に合わせる必要があります。

次のステップ

マリーナの例から、学習データはタスクと同じくらい重要だと分かりました。次は、データセットが実際の導入環境に合っているかを確認します。