#[cfg(test)]
mod tests {
use crate::core::*;
use crate::imgproc::*;
#[test]
fn test_blur() {
let m = Matrix::from_vec(3, 3, 1, vec![10u8, 10, 10, 10, 10, 10, 10, 10, 10]);
let ksize = Size2i::new(3, 3);
let res = blur(&m, ksize, Point2i::new(-1, -1), BorderTypes::Reflect101).unwrap();
assert_eq!(res.data, vec![10u8; 9]);
}
#[test]
fn test_box_filter() {
let m = Matrix::from_vec(3, 3, 1, vec![1u8, 1, 1, 1, 1, 1, 1, 1, 1]);
let ksize = Size2i::new(3, 3);
let res = box_filter(
&m,
ksize,
Point2i::new(-1, -1),
false,
BorderTypes::Reflect101,
)
.unwrap();
for val in res.data {
assert_eq!(val, 9u8);
}
}
#[test]
fn test_gaussian_blur() {
let m = Matrix::from_vec(5, 5, 1, vec![100u8; 25]);
let ksize = Size2i::new(3, 3);
let res = gaussian_blur(&m, ksize, 1.0, 1.0, BorderTypes::Reflect101).unwrap();
for val in res.data {
assert!(val >= 99 && val <= 101); }
}
#[test]
fn test_median_blur() {
let mut data = vec![10u8; 9];
data[4] = 255; let src = Matrix::from_vec(3, 3, 1, data);
let blur = median_blur(&src, 3).unwrap();
assert_eq!(*blur.at(1, 1, 0).unwrap(), 10);
}
#[test]
fn test_bilateral_filter() {
let mut data = vec![0u8; 25];
for x in 3..5 {
for y in 0..5 {
data[y * 5 + x] = 255;
}
}
let src = Matrix::from_vec(5, 5, 1, data);
let res = bilateral_filter(&src, 5, 50.0, 50.0, BorderTypes::Reflect101).unwrap();
let val_at_2_2 = *res.at(2, 2, 0).unwrap();
let val_at_2_3 = *res.at(2, 3, 0).unwrap();
assert!(val_at_2_2 < 50);
assert!(val_at_2_3 > 200);
}
#[test]
fn test_sobel() {
let mut data = vec![0u8; 100];
for x in 5..10 {
for y in 0..10 {
data[y * 10 + x] = 255;
}
}
let src = Matrix::from_vec(10, 10, 1, data);
let _res = sobel(&src, 1, 0, 3, 1.0, 0.0, BorderTypes::Reflect101).unwrap();
let src_f32: Matrix<f32> =
Matrix::from_vec(10, 10, 1, src.data.iter().map(|&v| v as f32).collect());
let res_f32 = sobel(&src_f32, 1, 0, 3, 1.0, 0.0, BorderTypes::Reflect101).unwrap();
let edge_val = *res_f32.at(5, 5, 0).unwrap();
assert!(edge_val > 500.0); }
#[test]
fn test_scharr() {
let mut data = vec![0u8; 100];
for x in 5..10 {
for y in 0..10 {
data[y * 10 + x] = 255;
}
}
let src = Matrix::<f32>::from_vec(10, 10, 1, data.iter().map(|&v| v as f32).collect());
let res = scharr(&src, 1, 0, 1.0, 0.0, BorderTypes::Reflect101).unwrap();
let edge_val = *res.at(5, 5, 0).unwrap();
assert!(edge_val > 2000.0);
}
#[test]
fn test_laplacian() {
let src = Matrix::<f32>::from_vec(5, 5, 1, vec![100.0; 25]);
let res = laplacian(&src, 1, 1.0, 0.0, BorderTypes::Reflect101).unwrap();
for &val in &res.data {
assert!(val.abs() < 1e-5);
}
let mut src_peak = Matrix::<f64>::new(5, 5, 1);
src_peak.set(2, 2, 0, 255.0);
let res_peak = laplacian(&src_peak, 1, 1.0, 0.0, BorderTypes::Reflect101).unwrap();
assert!(((*res_peak.at(2, 2, 0).unwrap() + 1020.0f64).abs()) < 1e-5);
}
#[test]
fn test_canny() {
let mut data = vec![0u8; 100];
for x in 4..7 {
for y in 0..10 {
data[y * 10 + x] = 255;
}
}
let src = Matrix::from_vec(10, 10, 1, data);
let edges = canny(&src, 50.0, 150.0, 3, false).unwrap();
assert_eq!(*edges.at(5, 4, 0).unwrap(), 255);
assert_eq!(*edges.at(5, 7, 0).unwrap(), 255);
assert_eq!(*edges.at(5, 0, 0).unwrap(), 0);
}
#[test]
fn test_cvt_color() {
let mut data = vec![0u8; 12];
data[0] = 255; data[4] = 255; data[8] = 255; let rgb_src = Matrix::from_vec(2, 2, 3, data);
let gray = cvt_color(&rgb_src, ColorConversionCode::COLOR_RGB2GRAY).unwrap();
assert!(
(*gray.at(0, 0, 0).unwrap() as i16 - 76).abs() <= 1,
"Red expected ~76, got {}",
*gray.at(0, 0, 0).unwrap()
);
assert!(
(*gray.at(0, 1, 0).unwrap() as i16 - 150).abs() <= 1,
"Green expected ~150, got {}",
*gray.at(0, 1, 0).unwrap()
);
assert!(
(*gray.at(1, 0, 0).unwrap() as i16 - 29).abs() <= 1,
"Blue expected ~29, got {}",
*gray.at(1, 0, 0).unwrap()
);
assert_eq!(*gray.at(1, 1, 0).unwrap(), 0);
let mut bgr_data = vec![0u8; 12];
bgr_data[0] = 255; bgr_data[4] = 255; bgr_data[8] = 255; let bgr_src = Matrix::from_vec(2, 2, 3, bgr_data);
let gray_bgr = cvt_color(&bgr_src, ColorConversionCode::COLOR_BGR2GRAY).unwrap();
assert!(
(*gray_bgr.at(0, 0, 0).unwrap() as i16 - 29).abs() <= 1,
"Blue expected ~29, got {}",
*gray_bgr.at(0, 0, 0).unwrap()
);
assert!(
(*gray_bgr.at(0, 1, 0).unwrap() as i16 - 150).abs() <= 1,
"Green expected ~150, got {}",
*gray_bgr.at(0, 1, 0).unwrap()
);
assert!(
(*gray_bgr.at(1, 0, 0).unwrap() as i16 - 76).abs() <= 1,
"Red expected ~76, got {}",
*gray_bgr.at(1, 0, 0).unwrap()
);
assert_eq!(*gray_bgr.at(1, 1, 0).unwrap(), 0);
}
#[test]
fn test_threshold() {
let data = vec![10u8, 50, 100, 150, 200, 250];
let src = Matrix::from_vec(1, 6, 1, data);
let (_, res) = threshold(&src, 127.0, 255.0, ThresholdTypes::THRESH_BINARY).unwrap();
assert_eq!(res.data, vec![0, 0, 0, 255, 255, 255]);
let (_, res_inv) =
threshold(&src, 127.0, 255.0, ThresholdTypes::THRESH_BINARY_INV).unwrap();
assert_eq!(res_inv.data, vec![255, 255, 255, 0, 0, 0]);
let (_, res_trunc) = threshold(&src, 127.0, 255.0, ThresholdTypes::THRESH_TRUNC).unwrap();
assert_eq!(res_trunc.data, vec![10, 50, 100, 127, 127, 127]);
let (_, res_zero) = threshold(&src, 127.0, 255.0, ThresholdTypes::THRESH_TOZERO).unwrap();
assert_eq!(res_zero.data, vec![0, 0, 0, 150, 200, 250]);
let (_, res_zero_inv) =
threshold(&src, 127.0, 255.0, ThresholdTypes::THRESH_TOZERO_INV).unwrap();
assert_eq!(res_zero_inv.data, vec![10, 50, 100, 0, 0, 0]);
}
#[test]
fn test_cvt_color_rgb_to_gray_large() {
let rows = 64;
let cols = 64;
let mut data = vec![0u8; rows * cols * 3];
for i in 0..rows * cols {
data[i * 3] = (i % 256) as u8; data[i * 3 + 1] = ((i * 3) % 256) as u8; data[i * 3 + 2] = ((i * 7) % 256) as u8; }
let src = Matrix::from_vec(rows, cols, 3, data.clone());
let gray = cvt_color(&src, ColorConversionCode::COLOR_RGB2GRAY).unwrap();
assert_eq!(gray.rows, rows);
assert_eq!(gray.cols, cols);
assert_eq!(gray.channels, 1);
for i in 0..rows * cols {
let r = data[i * 3] as f32;
let g = data[i * 3 + 1] as f32;
let b = data[i * 3 + 2] as f32;
let expected = (0.299 * r + 0.587 * g + 0.114 * b).round() as i16;
let actual = gray.data[i] as i16;
assert!(
(expected - actual).abs() <= 1,
"Pixel {i}: expected ~{expected}, got {actual}"
);
}
}
#[test]
fn test_cvt_color_bgr_to_gray_large() {
let rows = 64;
let cols = 64;
let mut data = vec![0u8; rows * cols * 3];
for i in 0..rows * cols {
data[i * 3] = ((i * 7) % 256) as u8; data[i * 3 + 1] = ((i * 3) % 256) as u8; data[i * 3 + 2] = (i % 256) as u8; }
let src = Matrix::from_vec(rows, cols, 3, data.clone());
let gray = cvt_color(&src, ColorConversionCode::COLOR_BGR2GRAY).unwrap();
for i in 0..rows * cols {
let b = data[i * 3] as f32;
let g = data[i * 3 + 1] as f32;
let r = data[i * 3 + 2] as f32;
let expected = (0.299 * r + 0.587 * g + 0.114 * b).round() as i16;
let actual = gray.data[i] as i16;
assert!(
(expected - actual).abs() <= 1,
"Pixel {i}: expected ~{expected}, got {actual}"
);
}
}
#[test]
fn test_cvt_color_rgba_to_gray_large() {
let rows = 32;
let cols = 32;
let mut data = vec![0u8; rows * cols * 4];
for i in 0..rows * cols {
data[i * 4] = (i % 256) as u8; data[i * 4 + 1] = ((i * 3) % 256) as u8; data[i * 4 + 2] = ((i * 7) % 256) as u8; data[i * 4 + 3] = 255; }
let src = Matrix::from_vec(rows, cols, 4, data.clone());
let gray = cvt_color(&src, ColorConversionCode::COLOR_RGBA2GRAY).unwrap();
for i in 0..rows * cols {
let r = data[i * 4] as f32;
let g = data[i * 4 + 1] as f32;
let b = data[i * 4 + 2] as f32;
let expected = (0.299 * r + 0.587 * g + 0.114 * b).round() as i16;
let actual = gray.data[i] as i16;
assert!(
(expected - actual).abs() <= 1,
"Pixel {i}: expected ~{expected}, got {actual}"
);
}
}
#[test]
fn test_threshold_all_types_u8() {
let data: Vec<u8> = (0..256).map(|i| i as u8).collect();
let src = Matrix::from_vec(1, 256, 1, data);
let (_, res) = threshold(&src, 127.0, 200.0, ThresholdTypes::THRESH_BINARY).unwrap();
for i in 0..256 {
let expected: u8 = if (i as u8) > 127 { 200 } else { 0 };
assert_eq!(res.data[i], expected, "BINARY mismatch at {i}");
}
let (_, res) = threshold(&src, 127.0, 200.0, ThresholdTypes::THRESH_BINARY_INV).unwrap();
for i in 0..256 {
let expected: u8 = if (i as u8) > 127 { 0 } else { 200 };
assert_eq!(res.data[i], expected, "BINARY_INV mismatch at {i}");
}
let (_, res) = threshold(&src, 127.0, 200.0, ThresholdTypes::THRESH_TRUNC).unwrap();
for i in 0..256 {
let expected: u8 = if (i as u8) > 127 { 127 } else { i as u8 };
assert_eq!(res.data[i], expected, "TRUNC mismatch at {i}");
}
let (_, res) = threshold(&src, 127.0, 200.0, ThresholdTypes::THRESH_TOZERO).unwrap();
for i in 0..256 {
let expected: u8 = if (i as u8) > 127 { i as u8 } else { 0 };
assert_eq!(res.data[i], expected, "TOZERO mismatch at {i}");
}
let (_, res) = threshold(&src, 127.0, 200.0, ThresholdTypes::THRESH_TOZERO_INV).unwrap();
for i in 0..256 {
let expected: u8 = if (i as u8) > 127 { 0 } else { i as u8 };
assert_eq!(res.data[i], expected, "TOZERO_INV mismatch at {i}");
}
}
#[test]
fn test_threshold_f32() {
let data: Vec<f32> = (0..100).map(|i| i as f32 * 0.01).collect();
let src = Matrix::from_vec(1, 100, 1, data);
let (_, res) = threshold(&src, 0.5, 1.0, ThresholdTypes::THRESH_BINARY).unwrap();
for i in 0..100 {
let val = i as f32 * 0.01;
let expected: f32 = if val > 0.5 { 1.0 } else { 0.0 };
assert!(
(res.data[i] - expected).abs() < 1e-5,
"f32 BINARY mismatch at {i}: expected {expected}, got {}",
res.data[i]
);
}
}
}