Improve support for accessing Mat->data
MODIFY
src/manual/core/mat.rs
src/manual/core/mat.rs
@@ -381,15 +381,26 @@ pub trait MatTraitConstManual: MatTraitConst {
}
fn is_allocated(&self) -> bool {
- extern "C" { fn cv_manual_Mat_is_allocated(instance: *const c_void) -> bool; }
- unsafe { cv_manual_Mat_is_allocated(self.as_raw_Mat()) }
+ !self.data().is_null()
}
- fn data(&self) -> Result<&u8> {
- extern "C" { fn cv_manual_Mat_data(instance: *const c_void) -> sys::Result<*const u8>; }
+ /// Raw pointer to the underlying data array, can be NULL
+ fn data(&self) -> *const u8 {
+ extern "C" { fn cv_manual_Mat_data(instance: *const c_void) -> *const u8; }
unsafe { cv_manual_Mat_data(self.as_raw_Mat()) }
- .into_result()
- .and_then(|x| unsafe { x.as_ref() }.ok_or_else(|| Error::new(core::StsNullPtr, "Function returned Null pointer".to_string())))
+ }
+
+ /// Returns underlying data array as byte slice, Mat must be continuous.
+ fn data_bytes(&self) -> Result<&[u8]> {
+ match_is_continuous(self)
+ .and_then(|_| {
+ let data = self.data();
+ if data.is_null() {
+ Err(Error::new(core::StsNullPtr, "Function returned Null pointer".to_string()))
+ } else {
+ Ok(unsafe { slice::from_raw_parts(data, self.total()? * self.elem_size()?) })
+ }
+ })
}
fn data_typed<T: DataType>(&self) -> Result<&[T]> {
@@ -401,8 +412,12 @@ pub trait MatTraitConstManual: MatTraitConst {
/// # Safety
/// Caller must ensure that the `T` type argument corresponds to the data stored in the `Mat`
unsafe fn data_typed_unchecked<T: DataType>(&self) -> Result<&[T]> {
- let total = self.total()?;
- self.data().map(|x| slice::from_raw_parts(x as *const u8 as *const T, total))
+ let data = self.data();
+ if data.is_null() {
+ Err(Error::new(core::StsNullPtr, "Function returned Null pointer".to_string()))
+ } else {
+ Ok(slice::from_raw_parts(data as *const T, self.total()?))
+ }
}
fn to_vec_2d<T: DataType>(&self) -> Result<Vec<Vec<T>>> {
@@ -505,6 +520,14 @@ pub trait MatTraitManual: MatTraitConstManual + MatTrait {
.into_result()
}
+ /// Returns underlying data array as mutable byte slice, Mat must be continuous.
+ fn data_bytes_mut(&mut self) -> Result<&mut [u8]> {
+ match_is_continuous(self)
+ .and_then(|_| {
+ Ok(unsafe { slice::from_raw_parts_mut(self.data_mut(), self.total()? * self.elem_size()?) })
+ })
+ }
+
fn data_typed_mut<T: DataType>(&mut self) -> Result<&mut [T]> {
match_format::<T>(self.typ()?)
.and_then(|_| match_is_continuous(self))?;

MODIFY
src_cpp/manual-core.cpp
src_cpp/manual-core.cpp
@@ -37,10 +37,6 @@ extern "C" {
} OCVRS_CATCH(Result<cv::Size>)
}
- bool cv_manual_Mat_is_allocated(const cv::Mat* instance) {
- return instance->data != NULL;
- }
-
Result_void cv_manual_Mat_set(cv::Mat* instance, cv::Scalar s) {
try {
*instance = s;
@@ -48,10 +44,8 @@ extern "C" {
} OCVRS_CATCH(Result_void)
}
- Result<const unsigned char*> cv_manual_Mat_data(const cv::Mat* instance) {
- try {
- return Ok<const unsigned char*>(instance->data);
- } OCVRS_CATCH(Result<const unsigned char*>)
+ const unsigned char* cv_manual_Mat_data(const cv::Mat* instance) {
+ return instance->data;
}
Result<cv::Size> cv_manual_UMat_size(const cv::UMat* instance) {

MODIFY
tests/mat.rs
tests/mat.rs
@@ -21,7 +21,7 @@ fn mat_default() -> Result<()> {
assert_eq!(Size::new(0, 0), mat.size()?);
assert_eq!(0, mat.dims());
assert!(!mat.is_allocated());
- assert_matches!(mat.data(), Err(Error { code: core::StsNullPtr, ..}));
+ assert!(mat.data().is_null());
Ok(())
}
@@ -30,12 +30,14 @@ fn mat_create() -> Result<()> {
let mut mat = Mat::default();
unsafe { mat.create_rows_cols(10, 10, u16::typ())? };
assert!(mat.is_allocated());
+ assert!(!mat.data().is_null());
mat.set(Scalar::from(7.))?;
assert_eq!(7, *mat.at_2d::<u16>(0, 0)?);
assert_eq!(7, *mat.at_2d::<u16>(3, 3)?);
assert_eq!(7, *mat.at_2d::<u16>(9, 9)?);
mat.release()?;
assert!(!mat.is_allocated());
+ assert!(mat.data().is_null());
assert_eq!(Size::new(0, 0), mat.size()?);
Ok(())
}
@@ -543,3 +545,29 @@ fn mat_mul() -> Result<()> {
}
Ok(())
}
+
+#[test]
+fn mat_data() -> Result<()> {
+ {
+ let mat = Mat::from_slice(&[8, 13, 21, 39u8])?;
+ assert_eq!(&[8, 13, 21, 39], mat.data_bytes()?);
+ let roi = Mat::roi(&mat, Rect::new(1, 0, 2, 1))?;
+ assert_eq!(&[13, 21], roi.data_bytes()?);
+ }
+
+ {
+ let mat = Mat::from_slice_2d(&[[6, 7], [16, 17u8]])?;
+ assert_eq!(&[6, 7, 16, 17], mat.data_bytes()?);
+ let roi = Mat::roi(&mat, Rect::new(0, 0, 1, 2))?;
+ assert_matches!(roi.data_bytes(), Err(Error { code: core::StsUnmatchedSizes, .. }));
+ }
+
+ {
+ let mut mat = Mat::from_slice(&[Vec2b::from([5, 8]), Vec2b::from([13, 21])])?;
+ assert_eq!(&[5, 8, 13, 21], mat.data_bytes()?);
+ let bytes = mat.data_bytes_mut()?;
+ bytes[1] = 90;
+ assert_eq!(&[5, 90, 13, 21], mat.data_bytes()?);
+ }
+ Ok(())
+}

Improve support for accessing Mat->data