Sharpen the capture with a separable unsharp mask

Capture sharpening as a two-pass unsharp mask in the detail stage: blur
along x, then along y, each pass applying a one-dimensional high-pass to
luminance so the composite preserves a flat field exactly and matches the
textbook kernel on any locally one-dimensional edge.

The radius is stated in source pixels and converted once per render, so a
radius tuned on a fit view is the radius the exported file gets. Below one
render pixel the operation declines to draw rather than showing sharpening
the file will not contain, and emits a single pass-through that still
carries the output transform.

The develop session now renders through render_detailed, which is what
lets an active neighbourhood operation reach the screen at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 19:13:00 +02:00
co-authored by Claude Opus 5
parent f78c8b6959
commit b321556dbe
3 changed files with 145 additions and 57 deletions
+5 -3
View File
@@ -217,10 +217,12 @@ fn a_proxy_and_an_export_sharpen_the_same_photograph() {
let Some(ctx) = ctx() else { return };
const SOURCE: u32 = 128;
let source = step_edge(&ctx, SOURCE, 90, 150);
// Four source pixels, so that even the half-size proxy has a two-pixel
// sigma and resolves the radius — the honest cut-off is tested in
// The widest radius the slider offers, so that even the half-size proxy
// has a 1.5-pixel sigma and resolves it — the honest cut-off is tested in
// `dr-pipeline`, and this test is about the case where both renders draw.
let graph = sharpened(100.0, 4.0, 0.0);
// Asking for more would be asking for a photograph nobody can produce:
// `EditGraph::set_param` clamps to the descriptor on the way in.
let graph = sharpened(100.0, 3.0, 0.0);
// The halo, measured against the same edit with no sharpening at the same
// size: how far from the transition the picture is still disturbed, as a