1#![warn(missing_docs, trivial_casts, trivial_numeric_casts, unused_qualifications)]
2
3use ndarray::{arr3, Array, Array3, ArrayRef, ArrayRef3, Dimension, 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 uniform::{uniform_filter, uniform_filter1d},
23 BorderMode,
24};
25pub use interpolation::{shift, spline_filter, spline_filter1d, zoom};
26pub use measurements::{label, label_histogram, largest_connected_components, most_frequent_label};
27pub use morphology::{binary_closing, binary_dilation, binary_erosion, binary_opening};
28pub use pad::{pad, pad_to, PadMode};
29
30pub type Mask = Array3<bool>;
32
33#[derive(Clone, Debug, PartialEq)]
35pub enum Kernel3d {
36 Star,
40 Ball,
44 Full,
48}
49
50impl Kernel3d {
51 pub fn generate(&self) -> Array3<bool> {
53 match self {
54 Kernel3d::Star => arr3(&[
55 [[false, false, false], [false, true, false], [false, false, false]],
56 [[false, true, false], [true, true, true], [false, true, false]],
57 [[false, false, false], [false, true, false], [false, false, false]],
58 ]),
59 Kernel3d::Ball => arr3(&[
60 [[false, true, false], [true, true, true], [false, true, false]],
61 [[true, true, true], [true, true, true], [true, true, true]],
62 [[false, true, false], [true, true, true], [false, true, false]],
63 ]),
64 Kernel3d::Full => Array3::from_elem((3, 3, 3), true),
65 }
66 }
67}
68
69pub fn array_like<A, D, Sh>(arr: &ArrayRef<A, D>, shape: Sh, elem: A) -> Array<A, D>
72where
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<A>(mask: &ArrayRef3<A>, n: usize) -> (usize, usize, usize)
87where
88 A: Clone,
89{
90 let (width, height, depth) = mask.dim();
91 (width - n, height - n, depth - n)
92}
93
94fn round_ties_even(x: f64) -> f64 {
97 let i = x as i32;
98 let f = (x - i as f64).abs();
99 if f == 0.5 {
100 if i & 1 == 1 {
101 (x.abs() + 0.5).copysign(x)
103 } else {
104 (x.abs() - 0.5).copysign(x)
105 }
106 } else {
107 x.round()
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use crate::round_ties_even;
114
115 #[test]
116 fn test_round_ties_even() {
117 assert_eq!(round_ties_even(-2.51), -3.0);
118 assert_eq!(round_ties_even(-2.5), -2.0);
119 assert_eq!(round_ties_even(-1.5), -2.0);
120 assert_eq!(round_ties_even(-0.5), -0.0);
121 assert_eq!(round_ties_even(-0.1), 0.0);
122 assert_eq!(round_ties_even(-0.0), 0.0);
123 assert_eq!(round_ties_even(0.0), 0.0);
124 assert_eq!(round_ties_even(0.1), 0.0);
125 assert_eq!(round_ties_even(0.5), 0.0);
126 assert_eq!(round_ties_even(1.5), 2.0);
127 assert_eq!(round_ties_even(2.5), 2.0);
128 assert_eq!(round_ties_even(2.51), 3.0);
129 }
130}