use image::{Pixel, Rgba};
use rand::rngs::StdRng;
use rand::SeedableRng;
use rand_distr::{Distribution, Normal};
use super::nearest_neighbor::NearestNeighborRemapper;
use super::InterpolatedRemapper;
pub struct GaussianSamplingRemapper<'a> {
iterations: usize,
seed: u64,
normal: Normal<f64>,
nearest_neighbor: NearestNeighborRemapper<'a>,
}
impl<'a> GaussianSamplingRemapper<'a> {
#[inline(always)]
pub fn new(
palette: &'a [[u8; 3]],
mean: f64,
std_dev: f64,
iterations: usize,
lum_factor: f64,
seed: u64,
preserve: bool,
) -> Self {
let normal = Normal::new(mean, std_dev).unwrap();
let nearest_neighbor = NearestNeighborRemapper::new(palette, lum_factor, preserve);
Self {
iterations,
seed,
normal,
nearest_neighbor,
}
}
}
impl<'a> InterpolatedRemapper<'a> for GaussianSamplingRemapper<'a> {
fn remap_pixel(&self, pixel: &mut Rgba<u8>) {
let mut mean = [0f64; 3];
let mut rng: StdRng = SeedableRng::seed_from_u64(self.seed);
for _ in 0..self.iterations {
let mut pixel = *pixel;
for c in pixel.channels_mut() {
*c = (*c as f64 + self.normal.sample(&mut rng)).round() as u8
}
self.nearest_neighbor.remap_pixel(&mut pixel);
let total = self.iterations as f64;
mean[0] += pixel.0[0] as f64 / total;
mean[1] += pixel.0[1] as f64 / total;
mean[2] += pixel.0[2] as f64 / total;
}
pixel.0[0..3].copy_from_slice(&[
mean[0].round() as u8,
mean[1].round() as u8,
mean[2].round() as u8,
]);
}
}