fullseye

BOP T-LESS 実機深度 6 自由度 PoC

examples/poc_real_tless_6dof.py は、PrimeSense Carmine 1.09 の実測深度を点群へ戻し、法線推定、RANSAC による作業台除去、Euclidean clustering、Point Pair Features、ICP を順に適用します。BOP toolkit は使わず、BOP JSON、16-bit depth PNG、ASCII PLY、対称性を自前で読みます。

データ、ライセンス、引用

BOP の一次配布ページの T-LESS 欄は license: CC BY 4.0 と明記しています。このため再配布と派生物の公開が可能です。データはリポジトリに含めず、tools/fetch_tless.py が外部キャッシュへ取得します。

取得した公式 LFS オブジェクトは次のとおりです。

ファイル bytes SHA-256
tless_base.zip 49,597 dd70ca884b7c471a530a952f70c5ab2c212f3d2c2f371be86397442b97d70a7e
tless_models.zip 33,468,762 6a29c59766b8d2af05e62e71739f0ca7243ad81bc3c7f9a24925504a8cb37928
tless_test_primesense_bop19.zip 825,276,992 1a18f6bbfb5ac4ced8529f7a35225adfed88c0f62ef38067933e2b541ef1d00b

固定した評価条件

BOP19 test_primesense の全20場面から、各場面に含まれる画像IDの最小値を決定的に1枚選びました。visib_fract >= 0.50 の全対象を採点したため、標本は20場面・132対象です。公開ベースラインは全テスト画像の値であり、この20画像 subset と同一標本の直接対決ではありません。

MSSD は物体径の 0.05d..0.50d、MSPD は 5..50 px の10閾値で recall を平均しました。PoC は VSD を計算しないため、公式ARは出しません。

設定掃引

Python 3.11で、同じ20場面・132対象に主経路だけを通しました。秒/対象は場面準備、PPFモデル構築、投票、ICP、採点を含む壁時計時間です。系列 ごとに基準行を再掲したため11設定です。密度以外の掃引は、10秒/対象以内で最も良かった1000/1000点・2 mmを固定して一変量ずつ振りました。

系列 model点 scene点 voxel mm ref_fraction angle bins ICP反復 AR_MSSD AR_MSPD 秒/対象
密度 180 160 6 0.25 24 50 0.162 0.185 0.254
密度 500 500 3 0.25 24 50 0.180 0.213 1.423
密度 1000 1000 2 0.25 24 50 0.196 0.217 8.380
密度 2000 2000 2 0.25 24 50 — — >54.6
ref 1000 1000 2 0.25 24 50 0.196 0.217 8.380
ref 1000 1000 2 0.50 24 50 0.201 0.233 15.068
ref 1000 1000 2 1.00 24 50 0.195 0.230 33.080
angle 1000 1000 2 0.25 24 50 0.196 0.217 8.380
angle 1000 1000 2 0.25 30 50 0.195 0.221 8.793
ICP 1000 1000 2 0.25 24 50 0.196 0.217 8.380
ICP 1000 1000 2 0.25 24 100 0.197 0.220 8.291

2000/2000点は全体を2時間走らせても完走せず、場面単位の再試行もscene 1の4対象だけで31分を超えたため打ち切りました。時間の下限は全体試行の 7204秒 / 132対象 > 54.6秒/対象 です。ARは一部標本から外挿せず未記録としました。

採用設定は1000/1000点、voxel 2 mm、ref_fraction=0.25、angle_bins=24、ICP 100反復です。10秒/対象以内の行で AR_MSSD が最大の0.197だったためです。0.5参照は0.201まで上がりましたが15.068秒/対象で上限外でした。

ベースライン比較

方法 official AR AR_MSSD AR_MSPD
Fullseye PPF+ICP、採用設定1000/1000点(20場面・132対象) — 0.197 0.220
Fullseye PPF+ICP、間引き180/160点(同じ20場面・132対象) — 0.162 0.185
Fullseye PPF+ICP、クラスタなし1000点(20場面・132対象) — 0.111 0.113
Fullseye PPF+ICP(前回2場面・10対象) — 0.290 0.320
Drost-CVPR10-3D-Only(公式全test) 0.444 0.478 0.480
Vidal-Sensors18(公式全test) 0.538 0.575 0.574

密度を上げると実機 AR_MSSD は0.162から0.197へ改善しました。したがって0.162をPPF自体の限界とは扱いません。一方、採用設定でも公開値を下回ります。ただし公開値は公式全test、PoCは固定20画像subsetで、同一標本の直接対決ではありません。

同じモデルと真値姿勢から作った理想 z-buffer 深度は0.985/0.985で、合成から実機への低下はMSSD 0.788、MSPD 0.765でした。ICPを外すと0.346/0.338、法線の符号をカメラ向きに揃えないと0.132/0.161です。ICPなしが良いのは、現行の局所refineが誤った大域仮説を別の局所解へ寄せる対象があるためで、次便の検討対象です。

クラスタ分割なしでは、平面除去後の場面点群全体を1000点へ決定的に間引き、各モデルを直接 surface_match しました。ARは0.111/0.113で、180/160点時の0.064/0.054からは改善しましたが、対象ごとの点を集中して残すクラスタありの0.197/0.220には届きませんでした。

PPF実装のボトルネック

ppf.py は全対距離行列を一括生成していません。しかし、ppf_model はモデルの各基準点について全点との差分を作り、Pythonの二重ループで全順序対をハッシュ辞書へ格納します。surface_match も ref_fraction × scene点数² の場面点対を走査し、各ハッシュ一致に入ったモデル候補列をPythonで一件ずつ投票します。形状によって大きなバケットができるため、2000点では単純な二乗増加以上に遅くなる対象がありました。

この便ではPPF本体を変更していません。次便ではモデル記述子の再利用、法線品質、dist_step の量子化、投票の正規化とバケット分布を調べます。

対象別

失敗は MSSD > 0.2d です。内訳の5列は失敗対象だけを数え、カテゴリ間の重複を許します。結合 は複数真値対象を同じクラスタへ割り当てた数、遮蔽 は可視率0.8未満、薄型 は厚さ/径0.45未満、欠測 は可視マスク内の欠測depthが1%超、対称 は対称変換を持つ対象です。

obj_id 件数 AR_MSSD AR_MSPD 失敗 結合 遮蔽 薄型 欠測 対称
1 17 0.088 0.112 15 7 1 0 6 15
2 9 0.100 0.178 9 4 1 0 2 9
3 8 0.175 0.212 6 2 0 0 0 6
4 13 0.200 0.277 10 6 1 0 2 10
5 4 0.100 0.050 4 0 0 0 2 4
6 2 0.750 0.700 0 0 0 0 0 0
7 5 0.200 0.080 4 0 1 4 2 4
8 3 0.100 0.000 3 1 1 3 3 3
9 5 0.340 0.300 3 0 0 3 1 3
10 3 0.000 0.000 3 0 0 0 0 3
11 4 0.050 0.150 4 0 0 0 0 4
12 3 0.200 0.267 3 0 0 0 0 3
13 3 0.000 0.033 3 2 0 0 1 3
14 3 0.467 0.533 2 1 0 0 0 2
15 3 0.233 0.267 2 1 0 0 1 2
16 4 0.325 0.350 3 2 0 0 1 3
17 3 0.533 0.533 1 0 0 0 0 1
18 3 0.467 0.400 2 1 0 0 2 0
19 4 0.250 0.300 3 1 0 0 2 3
20 4 0.075 0.125 4 1 0 0 2 4
21 3 0.233 0.300 2 1 0 0 1 0
22 3 0.267 0.300 2 0 0 0 1 0
23 5 0.200 0.180 4 1 0 4 2 4
24 4 0.325 0.350 3 0 0 0 1 3
25 2 0.200 0.300 2 0 0 0 1 2
26 2 0.000 0.000 2 1 0 0 1 2
27 1 0.000 0.000 1 0 1 1 0 1
28 4 0.300 0.275 4 1 2 4 0 4
29 2 0.150 0.100 2 0 0 2 2 2
30 3 0.167 0.300 3 1 0 0 0 3

全体では109/132対象が失敗し、重複内訳は結合34、遮蔽8、薄型21、欠測36、対称103でした。

場面別

scene 最初のimage 対象 cluster AR_MSSD AR_MSPD 失敗
1 1 4 6 0.125 0.225 4
2 3 3 5 0.500 0.367 1
3 5 5 8 0.320 0.440 4
4 0 4 5 0.325 0.250 4
5 7 5 6 0.140 0.180 4
6 2 5 13 0.160 0.140 4
7 3 8 9 0.362 0.350 5
8 1 5 8 0.500 0.600 2
9 0 12 13 0.300 0.400 8
10 5 6 9 0.300 0.383 4
11 4 4 7 0.225 0.200 3
12 2 6 7 0.383 0.417 4
13 2 7 5 0.129 0.114 7
14 2 6 14 0.050 0.000 6
15 1 5 9 0.140 0.160 5
16 8 8 10 0.175 0.212 7
17 3 7 24 0.000 0.043 7
18 2 7 19 0.114 0.114 6
19 1 9 10 0.167 0.156 8
20 3 16 2 0.000 0.013 16

所要時間

採用判定に使った主経路の掃引実行は1094.47秒、132対象で8.291秒/対象でした。合成、ICPなし、未整理法線、クラスタなしを同時に取る診断実行は、全照合と採点を終えて図生成へ入るまで約7189.2秒でした。この診断用総時間は採用上限の秒/対象には使いません。

実行

py -3.11 tools/fetch_tless.py
py -3.11 examples/poc_real_tless_6dof.py
$env:FULLSEYE_TLESS_SWEEP='density_1000_1000_v2'
py -3.11 examples/poc_real_tless_6dof.py

CIなどデータが無い環境では取得を始めず、PoCに固定した RECORDED を表示します。図を所定の場所へ再生成する場合だけ FULLSEYE_FIGURE_DIR=docs/articles/assets/poc/poc_real_tless_6dof を設定します。

図

  1. 01_pose_overlay.png: 推定姿勢(橙)と公開真値(青)。代表図。
  2. 02_rgb_depth.png: 実RGBと実機depth。
  3. 03_mssd_by_object.png: 20場面をobj_idごとに平均したAR_MSSD。棒上に値と件数。
  4. 04_synthetic_vs_real.png: 横軸を合成MSSD、合成MSPD、実機MSSD、実機MSPDの文字ラベルにした比較。
  5. 05_failure.png: 20場面でMSSDが最大だった失敗例。
  6. 06_density_vs_ar_time.png: scene点数に対するAR_MSSD(左軸)と秒/対象(右軸)。