pub mod constants;
use crate::{error, math};
use crate::enums::White;
use crate::error::ImgProcResult;
use crate::image::{BaseImage, Image, Number};
use std::collections::{BTreeMap, HashMap};
use std::f64::consts::{E, PI};
pub fn generate_xyz_tristimulus_vals(ref_white: &White) -> (f64, f64, f64) {
return match ref_white {
White::D50 => (96.4212, 100.0, 82.5188),
White::D65 => (95.0489, 100.0, 108.8840),
}
}
pub fn xyz_to_lab_fn(num: f64) -> f64 {
let d: f64 = 6.0 / 29.0;
if num > d.powf(3.0) {
num.powf(1.0 / 3.0)
} else {
(num / (3.0 * d * d)) + (4.0 / 29.0)
}
}
pub fn lab_to_xyz_fn(num: f64) -> f64 {
let d: f64 = 6.0 / 29.0;
if num > d {
num.powf(3.0)
} else {
3.0 * d * d * (num - (4.0 / 29.0))
}
}
pub fn generate_histogram_percentiles(input: &Image<f64>, percentiles: &mut HashMap<i32, f64>, precision: f64) {
let mut histogram = BTreeMap::new();
for y in 0..(input.info().height) {
for x in 0..(input.info().width) {
let p = (input.get_pixel(x, y)[0] * precision).round() as i32;
let count = histogram.entry(p).or_insert(1);
*count += 1;
}
}
let mut sum: i32 = 0;
let num_pixels = input.info().size() as f64;
for (key, val) in &histogram {
sum += val;
percentiles.insert(*key, sum as f64 / num_pixels);
}
}
pub fn create_lookup_table<T: Number, F>(table: &mut [T; 256], f: F)
where F: Fn(u8) -> T {
for i in 0..256 {
table[i] = f(i as u8);
}
}
pub fn generate_gaussian_kernel(size: u32, std_dev: f64) -> ImgProcResult<Vec<f64>> {
error::check_odd(size, "size")?;
let mut filter = vec![0.0; (size * size) as usize];
let k = (size - 1) / 2;
for i in 0..size {
for j in 0..size {
if i <= j {
let num = (1.0 / (2.0 * PI * std_dev * std_dev)) *
(E.powf(-(((i - k) * (i - k) + (j - k) * (j - k)) as f64) / (2.0 * std_dev * std_dev)));
filter[(i * size + j) as usize] = num;
if i != j {
filter[(j * size + i) as usize] = num;
}
}
}
}
Ok(filter)
}
pub fn generate_spatial_mat(size: u32, spatial: f64) -> ImgProcResult<Vec<f64>> {
let center = size / 2;
let mut mat = vec![0.0; (size * size) as usize];
for y in 0..(center + 1) {
for x in 0..(center + 1) {
if mat[(y * size + x) as usize] == 0.0 && !(x == center && y == center) {
let dist = math::distance(center, center, x, y);
let g = math::gaussian_fn(dist, spatial)?;
mat[(y * size + x) as usize] = g;
if x == y {
let delta = center - y;
let coord = center + delta;
mat[(coord * size + x) as usize] = g;
mat[(x * size + coord) as usize] = g;
mat[(coord * size + coord) as usize] = g;
} else if x == center {
let delta = center - y;
mat[(x * size + x - delta) as usize] = g;
mat[(x * size + x + delta) as usize] = g;
mat[((x + delta) * size + x) as usize] = g;
} else {
let delta_x = center - x;
let delta_y = center - y;
let pos_x = center + delta_x;
let pos_y = center + delta_y;
let neg_x = center - delta_x;
let neg_y = center - delta_y;
mat[(neg_x * size + neg_y) as usize] = g;
mat[(neg_y * size + pos_x) as usize] = g;
mat[(pos_x * size + neg_y) as usize] = g;
mat[(pos_y * size + neg_x) as usize] = g;
mat[(neg_x * size + pos_y) as usize] = g;
mat[(pos_y * size + pos_x) as usize] = g;
mat[(pos_x * size + pos_y) as usize] = g;
}
}
}
}
Ok(mat)
}
pub fn summed_area_table(input: &Image<f64>) -> Image<f64> {
let mut output = Image::blank(input.info());
let (width, height, channels) = input.info().whc();
let zeroes = vec![0.0; channels as usize];
for y in 0..height {
for x in 0..width {
let p_in = input.get_pixel(x, y);
let mut p_out = Vec::new();
let mut p_top = zeroes.as_slice();
let mut p_left = zeroes.as_slice();
let mut p_diag = zeroes.as_slice();
if x > 0 {
p_left = output.get_pixel(x - 1, y);
if y > 0 {
p_diag = output.get_pixel(x - 1, y - 1);
}
}
if y > 0 {
p_top = output.get_pixel(x, y - 1);
}
for c in 0..(channels as usize) {
p_out.push(p_in[c] + p_top[c] + p_left[c] - p_diag[c]);
}
output.set_pixel(x, y, &p_out);
}
}
output
}
pub fn rectangular_intensity_sum(summed_area_table: &Image<f64>, x_0: u32, y_0: u32, x_1: u32, y_1: u32) -> Vec<f64> {
let channels = summed_area_table.info().channels as usize;
let mut sum = Vec::new();
let zeroes = vec![0.0; channels];
let mut top_left = zeroes.as_slice();
let mut top_right = zeroes.as_slice();
let mut bot_left = zeroes.as_slice();
let bot_right = summed_area_table.get_pixel(x_1, y_1);
if x_0 != 0 {
bot_left = summed_area_table.get_pixel(x_0 - 1, y_1);
if y_0 != 0 {
top_left = summed_area_table.get_pixel(x_0 - 1, y_0 - 1);
}
}
if y_0 != 0 {
top_right = summed_area_table.get_pixel(x_1, y_0 - 1);
}
for i in 0..channels {
sum.push(bot_right[i] - top_right[i] - bot_left[i] + top_left[i]);
}
sum
}
pub fn get_2d_coords(i: u32, width: u32) -> (u32, u32) {
let x = i % width;
let y = (i - x) / width;
(x, y)
}