The ISP is where a camera stops measuring and starts deciding what the picture should look like. The order in euler-preprocess is fixed and worth memorising, because each stage's effect depends on the space the previous one left behind:
- denoise, on the raw-ish signal;
- colour matrix, sensor primaries to the working primaries;
- tone map, compressing scene range into display range;
- gamma, the sRGB encode;
- local contrast, a large-radius unsharp on the encoded image;
- sharpen, a small-radius unsharp;
- saturation, a lerp toward luma.
Stages 1–3 act on light. Stages 5–7 act on codes, because gamma has already happened. That split is the single most useful thing to know about the chain: a sharpening halo is a fixed fraction of a code value, not of a radiance, so its apparent strength depends on where in the tone curve it landed.
Two nonlinearities, stacked
-
The Reinhard tone map and its slope. Monotone, fixes zero, and asymptotes below 1 — which is what "compressing the highlights" means quantitatively. The shipped profile interpolates a 16-entry LUT instead; Reinhard is the one you can differentiate by hand, and it has the same shape.
-
A difference between two bright surfaces survives at a quarter of its original size, while the same difference in the shadows passes through untouched. Contrast has been moved, not removed.
-
Then the gamma encode, whose slope diverges as y goes to zero — so it expands exactly the shadow region the tone map left alone.
-
The composed response is the product of the two slopes, and the two curves pull in opposite directions. That product is what a histogram of the delivered image is showing you — never the scene.
Saturation closes the chain as a luma-preserving interpolation, with the luminance of the pixel. pulls colours toward grey and pushes them away, in both cases leaving untouched — which is why saturation adjustments do not change a luminance histogram at all.
Two things follow. Pushing above one can send a channel outside on a colour that was in range, and the clip that catches it changes the hue, not just the saturation. And when the scene is already desaturated — fog being the obvious case — an below one compounds with the physical desaturation of the veil, so the delivered image is less colourful than the fog model actually predicted.
A faint texture is clearly present in the render and absent from the delivered image. How do you find the stage that removed it?
Show answer
By asking at what level it vanished. If the texture sits in a bright region, suspect the tone map: its slope there may be a quarter of what it is in the shadows, so a difference that was several code values becomes less than one and the quantiser finishes the job. If it disappears at every level, suspect denoise — a smoothing removes low-amplitude high-frequency content regardless of where it sits. And if it survives in a PNG of the same render but not in the delivered JPEG, it was compression, which throws away high-frequency content per 8×8 block and does so most aggressively in the chroma channels.