opencv/manual/core/
mat.rs

1use std::convert::TryInto;
2use std::ffi::c_void;
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::{fmt, mem, ptr, slice};
6
7pub use mat_::*;
8
9use crate::boxed_ref::{BoxedRef, BoxedRefMut};
10use crate::core::{MatConstIterator, MatExpr, MatSize, MatStep, Point, Rect, Scalar, Size, UMat};
11use crate::manual::core::DataType;
12use crate::prelude::*;
13use crate::{core, input_output_array, input_output_array_vector, Error, Result};
14
15mod mat_;
16
17#[inline(always)]
18/// We rely on OpenCV to make sure that the pointer is correctly aligned
19unsafe fn convert_ptr<'r, T>(r: *const u8) -> &'r T {
20	unsafe { &*(r.cast::<T>()) }
21}
22
23#[inline(always)]
24/// We rely on OpenCV to make sure that the pointer is correctly aligned
25unsafe fn convert_ptr_mut<'r, T>(r: *mut u8) -> &'r mut T {
26	unsafe { &mut *(r.cast::<T>()) }
27}
28
29trait MatMatcher {
30	fn match_indices(&self, idx: &[i32]) -> Result<()>;
31	fn match_total(&self, idx: i32) -> Result<()>;
32	fn match_max_dims(&self, max_dims: i32) -> Result<()>;
33	fn match_is_continuous(&self) -> Result<()>;
34}
35
36impl<T: MatTraitConst + ?Sized> MatMatcher for T {
37	fn match_indices(&self, idx: &[i32]) -> Result<()> {
38		let mat_size = self.mat_size();
39		let size = &*mat_size;
40		if size.len() != idx.len() {
41			return Err(Error::new(
42				core::StsUnmatchedSizes,
43				format!(
44					"Amount of Mat dimensions: {} doesn't match the amount of requested indices: {}",
45					size.len(),
46					idx.len()
47				),
48			));
49		}
50		if let Some((out_idx, (out_idx_val, out_size))) = idx
51			.iter()
52			.zip(size)
53			.enumerate()
54			.find(|(_, (idx_val, &size))| !(0..size).contains(idx_val))
55		{
56			Err(Error::new(
57				core::StsOutOfRange,
58				format!("Index: {out_idx_val} along dimension: {out_idx} out of bounds 0..{out_size}"),
59			))
60		} else {
61			Ok(())
62		}
63	}
64
65	#[inline]
66	fn match_total(&self, idx: i32) -> Result<()> {
67		let size = self.total();
68		// safe because of the `0 <= idx` check
69		if 0 <= idx && (idx as usize) < size {
70			Ok(())
71		} else {
72			Err(Error::new(
73				core::StsOutOfRange,
74				format!("Index: {idx} out of bounds: 0..{size}"),
75			))
76		}
77	}
78
79	#[inline]
80	fn match_max_dims(&self, max_dims: i32) -> Result<()> {
81		let dims = self.dims();
82		// safe because of the `0 <= idx` check
83		if (0..=max_dims).contains(&dims) {
84			Ok(())
85		} else {
86			Err(Error::new(
87				core::StsOutOfRange,
88				format!("Mat contains too many dimensions: {dims}, maximum for this operation: {max_dims}"),
89			))
90		}
91	}
92
93	#[inline]
94	fn match_is_continuous(&self) -> Result<()> {
95		if self.is_continuous() {
96			Ok(())
97		} else {
98			Err(Error::new(
99				core::StsUnmatchedSizes,
100				"Mat is not continuous, operation is not applicable",
101			))
102		}
103	}
104}
105
106#[inline]
107fn match_format<T: DataType>(mat_type: i32) -> Result<()> {
108	let out_type = T::opencv_type();
109	if mat_type == out_type {
110		Ok(())
111	} else {
112		let mat_type = core::type_to_string(mat_type)?;
113		let out_type = core::type_to_string(out_type)?;
114		Err(Error::new(
115			core::StsUnmatchedFormats,
116			format!("Mat type is: {mat_type}, but requested type is: {out_type}"),
117		))
118	}
119}
120
121fn match_length(sizes: &[i32], slice_len: usize, size_mul: usize) -> Result<()> {
122	let mut expected_len: u64 = 1;
123	for (i, size) in sizes.iter().enumerate() {
124		let size =
125			u64::try_from(*size).map_err(|_| Error::new(core::StsOutOfRange, format!("Dimension {i} must not be negative")))?;
126		expected_len = expected_len.saturating_mul(size);
127	}
128	if size_mul > 1 {
129		expected_len = expected_len.saturating_mul(
130			u64::try_from(size_mul).map_err(|_| Error::new(core::StsOutOfRange, "Size multiplier must fit in u64"))?,
131		);
132	}
133	let slice_len = u64::try_from(slice_len).map_err(|_| Error::new(core::StsOutOfRange, "Length must fit in u64"))?;
134	if expected_len != slice_len {
135		let msg = match sizes {
136			[rows, cols] => {
137				format!("The length of the slice: {slice_len} must be: {expected_len} to match the passed row: {rows} and column: {cols} counts")
138			}
139			_ => {
140				format!("The length of the slice: {slice_len} must be: {expected_len} to match the passed dimensions: {sizes:?}")
141			}
142		};
143		return Err(Error::new(core::StsUnmatchedSizes, msg));
144	}
145	Ok(())
146}
147
148/// Port of the algo from `Mat::at(int i0)`, includes OpenCV 5 specifics
149#[inline(always)]
150unsafe fn data_at_idx<T: DataType>(mat: &(impl MatTraitConst + ?Sized), i0: usize) -> *const T {
151	let size = mat.mat_size();
152	let size = &*size;
153	let data = mat.data();
154	if size.len() <= 1 || mat.is_continuous() || size[0] == 1 {
155		unsafe { data.cast::<T>().add(i0) }
156	} else if size[1] == 1 {
157		unsafe { data.add(mat.mat_step()[0] * i0) }.cast::<T>()
158	} else {
159		let cols = usize::try_from(size[1]).unwrap_or(1);
160		let i = i0 / cols;
161		let j = i0 - i * cols;
162		unsafe { data.add(mat.mat_step()[0] * i).cast::<T>().add(j) }
163	}
164}
165
166#[inline]
167fn row_count_i32(row_count: usize) -> Result<i32> {
168	i32::try_from(row_count).map_err(|_| Error::new(core::StsBadArg, format!("Row count: {row_count} is too high")))
169}
170
171#[inline]
172fn col_count_i32(col_count: usize) -> Result<i32> {
173	i32::try_from(col_count).map_err(|_| Error::new(core::StsBadArg, format!("Column count: {col_count} is too high")))
174}
175
176impl Mat {
177	/// Create a new [Mat] from the iterator of known size
178	pub fn from_exact_iter<T: DataType>(s: impl ExactSizeIterator<Item = T>) -> Result<Self> {
179		let mut out = unsafe { Self::new_rows_cols(1, col_count_i32(s.len())?, T::opencv_type()) }?;
180		for (i, x) in s.enumerate() {
181			// safe because `row_count_i32` ensures that len of `s` fits `i32`
182			let i = i as i32;
183			unsafe { ptr::write(out.at_unchecked_mut::<T>(i), x) };
184		}
185		Ok(out)
186	}
187
188	/// Create a new [Mat] from a single-dimensional slice
189	#[inline]
190	pub fn from_slice<T: DataType>(s: &[T]) -> Result<BoxedRef<'_, Self>> {
191		Self::new_rows_cols_with_data(1, i32::try_from(s.len())?, s)
192	}
193
194	/// Create a new [Mat] from a single-dimensional byte slice
195	#[inline]
196	pub fn from_bytes<T: DataType>(s: &[u8]) -> Result<BoxedRef<'_, Self>> {
197		let rem = s.len() % mem::size_of::<T>();
198		if rem != 0 {
199			return Err(Error::new(
200				core::StsBadArg,
201				format!(
202					"Unexpected number of bytes: {}, expected multiple of: {} based on the indicated type",
203					s.len(),
204					mem::size_of::<T>()
205				),
206			));
207		}
208		let len = s.len() / mem::size_of::<T>();
209		Self::new_rows_cols_with_bytes::<T>(1, i32::try_from(len)?, s)
210	}
211
212	/// Create a new [Mat] from a mutable single-dimensional byte slice
213	#[inline]
214	pub fn from_bytes_mut<T: DataType>(s: &mut [u8]) -> Result<BoxedRefMut<'_, Self>> {
215		let rem = s.len() % mem::size_of::<T>();
216		if rem != 0 {
217			return Err(Error::new(
218				core::StsBadArg,
219				format!(
220					"Unexpected number of bytes: {}, expected multiple of: {} based on the indicated type",
221					s.len(),
222					mem::size_of::<T>()
223				),
224			));
225		}
226		let len = s.len() / mem::size_of::<T>();
227		Self::new_rows_cols_with_bytes_mut::<T>(1, i32::try_from(len)?, s)
228	}
229
230	/// Create a new [Mat] from a mutable single-dimensional slice
231	#[inline]
232	pub fn from_slice_mut<T: DataType>(s: &mut [T]) -> Result<BoxedRefMut<'_, Self>> {
233		Self::new_rows_cols_with_data_mut(1, i32::try_from(s.len())?, s)
234	}
235
236	/// Create a new 2D [Mat] by copying the data from a slice of slices
237	///
238	/// Every subslice must have the same length, otherwise an error is returned.
239	pub fn from_slice_2d<T: DataType>(s: &[impl AsRef<[T]>]) -> Result<Self> {
240		let col_count = if let Some(first_row) = s.first() {
241			col_count_i32(first_row.as_ref().len())?
242		} else {
243			0
244		};
245		let row_count = if col_count > 0 {
246			row_count_i32(s.len())?
247		} else {
248			0
249		};
250		let mut out = Self::new_rows_cols_with_default(row_count, col_count, T::opencv_type(), Scalar::all(0.))?;
251		if row_count > 0 && col_count > 0 {
252			for (row_n, row) in s.iter().enumerate() {
253				// safe because `row_count_i32` ensures that len of `s` fits `i32`
254				let row_n = row_n as i32;
255				let trg = out.at_row_mut(row_n)?;
256				let src = row.as_ref();
257				if trg.len() != src.len() {
258					return Err(Error::new(
259						core::StsUnmatchedSizes,
260						format!(
261							"Unexpected number of items: {} in a row index: {row_n}, expected: {}",
262							src.len(),
263							trg.len(),
264						),
265					));
266				}
267				trg.copy_from_slice(src);
268			}
269		}
270		Ok(out)
271	}
272
273	/// Create a new [Mat] that references a single-dimensional slice with a custom shape
274	#[inline]
275	pub fn new_rows_cols_with_data<T: DataType>(rows: i32, cols: i32, data: &[T]) -> Result<BoxedRef<'_, Self>> {
276		match_length(&[rows, cols], data.len(), 1)?;
277		let m = unsafe {
278			Self::new_rows_cols_with_data_unsafe_def(rows, cols, T::opencv_type(), data.as_ptr().cast::<c_void>().cast_mut())
279		}?;
280		Ok(<BoxedRef<Mat>>::from(m))
281	}
282
283	/// Create a new [Mat] that references a single-dimensional byte slice with a custom shape
284	#[inline]
285	pub fn new_rows_cols_with_bytes<T: DataType>(rows: i32, cols: i32, data: &[u8]) -> Result<BoxedRef<'_, Self>> {
286		match_length(&[rows, cols], data.len(), mem::size_of::<T>())?;
287		let m = unsafe {
288			Self::new_rows_cols_with_data_unsafe_def(rows, cols, T::opencv_type(), data.as_ptr().cast::<c_void>().cast_mut())
289		}?;
290		Ok(<BoxedRef<Mat>>::from(m))
291	}
292
293	/// Create a new mutable [Mat] that references a single-dimensional slice with a custom shape
294	#[inline]
295	pub fn new_rows_cols_with_data_mut<T: DataType>(rows: i32, cols: i32, data: &mut [T]) -> Result<BoxedRefMut<'_, Self>> {
296		match_length(&[rows, cols], data.len(), 1)?;
297		let m =
298			unsafe { Self::new_rows_cols_with_data_unsafe_def(rows, cols, T::opencv_type(), data.as_mut_ptr().cast::<c_void>()) }?;
299		Ok(<BoxedRefMut<Mat>>::from(m))
300	}
301
302	/// Create a new mutable [Mat] that references a single-dimensional byte slice with a custom shape
303	#[inline]
304	pub fn new_rows_cols_with_bytes_mut<T: DataType>(rows: i32, cols: i32, data: &mut [u8]) -> Result<BoxedRefMut<'_, Self>> {
305		match_length(&[rows, cols], data.len(), mem::size_of::<T>())?;
306		let m =
307			unsafe { Self::new_rows_cols_with_data_unsafe_def(rows, cols, T::opencv_type(), data.as_mut_ptr().cast::<c_void>()) }?;
308		Ok(<BoxedRefMut<Mat>>::from(m))
309	}
310
311	/// Create a new [Mat] that references a single-dimensional slice with a custom shape
312	#[inline]
313	pub fn new_size_with_data<T: DataType>(size: Size, data: &[T]) -> Result<BoxedRef<'_, Self>> {
314		match_length(&[size.width, size.height], data.len(), 1)?;
315		let m = unsafe { Self::new_size_with_data_unsafe_def(size, T::opencv_type(), data.as_ptr().cast::<c_void>().cast_mut()) }?;
316		Ok(<BoxedRef<Mat>>::from(m))
317	}
318
319	/// Create a new mutable [Mat] that references a single-dimensional slice with a custom shape
320	#[inline]
321	pub fn new_size_with_data_mut<T: DataType>(size: Size, data: &mut [T]) -> Result<BoxedRefMut<'_, Self>> {
322		match_length(&[size.width, size.height], data.len(), 1)?;
323		let m = unsafe { Self::new_size_with_data_unsafe_def(size, T::opencv_type(), data.as_mut_ptr().cast::<c_void>()) }?;
324		Ok(<BoxedRefMut<Mat>>::from(m))
325	}
326
327	/// Create a new [Mat] that references a single-dimensional slice with a custom shape
328	#[inline]
329	pub fn new_nd_with_data<'data, T: DataType>(sizes: &[i32], data: &'data [T]) -> Result<BoxedRef<'data, Self>> {
330		match_length(sizes, data.len(), 1)?;
331		let m = unsafe { Self::new_nd_with_data_unsafe_def(sizes, T::opencv_type(), data.as_ptr().cast::<c_void>().cast_mut()) }?;
332		Ok(<BoxedRef<Mat>>::from(m))
333	}
334
335	/// Create a new [Mat] that references a single-dimensional slice with a custom shape
336	#[inline]
337	pub fn new_nd_with_data_mut<'data, T: DataType>(sizes: &[i32], data: &'data mut [T]) -> Result<BoxedRefMut<'data, Self>> {
338		match_length(sizes, data.len(), 1)?;
339		let m = unsafe { Self::new_nd_with_data_unsafe_def(sizes, T::opencv_type(), data.as_mut_ptr().cast::<c_void>()) }?;
340		Ok(<BoxedRefMut<Mat>>::from(m))
341	}
342
343	/// Returns 2 mutable ROIs into a single [Mat] as long as they do not intersect
344	pub fn roi_2_mut<MAT: MatTrait>(m: &mut MAT, roi1: Rect, roi2: Rect) -> Result<(BoxedRefMut<'_, Mat>, BoxedRefMut<'_, Mat>)> {
345		if (roi1 & roi2).empty() {
346			// safe because we made sure that the interest areas do not intersect
347			let m2 = unsafe { (m as *mut MAT).as_mut().expect("Can't fail") };
348			let out1 = Mat::roi_mut(m, roi1)?;
349			let out2 = Mat::roi_mut(m2, roi2)?;
350			Ok((out1, out2))
351		} else {
352			Err(Error::new(core::StsBadArg, "ROIs must not intersect"))
353		}
354	}
355}
356
357pub struct MatIter<'m, T> {
358	iter: Option<MatConstIterator>,
359	_d: PhantomData<&'m T>,
360}
361
362impl<T: DataType> MatIter<'_, T> {
363	pub fn new(iter: MatConstIterator) -> Result<Self> {
364		match_format::<T>(iter.typ())?;
365		Ok(Self {
366			iter: Some(iter),
367			_d: PhantomData,
368		})
369	}
370}
371
372impl<T: DataType> Iterator for MatIter<'_, T> {
373	type Item = (Point, T);
374
375	fn next(&mut self) -> Option<Self::Item> {
376		self.iter.as_mut().and_then(|iter| {
377			if iter.has_elements() {
378				// the type is checked by the `MatIter::new()` and we ensure there are still elements by calling `has_elements()`
379				let cur = *unsafe { convert_ptr(iter.ptr()) };
380				let pos = iter.pos().ok()?;
381				iter.seek(1, true).ok()?;
382				Some((pos, cur))
383			} else {
384				None
385			}
386		})
387	}
388}
389
390pub struct MatIterMut<'m, T> {
391	iter: Option<MatConstIterator>,
392	_d: PhantomData<&'m mut T>,
393}
394
395impl<T: DataType> MatIterMut<'_, T> {
396	pub fn new(iter: MatConstIterator) -> Result<Self> {
397		match_format::<T>(iter.typ())?;
398		Ok(Self {
399			iter: Some(iter),
400			_d: PhantomData,
401		})
402	}
403}
404
405impl<'m, T: DataType> Iterator for MatIterMut<'m, T> {
406	type Item = (Point, &'m mut T);
407
408	fn next(&mut self) -> Option<Self::Item> {
409		self.iter.as_mut().and_then(|iter| {
410			if iter.has_elements() {
411				// the type is checked by the `MatIterMut::new()` and we ensure there are still elements by calling `has_elements()`
412				let cur = unsafe { convert_ptr_mut(iter.ptr().cast_mut()) };
413				let pos = iter.pos().ok()?;
414				iter.seek(1, true).ok()?;
415				Some((pos, cur))
416			} else {
417				None
418			}
419		})
420	}
421}
422
423pub(crate) mod mat_forward {
424	use super::*;
425
426	#[inline]
427	pub fn at<T: DataType>(mat: &(impl MatTraitConst + ?Sized), i0: i32) -> Result<&T> {
428		match_format::<T>(mat.typ())
429			.and_then(|_| mat.match_total(i0))
430			.and_then(|_| mat.match_max_dims(2))
431			.map(|_| unsafe { mat.at_unchecked(i0) })
432	}
433
434	#[inline]
435	pub fn at_def<T: DataType>(mat: &(impl MatTraitConst + ?Sized)) -> Result<&T> {
436		at(mat, 0)
437	}
438
439	#[inline]
440	pub fn at_mut<T: DataType>(mat: &mut (impl MatTrait + ?Sized), i0: i32) -> Result<&mut T> {
441		match_format::<T>(mat.typ()).and_then(|_| mat.match_total(i0))?;
442		Ok(unsafe { mat.at_unchecked_mut(i0) })
443	}
444
445	#[inline]
446	pub fn at_mut_def<T: DataType>(mat: &mut (impl MatTrait + ?Sized)) -> Result<&mut T> {
447		at_mut(mat, 0)
448	}
449
450	#[inline]
451	pub fn at_2d<T: DataType>(mat: &(impl MatTraitConst + ?Sized), row: i32, col: i32) -> Result<&T> {
452		match_format::<T>(mat.typ())
453			.and_then(|_| mat.match_indices(&[row, col]))
454			.and_then(|_| unsafe { mat.at_2d_unchecked(row, col) })
455	}
456
457	#[inline]
458	pub fn at_2d_mut<T: DataType>(mat: &mut (impl MatTrait + ?Sized), row: i32, col: i32) -> Result<&mut T> {
459		match_format::<T>(mat.typ()).and_then(|_| mat.match_indices(&[row, col]))?;
460		unsafe { mat.at_2d_unchecked_mut(row, col) }
461	}
462
463	#[inline]
464	pub fn at_pt<T: DataType>(mat: &(impl MatTraitConst + ?Sized), pt: Point) -> Result<&T> {
465		at_2d(mat, pt.y, pt.x)
466	}
467
468	#[inline]
469	pub fn at_pt_mut<T: DataType>(mat: &mut (impl MatTrait + ?Sized), pt: Point) -> Result<&mut T> {
470		at_2d_mut(mat, pt.y, pt.x)
471	}
472
473	#[inline]
474	pub fn at_3d<T: DataType>(mat: &(impl MatTraitConst + ?Sized), i0: i32, i1: i32, i2: i32) -> Result<&T> {
475		match_format::<T>(mat.typ())
476			.and_then(|_| mat.match_indices(&[i0, i1, i2]))
477			.and_then(|_| unsafe { mat.at_3d_unchecked(i0, i1, i2) })
478	}
479
480	#[inline]
481	pub fn at_3d_mut<T: DataType>(mat: &mut (impl MatTrait + ?Sized), i0: i32, i1: i32, i2: i32) -> Result<&mut T> {
482		match_format::<T>(mat.typ()).and_then(|_| mat.match_indices(&[i0, i1, i2]))?;
483		unsafe { mat.at_3d_unchecked_mut(i0, i1, i2) }
484	}
485
486	#[inline]
487	pub fn at_nd<'s, T: DataType>(mat: &'s (impl MatTraitConst + ?Sized), idx: &[i32]) -> Result<&'s T> {
488		match_format::<T>(mat.typ())
489			.and_then(|_| mat.match_indices(idx))
490			.and_then(|_| unsafe { mat.at_nd_unchecked(idx) })
491	}
492
493	#[inline]
494	pub fn at_nd_mut<'s, T: DataType>(mat: &'s mut (impl MatTrait + ?Sized), idx: &[i32]) -> Result<&'s mut T> {
495		match_format::<T>(mat.typ()).and_then(|_| mat.match_indices(idx))?;
496		unsafe { mat.at_nd_unchecked_mut(idx) }
497	}
498}
499
500pub trait MatTraitConstManual: MatTraitConst {
501	/// Like [Mat::at()] but performs no bounds or type checks
502	///
503	/// # Safety
504	/// Caller must ensure that index is within Mat bounds
505	#[inline]
506	unsafe fn at_unchecked<T: DataType>(&self, i0: i32) -> &T {
507		unsafe { &*data_at_idx::<T>(self, i0 as usize) }
508	}
509
510	/// Like [Mat::at_2d()] but performs no bounds or type checks
511	/// # Safety
512	/// Caller must ensure that indices are within Mat bounds
513	#[inline]
514	unsafe fn at_2d_unchecked<T: DataType>(&self, row: i32, col: i32) -> Result<&T> {
515		self.ptr_2d(row, col).map(|ptr| unsafe { convert_ptr(ptr) })
516	}
517
518	/// Like [Mat::at_pt()] but performs no bounds or type checks
519	/// # Safety
520	/// Caller must ensure that point is within Mat bounds
521	#[inline]
522	unsafe fn at_pt_unchecked<T: DataType>(&self, pt: Point) -> Result<&T> {
523		unsafe { self.at_2d_unchecked(pt.y, pt.x) }
524	}
525
526	/// Like [Mat::at_3d()] but performs no bounds or type checks
527	/// # Safety
528	/// Caller must ensure that indices are within Mat bounds
529	#[inline]
530	unsafe fn at_3d_unchecked<T: DataType>(&self, i0: i32, i1: i32, i2: i32) -> Result<&T> {
531		self.ptr_3d(i0, i1, i2).map(|ptr| unsafe { convert_ptr(ptr) })
532	}
533
534	/// Like [Mat::at_nd()] but performs no bounds or type checks
535	/// # Safety
536	/// Caller must ensure that indices are within Mat bounds
537	#[inline]
538	unsafe fn at_nd_unchecked<T: DataType>(&self, idx: &[i32]) -> Result<&T> {
539		self.ptr_nd(idx).map(|ptr| unsafe { convert_ptr(ptr) })
540	}
541
542	/// Return a complete read-only row
543	#[inline]
544	fn at_row<T: DataType>(&self, row: i32) -> Result<&[T]> {
545		match_format::<T>(self.typ())
546			.and_then(|_| self.match_indices(&[row, 0]))
547			.and_then(|_| unsafe { self.at_row_unchecked(row) })
548	}
549
550	/// Like [Mat::at_row()] but performs no bounds or type checks
551	/// # Safety
552	/// Caller must ensure that index is within Mat bounds
553	#[inline]
554	unsafe fn at_row_unchecked<T: DataType>(&self, row: i32) -> Result<&[T]> {
555		// safe because Mat::size() can't be negative
556		let width = self.size()?.width as usize;
557		self.ptr(row).map(|row| {
558			if row.is_null() {
559				&[]
560			} else {
561				unsafe { slice::from_raw_parts(convert_ptr(row), width) }
562			}
563		})
564	}
565
566	#[inline]
567	fn is_allocated(&self) -> bool {
568		!self.data().is_null()
569	}
570
571	/// Returns the underlying data array as a byte slice, [Mat] must be continuous
572	#[inline]
573	fn data_bytes(&self) -> Result<&[u8]> {
574		self.match_is_continuous().and_then(|_| {
575			let data = self.data();
576			Ok(if data.is_null() {
577				&[]
578			} else {
579				unsafe { slice::from_raw_parts(data, self.total() * self.elem_size()?) }
580			})
581		})
582	}
583
584	#[inline]
585	fn data_typed<T: DataType>(&self) -> Result<&[T]> {
586		match_format::<T>(self.typ())
587			.and_then(|_| self.match_is_continuous())
588			.and_then(|_| unsafe { self.data_typed_unchecked() })
589	}
590
591	/// # Safety
592	/// Caller must ensure that the `T` type argument corresponds to the data stored in the [Mat], and [Mat] is continuous
593	#[inline]
594	unsafe fn data_typed_unchecked<T: DataType>(&self) -> Result<&[T]> {
595		let data = self.data();
596		Ok(if data.is_null() {
597			&[]
598		} else {
599			unsafe { slice::from_raw_parts(data.cast::<T>(), self.total()) }
600		})
601	}
602
603	fn to_vec_2d<T: DataType>(&self) -> Result<Vec<Vec<T>>> {
604		match_format::<T>(self.typ()).and_then(|_| {
605			let size = match *self.mat_size() {
606				[rows, cols] => Size::new(cols, rows),
607				ref mat_size => {
608					return Err(Error::new(
609						core::StsUnmatchedSizes,
610						format!(
611							"Mat must have 2 dimensions for this operation, but it has: {}",
612							mat_size.len()
613						),
614					))
615				}
616			};
617			// safe because Mat size can't be negative
618			let width = size.width as usize;
619			if self.is_continuous() {
620				let data = self.data_typed()?;
621				Ok((0..size.height)
622					.map(|row_n| {
623						// safe because the iteration starts from 0
624						let row_n = row_n as usize;
625						let mut row = Vec::with_capacity(width);
626						row.extend_from_slice(&data[row_n * width..(row_n + 1) * width]);
627						row
628					})
629					.collect())
630			} else {
631				Ok((0..size.height)
632					.map(|row_n| {
633						self.at_row(row_n).map(|src_row| {
634							let mut row = Vec::with_capacity(width);
635							row.extend_from_slice(src_row);
636							row
637						})
638					})
639					.collect::<Result<_>>()?)
640			}
641		})
642	}
643
644	/// Returns an iterator over [Mat] elements and their positions
645	#[inline]
646	fn iter<T: DataType>(&self) -> Result<MatIter<'_, T>>
647	where
648		Self: Sized,
649	{
650		MatConstIterator::over(self).map_or(
651			Ok(MatIter {
652				iter: None,
653				_d: PhantomData,
654			}),
655			MatIter::new,
656		)
657	}
658
659	#[inline]
660	fn try_into_typed<T: DataType>(self) -> Result<Mat_<T>>
661	where
662		Self: Sized,
663		Mat_<T>: TryFrom<Self, Error = Error>,
664	{
665		self.try_into()
666	}
667}
668
669pub trait MatTraitManual: MatTraitConstManual + MatTrait {
670	/// Like [Mat::at_mut()] but performs no bounds or type checks
671	/// # Safety
672	/// Caller must ensure that index is within Mat bounds
673	#[inline]
674	unsafe fn at_unchecked_mut<T: DataType>(&mut self, i0: i32) -> &mut T {
675		unsafe { &mut *data_at_idx::<T>(self, i0 as usize).cast_mut() }
676	}
677
678	/// Like [Mat::at_2d_mut()] but performs no bounds or type checks
679	/// # Safety
680	/// Caller must ensure that indices are within Mat bounds
681	#[inline]
682	unsafe fn at_2d_unchecked_mut<T: DataType>(&mut self, row: i32, col: i32) -> Result<&mut T> {
683		self.ptr_2d_mut(row, col).map(|ptr| unsafe { convert_ptr_mut(ptr) })
684	}
685
686	/// Like [Mat::at_pt_mut()] but performs no bounds or type checks
687	/// # Safety
688	/// Caller must ensure that point is within Mat bounds
689	#[inline]
690	unsafe fn at_pt_unchecked_mut<T: DataType>(&mut self, pt: Point) -> Result<&mut T> {
691		unsafe { self.at_2d_unchecked_mut(pt.y, pt.x) }
692	}
693
694	/// Like [Mat::at_3d_mut()] but performs no bounds or type checks
695	/// # Safety
696	/// Caller must ensure that indices are within Mat bounds
697	#[inline]
698	unsafe fn at_3d_unchecked_mut<T: DataType>(&mut self, i0: i32, i1: i32, i2: i32) -> Result<&mut T> {
699		self.ptr_3d_mut(i0, i1, i2).map(|ptr| unsafe { convert_ptr_mut(ptr) })
700	}
701
702	/// Like [Mat::at_nd_mut()] but performs no bounds or type checks
703	/// # Safety
704	/// Caller must ensure that indices are within Mat bounds
705	#[inline]
706	unsafe fn at_nd_unchecked_mut<T: DataType>(&mut self, idx: &[i32]) -> Result<&mut T> {
707		self.ptr_nd_mut(idx).map(|ptr| unsafe { convert_ptr_mut(ptr) })
708	}
709
710	/// Return a complete writeable row
711	#[inline]
712	fn at_row_mut<T: DataType>(&mut self, row: i32) -> Result<&mut [T]> {
713		match_format::<T>(self.typ()).and_then(|_| self.match_indices(&[row, 0]))?;
714		unsafe { self.at_row_unchecked_mut(row) }
715	}
716
717	/// Like [Mat::at_row_mut()] but performs no bounds or type checks
718	/// # Safety
719	/// Caller must ensure that index is within Mat bounds
720	#[inline]
721	unsafe fn at_row_unchecked_mut<T: DataType>(&mut self, row: i32) -> Result<&mut [T]> {
722		// safe because Mat::size() can't be negative
723		let width = self.size()?.width as usize;
724		self.ptr_mut(row).map(|x| {
725			if x.is_null() {
726				&mut []
727			} else {
728				unsafe { slice::from_raw_parts_mut(convert_ptr_mut(x), width) }
729			}
730		})
731	}
732
733	/// Returns the underlying data array as a mutable byte slice, Mat must be continuous.
734	#[inline]
735	fn data_bytes_mut(&mut self) -> Result<&mut [u8]> {
736		self.match_is_continuous().and_then(|_| {
737			let data = self.data_mut();
738			Ok(if data.is_null() {
739				&mut []
740			} else {
741				unsafe { slice::from_raw_parts_mut(self.data_mut(), self.total() * self.elem_size()?) }
742			})
743		})
744	}
745
746	#[inline]
747	fn data_typed_mut<T: DataType>(&mut self) -> Result<&mut [T]> {
748		match_format::<T>(self.typ()).and_then(|_| self.match_is_continuous())?;
749		unsafe { self.data_typed_unchecked_mut() }
750	}
751
752	/// # Safety
753	/// Caller must ensure that the `T` type argument corresponds to the data stored in the [Mat], and [Mat] is continuous
754	#[inline]
755	unsafe fn data_typed_unchecked_mut<T: DataType>(&mut self) -> Result<&mut [T]> {
756		let total = self.total();
757		let data = self.data_mut();
758		Ok(if data.is_null() {
759			&mut []
760		} else {
761			unsafe { slice::from_raw_parts_mut(data.cast::<T>(), total) }
762		})
763	}
764
765	/// Returns a mutable iterator over [Mat] elements and their positions
766	#[inline]
767	fn iter_mut<T: DataType>(&mut self) -> Result<MatIterMut<'_, T>>
768	where
769		Self: Sized,
770	{
771		MatConstIterator::over(self).map_or(
772			Ok(MatIterMut {
773				iter: None,
774				_d: PhantomData,
775			}),
776			MatIterMut::new,
777		)
778	}
779}
780
781impl<T: MatTraitConst + ?Sized> MatTraitConstManual for T {}
782
783impl<T: MatTrait + ?Sized> MatTraitManual for T {}
784
785input_output_array! { Mat, from_mat, from_mat_mut }
786input_output_array_vector! { Mat, from_mat_vec, from_mat_vec_mut }
787
788unsafe impl Sync for Mat {}
789
790impl fmt::Debug for Mat {
791	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
792		let typ = self.typ();
793		let depth = self.depth();
794		let typ = core::type_to_string(typ).map_err(|_| fmt::Error)?;
795		let depth = core::depth_to_string(depth).map_err(|_| fmt::Error)?;
796		let flags = self.flags();
797		let mut flags_str = String::new();
798		if flags & core::Mat_MAGIC_VAL != core::Mat_MAGIC_VAL {
799			flags_str.push_str("invalid magic value");
800		} else {
801			if flags & core::Mat_CONTINUOUS_FLAG != 0 {
802				flags_str.push_str("continuous");
803			}
804			if flags & core::Mat_SUBMATRIX_FLAG != 0 {
805				if !flags_str.is_empty() {
806					flags_str.push_str(", ");
807				}
808				flags_str.push_str("submatrix");
809			}
810		}
811		f.debug_struct("Mat")
812			.field("type", &typ)
813			.field("flags", &format!("0x{flags:X} ({flags_str})"))
814			.field("channels", &self.channels())
815			.field("depth", &depth)
816			.field("dims", &self.dims())
817			.field("rows", &self.rows())
818			.field("cols", &self.cols())
819			.field("mat_size", &self.mat_size())
820			.field("elem_size", &self.elem_size().map_err(|_| fmt::Error)?)
821			.field("elem_size1", &self.elem_size1())
822			.field("mat_step", &self.mat_step())
823			.field("total", &self.total())
824			.field("is_continuous", &self.is_continuous())
825			.field("is_submatrix", &self.is_submatrix())
826			.field("data", &MatDataDumper(self))
827			.finish()
828	}
829}
830
831struct MatDataDumper<'r>(&'r Mat);
832
833impl fmt::Debug for MatDataDumper<'_> {
834	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
835		const MAX_DUMP_SIZE: usize = 1000;
836
837		if self.0.total() <= MAX_DUMP_SIZE {
838			f.write_str(&self.0.get_data_dump().map_err(|_| fmt::Error)?)
839		} else {
840			f.write_fmt(format_args!("<element count is higher than threshold: {MAX_DUMP_SIZE}>"))
841		}
842	}
843}
844
845input_output_array! { UMat, from_umat, from_umat_mut }
846input_output_array_vector! { UMat, from_umat_vec, from_umat_vec_mut }
847
848impl Deref for MatSize<'_> {
849	type Target = [i32];
850
851	#[inline]
852	fn deref(&self) -> &Self::Target {
853		let p = self.p();
854		if p.is_null() {
855			&[]
856		} else {
857			let dims = usize::try_from(self.dims()).unwrap_or(0);
858			unsafe { slice::from_raw_parts(p, dims) }
859		}
860	}
861}
862
863impl fmt::Debug for MatSize<'_> {
864	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
865		writeln!(f, "{:#?}", self.deref())
866	}
867}
868
869impl Deref for MatStep {
870	#[cfg(not(ocvrs_opencv_branch_5))]
871	type Target = [usize; 2];
872	#[cfg(ocvrs_opencv_branch_5)]
873	type Target = [usize; 3];
874
875	fn deref(&self) -> &Self::Target {
876		self.buf()
877	}
878}
879
880impl DerefMut for MatStep {
881	fn deref_mut(&mut self) -> &mut Self::Target {
882		self.buf_mut()
883	}
884}
885
886pub trait MatConstIteratorTraitManual: MatConstIteratorTrait {
887	#[inline]
888	fn has_elements(&self) -> bool {
889		self.ptr() != self.slice_end()
890	}
891
892	#[inline]
893	fn current<T: DataType>(&self) -> Result<&T> {
894		match_format::<T>(self.typ())?;
895		if self.has_elements() {
896			Ok(unsafe { convert_ptr(self.ptr()) })
897		} else {
898			Err(Error::new(
899				core::StsOutOfRange,
900				"MatConstIterator doesn't have any more elements",
901			))
902		}
903	}
904
905	#[inline]
906	fn current_mut<T: DataType>(&mut self) -> Result<&mut T> {
907		match_format::<T>(self.typ())?;
908		if self.has_elements() {
909			Ok(unsafe { convert_ptr_mut(self.ptr().cast_mut()) })
910		} else {
911			Err(Error::new(
912				core::StsOutOfRange,
913				"MatConstIterator doesn't have any more elements",
914			))
915		}
916	}
917}
918
919impl<T: MatConstIteratorTrait> MatConstIteratorTraitManual for T {}
920
921input_output_array! { MatExpr, from_matexpr }