Skip to content

Commit 1f60d32

Browse files
committed
Merge branch 'develop'
2 parents a481754 + 8b070c5 commit 1f60d32

File tree

14 files changed

+127
-75
lines changed

14 files changed

+127
-75
lines changed

.github/dependabot.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: cargo
4+
directory: "/"
5+
schedule:
6+
interval: daily
7+
open-pull-requests-limit: 10
8+
target-branch: develop
9+
ignore:
10+
- dependency-name: ndarray-rand
11+
versions:
12+
- 0.13.0
13+
- 0.14.0
14+
- dependency-name: ndarray-linalg
15+
versions:
16+
- 0.13.0
17+
- dependency-name: rand
18+
versions:
19+
- 0.8.0
20+
- dependency-name: ndarray-stats
21+
versions:
22+
- 0.4.0
23+
- dependency-name: ndarray
24+
versions:
25+
- 0.14.0

.github/workflows/ci.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Build
2+
on:
3+
push:
4+
branches:
5+
- "*"
6+
pull_request:
7+
jobs:
8+
linux:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
version:
13+
- stable
14+
- beta
15+
- nightly
16+
target:
17+
- x86_64-unknown-linux-gnu
18+
- x86_64-unknown-linux-musl
19+
fail-fast: false
20+
steps:
21+
- uses: actions/checkout@v2
22+
- uses: actions-rs/toolchain@v1
23+
with:
24+
toolchain: ${{ matrix.version }}
25+
override: true
26+
components: rustfmt
27+
- name: build
28+
run: |
29+
cargo check --no-default-features
30+
cargo check --all-features
31+
- name: test
32+
run: |
33+
cargo test
34+
- name: check formatting
35+
run: cargo fmt -- --check
36+
- name: code-coverage
37+
run: |
38+
cargo install cargo-tarpaulin --force --git https://github.com/xd009642/tarpaulin --branch develop
39+
cargo tarpaulin --force-clean --coveralls ${{ secrets.COVERALLS_TOKEN }}
40+
if: matrix.target == 'x86_64-unknown-linux-gnu' && matrix.version == 'nightly'

.travis.yml

Lines changed: 0 additions & 35 deletions
This file was deleted.

Cargo.toml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,25 @@ keywords = ["image", "vision", "image-processing"]
1010
categories = ["science", "science::robotics", "multimedia", "multimedia::images", "graphics"]
1111
edition = "2018"
1212

13+
[features]
14+
default = ["enhancement", "format", "morphology", "processing", "transform"]
15+
enhancement = []
16+
format = []
17+
morphology = []
18+
processing = []
19+
transform =["ndarray-linalg"]
20+
1321
[dependencies]
14-
ndarray = { version = "0.13", default-features = false }
15-
ndarray-stats = { version = "0.3", default-features = false }
16-
ndarray-linalg = { version = "0.12", default-features = false }
17-
noisy_float = { version = "0.1", default-features = false }
22+
ndarray = { version = "0.15", default-features = false }
23+
ndarray-stats = { version = "0.5", default-features = false }
24+
ndarray-linalg = { version = "0.14", default-features = false, optional = true }
25+
noisy_float = { version = "0.2", default-features = false }
1826
num-traits = { version = "0.2", default-features = false }
1927

2028
[dev-dependencies]
21-
ndarray-rand = "0.11.0"
22-
rand = "0.7"
29+
ndarray-rand = "0.14.0"
30+
rand = "0.8"
2331
assert_approx_eq = "1.1.0"
24-
noisy_float = "0.1.11"
32+
noisy_float = "0.2"
2533
png = "0.16"
26-
ndarray-linalg = { version = "0.12", features = ["intel-mkl"] }
34+
ndarray-linalg = { version = "0.14", features = ["intel-mkl"] }

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,11 @@ See the examples and tests for basic usage.
1818
* Sobel operator
1919
* Canny Edge Detection
2020
* Histogram Equalisation
21+
* Thresholding (basic, mean, Otsu)
2122
* Encoding and decoding PPM (binary or plaintext)
23+
24+
# Performance
25+
26+
Not a lot of work has been put towards performance yet but a rudimentary
27+
benchmarking project exists [here](https://github.com/xd009642/ndarray-vision-benchmarking)
28+
for comparative benchmarks against other image processing libraries in rust.

src/core/colour_models.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ where
199199
let mut res = Array3::<_>::zeros((image.rows(), image.cols(), HSV::channels()));
200200
let window = image.data.windows((1, 1, image.channels()));
201201

202-
Zip::indexed(window).apply(|(i, j, _), pix| {
202+
Zip::indexed(window).for_each(|(i, j, _), pix| {
203203
let red = pix[[0, 0, 0]];
204204
let green = pix[[0, 0, 1]];
205205
let blue = pix[[0, 0, 2]];
@@ -228,7 +228,7 @@ where
228228
let mut res = Array3::<T>::zeros((image.rows(), image.cols(), RGB::channels()));
229229
let window = image.data.windows((1, 1, image.channels()));
230230

231-
Zip::indexed(window).apply(|(i, j, _), pix| {
231+
Zip::indexed(window).for_each(|(i, j, _), pix| {
232232
let h = pix[[0, 0, 0]];
233233
let s = pix[[0, 0, 1]];
234234
let v = pix[[0, 0, 2]];
@@ -257,7 +257,7 @@ where
257257
let mut res = Array3::<T>::zeros((image.rows(), image.cols(), Gray::channels()));
258258
let window = image.data.windows((1, 1, image.channels()));
259259

260-
Zip::indexed(window).apply(|(i, j, _), pix| {
260+
Zip::indexed(window).for_each(|(i, j, _), pix| {
261261
let r = normalise_pixel_value(pix[[0, 0, 0]]);
262262
let g = normalise_pixel_value(pix[[0, 0, 1]]);
263263
let b = normalise_pixel_value(pix[[0, 0, 2]]);
@@ -288,7 +288,7 @@ where
288288
let mut res = Array3::<T>::zeros((image.rows(), image.cols(), RGB::channels()));
289289
let window = image.data.windows((1, 1, image.channels()));
290290

291-
Zip::indexed(window).apply(|(i, j, _), pix| {
291+
Zip::indexed(window).for_each(|(i, j, _), pix| {
292292
let gray = pix[[0, 0, 0]];
293293

294294
res.slice_mut(s![i, j, ..])
@@ -321,7 +321,7 @@ where
321321
[0.0139322, 0.0971045, 0.7141733],
322322
]);
323323

324-
Zip::indexed(window).apply(|(i, j, _), pix| {
324+
Zip::indexed(window).for_each(|(i, j, _), pix| {
325325
let pixel = pix
326326
.index_axis(Axis(0), 0)
327327
.index_axis(Axis(0), 0)
@@ -360,7 +360,7 @@ where
360360
[0.0719453, -0.2289914, 1.4052427],
361361
]);
362362

363-
Zip::indexed(window).apply(|(i, j, _), pix| {
363+
Zip::indexed(window).for_each(|(i, j, _), pix| {
364364
let pixel = pix
365365
.index_axis(Axis(0), 0)
366366
.index_axis(Axis(0), 0)

src/enhancement/histogram_equalisation.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use ndarray::{prelude::*, DataMut};
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;
76

87
/// Extension trait to implement histogram equalisation on other types
98
pub trait HistogramEqExt<A>

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@
2828
/// The core of `ndarray-vision` contains the `Image` type and colour models
2929
pub mod core;
3030
/// Image enhancement intrinsics and algorithms
31+
#[cfg(feature = "enhancement")]
3132
pub mod enhancement;
3233
/// Image formats - encoding and decoding images from bytes for saving and
3334
/// loading
35+
#[cfg(feature = "format")]
3436
pub mod format;
3537
/// Operations relating to morphological image processing
38+
#[cfg(feature = "morphology")]
3639
pub mod morphology;
3740
/// Image processing intrinsics and common filters/algorithms.
41+
#[cfg(feature = "processing")]
3842
pub mod processing;
3943
/// Image transforms and warping
44+
#[cfg(feature = "transform")]
4045
pub mod transform;

src/morphology/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ where
3232
let (ro, co) = kernel_centre(sh[0], sh[1]);
3333
let mut result = Self::Output::from_elem(self.dim(), false);
3434
if self.shape()[0] >= sh[0] && self.shape()[1] >= sh[1] {
35-
Zip::indexed(self.slice(s![.., .., 0]).windows(kernel.dim())).apply(
35+
Zip::indexed(self.slice(s![.., .., 0]).windows(kernel.dim())).for_each(
3636
|(i, j), window| {
3737
result[[i + ro, j + co, 0]] = (&kernel & &window) == kernel;
3838
},
@@ -50,7 +50,7 @@ where
5050
let (ro, co) = kernel_centre(sh[0], sh[1]);
5151
let mut result = Self::Output::from_elem(self.dim(), false);
5252
if self.shape()[0] >= sh[0] && self.shape()[1] >= sh[1] {
53-
Zip::indexed(self.slice(s![.., .., 0]).windows(kernel.dim())).apply(
53+
Zip::indexed(self.slice(s![.., .., 0]).windows(kernel.dim())).for_each(
5454
|(i, j), window| {
5555
result[[i + ro, j + co, 0]] = (&kernel & &window).iter().any(|x| *x);
5656
},

src/processing/conv.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::core::padding::*;
22
use crate::core::{kernel_centre, ColourModel, Image, ImageBase};
33
use crate::processing::Error;
4+
use core::mem::MaybeUninit;
45
use ndarray::prelude::*;
56
use ndarray::{Data, DataMut, Zip};
67
use num_traits::{Num, NumAssignOps};
@@ -118,9 +119,9 @@ where
118119
let shape = (self.shape()[0], self.shape()[1], self.shape()[2]);
119120

120121
if shape.0 > 0 && shape.1 > 0 {
121-
let mut result = unsafe { Self::Output::uninitialized(shape) };
122+
let mut result = Self::Output::uninit(shape);
122123

123-
Zip::indexed(self.windows(kernel.dim())).apply(|(i, j, _), window| {
124+
Zip::indexed(self.windows(kernel.dim())).for_each(|(i, j, _), window| {
124125
let mut temp;
125126
for channel in 0..k_s[2] {
126127
temp = T::zero();
@@ -130,7 +131,8 @@ where
130131
}
131132
}
132133
unsafe {
133-
*result.uget_mut([i + row_offset, j + col_offset, channel]) = temp;
134+
*result.uget_mut([i + row_offset, j + col_offset, channel]) =
135+
MaybeUninit::new(temp);
134136
}
135137
}
136138
});
@@ -140,7 +142,7 @@ where
140142
apply_edge_convolution(self.view(), kernel.view(), (r, c), strategy);
141143
for chan in 0..k_s[2] {
142144
unsafe {
143-
*result.uget_mut([r, c, chan]) = pixel[chan];
145+
*result.uget_mut([r, c, chan]) = MaybeUninit::new(pixel[chan]);
144146
}
145147
}
146148
let bottom = shape.0 - r - 1;
@@ -152,7 +154,7 @@ where
152154
);
153155
for chan in 0..k_s[2] {
154156
unsafe {
155-
*result.uget_mut([bottom, c, chan]) = pixel[chan];
157+
*result.uget_mut([bottom, c, chan]) = MaybeUninit::new(pixel[chan]);
156158
}
157159
}
158160
}
@@ -163,7 +165,7 @@ where
163165
apply_edge_convolution(self.view(), kernel.view(), (r, c), strategy);
164166
for chan in 0..k_s[2] {
165167
unsafe {
166-
*result.uget_mut([r, c, chan]) = pixel[chan];
168+
*result.uget_mut([r, c, chan]) = MaybeUninit::new(pixel[chan]);
167169
}
168170
}
169171
let right = shape.1 - c - 1;
@@ -175,12 +177,12 @@ where
175177
);
176178
for chan in 0..k_s[2] {
177179
unsafe {
178-
*result.uget_mut([r, right, chan]) = pixel[chan];
180+
*result.uget_mut([r, right, chan]) = MaybeUninit::new(pixel[chan]);
179181
}
180182
}
181183
}
182184
}
183-
Ok(result)
185+
Ok(unsafe { result.assume_init() })
184186
} else {
185187
Err(Error::InvalidDimensions)
186188
}

0 commit comments

Comments
 (0)