Outlier-handling benchmark — better weighting, no rejection¶
Per-view PnP on a synthetic camera, median over 60 views, with a controlled fraction of corners corrupted by a 50 px gross shift.
Note
Measured at the per-view pose level, before any downstream bundle adjustment — so the front-end's own robustness is the whole story, not masked by an outer optimizer.
- L2 —
solvePnPover all corners, no robustness (naive baseline). - reject — RANSAC P3P
- inlier refine (hard rejection, MC-Calib-style).
- reweight —
robust_pose_irls: RANSAC warm-start + redescending Cauchy IRLS (MAD auto-scale, GNC, studentized leverage) over every corner — no rejection.
| outlier % | L2 dR° | L2 dt | reject dR° | reject dt | reweight dR° | reweight dt | dR° reduction vs L2 |
|---|---|---|---|---|---|---|---|
| 0% | 0.045 | 0.0015 | 0.045 | 0.0015 | 0.046 | 0.0015 | -3.5% |
| 5% | 1.054 | 0.0359 | 0.046 | 0.0017 | 0.050 | 0.0017 | 95.2% |
| 10% | 164.051 | 3.9544 | 0.050 | 0.0018 | 0.051 | 0.0019 | 100.0% |
| 20% | 177.290 | 4.1124 | 0.048 | 0.0017 | 0.049 | 0.0017 | 100.0% |
| 30% | 177.837 | 4.1943 | 0.060 | 0.0019 | 0.059 | 0.0019 | 100.0% |
| 40% | 177.702 | 4.2501 | 0.059 | 0.0021 | 0.070 | 0.0023 | 100.0% |
Mean rotation-error reduction vs naive L2 at ≥10 % outliers: 100.0% (PASS >50%) — by weighting, every corner is kept.
Tip
The reject/reweight columns reproduce bit-for-bit run to run. The naive L2 blow-up values
are the ill-conditioned regime itself — unweighted L2 pose recovery is chaotic once outliers
dominate, landing anywhere in the 140–180° range across repeated runs rather than a single fixed
number. That instability is the point being measured, not noise in the measurement.
Studentized leverage — the self-masking outlier a residual kernel cannot see¶
One far-off-axis corner with a modest mis-decode: leverage — how much sway a point's position gives it over the fit — lets it pull the pose while keeping its own residual small, so a residual-only kernel never down-weights it.
Studentizing the residual recovers it: median rotation error 0.820° → 0.165° (79.9% lower).
Source: this page is generated by
scripts/benchmark_outliers.py —
run it to reproduce this benchmark. Robust estimator:
robust_pose_irls.