├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── ensure_no_std ├── .gitignore ├── Cargo.toml └── src │ └── main.rs ├── src ├── lib.rs ├── toimage.rs ├── tonalgebra.rs ├── tonalgebra │ └── ndarray_impl.rs ├── tondarray.rs └── tondarray │ ├── image_impl.rs │ └── nalgebra_impl.rs └── tests └── nalgebra.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | jobs: 9 | lints: 10 | name: lints 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout sources 14 | uses: actions/checkout@v2 15 | 16 | - name: Install beta toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | profile: minimal 20 | toolchain: beta 21 | override: true 22 | components: rustfmt, clippy 23 | 24 | - name: Set up cache 25 | uses: Swatinem/rust-cache@v1 26 | with: 27 | cache-on-failure: true 28 | 29 | - name: Run cargo fmt 30 | uses: actions-rs/cargo@v1 31 | with: 32 | command: fmt 33 | args: --all -- --check 34 | 35 | - name: Run cargo clippy 36 | uses: actions-rs/cargo@v1 37 | with: 38 | command: clippy 39 | args: --tests -- -D warnings 40 | 41 | no_std: 42 | name: no_std 43 | runs-on: ubuntu-latest 44 | steps: 45 | - name: Checkout sources 46 | uses: actions/checkout@v2 47 | 48 | - name: Install beta toolchain 49 | uses: actions-rs/toolchain@v1 50 | with: 51 | profile: minimal 52 | toolchain: beta 53 | target: armv7a-none-eabi 54 | override: true 55 | 56 | - name: Set up cache 57 | uses: Swatinem/rust-cache@v1 58 | with: 59 | cache-on-failure: true 60 | 61 | - name: Build binary for armv7a-none-eabi 62 | uses: actions-rs/cargo@v1 63 | with: 64 | command: rustc 65 | args: --target=armv7a-none-eabi --manifest-path=ensure_no_std/Cargo.toml 66 | 67 | tests: 68 | name: tests 69 | runs-on: ubuntu-latest 70 | steps: 71 | - name: Checkout sources 72 | uses: actions/checkout@v2 73 | 74 | - name: Install beta toolchain 75 | uses: actions-rs/toolchain@v1 76 | with: 77 | profile: minimal 78 | toolchain: beta 79 | override: true 80 | 81 | - name: Set up cache 82 | uses: Swatinem/rust-cache@v1 83 | with: 84 | cache-on-failure: true 85 | 86 | - name: Run cargo test 87 | uses: actions-rs/cargo@v1 88 | with: 89 | command: test 90 | args: --all-features -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nshare" 3 | version = "0.10.0" 4 | authors = ["Geordon Worley "] 5 | edition = "2021" 6 | description = "Conversion between n-dimensional types in different Rust crates" 7 | documentation = "https://docs.rs/nshare/" 8 | repository = "https://github.com/rust-cv/nshare" 9 | keywords = ["ndarray", "nalgebra", "image", "convert", "borrow"] 10 | categories = ["rust-patterns", "no-std"] 11 | license = "MIT" 12 | readme = "README.md" 13 | 14 | [features] 15 | default = ["alloc", "nalgebra", "ndarray", "image"] 16 | alloc = ["nalgebra?/alloc"] 17 | nalgebra = ["dep:nalgebra"] 18 | ndarray = ["dep:ndarray", "alloc"] 19 | image = ["dep:image", "alloc"] 20 | 21 | [dependencies] 22 | ndarray = { version = "0.16", default-features = false, optional = true } 23 | nalgebra = { version = "0.33", default-features = false, optional = true } 24 | image = { version = "0.25", default-features = false, optional = true } 25 | 26 | [package.metadata.docs.rs] 27 | all-features = true 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rust Computer Vision 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nshare 2 | 3 | [![Discord][dci]][dcl] [![Crates.io][ci]][cl] ![MIT/Apache][li] [![docs.rs][di]][dl] ![LoC][lo] ![ci][bci] 4 | 5 | [ci]: https://img.shields.io/crates/v/nshare.svg 6 | [cl]: https://crates.io/crates/nshare/ 7 | 8 | [li]: https://img.shields.io/crates/l/specs.svg?maxAge=2592000 9 | 10 | [di]: https://docs.rs/nshare/badge.svg 11 | [dl]: https://docs.rs/nshare/ 12 | 13 | [lo]: https://tokei.rs/b1/github/rust-cv/nshare?category=code 14 | 15 | [dci]: https://img.shields.io/discord/550706294311485440.svg?logo=discord&colorB=7289DA 16 | [dcl]: https://discord.gg/d32jaam 17 | 18 | [bci]: https://github.com/rust-cv/nshare/workflows/ci/badge.svg 19 | 20 | Provides traits that allow conversion between n-dimensional types in different Rust crates 21 | 22 | **NOTE**: By default, this crate includes conversions for all supported crates. If you want to limit compilation, use `no-default-features = true` enable the corresponding feature for each dependency: 23 | 24 | * `nalgebra` 25 | * `ndarray` 26 | * `image` 27 | 28 | When two crate features are enabled, any available conversions between the two crates are turned on. 29 | 30 | ## Limitations 31 | 32 | Right now this crate really only provides conversions to owned and borrowed ndarray types. Some limitations exist with `nalgebra`, as it only utilizes positive strides, while `ndarray` supports negative strides as well. The `image` crate has no concept of strides. Due to this, the `ndarray` crate is the most flexible, and is ideal for interoperability between these various crates. 33 | 34 | `nalgebra` currently does not offer a solution to directly pass it an owned vector from `ndarray`, so `into` conversions do perform a copy. It is recommended to create the owned copy in `nalgebra` and then borrow a mutable array view of it using ndarray. You can then populate it accordingly without any copies of the data. 35 | -------------------------------------------------------------------------------- /ensure_no_std/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /ensure_no_std/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ensure_no_std" 3 | version = "0.1.0" 4 | authors = ["Geordon Worley "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | nshare = { path = "..", default-features = false, features = [ 9 | "nalgebra", 10 | "ndarray", 11 | ] } 12 | 13 | [profile.dev] 14 | panic = "abort" 15 | 16 | [profile.release] 17 | panic = "abort" 18 | -------------------------------------------------------------------------------- /ensure_no_std/src/main.rs: -------------------------------------------------------------------------------- 1 | // ensure_no_std/src/main.rs 2 | #![no_std] 3 | #![no_main] 4 | 5 | use core::panic::PanicInfo; 6 | 7 | /// This function is called on panic. 8 | #[panic_handler] 9 | fn panic(_info: &PanicInfo) -> ! { 10 | loop {} 11 | } 12 | 13 | #[no_mangle] 14 | pub extern "C" fn _start() -> ! { 15 | loop {} 16 | } 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | #[cfg(feature = "nalgebra")] 4 | mod tonalgebra; 5 | #[cfg(feature = "nalgebra")] 6 | pub use tonalgebra::*; 7 | 8 | #[cfg(feature = "image")] 9 | mod toimage; 10 | #[cfg(feature = "image")] 11 | pub use toimage::*; 12 | 13 | #[cfg(feature = "ndarray")] 14 | mod tondarray; 15 | #[cfg(feature = "ndarray")] 16 | pub use tondarray::*; 17 | -------------------------------------------------------------------------------- /src/toimage.rs: -------------------------------------------------------------------------------- 1 | /// Converts a 2d type to a luma image type. 2 | /// 3 | /// This uses an associated type to avoid ambiguity for the compiler. 4 | /// By calling this, the compiler always knows the returned type. 5 | pub trait IntoImageLuma { 6 | type Out; 7 | 8 | fn into_image_luma(self) -> Self::Out; 9 | } 10 | -------------------------------------------------------------------------------- /src/tonalgebra.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "ndarray")] 2 | mod ndarray_impl; 3 | 4 | /// Converts a 1 or 2 dimensional type to a nalgebra type. 5 | /// 6 | /// This uses an associated type to avoid ambiguity for the compiler. 7 | /// By calling this, the compiler always knows the returned type. 8 | pub trait IntoNalgebra { 9 | type Out; 10 | 11 | fn into_nalgebra(self) -> Self::Out; 12 | } 13 | -------------------------------------------------------------------------------- /src/tonalgebra/ndarray_impl.rs: -------------------------------------------------------------------------------- 1 | //! Implementations for ndarray types being converted to nalgebra types. 2 | 3 | use super::*; 4 | 5 | use core::convert::TryFrom; 6 | use nalgebra::Dyn; 7 | 8 | /// ``` 9 | /// use nshare::IntoNalgebra; 10 | /// 11 | /// let arr = ndarray::array![0.1, 0.2, 0.3, 0.4]; 12 | /// let m = arr.view().into_nalgebra(); 13 | /// assert!(m.iter().eq(&[0.1, 0.2, 0.3, 0.4])); 14 | /// assert_eq!(m.shape(), (4, 1)); 15 | /// ``` 16 | impl<'a, T> IntoNalgebra for ndarray::ArrayView1<'a, T> 17 | where 18 | T: nalgebra::Scalar, 19 | { 20 | type Out = nalgebra::DVectorView<'a, T>; 21 | fn into_nalgebra(self) -> Self::Out { 22 | let len = Dyn(self.len()); 23 | let ptr = self.as_ptr(); 24 | let stride: usize = TryFrom::try_from(self.strides()[0]).expect("Negative stride"); 25 | let storage = unsafe { 26 | nalgebra::ViewStorage::from_raw_parts( 27 | ptr, 28 | (len, nalgebra::Const::<1>), 29 | (nalgebra::Const::<1>, Dyn(stride)), 30 | ) 31 | }; 32 | nalgebra::Matrix::from_data(storage) 33 | } 34 | } 35 | /// ``` 36 | /// use nshare::IntoNalgebra; 37 | /// 38 | /// let mut arr = ndarray::array![0.1, 0.2, 0.3, 0.4]; 39 | /// let m = arr.view_mut().into_nalgebra(); 40 | /// assert!(m.iter().eq(&[0.1, 0.2, 0.3, 0.4])); 41 | /// assert_eq!(m.shape(), (4, 1)); 42 | /// ``` 43 | impl<'a, T> IntoNalgebra for ndarray::ArrayViewMut1<'a, T> 44 | where 45 | T: nalgebra::Scalar, 46 | { 47 | type Out = nalgebra::DVectorViewMut<'a, T>; 48 | fn into_nalgebra(mut self) -> Self::Out { 49 | let len = Dyn(self.len()); 50 | let stride: usize = TryFrom::try_from(self.strides()[0]).expect("Negative stride"); 51 | let ptr = self.as_mut_ptr(); 52 | let storage = unsafe { 53 | nalgebra::ViewStorageMut::from_raw_parts( 54 | ptr, 55 | (len, nalgebra::Const::<1>), 56 | (nalgebra::Const::<1>, Dyn(stride)), 57 | ) 58 | }; 59 | nalgebra::Matrix::from_data(storage) 60 | } 61 | } 62 | 63 | /// ``` 64 | /// use nshare::IntoNalgebra; 65 | /// 66 | /// let arr = ndarray::array![0.1, 0.2, 0.3, 0.4]; 67 | /// let m = arr.into_nalgebra(); 68 | /// assert!(m.iter().eq(&[0.1, 0.2, 0.3, 0.4])); 69 | /// assert_eq!(m.shape(), (4, 1)); 70 | /// ``` 71 | impl IntoNalgebra for ndarray::Array1 72 | where 73 | T: nalgebra::Scalar, 74 | { 75 | type Out = nalgebra::DVector; 76 | fn into_nalgebra(self) -> Self::Out { 77 | let len = Dyn(self.len()); 78 | // There is no method to give nalgebra the vector directly where it isn't allocated. If you call 79 | // from_vec_generic, it simply calls from_iterator_generic which uses Iterator::collect(). Due to this, 80 | // the simplest solution is to just pass an iterator over the values. If you come across this because you 81 | // have a performance issue, I would recommend creating the owned data using naglebra and borrowing it with 82 | // ndarray to perform operations on it instead of the other way around. 83 | Self::Out::from_iterator_generic(len, nalgebra::Const::<1>, self.iter().cloned()) 84 | } 85 | } 86 | 87 | /// ``` 88 | /// use nshare::IntoNalgebra; 89 | /// 90 | /// let arr = ndarray::array![ 91 | /// [0.1, 0.2, 0.3, 0.4], 92 | /// [0.5, 0.6, 0.7, 0.8], 93 | /// [1.1, 1.2, 1.3, 1.4], 94 | /// [1.5, 1.6, 1.7, 1.8], 95 | /// ]; 96 | /// let m = arr.view().into_nalgebra(); 97 | /// assert!(m.row(1).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 98 | /// assert_eq!(m.shape(), (4, 4)); 99 | /// assert!(arr.t().into_nalgebra().column(1).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 100 | /// ``` 101 | impl<'a, T> IntoNalgebra for ndarray::ArrayView2<'a, T> 102 | where 103 | T: nalgebra::Scalar, 104 | { 105 | type Out = nalgebra::DMatrixView<'a, T, Dyn, Dyn>; 106 | fn into_nalgebra(self) -> Self::Out { 107 | let nrows = Dyn(self.nrows()); 108 | let ncols = Dyn(self.ncols()); 109 | let ptr = self.as_ptr(); 110 | let stride_row: usize = TryFrom::try_from(self.strides()[0]) 111 | .expect("can only convert positive row stride to nalgebra"); 112 | let stride_col: usize = TryFrom::try_from(self.strides()[1]) 113 | .expect("can only convert positive col stride to nalgebra"); 114 | let storage = unsafe { 115 | nalgebra::ViewStorage::from_raw_parts( 116 | ptr, 117 | (nrows, ncols), 118 | (Dyn(stride_row), Dyn(stride_col)), 119 | ) 120 | }; 121 | nalgebra::Matrix::from_data(storage) 122 | } 123 | } 124 | 125 | /// ``` 126 | /// use nshare::IntoNalgebra; 127 | /// 128 | /// let mut arr = ndarray::array![ 129 | /// [0.1, 0.2, 0.3, 0.4], 130 | /// [0.5, 0.6, 0.7, 0.8], 131 | /// [1.1, 1.2, 1.3, 1.4], 132 | /// [1.5, 1.6, 1.7, 1.8], 133 | /// ]; 134 | /// let m = arr.view_mut().into_nalgebra(); 135 | /// assert!(m.row(1).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 136 | /// assert_eq!(m.shape(), (4, 4)); 137 | /// assert!(arr.view_mut().reversed_axes().into_nalgebra().column(1).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 138 | /// ``` 139 | impl<'a, T> IntoNalgebra for ndarray::ArrayViewMut2<'a, T> 140 | where 141 | T: nalgebra::Scalar, 142 | { 143 | type Out = nalgebra::DMatrixViewMut<'a, T, Dyn, Dyn>; 144 | fn into_nalgebra(mut self) -> Self::Out { 145 | let nrows = Dyn(self.nrows()); 146 | let ncols = Dyn(self.ncols()); 147 | let stride_row: usize = TryFrom::try_from(self.strides()[0]) 148 | .expect("can only convert positive row stride to nalgebra"); 149 | let stride_col: usize = TryFrom::try_from(self.strides()[1]) 150 | .expect("can only convert positive col stride to nalgebra"); 151 | let ptr = self.as_mut_ptr(); 152 | let storage = unsafe { 153 | nalgebra::ViewStorageMut::from_raw_parts( 154 | ptr, 155 | (nrows, ncols), 156 | (Dyn(stride_row), Dyn(stride_col)), 157 | ) 158 | }; 159 | nalgebra::Matrix::from_data(storage) 160 | } 161 | } 162 | 163 | /// ``` 164 | /// use nshare::IntoNalgebra; 165 | /// 166 | /// let mut arr = ndarray::array![ 167 | /// [0.1, 0.2, 0.3, 0.4], 168 | /// [0.5, 0.6, 0.7, 0.8], 169 | /// [1.1, 1.2, 1.3, 1.4], 170 | /// [1.5, 1.6, 1.7, 1.8], 171 | /// ]; 172 | /// let m = arr.clone().into_nalgebra(); 173 | /// assert!(m.row(1).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 174 | /// assert_eq!(m.shape(), (4, 4)); 175 | /// assert!(arr.reversed_axes().into_nalgebra().column(1).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 176 | /// ``` 177 | impl IntoNalgebra for ndarray::Array2 178 | where 179 | T: nalgebra::Scalar, 180 | { 181 | type Out = nalgebra::DMatrix; 182 | fn into_nalgebra(self) -> Self::Out { 183 | let nrows = Dyn(self.nrows()); 184 | let ncols = Dyn(self.ncols()); 185 | Self::Out::from_iterator_generic(nrows, ncols, self.t().iter().cloned()) 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/tondarray.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "image")] 2 | mod image_impl; 3 | #[cfg(feature = "nalgebra")] 4 | mod nalgebra_impl; 5 | 6 | /// Converts a 1d type to a ndarray 1d array type. 7 | /// 8 | /// This uses an associated type to avoid ambiguity for the compiler. 9 | /// By calling this, the compiler always knows the returned type. 10 | pub trait IntoNdarray1 { 11 | type Out; 12 | 13 | fn into_ndarray1(self) -> Self::Out; 14 | } 15 | 16 | /// Converts a 2d type to a ndarray 2d array type. 17 | /// 18 | /// Coordinates are in (row, col). 19 | /// 20 | /// This uses an associated type to avoid ambiguity for the compiler. 21 | /// By calling this, the compiler always knows the returned type. 22 | pub trait IntoNdarray2 { 23 | type Out; 24 | 25 | fn into_ndarray2(self) -> Self::Out; 26 | } 27 | 28 | /// Converts a 3d type to a ndarray 2d array type. 29 | /// 30 | /// Coordinates are in `(channel, row, col)`, where channel is typically a color channel, 31 | /// or they are in `(z, y, x)`. 32 | /// 33 | /// This uses an associated type to avoid ambiguity for the compiler. 34 | /// By calling this, the compiler always knows the returned type. 35 | pub trait IntoNdarray3 { 36 | type Out; 37 | 38 | fn into_ndarray3(self) -> Self::Out; 39 | } 40 | 41 | /// Borrows a 1d type to a ndarray 1d array type. 42 | /// 43 | /// This uses an associated type to avoid ambiguity for the compiler. 44 | /// By calling this, the compiler always knows the returned type. 45 | pub trait AsNdarray1 { 46 | type Out<'a> 47 | where 48 | Self: 'a; 49 | 50 | fn as_ndarray1(&self) -> Self::Out<'_>; 51 | } 52 | 53 | /// Borrows a 2d type to a ndarray 2d array type. 54 | /// 55 | /// Coordinates are in (row, col). 56 | /// 57 | /// This uses an associated type to avoid ambiguity for the compiler. 58 | /// By calling this, the compiler always knows the returned type. 59 | pub trait AsNdarray2 { 60 | type Out<'a> 61 | where 62 | Self: 'a; 63 | 64 | fn as_ndarray2(&self) -> Self::Out<'_>; 65 | } 66 | 67 | /// Borrows a 3d type to a ndarray 2d array type. 68 | /// 69 | /// Coordinates are in `(channel, row, col)`, where channel is typically a color channel, 70 | /// or they are in `(z, y, x)`. 71 | /// 72 | /// This uses an associated type to avoid ambiguity for the compiler. 73 | /// By calling this, the compiler always knows the returned type. 74 | pub trait AsNdarray3 { 75 | type Out<'a> 76 | where 77 | Self: 'a; 78 | 79 | fn as_ndarray3(&self) -> Self::Out<'_>; 80 | } 81 | 82 | /// Mutably borrows a 1d type to a ndarray 1d array type. 83 | /// 84 | /// This uses an associated type to avoid ambiguity for the compiler. 85 | /// By calling this, the compiler always knows the returned type. 86 | pub trait AsNdarray1Mut { 87 | type Out<'a> 88 | where 89 | Self: 'a; 90 | 91 | fn as_ndarray1_mut(&mut self) -> Self::Out<'_>; 92 | } 93 | 94 | /// Mutably borrows a 2d type to a ndarray 2d array type. 95 | /// 96 | /// Coordinates are in (row, col). 97 | /// 98 | /// This uses an associated type to avoid ambiguity for the compiler. 99 | /// By calling this, the compiler always knows the returned type. 100 | pub trait AsNdarray2Mut { 101 | type Out<'a> 102 | where 103 | Self: 'a; 104 | 105 | fn as_ndarray2_mut(&mut self) -> Self::Out<'_>; 106 | } 107 | 108 | /// Mutably borrows a 3d type to a ndarray 2d array type. 109 | /// 110 | /// Coordinates are in `(channel, row, col)`, where channel is typically a color channel, 111 | /// or they are in `(z, y, x)`. 112 | /// 113 | /// This uses an associated type to avoid ambiguity for the compiler. 114 | /// By calling this, the compiler always knows the returned type. 115 | pub trait AsNdarray3Mut { 116 | type Out<'a> 117 | where 118 | Self: 'a; 119 | 120 | fn as_ndarray3_mut(&mut self) -> Self::Out<'_>; 121 | } 122 | -------------------------------------------------------------------------------- /src/tondarray/image_impl.rs: -------------------------------------------------------------------------------- 1 | //! Implementations for conversions from image types to ndarray types. 2 | 3 | use super::*; 4 | use core::ops::{Deref, DerefMut}; 5 | use image::{flat::SampleLayout, ImageBuffer, Luma, Pixel, Primitive}; 6 | use ndarray::{Array2, Array3, ArrayView2, ArrayView3, ArrayViewMut2, ArrayViewMut3, ShapeBuilder}; 7 | 8 | extern crate alloc; 9 | 10 | use alloc::vec::Vec; 11 | 12 | /// ``` 13 | /// use image::GrayImage; 14 | /// use nshare::IntoNdarray2; 15 | /// use ndarray::s; 16 | /// 17 | /// let zeros = GrayImage::new(2, 4); 18 | /// let mut nd = zeros.into_ndarray2(); 19 | /// nd.fill(255); 20 | /// // ndarray uses (row, col), so the dims get flipped. 21 | /// assert_eq!(nd.dim(), (4, 2)); 22 | /// ``` 23 | impl IntoNdarray2 for ImageBuffer, Vec> 24 | where 25 | A: Primitive + 'static, 26 | { 27 | type Out = Array2; 28 | 29 | fn into_ndarray2(self) -> Self::Out { 30 | let SampleLayout { 31 | height, 32 | height_stride, 33 | width, 34 | width_stride, 35 | .. 36 | } = self.sample_layout(); 37 | let shape = (height as usize, width as usize); 38 | let strides = (height_stride, width_stride); 39 | Array2::from_shape_vec(shape.strides(strides), self.into_raw()).unwrap() 40 | } 41 | } 42 | 43 | /// ``` 44 | /// use image::{GrayImage, Luma}; 45 | /// use nshare::AsNdarray2; 46 | /// use ndarray::s; 47 | /// 48 | /// let mut vals = GrayImage::new(2, 4); 49 | /// vals[(1, 0)] = Luma([255]); 50 | /// let nd = vals.as_ndarray2(); 51 | /// // ndarray uses (row, col), so the dims get flipped. 52 | /// assert_eq!(nd.dim(), (4, 2)); 53 | /// // The first row should sum to 255. 54 | /// assert_eq!(nd.slice(s![0, ..]).sum(), 255); 55 | /// ``` 56 | impl AsNdarray2 for ImageBuffer, Container> 57 | where 58 | A: Primitive + 'static, 59 | Container: Deref, 60 | { 61 | type Out<'a> = ArrayView2<'a, A> 62 | where 63 | Container: 'a; 64 | 65 | fn as_ndarray2(&self) -> Self::Out<'_> { 66 | let SampleLayout { 67 | height, 68 | height_stride, 69 | width, 70 | width_stride, 71 | .. 72 | } = self.sample_layout(); 73 | let shape = (height as usize, width as usize); 74 | let strides = (height_stride, width_stride); 75 | ArrayView2::from_shape(shape.strides(strides), self).unwrap() 76 | } 77 | } 78 | 79 | /// ``` 80 | /// use image::{GrayImage, Luma}; 81 | /// use nshare::AsNdarray2Mut; 82 | /// use ndarray::s; 83 | /// 84 | /// let mut vals = GrayImage::new(2, 4); 85 | /// let mut nd = vals.as_ndarray2_mut(); 86 | /// assert_eq!(nd.dim(), (4, 2)); 87 | /// nd.slice_mut(s![0, ..]).fill(255); 88 | /// assert_eq!(vals[(1, 0)], Luma([255])); 89 | /// ``` 90 | impl AsNdarray2Mut for ImageBuffer, Container> 91 | where 92 | A: Primitive + 'static, 93 | Container: DerefMut, 94 | { 95 | type Out<'a> = ArrayViewMut2<'a, A> 96 | where 97 | Container: 'a; 98 | 99 | fn as_ndarray2_mut(&mut self) -> Self::Out<'_> { 100 | let SampleLayout { 101 | height, 102 | height_stride, 103 | width, 104 | width_stride, 105 | .. 106 | } = self.sample_layout(); 107 | let shape = (height as usize, width as usize); 108 | let strides = (height_stride, width_stride); 109 | ArrayViewMut2::from_shape(shape.strides(strides), self).unwrap() 110 | } 111 | } 112 | 113 | /// ``` 114 | /// use image::RgbImage; 115 | /// use nshare::IntoNdarray3; 116 | /// use ndarray::s; 117 | /// 118 | /// let zeros = RgbImage::new(2, 4); 119 | /// let mut nd = zeros.into_ndarray3(); 120 | /// nd.fill(255); 121 | /// // ndarray uses (channel, row, col), so the dims get flipped. 122 | /// assert_eq!(nd.dim(), (3, 4, 2)); 123 | /// ``` 124 | impl

IntoNdarray3 for ImageBuffer> 125 | where 126 | P: Pixel + 'static, 127 | { 128 | type Out = Array3; 129 | 130 | fn into_ndarray3(self) -> Self::Out { 131 | let SampleLayout { 132 | channels, 133 | channel_stride, 134 | height, 135 | height_stride, 136 | width, 137 | width_stride, 138 | } = self.sample_layout(); 139 | let shape = (channels as usize, height as usize, width as usize); 140 | let strides = (channel_stride, height_stride, width_stride); 141 | Array3::from_shape_vec(shape.strides(strides), self.into_raw()).unwrap() 142 | } 143 | } 144 | 145 | /// ``` 146 | /// use image::{RgbImage, Rgb}; 147 | /// use nshare::AsNdarray3; 148 | /// use ndarray::s; 149 | /// 150 | /// let mut vals = RgbImage::new(2, 4); 151 | /// vals[(1, 0)] = Rgb([0, 255, 0]); 152 | /// let nd = vals.as_ndarray3(); 153 | /// // ndarray uses (channel, row, col), so the dims get flipped. 154 | /// assert_eq!(nd.dim(), (3, 4, 2)); 155 | /// // The first row green should sum to 255. 156 | /// assert_eq!(nd.slice(s![1, 0, ..]).sum(), 255); 157 | /// // The first row red should sum to 0. 158 | /// assert_eq!(nd.slice(s![0, 0, ..]).sum(), 0); 159 | /// ``` 160 | impl

AsNdarray3 for ImageBuffer> 161 | where 162 | P: Pixel + 'static, 163 | { 164 | type Out<'a> = ArrayView3<'a, P::Subpixel>; 165 | 166 | fn as_ndarray3(&self) -> Self::Out<'_> { 167 | let SampleLayout { 168 | channels, 169 | channel_stride, 170 | height, 171 | height_stride, 172 | width, 173 | width_stride, 174 | } = self.sample_layout(); 175 | let shape = (channels as usize, height as usize, width as usize); 176 | let strides = (channel_stride, height_stride, width_stride); 177 | ArrayView3::from_shape(shape.strides(strides), self).unwrap() 178 | } 179 | } 180 | 181 | /// ``` 182 | /// use image::{RgbImage, Rgb}; 183 | /// use nshare::AsNdarray3Mut; 184 | /// use ndarray::s; 185 | /// 186 | /// let mut vals = RgbImage::new(2, 4); 187 | /// // Set all the blue channel to 255. 188 | /// vals.as_ndarray3_mut().slice_mut(s![2, .., ..]).fill(255); 189 | /// assert_eq!(vals[(0, 0)], Rgb([0, 0, 255])); 190 | /// ``` 191 | impl

AsNdarray3Mut for ImageBuffer> 192 | where 193 | P: Pixel + 'static, 194 | { 195 | type Out<'a> = ArrayViewMut3<'a, P::Subpixel>; 196 | 197 | fn as_ndarray3_mut(&mut self) -> Self::Out<'_> { 198 | let SampleLayout { 199 | channels, 200 | channel_stride, 201 | height, 202 | height_stride, 203 | width, 204 | width_stride, 205 | } = self.sample_layout(); 206 | let shape = (channels as usize, height as usize, width as usize); 207 | let strides = (channel_stride, height_stride, width_stride); 208 | ArrayViewMut3::from_shape(shape.strides(strides), self).unwrap() 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/tondarray/nalgebra_impl.rs: -------------------------------------------------------------------------------- 1 | //! Implementations for nalgebra types being converted to ndarray types. 2 | 3 | use super::*; 4 | use nalgebra::{dimension::U1, Dim, Dyn, Scalar}; 5 | use ndarray::ShapeBuilder; 6 | 7 | /// ``` 8 | /// use nshare::AsNdarray1; 9 | /// use nalgebra::Vector4; 10 | /// use ndarray::s; 11 | /// 12 | /// let m = Vector4::new( 13 | /// 0.1, 0.2, 0.3, 0.4f32, 14 | /// ); 15 | /// let arr = m.as_ndarray1(); 16 | /// assert!(arr.iter().eq(&[0.1, 0.2, 0.3, 0.4])); 17 | /// assert_eq!(arr.dim(), 4); 18 | /// ``` 19 | impl AsNdarray1 for nalgebra::Vector 20 | where 21 | S: nalgebra::Storage, 22 | { 23 | type Out<'a> = ndarray::ArrayView1<'a, N> 24 | where 25 | S: 'a; 26 | 27 | fn as_ndarray1(&self) -> Self::Out<'_> { 28 | unsafe { 29 | ndarray::ArrayView1::from_shape_ptr( 30 | (self.shape().0,).strides((self.strides().0,)), 31 | self.as_ptr(), 32 | ) 33 | } 34 | } 35 | } 36 | 37 | /// ``` 38 | /// use nshare::AsNdarray1Mut; 39 | /// use nalgebra::Vector4; 40 | /// use ndarray::s; 41 | /// 42 | /// let mut m = Vector4::new( 43 | /// 0.1, 0.2, 0.3, 0.4f32, 44 | /// ); 45 | /// // Set everything to 0. 46 | /// m.as_ndarray1_mut().fill(0.0); 47 | /// assert!(m.iter().eq(&[0.0; 4])); 48 | /// ``` 49 | impl AsNdarray1Mut for nalgebra::Vector 50 | where 51 | S: nalgebra::StorageMut, 52 | { 53 | type Out<'a> = ndarray::ArrayViewMut1<'a, N> 54 | where 55 | S: 'a; 56 | 57 | fn as_ndarray1_mut(&mut self) -> Self::Out<'_> { 58 | unsafe { 59 | ndarray::ArrayViewMut1::from_shape_ptr( 60 | (self.shape().0,).strides((self.strides().0,)), 61 | self.as_ptr() as *mut N, 62 | ) 63 | } 64 | } 65 | } 66 | 67 | /// ``` 68 | /// use nshare::IntoNdarray1; 69 | /// use nalgebra::Vector4; 70 | /// 71 | /// let m = Vector4::new( 72 | /// 0.1, 0.2, 0.3, 0.4f32, 73 | /// ); 74 | /// let arr = m.rows(0, 4).into_ndarray1(); 75 | /// assert!(arr.iter().eq(&[0.1, 0.2, 0.3, 0.4])); 76 | /// assert_eq!(arr.dim(), 4); 77 | /// ``` 78 | impl<'a, N: Scalar, R: Dim, RStride: Dim, CStride: Dim> IntoNdarray1 79 | for nalgebra::Vector> 80 | { 81 | type Out = ndarray::ArrayView1<'a, N>; 82 | 83 | fn into_ndarray1(self) -> Self::Out { 84 | unsafe { 85 | ndarray::ArrayView1::from_shape_ptr( 86 | (self.shape().0,).strides((self.strides().0,)), 87 | self.as_ptr(), 88 | ) 89 | } 90 | } 91 | } 92 | 93 | /// ``` 94 | /// use nshare::IntoNdarray1; 95 | /// use nalgebra::{Vector4, dimension::U2, Const}; 96 | /// 97 | /// let mut m = Vector4::new( 98 | /// 0.1, 0.2, 0.3, 0.4, 99 | /// ); 100 | /// let arr = m.rows_generic_with_step_mut::>(0, Const::<2>, 1).into_ndarray1().fill(0.0); 101 | /// assert!(m.iter().eq(&[0.0, 0.2, 0.0, 0.4])); 102 | /// ``` 103 | impl<'a, N: Scalar, R: Dim, RStride: Dim, CStride: Dim> IntoNdarray1 104 | for nalgebra::Matrix> 105 | { 106 | type Out = ndarray::ArrayViewMut1<'a, N>; 107 | 108 | fn into_ndarray1(self) -> Self::Out { 109 | unsafe { 110 | ndarray::ArrayViewMut1::from_shape_ptr( 111 | (self.shape().0,).strides((self.strides().0,)), 112 | self.as_ptr() as *mut N, 113 | ) 114 | } 115 | } 116 | } 117 | 118 | /// ``` 119 | /// use nshare::AsNdarray2; 120 | /// use nalgebra::Matrix4; 121 | /// use ndarray::s; 122 | /// 123 | /// let m = Matrix4::new( 124 | /// 0.1, 0.2, 0.3, 0.4, 125 | /// 0.5, 0.6, 0.7, 0.8, 126 | /// 1.1, 1.2, 1.3, 1.4, 127 | /// 1.5, 1.6, 1.7, 1.8, 128 | /// ); 129 | /// let arr = m.as_ndarray2(); 130 | /// assert!(arr.slice(s![1, ..]).iter().eq(&[0.5, 0.6, 0.7, 0.8])); 131 | /// assert_eq!(arr.dim(), (4, 4)); 132 | /// ``` 133 | impl AsNdarray2 for nalgebra::Matrix 134 | where 135 | S: nalgebra::Storage, 136 | { 137 | type Out<'a> = ndarray::ArrayView2<'a, N> 138 | where 139 | S: 'a; 140 | 141 | fn as_ndarray2(&self) -> Self::Out<'_> { 142 | unsafe { 143 | ndarray::ArrayView2::from_shape_ptr(self.shape().strides(self.strides()), self.as_ptr()) 144 | } 145 | } 146 | } 147 | 148 | /// ``` 149 | /// use nshare::AsNdarray2Mut; 150 | /// use nalgebra::Matrix4; 151 | /// use ndarray::s; 152 | /// 153 | /// let mut m = Matrix4::new( 154 | /// 0.1, 0.2, 0.3, 0.4, 155 | /// 0.5, 0.6, 0.7, 0.8, 156 | /// 1.1, 1.2, 1.3, 1.4, 157 | /// 1.5, 1.6, 1.7, 1.8, 158 | /// ); 159 | /// let arr = m.as_ndarray2_mut().slice_mut(s![1, ..]).fill(0.0); 160 | /// assert!(m.row(1).iter().eq(&[0.0; 4])); 161 | /// ``` 162 | impl AsNdarray2Mut for nalgebra::Matrix 163 | where 164 | S: nalgebra::StorageMut, 165 | { 166 | type Out<'a> = ndarray::ArrayViewMut2<'a, N> 167 | where 168 | S: 'a; 169 | 170 | fn as_ndarray2_mut(&mut self) -> Self::Out<'_> { 171 | unsafe { 172 | ndarray::ArrayViewMut2::from_shape_ptr( 173 | self.shape().strides(self.strides()), 174 | self.as_ptr() as *mut N, 175 | ) 176 | } 177 | } 178 | } 179 | 180 | /// ``` 181 | /// use nshare::IntoNdarray2; 182 | /// use nalgebra::Matrix4; 183 | /// 184 | /// let m = Matrix4::new( 185 | /// 0.1, 0.2, 0.3, 0.4, 186 | /// 0.5, 0.6, 0.7, 0.8, 187 | /// 1.1, 1.2, 1.3, 1.4, 188 | /// 1.5, 1.6, 1.7, 1.8, 189 | /// ); 190 | /// let arr = m.row(1).into_ndarray2(); 191 | /// assert!(arr.iter().eq(&[0.5, 0.6, 0.7, 0.8])); 192 | /// assert_eq!(arr.dim(), (1, 4)); 193 | /// ``` 194 | impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> IntoNdarray2 195 | for nalgebra::Matrix> 196 | { 197 | type Out = ndarray::ArrayView2<'a, N>; 198 | 199 | fn into_ndarray2(self) -> Self::Out { 200 | unsafe { 201 | ndarray::ArrayView2::from_shape_ptr(self.shape().strides(self.strides()), self.as_ptr()) 202 | } 203 | } 204 | } 205 | 206 | /// ``` 207 | /// use nshare::IntoNdarray2; 208 | /// use nalgebra::Matrix4; 209 | /// 210 | /// let mut m = Matrix4::new( 211 | /// 0.1, 0.2, 0.3, 0.4, 212 | /// 0.5, 0.6, 0.7, 0.8, 213 | /// 1.1, 1.2, 1.3, 1.4, 214 | /// 1.5, 1.6, 1.7, 1.8, 215 | /// ); 216 | /// let arr = m.row_mut(1).into_ndarray2().fill(0.0); 217 | /// assert!(m.row(1).iter().eq(&[0.0; 4])); 218 | /// ``` 219 | impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> IntoNdarray2 220 | for nalgebra::Matrix> 221 | { 222 | type Out = ndarray::ArrayViewMut2<'a, N>; 223 | 224 | fn into_ndarray2(self) -> Self::Out { 225 | unsafe { 226 | ndarray::ArrayViewMut2::from_shape_ptr( 227 | self.shape().strides(self.strides()), 228 | self.as_ptr() as *mut N, 229 | ) 230 | } 231 | } 232 | } 233 | 234 | /// ``` 235 | /// use nshare::IntoNdarray1; 236 | /// use nalgebra::DVector; 237 | /// use ndarray::s; 238 | /// 239 | /// let m = DVector::from_vec(vec![ 240 | /// 0.1, 0.2, 0.3, 0.4, 241 | /// ]); 242 | /// let arr = m.into_ndarray1(); 243 | /// assert_eq!(arr.dim(), 4); 244 | /// assert!(arr.iter().eq(&[0.1, 0.2, 0.3, 0.4])); 245 | /// ``` 246 | impl IntoNdarray1 for nalgebra::DVector { 247 | type Out = ndarray::Array1; 248 | 249 | fn into_ndarray1(self) -> Self::Out { 250 | ndarray::Array1::from_shape_vec((self.shape().0,), self.data.into()).unwrap() 251 | } 252 | } 253 | 254 | /// ``` 255 | /// use nshare::IntoNdarray2; 256 | /// use nalgebra::{Matrix, dimension::{U4, Dynamic}}; 257 | /// use ndarray::s; 258 | /// 259 | /// // Note: from_vec takes data column-by-column ! 260 | /// let m = Matrix::::from_vec(3, 4, vec![ 261 | /// 0.1, 0.2, 0.3, 262 | /// 0.5, 0.6, 0.7, 263 | /// 1.1, 1.2, 1.3, 264 | /// 1.5, 1.6, 1.7, 265 | /// ]); 266 | /// let arr = m.into_ndarray2(); 267 | /// assert!(arr.slice(s![.., 0]).iter().eq(&[0.1, 0.2, 0.3])); 268 | /// assert!(arr.slice(s![0, ..]).iter().eq(&[0.1, 0.5, 1.1, 1.5])); 269 | /// ``` 270 | impl IntoNdarray2 for nalgebra::Matrix> 271 | where 272 | nalgebra::DefaultAllocator: 273 | nalgebra::allocator::Allocator = nalgebra::VecStorage>, 274 | { 275 | type Out = ndarray::Array2; 276 | 277 | fn into_ndarray2(self) -> Self::Out { 278 | ndarray::Array2::from_shape_vec(self.shape().strides(self.strides()), self.data.into()) 279 | .unwrap() 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /tests/nalgebra.rs: -------------------------------------------------------------------------------- 1 | use nshare::IntoNalgebra; 2 | 3 | #[test] 4 | fn single_row_ndarray_to_nalgebra() { 5 | let mut arr = ndarray::array![[0.1, 0.2, 0.3, 0.4]]; 6 | let m = arr.view_mut().into_nalgebra(); 7 | assert!(m.row(0).iter().eq(&[0.1, 0.2, 0.3, 0.4])); 8 | assert_eq!(m.shape(), (1, 4)); 9 | assert!(arr 10 | .view_mut() 11 | .reversed_axes() 12 | .into_nalgebra() 13 | .column(0) 14 | .iter() 15 | .eq(&[0.1, 0.2, 0.3, 0.4])); 16 | } 17 | --------------------------------------------------------------------------------