change the behavior of Mat::at() to follow the upstream
MODIFY
src/hub/manual/core/mat.rs
src/hub/manual/core/mat.rs
@@ -107,6 +107,16 @@ impl Mat {
}
}
+ #[inline(always)]
+ fn match_total(&self, idx: i32) -> Result<()> {
+ let size = self.total()?;
+ if 0 <= idx && (idx as usize) < size {
+ Ok(())
+ } else {
+ Err(Error::new(core::StsOutOfRange, format!("Index: {} out of bounds: 0..{}", idx, size)))
+ }
+ }
+
#[inline(always)]
fn convert_ptr<T>(r: &u8) -> &T {
unsafe { &*(r as *const _ as *const T) }
@@ -118,45 +128,51 @@ impl Mat {
}
#[inline(always)]
- pub(crate) fn _at<T: DataType>(&self, row: i32) -> Result<&T> {
- self.match_format::<T>()?;
- let size = self.size()?;
- if row >= size.height {
- return Err(Error::new(
- core::StsOutOfRange,
- format!("Given coordinate is out of bounds. \
- Mat has size {:?} but was given row: {}", size, row)));
- }
- unsafe { self.at_unchecked(row) }
+ pub(crate) fn _at<T: DataType>(&self, i0: i32) -> Result<&T> {
+ self.match_format::<T>()
+ .and_then(|_| self.match_dims(2))
+ .and_then(|_| self.match_total(i0))
+ .and_then(|_| unsafe { self.at_unchecked(i0) })
}
/// Like `Mat::at()` but performs no bounds or type checks
- ///
- /// Note that this (and `Mat::at()`) differs from the behavior of OpenCV's
- /// `_Tp& cv::Mat::at(int i0 = 0)`, in that it only looks up by row, and
- /// does not look up by column in the case of single-row Mats, as OpenCV's
- /// `Mat::at()` does.
- /// (This upstream behavior is documented at https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#aa5d20fc86d41d59e4d71ae93daee9726)
- pub unsafe fn at_unchecked<T: DataType>(&self, row: i32) -> Result<&T> {
- self.ptr(row).map(Self::convert_ptr)
+ pub unsafe fn at_unchecked<T: DataType>(&self, i0: i32) -> Result<&T> {
+ let mat_size = self.mat_size()?;
+ let mat_size = mat_size.deref();
+ let (i, j) = if self.is_continuous()? || mat_size[0] == 1 {
+ (0, i0)
+ } else if mat_size[1] == 1 {
+ (i0, 0)
+ } else {
+ let i = i0 / mat_size[1];
+ (i, i0 - i * mat_size[1])
+ };
+ self.ptr_2d(i, j)
+ .map(Self::convert_ptr)
}
#[inline(always)]
pub(crate) fn _at_mut<T: DataType>(&mut self, i0: i32) -> Result<&mut T> {
- self.match_format::<T>()?;
- let size = self.size()?;
- if i0 >= size.height {
- return Err(Error::new(
- core::StsOutOfRange,
- format!("Given coordinate is out of bounds. \
- Mat has size {:?} but was given i0: {}", size, i0)));
- }
+ self.match_format::<T>()
+ .and_then(|_| self.match_dims(2))
+ .and_then(|_| self.match_total(i0))?;
unsafe { self.at_mut_unchecked(i0) }
}
/// Like `Mat::at_mut()` but performs no bounds or type checks
pub unsafe fn at_mut_unchecked<T: DataType>(&mut self, i0: i32) -> Result<&mut T> {
- self.ptr_mut(i0).map(Self::convert_ptr_mut)
+ let mat_size = self.mat_size()?;
+ let mat_size = mat_size.deref();
+ let (i, j) = if self.is_continuous()? || mat_size[0] == 1 {
+ (0, i0)
+ } else if mat_size[1] == 1 {
+ (i0, 0)
+ } else {
+ let i = i0 / mat_size[1];
+ (i, i0 - i * mat_size[1])
+ };
+ self.ptr_2d_mut(i, j)
+ .map(Self::convert_ptr_mut)
}
#[inline(always)]
@@ -243,7 +259,7 @@ impl Mat {
/// Like `Mat::at_row()` but performs no bounds or type checks
pub unsafe fn at_row_unchecked<T: DataType>(&self, row: i32) -> Result<&[T]> {
let width = self.size()?.width as usize;
- self.at_unchecked(row).map(|x| slice::from_raw_parts(x, width))
+ self.ptr(row).map(Self::convert_ptr).map(|x| slice::from_raw_parts(x, width))
}
/// Return a complete writeable row
@@ -256,7 +272,7 @@ impl Mat {
/// Like `Mat::at_row_mut()` but performs no bounds or type checks
pub unsafe fn at_row_mut_unchecked<T: DataType>(&mut self, row: i32) -> Result<&mut [T]> {
let width = self.size()?.width as usize;
- self.at_mut_unchecked(row).map(|x| slice::from_raw_parts_mut(x, width))
+ self.ptr_mut(row).map(Self::convert_ptr_mut).map(|x| slice::from_raw_parts_mut(x, width))
}
pub fn size(&self) -> Result<core::Size> {

MODIFY
tests/mat.rs
tests/mat.rs
@@ -72,6 +72,7 @@ fn mat_nd() -> Result<()> {
{
let dims = VectorOfint::from_iter(vec![3, 3, 3]);
let mut mat = Mat::new_nd_with_default(&dims, Vec4w::typ(), Scalar::default())?;
+ assert_matches!(mat.at::<Vec4w>(0), Err(Error { code: core::StsUnmatchedSizes, ..}));
assert_eq!(0, mat.at_3d::<Vec4w>(1, 1, 1)?[0]);
*mat.at_3d_mut::<Vec4w>(1, 1, 1)? = Vec4w::all(10);
assert_eq!(10, mat.at_3d::<Vec4w>(1, 1, 1)?[0]);
@@ -99,11 +100,57 @@ fn mat_nd() -> Result<()> {
}
#[test]
-fn mat_at_1d_refers_to_rows() -> Result<()> {
- let mut mat =
- Mat::new_rows_cols_with_default(100, 100, f32::typ(), Scalar::all(1.23))?;
- *mat.at_mut::<f32>(5)? = 1.;
- assert_eq!(*mat.at_2d::<f32>(5, 0)?, 1.);
+fn mat_at_1d() -> Result<()> {
+ let s: Vec<Vec<f32>> = vec![
+ vec![1., 2., 3.],
+ vec![4., 5., 6.],
+ vec![7., 8., 9.],
+ ];
+
+ {
+ let mat = Mat::from_slice_2d(&s)?;
+ let mut mat = mat.reshape(1, 1)?;
+ assert_eq!(1, mat.rows()?);
+ assert_eq!(9, mat.cols()?);
+ assert_matches!(mat.at::<f32>(-1), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at::<f32>(10), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at_mut::<f32>(-1), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at_mut::<f32>(10), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_eq!(*mat.at::<f32>(0)?, 1.);
+ assert_eq!(*mat.at::<f32>(5)?, 6.);
+ assert_eq!(*mat.at::<f32>(8)?, 9.);
+ *mat.at_mut::<f32>(4)? = 2.;
+ assert_eq!(*mat.at::<f32>(4)?, 2.);
+ }
+
+ {
+ let mat = Mat::from_slice_2d(&s)?;
+ let mut mat = mat.reshape(1, 9)?;
+ assert_eq!(9, mat.rows()?);
+ assert_eq!(1, mat.cols()?);
+ assert_matches!(mat.at::<f32>(-1), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at::<f32>(10), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at_mut::<f32>(-1), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at_mut::<f32>(10), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_eq!(*mat.at::<f32>(0)?, 1.);
+ assert_eq!(*mat.at::<f32>(4)?, 5.);
+ assert_eq!(*mat.at::<f32>(8)?, 9.);
+ *mat.at_mut::<f32>(4)? = 2.;
+ assert_eq!(*mat.at::<f32>(4)?, 2.);
+ }
+
+ {
+ let mut mat = Mat::from_slice_2d(&s)?;
+ assert_matches!(mat.at::<f32>(-1), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at::<f32>(10), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at_mut::<f32>(-1), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at_mut::<f32>(10), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_eq!(*mat.at::<f32>(0)?, 1.);
+ assert_eq!(*mat.at::<f32>(6)?, 7.);
+ assert_eq!(*mat.at::<f32>(8)?, 9.);
+ *mat.at_mut::<f32>(4)? = 2.;
+ assert_eq!(*mat.at::<f32>(4)?, 2.);
+ }
Ok(())
}
@@ -125,7 +172,7 @@ fn mat_at_2d() -> Result<()> {
*mat.at_2d_mut::<f32>(0, 0)? = 1.;
assert_eq!(*mat.at_2d::<f32>(0, 0)?, 1.);
assert_matches!(mat.at::<i32>(0), Err(Error { code: core::StsUnmatchedFormats, ..}));
- assert_matches!(mat.at::<f32>(100), Err(Error { code: core::StsOutOfRange, ..}));
+ assert_matches!(mat.at::<f32>(10000), Err(Error { code: core::StsOutOfRange, ..}));
Ok(())
}

change the behavior of Mat::at() to follow the upstream