use crate::arena_roi::copy_roi;
use crate::border_mode::{reflect_index, reflect_index_101, BorderMode, MorphScalar};
use crate::filter_op_declare::Arena;
use crate::structuring_element::KernelShape;
use num_traits::AsPrimitive;
pub fn make_arena<T, const CN: usize>(
image: &[T],
width: u32,
height: u32,
kernel_size: KernelShape,
border_mode: BorderMode,
border_scalar: MorphScalar,
) -> Arena<T>
where
T: Default + Copy + 'static,
f64: AsPrimitive<T>,
{
let (kw, kh) = (kernel_size.width, kernel_size.height);
let pad_w = kw / 2;
let pad_h = kh / 2;
let new_height = height as usize + 2 * pad_h;
let new_width = width as usize + 2 * pad_w;
let mut padded_image = vec![T::default(); new_height * new_width * CN];
let old_stride = width as usize * CN;
let new_stride = new_width * CN;
unsafe {
copy_roi(
padded_image.get_unchecked_mut(pad_h * new_stride + (pad_w * CN)..),
image,
new_stride,
old_stride,
height as usize,
);
}
let filling_ranges = [
(0..pad_h, 0..new_width), (pad_h..(new_height - pad_h), 0..pad_w), ((height as usize + pad_h)..new_height, 0..new_width), (
pad_h..(new_height - pad_h),
(width as usize + pad_w)..new_width,
), ];
match border_mode {
BorderMode::Clamp => {
for ranges in filling_ranges.iter() {
for i in ranges.0.clone() {
for j in ranges.1.clone() {
let y = i.saturating_sub(pad_h).min(height as usize - 1);
let x = j.saturating_sub(pad_w).min(width as usize - 1);
unsafe {
let v_dst = i * new_stride + j * CN;
let v_src = y * old_stride + x * CN;
for i in 0..CN {
*padded_image.get_unchecked_mut(v_dst + i) =
*image.get_unchecked(v_src + i);
}
}
}
}
}
}
BorderMode::Wrap => {
for ranges in filling_ranges.iter() {
for i in ranges.0.clone() {
for j in ranges.1.clone() {
let y = (i as i64 - pad_h as i64).rem_euclid(height as i64) as usize;
let x = (j as i64 - pad_w as i64).rem_euclid(width as i64) as usize;
unsafe {
let v_dst = i * new_stride + j * CN;
let v_src = y * old_stride + x * CN;
for i in 0..CN {
*padded_image.get_unchecked_mut(v_dst + i) =
*image.get_unchecked(v_src + i);
}
}
}
}
}
}
BorderMode::Reflect => {
for ranges in filling_ranges.iter() {
for i in ranges.0.clone() {
for j in ranges.1.clone() {
let y = reflect_index(i as isize - pad_h as isize, height as isize);
let x = reflect_index(j as isize - pad_w as isize, width as isize);
unsafe {
let v_dst = i * new_stride + j * CN;
let v_src = y * old_stride + x * CN;
for i in 0..CN {
*padded_image.get_unchecked_mut(v_dst + i) =
*image.get_unchecked(v_src + i);
}
}
}
}
}
}
BorderMode::Reflect101 => {
for ranges in filling_ranges.iter() {
for i in ranges.0.clone() {
for j in ranges.1.clone() {
let y = reflect_index_101(i as isize - pad_h as isize, height as isize);
let x = reflect_index_101(j as isize - pad_w as isize, width as isize);
unsafe {
let v_dst = i * new_stride + j * CN;
let v_src = y * old_stride + x * CN;
for i in 0..CN {
*padded_image.get_unchecked_mut(v_dst + i) =
*image.get_unchecked(v_src + i);
}
}
}
}
}
}
BorderMode::Constant => {
for ranges in filling_ranges.iter() {
for i in ranges.0.clone() {
for j in ranges.1.clone() {
unsafe {
let v_dst = i * new_stride + j * CN;
for i in 0..CN {
*padded_image.get_unchecked_mut(v_dst + i) = border_scalar[i].as_();
}
}
}
}
}
}
}
Arena::new(padded_image, new_width, new_height, pad_w, pad_h, CN)
}