BookNotesSlidesP-sets Syllabusdraft · v0.2.49.1
◀▲⌂▶
💬Comments welcome. To leave a note, select any text and click the note / highlight button that pops up — or open the panel with the tab at the top-right (‹). Notes are visible only inside our private review group.
💡 In a hurry? Jump to this chapter’s 11 big lessons ↓

2.8 Noise, signal-to-noise ratio and dynamic range⧉

Noise earns a chapter of its own because, more than resolution or optics, noise is what ultimately limits our ability to measure and reconstruct an image. Almost everything else in this book (denoising, demosaicking, deblurring, HDR merging, depth from stereo, super-resolution) is at bottom an attempt to recover a clean signal from noisy measurements, and their performance is limited by how much noise corrupts the input. So understanding where noise comes from, how it scales with light, and which kind dominates when is not a side topic: it is the quiet constraint behind the whole field. It tells you what is recoverable and what is lost for good, how many photons or frames you need to reach a target quality, and, when a result disappoints, whether you are limited by your algorithm or by the physics of the measurement itself. Read this chapter as the floor under every later one.

2.8.1 Noise sources⧉

Counting photons is what makes a sensor linear, but counting is also where noise comes from. Take two photos of the same still scene at the same settings and they are not byte-for-byte identical; each pixel value jitters from frame to frame. Several physical sources contribute, and when their fluctuations are independent, their variances add, so to combine them we add variances ($\sigma^2$), not standard deviations (Figure 2.8.3).

💡 Big lesson (L2.37) — variance is the mathematically meaningful quantity; standard deviation is the human-readable one

Two numbers describe noise spread, and both exist for a reason. Variance (the mean squared deviation) is the quantity the mathematics wants: it is additive for independent sources, exactly what we just used, and the basis of the $1/\sqrt N$ averaging law in Part 13, Denoising; it is the second moment that falls out of every Gaussian and least-squares derivation, and it composes cleanly under linear operations. But its units are squared (squared gray-levels, squared photons), so it means nothing to the eye. The standard deviation $\sigma$ (its square root) is the one people should read: it is back in the original units, directly comparable to the signal: the "$\sigma$" of error bars and the grain you actually see. Rule of thumb: derive and combine in variance, report in standard deviation.

Photon (shot) noise is the deepest source, and it is not a defect of the sensor: it is the light itself. Light arrives as discrete photons at random times, so the count in a fixed interval fluctuates even from a perfectly steady source. For ordinary photographic illumination, the count is well modeled as Poisson, and the defining property of a Poisson process is that its variance equals its mean (Hasinoff 2012 is the canonical short reference). So if a pixel collects $N$ photons on average, the variance of the count is $N$ and the standard deviation is

$$ \sigma = \sqrt{N}. $$

This is irreducible: no better sensor can remove it, because it is a property of light, not of electronics. It dominates the midtones and highlights, where $N$ is large. Collecting more light, increasing detection efficiency, or pooling independent measurements improves the signal-to-noise ratio. For example, average $N_f$ independent frames of the same scene and the shot noise drops by $\sqrt{N_f}$: the statistical basis of burst denoising and astrophotography stacking.

💡 Big lesson (L2.38) — noise is fundamental: photon shot noise sets the floor

Even a flawless sensor is noisy, because light itself is grainy: photons arrive as discrete, randomly-timed events, so the count in any fixed interval follows Poisson statistics ($\sigma=\sqrt N$), and no electronics can remove it: the randomness is in the light, not the chip. The only true cure is collecting more photons: a bigger pixel, a wider aperture, a longer exposure, or averaging many frames. Raising ISO is not a cure: it is gain applied after capture, amplifying signal and shot noise together. This irreducible floor is why bigger sensors win, why shadows are noisy, and what every denoiser later in the book is ultimately fighting.

fig-poisson-noise
Figure 2.8.1. Photon shot noise, live and interactive. Photons rain from above into $K$ groups of $n$ buckets (pixels), both sliders. Each group fills at its own flux, chosen so its expected count is simple ($10, 100, 1000$ by default; a ratio slider spreads them around the middle), and the $n$ buckets in a group share that expectation, so their spread is exactly the shot noise at that level. Each exposure runs for the shutter time (1 s by default) and then we count. Because photon arrivals are independent and random the counts are Poisson, so the running mean and variance under each group stay nearly equal. Every exposure adds $K$ points to the upper plot, where you can read the spread as variance (climbing the line variance = mean), standard deviation, or SNR (both tracking $\sqrt N$); the lower plot scatters all $N\times K$ buckets, expected count vs. what each actually caught, so the cloud around $y=x$ visibly widens with brightness in absolute terms yet tightens in relative terms. It makes the defining fact of shot noise, $\sigma=\sqrt N$, something you watch happen. Log axes; no well saturation; reset clears the accumulated points.

The remaining sources are added by the hardware:

💡 Big lesson (L2.39) — know the noise sources, and when each one dominates

Sensor noise is a sum of distinct sources whose variances add, but each rules a different regime, so diagnosing a noisy image means asking which one you are seeing. Photon shot noise ($\propto\sqrt{\text{signal}}$) dominates the midtones and highlights, and any well-lit shot. Read noise is signal-independent and dominates the deep shadows and short exposures, setting the floor. Thermal / dark-current noise grows with exposure time and temperature: the long-exposure and astrophotography enemy. Quantization matters only with too few bits L2.47. And fixed-pattern noise / PRNU (static per-pixel gain and offset variation) reads as a structured pattern and is removed by calibration (dark and flat fields). Match the symptom to the source before reaching for a fix.

The same five sources, as a reference table (what each varies with, where it dominates, and whether you can remove it):

sourcewhat it isvaries withdominant regimeremovable?
photon (shot) noisePoisson statistics of photon arrival$\sigma=\sqrt{N}$, grows as √(signal)midtones & highlights; every well-lit shotno (fundamental: only more light helps)
read noiseamplifier + ADC at read-outconstant per read-out; relatively lower at higher analog ISOdeep shadows, short exposures (sets the floor)no, but minimized; charge-binning pays it once
dark-current (thermal)electrons freed by heatexposure time × temperature (≈ doubles per ~6–8 °C)long exposures, hot sensors, astropartly: cooling + dark-frame subtraction
quantizationfinite ADC bit depthnumber of bits (negligible with enough)only with too few bits / a heavy pushmore bits at capture reduce it; dithering decorrelates the error but cannot recover lost precision
fixed-pattern / PRNUper-pixel gain & offset variation, hot pixelsstatic (same each frame); gain part scales with signalstructured pattern, visible in flats/darksyes: flat- & dark-field calibration
fig-cooled-camera
Figure 2.8.2. A dedicated cooled astrophotography camera (ZWO ASI2600MC Pro). Front: the bare sensor (no cover glass), the same as in regular mirrorless cameras (the APS-C Sony IMX571: 26 MP, 6248 × 4176 at a 3.76 µm pixel pitch, 23.5 × 15.7 mm). Back: a finned heatsink and fan dump the heat that a thermoelectric (Peltier) cooler pumps off the sensor, powered by a dedicated 12 V line. Run at a regulated set-point tens of degrees below ambient, the cooler drives dark current down (it roughly halves per ~6–8 °C), so long deep-sky exposures stay clean and a library of dark frames stays repeatable. Photographs by Frédo Durand.
fig-noise-histogram
Figure 2.8.3. Noise at two ISO settings, measured on the green photosites of two camera originals at the same mean level, 0.19 of full scale: a clear sky at ISO 100 and a white door frame at ISO 3200. Each flat patch is enlarged beside its histogram: a spread, not a spike, and about five times wider at ISO 3200. The spread is the sum of independent sources whose variances add: photon/shot noise (Poisson, $\sigma = \sqrt{N}$, dominates midtones and highlights), read noise (signal-independent, dominates shadows, sets the floor), thermal/dark current (grows with time and heat), and structured fixed-pattern noise (removed by calibration).

We can see that noise directly. Shoot a burst of one static scene at high ISO and take, for every pixel, its variance across the frames: the result is a map of the noise itself, laid over the picture (Figure 2.8.4). The noise is not uniform: it is heavier in the brighter regions (shot noise) with the brightness dependence predicted by shot noise. Extra variance along edges can instead reveal camera motion, imperfect registration, or illumination changes; these must be excluded when measuring sensor noise.

fig-noise-variance-map
Figure 2.8.4. The noise of a real high-ISO image, and its SNR. From a 50-frame ISO-3200 burst of one static scene: the scene itself (left, mean of the burst), the per-pixel variance across the burst (middle), and the per-pixel SNR = signal/noise (right). Computed on linearized values, so shot noise behaves physically. The variance map is brightest where the scene is bright (absolute noise grows with signal), while the SNR map is also brightest in the bright areas and worst in the shadows, because noise only grows as √signal so the ratio improves with light. Bright pixels are noisier in absolute terms yet cleaner in relative terms. This is the raw material the affine model below summarizes.

2.8.2 The algebra of noise⧉

For independent sources, variances add: the single most useful fact for reasoning about noise, and worth turning into a tool. For $N$ independent measurements each of variance $\sigma^2$, the sum has variance $N\sigma^2$ (standard deviation $\sqrt N\,\sigma$), while the average has variance $\sigma^2/N$ (standard deviation $\sigma/\sqrt N$). That $1/\sqrt N$ is the engine of all averaging-based denoising (a whole chapter later). More generally, $\operatorname{Var}(\sum_i w_iX_i)=\sum_i w_i^2\operatorname{Var}(X_i)+2\sum_{i<j}w_iw_j\operatorname{Cov}(X_i,X_j)$. Shared banding and fixed patterns therefore do not follow the independent-frame averaging law. The same algebra settles a subtler, very practical question: is it better to measure light with one big pixel, or with several small ones and add them up?

For this comparison, assume the same quantum efficiency and the same read-noise variance per read, and count detected photoelectrons as $N$. Take a patch that collects $N$ of them. Capture it with one big pixel: it counts $N$ photons (shot variance $N$, since Poisson variance $=$ mean) and adds the read noise once, $\sigma_r^2$. Now split the same patch into four small pixels, each catching $N/4$ photons. Summing their four readings recovers the signal $N$, and the shot noise is identical: the four shot variances $N/4$ add back to $N$, exactly the big pixel's. But each small pixel contributes its own read noise, so the sum carries $4\sigma_r^2$: the read noise is paid four times over. So, provided no light is lost in the gaps between photosites, the big pixel's only real advantage is read noise, not shot noise. Shot noise depends solely on how many photons you caught, never on how you diced up the sensor; read noise is charged once per read-out.

This is exactly why binning matters, and why how you bin matters. Charge binning (pooling the pixels' charge in the analog domain before it reaches the amplifier and ADC) reads the combined charge once, paying read noise a single time and recovering the full big-pixel advantage; some sensors provide this operation, while others combine after separate reads. A quad-Bayer color-filter layout alone does not establish which operation is used. Digital binning (reading the four pixels separately and adding the numbers afterward) pays read noise four times and captures only the shot-noise equivalence. The gap is invisible in bright light (shot-noise-dominated) and decisive in the dark (read-noise-dominated). It also previews the affine model $\sigma^2 = g\,I + \sigma_r^2$ (developed shortly) from a new angle: aggregating $k$ measurements multiplies the read-noise term's contribution by $k$ unless you combine before read-out.

💡 Big lesson (L2.40) — aggregating measurements keeps the shot noise but multiplies the read noise

Add the readings of $k$ small pixels and you get the same Poisson (shot) noise as one big super-pixel that caught the same photons, but you pay the read noise $k$ times, once per read-out, instead of once. So the only fundamental advantage of a bigger pixel (or one longer exposure) over many smaller ones is the read noise, not the photon statistics, as long as no light is lost in the gaps. The same holds for aggregating along any dimension: summing $k$ short exposures, or $k$ burst frames, keeps the shot noise of the total light but charges read noise $k$ times. This is precisely why charge-domain binning (combine, then read once) beats digital summation (read $k$ times, then add) in the dark.

Video 2.8.1. Video: Why X + Y in probability is a beautiful mess (convolutions), by 3Blue1Brown (YouTube).

2.8.3 Signal-to-noise ratio: it's about ratios⧉

A counterintuitive fact ties the whole part together. Since shot noise is $\sigma = \sqrt{N}$, the absolute noise is actually larger in the bright parts of the image than in the dark parts: a highlight collecting 10,000 photons has $\sigma = 100$, while a shadow collecting 100 photons has only $\sigma = 10$. And yet noise looks worst in the shadows. The resolution is that noise visibility depends strongly on its size relative to the local signal, as well as on display brightness, spatial frequency, and image content. Signal-to-noise ratio (SNR) captures the first of these effects. For shot noise,

$$ \mathrm{SNR} = \frac{N}{\sqrt{N}} = \sqrt{N}. $$

The SNR grows with brightness, so it is worst where the light is faintest (the shadows) even though the raw noise magnitude is smallest there (Figure 2.8.6). This emphasis on ratios also motivates gamma and log encoding (log encoding gives equal steps to equal ratios, while a power-law gamma curve approximates perceptual spacing over a useful range) and exactly why exposing to the right works: collecting more photons everywhere, especially in the shadows, raises $N$ and therefore raises the SNR where it is worst.

One caution before we go on, because the acronyms collide: SNR is not PSNR. The signal-to-noise ratio here is a property of a capture, the true signal at a pixel relative to the sensor's noise there ($\sqrt N$ for shot noise), and it answers how clean is this measurement? Peak signal-to-noise ratio (PSNR), which you meet whenever an algorithm is evaluated, is a different animal: a full-reference quality metric that compares a processed image $\hat I$ against a ground-truth reference $I$, computed from their mean-squared error as

$$ \mathrm{PSNR} = 10\log_{10}\!\frac{\mathrm{peak}^2}{\mathrm{MSE}}\quad\text{(dB)}, $$

where $\mathrm{peak}$ is the largest possible value (e.g. often 1.0 for us when using floating point values, or 255 for 8-bit) and $\mathrm{MSE}=\tfrac1n\sum(\hat I-I)^2$. So SNR describes a photograph (how much noise a single measurement carries, with no reference needed), while PSNR scores a reconstruction against a known truth (how close a denoiser or codec got). Both compare a signal scale to an error scale, but their numerators and purposes differ. PSNR uses a fixed peak rather than the local signal. Maximizing expected PSNR through minimizing MSE favors a conditional-mean estimate, which can blur uncertain detail; that makes it useful for some comparisons but incomplete as a perceptual score.

A word on the decibel itself, since it recurs through this chapter and the next. A decibel is just a logarithmic way to write a ratio: for a power (or energy, intensity, variance) ratio it is $10\log_{10}$, and for an amplitude (or voltage, signal) ratio it is $20\log_{10}$, the factor of two coming from power $\propto$ amplitude$^2$. Photographers count the same ratios in stops, factors of two ($\log_2$), so one stop is about 6 dB of amplitude or 3 dB of power. Decibels, stops, plain linear ratios, and scientific notation are thus four scales for the same underlying number, a multiplicative factor, and it helps to move fluently between them (Figure 2.8.5).

fig-db-calculator
Figure 2.8.5. A units converter for ratios (interactive). Decibels, photographic stops (log₂), a plain linear ratio, and scientific notation are four ways of writing one multiplicative factor. Type into any field, or drag the log-progression slider, and the others update to match; a toggle switches the decibel convention between amplitude ($20\log_{10}$, about 6 dB per stop, the convention sensor datasheets use for dynamic range) and power or energy ($10\log_{10}$, about 3 dB per stop, for ratios of intensities or variances). Preset chips jump to the common landmarks: one stop, ten-fold, a million-to-one, a full-frame sensor's roughly fourteen stops.
💡 Big lesson (L2.41) — bright pixels are noisier (more absolute noise) but have better SNR

Shot noise is Poisson, so its variance grows linearly with the signal ($\sigma^2 \propto N$) and its standard deviation grows only as the square root ($\sigma \propto \sqrt{N}$). Two consequences pull in opposite directions: the absolute noise is larger in highlights than in shadows (a 10,000-photon highlight has $\sigma=100$; a 100-photon shadow has $\sigma=10$), yet the SNR $= N/\sqrt{N} = \sqrt{N}$ is higher in the highlights: the signal outgrows the noise. So bright areas are noisier in absolute terms but cleaner to the eye; the shadows have the worst SNR (Figure 2.8.4, Figure 2.8.6). This is why exposing to the right and brighter scenes look smoother, and why we gamma/log-encode so equal ratios get equal steps.

fig-snr-vs-stddev
Figure 2.8.6. Noise is numerically worse in highlights but looks worse in shadows. Three panels of the same brightness ramp, each labeled so the good direction is unambiguous. A standard-deviation map (absolute noise, higher = worse) is brightest in the highlights, since shot noise $\sigma = \sqrt{N}$ grows with brightness; an SNR map ($=\sqrt{N}$, higher = better) is worst in the shadows, since the ratio falls where photons are few; and a noise-only panel shows a single frame's residual, the measurement minus its expected value, on a diverging colormap (blue for negative excursions, red for positive, white at zero) so both signs read at once, the residual staying near zero-mean everywhere yet visibly growing in amplitude toward the highlights. Perception tracks the ratio, so shadows look noisiest, the reason for exposing-to-the-right and for gamma/log encoding. All three maps are computed in linear light and gamma-encoded only for display, so the noise magnitudes shown are faithful.

The affine model, whose full story is the next section, settles a lot of everyday "will this help my noise?" questions at a glance. Read each move against $\sigma^2 = g\,I + \sigma_r^2$ (signal $I$, photon-gain slope $g$, read-noise floor $\sigma_r$), tracking what happens to the signal, the noise $\sigma$, and their ratio. The entries below are for the shot-noise-dominated regime (well-lit midtones); the read-noise term $\sigma_r$ changes only the two rows that mention it.

scenariosignalnoise $\sigma$SNRwhat is really going on
raise ISO by 1 stop (×2 analog gain)×2×2≈ sameamplifies signal and noise together and adds no photons. Read noise, applied after the gain, shrinks relative to the signal, so deep shadows come out a touch cleaner. Not a substitute for light.
brighten by 1 EV in software (×2)×2×2unchangedmultiplies values already recorded, so it amplifies the noise baked in at capture. No shadow benefit, unlike raising ISO at capture.
darken by 1 EV in software (×½)×½×½unchangedpure scaling; the ratio is untouched (though it can still clip or quantize).
average $N$ frames×1÷$\sqrt N$×$\sqrt N$independent noise partly cancels while the signal stays: the $1/\sqrt N$ law behind burst denoising and stacking.
sum $N$ values×$N$×$\sqrt N$×$\sqrt N$variances add, so SNR grows just like averaging; but read noise is paid $N$ times if the values are read separately.
charge-bin $N$ pixels (combine, then read once)×$N$×$\sqrt N$×$\sqrt N$, cleaner shadowssame shot noise as a digital sum, but read noise is paid once, not $N$ times. Check that the sensor actually combines charge before separate readout.
gather 2× the light (wider aperture or longer exposure)×2×$\sqrt 2$×$\sqrt 2$collects more photons per measurement, improving SNR before any reconstruction. Read noise unchanged.

Software rescaling preserves SNR. Analog gain can reduce the relative contribution of noise added downstream, as the ISO section explains. Combining $N$ equally exposed independent measurements improves SNR as $\sqrt N$, while more photons per measurement improve the capture itself.

2.8.4 Noise variance is mostly affine in pixel brightness⧉

Because the variances of these sources add, and because the dominant two scale so simply with the signal, the whole noise level follows a strikingly simple rule that we can measure directly from data.

💡 Big lesson (L2.42) — in a linear image, noise variance is mostly an affine function of brightness (ignoring clipping).

The variances add, and two terms dominate: shot noise contributes an amount proportional to the signal (Poisson, variance = mean, scaled by the gain) and read noise a constant floor. So the total is variance ≈ gain·signal + read², a straight line in brightness (Figure 2.8.7). The slope is the photon gain (it steepens with ISO, which amplifies the signal and its shot noise together); the intercept is the read-noise floor. We can measure it without any model: take an aligned burst of a static scene and, per pixel, plot the variance across frames against the mean. This affine law is a statement about the variance and is essentially exact for the two dominant sources; it says nothing yet about the shape of the distribution. Where the electron count is large, a single pixel's value over many frames does look ≈ Gaussian (Figure 2.8.8), which licenses modeling per-pixel noise as additive Gaussian in the midtones and highlights. That bell is only an approximation, though: the shot term is really Poisson (variance = mean, but discrete, skewed, and non-negative), and in the deep shadows, where only a handful of electrons land, it stops looking Gaussian at all. The additive-Gaussian model is a convenience of the well-exposed regime, not a law of noise in general (we pin down where it breaks below).

fig-noise-affine
Figure 2.8.7. Noise variance is affine in brightness, measured. From a 50-frame burst of one static scene at ISO 3200, the per-pixel variance plotted against the per-pixel mean (in the linearized domain, on flat patches so mis-alignment doesn't masquerade as noise) traces a straight line: a constant read-noise floor (intercept) plus a shot-noise term proportional to the signal (slope = gain), $\sigma^2 \approx a\,I + b$. Toward the bright end the camera's highlight roll-off and clipping pull the measured variance below the line: the truncation taken up next. Raising the ISO amplifies the signal and its noise together by multiplying the gain: the fitted slope at ISO 3200 is about 7× that at ISO 400, close to the 8× ISO ratio.
fig-noise-gaussian-pixels
Figure 2.8.8. A single pixel, over many frames, is ≈ Gaussian. Histograms of a few flat pixels' values across the 50 frames, at increasing brightness, each with a fitted Gaussian: at these brightnesses the spread is well described by a normal distribution (the many-photon limit of the Poisson count plus Gaussian read noise). This is the empirical basis for the additive-Gaussian noise model used throughout denoising, in the bright regime; down in the deep shadows the underlying Poisson statistics show through and the bell breaks (see below).

Read the affine model the other way and it becomes a simplified noise simulator: the quickest way to turn a clean image into realistic noisy data, for stress-testing a denoiser or building the synthetic training pairs this book leans on (Chapter 7.3, Deep learning). Two rules make or break it. First, work on a linear image, never a gamma-encoded one: variance is affine in brightness only in linear light, so noise added after the tone curve injects the wrong amount in the shadows, exactly where it shows, and looks plainly fake. Second, and less often stated, do the physics in the sensor's native unit, electrons (photon counts), because that is the only unit in which shot noise is exactly Poisson. So convert the linear image to a mean electron count, draw the shot term as a Poisson variate and the read term as a Gaussian, then carry the result back out through gain, black level, clipping, and quantization (Algorithm 2.8.1):

Algorithm 2.8.1
for each linear pixel value I in [0, 1]:      # 1.0 == a full photosite well; NOT gamma-encoded
    N_e   = I * full_well                     # to ELECTRONS: the photon scale
    shot  = poisson(mean = N_e)               # shot noise IS a Poisson count  (var = mean, sigma = sqrt(N))
    shot  = min(shot, full_well)              # clip 1: the well saturates (electrons), BEFORE read-out
    e     = shot + gaussian(0, read_noise_e)  # read/constant noise: zero-mean Gaussian, in electrons
    DN    = round(e * gain + black_level)      # to code values: gain folds in ISO; add the pedestal
    DN    = clamp(DN, 0, max_DN)              # clip 2: the ADC rails (highlights at max, floor at 0)
    I_out = (DN - black_level) / (max_DN - black_level)   # linear; may be negative after black subtraction
# apply gamma / the display curve only AFTER this loop, never before

2.8.5 A fuller model of noise: Poisson photon noise plus clipping plus Gaussian electronic noise plus a second clipping⧉

The affine variance model is often paired with a fast distributional approximation: a symmetric Gaussian whose variance rides the affine line $\sigma^2=a\,I+b$. To see exactly where that approximation holds and where it breaks, and to simulate noise faithfully down in the shadows and up at saturation, we now build the full generative model it approximates. It has four stages, applied in the order the sensor applies them: Poisson photon noise, the well's saturation clip, additive Gaussian read noise, and the ADC's second clip. Working in electrons keeps the scales consistent. This remains a model: real read noise can be correlated or non-Gaussian, and real saturation need not be a perfect hard clip. The affine Gaussian follows away from clipping when counts are sufficiently large.

The units are everything. Three of them coexist, and you must keep them straight. The scene-linear image is normalized, values in $[0,1]$ with $1.0$ standing for a full well. The sensor counts in electrons (photons converted at the quantum efficiency $\eta$), and this is where shot noise lives: a mean of $N$ electrons gives a Poisson count whose variance is $N$, so $\sigma=\sqrt N$. The ADC finally reports digital numbers (DN, or ADU: the raw code values), related to electrons by a gain $g$ in DN per electron, into which the ISO setting folds. The one non-negotiable step is the conversion $N=I\cdot N_{\text{full}}$ before the Poisson draw: "variance equals mean" holds only for the count, so drawing Poisson in normalized $[0,1]$ or in DN gets the noise magnitude wrong by whatever the scale factor is. Multiply the clean image up into electrons, add the noise there, and only then scale back. Typical numbers: a full-frame photosite holds $N_{\text{full}}\approx30{,}000$-$60{,}000$ electrons, a phone pixel a few thousand; read noise $\sigma_r$ is $\sim1$-$3\,e^-$ on good CMOS when measured in input-referred electrons, and often falls as analog gain rises until a floor is reached. Pixel design and readout mode matter as much as sensor format.

In electrons the linear (shot) term is not a fitted constant, it is pure physics. Write the normalized linear measurement as $x\in[0,1]$, a fraction of full well. The mean electron count is

$$ N(x) \;=\; x\,N_{\text{full}}, $$

with $N_{\text{full}}$ the full-well capacity, the electrons a photosite holds at saturation. Shot noise is Poisson, so its variance in electrons equals that mean:

$$ \operatorname{Var}_{\text{shot}}(x) \;=\; N(x) \;=\; N_{\text{full}}\;x \qquad [\text{electrons}^2]. $$

That is the whole "linear term $a\,x$": a straight line through the origin whose slope is simply the well capacity, with nothing to tune. And the slope is set entirely by physics, by how many photons the exposure delivers and the quantum efficiency $\eta$ that converts them to electrons ($N=\eta\,N_{\text{photons}}$, so $N_{\text{full}}=\eta\,N_{\text{photons at saturation}}$). The normalized slope $a$ of L2.42 looks like a fitted number only because of the change of units: rescaling those electrons back into $[0,1]$ (divide by $N_{\text{full}}$) or into DN (multiply by the gain) turns the clean $N_{\text{full}}\,x$ into $a\,x$. In electrons it is just the photon count.

The affine Gaussian of L2.42 replaces the Poisson draw by a Gaussian with matching mean and variance. The coefficients depend on the units of both the signal and the noise. If the output is divided by full well, then, away from clipping and ignoring quantization,

$$ \operatorname{Var}(y\mid x)=\frac{x}{N_{\text{full}}}+\frac{\sigma_r^2}{N_{\text{full}}^2},\qquad a=\frac{1}{N_{\text{full}}},\quad b=\frac{\sigma_r^2}{N_{\text{full}}^2}. $$

For example, $N_{\text{full}}=30{,}000$ and $\sigma_r=2$ give $a=3.33\times10^{-5}$ and $b=4.44\times10^{-9}$. A smaller illustrative well of $3{,}000$ electrons with the same read noise gives $a=3.33\times10^{-4}$ and $b=4.44\times10^{-7}$. These are calculated examples, not specifications for a camera class. In black-subtracted DN, with mean $\mu=gN$, the variance is instead $g\mu+g^2\sigma_r^2$. If those DN are normalized by a code range $A$, the coefficients become $a=g/A$ and $b=g^2\sigma_r^2/A^2$. A noise profile is meaningless without this normalization convention.

When is that Gaussian good enough, and when does it break? A Poisson count is a sum of many independent tiny arrivals, so by the central limit theorem it approaches a Gaussian of the same mean and variance as the count grows: $\text{Poisson}(N)\approx\mathcal N(N,\,N)$. Its skewness is $1/\sqrt N$, so the bell is nearly symmetric once $N$ is a few dozen, and in midtones and highlights (thousands of electrons) the Gaussian is indistinguishable from the truth and cheaper to draw. It breaks in exactly the place that matters, the deep shadows, where $N$ falls to single digits. Three things go wrong at low counts: the distribution is discrete (you caught 3 photons or 4, never 3.5), it is right-skewed (a tail toward more photons, none toward fewer), and it is non-negative, whereas a Gaussian will hand back negative electron counts, which are unphysical and, once clipped at zero, bias the shadows bright (the truncation of L2.43 below). Rule of thumb: use the true Poisson draw below a couple of dozen electrons and the Gaussian above; a simulator that wants faithful shadows, or that models the low-light or photon-counting regime at all, must use Poisson. A Gaussian approximation can be faster, but the benefit depends on the sampler and hardware, and a threshold near $N\approx20$ still introduces approximation error. Test the distribution and runtime for the application; an exact Poisson sampler is a straightforward default.

How far from zero-mean is the noise? We lean everywhere on the assumption that noise averages out: that a measurement is right on average even when any single frame is off, since that is exactly what lets a burst average or a denoiser recover the truth. How well does that hold? Two of the effects just discussed pull in opposite directions. For shot noise alone the answer is: it is unbiased, exactly. A Poisson count satisfies $\mathbb{E}[\text{Poisson}(N)] = N$, so despite its right skew the expectation sits precisely on the true signal, and averaging many frames converges to it with no offset. The asymmetry is a fact about the shape of a single draw, not a bias in its mean; this is why a simple frame average is still the right estimator in the shadows even where the distribution is visibly lopsided. Clipping is what actually breaks zero-mean. At the black rail the recorded value cannot go below zero, so the negative half of the read noise is chopped off and the average is pushed up: for a signal sitting right on the floor with read-noise $\sigma_r$, the lift is about $\sigma_r/\sqrt{2\pi}\approx 0.4\,\sigma_r$ (a few tenths of an electron), decaying to nothing once the signal climbs a couple of $\sigma_r$ above zero. At the white rail the mirror image drags saturating highlights down. So the noise is zero-mean across the whole midtone range and departs from it near a rail, within a distance set by the noise standard deviation rather than a fixed number of exposure stops (the truncation of L2.43 below). That residual bias is small in electrons but lands where the eye is most critical, which is precisely why sensors add a black-level pedestal: lifting the signal a few hundred codes off zero keeps nearly all of the read-noise distribution measurable at black and makes clipping bias negligible. The pedestal is an offset in the recorded signal, described by metadata: the file must say how much was added, and every reader must subtract it before the numbers mean light. A file that misreports it renders as milk, with no reachable black and a cast the color of whichever channel's pedestal was largest; Chapter 8.2, What the numbers mean dissects a real case from this book's own raw developer, with the two renders side by side.

The model in one place. All the pieces now assemble into a single forward model whose operations happen in a definite order that a careless simulator scrambles. With $x\in[0,1]$ the normalized linear signal, $N_{\text{full}}$ the well capacity, $\sigma_r$ the read noise in electrons, $g$ the gain in DN per electron, $B$ the black-level pedestal, and $\mathrm{DN}_{\max}$ the ADC ceiling, the recorded value is built up as

$$ \begin{aligned} n &\sim \mathrm{Poisson}(x\,N_{\text{full}}) && \text{shot noise (a photon count, variance = mean)}\\ n_{\text{sat}} &= \min\!\big(n,\; N_{\text{full}}\big) && \text{clip 1: the well saturates, in electrons}\\ e &= n_{\text{sat}} + \mathcal N\!\big(0,\; \sigma_r^2\big) && \text{read noise (additive Gaussian, in electrons)}\\ \mathrm{DN} &= \mathrm{clip}\!\big(\mathrm{round}(g\,e + B),\; 0,\; \mathrm{DN}_{\max}\big) && \text{gain, pedestal, clip 2: the ADC rails.} \end{aligned} $$

Two choices are not interchangeable, as stressed above: the shot term is a discrete, non-negative Poisson count (Gaussian only in the many-electron limit), while the read term is modeled as Gaussian. What the single equation makes unmissable is that there are two clips, at different stages and in this order. Saturation is physical and comes first, in electrons, at the well: once the photosite is full it stops counting, capping $n$ before any read noise is added. The ADC clip comes last, after read noise and gain, and bites at both rails, $\mathrm{DN}_{\max}$ for highlights and $0$ for shadows, the floor being exactly what the pedestal $B$ exists to hold the read-noise bell clear of. The order is not cosmetic: when $gN_{\text{full}}+B$ coincides with the ADC ceiling, read noise added between the two clips produces a spike at $\mathrm{DN}_{\max}$ plus a short skirt below it (positive read excursions clipped away by the ADC, negative ones knocking saturated pixels back down), the very asymmetry the figure below draws. The affine Gaussian of L2.42 drops both clips and the Poisson shape at once, which is why it matches the full model through the midtones and parts from it at each extreme.

💡 Big lesson (L2.43) — noise is clipped at black and white, so near the extremes it is not zero-mean

A recorded value is clamped to $[0,\text{max}]$. Near black the negative half of the noise is cut off and frames pile up at 0; near white the positive half is. So at the extremes the noise distribution is asymmetric, with its mean pushed inward (Figure 2.8.12). The consequence for denoising: a naive average or smoothing returns that biased mean, so it makes shadows come out too bright and highlights too dark: a bias every denoiser must correct for (we return to it in Denoising, BASIC).

💡 Big lesson (L2.44) — the highlight clip is soft: over-range pixels do not all read the maximum

The top rail is not a hard wall. Read noise is added after the charge saturates at the well (clip 1) and before the ADC clamps (clip 2), so a pixel pinned at full well is digitized to $g\,N_{\text{full}}+B$ plus a zero-mean Gaussian excursion: about half of all saturated pixels read strictly below $\mathrm{DN}_{\max}$, by up to a read-noise's worth. It makes no difference how far over-range the pixel truly is: a highlight ten times too bright still only fills the well to $N_{\text{full}}$, gets the same read noise, and lands below the maximum half the time. So a measured value just under the ceiling does not prove a pixel was unsaturated, and a patch of genuinely clipped highlights reads a little spread of values, not one flat number. Anything that must know what saturated (HDR-merge pixel rejection, highlight reconstruction, clipping warnings) has to threshold a few $\sigma_r$ below $\mathrm{DN}_{\max}$, never exactly at it.

💡 Big lesson (L2.45) — the full noise model is Poisson, then clip, then Gaussian, then clip

A single measured value is built in four stages, in the order the sensor applies them: (1) Poisson photon shot noise, whose variance equals its mean, the irreducible floor; (2) saturation at the well, a hard clip of the electron count at the full-well capacity; (3) additive Gaussian read noise, the electronics' contribution, applied after the charge is held; and (4) the ADC clip to $[0,\mathrm{DN}_{\max}]$, after gain and the black-level pedestal. Do it in electrons, the only unit in which shot noise is exactly Poisson. The tidy affine Gaussian ($\sigma^2=a\,I+b$) is just the well-exposed limit of this recipe with the Poisson shape and both clips dropped, which is why it matches in the midtones and parts from the truth in the deep shadows (skewed, floored) and at saturation (a soft, spread-out ceiling). The order matters: because read noise lands between the two clips, saturated highlights do not pile up as a clean spike (see the two clipping lessons above). Get it right and you reproduce real noise; get it wrong and your simulator, training data, or denoiser is fitting a sensor that does not exist.

Which model should you use? For forward simulation of a raw sensor, the Poisson-plus-read-noise model with the two clips is a useful starting point. It preserves low-count behavior and saturation, and can be extended with dark current, fixed patterns, and correlated readout noise when those matter. The affine Gaussian is useful at higher counts or when an algorithm needs a continuous likelihood. Be careful about its claimed simplicity: a Gaussian with fixed variance has a quadratic negative log-likelihood, but signal-dependent variance does not. For one observation $y$ and unknown clean value $x$, it gives

$$ -\log p(y\mid x)=\frac12\log(ax+b)+\frac{(y-x)^2}{2(ax+b)}+\text{constant}. $$

Both the denominator and the log term depend on $x$. Freezing the variances from an estimate gives weighted least squares, often inside an iterative algorithm. A constant-variance Gaussian is a further approximation, appropriate when a small patch has nearly uniform brightness, after a suitable variance-stabilizing transform, or for a controlled benchmark. Choose the model for the data and the question, and keep its assumptions explicit.

fig-noise-model-compare
Figure 2.8.9. The fast affine-Gaussian model against the full sensor recipe (interactive). For a chosen mean signal, the distribution of measured values is drawn two ways: the simplified affine Gaussian (a symmetric bell of variance $N+\sigma_r^2$, never clipped) and the real sensor, which draws the shot term as a Poisson count, saturates the charge at the full well, adds Gaussian read noise, then lets the ADC clip the digitized value to the interval from zero to the full well (two clips in order: the well before read-out, the converter after). Slide the expected photon count from thousands down to single digits and the two curves, indistinguishable in the midtones, come apart in the shadows: the real distribution turns discrete and right-skewed and piles up against the zero floor, biasing the shadows bright, exactly where the affine bell hands back unphysical negative values. Push the signal toward the well and watch the two clips act in turn: the well saturates the charge, then read noise spreads it, so the real distribution shows a spike at the maximum (positive read noise clipped by the ADC) plus a skirt just below it (saturated pixels knocked back down by negative read noise), where the affine model sails symmetrically past. The read-noise slider sets the floor and the well-capacity slider sets the ceiling; switch on the black-level pedestal and the whole signal lifts off zero, so the negative half of the read noise stays measurable instead of clipping. A k×k patch of measured pixels is sampled and overlaid, and its empirical mean is marked against the true expected value: the finite-patch measurement drifts from the truth by the clipping bias plus sampling noise, and closes in as the patch grows (a new-sample button redraws a fresh random patch).
fig-noise-distribution-regimes
Figure 2.8.10. Four regimes of the real measured-value distribution, from the one recipe $\mathrm{clip}(\min(\mathrm{Poisson}, \text{well}) + \text{read noise},\, 0,\, \text{well})$ at four signal levels (normalized so 1 = full well). Near black it is Poisson-skewed and truncated, with a hard spike at black where the negative half of the read noise is clipped away, nothing like a Gaussian. In the midtone it is an almost pure Gaussian, clipping neither end. Near saturation the read noise, added after the charge already saturated at the well, smears the top and starts piling pixels at the maximum. And far over the well (mean 10×) the charge is pinned at the well, so read noise alone spreads the read-out: about half the pixels read strictly below full scale and look perfectly unclipped, even though every one of them was massively over-exposed. The affine-Gaussian model is a good fit only in the midtone.
fig-noise-bias-curve
Figure 2.8.11. Is the sensor unbiased, and how noisy? The expected measurement (top) and the expected error (bottom), each a line inside its ±1σ band (the noise), both colored by the signed bias on a diverging scale (blue = too dark, gray = unbiased, red = too bright), so the noise reads as band width and the bias as line color. The horizontal axis is the absolute expected photon count (log, independent of the well, to 100k); a relative-error toggle divides the error by the true value (revealing how badly the shadows fare in fractional terms). Across the midtones the measurement rides the identity line and the error is zero: shot noise is unbiased, its skew averages out, so a plain frame average recovers the truth. It breaks at both rails. Clipping at black lifts the shadows (a small positive bias), because the negative half of the read noise is chopped off; raise the black-level offset and the signal floats clear of zero, so the lift vanishes. And saturation pulls the highlights down without bound: past the well the measurement flattens at 1 while the true value keeps climbing, so an over-exposed pixel reports the well, not its intensity. A bigger well pushes the shadow bias to fainter intensities; more read noise deepens it. Read the two together: the band's width is the noise, the line's distance from zero the bias: the midtones are unbiased but noisy (wide band on zero), saturation is biased but quiet (narrow band far below zero).

Drawing Poisson noise. In Python, NumPy does it vectorized over the whole image at once, each pixel drawn at its own mean:

import numpy as np
rng = np.random.default_rng()
electrons = rng.poisson(mean_e)   # mean_e: float array of electron counts -> integer counts

In C++, the standard library provides it in <random>; the mean is a construction parameter, so a per-pixel mean means constructing (or re-parameterizing) the distribution for each pixel:

#include <random>
std::mt19937_64 rng(seed);
std::poisson_distribution<long long> shot(mean_e);  // mean_e > 0
long long k = shot(rng);                            // one Poisson electron count

Put together, the whole simulator is short, in Python (NumPy, whole image at once) or C++ (per pixel, standard library only). Pick a tab and copy (Listing 2.8.1):

Listing 2.8.1 · Physically-based sensor-noise simulatorembed
import numpy as np

def add_sensor_noise(img, full_well=30000.0, read_noise_e=2.0,
                     bit_depth=14, black_level_dn=0.0, rng=None):
    """Physically-based sensor noise on a scene-LINEAR image where 1.0 == full well.

    Everything happens in electrons, the only unit in which shot noise is Poisson.
    Returns a linear float image; black subtraction can produce negative values.
    """
    img = np.asarray(img, dtype=np.float64)
    if not (1 <= bit_depth <= 30) or int(bit_depth) != bit_depth:
        raise ValueError("bit_depth must be an integer from 1 to 30")
    bit_depth = int(bit_depth)
    if not np.isfinite(full_well) or full_well <= 0:
        raise ValueError("full_well must be finite and positive")
    if not np.isfinite(read_noise_e) or read_noise_e < 0:
        raise ValueError("read_noise_e must be finite and nonnegative")
    if not np.all(np.isfinite(img)):
        raise ValueError("image values must be finite")
    rng = np.random.default_rng() if rng is None else rng
    max_dn = float((1 << bit_depth) - 1)
    if not np.isfinite(black_level_dn) or not 0 <= black_level_dn < max_dn:
        raise ValueError("black level must be in [0, max_dn)")
    gain   = (max_dn - black_level_dn) / full_well          # DN per electron

    mean_e    = np.clip(img, 0.0, None) * full_well         # 1. to electrons
    electrons = rng.poisson(mean_e).astype(np.float64)      # 2. shot: Poisson count
    electrons = np.minimum(electrons, full_well)            # 3. clip 1: well saturation (electrons)
    electrons += rng.normal(0.0, read_noise_e, img.shape)   # 4. read: Gaussian, in electrons

    dn = np.round(electrons * gain + black_level_dn)        # 5. to DN: gain + pedestal
    dn = np.clip(dn, 0.0, max_dn)                           # 6. clip 2: the ADC rails
    return (dn - black_level_dn) / (max_dn - black_level_dn)  # 7. linear, retaining sub-black noise

The cardinal mistake is the one-liner everyone reaches for first: a single constant-$\sigma$ Gaussian added to a gamma-encoded image. It is signal-independent (no shot noise) and in the wrong space, so it looks wrong in exactly the shadows where noise matters. Poisson photoelectron counts plus Gaussian read noise provide the baseline model here; sensor-specific effects may require more terms.

To summarize, the affine law gets the variance right, but the Gaussian shape is only an approximation, and it departs from a real sensor in three ways. The first we have already met: in the deep shadows the true statistics are Poisson, not Gaussian. The other two happen at the two extremes, where the recorded value is clipped (the two soft-clipping lessons above, L2.43 and L2.44).

That clipping caveat is the first crack in the affine model; here is a larger one. The law $\sigma^2 \approx a\,I + b$ describes the noise as the sensor hands it over (the raw mosaic, straight off the ADC); it is a fact about the sensor, not about the final photograph. Run that raw through the computational-photography pipeline and the clean affine line bends. A burst merge (align-and-average $N$ frames, Part 13, Denoising) drives the variance toward $1/N$ of a single frame, but unevenly (the robust merge keeps more frames in still regions than near moving edges), so the noise becomes spatially varying, and highlight clipping means it is no longer even affine in brightness. Demosaicking (Part 15, Demosaicking and joint methods) bends it too: an interpolated color is a weighted average of neighboring pixels, and fixed positive averaging weights reduce variance for independent samples. The amount varies across pixels; negative or adaptive weights need not reduce it. Shared input samples also correlate neighboring output errors. After a few ISP stages the tidy 'gain·signal + read²' line is gone, and a downstream algorithm that still assumes it (a plain AWGN denoiser, say) is fitting a model the data no longer obeys.

fig-noise-truncation
Figure 2.8.12. Clipping makes noise asymmetric at the extremes. A near-black pixel spends about 44% of its frames pinned at 0 (the negative half of its noise is clamped away), so the average of its frames (what naive denoising returns) sits well above 0: biased bright. A clean midtone pixel, by contrast, is a symmetric Gaussian whose average is unbiased. Averaging therefore lifts shadows too bright and, symmetrically, pulls clipped highlights too dark.

Manufacturers know this and design around it: many sensors deliberately lift the black point before digitizing. They add a fixed offset (a "black level" or bias, a few hundred code values) to the signal, so nearly all of the read-noise distribution, negative excursions included, lands above zero and is recorded rather than clipped (the value depends on the camera, bit depth, channel, and readout mode). For example, the 50-megapixel Sony raws used for this book's figures record black at code 512 and saturation at 16383 on their 14-bit scale, and many 14-bit Canon raws sit near 2048; the file's own black-level tag, which exiftool prints, is the number to trust. The raw file then carries an explicit black-level tag that the converter subtracts back out. Keeping the noise unclipped this way is exactly what lets noise-weighted averaging, flat/dark calibration, and shadow-lifting stay unbiased down in the darkest tones, at the cost of a sliver of headroom. One discipline follows: after subtracting the black level, near-black pixels can legitimately go slightly negative, and that must be preserved, not clamped, all the way until display, or the bias creeps right back in.

Black-level handling must be checked for the actual raw format and camera mode. Some files preserve an offset and describe it in metadata; others have had a black estimate subtracted, sometimes followed by clipping. A reported black value of zero therefore does not by itself prove that no negative noise was lost. Clipping in-camera can make the darkest samples look tidier, but discards the sub-black tail, so subsequent averaging and dark-frame calibration are biased near black. Inspect optical-black samples or dark frames when available, and use a camera-specific calibration if the metadata is missing or inaccurate.

2.8.6 Noise as a function of ISO⧉

The affine constants $a$ and $b$ are not fixed properties of a sensor: they slide with the ISO setting, because an ISO setting can change analog gain, conversion-gain mode, and sometimes digital scaling. Here we first model an analog gain applied partway down the readout chain, and it matters a great deal where each noise source enters relative to that amplifier. Three sources, three positions:

Write the analog gain as $g$ (in DN per electron), rising with ISO. The mean recorded value is $\mu = g\,N$ (DN), and the three variances add, each in the domain it lives in. Referred to the output (DN$^2$):

$$ \sigma^2(\mu) \;=\; \underbrace{g\,\mu}_{\text{photon}} \;+\; \underbrace{g^2\,\sigma_{\text{pre}}^2}_{\text{pre-gain read}} \;+\; \underbrace{\sigma_{\text{post}}^2}_{\text{post-gain read}}. $$

This is the same affine line $\sigma^2 = a\,\mu + b$, now with its constants named by physics: the slope $a=g$ is the gain, so it rises with analog gain (not necessarily with every nominal ISO step), and the intercept $b = g^2\,\sigma_{\text{pre}}^2 + \sigma_{\text{post}}^2$ is the read-noise floor, a sum of a term the gain amplifies and a term it does not. (The photon term reads $g\,\mu$ because in electrons its variance is $N=\mu/g$, amplified by $g^2$.)

The revealing move is to refer that floor back to the input, dividing by $g^2$ to read it in electrons:

$$ \sigma_{\text{read}}^2(g) \;=\; \sigma_{\text{pre}}^2 \;+\; \frac{\sigma_{\text{post}}^2}{g^2} \qquad [\text{electrons}^2]. $$

As ISO climbs, the post-gain term shrinks as $1/g^2$ and the input-referred read noise falls toward the floor $\sigma_{\text{pre}}$. That single curve, read noise in electrons versus ISO, captures a sensor's low-light behavior (Figure 2.8.13).

fig-noise-vs-iso
Figure 2.8.13. Noise as a function of ISO, interactive. Left: the affine variance line $\sigma^2 = a\,\mu + b$ in the recorded (DN) domain; drag the ISO slider and watch the slope $a=g$ steepen in proportion to ISO while the floor $b=g^2\sigma_{\text{pre}}^2+\sigma_{\text{post}}^2$ lifts (a faint reference line marks base ISO). Right: the same model referred to the input, read noise in electrons versus ISO, falling as $\sqrt{\sigma_{\text{pre}}^2+\sigma_{\text{post}}^2/g^2}$ toward the pre-gain floor $\sigma_{\text{pre}}$: flat for an ISO-invariant sensor, steeply falling for a downstream-noise-limited one. A dual-conversion-gain toggle adds the hardware step where $\sigma_{\text{pre}}$ and the full well both drop, the sudden cleanup seen near ISO 500-800 on real bodies. Sliders for $\sigma_{\text{pre}}$, $\sigma_{\text{post}}$, and the full well dial in the cameras of the table below.

Within a fixed readout mode we approximate the pre- and post-gain terms as constants. The following illustrative cases show how their relative sizes change the result; they are not measured decompositions for named cameras. Let $g_0$ be base gain and express the downstream term as its input-equivalent value $\sigma_{\text{post}}/g_0$ at that gain.

illustrative casefull well (e⁻)pre-gain noise (e⁻)downstream noise referred to base-gain input (e⁻)total read noise at $g_0$ (e⁻)at $4g_0$ (e⁻)
low downstream noise45,0001.21.51.921.26
very low downstream noise28,0001.00.31.041.00
moderate downstream noise50,0001.32.02.391.39
downstream-limited readout68,0002.535.035.099.10
small-well example6,0001.52.02.501.58

For a real camera, measure or consult its input-referred read-noise curve for the relevant raw mode. Full well and read noise need not stay fixed across conversion-gain switches, bit-depth changes, or electronic-shutter modes. The table isolates analog gain to explain the mechanism.

What modern sensors do about it: ISO invariance and dual conversion gain. Two facts fall straight out of the input-referred equation. First, ISO invariance. If the pre-gain noise already dominates the floor at low ISO ($g^2\sigma_{\text{pre}}^2 \gg \sigma_{\text{post}}^2$), then $\sigma_{\text{read}}\approx\sigma_{\text{pre}}$ at every ISO, and raising ISO in the camera buys nothing that brightening the raw file in software could not. Such a sensor is called ISO-invariant: within such a gain range, a lower ISO can protect highlights while software lifting gives similar shadow noise. This does not establish that base ISO is always best: conversion-gain switches and other mode changes can alter the noise floor. On-chip ADCs reduce downstream noise, but the degree and range of ISO invariance remain camera-specific. The older arrangement, an off-chip ADC with large downstream noise (many DSLRs into the early 2010s), sat at the opposite extreme: $\sigma_{\text{post}}$ dominated at low ISO, so cranking the analog gain genuinely lowered the input-referred read noise, and "expose at the ISO you actually need" was real advice, not superstition. In affine-model terms, ISO invariance is just the statement that the input-referred intercept $b/g^2$ is already flat.

Second, dual conversion gain. A photosite cannot at once hold a huge charge (for highlight headroom in bright light) and convert that charge to voltage with tiny noise (for clean shadows in the dark); the conversion gain that trades between them is a hardware setting. Modern sensors refuse to choose and build two readout modes: a low-conversion-gain mode with a large full well and higher read noise for bright scenes, and a high-conversion-gain mode with a smaller well but markedly lower $\sigma_{\text{pre}}$ that switches in above a threshold ISO. On a read-noise-versus-ISO plot this appears as a sudden step down at that ISO (the drop near ISO 500-800 on many bodies), where a higher ISO is actually cleaner than a slightly lower one. In our model the switch changes the physical constants themselves: at the threshold both $N_{\text{full}}$ and $\sigma_{\text{pre}}$ drop, so the noise profile must be calibrated on both sides. Whether a plotted slope or intercept rises or falls also depends on gain and output normalization. The affine model is then not one line across all ISOs but a family of lines with a break at the dual-gain point.

The upshot ties the section together: $a$ and $b$ are not sensor constants but functions of ISO, with $a\propto g$ and $b=g^2\sigma_{\text{pre}}^2+\sigma_{\text{post}}^2$; ISO invariance is the regime where the input-referred floor $b/g^2$ is flat; and dual gain is a deliberate step in $\sigma_{\text{pre}}$ (and full well) that resets both constants at a chosen ISO. A denoiser or raw pipeline handed the wrong $a,b$ for the ISO, or blind to the dual-gain break, mis-models the noise in exactly the shadows it is trying to protect.

2.8.7 Dynamic range⧉

Two extremes bound what a single exposure can hold. At the top, a pixel's well saturates: once it has counted its full-well capacity of electrons, more light adds nothing and the highlight clips to white. At the bottom, the read-noise floor sets the dimmest signal still distinguishable from noise. The ratio of the two is the sensor's dynamic range: how much of a high-contrast scene a single exposure can capture. When a scene's range exceeds the sensor's (a bright window and a dim interior in one frame), no single exposure holds both ends, which is the motivation for high-dynamic-range (HDR) imaging, merging several exposures (Chapter 17.1, Dynamic range and multiple-exposure capture; Figure 2.8.14). Like everything else a photographer counts, dynamic range is quoted in stops (factors of two), which connects it straight to the exposure controls.

One subtlety keeps dynamic range from being the hard number it looks like: the bottom is not a sharp cliff where signal abruptly vanishes, but wherever the signal-to-noise ratio falls below what you are willing to accept. Engineers usually quote the engineering dynamic range, placing the floor at SNR = 1 (signal equal to noise); that is the most generous possible bound, and full-well divided by read noise approximates this criterion when read noise dominates at the threshold. With shot noise included, the electron signal $N$ at SNR $q$ solves $N/\sqrt{N+\sigma_r^2}=q$, giving $N_{\min}=(q^2+\sqrt{q^4+4q^2\sigma_r^2})/2$. The usable range is then $\log_2(N_{\mathrm{sat}}/N_{\min})$ stops, where $N_{\mathrm{sat}}$ is the effective saturation signal at the chosen gain. A photographer who wants genuinely clean shadows demands a far higher SNR, say 10 or 20, sets the floor higher, and counts fewer usable stops. This is why measurement sites report dynamic range at a stated quality threshold and their numbers disagree: the same sensor has a wide engineering range and a narrower photographic one. In this respect dynamic range behaves like depth of field: both carry a crisp-looking definition that actually rests on a chosen tolerance (an acceptable SNR here, an acceptable circle of confusion there), so the single figure you read off is only ever as hard as the criterion behind it.

There is one more limit that no sensor spec sheet lists: the lens. Bright parts of a scene scatter stray light inside the lens and camera body (faint reflections off every element surface, the diaphragm blades, and the barrel walls) that settle as a veil of light spread across the whole frame. This veiling glare, the diffuse cousin of lens flare, lifts the darkest tones off true black, adding a structured background and its shot noise. Even if the mean glare could be subtracted, its photon noise would remain; this differs from electronic read noise. It therefore caps the dynamic range a real photograph can reach below whatever the bare sensor could deliver, and it bites hardest exactly when dynamic range matters most, shooting a dim subject against a bright source. It is why lens coatings, hoods, and a clean front element buy real shadow contrast, and why the deepest blacks in a studio shot are easier to protect than those in a backlit scene. Flare and veiling glare get their full treatment as optical defects in Chapter 22.1, Aberrations and optical challenges (§10.1).

fig-dynamic-range-problem
Figure 2.8.14. The dynamic-range problem. One high-contrast scene (a sunset over water) developed at three exposures: expose for the highlights and the foreground is crushed to black; expose for the shadows and the sky blows out to white; the compromise loses both ends. No single exposure holds the full range: the motivation for high-dynamic-range merging of multiple exposures.

How wide a range, exactly? It helps to put numbers on it, because the dynamic ranges of real media and of the eye differ by a lot (Figure 2.8.15). A color slide is narrow, only about 5–6 stops; a reflective print about 6–7; a film negative is famously forgiving at roughly 12–13 stops of latitude; a phone sensor manages about 10–12 and a full-frame sensor about 14. The human eye sees about 10–14 stops instantaneously, but allow it to adapt (the slow re-centering of the retinal response covered with Chapter 3.3, Visual processing) and it spans 20+ stops over time; some animals do better still within their niche. Against all of these, an outdoor sun-and-shadow scene can exceed 20 stops in a single frame, which is precisely why no single capture holds it, and why HDR exists.

fig-dynamic-range-comparison
Figure 2.8.15. *Dynamic range across media and eyes, as a ladder of stops: color slide (~5–6 stops), reflective print (~6–7), film negative (~12–13 latitude), phone sensor (~10–12), full-frame sensor (~14), and the human eye (~10–14 instantaneous, ~20+ once adaptation is allowed), with an animal example, set against a real sun-and-shadow scene exceeding 20 stops, which no single capture spans: the motivation for HDR.

Recovering an underexposed shot: full-frame vs. phone. The clearest demonstration is to underexpose one. Shoot the same underexposed scene as raw on a full-frame camera and on a phone, then push the exposure up in software by three or four stops (Figure 2.8.16). The full-frame frame cleans up (its deep full-well and low read-noise floor give it the headroom to be lifted) while the phone frame breaks into shadow noise and banding, because lifting the exposure also amplifies its read-noise floor, which sat much closer to the signal to begin with. At matched framing, exposure, and output resolution, this illustrates the benefit a larger total collecting area can provide; it is not a universal rule that sensor size alone determines dynamic range, and exactly why phones lean on burst capture and HDR+ (Multiple-exposure part) rather than trusting a single exposure. It is also a coding exercise: see Exercises & Experiments.

[figure fig-underexposure-recovery-ff-vs-phone not built]
Figure 2.8.16. (Deferred, to be generated.) The same underexposed scene, shot as raw on a full-frame camera and on a phone, then pushed up about 3–4 stops in software: the full-frame frame cleans up (deep full-well, low read-noise floor → wide dynamic range), while the phone frame reveals amplified shadow noise and banding (its read-noise floor lifted with the signal): dynamic range scaling with sensor size.
💡 Big lesson (L2.46) — dynamic range = full-well capacity ÷ noise floor

A single exposure records from a top (the photosite's full-well capacity, where it saturates and clips to white) down to a bottom (the noise floor, the read noise that drowns the shadows). Their ratio is the dynamic range, quoted in stops. That floor is not absolute: it sits wherever the SNR drops below what you deem acceptable, so, just as with depth of field and its circle of confusion, the number depends on the quality criterion you pick (SNR = 1 gives the generous engineering range; a stricter SNR gives the narrower usable one). You widen it with a bigger well (larger photosites, why a full-frame sensor out-ranges a phone) or a lower floor (cooling, lower read noise), and you beat it altogether by merging multiple exposures (HDR). This is the capture-side companion to the quantization lesson below: what bounds a single shot is this range, full-well over floor, not the number of bits.

This is also the right moment to deflate a worry beginners often have about digital capture: that the image is quantized into a finite number of levels, and that this stair-stepping is what limits quality. With adequate raw bit depth and noise comparable to a code step, quantization is often a smaller limitation than sensor noise. Aggressive tonal edits or insufficient precision can still expose banding.

💡 Big lesson (L2.47) — quantization is rarely the real problem

With enough bits and a sane encoding, what limits image quality is noise and dynamic range (the two quantities of this section), not the number of levels the analog-to-digital converter (ADC) offers. The noise floor and the full well bound what you can record; the quantization step, once it sits below the noise, is invisible. (Indeed, a little noise dithers the quantization, hiding it further.) Levels matter in one place: banding in the deep shadows of a linearly-encoded image, too few codes where the eye, working in ratios, is most sensitive, and that is exactly the problem gamma encoding exists to solve, by spending code levels perceptually (Chapter 4.1, Color space 101). So "rarely" is not "never." We meet this lesson again in BASIC → Image representation → Float vs 8-bit, where floats with headroom are the sane default.

fig-noise-vs-quantization
Figure 2.8.17. The quantization step against the noise it has to beat (interactive). Both are standard deviations in the same units, so they can be compared directly: photon noise is Poisson, so $\sigma=\sqrt{S+r^2}$ electrons at a signal of $S$ electrons with read noise $r$, while one code step contributes $\sigma_q=\text{step}/\sqrt{12}$. The bars are the code steps and their width is the step itself, uniform under $\gamma=1$, squeezed into the shadows as $\gamma$ rises. Where a bar pokes above the noise curve, quantization is adding something the sensor was not already contributing; everywhere else it is buried, and the noise dithers it away. The scenario buttons set plausible hardware: a 14-bit linear raw from a good mirrorless, an 8-bit gamma-encoded JPEG from the same camera, and an 8-bit phone file whose pixel holds an order of magnitude fewer electrons. In the first three every step sits under the noise. Only 8-bit linear crosses, and only in the deepest shadows, the one place the lesson allows for, and exactly what gamma encoding exists to fix. Read noise, full well, bit depth and gamma are all adjustable, and the vertical axis can be read in electrons, as a fraction of the well, or in JNDs.

These three facts (that noise is the jitter of a photon count, that the signal-to-noise ratio is worst in the shadows, and that dynamic range is the full-well-over-floor a single exposure can hold) recur on nearly every later page: in how a photographer exposes to the right, in high-dynamic-range merging (Multiple-exposure part), and in the denoising of the basic pipeline. With measurement and its limits now in hand, the part turns next to what a second viewpoint buys you (depth), and then to the eye that will finally judge the result.


2.8.8 Regimes, and how close we are to the limits⧉

Pulling the chapter together: which noise matters depends entirely on how much light you have, and a single picture usually spans several regimes at once.

The same three regimes bound dynamic range, which is just full-well capacity ÷ read-noise floor L2.46: the top set by how many electrons a pixel holds before clipping, the bottom by the read noise.

How close are we to the theoretical limits? On two of the three axes, modern sensors are already close to their physical limits.

These limits explain the attraction of multi-frame computation: longer total collection improves photon statistics, averaging reduces independent read noise, and exposure bracketing extends the scene range beyond one capture. Sensor engineering and computation remain complementary. Improved efficiency, charge storage, readout, and optics still matter, especially outside the conditions where a particular sensor is already close to ideal.

Figure 2.8.18 makes the budget concrete.

fig-noise-calculator
Figure 2.8.18. Sensor noise calculator (interactive). Choose the sensor size, resolution, ISO, shutter duration, quantum efficiency, read noise, and the minimum SNR you will accept (in dB), all at typical values. From the pixel area it derives the full-well capacity and, for the chosen ISO, the saturation level, then reports the noise in electrons at black, at 18% gray, and at saturation, the corresponding SNR in decibels, and the affine noise model $\mathrm{Var}(I)=a+b\,I$ (read-noise floor $a$, photon slope $b$). A stacked bar splits the variance at 18% gray into photon, read, dark-current, and quantization shares, showing that the midtones are photon-limited and read noise only bites in the shadows. It gives the dynamic range two ways (full-well ÷ read noise, and the range down to your minimum SNR), in stops and decibels, and renders a log-spaced gray ramp with the model's real per-pixel noise so you can see the shadows go grainy while the highlights stay clean. Interactive: set sensor size, ISO, and read noise and read off the SNR, the per-source noise breakdown, the dynamic range, and a gray ramp rendered with the actual noise.

2.8.9 Making noise variance uniform⧉

The affine model above (#Noise variance is mostly affine in pixel brightness) is accurate but inconvenient: the noise variance changes with brightness, $\sigma^2(x) = a\,x + b$, so a bright patch is genuinely noisier, in absolute terms, than a dark one. Most denoising theory, though, is written for signal-independent noise, a constant-variance Gaussian everywhere. The bridge between the two is a variance-stabilizing transform (VST): a pointwise nonlinearity $f$ chosen so that $f(x)$ has (approximately) constant variance regardless of how bright $x$ is. Apply $f$, denoise in the stabilized domain with any off-the-shelf constant-variance method, then invert.

For pure Poisson (photon) noise, where $\sigma^2 = x$, the classical choice is the Anscombe transform (Anscombe 1948 (variance-stabilizing transform)),

$$ f(x) = 2\sqrt{x + \tfrac{3}{8}}, $$

whose output has variance $\approx 1$ once counts are sufficiently large (the $3/8$ is a small correction that keeps the approximation good down to a handful of photons). A real sensor is Poisson plus read noise, exactly the affine $a\,x + b$ of this chapter, and the generalized Anscombe transform (GAT) (Starck, Murtagh & Bijaoui, Image Processing and Data Analysis (1998)) handles that,

$$ f(x) = \frac{2}{a}\sqrt{\max(0,a\,x + \tfrac{3}{8}a^2 + b)}, $$

with $a$ the photon-gain slope and $b$ the read-noise variance, both measured as in this chapter, with black level already removed and $a>0$. Stabilization is approximate at very low counts, and clamping the radicand handles negative noisy samples. The one subtlety is the way back: naively inverting $f$ biases the result, because a mean does not survive a nonlinear map, so the exact unbiased inverse of Mäkitalo and Foi (Mäkitalo & Foi 2013 (generalized Anscombe)) is what you actually apply. The pipeline is stabilize, denoise as if Gaussian, invert, and it is why a great deal of raw denoising quietly runs in an Anscombe domain.

Gamma helps too, more crudely and for free. A gamma encoding compresses the highlights, where Poisson noise is largest in absolute terms, and stretches the shadows, so a square-root-like encoding can make the absolute encoded variance flatter in shot-noise-dominated regions, one more reason processing and viewing so often happen in an encoded space (Chapter 4.3, Encoding: linear, gamma or log). It is not a true variance-stabilizer, the variance is only roughly equalized and the curve was chosen for perception rather than statistics, but it can help over a restricted range. A log transform is different: the delta method gives variance approximately proportional to $1/x$ for pure Poisson input, so it does not stabilize shot-noise variance. Neither encoding recovers SNR lost during capture.

Recap: big lessons of this chapter

💡 Big lesson (L2.37) — variance is the mathematically meaningful quantity; standard deviation is the human-readable one

Two numbers describe noise spread, and both exist for a reason. Variance (the mean squared deviation) is the quantity the mathematics wants: it is additive for independent sources, exactly what we just used, and the basis of the $1/\sqrt N$ averaging law in Part 13, Denoising; it is the second moment that falls out of every Gaussian and least-squares derivation, and it composes cleanly under linear operations. But its units are squared (squared gray-levels, squared photons), so it means nothing to the eye. The standard deviation $\sigma$ (its square root) is the one people should read: it is back in the original units, directly comparable to the signal: the "$\sigma$" of error bars and the grain you actually see. Rule of thumb: derive and combine in variance, report in standard deviation.

💡 Big lesson (L2.38) — noise is fundamental: photon shot noise sets the floor

Even a flawless sensor is noisy, because light itself is grainy: photons arrive as discrete, randomly-timed events, so the count in any fixed interval follows Poisson statistics ($\sigma=\sqrt N$), and no electronics can remove it: the randomness is in the light, not the chip. The only true cure is collecting more photons: a bigger pixel, a wider aperture, a longer exposure, or averaging many frames. Raising ISO is not a cure: it is gain applied after capture, amplifying signal and shot noise together. This irreducible floor is why bigger sensors win, why shadows are noisy, and what every denoiser later in the book is ultimately fighting.

fig-poisson-noise
Figure 2.8.1 (reproduced). Photon shot noise, live and interactive. Photons rain from above into $K$ groups of $n$ buckets (pixels), both sliders. Each group fills at its own flux, chosen so its expected count is simple ($10, 100, 1000$ by default; a ratio slider spreads them around the middle), and the $n$ buckets in a group share that expectation, so their spread is exactly the shot noise at that level. Each exposure runs for the shutter time (1 s by default) and then we count. Because photon arrivals are independent and random the counts are Poisson, so the running mean and variance under each group stay nearly equal. Every exposure adds $K$ points to the upper plot, where you can read the spread as variance (climbing the line variance = mean), standard deviation, or SNR (both tracking $\sqrt N$); the lower plot scatters all $N\times K$ buckets, expected count vs. what each actually caught, so the cloud around $y=x$ visibly widens with brightness in absolute terms yet tightens in relative terms. It makes the defining fact of shot noise, $\sigma=\sqrt N$, something you watch happen. Log axes; no well saturation; reset clears the accumulated points.
💡 Big lesson (L2.39) — know the noise sources, and when each one dominates

Sensor noise is a sum of distinct sources whose variances add, but each rules a different regime, so diagnosing a noisy image means asking which one you are seeing. Photon shot noise ($\propto\sqrt{\text{signal}}$) dominates the midtones and highlights, and any well-lit shot. Read noise is signal-independent and dominates the deep shadows and short exposures, setting the floor. Thermal / dark-current noise grows with exposure time and temperature: the long-exposure and astrophotography enemy. Quantization matters only with too few bits L2.47. And fixed-pattern noise / PRNU (static per-pixel gain and offset variation) reads as a structured pattern and is removed by calibration (dark and flat fields). Match the symptom to the source before reaching for a fix.

💡 Big lesson (L2.40) — aggregating measurements keeps the shot noise but multiplies the read noise

Add the readings of $k$ small pixels and you get the same Poisson (shot) noise as one big super-pixel that caught the same photons, but you pay the read noise $k$ times, once per read-out, instead of once. So the only fundamental advantage of a bigger pixel (or one longer exposure) over many smaller ones is the read noise, not the photon statistics, as long as no light is lost in the gaps. The same holds for aggregating along any dimension: summing $k$ short exposures, or $k$ burst frames, keeps the shot noise of the total light but charges read noise $k$ times. This is precisely why charge-domain binning (combine, then read once) beats digital summation (read $k$ times, then add) in the dark.

💡 Big lesson (L2.41) — bright pixels are noisier (more absolute noise) but have better SNR

Shot noise is Poisson, so its variance grows linearly with the signal ($\sigma^2 \propto N$) and its standard deviation grows only as the square root ($\sigma \propto \sqrt{N}$). Two consequences pull in opposite directions: the absolute noise is larger in highlights than in shadows (a 10,000-photon highlight has $\sigma=100$; a 100-photon shadow has $\sigma=10$), yet the SNR $= N/\sqrt{N} = \sqrt{N}$ is higher in the highlights: the signal outgrows the noise. So bright areas are noisier in absolute terms but cleaner to the eye; the shadows have the worst SNR (Figure 2.8.4, Figure 2.8.6). This is why exposing to the right and brighter scenes look smoother, and why we gamma/log-encode so equal ratios get equal steps.

fig-snr-vs-stddev
Figure 2.8.6 (reproduced). Noise is numerically worse in highlights but looks worse in shadows. Three panels of the same brightness ramp, each labeled so the good direction is unambiguous. A standard-deviation map (absolute noise, higher = worse) is brightest in the highlights, since shot noise $\sigma = \sqrt{N}$ grows with brightness; an SNR map ($=\sqrt{N}$, higher = better) is worst in the shadows, since the ratio falls where photons are few; and a noise-only panel shows a single frame's residual, the measurement minus its expected value, on a diverging colormap (blue for negative excursions, red for positive, white at zero) so both signs read at once, the residual staying near zero-mean everywhere yet visibly growing in amplitude toward the highlights. Perception tracks the ratio, so shadows look noisiest, the reason for exposing-to-the-right and for gamma/log encoding. All three maps are computed in linear light and gamma-encoded only for display, so the noise magnitudes shown are faithful.
fig-noise-variance-map
Figure 2.8.4 (reproduced). The noise of a real high-ISO image, and its SNR. From a 50-frame ISO-3200 burst of one static scene: the scene itself (left, mean of the burst), the per-pixel variance across the burst (middle), and the per-pixel SNR = signal/noise (right). Computed on linearized values, so shot noise behaves physically. The variance map is brightest where the scene is bright (absolute noise grows with signal), while the SNR map is also brightest in the bright areas and worst in the shadows, because noise only grows as √signal so the ratio improves with light. Bright pixels are noisier in absolute terms yet cleaner in relative terms. This is the raw material the affine model below summarizes.
💡 Big lesson (L2.42) — in a linear image, noise variance is mostly an affine function of brightness (ignoring clipping).

The variances add, and two terms dominate: shot noise contributes an amount proportional to the signal (Poisson, variance = mean, scaled by the gain) and read noise a constant floor. So the total is variance ≈ gain·signal + read², a straight line in brightness (Figure 2.8.7). The slope is the photon gain (it steepens with ISO, which amplifies the signal and its shot noise together); the intercept is the read-noise floor. We can measure it without any model: take an aligned burst of a static scene and, per pixel, plot the variance across frames against the mean. This affine law is a statement about the variance and is essentially exact for the two dominant sources; it says nothing yet about the shape of the distribution. Where the electron count is large, a single pixel's value over many frames does look ≈ Gaussian (Figure 2.8.8), which licenses modeling per-pixel noise as additive Gaussian in the midtones and highlights. That bell is only an approximation, though: the shot term is really Poisson (variance = mean, but discrete, skewed, and non-negative), and in the deep shadows, where only a handful of electrons land, it stops looking Gaussian at all. The additive-Gaussian model is a convenience of the well-exposed regime, not a law of noise in general (we pin down where it breaks below).

fig-noise-affine
Figure 2.8.7 (reproduced). Noise variance is affine in brightness, measured. From a 50-frame burst of one static scene at ISO 3200, the per-pixel variance plotted against the per-pixel mean (in the linearized domain, on flat patches so mis-alignment doesn't masquerade as noise) traces a straight line: a constant read-noise floor (intercept) plus a shot-noise term proportional to the signal (slope = gain), $\sigma^2 \approx a\,I + b$. Toward the bright end the camera's highlight roll-off and clipping pull the measured variance below the line: the truncation taken up next. Raising the ISO amplifies the signal and its noise together by multiplying the gain: the fitted slope at ISO 3200 is about 7× that at ISO 400, close to the 8× ISO ratio.
fig-noise-gaussian-pixels
Figure 2.8.8 (reproduced). A single pixel, over many frames, is ≈ Gaussian. Histograms of a few flat pixels' values across the 50 frames, at increasing brightness, each with a fitted Gaussian: at these brightnesses the spread is well described by a normal distribution (the many-photon limit of the Poisson count plus Gaussian read noise). This is the empirical basis for the additive-Gaussian noise model used throughout denoising, in the bright regime; down in the deep shadows the underlying Poisson statistics show through and the bell breaks (see below).
💡 Big lesson (L2.43) — noise is clipped at black and white, so near the extremes it is not zero-mean

A recorded value is clamped to $[0,\text{max}]$. Near black the negative half of the noise is cut off and frames pile up at 0; near white the positive half is. So at the extremes the noise distribution is asymmetric, with its mean pushed inward (Figure 2.8.12). The consequence for denoising: a naive average or smoothing returns that biased mean, so it makes shadows come out too bright and highlights too dark: a bias every denoiser must correct for (we return to it in Denoising, BASIC).

fig-noise-truncation
Figure 2.8.12 (reproduced). Clipping makes noise asymmetric at the extremes. A near-black pixel spends about 44% of its frames pinned at 0 (the negative half of its noise is clamped away), so the average of its frames (what naive denoising returns) sits well above 0: biased bright. A clean midtone pixel, by contrast, is a symmetric Gaussian whose average is unbiased. Averaging therefore lifts shadows too bright and, symmetrically, pulls clipped highlights too dark.
💡 Big lesson (L2.44) — the highlight clip is soft: over-range pixels do not all read the maximum

The top rail is not a hard wall. Read noise is added after the charge saturates at the well (clip 1) and before the ADC clamps (clip 2), so a pixel pinned at full well is digitized to $g\,N_{\text{full}}+B$ plus a zero-mean Gaussian excursion: about half of all saturated pixels read strictly below $\mathrm{DN}_{\max}$, by up to a read-noise's worth. It makes no difference how far over-range the pixel truly is: a highlight ten times too bright still only fills the well to $N_{\text{full}}$, gets the same read noise, and lands below the maximum half the time. So a measured value just under the ceiling does not prove a pixel was unsaturated, and a patch of genuinely clipped highlights reads a little spread of values, not one flat number. Anything that must know what saturated (HDR-merge pixel rejection, highlight reconstruction, clipping warnings) has to threshold a few $\sigma_r$ below $\mathrm{DN}_{\max}$, never exactly at it.

💡 Big lesson (L2.45) — the full noise model is Poisson, then clip, then Gaussian, then clip

A single measured value is built in four stages, in the order the sensor applies them: (1) Poisson photon shot noise, whose variance equals its mean, the irreducible floor; (2) saturation at the well, a hard clip of the electron count at the full-well capacity; (3) additive Gaussian read noise, the electronics' contribution, applied after the charge is held; and (4) the ADC clip to $[0,\mathrm{DN}_{\max}]$, after gain and the black-level pedestal. Do it in electrons, the only unit in which shot noise is exactly Poisson. The tidy affine Gaussian ($\sigma^2=a\,I+b$) is just the well-exposed limit of this recipe with the Poisson shape and both clips dropped, which is why it matches in the midtones and parts from the truth in the deep shadows (skewed, floored) and at saturation (a soft, spread-out ceiling). The order matters: because read noise lands between the two clips, saturated highlights do not pile up as a clean spike (see the two clipping lessons above). Get it right and you reproduce real noise; get it wrong and your simulator, training data, or denoiser is fitting a sensor that does not exist.

fig-noise-distribution-regimes
Figure 2.8.10 (reproduced). Four regimes of the real measured-value distribution, from the one recipe $\mathrm{clip}(\min(\mathrm{Poisson}, \text{well}) + \text{read noise},\, 0,\, \text{well})$ at four signal levels (normalized so 1 = full well). Near black it is Poisson-skewed and truncated, with a hard spike at black where the negative half of the read noise is clipped away, nothing like a Gaussian. In the midtone it is an almost pure Gaussian, clipping neither end. Near saturation the read noise, added after the charge already saturated at the well, smears the top and starts piling pixels at the maximum. And far over the well (mean 10×) the charge is pinned at the well, so read noise alone spreads the read-out: about half the pixels read strictly below full scale and look perfectly unclipped, even though every one of them was massively over-exposed. The affine-Gaussian model is a good fit only in the midtone.
💡 Big lesson (L2.46) — dynamic range = full-well capacity ÷ noise floor

A single exposure records from a top (the photosite's full-well capacity, where it saturates and clips to white) down to a bottom (the noise floor, the read noise that drowns the shadows). Their ratio is the dynamic range, quoted in stops. That floor is not absolute: it sits wherever the SNR drops below what you deem acceptable, so, just as with depth of field and its circle of confusion, the number depends on the quality criterion you pick (SNR = 1 gives the generous engineering range; a stricter SNR gives the narrower usable one). You widen it with a bigger well (larger photosites, why a full-frame sensor out-ranges a phone) or a lower floor (cooling, lower read noise), and you beat it altogether by merging multiple exposures (HDR). This is the capture-side companion to the quantization lesson below: what bounds a single shot is this range, full-well over floor, not the number of bits.

💡 Big lesson (L2.47) — quantization is rarely the real problem

With enough bits and a sane encoding, what limits image quality is noise and dynamic range (the two quantities of this section), not the number of levels the analog-to-digital converter (ADC) offers. The noise floor and the full well bound what you can record; the quantization step, once it sits below the noise, is invisible. (Indeed, a little noise dithers the quantization, hiding it further.) Levels matter in one place: banding in the deep shadows of a linearly-encoded image, too few codes where the eye, working in ratios, is most sensitive, and that is exactly the problem gamma encoding exists to solve, by spending code levels perceptually (Chapter 4.1, Color space 101). So "rarely" is not "never." We meet this lesson again in BASIC → Image representation → Float vs 8-bit, where floats with headroom are the sane default.

fig-noise-vs-quantization
Figure 2.8.17 (reproduced). The quantization step against the noise it has to beat (interactive). Both are standard deviations in the same units, so they can be compared directly: photon noise is Poisson, so $\sigma=\sqrt{S+r^2}$ electrons at a signal of $S$ electrons with read noise $r$, while one code step contributes $\sigma_q=\text{step}/\sqrt{12}$. The bars are the code steps and their width is the step itself, uniform under $\gamma=1$, squeezed into the shadows as $\gamma$ rises. Where a bar pokes above the noise curve, quantization is adding something the sensor was not already contributing; everywhere else it is buried, and the noise dithers it away. The scenario buttons set plausible hardware: a 14-bit linear raw from a good mirrorless, an 8-bit gamma-encoded JPEG from the same camera, and an 8-bit phone file whose pixel holds an order of magnitude fewer electrons. In the first three every step sits under the noise. Only 8-bit linear crosses, and only in the deepest shadows, the one place the lesson allows for, and exactly what gamma encoding exists to fix. Read noise, full well, bit depth and gamma are all adjustable, and the vertical axis can be read in electrons, as a fraction of the well, or in JNDs.