github.com/kocurvik/fastpose · Benchmark · ETH3D · ScanNet++ · PhotoTourism
fastpose is a numba-compiled LO-RANSAC engine for camera pose estimation. It includes estimators for calibred/uncalibrated relative pose, relative pose with known depth (RePoseD), homography and fundamental matrix estimation, and calibrated/uncalibrated absolute pose. Against PoseLib’s C++ implementation on the same correspondences, budget and error thresholds, it lands the same relative poses — a median difference of a few hundredths of an mAA point — and gets there two to ten times sooner on one CPU core, or one to two orders of magnitude sooner on a GPU.
The frontier, in one panel
ScanNet++ · calibrated RePoseD 3‑point · RoMa v2 4096
PoseLib needs 1101 ms and 5000 iterations to reach 89.01 mAA. fastpose passes it on the GPU in 12.7 ms — and beats it on a single core in 84 ms.
Two dependencies, numpy and numba. Every estimate_*
function takes device='cuda' to run the same estimate batched on the GPU.
# warm the numba kernels once, before you fork workers from fastpose.estimators.warmup import warmup warmup() # calibrated relative pose, 5-point, on the CPU from fastpose.estimators import estimate_relative_pose model, info = estimate_relative_pose(x1, x2, camera1=K1, camera2=K2, iterations=5000, max_error=2.0) # the pose comes out of the model dict R = model['R'] # 3x3 rotation t = model['t'] # 3-vector translation, up to scale inliers = info['inliers'] # boolean mask over the correspondences # the same call, batched on the GPU model, info = estimate_relative_pose(x1, x2, camera1=K1, camera2=K2, iterations=5000, max_error=2.0, device='cuda') R, t = model['R'], model['t']
Numba compiles lazily, so the first call to each estimator is slow. Run
fastpose-warmup (or --device cuda) up front, and always warm the
cache before forking worker processes.
Each point is one RANSAC budget, 100 to 5000 iterations, and 20 000 on the GPU. Accuracy saturates early, so the curves separate along the horizontal rather than the vertical. Note the compressed accuracy axis: a panel usually spans about one mAA point, so a curve further left is faster at equal accuracy, not a trade against it.
Applies to every chart on this page.
On a CPU every iteration is paid for in full, so the budget trades against latency. The CUDA backend runs the batch on the device, where 5000 iterations — past the flattening of the curves above — costs roughly what a single core needs for its cheapest 100-iteration run. Going on to 20 000 costs about 60% more, and moves accuracy by under a point either way.
Runtime as the budget grows
Wall-clock time per pair at a matched 5000 iterations, divided by PoseLib’s time on the same pairs; 1× is parity. The scale is logarithmic because the GPU sits two orders of magnitude from the CPU. Median over the datasets each solver runs on.
Speed-up over PoseLib — matched at 5000 iterations
Produced by fastposebench.
Every 5th pair of the standard benchmark: ETH3D and ScanNet++ (shared intrinsics) and PhotoTourism (varying intrinsics). Correspondences from RoMa v2 base and from LoMa; the budget selector is total sampled matches for RoMa v2 and maximum keypoints for LoMa.
Both backends see the identical correspondences, the same Sampson threshold (2.0 px), the same truncated reprojection threshold (16.0 px) and the same iteration count. Timings are mean wall-clock per pair and exclude the depth network, which costs about 88 ms per pair on its own.
CPU runs are one process pinned to 1 or 4 cores. The GPU column is the CUDA backend running the whole estimate batched on one device, at 5000–20 000 iterations; lower budgets do not fill the device and are not reported.
Pose mAA@10° is the mean average accuracy of the max of rotation and translation error, integrated to a 10° threshold, in percent. Higher is better. mAA@5° and the median pose error are in the table views.
If you found fastpose useful please consider citing:
@misc{fastpose,
title = {{fastpose -- A Fast Python Backend for Robust Camera Pose Estimation}},
author = {Kocur, Viktor},
url = {https://github.com/kocurvik/fastpose},
year = {2026}
}
fastpose is a numba port of algorithms implemented in PoseLib. If you use it, please cite PoseLib and the papers behind the solvers you actually run.