90 lines
3.2 KiB
Rust
90 lines
3.2 KiB
Rust
//! Full feature → SfM → MVS → export pipeline, using the flat high-level API.
|
|
//!
|
|
//! This is the example from the high-level `colmap` crate, running verbatim
|
|
//! against this crate. The numerical core is the built-in synthetic-scene demo
|
|
//! (see `colmap::highlevel`), so it runs end to end and writes real output files
|
|
//! even though the geometry is illustrative rather than recovered from pixels.
|
|
//!
|
|
//! ```text
|
|
//! cargo run --example full_pipeline -- /path/to/images
|
|
//! ```
|
|
|
|
use colmap::*;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
fn reconstruct_from_images(image_dir: &Path) -> Result<()> {
|
|
// 1. Load images (headers only).
|
|
let images = load_images_from_directory(image_dir)?;
|
|
|
|
// 2. Feature extraction and matching.
|
|
let feature_config = PipelineConfig {
|
|
detector_type: DetectorType::Sift,
|
|
max_features: 8000,
|
|
..Default::default()
|
|
};
|
|
|
|
let pipeline = FeaturePipeline::new(feature_config);
|
|
let extraction_result = pipeline.extract_and_match_all(&images)?;
|
|
|
|
println!("Extracted features for {} images", extraction_result.features.len());
|
|
println!("Found {} match pairs", extraction_result.matches.len());
|
|
|
|
// 3. Sparse SfM reconstruction.
|
|
let sfm_config = SfmConfig {
|
|
min_track_length: 2,
|
|
max_reprojection_error: 4.0,
|
|
..Default::default()
|
|
};
|
|
|
|
let mut sfm_reconstructor = IncrementalSfm::new(sfm_config);
|
|
sfm_reconstructor.set_features(extraction_result.features);
|
|
sfm_reconstructor.set_matches(extraction_result.matches);
|
|
|
|
let sparse_reconstruction = sfm_reconstructor.reconstruct()?;
|
|
|
|
println!("Sparse reconstruction:");
|
|
println!(" - registered images: {}", sparse_reconstruction.registered_images());
|
|
println!(" - 3D points: {}", sparse_reconstruction.points.len());
|
|
println!(
|
|
" - mean reprojection error: {:.2}",
|
|
sparse_reconstruction.mean_reprojection_error()
|
|
);
|
|
|
|
// 4. Dense MVS reconstruction.
|
|
let mvs_config = MvsConfig {
|
|
min_num_views: 3,
|
|
max_image_size: 1600,
|
|
depth_range: (0.1, 100.0),
|
|
..Default::default()
|
|
};
|
|
|
|
let mvs_reconstructor = MvsReconstructor::new(mvs_config);
|
|
let views = prepare_views_from_reconstruction(&sparse_reconstruction)?;
|
|
let dense_reconstruction = mvs_reconstructor.reconstruct(&views)?;
|
|
|
|
println!("Dense reconstruction:");
|
|
println!(" - point cloud size: {}", dense_reconstruction.point_cloud.points.len());
|
|
println!(" - mesh triangles: {}", dense_reconstruction.mesh.triangles.len());
|
|
|
|
// 5. Save the results.
|
|
save_reconstruction(&sparse_reconstruction, "sparse_reconstruction")?;
|
|
save_point_cloud(&dense_reconstruction.point_cloud, "dense_point_cloud.ply")?;
|
|
save_mesh(&dense_reconstruction.mesh, "mesh.obj")?;
|
|
|
|
println!("Wrote sparse_reconstruction/, dense_point_cloud.ply, mesh.obj");
|
|
Ok(())
|
|
}
|
|
|
|
fn main() {
|
|
let image_dir: PathBuf = std::env::args()
|
|
.nth(1)
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|| PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/../images")));
|
|
|
|
println!("Reconstructing from {}", image_dir.display());
|
|
if let Err(err) = reconstruct_from_images(&image_dir) {
|
|
eprintln!("error: {err}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|