use crate::{Error, Result, Size, Point, Rect, Scalar};
use std::fmt;
use std::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum MatType {
CV_8U = 0,
CV_8S = 1,
CV_16U = 2,
CV_16S = 3,
CV_32S = 4,
CV_32F = 5,
CV_64F = 6,
CV_16F = 7,
}
impl MatType {
pub fn elem_size(&self) -> usize {
match self {
MatType::CV_8U | MatType::CV_8S => 1,
MatType::CV_16U | MatType::CV_16S | MatType::CV_16F => 2,
MatType::CV_32S | MatType::CV_32F => 4,
MatType::CV_64F => 8,
}
}
pub fn is_float(&self) -> bool {
matches!(self, MatType::CV_32F | MatType::CV_64F | MatType::CV_16F)
}
pub fn is_signed(&self) -> bool {
matches!(self, MatType::CV_8S | MatType::CV_16S | MatType::CV_32S | MatType::CV_32F | MatType::CV_64F | MatType::CV_16F)
}
}
pub struct Mat {
data: Vec<u8>,
rows: i32,
cols: i32,
mat_type: MatType,
channels: i32,
}
unsafe impl Send for Mat {}
unsafe impl Sync for Mat {}
impl Mat {
pub fn new() -> Result<Self> {
Ok(Mat {
data: Vec::new(),
rows: 0,
cols: 0,
mat_type: MatType::CV_8U,
channels: 1,
})
}
pub fn new_size(size: Size, mat_type: MatType) -> Result<Self> {
Self::new_size_with_default(size, mat_type, Scalar::default())
}
pub fn new_size_with_default(size: Size, mat_type: MatType, _default_value: Scalar) -> Result<Self> {
let total_size = (size.width * size.height) as usize * mat_type.elem_size();
Ok(Mat {
data: vec![0u8; total_size],
rows: size.height,
cols: size.width,
mat_type,
channels: 1,
})
}
pub fn from_slice<T>(data: &[T], rows: i32, cols: i32, mat_type: MatType) -> Result<Self> {
let elem_size = mat_type.elem_size();
let expected_size = (rows * cols) as usize;
if data.len() != expected_size {
return Err(Error::InvalidArgument(format!(
"Data size mismatch: expected {}, got {}",
expected_size,
data.len()
)));
}
let byte_size = expected_size * elem_size;
let mut mat_data = vec![0u8; byte_size];
unsafe {
std::ptr::copy_nonoverlapping(
data.as_ptr() as *const u8,
mat_data.as_mut_ptr(),
byte_size,
);
}
Ok(Mat {
data: mat_data,
rows,
cols,
mat_type,
channels: 1,
})
}
pub fn rows(&self) -> i32 {
self.rows
}
pub fn cols(&self) -> i32 {
self.cols
}
pub fn size(&self) -> Size {
Size::new(self.cols, self.rows)
}
pub fn mat_type(&self) -> MatType {
self.mat_type
}
pub fn channels(&self) -> i32 {
self.channels
}
pub fn is_empty(&self) -> bool {
self.data.is_empty() || self.rows == 0 || self.cols == 0
}
pub fn roi(&self, rect: Rect) -> Result<Mat> {
if rect.x < 0 || rect.y < 0 ||
rect.x + rect.width > self.cols ||
rect.y + rect.height > self.rows {
return Err(Error::InvalidArgument("ROI out of bounds".into()));
}
Ok(Mat {
data: Vec::new(), rows: rect.height,
cols: rect.width,
mat_type: self.mat_type,
channels: self.channels,
})
}
pub fn clone(&self) -> Result<Mat> {
Ok(Mat {
data: self.data.clone(),
rows: self.rows,
cols: self.cols,
mat_type: self.mat_type,
channels: self.channels,
})
}
pub fn copy_to(&self, dst: &mut Mat) -> Result<()> {
dst.data = self.data.clone();
dst.rows = self.rows;
dst.cols = self.cols;
dst.mat_type = self.mat_type;
dst.channels = self.channels;
Ok(())
}
pub fn convert_to(&self, dst: &mut Mat, rtype: MatType, _alpha: f64, _beta: f64) -> Result<()> {
dst.data = self.data.clone();
dst.rows = self.rows;
dst.cols = self.cols;
dst.mat_type = rtype;
dst.channels = self.channels;
Ok(())
}
pub fn data_ptr(&self) -> *const u8 {
self.data.as_ptr()
}
pub fn data_ptr_mut(&mut self) -> *mut u8 {
self.data.as_mut_ptr()
}
pub fn elem_size(&self) -> usize {
self.mat_type.elem_size() * self.channels as usize
}
pub fn total(&self) -> usize {
(self.rows * self.cols) as usize
}
}
impl Default for Mat {
fn default() -> Self {
Self::new().expect("Failed to create default Mat")
}
}
impl fmt::Debug for Mat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mat")
.field("rows", &self.rows)
.field("cols", &self.cols)
.field("type", &self.mat_type)
.field("channels", &self.channels)
.field("empty", &self.is_empty())
.finish()
}
}
pub trait MatTrait {
fn rows(&self) -> i32;
fn cols(&self) -> i32;
fn size(&self) -> Size;
fn mat_type(&self) -> MatType;
fn channels(&self) -> i32;
fn is_empty(&self) -> bool;
}
impl MatTrait for Mat {
fn rows(&self) -> i32 {
self.rows()
}
fn cols(&self) -> i32 {
self.cols()
}
fn size(&self) -> Size {
self.size()
}
fn mat_type(&self) -> MatType {
self.mat_type()
}
fn channels(&self) -> i32 {
self.channels()
}
fn is_empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mat_creation() {
let mat = Mat::new().unwrap();
assert!(mat.is_empty());
}
#[test]
fn test_mat_with_size() {
let size = Size::new(640, 480);
let mat = Mat::new_size(size, MatType::CV_8U).unwrap();
assert_eq!(mat.rows(), 480);
assert_eq!(mat.cols(), 640);
assert_eq!(mat.mat_type(), MatType::CV_8U);
}
#[test]
fn test_mat_type_properties() {
assert_eq!(MatType::CV_8U.elem_size(), 1);
assert_eq!(MatType::CV_32F.elem_size(), 4);
assert!(MatType::CV_32F.is_float());
assert!(!MatType::CV_8U.is_float());
assert!(MatType::CV_8S.is_signed());
assert!(!MatType::CV_8U.is_signed());
}
}