fix: restore OpenICE's synthetic grain (§8 dither) - #758
Merged
Conversation
The port dropped ICE's LCG dither on the grounds that the finest detail band already restores real grain. It only does so where the pixel itself survived: under solid dust nothing survives, the reconstruction is an average of intact neighbours, and the repair comes back glassy against the film around it (#732). Grain is back with ICE's own amplitudes and band anchors — those scale with the density being written, so unlike the level constants they transfer between scanners. The uniform draw comes from a hash of the pixel's absolute coordinate rather than the frame-global LCG, which is the algorithm's only serial dependency and would make a banded pass differ from a whole-frame one. ICE's second draw for the never-darken comparison is not reproduced. Measured on samples/scans/20260731_016: high-frequency sigma in the repaired area 0.0027 -> 0.0040, against 0.0035 for the film's own grain.
marcinz606
marked this pull request as ready for review
August 4, 2026 17:16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #732 (the OpenICE half of it).
The port dropped ICE's LCG dither, reasoning that the ℓ=3 detail band already restores real grain. As @a6o pointed out on the issue, that band restores grain from the pixel itself — under solid dust there is nothing left to restore, so the repair is a plain average of intact neighbours and reads as a smooth patch against film.
What changed
env(x) · (u − ½) · α_ch · xin log density,α = (0.015, 0.015, 0.025), parabolic envelope over[D(⌊0.01M⌋), D(⌊0.99M⌋)], no grain unlessx + ditheralso stays in band. ICE's own constants — they scale with the density being written, so unlike the level constants they transfer across scanners.Verification
make allgreen. Measured onsamples/scans/20260731_016, high-frequency σ inside the repaired area: 0.0027 without grain → 0.0040 with, against 0.0035 for the film's own grain nearby.New tests: the dither's envelope, zero mean and band edges; grain reaches a real repair without shifting its level and without touching clean film. Two accuracy tests pin the grain off (the same hook the C reference has as
ice_no_dither), since a random per-pixel write floors how close a repair can land to the clean frame.Docs:
docs/PIPELINE.mdgains it as step 7 of the OpenICE stage;docs/USER_GUIDE.mdnotes it under Method → OpenICE.