1#![warn(missing_docs, trivial_casts, trivial_numeric_casts, unused_qualifications)]
2
3use ndarray::{arr3, Array, Array3, ArrayBase, Data, Dimension, Ix3, ShapeBuilder};
7
8mod filters;
9mod interpolation;
10mod measurements;
11mod morphology;
12mod pad;
13
14pub use filters::{
15 con_corr::{convolve, convolve1d, correlate, correlate1d, prewitt, sobel},
16 gaussian::{gaussian_filter, gaussian_filter1d},
17 median::median_filter,
18 min_max::{
19 maximum_filter, maximum_filter1d, maximum_filter1d_to, minimum_filter, minimum_filter1d,
20 minimum_filter1d_to,
21 },
22 BorderMode,
23};
24pub use interpolation::{shift, spline_filter, spline_filter1d, zoom};
25pub use measurements::{label, label_histogram, largest_connected_components, most_frequent_label};
26pub use morphology::{binary_closing, binary_dilation, binary_erosion, binary_opening};
27pub use pad::{pad, pad_to, PadMode};
28
29pub type Mask = Array3<bool>;
31
32#[derive(Clone, Debug, PartialEq)]
34pub enum Kernel3d {
35 Star,
39 Ball,
43 Full,
47}
48
49impl Kernel3d {
50 pub fn generate(&self) -> Array3<bool> {
52 match self {
53 Kernel3d::Star => arr3(&[
54 [[false, false, false], [false, true, false], [false, false, false]],
55 [[false, true, false], [true, true, true], [false, true, false]],
56 [[false, false, false], [false, true, false], [false, false, false]],
57 ]),
58 Kernel3d::Ball => arr3(&[
59 [[false, true, false], [true, true, true], [false, true, false]],
60 [[true, true, true], [true, true, true], [true, true, true]],
61 [[false, true, false], [true, true, true], [false, true, false]],
62 ]),
63 Kernel3d::Full => Array3::from_elem((3, 3, 3), true),
64 }
65 }
66}
67
68pub fn array_like<S, A, D, Sh>(arr: &ArrayBase<S, D>, shape: Sh, elem: A) -> Array<A, D>
71where
72 S: Data<Elem = A>,
73 A: Clone,
74 D: Dimension,
75 Sh: ShapeBuilder<Dim = D>,
76{
77 if arr.is_standard_layout() {
79 Array::from_elem(shape, elem)
80 } else {
81 Array::from_elem(shape.f(), elem)
82 }
83}
84
85pub fn dim_minus<S, A>(mask: &ArrayBase<S, Ix3>, n: usize) -> (usize, usize, usize)
87where
88 S: Data<Elem = A>,
89 A: Clone,
90{
91 let (width, height, depth) = mask.dim();
92 (width - n, height - n, depth - n)
93}
94
95fn round_ties_even(x: f64) -> f64 {
98 let i = x as i32;
99 let f = (x - i as f64).abs();
100 if f == 0.5 {
101 if i & 1 == 1 {
102 (x.abs() + 0.5).copysign(x)
104 } else {
105 (x.abs() - 0.5).copysign(x)
106 }
107 } else {
108 x.round()
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use crate::round_ties_even;
115
116 #[test]
117 fn test_round_ties_even() {
118 assert_eq!(round_ties_even(-2.51), -3.0);
119 assert_eq!(round_ties_even(-2.5), -2.0);
120 assert_eq!(round_ties_even(-1.5), -2.0);
121 assert_eq!(round_ties_even(-0.5), -0.0);
122 assert_eq!(round_ties_even(-0.1), 0.0);
123 assert_eq!(round_ties_even(-0.0), 0.0);
124 assert_eq!(round_ties_even(0.0), 0.0);
125 assert_eq!(round_ties_even(0.1), 0.0);
126 assert_eq!(round_ties_even(0.5), 0.0);
127 assert_eq!(round_ties_even(1.5), 2.0);
128 assert_eq!(round_ties_even(2.5), 2.0);
129 assert_eq!(round_ties_even(2.51), 3.0);
130 }
131}