Sensor/detector DNs

This commit is contained in:
connor committed 2026-10-14 17:05:21 -04:00
1 parent da1d41d7f3
commit 32cc17a622
10 files changed
+532 -56

No files matched your search

+29 -3
View File
@@ -242,7 +242,7 @@ the channel count generic for that reason.
## From radiance to electrons: the camera equation
Code: `radiometry.rs` (`Radiometry::electrons`); the sensor pass, #9.
Code: `radiometry.rs` (`Radiometry::electrons`); `gpu/sensor.rs`, `shaders/sensor.wgsl`.
A lens with focal length f and aperture diameter D has f-number
N = f / D. The example camera is f/4: a 50 mm lens with a 12.5 mm aperture.
@@ -282,7 +282,7 @@ For the example camera, pi * A * t / (4 N^2) is 1.48e-16 m^2 sr s.
## From electrons to DN: the detector
Code: `camera.rs` (`Detector`); the sensor pass, #9.
Code: `camera.rs` (`Detector::dn`); `gpu/sensor.rs`, `shaders/sensor.wgsl`.
- **Full well.** The maximum number of electrons a pixel holds. Beyond it
the pixel saturates and reads its maximum value whatever the light.
@@ -294,7 +294,28 @@ Code: `camera.rs` (`Detector`); the sensor pass, #9.
signal does not get clipped at 0. The example uses 64 DN.
- **ADC bits.** The output resolution. 12 bits gives values 0 to 4095.
So DN = bias + electrons / gain, rounded and clipped to the ADC range.
So DN = bias + min(electrons, full well) / gain, rounded and clipped to the
ADC range. The renderer does this on the GPU for every pixel and channel,
as the last step of a frame, and reads back only the resulting integers.
Noise (M3) will enter between the electrons and the gain.
Two consequences of these numbers show up in every image:
- **Saturation is not always the ADC's maximum.** In the example camera the
full well fills first: 20,000 / 5 + 64 = 4064 DN, below the 12-bit maximum
of 4095. A saturated pixel there reads 4064. Real cameras are designed
either way, and an algorithm that detects saturation by looking for 4095
would miss it in this one.
- **Black is not zero.** A pixel that receives no light reads the bias,
64 DN, so empty space in a raw frame displays as dark gray.
Raw frames are also not white-balanced. The camera reports what each
channel collected, and the channels collect different amounts from the same
gray surface. In the example camera, sunlight on a gray surface gives about
15 % fewer electrons in blue than in red, so gray things look slightly
yellow-green in a raw image. A white balance step, applied after capture,
would scale the channels to make them equal. The renderer leaves it out,
because it simulates what the sensor records.
### Worked example
@@ -308,6 +329,11 @@ checks the green figure.)
- The full well is 20,000 electrons, so this surface is at 56 % of
saturation.
- Earth, with albedo near 0.3, reads about 64 + 3,342 / 5, about 732 DN.
- The same white surface at the image corner, 6.9 degrees off axis, gets
cos^4 of that, 97 %: 10,819 electrons, 2228 DN.
The sensor tests check the 2292, 2228, 732, 4064 and 64 DN figures
exactly, on the GPU and on lavapipe.
Picking the exposure time is the same trade a photographer makes. A longer
exposure saturates the sunlit target. A shorter one leaves the side of the