Skip to content

Commit 3f699de

Browse files
committed
Add in-place modification helper
1 parent 587e166 commit 3f699de

File tree

4 files changed

+75
-1
lines changed

4 files changed

+75
-1
lines changed

src/manual/core.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub use affine3::*;
22
pub use data_type::*;
33
pub use directx::*;
4+
pub use inplace::*;
45
pub use input_output_array::*;
56
pub use mat::*;
67
pub use mat_ops::*;
@@ -21,6 +22,7 @@ mod affine3;
2122
mod data_type;
2223
mod directx;
2324
mod gpumat;
25+
mod inplace;
2426
mod input_output_array;
2527
mod mat;
2628
mod mat_ops;

src/manual/core/inplace.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::boxed_ref::BoxedRefMut;
2+
use crate::traits::Boxed;
3+
4+
pub trait ModifyInplace {
5+
/// Helper function to call OpenCV functions that allow in-place modification of a `Mat` or another similar object. By passing
6+
/// a mutable reference to the `Mat` to this function your closure will get called with the read reference and a write references
7+
/// to the same `Mat`. This is of course unsafe as it breaks the Rust aliasing rules, but it might be useful for some performance
8+
/// sensitive operations. One example of an OpenCV function that allows such in-place modification is `imgproc::threshold`.
9+
///
10+
/// # Safety
11+
/// Caller must make sure that any functions called inside the closure can act on a `Mat` in-place.
12+
unsafe fn modify_inplace<Res>(&mut self, f: impl FnOnce(&Self, &mut Self) -> Res) -> Res;
13+
}
14+
15+
impl<Mat: Boxed> ModifyInplace for Mat {
16+
#[inline(always)]
17+
unsafe fn modify_inplace<Res>(&mut self, f: impl FnOnce(&Self, &mut Self) -> Res) -> Res {
18+
let mut m_alias = Mat::from_raw(self.as_raw_mut());
19+
let out = f(self, &mut m_alias);
20+
// prevent running destructor on m_alias
21+
let _ = m_alias.into_raw();
22+
out
23+
}
24+
}
25+
26+
impl<'b, Mat: Boxed> ModifyInplace for BoxedRefMut<'b, Mat> {
27+
#[inline(always)]
28+
unsafe fn modify_inplace<Res>(&mut self, f: impl FnOnce(&Self, &mut Self) -> Res) -> Res {
29+
let mut m_alias = BoxedRefMut::from(Mat::from_raw(self.reference.as_raw_mut()));
30+
let out = f(self, &mut m_alias);
31+
// prevent running destructor on m_alias
32+
let _ = m_alias.reference.into_raw();
33+
out
34+
}
35+
}

src/manual/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ pub mod prelude {
1010
pub use super::core::MatSizeTraitConstManual;
1111
pub use super::core::VectorToVec;
1212
#[cfg(ocvrs_has_module_core)]
13-
pub use super::core::{MatConstIteratorTraitManual, MatTraitConstManual, MatTraitManual, MatxTrait};
13+
pub use super::core::{MatConstIteratorTraitManual, MatTraitConstManual, MatTraitManual, MatxTrait, ModifyInplace};
1414
}

tests/inplace.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use opencv::core::Vector;
2+
use opencv::prelude::*;
3+
use opencv::{imgproc, Result};
4+
5+
#[test]
6+
fn inplace() -> Result<()> {
7+
// owned Mat
8+
{
9+
let data: [f32; 9] = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
10+
let mut m = Mat::new_rows_cols_with_data(3, 3, &data)?.clone_pointee();
11+
unsafe {
12+
m.modify_inplace(|i, o| imgproc::threshold(i, o, 4., 100., imgproc::THRESH_BINARY))?;
13+
}
14+
assert_eq!([0., 0., 0., 0., 100., 100., 100., 100., 100.], m.data_typed::<f32>()?);
15+
}
16+
17+
// BoxedRefMut<Mat>
18+
{
19+
let mut data: [f32; 9] = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
20+
let mut m = Mat::new_rows_cols_with_data_mut(3, 3, &mut data)?;
21+
unsafe {
22+
m.modify_inplace(|i, o| imgproc::threshold(i, o, 4., 100., imgproc::THRESH_BINARY))?;
23+
}
24+
assert_eq!([0., 0., 0., 0., 100., 100., 100., 100., 100.], m.data_typed::<f32>()?);
25+
assert_eq!([0., 0., 0., 0., 100., 100., 100., 100., 100.], data);
26+
}
27+
28+
// Vector
29+
{
30+
let mut data = Vector::<f64>::from_slice(&[1., 2., 3., 4., 5., 6., 7., 8., 9.]);
31+
unsafe {
32+
data.modify_inplace(|i, o| imgproc::threshold(i, o, 4., 100., imgproc::THRESH_BINARY))?;
33+
}
34+
assert_eq!([0., 0., 0., 0., 100., 100., 100., 100., 100.], data.as_slice());
35+
}
36+
Ok(())
37+
}

0 commit comments

Comments
 (0)