Added spectrum and camera specs
This commit is contained in:
1 parent
114b03740a
commit
3eb7ec4808
9 files changed
+714
-1
No files matched your search
+267
@@ -0,0 +1,267 @@
|
||||
# Optics and radiometry guide
|
||||
|
||||
This explains the physics the renderer models, for a reader who knows
|
||||
orbital mechanics but not optics. Each section says which code implements
|
||||
it. When a feature adds a new optical effect, it adds or updates a section
|
||||
here in the same change.
|
||||
|
||||
Numbers in the examples come from `CameraConfig::example()` unless stated
|
||||
otherwise: 1920 x 1080 pixels, 5.5 um pitch, 50 mm focal length, f/4, three
|
||||
color channels, 12-bit output.
|
||||
|
||||
## The chain from Sun to number
|
||||
|
||||
Every pixel value comes from the same sequence:
|
||||
|
||||
1. The Sun emits power across a range of wavelengths.
|
||||
2. Some of it lands on a surface (Earth, the Moon, the target), which
|
||||
reflects part of it in various directions.
|
||||
3. The fraction reflected toward the camera enters the lens aperture. The
|
||||
optics focus it onto one pixel, losing a little to absorption.
|
||||
4. The pixel converts some of the arriving photons into electrons. The
|
||||
fraction depends on wavelength and on the color filter over that pixel.
|
||||
5. The electrons pile up during the exposure, up to a limit.
|
||||
6. The readout electronics turn the electron count into an integer, the
|
||||
digital number (DN).
|
||||
|
||||
The renderer follows this chain with physical units at every step. Image
|
||||
brightness therefore comes from the scene and the camera settings, not from
|
||||
a tuned scale factor. Change the exposure time, and the image changes
|
||||
exactly as a real camera's would.
|
||||
|
||||
## Geometry: the pinhole camera
|
||||
|
||||
Code: `camera.rs` (`Intrinsics`), `scene.rs`.
|
||||
|
||||
A pinhole camera maps each direction in space to one point on the focal
|
||||
plane. Put the pinhole at the origin, looking along +Z. A point at camera
|
||||
coordinates (x, y, z) lands on the focal plane at (f x / z, f y / z), where
|
||||
f is the focal length. Dividing by the pixel pitch p converts focal-plane
|
||||
distance to pixels:
|
||||
|
||||
```text
|
||||
u = (f / p) * x / z + cx
|
||||
v = (f / p) * y / z + cy
|
||||
```
|
||||
|
||||
`f / p` is the focal length in pixels. (cx, cy) is the principal point,
|
||||
where the boresight hits the image, normally the image center. For the
|
||||
example camera, f / p = 50 mm / 5.5 um = 9091 pixels.
|
||||
|
||||
Some quantities that follow from that:
|
||||
|
||||
- **IFOV, the instantaneous field of view.** The angle one pixel covers:
|
||||
p / f = 110 microradians. At 10 m that is 1.1 mm per pixel; at 7000 km
|
||||
it is 770 m per pixel. This sets the smallest detail the camera can
|
||||
resolve.
|
||||
- **FOV, the field of view.** The angle the whole image covers:
|
||||
2 atan(width / 2 / (f / p)), about 12.1 x 6.8 degrees here. A longer
|
||||
focal length or smaller sensor gives a narrower field of view and finer
|
||||
IFOV.
|
||||
|
||||
Real lenses are not perfect pinholes. They bend straight lines slightly
|
||||
(distortion, planned in M3) and spread each point into a small blur (the
|
||||
point spread function, also M3). The pinhole model is the starting point
|
||||
those effects are added to.
|
||||
|
||||
### Coordinate conventions
|
||||
|
||||
The camera frame has +Z along the boresight, +X toward increasing column u,
|
||||
and +Y toward increasing row v. This is the computer-vision convention: row
|
||||
0 is the top of the image, so +Y points down in the picture. Pixel (i, j)
|
||||
covers u in [i, i+1) and v in [j, j+1), so its center is at (i + 0.5,
|
||||
j + 0.5).
|
||||
|
||||
### Why the GPU sees camera-relative coordinates
|
||||
|
||||
GPUs compute in 32-bit floats, which carry about 7 significant digits. A
|
||||
spacecraft 7000 km from Earth's center, stored in Earth-centered f32
|
||||
coordinates, can only be placed to the nearest 0.5 m. A target 10 m away
|
||||
would jitter by several pixels. So all positions stay in 64-bit floats on
|
||||
the CPU. They are made relative to the camera there, and converted to
|
||||
32-bit only after that. A target 10 m from the camera is then placed to
|
||||
about a micrometer.
|
||||
|
||||
### Depth
|
||||
|
||||
When two things overlap in the image, the nearer one must win. The GPU
|
||||
keeps a depth value per pixel for this. The renderer stores near / z,
|
||||
which is 1 at the near clip distance and falls toward 0 with distance.
|
||||
Combined with how floating-point numbers are spaced, this gives roughly the
|
||||
same relative precision at every distance. That matters in a scene that
|
||||
contains a 10 m target, Earth at thousands of kilometers, and the Sun at
|
||||
150 million kilometers. The scheme is called reversed-Z with an infinite
|
||||
far plane.
|
||||
|
||||
## Radiometric quantities
|
||||
|
||||
Code: `spectrum.rs` now; `radiometry.rs` in #4.
|
||||
|
||||
Light has a few distinct measures, and the camera measures a specific one.
|
||||
|
||||
- **Irradiance, E, in W/m^2.** Power arriving per unit area of a surface.
|
||||
Sunlight at 1 AU delivers about 1361 W/m^2 to a surface facing the Sun.
|
||||
It falls off with the square of the distance from the Sun. A surface
|
||||
tilted by angle theta from the Sun direction receives E cos(theta).
|
||||
- **Solid angle, in steradians (sr).** The 2D version of an angle: the area
|
||||
a cone cuts out of a unit sphere. The full sphere is 4 pi sr. One pixel
|
||||
of the example camera covers (110 urad)^2, about 1.2e-8 sr.
|
||||
- **Radiance, L, in W/m^2/sr.** Power per unit area per unit solid angle,
|
||||
traveling in a particular direction. It is what a camera pixel responds
|
||||
to: how bright a surface looks from a given direction.
|
||||
|
||||
Radiance has a property that explains a lot of what a camera sees: it does
|
||||
not change along a ray through empty space. Move a camera twice as far from
|
||||
a wall, and each pixel sees four times as much wall area. But each square
|
||||
meter now contributes a quarter of the power, so the pixel value is
|
||||
unchanged. An object that covers many pixels has the same surface
|
||||
brightness at any distance; it just covers fewer pixels farther away.
|
||||
|
||||
That stops being true once the object is smaller than a pixel. The pixel
|
||||
then also sees dark space around the object, so the signal falls as one
|
||||
over distance squared. That is the regime of a distant satellite seen as a
|
||||
point (space situational awareness), as opposed to the resolved imagery
|
||||
this renderer is mostly for.
|
||||
|
||||
### Reflection: albedo and Lambertian surfaces
|
||||
|
||||
A Lambertian surface reflects light equally in every direction. Matte
|
||||
paint, the Moon (roughly) and cloud tops behave close to this. If such a
|
||||
surface receives irradiance E and reflects a fraction rho (its albedo), its
|
||||
radiance in every direction is:
|
||||
|
||||
```text
|
||||
L = rho * E / pi
|
||||
```
|
||||
|
||||
The pi comes from integrating the reflected radiance over the hemisphere
|
||||
above the surface. A white Lambertian sheet facing the Sun at 1 AU, with
|
||||
rho = 1, has a radiance of about 1361 / pi = 433 W/m^2/sr, summed over all
|
||||
wavelengths. Earth's average albedo is about 0.3.
|
||||
|
||||
Real spacecraft surfaces are not Lambertian. Multilayer insulation (MLI)
|
||||
and solar cells are partly mirror-like and produce bright glints at
|
||||
particular angles. These are modeled by a BRDF, a function giving reflected
|
||||
radiance for every pair of incoming and outgoing directions. That arrives
|
||||
in M4.
|
||||
|
||||
## Wavelength: spectra, channels and photons
|
||||
|
||||
Code: `spectrum.rs` (`Spectrum`), `camera.rs` (`Channel`).
|
||||
|
||||
Everything above varies with wavelength. Sunlight peaks around 500 nm and
|
||||
extends from the ultraviolet into the infrared. Surfaces reflect different
|
||||
wavelengths differently; that is what color is. Optics transmit some
|
||||
wavelengths better than others. The sensor's sensitivity also depends on
|
||||
wavelength.
|
||||
|
||||
The renderer describes each of these as a `Spectrum`: a value as a function
|
||||
of wavelength, in meters.
|
||||
|
||||
- **Quantum efficiency (QE).** The fraction of arriving photons that become
|
||||
electrons in a pixel. A color camera puts red, green and blue filters
|
||||
over different pixels, so each channel has its own QE curve. The example
|
||||
camera uses idealized Gaussian curves centered at 620, 540 and 460 nm,
|
||||
80 nm wide at half height, peaking at 60 %.
|
||||
- **Transmission (tau).** The fraction of light the lenses pass, about 0.9
|
||||
for the example camera.
|
||||
|
||||
Detectors count photons, not energy. A photon of wavelength lambda carries
|
||||
energy h c / lambda (h is Planck's constant, c the speed of light). So one
|
||||
watt of red light delivers more photons than one watt of blue. The
|
||||
renderer converts power to photons per wavelength before applying QE.
|
||||
|
||||
### Folding spectra into per-channel constants
|
||||
|
||||
Doing all of this wavelength by wavelength for every pixel would be slow.
|
||||
Most factors do not depend on the pixel: the solar spectrum, the optics,
|
||||
and the QE curves. The renderer multiplies and integrates those over
|
||||
wavelength once, when the camera is set up. That yields a few numbers per
|
||||
channel, and the GPU only multiplies by them.
|
||||
|
||||
The cost is a small error where two spectra both vary inside one channel's
|
||||
band. An example is a surface whose reflectance changes steeply across
|
||||
green. Rendering more, narrower channels reduces that error, and the code
|
||||
keeps the channel count generic for that reason. (#4)
|
||||
|
||||
## From radiance to electrons: the camera equation
|
||||
|
||||
Code: the sensor pass, #9.
|
||||
|
||||
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.
|
||||
For a scene radiance L, the irradiance on the focal plane at the image
|
||||
center is:
|
||||
|
||||
```text
|
||||
E_image = pi * L * tau / (4 N^2)
|
||||
```
|
||||
|
||||
The aperture collects light over a solid angle proportional to (D / f)^2 =
|
||||
1 / N^2. So opening the aperture one "stop", which divides N by the square
|
||||
root of 2, doubles the light. Image irradiance is independent of distance
|
||||
for the same reason radiance is.
|
||||
|
||||
Away from the center, image irradiance falls off as cos^4(theta), where
|
||||
theta is the angle from the boresight. Two factors come from the longer
|
||||
path to the off-axis pixel. One comes from the aperture appearing
|
||||
foreshortened. One comes from light reaching the pixel at a slant. At the
|
||||
corner of the example camera, theta is 6.9 degrees, and the falloff is
|
||||
3 %. Real lenses add more falloff of their own, called vignetting.
|
||||
|
||||
The electrons a pixel collects in one channel are then:
|
||||
|
||||
```text
|
||||
electrons = E_image * (pixel area) * (exposure time) * (photons per joule) * QE
|
||||
```
|
||||
|
||||
The last two factors are wavelength-dependent and are folded together per
|
||||
channel, as described above.
|
||||
|
||||
## From electrons to DN: the detector
|
||||
|
||||
Code: `camera.rs` (`Detector`); the sensor pass, #9.
|
||||
|
||||
- **Full well.** The maximum number of electrons a pixel holds. Beyond it
|
||||
the pixel saturates and reads its maximum value whatever the light.
|
||||
Brighter scenes do not look brighter. In real sensors, excess charge can
|
||||
also spill into neighboring pixels (blooming, M3).
|
||||
- **Gain.** Electrons per DN. With a gain of 5, every 5 electrons add 1 to
|
||||
the output.
|
||||
- **Bias.** A fixed offset added to every pixel, so that noise around zero
|
||||
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.
|
||||
|
||||
### Worked example
|
||||
|
||||
Take a white Lambertian surface facing the Sun at 1 AU, seen by the example
|
||||
camera's green channel. Integrating the solar spectrum through the green QE
|
||||
curve, f/4 optics, 5.5 um pixels and a 0.1 ms exposure gives about 10,300
|
||||
electrons. That figure came from a blackbody approximation of the Sun; #4
|
||||
replaces it with the measured solar spectrum.
|
||||
|
||||
- DN = 64 + 10,300 / 5, about 2125, roughly half the 12-bit range.
|
||||
- The full well is 20,000 electrons, so this surface is at about half of
|
||||
saturation.
|
||||
- Earth, with albedo near 0.3, reads about 64 + 3,100 / 5, about 682 DN.
|
||||
|
||||
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
|
||||
target lit only by Earthshine lost in noise once noise is modeled (M3).
|
||||
|
||||
## Not modeled yet
|
||||
|
||||
| Effect | Where |
|
||||
|---|---|
|
||||
| Light from Earth and the Moon illuminating the target (Earthshine, Moonshine) | M2 |
|
||||
| Shadows the target casts on itself | M2 |
|
||||
| The Sun as a disk that is darker toward its edge (limb darkening) | M2 |
|
||||
| Lens distortion | M3 |
|
||||
| Blur from diffraction and lens imperfections (point spread function) | M3 |
|
||||
| Noise: photon shot noise, read noise, dark current, pixel-to-pixel variation | M3 |
|
||||
| Saturation spilling into neighbors (blooming) | M3 |
|
||||
| Non-Lambertian materials (BRDFs), glints | M4 |
|
||||
| Earth's atmosphere: scattering, the bright limb | M4 |
|
||||
| Motion blur, rolling shutter, stray light | M6 |
|
||||
Reference in new issue
Block a user