Skip to content

fix(exposure): scale the luma window's reach by each channel's own range - #1366

Closed
seanharding wants to merge 1 commit into
marcinz606:mainfrom
seanharding:fix/bounds-unequal-channel-ranges
Closed

seanharding wants to merge 1 commit into
marcinz606:mainfrom
seanharding:fix/bounds-unequal-channel-ranges

Conversation

@seanharding

Copy link
Copy Markdown
Contributor

Problem

The bounds analysis widened every channel's color refs to the luma window by the same amount in log units. On a negative whose channels differ in density range, that reach is a different fraction of each channel's span, so a gray scale normalizes to a different value in each channel and the print takes a cast.

A faded 126 color negative showed it once Sensor Correction was on. Unmixed, its green density range is about 3.5 times blue's (0.67 against 0.19 log), and the frame rendered yellow-green. With the unmix off, the sensor crosstalk blends the channels and hides the difference, so the profile looked like the cause. It is not: the matrix is close to a bare-light one, and all three unmix modes gave the same cast.

Note: I think this warrants some testing by other people on their own frames to confirm that it doesn't introduce any unexpected problems.

Change

analyze_log_exposure_bounds_from_log now expresses the luma window's reach past the color refs as a fraction of each channel's own span, averaged over the channels. Both engines call this one function, so there is no shader change.

The window keeps its mean-minus-median base offset, so a frame with exactly equal channel ranges gets the same bounds as before, and the tone-reproduction test numbers do not move. A channel with no span falls back to the previous formula.

Effect on other frames

Real film never has exactly equal channel ranges, so most frames shift a little when their bounds are next measured. I rendered 59 saved color-negative frames with the old and new bounds (CPU path, 420 px, roll averages off):

  • No frame took a cast or broke.
  • Median mean-absolute change is about 4 levels out of 255, mostly brightness; many frames move 5 to 10.
  • Frames with a range ratio near 2.8 move 16 to 20 levels and render darker.
  • On two color chart frames, the mean channel spread over the six gray patches fell from about 5.5 to 4.3 levels. The mid-grays improved most; the white patch got slightly warmer.

Saved edits keep their stored bounds and do not change until a frame is re-analyzed.

Not changed

mix_luma_color_bounds (Roll Analysis luma and color averages) still shifts all channels by the same log amount, so a roll of this kind can show a milder version of the cast with those averages on.

Tests and housekeeping

  • New: test_unequal_channel_ranges_keep_a_gray_scale_neutral; it fails without the fix.
  • tests/test_same_pixel_bounds.py: the helper mirrors the new recombination, and the thin-end test's tolerance goes from 1e-9 to 5e-3, because the ceiling now depends on the span.
  • THUMBNAIL_RENDER_VERSION 3 → 4. Recording its golden also picked up the autocrop_square and autocrop_squared defaults it was missing.
  • docs/PIPELINE.md describes the new formula.
  • Checked in the desktop app on the 126 frame with the profile on and off.

The bounds analysis widened every channel's color refs to the luma window
by the same amount in log units. On a negative whose channels differ in
density range, that reach is a different fraction of each channel's span,
so a gray scale normalizes to a different value per channel.

A faded 126 negative showed it once the sensor unmix was on: unmixed, its
green range is about 3.5 times blue's (0.67 against 0.19 log), and the
frame rendered yellow-green. With the unmix off, the crosstalk blends the
channels and hides the difference.

The reach is now a fraction of each channel's span between its color refs,
averaged over the channels. The window keeps its mean-minus-median base
offset, so the tone-reproduction numbers do not move. Real frames, whose
channel ranges are never exactly equal, shift by a few levels out of 255
when their bounds are next measured; saved edits keep their stored bounds.

Bumps THUMBNAIL_RENDER_VERSION; recording its golden also picked up the
autocrop_square and autocrop_squared defaults it was missing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants