use crate::circular_feature_descriptor_matcher::CircularFeatureDescriptorMatcher;
use crate::circular_feature_grid;
use crate::correspondence_mapping_algorithm::CorrespondenceMappingAlgorithm;
use crate::dense_photo_map::DensePhotoMap;
use crate::photo::Photo;
use std::collections::HashMap;
use std::sync::Arc;
pub const DEFAULT_SEED: u64 = 0x5049_5845_4C4D_4150;
pub struct PixelMapProcessor {
photo1: Arc<Photo>,
photo2: Arc<Photo>,
ocm_manager1: CorrespondenceMappingAlgorithm,
ocm_manager2: CorrespondenceMappingAlgorithm,
total_comparisons: usize,
initial_photo_width: usize,
seed: u64,
algorithms_built: u64,
scaled: HashMap<(usize, usize), Arc<Photo>>,
}
impl PixelMapProcessor {
pub fn new(photo1: Arc<Photo>, photo2: Arc<Photo>, photo_width: usize) -> Self {
Self::with_seed(photo1, photo2, photo_width, DEFAULT_SEED)
}
pub fn with_seed(
photo1: Arc<Photo>,
photo2: Arc<Photo>,
photo_width: usize,
seed: u64,
) -> Self {
let dummy_photo = Photo::default();
PixelMapProcessor {
photo1,
photo2,
ocm_manager1: CorrespondenceMappingAlgorithm::new(
photo_width,
&dummy_photo,
&dummy_photo,
5,
5,
seed,
),
ocm_manager2: CorrespondenceMappingAlgorithm::new(
photo_width,
&dummy_photo,
&dummy_photo,
5,
5,
seed,
),
total_comparisons: 0,
initial_photo_width: photo_width,
seed,
algorithms_built: 0,
scaled: HashMap::new(),
}
}
fn next_seed(&mut self) -> u64 {
let n = self.algorithms_built;
self.algorithms_built += 1;
self.seed ^ n.wrapping_mul(0x9E37_79B9_7F4A_7C15)
}
fn scaled(&mut self, which: usize, width: usize) -> Arc<Photo> {
if let Some(p) = self.scaled.get(&(which, width)) {
return p.clone();
}
let src = if which == 0 {
&self.photo1
} else {
&self.photo2
};
let p = Arc::new(src.scaled_to_width(width));
self.scaled.insert((which, width), p.clone());
p
}
pub fn init(&mut self) {
let width = usize::min(self.initial_photo_width, self.photo1.width);
let photo1scaled = self.scaled(0, width);
let photo2scaled = self.scaled(1, width);
let image1 = circular_feature_grid::CircularFeatureGrid::new(
&photo1scaled,
photo1scaled.width,
photo1scaled.height,
10,
);
let image2 = circular_feature_grid::CircularFeatureGrid::new(
&photo2scaled,
photo2scaled.width,
photo2scaled.height,
10,
);
let circle_area_info_matcher = CircularFeatureDescriptorMatcher::new();
let pairs = circle_area_info_matcher.match_areas(&image1, &image2);
let w = photo1scaled.width;
let (s1, s2) = (self.scaled(0, w), self.scaled(1, w));
let (seed1, seed2) = (self.next_seed(), self.next_seed());
let mut ocm_manager1 =
CorrespondenceMappingAlgorithm::with_scaled(s1.clone(), s2.clone(), 5, 5, seed1);
let mut ocm_manager2 = CorrespondenceMappingAlgorithm::with_scaled(s2, s1, 5, 5, seed2);
for m in pairs {
let vv = -m.angle_delta;
ocm_manager1.add_init_point(m.x1 as f32, m.y1 as f32, m.x2 as f32, m.y2 as f32, vv);
ocm_manager2.add_init_point(m.x2 as f32, m.y2 as f32, m.x1 as f32, m.y1 as f32, -vv);
}
ocm_manager1.run_until_done();
ocm_manager2.run_until_done();
self.total_comparisons =
ocm_manager1.total_comparisons() + ocm_manager2.total_comparisons();
self.ocm_manager1 = ocm_manager1;
self.ocm_manager2 = ocm_manager2;
}
pub fn total_comparisons(&self) -> usize {
self.total_comparisons
}
pub fn iterate(
&mut self,
photo_width: usize,
grid_cell_size: usize,
neighborhood_radius: usize,
smooth_iterations: usize,
clean_max_dist: f32,
) {
let mut pm1 = self.ocm_manager1.get_photo_mapping();
let mut pm2 = self.ocm_manager2.get_photo_mapping();
pm1.remove_outliers(&pm2, clean_max_dist);
pm2.remove_outliers(&pm1, clean_max_dist);
let pm1_smooth = pm1.smooth_grid_points_n_times(smooth_iterations);
let pm2_smooth = pm2.smooth_grid_points_n_times(smooth_iterations);
let (s1, s2) = (self.scaled(0, photo_width), self.scaled(1, photo_width));
let (seed1, seed2) = (self.next_seed(), self.next_seed());
let mut ocm_manager1 = CorrespondenceMappingAlgorithm::with_scaled(
s1.clone(),
s2.clone(),
grid_cell_size,
neighborhood_radius,
seed1,
);
let mut ocm_manager2 = CorrespondenceMappingAlgorithm::with_scaled(
s2,
s1,
grid_cell_size,
neighborhood_radius,
seed2,
);
ocm_manager1.init_from_photomapping(&pm1_smooth);
ocm_manager2.init_from_photomapping(&pm2_smooth);
ocm_manager1.run_until_done();
ocm_manager2.run_until_done();
self.total_comparisons +=
ocm_manager1.total_comparisons() + ocm_manager2.total_comparisons();
self.ocm_manager1 = ocm_manager1;
self.ocm_manager2 = ocm_manager2;
}
pub fn finish(&mut self, clean_max_dist: f32) -> (DensePhotoMap, DensePhotoMap) {
let mut pm1 = self.ocm_manager1.get_photo_mapping();
let mut pm2 = self.ocm_manager2.get_photo_mapping();
pm1.remove_outliers(&pm2, clean_max_dist);
pm2.remove_outliers(&pm1, clean_max_dist);
(pm1, pm2)
}
pub fn matched_area(&self) -> f32 {
let pm1 = self.ocm_manager1.get_photo_mapping();
let pm2 = self.ocm_manager2.get_photo_mapping();
let mut pm1 = pm1.clone();
let mut pm2 = pm2.clone();
pm1.remove_outliers(&pm2, 2.0);
pm2.remove_outliers(&pm1, 2.0);
pm1.calculate_used_area()
}
}