The learned demosaic was an option under Detail, off by default. It is now how a Bayer raw is developed: on by default at full strength on every device — which hardware runs it is the inference engine's choice — and first in the Adjust panel, since it decides what every control below is applied to. Strength (0-100, default 100) replaces Keep grain: grain = 100 - strength, the same luminance-only blend, so moving it is one GPU pass and never a re-run. 0.21.0's sidecars stored grain; it is still read, as the inverse, and never written. With it on for every photograph, the result is now kept on disk (denoise.md §7.1, §12): the network's output as half floats, keyed on a SHA-256 of the file's bytes and the model, oldest first past a 5 GB budget, beside the inference engine's cache. A reopened photograph and an export of one already developed read it back instead of running the network again; a damaged entry is a miss.
61 lines
2.5 KiB
Rust
61 lines
2.5 KiB
Rust
//! TRACES: FR-DEV-3g
|
||
//! The learned denoise's settings: whether to use it, and how much grain to
|
||
//! keep.
|
||
//!
|
||
//! Not an [`crate::operation::Operation`]: the learned stage replaces the
|
||
//! demosaic and runs once per photograph, off the render path
|
||
//! (docs/dev/denoise.md §2, §7), and the grain is a blend of its result with
|
||
//! the classical one, done where the source is chosen. But what a
|
||
//! photographer sets travels the one road every setting travels — the
|
||
//! capability list feeds the panel, [`crate::Preset`] captures it, the
|
||
//! sidecar stores it, the undo stack replays it (FR-DEV-3c) — so it is
|
||
//! published as a capability, like the lens profile switch.
|
||
|
||
use std::sync::{Arc, LazyLock};
|
||
|
||
use crate::descriptor::{Attribute, LocalizedKey, OpDescriptor, ParamDescriptor, Scale, Unit};
|
||
use crate::{OpId, ParamId};
|
||
|
||
pub const ID: OpId = OpId("learned_denoise");
|
||
pub const APPLY: ParamId = ParamId("apply");
|
||
/// TRACES: FR-DEV-3g
|
||
/// How strongly to denoise, 0–100: 100 is the network's result as it is, and
|
||
/// lower puts the removed noise's brightness back as grain.
|
||
pub const STRENGTH: ParamId = ParamId("strength");
|
||
/// What 0.21.0 stored instead of [`STRENGTH`]: the grain kept, its inverse.
|
||
/// Still read, so an edit saved by that release keeps its look; never
|
||
/// written, and not offered as a control.
|
||
pub const GRAIN: ParamId = ParamId("grain");
|
||
|
||
/// On by default, at full strength: every Bayer raw is developed from the
|
||
/// learned demosaic, and the switch and the slider are there to take it back
|
||
/// or ease it off. It costs seconds per photograph the first time, while
|
||
/// the classical demosaic shows; the result is cached, so a photograph
|
||
/// reopened or exported does not pay again (docs/dev/denoise.md §7).
|
||
pub(crate) static DESCRIPTOR: LazyLock<Arc<OpDescriptor>> = LazyLock::new(|| {
|
||
Arc::new(OpDescriptor {
|
||
id: ID,
|
||
label: LocalizedKey("op.learned_denoise"),
|
||
params: vec![
|
||
ParamDescriptor::switch_on("apply", "param.learned_denoise.apply"),
|
||
ParamDescriptor::scalar(
|
||
"strength",
|
||
"param.learned_denoise.strength",
|
||
0.0,
|
||
100.0,
|
||
100.0,
|
||
Unit::Percent,
|
||
Scale::Linear,
|
||
0,
|
||
),
|
||
],
|
||
// With the classical noise reduction, which is what a photographer
|
||
// looks for it beside.
|
||
attributes: vec![Attribute::Detail],
|
||
})
|
||
});
|
||
|
||
pub fn descriptor() -> Arc<OpDescriptor> {
|
||
DESCRIPTOR.clone()
|
||
}
|