///|
/// Physical degradation noise and illumination models for fiducial marker robustness testing.
pub(all) enum NoiseType {
Gaussian(Double)
SaltAndPepper(Double)
Poisson
MotionBlur(Int, Double) // (kernel_size, angle_radians)
Vignetting(Double) // Falloff power
LinearGradient(Double, Double) // (dx_slope, dy_slope)
} derive(Debug, Eq)
///|
/// Applies motion blur along a specific directional angle theta (simulating rapid robot/camera movement).
pub fn apply_motion_blur(
img : Image,
kernel_size : Int,
angle_rad : Double,
) -> Image {
let w = img.width
let h = img.height
let res = Image::new(w, h)
let k = if kernel_size < 3 { 3 } else { kernel_size }
let half_k = k / 2
let dx = @math.cos(angle_rad)
let dy = @math.sin(angle_rad)
for y in 0..= 0 && px < w && py >= 0 && py < h {
sum += img.get(px, py).to_double()
count += 1.0
}
}
let avg = if count > 0.0 {
(sum / count).round().to_int()
} else {
img.get(x, y)
}
res.set(x, y, avg)
}
}
res
}
///|
/// Applies radial vignetting light falloff (cos^4 law) from optical center.
pub fn apply_lens_vignetting(img : Image, strength : Double) -> Image {
let w = img.width
let h = img.height
let res = Image::new(w, h)
let cx = w.to_double() * 0.5
let cy = h.to_double() * 0.5
let max_radius = (cx * cx + cy * cy).sqrt()
for y in 0.. 255 { 255 } else { v })
}
}
res
}
///|
/// Applies non-uniform ambient illumination gradient across the canvas.
pub fn apply_lighting_gradient(
img : Image,
slope_x : Double,
slope_y : Double,
) -> Image {
let w = img.width
let h = img.height
let res = Image::new(w, h)
for y in 0.. 255 { 255 } else { v }
res.set(x, y, clamped)
}
}
res
}
///|
/// Synthetically occludes a rectangular sub-region inside a quad (simulating finger / cable occlusion).
pub fn apply_marker_occlusion_box(
img : Image,
x0 : Int,
y0 : Int,
w : Int,
h : Int,
fill_color : Int,
) -> Image {
let res = img.clone()
for cy in 0..= 0 && px < res.width && py >= 0 && py < res.height {
res.set(px, py, fill_color)
}
}
}
res
}