use crate::dynmatrix::DynMatrix;
use crate::traits::{MatrixMut, MatrixRef, Scalar};
use super::border::{fetch_border, BorderMode};
pub fn flip_horizontal<T: Scalar>(src: &DynMatrix<T>) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
let mut out = DynMatrix::<T>::zeros(h, w);
for j in 0..w {
let src_col = src.col_as_slice(w - 1 - j, 0);
let dst_col = out.col_as_mut_slice(j, 0);
dst_col.copy_from_slice(src_col);
}
out
}
pub fn flip_vertical<T: Scalar>(src: &DynMatrix<T>) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
let mut out = DynMatrix::<T>::zeros(h, w);
for j in 0..w {
let src_col = src.col_as_slice(j, 0);
let dst_col = out.col_as_mut_slice(j, 0);
for i in 0..h {
dst_col[i] = src_col[h - 1 - i];
}
}
out
}
pub fn rotate_90<T: Scalar>(src: &DynMatrix<T>) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
let mut out = DynMatrix::<T>::zeros(w, h);
for i in 0..h {
for j in 0..w {
out[(j, h - 1 - i)] = src[(i, j)];
}
}
out
}
pub fn rotate_180<T: Scalar>(src: &DynMatrix<T>) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
let mut out = DynMatrix::<T>::zeros(h, w);
for j in 0..w {
let src_col = src.col_as_slice(j, 0);
let dst_col = out.col_as_mut_slice(w - 1 - j, 0);
for i in 0..h {
dst_col[i] = src_col[h - 1 - i];
}
}
out
}
pub fn rotate_270<T: Scalar>(src: &DynMatrix<T>) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
let mut out = DynMatrix::<T>::zeros(w, h);
for i in 0..h {
for j in 0..w {
out[(w - 1 - j, i)] = src[(i, j)];
}
}
out
}
pub fn pad<T: Scalar>(
src: &DynMatrix<T>,
top: usize,
bottom: usize,
left: usize,
right: usize,
border: BorderMode<T>,
) -> DynMatrix<T> {
let h_in = src.nrows();
let w_in = src.ncols();
let h_out = h_in + top + bottom;
let w_out = w_in + left + right;
let mut out = DynMatrix::<T>::zeros(h_out, w_out);
for j_out in 0..w_out {
let src_j = j_out as isize - left as isize;
let dst_col = out.col_as_mut_slice(j_out, 0);
if src_j >= 0 && (src_j as usize) < w_in {
let src_col = src.col_as_slice(src_j as usize, 0);
for i_out in 0..h_out {
let src_i = i_out as isize - top as isize;
dst_col[i_out] = fetch_vertical(src_col, src_i, h_in, border);
}
} else {
for i_out in 0..h_out {
let src_i = i_out as isize - top as isize;
dst_col[i_out] = fetch_both_axes(src, src_i, src_j, border);
}
}
}
out
}
pub fn crop<T: Scalar>(
src: &DynMatrix<T>,
top: usize,
left: usize,
height: usize,
width: usize,
) -> DynMatrix<T> {
assert!(
top + height <= src.nrows() && left + width <= src.ncols(),
"crop region out of bounds"
);
let mut out = DynMatrix::<T>::zeros(height, width);
for j in 0..width {
let src_col = src.col_as_slice(left + j, top);
let dst_col = out.col_as_mut_slice(j, 0);
dst_col.copy_from_slice(&src_col[..height]);
}
out
}
pub fn resize_nearest<T: Scalar>(
src: &DynMatrix<T>,
new_rows: usize,
new_cols: usize,
) -> DynMatrix<T> {
let h_in = src.nrows();
let w_in = src.ncols();
let mut out = DynMatrix::<T>::zeros(new_rows, new_cols);
if h_in == 0 || w_in == 0 || new_rows == 0 || new_cols == 0 {
return out;
}
let mut i_src = alloc::vec![0usize; new_rows];
let mut j_src = alloc::vec![0usize; new_cols];
let h_in_i = h_in as isize;
let w_in_i = w_in as isize;
let h_out_i = new_rows as isize;
let w_out_i = new_cols as isize;
for i_out in 0..new_rows {
let num = (2 * i_out as isize + 1) * h_in_i - h_out_i;
let idx = if num <= 0 {
0
} else {
let rounded = (num + h_out_i) / (2 * h_out_i);
rounded.min(h_in_i - 1) as usize
};
i_src[i_out] = idx;
}
for j_out in 0..new_cols {
let num = (2 * j_out as isize + 1) * w_in_i - w_out_i;
let idx = if num <= 0 {
0
} else {
let rounded = (num + w_out_i) / (2 * w_out_i);
rounded.min(w_in_i - 1) as usize
};
j_src[j_out] = idx;
}
for j_out in 0..new_cols {
let src_col = src.col_as_slice(j_src[j_out], 0);
let dst_col = out.col_as_mut_slice(j_out, 0);
for i_out in 0..new_rows {
dst_col[i_out] = src_col[i_src[i_out]];
}
}
out
}
#[inline]
fn fetch_vertical<T: Scalar>(col: &[T], idx: isize, n: usize, border: BorderMode<T>) -> T {
if idx >= 0 && (idx as usize) < n {
col[idx as usize]
} else {
fetch_border(col, idx, border)
}
}
#[inline]
fn fetch_both_axes<T: Scalar>(
src: &DynMatrix<T>,
i: isize,
j: isize,
border: BorderMode<T>,
) -> T {
let h = src.nrows() as isize;
let w = src.ncols() as isize;
if i >= 0 && i < h && j >= 0 && j < w {
return src[(i as usize, j as usize)];
}
match border {
BorderMode::Zero => T::zero(),
BorderMode::Constant(c) => c,
BorderMode::Replicate => {
let ii = i.clamp(0, h - 1) as usize;
let jj = j.clamp(0, w - 1) as usize;
src[(ii, jj)]
}
BorderMode::Reflect => {
let ii = reflect(i, h);
let jj = reflect(j, w);
src[(ii, jj)]
}
}
}
#[inline]
fn reflect(idx: isize, n: isize) -> usize {
if n <= 1 {
return 0;
}
let period = 2 * (n - 1);
let mut m = idx.rem_euclid(period);
if m >= n {
m = period - m;
}
m as usize
}