use colmap::core::{Image, Feature, Result, FeatureMatch};
use colmap::feature::{FeatureConfig, MatchConfig};
use std::collections::HashMap;
fn main() -> Result<()> {
println!("=== COLMAP 特征匹配示例 ===");
let images = create_sample_images();
println!("\n🔍 SIFT 特征提取示例");
sift_feature_extraction(&images)?;
println!("\n🎯 ORB 特征提取示例");
orb_feature_extraction(&images)?;
println!("\n🔗 特征匹配示例");
feature_matching_example(&images)?;
println!("\n✅ 特征处理完成!");
Ok(())
}
fn sift_feature_extraction(images: &[Image]) -> Result<()> {
println!(" 📸 使用 SIFT 检测器处理 {} 张图像", images.len());
let _config = FeatureConfig {
max_features: 2000,
quality_threshold: 0.01,
..Default::default()
};
for image in images {
let features = simulate_sift_features(image, 1500);
println!(" - 图像 {}: {} 个 SIFT 特征", image.id, features.len());
}
println!(" ✓ SIFT 特征提取完成");
Ok(())
}
fn orb_feature_extraction(images: &[Image]) -> Result<()> {
println!(" 🎯 使用 ORB 检测器处理 {} 张图像", images.len());
let _config = FeatureConfig {
max_features: 1000,
quality_threshold: 0.02,
..Default::default()
};
for image in images {
let features = simulate_orb_features(image, 800);
println!(" - 图像 {}: {} 个 ORB 特征", image.id, features.len());
}
println!(" ✓ ORB 特征提取完成");
Ok(())
}
fn feature_matching_example(images: &[Image]) -> Result<()> {
println!(" 🔗 执行特征匹配...");
let mut all_features = HashMap::new();
for image in images {
let features = simulate_sift_features(image, 1000);
all_features.insert(image.id, features);
}
let _config = MatchConfig {
max_distance: 0.8,
cross_check: true,
..Default::default()
};
let mut total_matches = 0;
for i in 0..images.len() {
for j in (i + 1)..images.len() {
let image1_id = images[i].id;
let image2_id = images[j].id;
let features1 = &all_features[&image1_id];
let features2 = &all_features[&image2_id];
let matches = simulate_feature_matching(features1, features2, 150, image1_id, image2_id);
total_matches += matches.len();
println!(" - 图像 {} <-> {}: {} 个匹配", image1_id, image2_id, matches.len());
}
}
println!(" ✓ 特征匹配完成,总匹配数: {}", total_matches);
Ok(())
}
fn create_sample_images() -> Vec<Image> {
(0..4)
.map(|i| Image {
id: i,
name: format!("image_{:03}.jpg", i),
camera_id: 0,
size: (1920, 1080),
pose: None,
features: Vec::new(),
registered: false,
quality_score: 0.0,
})
.collect()
}
fn simulate_sift_features(image: &Image, count: usize) -> Vec<Feature> {
(0..count)
.map(|i| Feature {
point: nalgebra::Point2::new(
(i as f64 * 0.1 + image.id as f64 * 100.0) % image.size.0 as f64,
(i as f64 * 0.07 + image.id as f64 * 50.0) % image.size.1 as f64,
),
descriptor: vec![((i * 17 + image.id as usize * 23) % 256) as u8; 128],
scale: 1.0,
angle: 0.0,
response: 0.5,
octave: 0,
point3d_id: None,
})
.collect()
}
fn simulate_orb_features(image: &Image, count: usize) -> Vec<Feature> {
(0..count)
.map(|i| Feature {
point: nalgebra::Point2::new(
(i as f64 * 0.13 + image.id as f64 * 80.0) % image.size.0 as f64,
(i as f64 * 0.11 + image.id as f64 * 60.0) % image.size.1 as f64,
),
descriptor: vec![((i * 19 + image.id as usize * 31) % 256) as u8; 32],
scale: 1.0,
angle: 0.0,
response: 0.5,
octave: 0,
point3d_id: None,
})
.collect()
}
fn simulate_feature_matching(
features1: &[Feature],
features2: &[Feature],
max_matches: usize,
image1_id: u32,
image2_id: u32,
) -> Vec<FeatureMatch> {
let actual_matches = max_matches.min(features1.len()).min(features2.len());
(0..actual_matches)
.map(|i| FeatureMatch {
image1_id,
image2_id,
feature1_idx: i,
feature2_idx: i,
distance: 0.3 + (i as f32 * 0.001) % 0.4,
confidence: 0.8 - (i as f32 * 0.001),
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample_images_creation() {
let images = create_sample_images();
assert_eq!(images.len(), 4);
for (i, image) in images.iter().enumerate() {
assert_eq!(image.id, i as u32);
assert_eq!(image.size.0, 1920);
assert_eq!(image.size.1, 1080);
}
}
#[test]
fn test_sift_features_simulation() {
let image = Image {
id: 0,
name: "test.jpg".to_string(),
camera_id: 0,
size: (640, 480),
pose: None,
features: Vec::new(),
registered: false,
quality_score: 0.0,
};
let features = simulate_sift_features(&image, 100);
assert_eq!(features.len(), 100);
assert_eq!(features[0].descriptor.len(), 128);
}
#[test]
fn test_orb_features_simulation() {
let image = Image {
id: 1,
name: "test.jpg".to_string(),
camera_id: 0,
size: (640, 480),
pose: None,
features: Vec::new(),
registered: false,
quality_score: 0.0,
};
let features = simulate_orb_features(&image, 50);
assert_eq!(features.len(), 50);
assert_eq!(features[0].descriptor.len(), 32);
}
#[test]
fn test_feature_matching_simulation() {
let features1 = vec![
Feature {
point: nalgebra::Point2::new(100.0, 100.0),
descriptor: vec![0u8; 128],
scale: 1.0,
angle: 0.0,
response: 0.5,
octave: 0,
point3d_id: None,
},
Feature {
point: nalgebra::Point2::new(200.0, 200.0),
descriptor: vec![1u8; 128],
scale: 1.0,
angle: 0.0,
response: 0.5,
octave: 0,
point3d_id: None,
},
];
let features2 = vec![
Feature {
point: nalgebra::Point2::new(105.0, 105.0),
descriptor: vec![0u8; 128],
scale: 1.0,
angle: 0.0,
response: 0.5,
octave: 0,
point3d_id: None,
},
Feature {
point: nalgebra::Point2::new(205.0, 205.0),
descriptor: vec![1u8; 128],
scale: 1.0,
angle: 0.0,
response: 0.5,
octave: 0,
point3d_id: None,
},
];
let matches = simulate_feature_matching(&features1, &features2, 10, 0, 1);
assert_eq!(matches.len(), 2);
assert!(matches[0].distance >= 0.3 && matches[0].distance <= 0.7);
}
}