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:
+35
-26
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user