姿勢推定とOBB
YOLO26のキーポイントと回転ボックスを読み取り、それぞれにルールを適用して、姿勢や角度が本当に重要な手掛かりとなる状況を見分けます。
介護施設では人が転倒したかどうかを把握する必要があり、港ではドローン画像で隣り合って密集する船を数える必要があります。通常のボックスでは、どちらの問題も解決できません。人物が直立しているかどうかはボックスから分からず、斜めの船を囲む直立したボックスには水面が大部分含まれます。姿勢推定とOBBは、まさにこの2つの問題を解決するためのものです。
実践的
姿勢推定:姿勢が手掛かりとなる場合#

姿勢推定モデルは、人物ごとにボックスと固定リストのキーポイントを出力します。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 -> unknown3人が明らかに直立しています。最後の2行は、左端で一部が切れている人物と、信頼度の低い重複検出です。キーポイントが1つか2つしか見えない場合は判断できないため、このルールは推測せず「不明」とします。本番環境の転倒検出では、トラッキングを通じて、急速に倒れた後に数秒以上横たわっているかどうかも判定します。
症状: 手首が宙に浮いたスケルトンや、半分しか見えていない人物にも反応する姿勢ルールが発生します。原因: keypoints.xyは、モデルから見えなかったものも含めて17個すべてのキーポイントの位置を返します。対処法: 前述のようにkeypoints.confでフィルタリングし、何かを判断する前に、見えているキーポイントが最低数以上あることを条件にします。
身体の動きによって答えが変わる場合、姿勢推定が役立ちます。たとえば、安全管理における転倒や背中を曲げた状態での持ち上げ動作、ワークアウトのモニタリングのようなスポーツでの関節角度や反復回数、家畜の姿勢、カスタムのキーポイント配置を使った部品上の固定ランドマークなどです。「ここに人物がいるか」を知りたい場合は、通常の検出を使ってください。
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は角度を追加します。コードでキーポイントや角度を一度も読み取らないのであれば、通常の検出器のほうがラベル付けも実行も速く、デバッグも簡単です。
解答を表示
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の問題が起きます。タスクと学習データの両方を、実際の運用環境での見え方に合わせる必要があります。