From 0c9d56458610db2eef86050450df36d29a434c5e Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 3 Oct 2026 21:17:07 -0400 Subject: [PATCH] Repair photosites beyond 8 sigma of every neighbour before the network The app's hot-pixel pass takes gross defects only; at ISO 6400-25600 a 6D frame keeps 1000-2000 photosites more than 8 sigma beyond all their same-colour and adjacent neighbours, which the network turned into specks. The same two tests with the threshold in the photosite's own sigma, plus the factor of two that keeps a bright point of light (where 8 sigma is a sliver of the signal). The next model is trained behind exactly this; on an ISO 25600 frame the Rust and training code both repair 935. --- core/dr-denoise/src/lib.rs | 14 +++- core/dr-denoise/src/repair.rs | 145 ++++++++++++++++++++++++++++++++++ docs/dev/traceability.md | 6 +- 3 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 core/dr-denoise/src/repair.rs diff --git a/core/dr-denoise/src/lib.rs b/core/dr-denoise/src/lib.rs index ad8ee4b..1e245c8 100644 --- a/core/dr-denoise/src/lib.rs +++ b/core/dr-denoise/src/lib.rs @@ -19,6 +19,7 @@ pub mod noise; #[cfg(feature = "onnx")] pub mod onnx; +pub mod repair; pub mod tile; use dr_decode::RawImage; @@ -67,12 +68,23 @@ pub fn denoise( } let active = noise::active(raw); let (h, w) = (active.h, active.w); + // The active area laid out once, then the noise-aware repair the model + // was trained behind (see `repair`). + let mut mosaic: Vec = (0..h * w).map(|i| active.at(i / w, i % w)).collect(); + let pattern = raw.cfa_pattern; + let repaired = repair::repair(&mut mosaic, h, w, repair::REPAIR_K, &|y, x, v| { + noise.sigma(pattern.colour_at(x as u32, y as u32) as usize, v) + }); + log::info!( + "learned denoise: {repaired} photosites beyond {}σ of every neighbour repaired", + repair::REPAIR_K + ); tile::run_tiled( net, h, w, raw.cfa_pattern, - &|y, x| active.at(y, x), + &|y, x| mosaic[y * w + x], &|c, v| noise.sigma(c, v), progress, ) diff --git a/core/dr-denoise/src/repair.rs b/core/dr-denoise/src/repair.rs new file mode 100644 index 0000000..ec72056 --- /dev/null +++ b/core/dr-denoise/src/repair.rs @@ -0,0 +1,145 @@ +//! TRACES: FR-DEV-3g +//! Hot and dead photosites, judged against the noise, before the network. +//! +//! The app's own pass (`dr_gpu::Demosaicer::repair_hot_pixels`) runs first and +//! takes the gross defects. At high ISO it leaves thousands of photosites per +//! 6D frame more than 8σ beyond every neighbour, which the network turns into +//! specks. This second pass uses that pass's two tests with the threshold in +//! units of the photosite's own σ from the noise model: +//! +//! - beyond every same-colour neighbour (two photosites away, the 3×3 of its +//! plane) by more than `k·σ`, and +//! - beyond every adjacent photosite, whatever its colour, by more than +//! `k·σ` **and** by a factor of two — what keeps a real point of light, +//! which lights its neighbours through the lens and the anti-aliasing +//! filter. A margin in σ alone is not enough: on a bright star 8σ is a +//! sliver of the signal, and the star would be flattened. +//! +//! A hot one becomes its brightest same-colour neighbour, a dead one its +//! darkest. The shipped model was trained on input repaired exactly so +//! (darkroom-denoise `denoise/repair.py`, `--repair-k 8`): the threshold +//! belongs to the model, and changes with it. Neighbours off the frame are +//! the nearest photosite on it, as the training code reads them. + +/// The threshold the shipped model was trained with, in σ. +pub const REPAIR_K: f32 = 8.0; + +/// Repair `mosaic` (`h×w`, row-major, normalised) in place; `sigma(y, x, v)` +/// is the photosite's σ. Returns how many photosites changed. +pub fn repair( + mosaic: &mut [f32], + h: usize, + w: usize, + k: f32, + sigma: &(dyn Fn(usize, usize, f32) -> f32 + Sync), +) -> usize { + let copy = mosaic.to_vec(); + let original = © + let at = |y: isize, x: isize| { + let y = y.clamp(0, h as isize - 1) as usize; + let x = x.clamp(0, w as isize - 1) as usize; + original[y * w + x] + }; + let threads = std::thread::available_parallelism().map_or(1, |n| n.get()); + let rows_per = h.div_ceil(threads).max(1); + let mut counts = vec![0usize; h.div_ceil(rows_per)]; + std::thread::scope(|scope| { + for ((chunk, rows), count) in mosaic + .chunks_mut(rows_per * w) + .enumerate() + .zip(counts.iter_mut()) + { + let at = &at; + scope.spawn(move || { + for (i, row) in rows.chunks_mut(w).enumerate() { + let y = chunk * rows_per + i; + for (x, out) in row.iter_mut().enumerate() { + let v = original[y * w + x]; + let (yi, xi) = (y as isize, x as isize); + let (mut s_hi, mut s_lo) = (f32::MIN, f32::MAX); + let (mut a_hi, mut a_lo) = (f32::MIN, f32::MAX); + for dy in -1isize..=1 { + for dx in -1isize..=1 { + if dy == 0 && dx == 0 { + continue; + } + let s = at(yi + 2 * dy, xi + 2 * dx); + s_hi = s_hi.max(s); + s_lo = s_lo.min(s); + let a = at(yi + dy, xi + dx); + a_hi = a_hi.max(a); + a_lo = a_lo.min(a); + } + } + let t = k * sigma(y, x, v); + if v - s_hi > t && v - a_hi > t && a_hi < 0.5 * v { + *out = s_hi; + *count += 1; + } else if s_lo - v > t && a_lo - v > t && v < 0.5 * a_lo { + *out = s_lo; + *count += 1; + } + } + } + }); + } + }); + counts.iter().sum() +} + +#[cfg(test)] +mod tests { + use super::*; + + const N: usize = 16; + + fn flat(level: f32) -> Vec { + vec![level; N * N] + } + + fn run(m: &mut [f32]) -> usize { + repair(m, N, N, REPAIR_K, &|_, _, _| 0.01) + } + + #[test] + fn a_hot_photosite_becomes_its_brightest_same_colour_neighbour() { + let mut m = flat(0.1); + m[8 * N + 8] = 0.5; // 40σ above everything around it + m[8 * N + 10] = 0.12; // a same-colour neighbour, a little brighter + assert_eq!(run(&mut m), 1); + assert_eq!(m[8 * N + 8], 0.12); + } + + #[test] + fn a_dead_photosite_in_a_lit_area_is_repaired() { + let mut m = flat(0.5); + m[5 * N + 5] = 0.0; + assert_eq!(run(&mut m), 1); + assert_eq!(m[5 * N + 5], 0.5); + } + + #[test] + fn a_point_of_real_light_is_kept() { + // Light through a lens lands on a patch: its adjacent photosites are + // lit too, so the second test refuses it. + let mut m = flat(0.1); + for dy in 0..3 { + for dx in 0..3 { + m[(7 + dy) * N + 7 + dx] = if (dy, dx) == (1, 1) { 0.9 } else { 0.6 }; + } + } + let before = m.clone(); + assert_eq!(run(&mut m), 0); + assert_eq!(m, before); + } + + #[test] + fn noise_within_the_threshold_is_left_alone() { + let mut m: Vec = (0..N * N) + .map(|i| 0.1 + 0.005 * ((i * 7919 % 13) as f32 - 6.0) / 6.0) + .collect(); + let before = m.clone(); + assert_eq!(run(&mut m), 0); + assert_eq!(m, before); + } +} diff --git a/docs/dev/traceability.md b/docs/dev/traceability.md index b2b9dd8..460aff5 100644 --- a/docs/dev/traceability.md +++ b/docs/dev/traceability.md @@ -9,8 +9,8 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n | Metric | Value | |---|---| -| Source files scanned | 501 | -| TRACES tags found | 2105 | +| Source files scanned | 502 | +| TRACES tags found | 2106 | | Requirements defined | 193 | | Requirements deferred (post-v1) | 24 | | Requirements covered | 166 | @@ -81,7 +81,7 @@ _None._ | FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:1107`](../../core/dr-gpu/src/adjust.rs#L1107), [`core/dr-gpu/src/adjust.rs:112`](../../core/dr-gpu/src/adjust.rs#L112), [`core/dr-gpu/src/adjust.rs:1429`](../../core/dr-gpu/src/adjust.rs#L1429), [`core/dr-gpu/src/adjust.rs:1523`](../../core/dr-gpu/src/adjust.rs#L1523), [`core/dr-gpu/src/adjust.rs:82`](../../core/dr-gpu/src/adjust.rs#L82), [`core/dr-gpu/tests/capture_sharpen.rs:433`](../../core/dr-gpu/tests/capture_sharpen.rs#L433), [`core/dr-gpu/tests/detail_stage.rs:241`](../../core/dr-gpu/tests/detail_stage.rs#L241), [`core/dr-gpu/tests/local_contrast.rs:557`](../../core/dr-gpu/tests/local_contrast.rs#L557), [`core/dr-gpu/tests/noise_reduction.rs:555`](../../core/dr-gpu/tests/noise_reduction.rs#L555), [`core/dr-pipeline/src/framing.rs:481`](../../core/dr-pipeline/src/framing.rs#L481), [`core/dr-pipeline/src/graph.rs:1142`](../../core/dr-pipeline/src/graph.rs#L1142), [`core/dr-pipeline/src/operation.rs:32`](../../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:505`](../../core/dr-pipeline/src/operation.rs#L505), [`core/dr-pipeline/src/operation.rs:53`](../../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../../core/dr-pipeline/src/operation.rs#L71) | | FR-DEV-3e | [`core/dr-decode/src/dcp.rs:132`](../../core/dr-decode/src/dcp.rs#L132), [`core/dr-decode/src/dcp.rs:163`](../../core/dr-decode/src/dcp.rs#L163), [`core/dr-decode/src/dcp.rs:182`](../../core/dr-decode/src/dcp.rs#L182), [`core/dr-decode/src/dcp.rs:1`](../../core/dr-decode/src/dcp.rs#L1), [`core/dr-decode/src/dcp.rs:205`](../../core/dr-decode/src/dcp.rs#L205), [`core/dr-decode/src/dcp.rs:240`](../../core/dr-decode/src/dcp.rs#L240), [`core/dr-decode/src/dcp.rs:431`](../../core/dr-decode/src/dcp.rs#L431), [`core/dr-decode/src/dcp.rs:482`](../../core/dr-decode/src/dcp.rs#L482), [`core/dr-decode/src/dcp.rs:493`](../../core/dr-decode/src/dcp.rs#L493), [`core/dr-decode/src/dcp.rs:526`](../../core/dr-decode/src/dcp.rs#L526), [`core/dr-decode/src/dcp.rs:546`](../../core/dr-decode/src/dcp.rs#L546), [`core/dr-decode/src/dcp.rs:559`](../../core/dr-decode/src/dcp.rs#L559), [`core/dr-decode/src/dcp.rs:79`](../../core/dr-decode/src/dcp.rs#L79), [`core/dr-decode/src/lib.rs:126`](../../core/dr-decode/src/lib.rs#L126), [`core/dr-decode/src/lib.rs:141`](../../core/dr-decode/src/lib.rs#L141), [`core/dr-decode/src/lib.rs:150`](../../core/dr-decode/src/lib.rs#L150), [`core/dr-decode/src/lib.rs:601`](../../core/dr-decode/src/lib.rs#L601), [`core/dr-decode/src/lib.rs:799`](../../core/dr-decode/src/lib.rs#L799), [`core/dr-decode/src/lib.rs:839`](../../core/dr-decode/src/lib.rs#L839), [`core/dr-decode/src/profile.rs:104`](../../core/dr-decode/src/profile.rs#L104), [`core/dr-decode/src/profile.rs:153`](../../core/dr-decode/src/profile.rs#L153), [`core/dr-decode/src/profile.rs:1`](../../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:237`](../../core/dr-decode/src/profile.rs#L237), [`core/dr-decode/src/profile.rs:288`](../../core/dr-decode/src/profile.rs#L288), [`core/dr-decode/src/profile.rs:345`](../../core/dr-decode/src/profile.rs#L345), [`core/dr-decode/src/profile.rs:475`](../../core/dr-decode/src/profile.rs#L475), [`core/dr-decode/src/profile.rs:509`](../../core/dr-decode/src/profile.rs#L509), [`core/dr-decode/src/profile.rs:680`](../../core/dr-decode/src/profile.rs#L680), [`core/dr-gpu/src/adjust.rs:523`](../../core/dr-gpu/src/adjust.rs#L523), [`core/dr-gpu/src/adjust.rs:536`](../../core/dr-gpu/src/adjust.rs#L536), [`core/dr-gpu/src/adjust.rs:74`](../../core/dr-gpu/src/adjust.rs#L74), [`core/dr-gpu/src/demosaic.rs:110`](../../core/dr-gpu/src/demosaic.rs#L110), [`core/dr-gpu/src/demosaic.rs:215`](../../core/dr-gpu/src/demosaic.rs#L215), [`core/dr-gpu/src/demosaic.rs:592`](../../core/dr-gpu/src/demosaic.rs#L592), [`core/dr-gpu/tests/camera_profile.rs:1`](../../core/dr-gpu/tests/camera_profile.rs#L1), [`core/dr-pipeline/src/camera_raw.rs:1`](../../core/dr-pipeline/src/camera_raw.rs#L1), [`core/dr-pipeline/src/declared/decl.rs:279`](../../core/dr-pipeline/src/declared/decl.rs#L279), [`core/dr-pipeline/src/operation.rs:2459`](../../core/dr-pipeline/src/operation.rs#L2459), [`core/dr-pipeline/src/operation.rs:2483`](../../core/dr-pipeline/src/operation.rs#L2483), [`core/dr-pipeline/src/operation.rs:273`](../../core/dr-pipeline/src/operation.rs#L273), [`core/dr-pipeline/src/operation.rs:349`](../../core/dr-pipeline/src/operation.rs#L349), [`core/dr-pipeline/src/operation.rs:369`](../../core/dr-pipeline/src/operation.rs#L369), [`core/dr-pipeline/src/operation.rs:443`](../../core/dr-pipeline/src/operation.rs#L443), [`core/dr-pipeline/src/operation.rs:463`](../../core/dr-pipeline/src/operation.rs#L463), [`core/dr-pipeline/src/ops/camera_profile.rs:1`](../../core/dr-pipeline/src/ops/camera_profile.rs#L1), [`core/dr-pipeline/src/ops/camera_profile.rs:393`](../../core/dr-pipeline/src/ops/camera_profile.rs#L393), [`core/dr-pipeline/src/ops/camera_profile.rs:430`](../../core/dr-pipeline/src/ops/camera_profile.rs#L430), [`core/dr-pipeline/src/view.rs:238`](../../core/dr-pipeline/src/view.rs#L238), [`core/dr-types/src/hue_sat.rs:1`](../../core/dr-types/src/hue_sat.rs#L1), [`core/dr-types/src/tone.rs:162`](../../core/dr-types/src/tone.rs#L162), [`core/dr-types/src/tone.rs:1`](../../core/dr-types/src/tone.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1031`](../../ui/dr-ui/src/derived_sync.rs#L1031), [`ui/dr-ui/src/derived_sync.rs:2056`](../../ui/dr-ui/src/derived_sync.rs#L2056), [`ui/dr-ui/src/derived_sync.rs:244`](../../ui/dr-ui/src/derived_sync.rs#L244), [`ui/dr-ui/src/derived_sync.rs:94`](../../ui/dr-ui/src/derived_sync.rs#L94), [`ui/dr-ui/src/develop/session.rs:606`](../../ui/dr-ui/src/develop/session.rs#L606), [`ui/dr-ui/src/develop/session.rs:646`](../../ui/dr-ui/src/develop/session.rs#L646), [`ui/dr-ui/src/develop/session.rs:681`](../../ui/dr-ui/src/develop/session.rs#L681), [`ui/dr-ui/src/develop/session.rs:690`](../../ui/dr-ui/src/develop/session.rs#L690), [`ui/dr-ui/src/develop/session.rs:73`](../../ui/dr-ui/src/develop/session.rs#L73), [`ui/dr-ui/src/develop/session.rs:882`](../../ui/dr-ui/src/develop/session.rs#L882), [`ui/dr-ui/src/develop/session.rs:955`](../../ui/dr-ui/src/develop/session.rs#L955), [`ui/dr-ui/src/lib.rs:1243`](../../ui/dr-ui/src/lib.rs#L1243), [`ui/dr-ui/src/lib.rs:1541`](../../ui/dr-ui/src/lib.rs#L1541), [`ui/dr-ui/src/lib.rs:1559`](../../ui/dr-ui/src/lib.rs#L1559), [`ui/dr-ui/src/lib.rs:330`](../../ui/dr-ui/src/lib.rs#L330), [`ui/dr-ui/ui/develop.slint:386`](../../ui/dr-ui/ui/develop.slint#L386), [`ui/dr-ui/ui/develop.slint:395`](../../ui/dr-ui/ui/develop.slint#L395) | | FR-DEV-3f | [`core/dr-film/src/bake.rs:161`](../../core/dr-film/src/bake.rs#L161), [`core/dr-film/src/bake.rs:384`](../../core/dr-film/src/bake.rs#L384), [`core/dr-film/src/bake.rs:52`](../../core/dr-film/src/bake.rs#L52), [`core/dr-film/src/bake.rs:662`](../../core/dr-film/src/bake.rs#L662), [`core/dr-film/src/bake.rs:689`](../../core/dr-film/src/bake.rs#L689), [`core/dr-film/src/bake.rs:710`](../../core/dr-film/src/bake.rs#L710), [`core/dr-film/src/bake.rs:747`](../../core/dr-film/src/bake.rs#L747), [`core/dr-film/src/bake.rs:95`](../../core/dr-film/src/bake.rs#L95), [`core/dr-film/src/boolean_grain.rs:1`](../../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:152`](../../core/dr-gpu/src/adjust.rs#L152), [`core/dr-gpu/src/adjust.rs:422`](../../core/dr-gpu/src/adjust.rs#L422), [`core/dr-gpu/src/adjust.rs:632`](../../core/dr-gpu/src/adjust.rs#L632), [`core/dr-gpu/src/adjust.rs:67`](../../core/dr-gpu/src/adjust.rs#L67), [`core/dr-gpu/src/adjust.rs:765`](../../core/dr-gpu/src/adjust.rs#L765), [`core/dr-gpu/tests/film_sim.rs:1`](../../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-gpu/tests/film_sim.rs:215`](../../core/dr-gpu/tests/film_sim.rs#L215), [`core/dr-gpu/tests/film_sim.rs:349`](../../core/dr-gpu/tests/film_sim.rs#L349), [`core/dr-gpu/tests/film_sim.rs:388`](../../core/dr-gpu/tests/film_sim.rs#L388), [`core/dr-gpu/tests/film_sim.rs:417`](../../core/dr-gpu/tests/film_sim.rs#L417), [`core/dr-gpu/tests/film_sim.rs:457`](../../core/dr-gpu/tests/film_sim.rs#L457), [`core/dr-pipeline/src/graph.rs:110`](../../core/dr-pipeline/src/graph.rs#L110), [`core/dr-pipeline/src/graph.rs:187`](../../core/dr-pipeline/src/graph.rs#L187), [`core/dr-pipeline/src/graph.rs:689`](../../core/dr-pipeline/src/graph.rs#L689), [`core/dr-pipeline/src/mask.rs:2452`](../../core/dr-pipeline/src/mask.rs#L2452), [`core/dr-pipeline/src/mask.rs:2485`](../../core/dr-pipeline/src/mask.rs#L2485), [`core/dr-pipeline/src/operation.rs:1086`](../../core/dr-pipeline/src/operation.rs#L1086), [`core/dr-pipeline/src/operation.rs:1436`](../../core/dr-pipeline/src/operation.rs#L1436), [`core/dr-pipeline/src/operation.rs:1670`](../../core/dr-pipeline/src/operation.rs#L1670), [`core/dr-pipeline/src/operation.rs:1698`](../../core/dr-pipeline/src/operation.rs#L1698), [`core/dr-pipeline/src/operation.rs:1750`](../../core/dr-pipeline/src/operation.rs#L1750), [`core/dr-pipeline/src/operation.rs:2377`](../../core/dr-pipeline/src/operation.rs#L2377), [`core/dr-pipeline/src/operation.rs:309`](../../core/dr-pipeline/src/operation.rs#L309), [`core/dr-pipeline/src/operation.rs:323`](../../core/dr-pipeline/src/operation.rs#L323), [`core/dr-pipeline/src/operation.rs:334`](../../core/dr-pipeline/src/operation.rs#L334), [`core/dr-pipeline/src/operation.rs:349`](../../core/dr-pipeline/src/operation.rs#L349), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:134`](../../core/dr-pipeline/src/ops/film_sim.rs#L134), [`core/dr-pipeline/src/ops/film_sim.rs:186`](../../core/dr-pipeline/src/ops/film_sim.rs#L186), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:233`](../../core/dr-pipeline/src/ops/film_sim.rs#L233), [`core/dr-pipeline/src/ops/film_sim.rs:315`](../../core/dr-pipeline/src/ops/film_sim.rs#L315), [`core/dr-pipeline/src/ops/film_sim.rs:329`](../../core/dr-pipeline/src/ops/film_sim.rs#L329), [`core/dr-pipeline/src/ops/film_sim.rs:438`](../../core/dr-pipeline/src/ops/film_sim.rs#L438), [`core/dr-pipeline/src/ops/film_sim.rs:48`](../../core/dr-pipeline/src/ops/film_sim.rs#L48), [`core/dr-pipeline/src/ops/film_sim.rs:736`](../../core/dr-pipeline/src/ops/film_sim.rs#L736), [`core/dr-pipeline/src/preset.rs:1343`](../../core/dr-pipeline/src/preset.rs#L1343), [`core/dr-pipeline/src/preset.rs:1353`](../../core/dr-pipeline/src/preset.rs#L1353), [`core/dr-pipeline/src/preset.rs:1362`](../../core/dr-pipeline/src/preset.rs#L1362), [`core/dr-pipeline/src/preset.rs:1378`](../../core/dr-pipeline/src/preset.rs#L1378), [`core/dr-pipeline/src/preset.rs:1390`](../../core/dr-pipeline/src/preset.rs#L1390), [`core/dr-pipeline/src/preset.rs:1406`](../../core/dr-pipeline/src/preset.rs#L1406), [`core/dr-pipeline/src/preset.rs:1670`](../../core/dr-pipeline/src/preset.rs#L1670), [`core/dr-pipeline/src/preset.rs:1685`](../../core/dr-pipeline/src/preset.rs#L1685), [`core/dr-pipeline/src/preset.rs:248`](../../core/dr-pipeline/src/preset.rs#L248), [`core/dr-pipeline/src/preset.rs:739`](../../core/dr-pipeline/src/preset.rs#L739), [`core/dr-pipeline/src/preset.rs:828`](../../core/dr-pipeline/src/preset.rs#L828), [`core/dr-pipeline/src/sidecar.rs:1077`](../../core/dr-pipeline/src/sidecar.rs#L1077), [`core/dr-pipeline/src/sidecar.rs:133`](../../core/dr-pipeline/src/sidecar.rs#L133), [`core/dr-pipeline/src/sidecar.rs:217`](../../core/dr-pipeline/src/sidecar.rs#L217), [`core/dr-pipeline/src/sidecar.rs:2724`](../../core/dr-pipeline/src/sidecar.rs#L2724), [`core/dr-pipeline/src/sidecar.rs:2800`](../../core/dr-pipeline/src/sidecar.rs#L2800), [`core/dr-pipeline/src/sidecar.rs:595`](../../core/dr-pipeline/src/sidecar.rs#L595), [`core/dr-pipeline/src/sidecar.rs:898`](../../core/dr-pipeline/src/sidecar.rs#L898), [`core/dr-pipeline/src/state.rs:100`](../../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop/render.rs:1002`](../../ui/dr-ui/src/develop/render.rs#L1002), [`ui/dr-ui/src/develop/render.rs:1053`](../../ui/dr-ui/src/develop/render.rs#L1053), [`ui/dr-ui/src/develop/render.rs:1079`](../../ui/dr-ui/src/develop/render.rs#L1079), [`ui/dr-ui/src/develop/render.rs:1402`](../../ui/dr-ui/src/develop/render.rs#L1402), [`ui/dr-ui/src/develop/render.rs:1442`](../../ui/dr-ui/src/develop/render.rs#L1442), [`ui/dr-ui/src/develop/render.rs:1477`](../../ui/dr-ui/src/develop/render.rs#L1477), [`ui/dr-ui/src/develop/render.rs:830`](../../ui/dr-ui/src/develop/render.rs#L830), [`ui/dr-ui/src/develop/render.rs:847`](../../ui/dr-ui/src/develop/render.rs#L847), [`ui/dr-ui/src/develop/render.rs:859`](../../ui/dr-ui/src/develop/render.rs#L859), [`ui/dr-ui/src/develop/render.rs:897`](../../ui/dr-ui/src/develop/render.rs#L897), [`ui/dr-ui/src/develop/render.rs:934`](../../ui/dr-ui/src/develop/render.rs#L934), [`ui/dr-ui/src/develop/render.rs:945`](../../ui/dr-ui/src/develop/render.rs#L945), [`ui/dr-ui/src/develop/session.rs:760`](../../ui/dr-ui/src/develop/session.rs#L760), [`ui/dr-ui/src/develop/session.rs:780`](../../ui/dr-ui/src/develop/session.rs#L780), [`ui/dr-ui/src/develop/tabs.rs:80`](../../ui/dr-ui/src/develop/tabs.rs#L80), [`ui/dr-ui/src/develop_ui.rs:534`](../../ui/dr-ui/src/develop_ui.rs#L534), [`ui/dr-ui/src/lib.rs:916`](../../ui/dr-ui/src/lib.rs#L916), [`ui/dr-ui/src/lib.rs:981`](../../ui/dr-ui/src/lib.rs#L981), [`ui/dr-ui/src/library/sidecar.rs:325`](../../ui/dr-ui/src/library/sidecar.rs#L325), [`ui/dr-ui/src/library/sidecar.rs:50`](../../ui/dr-ui/src/library/sidecar.rs#L50), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:602`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L602), [`ui/dr-ui/src/presets.rs:1933`](../../ui/dr-ui/src/presets.rs#L1933), [`ui/dr-ui/src/presets.rs:422`](../../ui/dr-ui/src/presets.rs#L422), [`ui/dr-ui/tests/film_list_reaches_every_stock.rs:1`](../../ui/dr-ui/tests/film_list_reaches_every_stock.rs#L1), [`ui/dr-ui/ui/adjust.slint:1071`](../../ui/dr-ui/ui/adjust.slint#L1071), [`ui/dr-ui/ui/adjust.slint:1081`](../../ui/dr-ui/ui/adjust.slint#L1081), [`ui/dr-ui/ui/adjust.slint:1298`](../../ui/dr-ui/ui/adjust.slint#L1298) | -| FR-DEV-3g | [`core/dr-decode/src/lib.rs:553`](../../core/dr-decode/src/lib.rs#L553), [`core/dr-decode/src/profile.rs:743`](../../core/dr-decode/src/profile.rs#L743), [`core/dr-denoise/src/lib.rs:1`](../../core/dr-denoise/src/lib.rs#L1), [`core/dr-denoise/src/noise.rs:1`](../../core/dr-denoise/src/noise.rs#L1), [`core/dr-denoise/src/onnx.rs:1`](../../core/dr-denoise/src/onnx.rs#L1), [`core/dr-denoise/src/tile.rs:1`](../../core/dr-denoise/src/tile.rs#L1), [`core/dr-gpu/src/demosaic.rs:1063`](../../core/dr-gpu/src/demosaic.rs#L1063), [`core/dr-gpu/src/demosaic.rs:349`](../../core/dr-gpu/src/demosaic.rs#L349), [`core/dr-gpu/src/grain.rs:1`](../../core/dr-gpu/src/grain.rs#L1), [`core/dr-gpu/tests/grain.rs:1`](../../core/dr-gpu/tests/grain.rs#L1), [`core/dr-pipeline/src/graph.rs:173`](../../core/dr-pipeline/src/graph.rs#L173), [`core/dr-pipeline/src/graph.rs:2122`](../../core/dr-pipeline/src/graph.rs#L2122), [`core/dr-pipeline/src/graph.rs:417`](../../core/dr-pipeline/src/graph.rs#L417), [`core/dr-pipeline/src/graph.rs:423`](../../core/dr-pipeline/src/graph.rs#L423), [`core/dr-pipeline/src/graph.rs:431`](../../core/dr-pipeline/src/graph.rs#L431), [`core/dr-pipeline/src/graph.rs:619`](../../core/dr-pipeline/src/graph.rs#L619), [`core/dr-pipeline/src/learned_denoise.rs:1`](../../core/dr-pipeline/src/learned_denoise.rs#L1), [`core/dr-pipeline/src/learned_denoise.rs:21`](../../core/dr-pipeline/src/learned_denoise.rs#L21), [`ui/dr-ui/src/activity.rs:86`](../../ui/dr-ui/src/activity.rs#L86), [`ui/dr-ui/src/develop/denoise.rs:1`](../../ui/dr-ui/src/develop/denoise.rs#L1), [`ui/dr-ui/src/develop/denoise.rs:292`](../../ui/dr-ui/src/develop/denoise.rs#L292), [`ui/dr-ui/src/develop/denoise.rs:95`](../../ui/dr-ui/src/develop/denoise.rs#L95), [`ui/dr-ui/src/develop/denoise_cache.rs:1`](../../ui/dr-ui/src/develop/denoise_cache.rs#L1), [`ui/dr-ui/src/develop/render.rs:238`](../../ui/dr-ui/src/develop/render.rs#L238), [`ui/dr-ui/src/develop/render.rs:712`](../../ui/dr-ui/src/develop/render.rs#L712), [`ui/dr-ui/src/develop/session.rs:126`](../../ui/dr-ui/src/develop/session.rs#L126), [`ui/dr-ui/src/develop/session.rs:389`](../../ui/dr-ui/src/develop/session.rs#L389), [`ui/dr-ui/src/develop_ui.rs:139`](../../ui/dr-ui/src/develop_ui.rs#L139), [`ui/dr-ui/src/lib.rs:327`](../../ui/dr-ui/src/lib.rs#L327), [`ui/dr-ui/src/library/paths.rs:392`](../../ui/dr-ui/src/library/paths.rs#L392), [`ui/dr-ui/src/library/paths.rs:396`](../../ui/dr-ui/src/library/paths.rs#L396) | +| FR-DEV-3g | [`core/dr-decode/src/lib.rs:553`](../../core/dr-decode/src/lib.rs#L553), [`core/dr-decode/src/profile.rs:743`](../../core/dr-decode/src/profile.rs#L743), [`core/dr-denoise/src/lib.rs:1`](../../core/dr-denoise/src/lib.rs#L1), [`core/dr-denoise/src/noise.rs:1`](../../core/dr-denoise/src/noise.rs#L1), [`core/dr-denoise/src/onnx.rs:1`](../../core/dr-denoise/src/onnx.rs#L1), [`core/dr-denoise/src/repair.rs:1`](../../core/dr-denoise/src/repair.rs#L1), [`core/dr-denoise/src/tile.rs:1`](../../core/dr-denoise/src/tile.rs#L1), [`core/dr-gpu/src/demosaic.rs:1063`](../../core/dr-gpu/src/demosaic.rs#L1063), [`core/dr-gpu/src/demosaic.rs:349`](../../core/dr-gpu/src/demosaic.rs#L349), [`core/dr-gpu/src/grain.rs:1`](../../core/dr-gpu/src/grain.rs#L1), [`core/dr-gpu/tests/grain.rs:1`](../../core/dr-gpu/tests/grain.rs#L1), [`core/dr-pipeline/src/graph.rs:173`](../../core/dr-pipeline/src/graph.rs#L173), [`core/dr-pipeline/src/graph.rs:2122`](../../core/dr-pipeline/src/graph.rs#L2122), [`core/dr-pipeline/src/graph.rs:417`](../../core/dr-pipeline/src/graph.rs#L417), [`core/dr-pipeline/src/graph.rs:423`](../../core/dr-pipeline/src/graph.rs#L423), [`core/dr-pipeline/src/graph.rs:431`](../../core/dr-pipeline/src/graph.rs#L431), [`core/dr-pipeline/src/graph.rs:619`](../../core/dr-pipeline/src/graph.rs#L619), [`core/dr-pipeline/src/learned_denoise.rs:1`](../../core/dr-pipeline/src/learned_denoise.rs#L1), [`core/dr-pipeline/src/learned_denoise.rs:21`](../../core/dr-pipeline/src/learned_denoise.rs#L21), [`ui/dr-ui/src/activity.rs:86`](../../ui/dr-ui/src/activity.rs#L86), [`ui/dr-ui/src/develop/denoise.rs:1`](../../ui/dr-ui/src/develop/denoise.rs#L1), [`ui/dr-ui/src/develop/denoise.rs:292`](../../ui/dr-ui/src/develop/denoise.rs#L292), [`ui/dr-ui/src/develop/denoise.rs:95`](../../ui/dr-ui/src/develop/denoise.rs#L95), [`ui/dr-ui/src/develop/denoise_cache.rs:1`](../../ui/dr-ui/src/develop/denoise_cache.rs#L1), [`ui/dr-ui/src/develop/render.rs:238`](../../ui/dr-ui/src/develop/render.rs#L238), [`ui/dr-ui/src/develop/render.rs:712`](../../ui/dr-ui/src/develop/render.rs#L712), [`ui/dr-ui/src/develop/session.rs:126`](../../ui/dr-ui/src/develop/session.rs#L126), [`ui/dr-ui/src/develop/session.rs:389`](../../ui/dr-ui/src/develop/session.rs#L389), [`ui/dr-ui/src/develop_ui.rs:139`](../../ui/dr-ui/src/develop_ui.rs#L139), [`ui/dr-ui/src/lib.rs:327`](../../ui/dr-ui/src/lib.rs#L327), [`ui/dr-ui/src/library/paths.rs:392`](../../ui/dr-ui/src/library/paths.rs#L392), [`ui/dr-ui/src/library/paths.rs:396`](../../ui/dr-ui/src/library/paths.rs#L396) | | FR-DEV-3h | [`core/dr-decode/src/lib.rs:451`](../../core/dr-decode/src/lib.rs#L451), [`core/dr-decode/src/preview.rs:29`](../../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:1492`](../../core/dr-pipeline/src/framing.rs#L1492), [`core/dr-pipeline/src/framing.rs:499`](../../core/dr-pipeline/src/framing.rs#L499), [`core/dr-pipeline/src/framing.rs:717`](../../core/dr-pipeline/src/framing.rs#L717), [`core/dr-types/src/lib.rs:342`](../../core/dr-types/src/lib.rs#L342), [`core/dr-types/src/lib.rs:450`](../../core/dr-types/src/lib.rs#L450), [`core/dr-types/src/lib.rs:462`](../../core/dr-types/src/lib.rs#L462), [`core/dr-types/src/lib.rs:478`](../../core/dr-types/src/lib.rs#L478), [`ui/dr-ui/src/develop/masks.rs:280`](../../ui/dr-ui/src/develop/masks.rs#L280), [`ui/dr-ui/src/develop/segmentation.rs:114`](../../ui/dr-ui/src/develop/segmentation.rs#L114), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499) | | FR-DEV-3i | [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-segment/src/lib.rs:1`](../../core/dr-segment/src/lib.rs#L1), [`ui/dr-ui/src/segmentation.rs:1`](../../ui/dr-ui/src/segmentation.rs#L1) | | FR-DEV-3j | [`core/dr-gpu/src/adjust.rs:1301`](../../core/dr-gpu/src/adjust.rs#L1301), [`core/dr-gpu/src/adjust.rs:1539`](../../core/dr-gpu/src/adjust.rs#L1539), [`core/dr-gpu/src/adjust.rs:3396`](../../core/dr-gpu/src/adjust.rs#L3396), [`core/dr-gpu/tests/camera_profile.rs:209`](../../core/dr-gpu/tests/camera_profile.rs#L209), [`core/dr-gpu/tests/scene_referred.rs:145`](../../core/dr-gpu/tests/scene_referred.rs#L145), [`core/dr-gpu/tests/scene_referred.rs:1`](../../core/dr-gpu/tests/scene_referred.rs#L1), [`core/dr-gpu/tests/view_transform.rs:114`](../../core/dr-gpu/tests/view_transform.rs#L114), [`core/dr-gpu/tests/view_transform.rs:137`](../../core/dr-gpu/tests/view_transform.rs#L137), [`core/dr-gpu/tests/view_transform.rs:163`](../../core/dr-gpu/tests/view_transform.rs#L163), [`core/dr-gpu/tests/view_transform.rs:1`](../../core/dr-gpu/tests/view_transform.rs#L1), [`core/dr-gpu/tests/view_transform.rs:201`](../../core/dr-gpu/tests/view_transform.rs#L201), [`core/dr-gpu/tests/view_transform.rs:63`](../../core/dr-gpu/tests/view_transform.rs#L63), [`core/dr-pipeline/src/camera_raw.rs:1`](../../core/dr-pipeline/src/camera_raw.rs#L1), [`core/dr-pipeline/src/camera_raw.rs:56`](../../core/dr-pipeline/src/camera_raw.rs#L56), [`core/dr-pipeline/src/operation.rs:1414`](../../core/dr-pipeline/src/operation.rs#L1414), [`core/dr-pipeline/src/operation.rs:2377`](../../core/dr-pipeline/src/operation.rs#L2377), [`core/dr-pipeline/src/operation.rs:2493`](../../core/dr-pipeline/src/operation.rs#L2493), [`core/dr-pipeline/src/operation.rs:2510`](../../core/dr-pipeline/src/operation.rs#L2510), [`core/dr-pipeline/src/operation.rs:2700`](../../core/dr-pipeline/src/operation.rs#L2700), [`core/dr-pipeline/src/operation.rs:2738`](../../core/dr-pipeline/src/operation.rs#L2738), [`core/dr-pipeline/src/operation.rs:580`](../../core/dr-pipeline/src/operation.rs#L580), [`core/dr-pipeline/src/operation.rs:880`](../../core/dr-pipeline/src/operation.rs#L880), [`core/dr-pipeline/src/operation.rs:930`](../../core/dr-pipeline/src/operation.rs#L930), [`core/dr-pipeline/src/ops/camera_profile.rs:393`](../../core/dr-pipeline/src/ops/camera_profile.rs#L393), [`core/dr-pipeline/src/ops/film_sim.rs:315`](../../core/dr-pipeline/src/ops/film_sim.rs#L315), [`core/dr-pipeline/src/ops/view_transform.rs:1`](../../core/dr-pipeline/src/ops/view_transform.rs#L1), [`core/dr-pipeline/src/ops/view_transform.rs:224`](../../core/dr-pipeline/src/ops/view_transform.rs#L224), [`core/dr-pipeline/src/ops/view_transform.rs:36`](../../core/dr-pipeline/src/ops/view_transform.rs#L36), [`core/dr-pipeline/src/view.rs:195`](../../core/dr-pipeline/src/view.rs#L195), [`core/dr-pipeline/src/view.rs:1`](../../core/dr-pipeline/src/view.rs#L1), [`core/dr-pipeline/src/view.rs:208`](../../core/dr-pipeline/src/view.rs#L208), [`core/dr-pipeline/src/view.rs:222`](../../core/dr-pipeline/src/view.rs#L222), [`core/dr-pipeline/src/view.rs:238`](../../core/dr-pipeline/src/view.rs#L238), [`core/dr-pipeline/src/view.rs:254`](../../core/dr-pipeline/src/view.rs#L254), [`core/dr-pipeline/src/view.rs:265`](../../core/dr-pipeline/src/view.rs#L265), [`core/dr-types/src/tone.rs:1`](../../core/dr-types/src/tone.rs#L1) |