Browse by type
This repo contains the official implementation of the solvers and estimators proposed in the paper "Relative Pose Estimation through Affine Corrections of Monocular Depth Priors" (CVPR 2025 Highlight). The solvers and estimators are implemented using C++, and we provide easy-to-use Python bindings.
Note: "MAD" is an acronym for "Monocular Affine Depth".
Overview: Our method takes a pair of images as input, runs off-the-shelf feature matching and monocular depth
estimation, then jointly estimates the relative pose, scale and shift parameters of the two depth maps, and optionally the focal lengths.
We develop three solvers for relative pose estimation that explicitly account for independent affine (scale and shift) ambiguities, tailored for three setups of cameras: calibrated, shared-focal, and unknown focal lengths (two-focal). The solvers are further combined with classic point-based solvers and epipolar constraints in our hybrid RANSAC estimators. Our estimators show consistent improvements over classic point-based methods (e.g. PoseLib) and recent two-view reconstruction methods DUSt3R and MASt3R, across different datasets with different feature matchers and monocular depth estimation models.
Some highlight results (probably best viewed in light theme on GitHub!):
| Matches | Method | MD Model | AUC@5° | AUC@10° | AUC@20° |
|---|---|---|---|---|---|
| SP+SG | PoseLib-6pt | - | 12.84 | 28.13 | 45.64 |
| Ours-sf | DA-met. | 18.35 | 37.54 | 57.58 | |
| RoMa | PoseLib-6pt | - | 27.17 | 49.24 | 67.42 |
| Ours-sf | DA-met. | 29.81 | 53.11 | 71.15 | |
| MASt3R | PoseLib-6pt | - | 30.28 | 54.16 | 72.87 |
| Ours-sf | DA-met. | 31.87 | 56.20 | 74.51 | |
| MASt3R | 32.58 | 56.99 | 74.91 | ||
| Reference entry - DUSt3R | 25.90 | 48.45 | 68.03 | ||
| Reference entry - MASt3R | 23.94 | 46.44 | 66.18 |
| Matches | Method | MD Model | AUC@2° | AUC@5° | AUC@10° | AUC@20° |
|---|---|---|---|---|---|---|
| SP+LG | PoseLib-7pt | - | 5.85 | 13.95 | 21.94 | 30.71 |
| Ours-tf | DAv2-met. | 9.15 | 22.22 | 32.80 | 43.26 | |
| RoMa | PoseLib-7pt | - | 8.73 | 20.31 | 30.45 | 41.48 |
| Ours-tf | DAv2-met. | 13.50 | 29.19 | 42.18 | 54.42 | |
| MASt3R | PoseLib-7pt | - | 12.58 | 30.27 | 45.57 | 59.85 |
| Ours-tf | DAv2-met. | 18.05 | 39.92 | 56.64 | 70.86 | |
| MASt3R | 22.44 | 48.02 | 64.79 | 76.55 | ||
| Reference entry - DUSt3R | 6.43 | 24.47 | 42.39 | 58.36 | ||
| Reference entry - MASt3R | 13.39 | 38.41 | 57.92 | 71.91 |
Please refer to the paper for more results and discussions.
We are working on setting up wheel for easy installation using PyPI. Currently please use the following method to install from source.
sudo apt-get install libeigen3-dev libceres-dev libopencv-dev
Note: The two-focal estimator currently relies on cv::recoverPose from OpenCV, we plan to remove dependency on OpenCV in future updates.
git clone --recursive https://github.com/MarkYu98/madpose
pip install .
If you would like to see the building process (e.g. CMake logs) you can add -v option to the above command.
Note: MADPose also depends on PoseLib. By default, CMake will automatically build PoseLib using FetchContent. Set FETCH_POSELIB CMake option to OFF if you prefer to use a self-installed version.
python -c "import madpose"
You should not see any errors if MADPose is successfully installed.
We provide Python bindings of our 3 hybrid estimators for image pairs with calibrated cameras, shared-focal cameras, and cameras with unknown focal lengths (two-focal).
The estimators take HybridLORansacOptions and EstimatorConfig for related settings, some useful settings are:
```python
import madpose
options = madpose.HybridLORansacOptions() options.min_num_iterations = 100 options.max_num_iterations = 1000 options.success_probability = 0.9999 options.random_seed = 0 # for reproducibility options.final_least_squares = True options.threshold_multiplier = 5.0 options.num_lo_steps = 4
options.squared_inlier_thresholds = [reproj_pix_thres ** 2, epipolar_pix_thres ** 2]
options.data_type_weights = [1.0, epipolar_weight]
est_config = madpose.EstimatorConfig()
est_config.min_depth_constraint = True
$ claude mcp add madpose \
-- python -m otcore.mcp_server <graph>