#[cfg(test)]
mod tests {
use crate::core::arithm::*;
use crate::core::types::*;
use crate::core::utils::*;
use crate::core::*;
#[test]
fn test_point_add() {
let p1 = Point2i::new(10, 20);
let p2 = Point2i::new(5, 5);
let p3 = p1 + p2;
assert_eq!(p3.x, 15);
assert_eq!(p3.y, 25);
}
#[test]
fn test_size_area() {
let sz = Size2i::new(100, 50);
assert_eq!(sz.area(), 5000);
}
#[test]
fn test_matrix_from_size() {
let sz = Size2i::new(100, 200);
let mat: Matrix<u8> =
Matrix::from_size(Size::new(sz.width as usize, sz.height as usize), 3);
assert_eq!(mat.cols, 100);
assert_eq!(mat.rows, 200);
assert_eq!(mat.channels, 3);
assert_eq!(mat.data.len(), 100 * 200 * 3);
}
#[test]
fn test_rect_tl_br() {
let r = Rect2i::new(10, 10, 100, 50);
assert_eq!(r.tl(), Point2i::new(10, 10));
assert_eq!(r.br(), Point2i::new(110, 60));
}
#[test]
fn test_range() {
let r = Range::new(10, 20);
assert_eq!(r.size(), 10);
assert!(!r.empty());
let r_all = Range::all();
assert_eq!(r_all.start, i32::MIN);
}
#[test]
fn test_scalar() {
let s = Scalar::<u8>::all(255);
assert_eq!(s.v, [255, 255, 255, 255]);
}
#[test]
fn test_arithmetic() {
let m1 = Matrix::from_vec(2, 2, 1, vec![10, 20, 30, 40]);
let m2 = Matrix::from_vec(2, 2, 1, vec![5, 5, 5, 5]);
let sum = add(&m1, &m2).unwrap();
assert_eq!(sum.data, vec![15, 25, 35, 45]);
let diff = subtract(&m1, &m2).unwrap();
assert_eq!(diff.data, vec![5, 15, 25, 35]);
let prod = multiply(&m1, &m2).unwrap();
assert_eq!(prod.data, vec![50, 100, 150, 200]);
let quot = divide(&m1, &m2).unwrap();
assert_eq!(quot.data, vec![2, 4, 6, 8]);
let abs_diff = absdiff(&m2, &m1).unwrap();
assert_eq!(abs_diff.data, vec![5, 15, 25, 35]);
}
#[test]
fn test_bitwise() {
let m1 = Matrix::from_vec(1, 4, 1, vec![0b1010, 0b1100, 0b1111, 0b0000]);
let m2 = Matrix::from_vec(1, 4, 1, vec![0b0101, 0b0110, 0b0000, 0b1111]);
let and = bitwise_and(&m1, &m2).unwrap();
assert_eq!(and.data, vec![0b0000, 0b0100, 0b0000, 0b0000]);
let or = bitwise_or(&m1, &m2).unwrap();
assert_eq!(or.data, vec![0b1111, 0b1110, 0b1111, 0b1111]);
let xor = bitwise_xor(&m1, &m2).unwrap();
assert_eq!(xor.data, vec![0b1111, 0b1010, 0b1111, 0b1111]);
let m3 = Matrix::from_vec(1, 1, 1, vec![0u8]);
let not = bitwise_not(&m3).unwrap();
assert_eq!(not.data, vec![255u8]);
}
#[test]
fn test_weighted() {
let m1 = Matrix::from_vec(1, 2, 1, vec![100u8, 200u8]);
let m2 = Matrix::from_vec(1, 2, 1, vec![50u8, 10u8]);
let res = add_weighted(&m1, 0.5, &m2, 0.1, 10.0).unwrap();
assert_eq!(res.data, vec![65, 111]);
}
#[test]
fn test_scalar_term() {
use crate::core::types::{Scalar, TermCriteria, TermType};
let s = Scalar::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(s.v[0], 1.0);
assert_eq!(s.v[3], 4.0);
let term = TermCriteria::new(TermType::Both, 100, 0.001);
assert_eq!(term.max_count, 100);
assert_eq!(term.epsilon, 0.001);
}
#[test]
fn test_convert_scale_abs() {
let m = Matrix::<f32>::from_vec(1, 3, 1, vec![-10.0, 0.0, 10.0]);
let res = convert_scale_abs(&m, 1.0, 0.0).unwrap();
assert_eq!(res.data[0], 10);
assert_eq!(res.data[1], 0);
assert_eq!(res.data[2], 10);
let m2 = Matrix::<f32>::from_vec(1, 1, 1, vec![100.0]);
let res2 = convert_scale_abs(&m2, 2.0, 100.0).unwrap();
assert_eq!(res2.data[0], 255);
}
#[test]
fn test_structural() {
use crate::core::structural::*;
let m = Matrix::<u8>::from_vec(2, 2, 1, vec![1, 2, 3, 4]);
let f_v = flip(&m, 0).unwrap(); assert_eq!(f_v.data, vec![3, 4, 1, 2]);
let f_h = flip(&m, 1).unwrap(); assert_eq!(f_h.data, vec![2, 1, 4, 3]);
let m_rect = Matrix::<u8>::from_vec(2, 3, 1, vec![1, 2, 3, 4, 5, 6]);
let t = transpose(&m_rect).unwrap();
assert_eq!(t.rows, 3);
assert_eq!(t.cols, 2);
assert_eq!(t.data, vec![1, 4, 2, 5, 3, 6]);
let m_rgb = Matrix::<u8>::from_vec(1, 1, 3, vec![10, 20, 30]);
let channels = split(&m_rgb).unwrap();
assert_eq!(channels.len(), 3);
assert_eq!(channels[0].data[0], 10);
assert_eq!(channels[1].data[0], 20);
assert_eq!(channels[2].data[0], 30);
let merged = merge(&channels).unwrap();
assert_eq!(merged.data, vec![10, 20, 30]);
let m_rot = Matrix::<u8>::from_vec(2, 2, 1, vec![1, 2, 3, 4]);
let rot90 = rotate(&m_rot, 0).unwrap();
assert_eq!(rot90.data, vec![3, 1, 4, 2]);
let m_rep = Matrix::<u8>::from_vec(1, 2, 1, vec![1, 2]);
let rep = repeat(&m_rep, 2, 2).unwrap();
assert_eq!(rep.rows, 2);
assert_eq!(rep.cols, 4);
assert_eq!(rep.data, vec![1, 2, 1, 2, 1, 2, 1, 2]);
let m_rgb = Matrix::<u8>::from_vec(1, 1, 3, vec![1, 2, 3]);
let m_bgr = Matrix::<u8>::new(1, 1, 3);
let mut dst_vec = vec![m_bgr];
mix_channels(&[m_rgb], &mut dst_vec, &[(0, 2), (1, 1), (2, 0)]).unwrap();
assert_eq!(dst_vec[0].data, vec![3, 2, 1]);
let m_pad = Matrix::<u8>::from_vec(1, 1, 1, vec![100]);
let padded =
copy_make_border(&m_pad, 1, 1, 1, 1, 0, crate::core::types::Scalar::all(0)).unwrap();
assert_eq!(padded.rows, 3);
assert_eq!(padded.cols, 3);
assert_eq!(padded.data, vec![0, 0, 0, 0, 100, 0, 0, 0, 0]);
let m_reshape = Matrix::<u8>::from_vec(1, 4, 1, vec![1, 2, 3, 4]);
let reshaped = reshape(&m_reshape, 1, 2).unwrap();
assert_eq!(reshaped.rows, 2);
assert_eq!(reshaped.cols, 2);
assert_eq!(reshaped.data, vec![1, 2, 3, 4]);
let m1 = Matrix::<u8>::from_vec(2, 1, 1, vec![1, 2]);
let m2 = Matrix::<u8>::from_vec(2, 1, 1, vec![3, 4]);
let h_concat = hconcat(&[m1.clone(), m2.clone()]).unwrap();
assert_eq!(h_concat.rows, 2);
assert_eq!(h_concat.cols, 2);
assert_eq!(h_concat.data, vec![1, 3, 2, 4]);
let v_concat = vconcat(&[m1, m2]).unwrap();
assert_eq!(v_concat.rows, 4);
assert_eq!(v_concat.cols, 1);
assert_eq!(v_concat.data, vec![1, 2, 3, 4]);
}
#[test]
fn test_math() {
let m1 = Matrix::from_vec(1, 4, 1, vec![1.0f32, 4.0, 9.0, 16.0]);
let s = sqrt(&m1).unwrap();
assert_eq!(s.data, vec![1.0, 2.0, 3.0, 4.0]);
let m2 = Matrix::from_vec(1, 2, 1, vec![0.0f32, 1.0]);
let e = exp(&m2).unwrap();
assert!((e.data[0] - 1.0).abs() < 1e-6);
assert!((e.data[1] - std::f32::consts::E).abs() < 1e-6);
let m3 = Matrix::from_vec(1, 2, 1, vec![1.0f32, std::f32::consts::E]);
let l = crate::core::arithm::log(&m3).unwrap();
assert!((l.data[0] - 0.0).abs() < 1e-6);
assert!((l.data[1] - 1.0).abs() < 1e-6);
let m4 = Matrix::from_vec(1, 2, 1, vec![2.0f32, 3.0]);
let p = pow(&m4, 2.0).unwrap();
assert_eq!(p.data, vec![4.0, 9.0]);
}
#[test]
fn test_convert_to() {
let m = Matrix::from_vec(2, 2, 1, vec![1u8, 2u8, 3u8, 4u8]);
let m_f32 = m.convert_to::<f32>().unwrap();
assert_eq!(m_f32.data, vec![1.0f32, 2.0, 3.0, 4.0]);
}
#[test]
fn test_norm_normalize() {
let m = Matrix::from_vec(1, 3, 1, vec![1.0f64, 2.0, 3.0]);
assert_eq!(norm(&m, NormTypes::Inf, None).unwrap(), 3.0);
assert_eq!(norm(&m, NormTypes::L1, None).unwrap(), 6.0);
assert_eq!(
norm(&m, NormTypes::L2, None).unwrap(),
(1.0f64 + 4.0 + 9.0).sqrt()
);
let mut m_minmax = Matrix::<f64>::new(1, 3, 1);
normalize(&m, &mut m_minmax, 0.0, 1.0, NormTypes::MinMax, -1, None).unwrap();
assert_eq!(m_minmax.data[0], 0.0);
assert_eq!(m_minmax.data[2], 1.0);
assert!((m_minmax.data[1] - 0.5).abs() < 1e-6);
let mut m_l2 = Matrix::<f64>::new(1, 3, 1);
normalize(&m, &mut m_l2, 1.0, 0.0, NormTypes::L2, -1, None).unwrap();
let n_l2 = norm(&m_l2, NormTypes::L2, None).unwrap();
assert!((n_l2 - 1.0).abs() < 1e-6);
}
#[test]
fn test_stats() {
let m = Matrix::from_vec(2, 2, 1, vec![10.0f64, 20.0, 30.0, 40.0]);
let s = sum(&m);
assert_eq!(s.v[0], 100.0);
let mn = mean(&m);
assert_eq!(mn.v[0], 25.0);
let (min_val, max_val, min_loc, max_loc) = min_max_loc(&m);
assert_eq!(min_val, 10.0);
assert_eq!(max_val, 40.0);
assert_eq!(min_loc.0, 0);
assert_eq!(min_loc.1, 0);
assert_eq!(max_loc.0, 1);
assert_eq!(max_loc.1, 1);
let (mn2, sd) = mean_std_dev(&m);
assert_eq!(mn2.v[0], 25.0);
assert!((sd.v[0] - 125.0f64.sqrt()).abs() < 1e-6);
}
#[test]
fn test_matrix_factories() {
let m_zeros = Matrix::<u8>::zeros(2, 2, 1);
assert_eq!(m_zeros.data, vec![0, 0, 0, 0]);
let m_ones = Matrix::<f32>::ones(1, 4, 1);
assert_eq!(m_ones.data, vec![1.0, 1.0, 1.0, 1.0]);
let m_eye = Matrix::<i32>::eye(3, 3, 1);
let expected_eye = vec![1, 0, 0, 0, 1, 0, 0, 0, 1];
assert_eq!(m_eye.data, expected_eye);
let diag_vals = vec![1.0, 2.0, 3.0];
let m_diag = Matrix::diag(&diag_vals);
assert_eq!(m_diag.rows, 3);
assert_eq!(m_diag.cols, 3);
let expected_diag = vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0];
assert_eq!(m_diag.data, expected_diag);
}
#[test]
fn test_mat_type_integration() {
assert_eq!(u8::depth(), Depth::CV_8U);
assert_eq!(f32::depth(), Depth::CV_32F);
let mat = Matrix::<u8>::new_with_type(10, 20, CV_8UC3);
assert_eq!(mat.rows, 10);
assert_eq!(mat.cols, 20);
assert_eq!(mat.channels, 3);
assert_eq!(mat.mat_type(), CV_8UC3);
let z = Matrix::<f32>::zeros_with_type(5, 5, CV_32FC1);
assert_eq!(z.data.len(), 25);
assert!(z.data.iter().all(|&v| v == 0.0));
assert_eq!(z.mat_type(), CV_32FC1);
let o = Matrix::<i16>::ones_with_type(2, 2, CV_16SC2);
assert_eq!(o.data.len(), 8);
assert!(o.data.iter().all(|&v| v == 1));
assert_eq!(o.mat_type(), CV_16SC2);
}
#[test]
fn test_dot_cross_trace() {
let m1 = Matrix::from_vec(1, 3, 1, vec![1.0, 2.0, 3.0]);
let m2 = Matrix::from_vec(1, 3, 1, vec![4.0, 5.0, 6.0]);
assert_eq!(dot(&m1, &m2).unwrap(), 32.0);
let c = cross(&m1, &m2).unwrap();
assert_eq!(c.data, vec![-3.0, 6.0, -3.0]);
let m_eye = Matrix::<f64>::eye(3, 3, 1);
assert_eq!(trace(&m_eye).v[0], 3.0);
}
#[test]
fn test_set_identity() {
let mut m = Matrix::<f64>::zeros(3, 3, 1);
set_identity(&mut m, Scalar::all(5.0));
assert_eq!(m.data, vec![5.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 5.0]);
}
#[test]
fn test_check_range() {
let m = Matrix::from_vec(1, 3, 1, vec![1.0, 2.0, 3.0]);
assert!(check_range(&m, 0.0, 4.0));
assert!(!check_range(&m, 0.0, 2.5));
let m_nan = Matrix::from_vec(1, 1, 1, vec![f64::NAN]);
assert!(!check_range(&m_nan, 0.0, 10.0));
}
#[test]
fn test_gemm() {
let a = Matrix::from_vec(2, 2, 1, vec![1.0, 2.0, 3.0, 4.0]);
let b = Matrix::from_vec(2, 2, 1, vec![5.0, 6.0, 7.0, 8.0]);
let c = Matrix::from_vec(2, 2, 1, vec![1.0, 1.0, 1.0, 1.0]);
let res = gemm(&a, &b, 1.0, &c, 1.0, 0).unwrap();
assert_eq!(res.data, vec![20.0, 23.0, 44.0, 51.0]);
let empty = Matrix::<f64>::new(0, 0, 1);
let res_t = gemm(&a, &b, 1.0, &empty, 0.0, GEMM_1_T).unwrap();
assert_eq!(res_t.data, vec![26.0, 30.0, 38.0, 44.0]);
}
#[test]
fn test_randu_basic() {
use crate::core::rng::{randu, set_rng_seed};
set_rng_seed(1234);
let mut mat = Matrix::<f64>::new(10, 10, 1);
randu(&mut mat, Scalar::all(0.0), Scalar::all(1.0)).unwrap();
for &v in &mat.data {
assert!(v >= 0.0 && v < 1.0, "value {} out of [0, 1)", v);
}
}
#[test]
fn test_randn_basic() {
use crate::core::rng::{randn, set_rng_seed};
set_rng_seed(5678);
let mut mat = Matrix::<f64>::new(10, 10, 1);
randn(&mut mat, Scalar::all(0.0), Scalar::all(1.0)).unwrap();
let any_nonzero = mat.data.iter().any(|&v| v != 0.0);
assert!(any_nonzero, "randn produced all zeros");
}
#[test]
fn test_set_rng_seed_reproducible() {
use crate::core::rng::{randu, set_rng_seed};
set_rng_seed(999);
let mut a = Matrix::<f32>::new(5, 5, 3);
randu(&mut a, Scalar::all(0.0), Scalar::all(255.0)).unwrap();
set_rng_seed(999);
let mut b = Matrix::<f32>::new(5, 5, 3);
randu(&mut b, Scalar::all(0.0), Scalar::all(255.0)).unwrap();
assert_eq!(a.data, b.data);
}
#[test]
fn test_transform_identity() {
let src = Matrix::from_vec(1, 2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let m = Matrix::from_vec(3, 3, 1, vec![1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
transform(&src, &mut dst, &m).unwrap();
assert_eq!(dst.data, src.data);
}
#[test]
fn test_transform_swap_channels() {
let src = Matrix::from_vec(1, 1, 3, vec![10.0, 20.0, 30.0]);
let m = Matrix::from_vec(3, 3, 1, vec![0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
transform(&src, &mut dst, &m).unwrap();
assert_eq!(dst.data, vec![30.0, 20.0, 10.0]);
}
#[test]
fn test_transform_affine() {
let src = Matrix::from_vec(1, 2, 2, vec![1.0, 2.0, 3.0, 4.0]);
let m = Matrix::from_vec(2, 3, 1, vec![1.0, 0.0, 5.0, 0.0, 1.0, 10.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
transform(&src, &mut dst, &m).unwrap();
assert_eq!(dst.data, vec![6.0, 12.0, 8.0, 14.0]);
}
#[test]
fn test_transform_reduce_channels() {
let src = Matrix::from_vec(1, 1, 3, vec![100.0, 150.0, 200.0]);
let m = Matrix::from_vec(1, 3, 1, vec![0.299, 0.587, 0.114]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
transform(&src, &mut dst, &m).unwrap();
assert_eq!(dst.channels, 1);
let expected = 0.299 * 100.0 + 0.587 * 150.0 + 0.114 * 200.0;
assert!((dst.data[0] - expected).abs() < 1e-10);
}
#[test]
fn test_perspective_transform_identity() {
let src = Matrix::from_vec(1, 2, 2, vec![10.0, 20.0, 30.0, 40.0]);
let m = Matrix::from_vec(3, 3, 1, vec![1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
perspective_transform(&src, &mut dst, &m).unwrap();
assert_eq!(dst.channels, 2);
assert!((dst.data[0] - 10.0).abs() < 1e-10);
assert!((dst.data[1] - 20.0).abs() < 1e-10);
assert!((dst.data[2] - 30.0).abs() < 1e-10);
assert!((dst.data[3] - 40.0).abs() < 1e-10);
}
#[test]
fn test_perspective_transform_translation() {
#[rustfmt::skip]
let m = Matrix::from_vec(3, 3, 1, vec![
1.0, 0.0, 5.0,
0.0, 1.0, 10.0,
0.0, 0.0, 1.0,
]);
let src = Matrix::from_vec(1, 1, 2, vec![3.0, 7.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
perspective_transform(&src, &mut dst, &m).unwrap();
assert!((dst.data[0] - 8.0).abs() < 1e-10);
assert!((dst.data[1] - 17.0).abs() < 1e-10);
}
#[test]
fn test_perspective_transform_scaling() {
#[rustfmt::skip]
let m = Matrix::from_vec(3, 3, 1, vec![
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 2.0,
]);
let src = Matrix::from_vec(1, 1, 2, vec![10.0, 20.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
perspective_transform(&src, &mut dst, &m).unwrap();
assert!((dst.data[0] - 5.0).abs() < 1e-10);
assert!((dst.data[1] - 10.0).abs() < 1e-10);
}
#[test]
fn test_perspective_transform_3d() {
#[rustfmt::skip]
let m = Matrix::from_vec(4, 4, 1, vec![
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]);
let src = Matrix::from_vec(1, 1, 3, vec![1.0, 2.0, 3.0]);
let mut dst = Matrix::<f64>::new(0, 0, 0);
perspective_transform(&src, &mut dst, &m).unwrap();
assert_eq!(dst.channels, 3);
assert!((dst.data[0] - 1.0).abs() < 1e-10);
assert!((dst.data[1] - 2.0).abs() < 1e-10);
assert!((dst.data[2] - 3.0).abs() < 1e-10);
}
#[test]
fn test_solve_poly_cubic() {
use crate::core::arithm::solve_poly;
let coeffs = Matrix::from_vec(1, 4, 1, vec![-6.0, 11.0, -6.0, 1.0]);
let mut roots = Matrix::<f64>::new(0, 0, 0);
let residual = solve_poly(&coeffs, &mut roots, 0).unwrap();
assert!(residual < 1e-6);
assert_eq!(roots.rows, 3);
let mut reals: Vec<f64> = (0..3).map(|k| roots.data[k * 2]).collect();
reals.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert!((reals[0] - 1.0).abs() < 1e-6);
assert!((reals[1] - 2.0).abs() < 1e-6);
assert!((reals[2] - 3.0).abs() < 1e-6);
}
#[test]
fn test_sort_integration() {
use crate::core::arithm::{sort, sort_idx};
let src = Matrix::from_vec(2, 3, 1, vec![9i32, 3, 6, 1, 7, 4]);
let mut dst = Matrix::<i32>::new(0, 0, 0);
sort(&src, &mut dst, 0).unwrap(); assert_eq!(dst.data, vec![3, 6, 9, 1, 4, 7]);
let mut idx = Matrix::<i32>::new(0, 0, 0);
sort_idx(&src, &mut idx, 0).unwrap();
assert_eq!(&idx.data[0..3], &[1, 2, 0]);
}
#[test]
fn test_kmeans_multidim() {
use crate::core::arithm::kmeans;
use crate::core::types::{TermCriteria, TermType, KMEANS_PP_CENTERS};
let mut data = Matrix::<f32>::new(6, 2, 1);
data.data = vec![
0.0, 0.0, 0.1, 0.1, 0.2, 0.2, 10.0, 10.0, 10.1, 10.1, 10.2, 10.2,
];
let mut labels = Matrix::<i32>::new(0, 0, 0);
let criteria = TermCriteria::new(TermType::Both, 100, 1e-6);
let mut centers = Some(Matrix::<f32>::new(0, 0, 0));
let comp = kmeans(
&data,
2,
&mut labels,
criteria,
3,
KMEANS_PP_CENTERS,
&mut centers,
)
.unwrap();
assert!(comp < 1.0);
let la = labels.data[0];
let lb = labels.data[3];
assert_ne!(la, lb);
for i in 0..3 {
assert_eq!(labels.data[i], la);
}
for i in 3..6 {
assert_eq!(labels.data[i], lb);
}
}
}