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 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<S, A, D, Sh>(arr: &ArrayBase<S, D>, shape: Sh, elem: A) -> Array<A, D>
72where
73 S: Data<Elem = A>,
74 A: Clone,
75 D: Dimension,
76 Sh: ShapeBuilder<Dim = D>,
77{
78 if arr.is_standard_layout() {
80 Array::from_elem(shape, elem)
81 } else {
82 Array::from_elem(shape.f(), elem)
83 }
84}
85
86pub fn dim_minus<S, A>(mask: &ArrayBase<S, Ix3>, n: usize) -> (usize, usize, usize)
88where
89 S: Data<Elem = A>,
90 A: Clone,
91{
92 let (width, height, depth) = mask.dim();
93 (width - n, height - n, depth - n)
94}
95
96fn round_ties_even(x: f64) -> f64 {
99 let i = x as i32;
100 let f = (x - i as f64).abs();
101 if f == 0.5 {
102 if i & 1 == 1 {
103 (x.abs() + 0.5).copysign(x)
105 } else {
106 (x.abs() - 0.5).copysign(x)
107 }
108 } else {
109 x.round()
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use crate::round_ties_even;
116
117 #[test]
118 fn test_round_ties_even() {
119 assert_eq!(round_ties_even(-2.51), -3.0);
120 assert_eq!(round_ties_even(-2.5), -2.0);
121 assert_eq!(round_ties_even(-1.5), -2.0);
122 assert_eq!(round_ties_even(-0.5), -0.0);
123 assert_eq!(round_ties_even(-0.1), 0.0);
124 assert_eq!(round_ties_even(-0.0), 0.0);
125 assert_eq!(round_ties_even(0.0), 0.0);
126 assert_eq!(round_ties_even(0.1), 0.0);
127 assert_eq!(round_ties_even(0.5), 0.0);
128 assert_eq!(round_ties_even(1.5), 2.0);
129 assert_eq!(round_ties_even(2.5), 2.0);
130 assert_eq!(round_ties_even(2.51), 3.0);
131 }
132}