A new crate holding the CPU half of a merge (FR-MRG-10): the grayscale proxy with orientation, the XFeat decoder ported step for step from the reference detectAndCompute, mutual-nearest-neighbour matching, a robust pairwise homography with the focal length read off it, a hand-rolled Levenberg–Marquardt bundle adjustment over every rotation and the focal, the three output projections, and align(), which chains it all and names the frames it could not place rather than guessing (FR-MRG-5). Dependency-free without the xfeat feature — linalg.rs says why the dense algebra is hand-rolled — and tested on synthetic sweeps whose answer is known exactly. The noise test records the single-row degeneracy: one pixel of noise is a tenth of a percent of focal, which is a uniform stretch of the sweep, not a misalignment.
66 lines
2.4 KiB
Rust
66 lines
2.4 KiB
Rust
//! TRACES: FR-MRG-1 | FR-MRG-10
|
|
//! Panorama geometry — from several frames to the rotations that relate
|
|
//! them, and the projections that lay them out.
|
|
//!
|
|
//! This is the CPU half of a merge (FR-MRG-10): keypoints, matching, the
|
|
//! rotation solve and the choice of output surface. The per-pixel half —
|
|
//! rendering, warping, seams, blending — is the GPU's and lives in
|
|
//! `dr-gpu`, driven from above; nothing here touches a full-resolution
|
|
//! pixel. The split is the whole design (panorama.md §4): everything in
|
|
//! this crate is bounded by the number of frames, not the size of the
|
|
//! composite, and runs on proxies.
|
|
//!
|
|
//! # Layout
|
|
//!
|
|
//! - [`image`] — the grayscale proxy a detector reads: oriented, resampled.
|
|
//! - [`features`] — keypoints with descriptors, and the XFeat decoder.
|
|
//! - [`xfeat`] — the network under tract (feature `xfeat`).
|
|
//! - [`matching`] — mutual nearest neighbours.
|
|
//! - [`homography`] — a robust pairwise homography, the focal length read
|
|
//! off it, and the rotation it implies.
|
|
//! - [`bundle`] — every rotation and the focal length refined together.
|
|
//! - [`align`] — the whole thing, from features to cameras, honest about
|
|
//! what it could not place.
|
|
//! - [`projection`] — perspective, cylindrical, spherical.
|
|
//! - [`linalg`] — the small dense algebra all of it uses.
|
|
//!
|
|
//! # What it depends on
|
|
//!
|
|
//! Nothing, without the `xfeat` feature: the geometry is pure Rust with
|
|
//! hand-rolled linear algebra (`linalg` says why) so that it tests without
|
|
//! a model, a GPU or a device, on synthetic sets whose answer is known
|
|
//! exactly. With the feature it adds the same `ort`-over-tract runtime the
|
|
//! rest of the application already carries.
|
|
|
|
pub mod align;
|
|
pub mod bundle;
|
|
pub mod features;
|
|
pub mod homography;
|
|
pub mod image;
|
|
pub mod linalg;
|
|
pub mod matching;
|
|
pub mod projection;
|
|
#[cfg(feature = "xfeat")]
|
|
pub mod xfeat;
|
|
|
|
pub use align::{align, AlignOptions, Alignment, Link, Unaligned};
|
|
pub use bundle::Cameras;
|
|
pub use features::{Features, Keypoint};
|
|
pub use image::Gray;
|
|
pub use projection::Projection;
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum PanoError {
|
|
#[error("bad input: {0}")]
|
|
Input(String),
|
|
#[error("geometry: {0}")]
|
|
Geometry(String),
|
|
#[error("model: {0}")]
|
|
Model(String),
|
|
#[error("could not read the model: {0}")]
|
|
ModelRead(#[source] std::io::Error),
|
|
#[cfg(feature = "xfeat")]
|
|
#[error("inference: {0}")]
|
|
Inference(#[source] ort::Error),
|
|
}
|