Two different quantities share the name "pixel value".
Scene-linear radiance is proportional to the number of photons: double the light and you double the number. It is the space every physical process lives in — a lens sums it, a sensor integrates it, fog mixes into it — and the space in which addition means addition.
Display-encoded sRGB is a perceptual code. Eight bits of linear radiance would band visibly in the shadows, where the eye is most sensitive to ratio, so the standard spends its codes unevenly, roughly as . Every PNG, every JPEG, and every image tensor that came from either is in this space unless someone converted it.
The conversion is not a pure power law — it has a linear segment near black, because a power law has infinite slope at zero:
with the code value in and the linear radiance. The srgbToLinear helper in the education geometry module is this function, transliterated from the same common/color.py the training data uses, so a figure and the dataset cannot disagree about what a number means.
What averaging two code values actually computes
-
Average two codes — black and white — the way a resize, a blur or a mean pooling layer would, and decode the answer to see what light it claims.
-
Now average the light instead. Half the photons is the physically correct answer for "half of each", and it is a different number.
-
Encoding the correct answer gives code 188, not 128. The two disagree by 60 code values on the most ordinary operation in image processing.
-
Expressed the way a photographer would: averaging in the encoded space is 1.2 stops too dark. Every edge in a downsized image is darkened by some fraction of that, which is why naively resized images look muddy.
This is why the fog pipeline has a render input space setting at all. When it is set to sRGB the pipeline converts to linear before the fog render, because is a mixture of radiances and mixing encoded codes with those weights is not a mixture of anything. Fog composited in the encoded space comes out too light in the shadows and too contrasty in the midtones — it reads as a grey wash laid over the picture, which is exactly the look people mean when they say augmented fog looks fake.
Then the sensor stage converts again, because the camera it models is looking at scene radiance, not at a display. So a sample can make the round trip twice before anything trains on it, and each 8-bit leg of that trip quantises.
You composite a fog veil at 50 % opacity onto an 8-bit sRGB image and it looks thin in the shadows and heavy in the midtones. What is wrong?
Show answer
The blend is being done on codes, not on light. A blend toward the airlight is a statement about radiance; performed on the encoded values it applies a much larger fraction of the veil to the midtones — where the curve is shallow — and a much smaller one to the shadows, where it is steep. The fix is one decode and one encode around the composite, and the visible effect is that the fog stops looking like a layer and starts looking like distance.