第8章
物体の位置関係と2次元・3次元の違い
検出枠から左右・上下・重なりを求め、画像だけで距離を決められない理由を学びます。
この章で学ぶこと
- YOLOの検出枠から物体同士の位置関係を計算する
- ピクセル座標とメートル単位の座標を区別する
- 奥行き推定に必要な追加の情報を説明する
1. 画像座標で考える
画像では左上が原点、右がxの正方向、下がyの正方向です。枠の中心は次のように計算できます。
u = (x1 + x2) / 2
v = (y1 + y2) / 2
物体Aの中心uが物体Bより小さければ、Aの中心はBより画像の左にあります。ただし、Aの全体がBの左にあるとは限りません。「枠全体が左」なら A.x2 < B.x1 のような別の条件が必要です。
2. 保存した位置関係を読む
前章の yolo_detect.py は、同じフレームのすべての検出ペアについて関係を計算し、detections.jsonl の relations に保存しています。
{"a": 0, "b": 1, "horizontal": "left", "vertical": "aligned", "center_distance_px": 120.0, "iou": 0.0}
これは形式を示す例です。AはBより左、中心の高さはほぼ同じ、中心間距離120ピクセル、枠の重なりなし、という意味です。実際の番号と座標は各自の検出結果で変わります。
左右・上下の判定には、どちらも画像幅の2%を許容幅として使っています。差がその範囲なら aligned とします。わずかな検出の揺れで判定が切り替わるのを減らすためです。これは教材で選んだ基準で、用途に合わせて変更できます。
計算を単独で試すこともできます。次を relation_example.py としてコード一式と同じフォルダーへ保存します。
from vision_common import box_relation
a = [10, 20, 50, 80]
b = [110, 20, 150, 80]
print(box_relation(a, b, tolerance=10))
python relation_example.py
結果は left、aligned、中心間距離 100.0、IoU 0.0 になります。A・Bの座標を入れ替えると、左右の判定が逆になります。
3. 重なり・接触・奥行きは別
| 観察できたこと | そこからは決まらないこと |
|---|---|
| 枠のIoUが大きい | 実物が接触しているか |
| Aの中心がBより左 | 世界座標でもAがBより左か |
| Aの枠がBより大きい | Aの方が近いか。実物の大きさも影響する |
| 中心間が100ピクセル | 実物同士が何cm離れているか |
カメラの向きが変われば、画像内の左右も変わります。物体が隠れたときは、検出枠の中心が実物の中心からずれることもあります。
4. 奥行きに必要な手掛かり
歪みを除いたピンホールカメラでは、カメラ座標 (X, Y, Z) と画素 (u, v) の関係を次のように表せます。
u = fx × X / Z + cx
v = fy × Y / Z + cy
同じ X/Z と Y/Z になる点は、同じ画素に写ります。そのため、単眼画像の画素座標だけでは奥行きZを一意に決められません。
| 方法 | 追加する情報・条件 |
|---|---|
| 既知サイズのマーカーとPnP | マーカーの実寸、対応する角、校正したカメラ |
| ステレオ | 2台のカメラの間隔と校正、左右画像の対応点 |
| RGB-Dカメラ | 距離センサーとカラー画像の位置合わせ |
| 既知平面への変換 | 床面などの対応点。同じ平面上の点に限る |
| 単眼の学習型深度推定 | 学習済みの事前知識。モデルごとの尺度と利用条件の確認 |
たとえば、正面を向いた既知幅 W=0.10m の平面物体が w=100px に写り、fx=800px なら、概算は Z ≈ fx × W / w = 0.80m です。物体が傾く、隠れる、枠が実物の端とずれるとこの近似は崩れます。任意のYOLOの枠から常に距離が求まる式ではありません。
次章ではカメラの fx, fy, cx, cy と歪みを求め、その後に実寸が分かるマーカーの四隅を使った推定へ進みます。
やってみよう
- 2つのコップを前後に置き、カメラを横へ動かしたとき画像の関係が変わるか確かめてください。
- 枠が重なっていても実物が接触していない配置を作ってください。
- 上の近似で見かけの幅が50pxになった場合、Zはいくつでしょうか。
3の答えは1.60mです。物体の実寸と姿勢など、近似の条件が同じ場合に限ります。