Skip to content

Commit 76c71e6

Browse files
authored
Merge pull request #16 from stefan-k/ndarray_0.13
update of ndarray, ndarray-stats, ndarray-rand and rand
2 parents fdaf03a + a6a9564 commit 76c71e6

File tree

5 files changed

+56
-65
lines changed

5 files changed

+56
-65
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ categories = ["Science", "Multimedia"]
1111
edition = "2018"
1212

1313
[dependencies]
14-
ndarray = "0.12"
15-
ndarray-stats = "0.2"
14+
ndarray = "0.13"
15+
ndarray-stats = "0.3"
1616
noisy_float = "0.1"
1717
num-traits = "0.2"
1818

1919
[dev-dependencies]
20-
ndarray-rand = "0.9.0"
21-
rand = "0.6.5"
20+
ndarray-rand = "0.11.0"
21+
rand = "0.7"
2222
assert_approx_eq = "1.1.0"
2323
noisy_float = "0.1.11"

src/enhancement/histogram_equalisation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use ndarray::prelude::*;
33
use ndarray_stats::{histogram::Grid, HistogramExt};
44
use num_traits::cast::{FromPrimitive, ToPrimitive};
55
use num_traits::{Num, NumAssignOps};
6+
use std::iter::FromIterator;
67

78
/// Extension trait to implement histogram equalisation on other types
89
pub trait HistogramEqExt<A>

src/processing/filter.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use ndarray_stats::interpolate::*;
55
use ndarray_stats::Quantile1dExt;
66
use noisy_float::types::n64;
77
use num_traits::{FromPrimitive, Num, ToPrimitive};
8+
use std::iter::FromIterator;
89
use std::marker::PhantomData;
910

1011
/// Median filter, given a region to move over the image, each pixel is given
@@ -32,7 +33,7 @@ where
3233
let mut result = Array3::<T>::zeros(self.dim());
3334
Zip::indexed(self.windows(region)).apply(|(i, j, k), window| {
3435
let mut flat_window = Array::from_iter(window.iter()).mapv(|x| *x);
35-
if let Ok(v) = flat_window.quantile_mut(n64(0.5f64), &Linear{}) {
36+
if let Ok(v) = flat_window.quantile_mut(n64(0.5f64), &Linear {}) {
3637
result
3738
.get_mut([i + r_offset, j + c_offset, k])
3839
.map(|r| *r = v);

src/processing/kernels.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,14 @@ mod tests {
304304

305305
#[test]
306306
fn test_laplace_filters() {
307-
let standard = LaplaceFilter::build().unwrap();
307+
let standard: Array3<i64> = LaplaceFilter::build().unwrap();
308308
assert_eq!(
309309
standard,
310310
arr3(&[[[0], [-1], [0]], [[-1], [4], [-1]], [[0], [-1], [0]]])
311311
);
312312

313-
let standard = LaplaceFilter::build_with_params(LaplaceType::Diagonal).unwrap();
313+
let standard: Array3<i64> =
314+
LaplaceFilter::build_with_params(LaplaceType::Diagonal).unwrap();
314315
assert_eq!(
315316
standard,
316317
arr3(&[[[-1], [-1], [-1]], [[-1], [8], [-1]], [[-1], [-1], [-1]]])

src/processing/threshold.rs

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
use crate::core::PixelBound;
12
use crate::core::{ColourModel, Image};
2-
use crate::core::{PixelBound};
33
use crate::processing::*;
44
use ndarray::prelude::*;
5-
use num_traits::cast::{FromPrimitive};
6-
use num_traits::cast::{ToPrimitive};
7-
use ndarray_stats::QuantileExt;
5+
use ndarray_stats::histogram::{Bins, Edges, Grid};
86
use ndarray_stats::HistogramExt;
9-
use ndarray_stats::histogram::{Grid, Bins, Edges};
7+
use ndarray_stats::QuantileExt;
8+
use num_traits::cast::FromPrimitive;
9+
use num_traits::cast::ToPrimitive;
1010
use num_traits::{Num, NumAssignOps};
11+
use std::iter::FromIterator;
1112
use std::marker::PhantomData;
1213

1314
// Development
@@ -16,14 +17,13 @@ use assert_approx_eq::assert_approx_eq;
1617
#[cfg(test)]
1718
use noisy_float::types::n64;
1819

19-
2020
/// Runs the Otsu Thresholding algorithm on a type T
2121
pub trait ThresholdOtsuExt<T> {
2222
/// Output type, this is different as Otsu outputs a binary image
2323
type Output;
2424

25-
/// Run the Otsu threshold detection algorithm with the
26-
/// given parameters. Due to Otsu being specified as working
25+
/// Run the Otsu threshold detection algorithm with the
26+
/// given parameters. Due to Otsu being specified as working
2727
/// on greyscale images all current implementations
2828
/// assume a single channel image returning an error otherwise.
2929
fn threshold_otsu(&self) -> Result<Self::Output, Error>;
@@ -34,8 +34,8 @@ pub trait ThresholdMeanExt<T> {
3434
/// Output type, this is different as Otsu outputs a binary image
3535
type Output;
3636

37-
/// Run the Otsu threshold detection algorithm with the
38-
/// given parameters. Due to Otsu being specified as working
37+
/// Run the Otsu threshold detection algorithm with the
38+
/// given parameters. Due to Otsu being specified as working
3939
/// on greyscale images all current implementations
4040
/// assume a single channel image returning an error otherwise.
4141
fn threshold_mean(&self) -> Result<Self::Output, Error>;
@@ -60,7 +60,7 @@ where
6060

6161
impl<T> ThresholdOtsuExt<T> for Array3<T>
6262
where
63-
T: Copy + Clone + Ord + Num + NumAssignOps + ToPrimitive + FromPrimitive
63+
T: Copy + Clone + Ord + Num + NumAssignOps + ToPrimitive + FromPrimitive,
6464
{
6565
type Output = Array3<bool>;
6666

@@ -76,60 +76,58 @@ where
7676
}
7777

7878
///
79-
/// Calculates Otsu's threshold
80-
/// Works per channel, but currently
79+
/// Calculates Otsu's threshold
80+
/// Works per channel, but currently
8181
/// assumes grayscale (see the error above if number of channels is > 1
82-
/// i.e. single channel; otherwise we need to output all 3 threshold values).
82+
/// i.e. single channel; otherwise we need to output all 3 threshold values).
8383
/// Todo: Add optional nbins
8484
///
8585
fn calculate_threshold_otsu<T>(mat: &Array3<T>) -> Result<f64, Error>
8686
where
87-
T: Copy + Clone + Ord + Num + NumAssignOps + ToPrimitive + FromPrimitive
87+
T: Copy + Clone + Ord + Num + NumAssignOps + ToPrimitive + FromPrimitive,
8888
{
8989
let mut threshold = 0.0;
9090
let n_bins = 255;
9191
for c in mat.axis_iter(Axis(2)) {
92-
let scale_factor = (n_bins) as f64
93-
/(c.max().unwrap().to_f64().unwrap());
92+
let scale_factor = (n_bins) as f64 / (c.max().unwrap().to_f64().unwrap());
9493
let edges_vec: Vec<u8> = (0..n_bins).collect();
9594
let grid = Grid::from(vec![Bins::new(Edges::from(edges_vec))]);
96-
95+
9796
// get the histogram
9897
let flat = Array::from_iter(c.iter()).insert_axis(Axis(1));
99-
let flat2 = flat.mapv(
100-
|x| ((*x).to_f64().unwrap() * scale_factor).to_u8().unwrap()
101-
);
98+
let flat2 = flat.mapv(|x| ((*x).to_f64().unwrap() * scale_factor).to_u8().unwrap());
10299
let hist = flat2.histogram(grid);
103-
// Straight out of wikipedia:
104-
let counts = hist.counts();
100+
// Straight out of wikipedia:
101+
let counts = hist.counts();
105102
let total = counts.sum().to_f64().unwrap();
106103
let counts = Array::from_iter(counts.iter());
107-
// NOTE: Could use the cdf generation for skimage-esque implementation
108-
// which entails a cumulative sum of the standard histogram
104+
// NOTE: Could use the cdf generation for skimage-esque implementation
105+
// which entails a cumulative sum of the standard histogram
109106
let mut sum_b = 0.0;
110107
let mut weight_b = 0.0;
111108
let mut maximum = 0.0;
112109
let mut level = 0.0;
113110
let mut sum_intensity = 0.0;
114-
for (index, count) in counts.indexed_iter(){
111+
for (index, count) in counts.indexed_iter() {
115112
sum_intensity += (index as f64) * (*count).to_f64().unwrap();
116113
}
117-
for (index, count) in counts.indexed_iter(){
114+
for (index, count) in counts.indexed_iter() {
118115
weight_b = weight_b + count.to_f64().unwrap();
119-
sum_b = sum_b + (index as f64)* count.to_f64().unwrap();
116+
sum_b = sum_b + (index as f64) * count.to_f64().unwrap();
120117
let weight_f = total - weight_b;
121-
if (weight_b > 0.0) && (weight_f > 0.0){
118+
if (weight_b > 0.0) && (weight_f > 0.0) {
122119
let mean_f = (sum_intensity - sum_b) / weight_f;
123-
let val = weight_b * weight_f
124-
* ((sum_b / weight_b) - mean_f)
125-
* ((sum_b / weight_b) - mean_f);
126-
if val > maximum{
120+
let val = weight_b
121+
* weight_f
122+
* ((sum_b / weight_b) - mean_f)
123+
* ((sum_b / weight_b) - mean_f);
124+
if val > maximum {
127125
level = 1.0 + (index as f64);
128126
maximum = val;
129127
}
130128
}
131129
}
132-
threshold = level as f64 / scale_factor;
130+
threshold = level as f64 / scale_factor;
133131
}
134132
Ok(threshold)
135133
}
@@ -153,7 +151,7 @@ where
153151

154152
impl<T> ThresholdMeanExt<T> for Array3<T>
155153
where
156-
T: Copy + Clone + Ord + Num + NumAssignOps + ToPrimitive + FromPrimitive
154+
T: Copy + Clone + Ord + Num + NumAssignOps + ToPrimitive + FromPrimitive,
157155
{
158156
type Output = Array3<bool>;
159157

@@ -170,12 +168,11 @@ where
170168

171169
fn calculate_threshold_mean<T>(array: &Array3<T>) -> Result<f64, Error>
172170
where
173-
T: Copy + Clone + Num + NumAssignOps + ToPrimitive + FromPrimitive
171+
T: Copy + Clone + Num + NumAssignOps + ToPrimitive + FromPrimitive,
174172
{
175173
Ok(array.sum().to_f64().unwrap() / array.len() as f64)
176174
}
177175

178-
179176
fn apply_threshold<T>(data: &Array3<T>, threshold: f64) -> Array3<bool>
180177
where
181178
T: Copy + Clone + Num + NumAssignOps + ToPrimitive + FromPrimitive,
@@ -184,7 +181,6 @@ where
184181
result
185182
}
186183

187-
188184
#[cfg(test)]
189185
mod tests {
190186
use super::*;
@@ -208,24 +204,20 @@ mod tests {
208204

209205
assert_eq!(result, expected);
210206
}
211-
207+
212208
#[test]
213209
fn threshold_calculate_threshold_otsu_ints() {
214-
let data = arr3(&[
215-
[[2], [4], [0]],
216-
[[7], [5], [8]],
217-
[[1], [6], [0]],
218-
]);
210+
let data = arr3(&[[[2], [4], [0]], [[7], [5], [8]], [[1], [6], [0]]]);
219211
let result = calculate_threshold_otsu(&data).unwrap();
220212
println!("Done {}", result);
221213

222-
// Calculated using Python's skimage.filters.threshold_otsu
223-
// on int input array. Float array returns 2.0156...
214+
// Calculated using Python's skimage.filters.threshold_otsu
215+
// on int input array. Float array returns 2.0156...
224216
let expected = 2.0;
225217

226218
assert_approx_eq!(result, expected, 5e-1);
227219
}
228-
220+
229221
#[test]
230222
fn threshold_calculate_threshold_otsu_floats() {
231223
let data = arr3(&[
@@ -236,27 +228,23 @@ mod tests {
236228

237229
let result = calculate_threshold_otsu(&data).unwrap();
238230

239-
// Calculated using Python's skimage.filters.threshold_otsu
240-
// on int input array. Float array returns 2.0156...
231+
// Calculated using Python's skimage.filters.threshold_otsu
232+
// on int input array. Float array returns 2.0156...
241233
let expected = 2.0156;
242234

243235
assert_approx_eq!(result, expected, 5e-1);
244236
}
245-
237+
246238
#[test]
247239
fn threshold_calculate_threshold_mean_ints() {
248-
let data = arr3(&[
249-
[[4], [4], [4]],
250-
[[5], [5], [5]],
251-
[[6], [6], [6]],
252-
]);
240+
let data = arr3(&[[[4], [4], [4]], [[5], [5], [5]], [[6], [6], [6]]]);
253241

254242
let result = calculate_threshold_mean(&data).unwrap();
255243
let expected = 5.0;
256-
244+
257245
assert_approx_eq!(result, expected, 1e-16);
258246
}
259-
247+
260248
#[test]
261249
fn threshold_calculate_threshold_mean_floats() {
262250
let data = arr3(&[
@@ -267,7 +255,7 @@ mod tests {
267255

268256
let result = calculate_threshold_mean(&data).unwrap();
269257
let expected = 5.0;
270-
258+
271259
assert_approx_eq!(result, expected, 1e-16);
272260
}
273261
}

0 commit comments

Comments
 (0)