//! Mat <--> ndarray conversion traits //! //! Conversion Table //! //! | ndarray | Mat | //! |--------- |----- | //! | Array | Mat(ndims = 1, channels = 1) | //! | Array | Mat(ndims = 2, channels = 1) | //! | Array | Mat(ndims = 1, channels = X) | //! | Array | Mat(ndims = 3, channels = 1) | //! | Array | Mat(ndims = 2, channels = X) | //! | Array | Mat(ndims = 4, channels = 1) | //! | Array | Mat(ndims = 3, channels = X) | //! | Array | Mat(ndims = 5, channels = 1) | //! | Array | Mat(ndims = 4, channels = X) | //! | Array | Mat(ndims = 6, channels = 1) | //! | Array | Mat(ndims = 5, channels = X) | //! //! // X is the last dimension use crate::NdCvError; use crate::type_depth; use error_stack::*; use ndarray::{Ix2, Ix3}; use opencv::core::MatTraitConst; mod impls; pub(crate) mod matref; use matref::{MatRef, MatRefMut}; pub(crate) mod seal { pub trait SealedInternal {} impl, D> SealedInternal for ndarray::ArrayBase {} // impl, D> SealedInternal for ndarray::ArrayBase {} } pub trait NdCvConversion: seal::SealedInternal + Sized { fn to_mat(&self) -> Result; fn from_mat( mat: opencv::core::Mat, ) -> Result, D>, NdCvError>; } impl, D: ndarray::Dimension> NdCvConversion for ndarray::ArrayBase where Self: NdAsImage, { fn to_mat(&self) -> Result { Ok(self.as_image_mat()?.mat.clone()) } fn from_mat( mat: opencv::core::Mat, ) -> Result, D>, NdCvError> { let ndarray = unsafe { impls::mat_to_ndarray::(&mat) }.change_context(NdCvError)?; Ok(ndarray.to_owned()) } } pub trait MatAsNd { fn as_ndarray( &self, ) -> Result, NdCvError>; } impl MatAsNd for opencv::core::Mat { fn as_ndarray( &self, ) -> Result, NdCvError> { unsafe { impls::mat_to_ndarray::(self) }.change_context(NdCvError) } } pub trait NdAsMat { fn as_single_channel_mat(&self) -> Result; fn as_multi_channel_mat(&self) -> Result; } pub trait NdAsMatMut: NdAsMat { fn as_single_channel_mat_mut(&mut self) -> Result; fn as_multi_channel_mat_mut(&mut self) -> Result; } impl, D: ndarray::Dimension> NdAsMat for ndarray::ArrayBase { fn as_single_channel_mat(&self) -> Result { let mat = unsafe { impls::ndarray_to_mat_regular(self) }.change_context(NdCvError)?; Ok(MatRef::new(mat)) } fn as_multi_channel_mat(&self) -> Result { let mat = unsafe { impls::ndarray_to_mat_consolidated(self) }.change_context(NdCvError)?; Ok(MatRef::new(mat)) } } impl, D: ndarray::Dimension> NdAsMatMut for ndarray::ArrayBase { fn as_single_channel_mat_mut(&mut self) -> Result { let mat = unsafe { impls::ndarray_to_mat_regular(self) }.change_context(NdCvError)?; Ok(MatRefMut::new(mat)) } fn as_multi_channel_mat_mut(&mut self) -> Result { let mat = unsafe { impls::ndarray_to_mat_consolidated(self) }.change_context(NdCvError)?; Ok(MatRefMut::new(mat)) } } pub trait NdAsImage { fn as_image_mat(&self) -> Result; } pub trait NdAsImageMut { fn as_image_mat_mut(&mut self) -> Result; } impl NdAsImage for ndarray::ArrayBase where T: bytemuck::Pod + Copy, S: ndarray::Data, { fn as_image_mat(&self) -> Result { self.as_single_channel_mat() } } impl NdAsImageMut for ndarray::ArrayBase where T: bytemuck::Pod + Copy, S: ndarray::DataMut, { fn as_image_mat_mut(&mut self) -> Result { self.as_single_channel_mat_mut() } } impl NdAsImage for ndarray::ArrayBase where T: bytemuck::Pod + Copy, S: ndarray::Data, { fn as_image_mat(&self) -> Result { self.as_multi_channel_mat() } } impl NdAsImageMut for ndarray::ArrayBase where T: bytemuck::Pod + Copy, S: ndarray::DataMut, { fn as_image_mat_mut(&mut self) -> Result { self.as_multi_channel_mat_mut() } } // #[test] // fn test_1d_mat_to_ndarray() { // let mat = opencv::core::Mat::new_nd_with_default( // &[10], // opencv::core::CV_MAKE_TYPE(opencv::core::CV_8U, 1), // 200.into(), // ) // .expect("failed"); // let array: ndarray::ArrayView1 = mat.as_ndarray().expect("failed"); // array.into_iter().for_each(|&x| assert_eq!(x, 200)); // } // #[test] // fn test_2d_mat_to_ndarray() { // let mat = opencv::core::Mat::new_nd_with_default( // &[10], // opencv::core::CV_16SC3, // (200, 200, 200).into(), // ) // .expect("failed"); // let array2: ndarray::ArrayView2 = mat.as_ndarray().expect("failed"); // assert_eq!(array2.shape(), [10, 3]); // array2.into_iter().for_each(|&x| { // assert_eq!(x, 200); // }); // } // #[test] // fn test_3d_mat_to_ndarray() { // let mat = opencv::core::Mat::new_nd_with_default( // &[20, 30], // opencv::core::CV_32FC3, // (200, 200, 200).into(), // ) // .expect("failed"); // let array2: ndarray::ArrayView3 = mat.as_ndarray().expect("failed"); // array2.into_iter().for_each(|&x| { // assert_eq!(x, 200f32); // }); // } // #[test] // fn test_mat_to_dyn_ndarray() { // let mat = opencv::core::Mat::new_nd_with_default(&[10], opencv::core::CV_8UC1, 200.into()) // .expect("failed"); // let array2: ndarray::ArrayViewD = mat.as_ndarray().expect("failed"); // array2.into_iter().for_each(|&x| assert_eq!(x, 200)); // } // #[test] // fn test_3d_mat_to_ndarray_4k() { // let mat = opencv::core::Mat::new_nd_with_default( // &[4096, 4096], // opencv::core::CV_8UC3, // (255, 0, 255).into(), // ) // .expect("failed"); // let array2: ndarray::ArrayView3 = (mat).as_ndarray().expect("failed"); // array2.exact_chunks((1, 1, 3)).into_iter().for_each(|x| { // assert_eq!(x[(0, 0, 0)], 255); // assert_eq!(x[(0, 0, 1)], 0); // assert_eq!(x[(0, 0, 2)], 255); // }); // } // // #[test] // // fn test_3d_mat_to_ndarray_8k() { // // let mat = opencv::core::Mat::new_nd_with_default( // // &[8192, 8192], // // opencv::core::CV_8UC3, // // (255, 0, 255).into(), // // ) // // .expect("failed"); // // let array2 = ndarray::Array3::::from_mat(mat).expect("failed"); // // array2.exact_chunks((1, 1, 3)).into_iter().for_each(|x| { // // assert_eq!(x[(0, 0, 0)], 255); // // assert_eq!(x[(0, 0, 1)], 0); // // assert_eq!(x[(0, 0, 2)], 255); // // }); // // } // #[test] // pub fn test_mat_to_nd_default_strides() { // let mat = opencv::core::Mat::new_rows_cols_with_default( // 10, // 10, // opencv::core::CV_8UC3, // opencv::core::VecN([10f64, 0.0, 0.0, 0.0]), // ) // .expect("failed"); // let array = unsafe { impls::mat_to_ndarray::(&mat) }.expect("failed"); // assert_eq!(array.shape(), [10, 10, 3]); // assert_eq!(array.strides(), [30, 3, 1]); // assert_eq!(array[(0, 0, 0)], 10); // } // #[test] // pub fn test_mat_to_nd_custom_strides() { // let mat = opencv::core::Mat::new_rows_cols_with_default( // 10, // 10, // opencv::core::CV_8UC3, // opencv::core::VecN([10f64, 0.0, 0.0, 0.0]), // ) // .unwrap(); // let mat_roi = opencv::core::Mat::roi(&mat, opencv::core::Rect::new(3, 2, 3, 5)) // .expect("failed to get roi"); // let array = unsafe { impls::mat_to_ndarray::(&mat_roi) }.expect("failed"); // assert_eq!(array.shape(), [5, 3, 3]); // assert_eq!(array.strides(), [30, 3, 1]); // assert_eq!(array[(0, 0, 0)], 10); // } // #[test] // pub fn test_non_continuous_3d() { // let array = ndarray::Array3::::from_shape_fn((10, 10, 4), |(i, j, k)| { // ((i + 1) * (j + 1) * (k + 1)) as f32 // }); // let slice = array.slice(ndarray::s![3..7, 3..7, 0..4]); // let mat = unsafe { impls::ndarray_to_mat_consolidated(&slice) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert!(slice == arr); // } // #[test] // pub fn test_5d_array() { // let array = ndarray::Array5::::ones((1, 2, 3, 4, 5)); // let mat = unsafe { impls::ndarray_to_mat_consolidated(&array) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert_eq!(array, arr); // } // #[test] // pub fn test_3d_array() { // let array = ndarray::Array3::::ones((23, 31, 33)); // let mat = unsafe { impls::ndarray_to_mat_consolidated(&array) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert_eq!(array, arr); // } // #[test] // pub fn test_2d_array() { // let array = ndarray::Array2::::ones((23, 31)); // let mat = unsafe { impls::ndarray_to_mat_consolidated(&array) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert_eq!(array, arr); // } // #[test] // #[should_panic] // pub fn test_1d_array_consolidated() { // let array = ndarray::Array1::::ones(23); // let mat = unsafe { impls::ndarray_to_mat_consolidated(&array) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert_eq!(array, arr); // } // #[test] // pub fn test_1d_array_regular() { // let array = ndarray::Array1::::ones(23); // let mat = unsafe { impls::ndarray_to_mat_regular(&array) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert_eq!(array, arr); // } // #[test] // pub fn test_2d_array_regular() { // let array = ndarray::Array2::::ones((23, 31)); // let mat = unsafe { impls::ndarray_to_mat_regular(&array) }.unwrap(); // let arr = unsafe { impls::mat_to_ndarray::(&mat).unwrap() }; // assert_eq!(array, arr); // } // #[test] // pub fn test_ndcv_1024_1024_to_mat() { // let array = ndarray::Array2::::ones((1024, 1024)); // let _mat = array.to_mat().unwrap(); // }