recover_pose — 3D two_view op

• Data kinds: image2d × image2d → pose

• Call: import fullseye as fs; fs.ledger.recover_pose(pts1, pts2, K1, K2=None, planar_tol=3.0) (implementation को सीधे call करना हो तो import twoview; twoview.recover_pose(pts1, pts2, K1, K2=None, planar_tol=3.0), registry से लेना हो तो ops3d.get("recover_pose"))

• GPU: नहीं (केवल CPU reference implementation)

उपयोग

corresponding points + K से relative pose (R,t) और 3D structure वापस निकालता है (cheirality से एकमात्र हल)। → (R, t_unit, points3d)।

t का scale अनिश्चित है, इसलिए यह unit vector है। points3d cam1 coordinate system में है (|t|=1 के संगत scale पर)।

fail-closed: planar (coplanar 3D) / pure rotation scenes essential matrix decomposition के degenerate configuration हैं, Sampson residual ~0 रहते हुए भी translation की दिशा गलत लौटती है (देखने में एकदम सही)। ऐसे input से pose recover नहीं हो सकता, इसलिए उन्हें ValueError से स्पष्ट रूप से reject किया जाता है (homography decomposition का उपयोग करें)। planar_tol parallax और scale से स्वतंत्र planarity threshold है (_planar_degeneracy_ratio = H और F के fit का अनुपात इससे कम हो तो degenerate माना जाता है; default 3.0)।

प्रक्रिया:

• प्रवेश जाँच (कम से कम 8 points, points की संख्या मेल खाए, (N,2) और finite)।

• planarity: normalised DLT से homography H और normalised 8-point से F दोनों fit करके, degrees of freedom से भाग दिए गए residual scales का अनुपात σ_H / σ_F निकाला जाता है (_planar_degeneracy_ratio)। यह planar_tol (default 3.0) से कम हो तो ValueError। planar और pure rotation में लगभग √2, non-planar में parallax / noise के अनुपात में बड़ा। H singular हो तो अनुपात 0 मानकर उसी तरह reject। ठीक 8 points पर F के residual से noise नहीं मापा जा सकता, इसलिए पुरानी जाँच (H residual का median / points का फैलाव < 1e-2, parallax के अनुपात में) उपयोग होती है।

• ★2026-11-05 (adversarial verification G11): पुराना अनुपात (H residual / points का फैलाव, default 1e-2) parallax के अनुपात में था, और baseline छोटी होने पर non-planar को भी reject करता था (camera.recover_pose वही data हल करता है)। उलटे, noise बड़ा हो तो planar को भी पास कर देता था (σ = 2 px पर अनुपात 1e-2 से अधिक)। नया अनुपात दोनों ठीक करता है।

• essential_8point → 4 candidates (R, ±t) में decomposition → हर candidate के लिए triangulate करके, दोनों cameras में depth > 0 वाले points की अधिकतम संख्या वाला candidate लिया जाता है (बराबरी पर पहले वाला candidate)।

return value: R (3,3), t (3,) unit vector, points3d (N,3)। परिपाटी cam1 = K1[I|0], cam2 = K2[R|t] के साथ X2 = R X1 + t है। points3d cam1 coordinate system में |t|=1 के scale पर है। समानांतर line of sight वाले correspondence NaN rows बन जाते हैं।

• K2 छोड़ने पर K1 दोनों images के लिए उपयोग होता है।

• outliers के सामने असुरक्षित (RANSAC नहीं किया जाता)। पिछले चरण में गलत correspondence हटाएँ।

• deterministic। GT सत्यापन के लिए pose_error, residual के लिए sampson_distance।

पृष्ठभूमि guides (इस op के पीछे की physics और conventions)

• depth_sensors — Depth sensors — ranging के सिद्धांत, असली devices के आँकड़े, dropouts कैसे दिखते हैं

संदर्भ (sample data, साहित्य)

• Sample data catalog (DL URL / license) — 2-D के लिए skimage.data (BSD/public) + synthetic, 3-D के लिए real data sources (Stanford/PDS आदि) के DL URL।

• Operators का स्रोत और संदर्भ — इस op family के मूल research/methods के स्रोत।

चलाए जा सकने वाले उदाहरण (verified samples जो सच में यह op call करते हैं)

• two_view_pose — py -3.11 examples_3d/two_view_pose.py

वे अगले ops जिनसे type जुड़ता है (pose को input के रूप में लेते हैं)

fuse_to_voxel · pose_error · bundle_adjust · mean_reprojection_error · optimize_pose_graph · relative_pose · mean_edge_error · rotation_translation_error

इसी category के (two_view)

fundamental_8point · essential_8point · triangulate · sampson_distance


*Provenance: twoview.py — 3D operator registry. यह per-op note tools/opdocs.py md से अपने-आप generate होता है (हाथ से edit न करें)।*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.