use crate::hist_support::{
blerp, cdf, clip_hist_clahe, make_histogram_region, minmax, AheImplementation, ClaheGridSize,
ImageHistogram,
};
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
use rayon::prelude::ParallelSliceMut;
#[allow(dead_code)]
pub(crate) fn clahe_impl_u16_proxy<const CHANNELS: usize, const IMPLEMENTATION: u8>(
src: &[u8],
src_stride: u32,
dst: &mut [u8],
dst_stride: u32,
width: u32,
height: u32,
threshold: f32,
clahe_grid_size: ClaheGridSize,
bins_count: usize,
destructuring: fn(&[u8], u32, &mut [u16], u32, &mut [f32], u32, u32, f32),
structuring: fn(&[u16], u32, &[f32], &mut [u8], u32, u32, u32, f32),
) {
if bins_count <= 1 {
panic!("Bins count must be more than one");
}
if clahe_grid_size.w == 0 || clahe_grid_size.h == 0 {
panic!("zero sized grid is not accepted");
}
let implementation: AheImplementation = IMPLEMENTATION.into();
let horizontal_tile_size = width / clahe_grid_size.w;
let vertical_tile_size = height / clahe_grid_size.h;
let tiles_horizontal = width / horizontal_tile_size;
let tiles_vertical = height / vertical_tile_size;
let mut hsv_image: Vec<u16> = vec![0u16; width as usize * height as usize];
let hsv_stride = width as usize;
let mut color_planes: Vec<f32> = vec![0.; width as usize * height as usize * (CHANNELS - 1)];
destructuring(
src,
src_stride,
&mut hsv_image,
hsv_stride as u32 * std::mem::size_of::<u16>() as u32,
&mut color_planes,
width,
height,
(bins_count - 1) as f32,
);
let mut histograms: Vec<Vec<ImageHistogram>> = vec![];
let max_bins = bins_count - 1;
for h in 0..tiles_vertical {
let mut regions_hist: Vec<ImageHistogram> = vec![];
for w in 0..tiles_horizontal {
let start_x = w * horizontal_tile_size;
let start_y = h * vertical_tile_size;
let mut end_x = (w + 1) * horizontal_tile_size;
if w + 1 == tiles_horizontal {
end_x = width;
}
let mut end_y = (h + 1) * vertical_tile_size;
if h + 1 == tiles_vertical {
end_y = height;
}
let mut region_hist = make_histogram_region::<0, 1, u16>(
&hsv_image,
hsv_stride as u32,
start_x,
end_x,
start_y,
end_y,
bins_count,
);
let mut bins = region_hist.bins;
if implementation == AheImplementation::Clahe {
clip_hist_clahe(
&mut bins,
threshold,
(end_x - start_x) as usize,
(end_y - start_y) as usize,
);
}
cdf(&mut bins);
let (min_bin, _) = minmax(&bins);
let distance_r =
1f64 / ((end_y - start_y) as f64 * (end_x - start_x) as f64 - min_bin as f64);
if distance_r != 0f64 {
for i in 0..bins_count {
unsafe {
*bins.get_unchecked_mut(i) = (max_bins as f64
* (*bins.get_unchecked(i) as f64 - min_bin as f64)
* distance_r)
.round()
.min(max_bins as f64)
.max(0f64) as u64;
}
}
}
region_hist.bins = bins;
regions_hist.push(region_hist);
}
histograms.push(regions_hist);
}
let max_bins = bins_count - 1;
hsv_image
.par_chunks_exact_mut(hsv_stride)
.enumerate()
.for_each(|(y, hsv_image)| {
for (x, hsv) in hsv_image.iter_mut().enumerate() {
let c_x_f =
(x as f32 - horizontal_tile_size as f32 / 2f32) / horizontal_tile_size as f32;
let r_y_f =
(y as f32 - vertical_tile_size as f32 / 2f32) / vertical_tile_size as f32;
let x1 = (x as f32
- ((c_x_f as i64) as f32 + 0.5f32) * horizontal_tile_size as f32)
/ horizontal_tile_size as f32;
let y1 = (y as f32 - ((r_y_f as i64) as f32 + 0.5f32) * vertical_tile_size as f32)
/ vertical_tile_size as f32;
let value = (*hsv).min(max_bins as u16) as usize;
let r_y = r_y_f.max(0f32) as i64;
let c_x = c_x_f.max(0f32) as i64;
let r = (r_y as usize).min(tiles_vertical as usize - 1usize);
let c = (c_x as usize).min(tiles_horizontal as usize - 1usize);
unsafe {
let bin1 = *histograms
.get_unchecked(r)
.get_unchecked(c)
.bins
.get_unchecked(value) as f32;
let bin2 = *histograms
.get_unchecked(r)
.get_unchecked((c + 1).min(tiles_horizontal as usize - 1usize))
.bins
.get_unchecked(value) as f32;
let bin3 = *histograms
.get_unchecked((r + 1).min(tiles_vertical as usize - 1usize))
.get_unchecked(c)
.bins
.get_unchecked(value) as f32;
let bin4 = *histograms
.get_unchecked((r + 1).min(tiles_vertical as usize - 1usize))
.get_unchecked((c + 1).min(tiles_horizontal as usize - 1usize))
.bins
.get_unchecked(value) as f32;
let interpolated = blerp(bin1, bin2, bin3, bin4, x1, y1);
*hsv = interpolated.min(max_bins as f32).max(0f32) as u16;
}
}
});
structuring(
&hsv_image,
hsv_stride as u32 * std::mem::size_of::<u16>() as u32,
&color_planes,
dst,
dst_stride,
width,
height,
(bins_count - 1) as f32,
);
}