#![warn(missing_docs, trivial_casts, trivial_numeric_casts, unused_qualifications)]
use ndarray::{arr3, Array, Array3, ArrayRef, ArrayRef3, Dimension, ShapeBuilder};
mod filters;
mod interpolation;
mod measurements;
mod morphology;
mod pad;
pub use filters::{
con_corr::{convolve, convolve1d, correlate, correlate1d, prewitt, sobel},
gaussian::{gaussian_filter, gaussian_filter1d},
median::median_filter,
min_max::{
maximum_filter, maximum_filter1d, maximum_filter1d_to, minimum_filter, minimum_filter1d,
minimum_filter1d_to,
},
uniform::{uniform_filter, uniform_filter1d},
BorderMode,
};
pub use interpolation::{shift, spline_filter, spline_filter1d, zoom};
pub use measurements::{label, label_histogram, largest_connected_components, most_frequent_label};
pub use morphology::{binary_closing, binary_dilation, binary_erosion, binary_opening};
pub use pad::{pad, pad_to, PadMode};
pub type Mask = Array3<bool>;
#[derive(Clone, Debug, PartialEq)]
pub enum Kernel3d {
Star,
Ball,
Full,
}
impl Kernel3d {
pub fn generate(&self) -> Array3<bool> {
match self {
Kernel3d::Star => arr3(&[
[[false, false, false], [false, true, false], [false, false, false]],
[[false, true, false], [true, true, true], [false, true, false]],
[[false, false, false], [false, true, false], [false, false, false]],
]),
Kernel3d::Ball => arr3(&[
[[false, true, false], [true, true, true], [false, true, false]],
[[true, true, true], [true, true, true], [true, true, true]],
[[false, true, false], [true, true, true], [false, true, false]],
]),
Kernel3d::Full => Array3::from_elem((3, 3, 3), true),
}
}
}
pub fn array_like<A, D, Sh>(arr: &ArrayRef<A, D>, shape: Sh, elem: A) -> Array<A, D>
where
A: Clone,
D: Dimension,
Sh: ShapeBuilder<Dim = D>,
{
if arr.is_standard_layout() {
Array::from_elem(shape, elem)
} else {
Array::from_elem(shape.f(), elem)
}
}
pub fn dim_minus<A>(mask: &ArrayRef3<A>, n: usize) -> (usize, usize, usize)
where
A: Clone,
{
let (width, height, depth) = mask.dim();
(width - n, height - n, depth - n)
}
fn round_ties_even(x: f64) -> f64 {
let i = x as i32;
let f = (x - i as f64).abs();
if f == 0.5 {
if i & 1 == 1 {
(x.abs() + 0.5).copysign(x)
} else {
(x.abs() - 0.5).copysign(x)
}
} else {
x.round()
}
}
#[cfg(test)]
mod tests {
use crate::round_ties_even;
#[test]
fn test_round_ties_even() {
assert_eq!(round_ties_even(-2.51), -3.0);
assert_eq!(round_ties_even(-2.5), -2.0);
assert_eq!(round_ties_even(-1.5), -2.0);
assert_eq!(round_ties_even(-0.5), -0.0);
assert_eq!(round_ties_even(-0.1), 0.0);
assert_eq!(round_ties_even(-0.0), 0.0);
assert_eq!(round_ties_even(0.0), 0.0);
assert_eq!(round_ties_even(0.1), 0.0);
assert_eq!(round_ties_even(0.5), 0.0);
assert_eq!(round_ties_even(1.5), 2.0);
assert_eq!(round_ties_even(2.5), 2.0);
assert_eq!(round_ties_even(2.51), 3.0);
}
}