Show each denoise method in the manual as a close-up

The manual's AI denoise section names the four methods and their measured
times, and shows the lamp and railing of the ISO 8000 frame at 1:1 by each
in place of the film and the before/after pair. The scene clicks each
method and waits for that network's result: the repair now logs its own
"learned denoise:" line first, so the wait matches the result's.
This commit is contained in:
2026-10-04 08:11:24 -04:00
parent 06422a07db
commit b6ca7be185
10 changed files with 99 additions and 55 deletions
+26 -10
View File
@@ -210,23 +210,39 @@ the sensor recorded.
How every raw is developed. `AI Denoise`, at the top of the Adjust panel,
replaces how the camera's raw data is turned into colour: a network trained
on this library's own photographs removes the noise and the blotches of
colour that come with it, while keeping the fine detail. It is on for every
raw unless you switch it off with `Apply`. Look at it at 1:1, where noise
lives.
colour that come with it, while keeping the fine detail. Look at it at
1:1, where noise lives.
`Method` chooses how:
- `Best`, the default: two networks, one for smooth areas and one for
edges, blended where each is better. The cleanest skies and the sharpest
lettering, and the slowest.
- `Medium`: one network taught by `Best`. Nearly as clean in smooth areas,
a little softer on hard edges, in about a third of the time.
- `Fast`: a smaller one, taught the same way. Visibly noisier at very high
ISO than the other two, but still far cleaner than none, and quick.
- `Bilinear`: the camera's ordinary conversion, noise and all.
The photograph shows the camera's ordinary conversion while the network
works, with its progress in the bar at the top, and changes when it is
done — a few seconds on a computer with a graphics card, about
fifteen on its processor alone, longer on the tablet. The result is kept,
so a photograph opened again, or exported, does not wait a second time.
done — on a laptop's graphics card, about two and a half seconds for a
20-megapixel photograph with `Best` and under one with the other two;
longer on a processor alone or on the tablet. The first photograph after
installing waits a few minutes more while the graphics card prepares each
network, once. The result is kept, so a photograph opened again,
or exported, does not wait a second time, and switching back to a method
already used is quick.
`Strength` eases it off: below 100 % it puts back some of what was removed,
as grain without colour, for a picture that does not look too smooth.
![An ISO 8000 night frame at 1:1, AI Denoise switched on, then some grain kept](media/develop-denoise.gif)
The lamp and railing of a night frame at ISO 8000, at 1:1, by each method:
| Before | After |
| Bilinear | Fast |
|---|---|
| ![The railing and the lamp at ISO 8000, as the camera recorded them](media/develop-denoise-before.png) | ![The same, with AI Denoise](media/develop-denoise-after.png) |
| ![The railing and the lamp at ISO 8000, as the camera recorded them](media/develop-denoise-bilinear.png) | ![The same, with the Fast network](media/develop-denoise-fast.png) |
| **Medium** | **Best** |
| ![The same, with the Medium network](media/develop-denoise-medium.png) | ![The same, with the Best network](media/develop-denoise-best.png) |
It works on raw files from any camera with the usual colour pattern of
red, green and blue squares — not on JPEGs, and not yet on Fujifilm's
@@ -234,7 +250,7 @@ X-Trans. How noisy the camera is at each ISO was measured for the Canon
EOS 6D; for other cameras it is read from a DNG's own figures or
estimated from the photograph, and the finished job in the activity list
says which. An export uses
it whenever the photograph has it switched on.
the method the photograph has.
### Moving between photographs
+26 -10
View File
@@ -292,19 +292,35 @@ the sensor recorded.</p>
<p>How every raw is developed. <code>AI Denoise</code>, at the top of the Adjust panel,
replaces how the camera's raw data is turned into colour: a network trained
on this library's own photographs removes the noise and the blotches of
colour that come with it, while keeping the fine detail. It is on for every
raw unless you switch it off with <code>Apply</code>. Look at it at 1:1, where noise
lives.</p>
colour that come with it, while keeping the fine detail. Look at it at
1:1, where noise lives.</p>
<p><code>Method</code> chooses how:</p>
<ul>
<li><code>Best</code>, the default: two networks, one for smooth areas and one for
edges, blended where each is better. The cleanest skies and the sharpest
lettering, and the slowest.</li>
<li><code>Medium</code>: one network taught by <code>Best</code>. Nearly as clean in smooth areas,
a little softer on hard edges, in about a third of the time.</li>
<li><code>Fast</code>: a smaller one, taught the same way. Visibly noisier at very high
ISO than the other two, but still far cleaner than none, and quick.</li>
<li><code>Bilinear</code>: the camera's ordinary conversion, noise and all.</li>
</ul>
<p>The photograph shows the camera's ordinary conversion while the network
works, with its progress in the bar at the top, and changes when it is
done — a few seconds on a computer with a graphics card, about
fifteen on its processor alone, longer on the tablet. The result is kept,
so a photograph opened again, or exported, does not wait a second time.
done — on a laptop's graphics card, about two and a half seconds for a
20-megapixel photograph with <code>Best</code> and under one with the other two;
longer on a processor alone or on the tablet. The first photograph after
installing waits a few minutes more while the graphics card prepares each
network, once. The result is kept, so a photograph opened again,
or exported, does not wait a second time, and switching back to a method
already used is quick.
<code>Strength</code> eases it off: below 100 % it puts back some of what was removed,
as grain without colour, for a picture that does not look too smooth.</p>
<figure><img loading="lazy" src="media/develop-denoise.gif" alt="An ISO 8000 night frame at 1:1, AI Denoise switched on, then some grain kept"><figcaption>An ISO 8000 night frame at 1:1, AI Denoise switched on, then some grain kept</figcaption></figure>
<table><thead><tr><th>Before</th><th>After</th></tr></thead><tbody>
<tr><td><img src="media/develop-denoise-before.png" alt="The railing and the lamp at ISO 8000, as the camera recorded them" /></td><td><img src="media/develop-denoise-after.png" alt="The same, with AI Denoise" /></td></tr>
<p>The lamp and railing of a night frame at ISO 8000, at 1:1, by each method:</p>
<table><thead><tr><th>Bilinear</th><th>Fast</th></tr></thead><tbody>
<tr><td><img src="media/develop-denoise-bilinear.png" alt="The railing and the lamp at ISO 8000, as the camera recorded them" /></td><td><img src="media/develop-denoise-fast.png" alt="The same, with the Fast network" /></td></tr>
<tr><td><strong>Medium</strong></td><td><strong>Best</strong></td></tr>
<tr><td><img src="media/develop-denoise-medium.png" alt="The same, with the Medium network" /></td><td><img src="media/develop-denoise-best.png" alt="The same, with the Best network" /></td></tr>
</tbody></table>
<p>It works on raw files from any camera with the usual colour pattern of
red, green and blue squares — not on JPEGs, and not yet on Fujifilm's
@@ -312,7 +328,7 @@ X-Trans. How noisy the camera is at each ISO was measured for the Canon
EOS 6D; for other cameras it is read from a DNG's own figures or
estimated from the photograph, and the finished job in the activity list
says which. An export uses
it whenever the photograph has it switched on.</p>
the method the photograph has.</p>
<h3 id="moving-between-photographs">Moving between photographs</h3>
<p>The roll along the foot of the canvas holds the photographs the grid was
showing; click one to open it. The right arrow, <code>D</code> or space opens the next,
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+35 -26
View File
@@ -842,13 +842,21 @@ def develop_zoom():
pause(1.2)
@scene(media=['develop-denoise.gif', 'develop-denoise-before.png', 'develop-denoise-after.png'],
# The methods in the order the scene visits them: `Best` is what the
# photograph opens with, then each smaller network, then none.
DENOISE_METHODS = ['Best', 'Medium', 'Fast', 'Bilinear']
DENOISE_CLOSE_UP = 560 # pixels of canvas, square, around the lamp at 1:1
@scene(media=[f'develop-denoise-{m.lower()}.png' for m in DENOISE_METHODS],
sources=DEVELOP_SRC + ['ui/dr-ui/src/develop/denoise.rs', 'core/dr-denoise/**',
'core/dr-gpu/src/grain.rs', 'models/denoise/**'])
'core/dr-pipeline/src/learned_denoise.rs', 'models/denoise/**'])
def develop_denoise():
"""A night frame at ISO 8000 at 1:1, AI Denoise switched on and landed,
then some grain kept. Waits for the network rather than for a fixed
time: on the CPU it takes several times what it does on a GPU."""
"""The lit lamp and railing of an ISO 8000 night frame at 1:1, once per
AI Denoise method, each cut to the same square of the canvas. Waits for
each network rather than for a fixed time: on the CPU, which the demo
profile uses, Best takes several times what Fast does."""
mark = log_size()
at_develop(DENOISE)
a = dr.photo(0.45, 0.55) # the lit lamp, the railing and the skyline over the water
dr.move(*a)
@@ -857,32 +865,31 @@ def develop_denoise():
pause(1.5)
group('Detail')
in_column('AI Denoise@Text')
shot('develop-denoise-before')
rec('develop-denoise')
pause(0.8)
mark = log_size()
dr.click(*denoise_switch())
t0 = time.time()
while time.time() - t0 < 300 and not denoise_landed(mark):
pause(0.5)
pause(1.5)
shot('develop-denoise-after')
slide('Keep grain', 60)
pause(2.0)
cut()
for method in DENOISE_METHODS:
if method != 'Best':
mark = log_size()
dr.click(*in_column(f'{method}@RadioButton'))
if method != 'Bilinear':
t0 = time.time()
while time.time() - t0 < 600 and not denoise_landed(mark):
pause(0.5)
pause(1.5)
close_up(f'develop-denoise-{method.lower()}', a)
undo_all()
dr.move(*a)
dr.x('click', '--repeat', 2, '--delay', 80, 1)
pause(1.2)
def denoise_switch():
"""The `Apply` box under the AI Denoise heading — the lens profile's
switch is also called Apply, so it is found by where it sits."""
head = dr.matches('AI Denoise@Text', within=column())[0]
below = [e for e in dr.matches('Apply@CheckBox', within=column()) if e['y'] > head['y']]
e = min(below, key=lambda e: e['y'])
return int(e['x'] + e['w'] / 2), int(e['y'] + e['h'] / 2)
def close_up(name, p, size=DENOISE_CLOSE_UP):
"""A square of the canvas centred on `p`, kept inside the canvas."""
shot(name)
x0, y0, x1, y1 = dr.rect('id:canvas-image')
half = size // 2
cx = min(max(p[0], x0 + half), x1 - half)
cy = min(max(p[1], y0 + half), y1 - half)
subprocess.run(['mogrify', '-crop', f'{size}x{size}+{cx - half}+{cy - half}', '+repage',
f'{OUT}/{name}.png'], check=True)
def log_size():
@@ -899,7 +906,9 @@ def denoise_landed(since):
try:
with open(f'{dr.HOME}/app.log', 'rb') as f:
f.seek(since)
return b'learned denoise:' in f.read()
# The result's line, "learned denoise: W×H on …", not the
# repair's, which comes first.
return re.search(rb'learned denoise: \d+\xc3\x97', f.read()) is not None
except OSError:
return False