Use proptest for kernel convolution

This commit is contained in:
cdo committed 2026-10-26 15:52:20 +00:00
1 parent 96d1af5b78
commit a3743dd921
1 file changed
+49 -39
+49 -39
View File
@@ -28,25 +28,23 @@ impl<const N: usize> Kernel for [[f32; N]; N] {
x: img.extent.x - 2 * l, x: img.extent.x - 2 * l,
y: img.extent.y - 2 * l, y: img.extent.y - 2 * l,
}; };
let mut result = image::Image::with_extent(extent); let mut result = image::Image::with_extent(extent);
result.for_each(|x, y, p| { result.for_each(|x, y, p| {
for i in 0..N { for i in 0..N {
for j in 0..N { for j in 0..N {
let img_x = x as usize + i; *p += img.at(x + i, y + j) * self[j][i];
let img_y = y as usize + j;
let idx = img_y * img.extent.x as usize + img_x;
*p += img.pixels[idx] * self[j][i];
} }
} }
*p /= mag; *p /= mag;
}); });
result result
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use proptest::prelude::*;
#[test] #[test]
fn size_of_result_img() { fn size_of_result_img() {
@@ -60,37 +58,49 @@ mod tests {
assert_eq!(output.extent.y, 8); assert_eq!(output.extent.y, 8);
} }
#[test] proptest! {
fn single_pixel_result() { #[test]
let input = image::Image { fn single_pixel_result_3x3(
extent: image::Extent { x: 3, y: 3 }, p1 in 0.1f32..1.0,
pixels: vec![ p2 in 0.0f32..1.0,
image::SRGB::new(0.1, 0.0, 0.0), p3 in 0.0f32..1.0,
image::SRGB::new(0.0, 0.2, 0.0), p4 in 0.0f32..1.0,
image::SRGB::new(0.0, 0.0, 0.3), p5 in 0.0f32..1.0,
image::SRGB::new(0.2, 0.0, 0.0), p6 in 0.0f32..1.0,
image::SRGB::new(0.0, 0.3, 0.0), p7 in 0.0f32..1.0,
image::SRGB::new(0.0, 0.0, 0.1), p8 in 0.0f32..1.0,
image::SRGB::new(0.3, 0.0, 0.0), p9 in 0.0f32..1.0,
image::SRGB::new(0.0, 0.1, 0.0), k1 in 0.0f32..1.0,
image::SRGB::new(0.0, 0.0, 0.2), k2 in 0.0f32..1.0,
], k3 in 0.0f32..1.0,
}; k4 in 0.0f32..1.0,
let kernel = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6], [0.7, 0.8, 0.9]]; k5 in 0.0f32..1.0,
let output = kernel.convolve(&input); k6 in 0.0f32..1.0,
assert_eq!(output.extent.x, 1); k7 in 0.0f32..1.0,
assert_eq!(output.extent.y, 1); k8 in 0.0f32..1.0,
assert_eq!( k9 in 0.0f32..1.0,
output.pixels[0].r, ) {
(0.1 * 0.1 + 0.2 * 0.4 + 0.3 * 0.7) / 4.5, let input = image::Image {
); extent: image::Extent { x: 5, y: 5 },
assert_eq!( pixels: vec![
output.pixels[0].g, 10.0, 10.0, 10.0, 10.0, 10.0,
(0.2 * 0.2 + 0.3 * 0.5 + 0.1 * 0.8) / 4.5, 10.0, p1, p2, p3, 10.0,
); 10.0, p4, p5, p6, 10.0,
assert_eq!( 10.0, p7, p8, p9, 10.0,
output.pixels[0].b, 10.0, 10.0, 10.0, 10.0, 10.0,
(0.3 * 0.3 + 0.1 * 0.6 + 0.2 * 0.9) / 4.5, ],
); };
let kernel = [[k1, k2, k3], [k4, k5, k6], [k7, k8, k9]];
let output = kernel.convolve(&input);
prop_assert_eq!(output.extent.x, 3);
prop_assert_eq!(output.extent.y, 3);
let mag = k1 + k2 + k3 + k4 + k5 + k6 + k7 + k8 + k9;
let sum = p1 * k1 + p2 * k2 + p3 * k3
+ p4 * k4 + p5 * k5 + p6 * k6
+ p7 * k7 + p8 * k8 + p9 * k9;
let exp = sum / mag;
prop_assert!((output.at(1, 1) - exp).abs() < 1e-6);
}
} }
} }