av_denoise/nlmeans/prefilter/
mod.rs1mod bilateral;
2
3pub use bilateral::bilateral_radius;
4use cubecl::prelude::*;
5use cubecl::server::Handle;
6
7#[non_exhaustive]
14#[derive(Debug, Default, Clone, Copy, PartialEq)]
15pub enum PrefilterMode {
16 #[default]
17 None,
18 External,
19 Bilateral {
20 sigma_s: f32,
21 sigma_r: f32,
22 },
23}
24
25impl PrefilterMode {
26 pub(crate) fn needs_reference_buf(self) -> bool {
28 !matches!(self, Self::None)
29 }
30
31 pub(crate) fn is_gpu_internal(self) -> bool {
34 matches!(self, Self::Bilateral { .. })
35 }
36}
37
38pub(crate) struct PrefilterCtx<'a> {
42 pub width: u32,
43 pub height: u32,
44 pub channels: u32,
45 pub stored_ch: u32,
46 pub frame_count: u32,
47 pub frame: u32,
48 pub input_buf: &'a Handle,
49 pub reference_buf: &'a Handle,
50}
51
52pub(crate) fn run_prefilter<R: Runtime>(
55 mode: PrefilterMode,
56 client: &ComputeClient<R>,
57 ctx: &PrefilterCtx<'_>,
58) -> Result<(), anyhow::Error> {
59 match mode {
60 PrefilterMode::None | PrefilterMode::External => Ok(()),
61 PrefilterMode::Bilateral { sigma_s, sigma_r } => {
62 bilateral::run_bilateral::<R>(client, ctx, sigma_s, sigma_r)
63 },
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn none_requires_no_reference_buffer() {
73 assert!(!PrefilterMode::None.needs_reference_buf());
74 assert!(!PrefilterMode::None.is_gpu_internal());
75 }
76
77 #[test]
78 fn external_needs_buffer_but_not_gpu() {
79 assert!(PrefilterMode::External.needs_reference_buf());
80 assert!(!PrefilterMode::External.is_gpu_internal());
81 }
82
83 #[test]
84 fn bilateral_is_gpu_internal() {
85 let m = PrefilterMode::Bilateral {
86 sigma_s: 3.0,
87 sigma_r: 0.02,
88 };
89
90 assert!(m.needs_reference_buf());
91 assert!(m.is_gpu_internal());
92 }
93
94 #[test]
95 fn bilateral_radius_truncates_at_two_sigma() {
96 assert_eq!(bilateral_radius(0.1), 1);
97 assert_eq!(bilateral_radius(1.0), 2);
98 assert_eq!(bilateral_radius(3.0), 6);
99 assert_eq!(bilateral_radius(3.5), 7);
100 }
101}