@photivra/engine 2.20.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +295 -1
- package/CITATION.cff +1 -1
- package/README.md +7 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +18 -0
- package/dist/capture/c2pa-embed.d.ts +116 -0
- package/dist/capture/c2pa-embed.js +493 -0
- package/dist/capture/c2pa-embed.js.map +1 -0
- package/dist/capture/dng-import.d.ts +73 -8
- package/dist/capture/dng-import.js +315 -80
- package/dist/capture/dng-import.js.map +1 -1
- package/dist/capture/dng-lens-correction-opcodes.d.ts +2 -2
- package/dist/capture/dng-lens-correction-opcodes.js +2 -2
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -1
- package/dist/capture/dng-opcodes.d.ts +96 -0
- package/dist/capture/dng-opcodes.js +391 -0
- package/dist/capture/dng-opcodes.js.map +1 -0
- package/dist/capture/dng-profile-maps.d.ts +99 -0
- package/dist/capture/dng-profile-maps.js +381 -0
- package/dist/capture/dng-profile-maps.js.map +1 -0
- package/dist/capture/dng-stage-image.d.ts +23 -0
- package/dist/capture/dng-stage-image.js +65 -0
- package/dist/capture/dng-stage-image.js.map +1 -0
- package/dist/capture/exposure-build-up-stage.d.ts +16 -0
- package/dist/capture/exposure-build-up-stage.js +4 -0
- package/dist/capture/exposure-build-up-stage.js.map +1 -0
- package/dist/capture/jpeg-xl-tiles.d.ts +22 -0
- package/dist/capture/jpeg-xl-tiles.js +151 -0
- package/dist/capture/jpeg-xl-tiles.js.map +1 -0
- package/dist/capture/lossy-jpeg.d.ts +17 -0
- package/dist/capture/lossy-jpeg.js +369 -0
- package/dist/capture/lossy-jpeg.js.map +1 -0
- package/dist/capture/native-environment-lean.d.ts +2 -1
- package/dist/capture/native-environment-lean.js +41 -73
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-tabulated.js +4 -3
- package/dist/capture/native-environment-tabulated.js.map +1 -1
- package/dist/capture/native-raw-development.d.ts +2 -1
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/capture/native-raw.d.ts +3 -2
- package/dist/capture/native-raw.js +5 -4
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/sensor-raw-producer.d.ts +4 -1
- package/dist/capture/sensor-raw-producer.js +12 -3
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/neighbor-highlight-reconstruction.d.ts +66 -0
- package/dist/color/neighbor-highlight-reconstruction.js +234 -0
- package/dist/color/neighbor-highlight-reconstruction.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +5 -0
- package/dist/color/sensor-color-development.js +7 -1
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/color/spectral-spikiness.d.ts +11 -0
- package/dist/color/spectral-spikiness.js +23 -0
- package/dist/color/spectral-spikiness.js.map +1 -0
- package/dist/core/execution-error.d.ts +21 -0
- package/dist/core/execution-error.js +12 -0
- package/dist/core/execution-error.js.map +1 -0
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/generic-lens-catalogue.d.ts +3 -2
- package/dist/equipment/generic-lens-catalogue.js +18 -5
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +32 -0
- package/dist/equipment/generic-tier-assets.js +16 -11
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/sensor-profile-body.d.ts +78 -0
- package/dist/equipment/sensor-profile-body.js +77 -0
- package/dist/equipment/sensor-profile-body.js.map +1 -0
- package/dist/equipment/sensor-profiles.d.ts +8 -0
- package/dist/equipment/sensor-profiles.js +82 -0
- package/dist/equipment/sensor-profiles.js.map +1 -0
- package/dist/facade/catalogue-lens-signal.d.ts +28 -3
- package/dist/facade/catalogue-lens-signal.js +83 -78
- package/dist/facade/catalogue-lens-signal.js.map +1 -1
- package/dist/facade/chart-radiance-batch.js +2 -1
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/defocus-image-space-provider.d.ts +7 -0
- package/dist/facade/defocus-image-space-provider.js +64 -76
- package/dist/facade/defocus-image-space-provider.js.map +1 -1
- package/dist/facade/diffraction-provider.d.ts +1 -1
- package/dist/facade/diffraction-provider.js +4 -4
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.js +39 -5
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +19 -6
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.js +25 -23
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view-normal.d.ts +15 -0
- package/dist/facade/display-view-normal.js +44 -0
- package/dist/facade/display-view-normal.js.map +1 -0
- package/dist/facade/display-view-rendering.d.ts +97 -0
- package/dist/facade/display-view-rendering.js +598 -0
- package/dist/facade/display-view-rendering.js.map +1 -0
- package/dist/facade/display-view.d.ts +37 -65
- package/dist/facade/display-view.js +152 -499
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.d.ts +3 -1
- package/dist/facade/expected-signal-setup.js +3 -3
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +47 -14
- package/dist/facade/expected-signal.js +117 -112
- package/dist/facade/expected-signal.js.map +1 -1
- package/dist/facade/exposure-build-up.d.ts +70 -0
- package/dist/facade/exposure-build-up.js +164 -0
- package/dist/facade/exposure-build-up.js.map +1 -0
- package/dist/facade/fast-methods.d.ts +1 -1
- package/dist/facade/fast-methods.js +46 -9
- package/dist/facade/fast-methods.js.map +1 -1
- package/dist/facade/generic-lens-capture.d.ts +3 -3
- package/dist/facade/generic-lens-capture.js +3 -3
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/image-plane-enable.d.ts +7 -0
- package/dist/facade/image-plane-enable.js +17 -0
- package/dist/facade/image-plane-enable.js.map +1 -0
- package/dist/facade/image-plane-lattice-data.d.ts +6 -0
- package/dist/facade/image-plane-lattice-data.js +10 -0
- package/dist/facade/image-plane-lattice-data.js.map +1 -0
- package/dist/facade/image-plane-support.d.ts +33 -0
- package/dist/facade/image-plane-support.js +11 -0
- package/dist/facade/image-plane-support.js.map +1 -0
- package/dist/facade/image-plane.d.ts +36 -0
- package/dist/facade/image-plane.js +384 -0
- package/dist/facade/image-plane.js.map +1 -0
- package/dist/facade/mixed-illumination.d.ts +108 -0
- package/dist/facade/mixed-illumination.js +174 -0
- package/dist/facade/mixed-illumination.js.map +1 -0
- package/dist/facade/on-demand-kits.d.ts +14 -0
- package/dist/facade/on-demand-kits.js +36 -0
- package/dist/facade/on-demand-kits.js.map +1 -0
- package/dist/facade/opt-in-kit.d.ts +9 -0
- package/dist/facade/opt-in-kit.js +11 -0
- package/dist/facade/opt-in-kit.js.map +1 -0
- package/dist/facade/quality-kit.d.ts +21 -0
- package/dist/facade/quality-kit.js +23 -0
- package/dist/facade/quality-kit.js.map +1 -0
- package/dist/facade/quality-paths.d.ts +22 -0
- package/dist/facade/quality-paths.js +44 -0
- package/dist/facade/quality-paths.js.map +1 -0
- package/dist/facade/representative-light-sources.d.ts +72 -0
- package/dist/facade/representative-light-sources.js +124 -0
- package/dist/facade/representative-light-sources.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +145 -4
- package/dist/facade/scene-radiance.js +50 -13
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +68 -20
- package/dist/facade/simulate-capture.js +399 -146
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +10 -12
- package/dist/facade/simulate-display-view.js +70 -53
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.d.ts +13 -1
- package/dist/gpu/chart-composite-gpu.js +48 -9
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +4 -30
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
- package/dist/gpu/display-view-composite-material-module.js +39 -13
- package/dist/gpu/display-view-composite-material-module.js.map +1 -1
- package/dist/gpu/display-view-gpu-renderer.d.ts +43 -0
- package/dist/gpu/display-view-gpu-renderer.js +134 -0
- package/dist/gpu/display-view-gpu-renderer.js.map +1 -0
- package/dist/gpu/display-view-image-material-module.d.ts +87 -0
- package/dist/gpu/display-view-image-material-module.js +361 -0
- package/dist/gpu/display-view-image-material-module.js.map +1 -0
- package/dist/gpu/display-view-image-quality.d.ts +87 -0
- package/dist/gpu/display-view-image-quality.js +625 -0
- package/dist/gpu/display-view-image-quality.js.map +1 -0
- package/dist/gpu/display-view-quality-gpu.d.ts +80 -65
- package/dist/gpu/display-view-quality-gpu.js +187 -445
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +67 -19
- package/dist/gpu/display-view-speed-gpu.js +181 -105
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/image-kernel-accelerator.js +3 -0
- package/dist/gpu/image-kernel-accelerator.js.map +1 -1
- package/dist/gpu/image-kernel-execution.d.ts +2 -13
- package/dist/gpu/image-kernel-execution.js +2 -10
- package/dist/gpu/image-kernel-execution.js.map +1 -1
- package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +8 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js +21 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
- package/dist/gpu/wgsl-display-view-coupled.d.ts +88 -0
- package/dist/gpu/wgsl-display-view-coupled.js +353 -0
- package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +33 -24
- package/dist/gpu/wgsl-display-view-quality-kernel.js +166 -146
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +19 -44
- package/dist/gpu/wgsl-display-view-speed-kernel.js +116 -18
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
- package/dist/gpu/wgsl-exact-sum.js +42 -0
- package/dist/gpu/wgsl-exact-sum.js.map +1 -0
- package/dist/index.d.ts +22 -6
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/motion/subject-motion.d.ts +66 -0
- package/dist/motion/subject-motion.js +52 -0
- package/dist/motion/subject-motion.js.map +1 -0
- package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
- package/dist/optics/generic-lens-lateral-color.js +77 -0
- package/dist/optics/generic-lens-lateral-color.js.map +1 -0
- package/dist/optics/generic-lens-psf.js +54 -46
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +7 -0
- package/dist/optics/lens-psf-profile.js +2 -1
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/output/camera-channel-response.d.ts +50 -0
- package/dist/output/camera-channel-response.js +69 -0
- package/dist/output/camera-channel-response.js.map +1 -0
- package/dist/output/developed-lens-corrections.d.ts +19 -5
- package/dist/output/developed-lens-corrections.js +28 -9
- package/dist/output/developed-lens-corrections.js.map +1 -1
- package/dist/output/generic-lens-corrections.d.ts +41 -5
- package/dist/output/generic-lens-corrections.js +52 -8
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.js +5 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/print-plan.d.ts +41 -5
- package/dist/output/print-plan.js +59 -14
- package/dist/output/print-plan.js.map +1 -1
- package/dist/output/sdr-rendering.d.ts +18 -1
- package/dist/output/sdr-rendering.js +39 -2
- package/dist/output/sdr-rendering.js.map +1 -1
- package/dist/sensor/binomial-sample.d.ts +3 -0
- package/dist/sensor/binomial-sample.js +86 -0
- package/dist/sensor/binomial-sample.js.map +1 -0
- package/dist/sensor/native-sensor-report.d.ts +10 -0
- package/dist/sensor/native-sensor-report.js +16 -0
- package/dist/sensor/native-sensor-report.js.map +1 -0
- package/dist/sensor/sensor-characteristics.d.ts +91 -13
- package/dist/sensor/sensor-characteristics.js +30 -15
- package/dist/sensor/sensor-characteristics.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +214 -4
- package/docs/QUICK_START.md +162 -8
- package/docs/USAGE.md +195 -22
- package/docs/api/capture-c2pa-embed.md +177 -0
- package/docs/api/capture-dng-import.md +86 -10
- package/docs/api/capture-dng-opcodes.md +93 -0
- package/docs/api/capture-dng-profile-maps.md +141 -0
- package/docs/api/capture-dng-stage-image.md +43 -0
- package/docs/api/capture-jpeg-xl-tiles.md +33 -0
- package/docs/api/capture-lossy-jpeg.md +41 -0
- package/docs/api/capture-native-raw-development.md +2 -1
- package/docs/api/core-execution-error.md +43 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +10 -5
- package/docs/api/equipment-sensor-profile-body.md +64 -0
- package/docs/api/equipment-sensor-profiles.md +86 -0
- package/docs/api/exports.json +460 -5
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-display-view.md +11 -15
- package/docs/api/facade-exposure-build-up.md +105 -0
- package/docs/api/facade-fast-methods.md +47 -10
- package/docs/api/facade-image-plane-enable.md +16 -0
- package/docs/api/facade-mixed-illumination.md +67 -0
- package/docs/api/facade-quality-paths.md +24 -0
- package/docs/api/facade-representative-light-sources.md +131 -0
- package/docs/api/facade-scene-radiance.md +54 -3
- package/docs/api/facade-simulate-capture.md +48 -11
- package/docs/api/facade-simulate-display-view.md +10 -12
- package/docs/api/gpu-image-kernel-execution.md +0 -36
- package/docs/api/motion-subject-motion.md +23 -0
- package/docs/api/optics-generic-lens-lateral-color.md +79 -0
- package/docs/api/output-camera-channel-response.md +55 -0
- package/docs/api/output-developed-lens-corrections.md +10 -1
- package/docs/api/output-generic-lens-corrections.md +40 -4
- package/docs/api/output-print-plan.md +35 -1
- package/docs/api/output-sdr-rendering.md +6 -1
- package/docs/api/sensor-sensor-characteristics.md +54 -2
- package/llms.txt +3 -0
- package/package.json +6 -5
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type SimulateCaptureOptions, type SimulateCaptureResult } from "./simulate-capture.js";
|
|
2
|
+
/** The most fractions one build-up takes. */
|
|
3
|
+
export declare const EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS = 64;
|
|
4
|
+
/**
|
|
5
|
+
* The first stream ID of the build-up's per-site random streams (`deriveNativeSiteStreamSeedUint32`): fraction j's photo split,
|
|
6
|
+
* dark split and readout use streams base + 3j, + 3j + 1 and + 3j + 2 (j = 0 … 63). The whole exposure keeps the ordinary
|
|
7
|
+
* streams 0 (charge) and 1 (read noise).
|
|
8
|
+
*/
|
|
9
|
+
export declare const EXPOSURE_BUILD_UP_STREAM_BASE = 1112866816;
|
|
10
|
+
/** The build-up to render with {@link simulateExposureBuildUp}. */
|
|
11
|
+
export interface SimulateExposureBuildUpOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Fractions of `exposure.shutterSeconds` to read out, strictly increasing, each above 0 and at most 1 (1 to 64 of them), for
|
|
14
|
+
* example `[0.2, 0.4, 0.6, 0.8, 1]`. A fraction of 1 is the whole exposure: `simulateCapture` of the request.
|
|
15
|
+
*/
|
|
16
|
+
fractions: readonly number[];
|
|
17
|
+
}
|
|
18
|
+
/** One readout of a build-up. */
|
|
19
|
+
export interface SimulateExposureBuildUpFrame {
|
|
20
|
+
/** The fraction of the exposure collected. */
|
|
21
|
+
fraction: number;
|
|
22
|
+
/** fraction × the request's shutter time, in s. */
|
|
23
|
+
elapsedSeconds: number;
|
|
24
|
+
/**
|
|
25
|
+
* The fraction developed as its own photo. At fraction 1 it is `simulateCapture(options)` itself, byte for byte. Below 1 it is
|
|
26
|
+
* the result of the fraction's capture (manual, the whole exposure's f-number and ISO, shutter fraction·t: its `image`, `raw`,
|
|
27
|
+
* `plan` and `request`), with the build-up's counts, the `exposure.buildUp` assumption, and the whole exposure's `exposure` and
|
|
28
|
+
* `sensor` reports (the camera's settings and noise figure, not the elapsed part's).
|
|
29
|
+
*/
|
|
30
|
+
result: SimulateCaptureResult;
|
|
31
|
+
}
|
|
32
|
+
/** The readouts of {@link simulateExposureBuildUp}, in the order of `fractions`. */
|
|
33
|
+
export interface SimulateExposureBuildUpResult {
|
|
34
|
+
/** The whole exposure's shutter time, in s. */
|
|
35
|
+
shutterSeconds: number;
|
|
36
|
+
frames: readonly SimulateExposureBuildUpFrame[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Renders fractions of one exposure as one accumulating process (#534), the way a camera's live readout of a long exposure
|
|
40
|
+
* would show the light building up. Each fraction is read out and developed as its own photo.
|
|
41
|
+
*
|
|
42
|
+
* The model: photon and dark-charge arrivals at a site are Poisson processes (photon shot noise: EMVA 1288 Release 4.0,
|
|
43
|
+
* section 2, free), with any rate over time. Given the count n over [0, t] of a Poisson process with mean Λ(t), its arrival
|
|
44
|
+
* times are n independent times with distribution Λ(s)/Λ(t) on [0, t], so its count over [0, s] is Binomial(n, Λ(s)/Λ(t))
|
|
45
|
+
* (R. G. Gallager, Discrete Stochastic Processes, chapter 2, sections 2.4 and 2.5, MIT OpenCourseWare 6.262, free).
|
|
46
|
+
*
|
|
47
|
+
* The method: the whole exposure is `simulateCapture(options)` itself, with its ordinary draws and seeds. Each earlier fraction
|
|
48
|
+
* fⱼ is a capture of the same request in manual mode at the whole exposure's resolved f-number and ISO and the shutter fⱼ·t,
|
|
49
|
+
* so its expected signal at every site is integrated from the spectrum over the window [0, fⱼ·t] by the capture itself (the
|
|
50
|
+
* camera rotation, `motion.subject` and mixed lighting included, and each row's own window with a rolling shutter). Its
|
|
51
|
+
* counts are not drawn anew: going down the fractions, each site's photo and dark counts are N(fⱼ) ~ Binomial(N(fⱼ₊₁), λ(fⱼ) /
|
|
52
|
+
* λ(fⱼ₊₁)), with λ the site's expected mean in each render (after PRNU and DSNU). So every fraction's counts are Poisson with
|
|
53
|
+
* that fraction's own mean (the mean and variance of `simulateCapture` at fⱼ·t), they never decrease from one fraction to the
|
|
54
|
+
* next, and two fractions' counts covary by the earlier one's mean. Fixed-pattern noise is the sensor's own and the same in
|
|
55
|
+
* every fraction. Each fraction's charge is clipped at the full well, then read once: its own read noise (dual gain as the ISO
|
|
56
|
+
* selects), pre-ADC and ADC saturation and quantization at the ADC bit depth.
|
|
57
|
+
*
|
|
58
|
+
* The windows are nested, so the true means never decrease; the capture's temporal midpoint quadrature can still put an
|
|
59
|
+
* earlier fraction's estimate above a later one's at a site (motion blur). There the split takes probability 1 (the count is
|
|
60
|
+
* kept), and the `exposure.buildUp` assumption counts those sites (`nonMonotoneSites`): an approximation of the quadrature,
|
|
61
|
+
* not of the binomial law. Raise `sensor.temporalSampleCount` to remove them.
|
|
62
|
+
*
|
|
63
|
+
* Cost: one capture per fraction, plus about 64 bytes per native site for the chain. Exact or fast: the request's own `fast`
|
|
64
|
+
* (and the format default) applies to every fraction; the build-up adds no fast method, so with `fast: false` (the calculator's
|
|
65
|
+
* setting) every fraction is an exact capture. On screen only: formats "srgb-8" and "srgb-16" (a fraction's JPEG, PNG or DNG
|
|
66
|
+
* is refused). A fraction's realization depends on the whole `fractions` list (each step of the chain has its own streams);
|
|
67
|
+
* the same request and list always give the same frames.
|
|
68
|
+
* @returns One frame per fraction, in order.
|
|
69
|
+
*/
|
|
70
|
+
export declare function simulateExposureBuildUp(options: SimulateCaptureOptions, buildUp: SimulateExposureBuildUpOptions): Promise<SimulateExposureBuildUpResult>;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Exposure build-up (#534): fractions of one exposure, read out as it accumulates.
|
|
4
|
+
* @see docs/QUICK_START.md, "Exposure build-up".
|
|
5
|
+
*/
|
|
6
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
7
|
+
import { EXPOSURE_BUILD_UP_STAGES } from "../capture/exposure-build-up-stage.js";
|
|
8
|
+
import { sampleBinomial } from "../sensor/binomial-sample.js";
|
|
9
|
+
import { createResettableUniformStream, deriveNativeSiteStreamSeedUint32, NATIVE_SITE_READ_NOISE_STREAM_ID } from "../sensor/stochastic-seed.js";
|
|
10
|
+
import { runCapture } from "./simulate-capture.js";
|
|
11
|
+
/** The most fractions one build-up takes. */
|
|
12
|
+
export const EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS = 64;
|
|
13
|
+
/**
|
|
14
|
+
* The first stream ID of the build-up's per-site random streams (`deriveNativeSiteStreamSeedUint32`): fraction j's photo split,
|
|
15
|
+
* dark split and readout use streams base + 3j, + 3j + 1 and + 3j + 2 (j = 0 … 63). The whole exposure keeps the ordinary
|
|
16
|
+
* streams 0 (charge) and 1 (read noise).
|
|
17
|
+
*/
|
|
18
|
+
export const EXPOSURE_BUILD_UP_STREAM_BASE = 0x42550000;
|
|
19
|
+
function fail(message) { throw new InvalidConfigurationError(message); }
|
|
20
|
+
function siteRecord() {
|
|
21
|
+
return { photoMean: new Float64Array(0), darkMean: new Float64Array(0), photo: new Float64Array(0), dark: new Float64Array(0), written: new Uint8Array(0), count: 0 };
|
|
22
|
+
}
|
|
23
|
+
/** Records site `index` (growing the arrays as needed; a site computed twice writes the same values again). */
|
|
24
|
+
function record(r, index, photoMean, darkMean, photo, dark) {
|
|
25
|
+
if (index >= r.written.length) {
|
|
26
|
+
const size = Math.max(1024, 2 * r.written.length, index + 1);
|
|
27
|
+
const grow = (a) => { const b = new Float64Array(size); b.set(a); return b; };
|
|
28
|
+
r.photoMean = grow(r.photoMean);
|
|
29
|
+
r.darkMean = grow(r.darkMean);
|
|
30
|
+
r.photo = grow(r.photo);
|
|
31
|
+
r.dark = grow(r.dark);
|
|
32
|
+
const w = new Uint8Array(size);
|
|
33
|
+
w.set(r.written);
|
|
34
|
+
r.written = w;
|
|
35
|
+
}
|
|
36
|
+
if (!r.written[index]) {
|
|
37
|
+
r.written[index] = 1;
|
|
38
|
+
r.count++;
|
|
39
|
+
}
|
|
40
|
+
r.photoMean[index] = photoMean;
|
|
41
|
+
r.darkMean[index] = darkMean;
|
|
42
|
+
r.photo[index] = photo;
|
|
43
|
+
r.dark[index] = dark;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Renders fractions of one exposure as one accumulating process (#534), the way a camera's live readout of a long exposure
|
|
47
|
+
* would show the light building up. Each fraction is read out and developed as its own photo.
|
|
48
|
+
*
|
|
49
|
+
* The model: photon and dark-charge arrivals at a site are Poisson processes (photon shot noise: EMVA 1288 Release 4.0,
|
|
50
|
+
* section 2, free), with any rate over time. Given the count n over [0, t] of a Poisson process with mean Λ(t), its arrival
|
|
51
|
+
* times are n independent times with distribution Λ(s)/Λ(t) on [0, t], so its count over [0, s] is Binomial(n, Λ(s)/Λ(t))
|
|
52
|
+
* (R. G. Gallager, Discrete Stochastic Processes, chapter 2, sections 2.4 and 2.5, MIT OpenCourseWare 6.262, free).
|
|
53
|
+
*
|
|
54
|
+
* The method: the whole exposure is `simulateCapture(options)` itself, with its ordinary draws and seeds. Each earlier fraction
|
|
55
|
+
* fⱼ is a capture of the same request in manual mode at the whole exposure's resolved f-number and ISO and the shutter fⱼ·t,
|
|
56
|
+
* so its expected signal at every site is integrated from the spectrum over the window [0, fⱼ·t] by the capture itself (the
|
|
57
|
+
* camera rotation, `motion.subject` and mixed lighting included, and each row's own window with a rolling shutter). Its
|
|
58
|
+
* counts are not drawn anew: going down the fractions, each site's photo and dark counts are N(fⱼ) ~ Binomial(N(fⱼ₊₁), λ(fⱼ) /
|
|
59
|
+
* λ(fⱼ₊₁)), with λ the site's expected mean in each render (after PRNU and DSNU). So every fraction's counts are Poisson with
|
|
60
|
+
* that fraction's own mean (the mean and variance of `simulateCapture` at fⱼ·t), they never decrease from one fraction to the
|
|
61
|
+
* next, and two fractions' counts covary by the earlier one's mean. Fixed-pattern noise is the sensor's own and the same in
|
|
62
|
+
* every fraction. Each fraction's charge is clipped at the full well, then read once: its own read noise (dual gain as the ISO
|
|
63
|
+
* selects), pre-ADC and ADC saturation and quantization at the ADC bit depth.
|
|
64
|
+
*
|
|
65
|
+
* The windows are nested, so the true means never decrease; the capture's temporal midpoint quadrature can still put an
|
|
66
|
+
* earlier fraction's estimate above a later one's at a site (motion blur). There the split takes probability 1 (the count is
|
|
67
|
+
* kept), and the `exposure.buildUp` assumption counts those sites (`nonMonotoneSites`): an approximation of the quadrature,
|
|
68
|
+
* not of the binomial law. Raise `sensor.temporalSampleCount` to remove them.
|
|
69
|
+
*
|
|
70
|
+
* Cost: one capture per fraction, plus about 64 bytes per native site for the chain. Exact or fast: the request's own `fast`
|
|
71
|
+
* (and the format default) applies to every fraction; the build-up adds no fast method, so with `fast: false` (the calculator's
|
|
72
|
+
* setting) every fraction is an exact capture. On screen only: formats "srgb-8" and "srgb-16" (a fraction's JPEG, PNG or DNG
|
|
73
|
+
* is refused). A fraction's realization depends on the whole `fractions` list (each step of the chain has its own streams);
|
|
74
|
+
* the same request and list always give the same frames.
|
|
75
|
+
* @returns One frame per fraction, in order.
|
|
76
|
+
*/
|
|
77
|
+
export async function simulateExposureBuildUp(options, buildUp) {
|
|
78
|
+
if (typeof buildUp !== "object" || buildUp === null || !Array.isArray(buildUp.fractions))
|
|
79
|
+
fail("simulateExposureBuildUp needs { fractions: number[] }.");
|
|
80
|
+
for (const key of Object.keys(buildUp))
|
|
81
|
+
if (key !== "fractions")
|
|
82
|
+
fail("Unknown simulateExposureBuildUp option: " + key + ".");
|
|
83
|
+
const fractions = buildUp.fractions;
|
|
84
|
+
if (fractions.length < 1 || fractions.length > EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS)
|
|
85
|
+
fail("fractions takes 1 to " + EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS + " values.");
|
|
86
|
+
fractions.forEach((f, j) => {
|
|
87
|
+
if (typeof f !== "number" || !(f > 0 && f <= 1))
|
|
88
|
+
fail("Each fraction must be above 0 and at most 1.");
|
|
89
|
+
if (j > 0 && !(f > fractions[j - 1]))
|
|
90
|
+
fail("fractions must increase strictly.");
|
|
91
|
+
});
|
|
92
|
+
if (typeof options !== "object" || options === null)
|
|
93
|
+
fail("simulateExposureBuildUp needs the capture options.");
|
|
94
|
+
const format = options.output?.format ?? "srgb-8";
|
|
95
|
+
if (format !== "srgb-8" && format !== "srgb-16")
|
|
96
|
+
fail("simulateExposureBuildUp renders on screen: output.format \"srgb-8\" or \"srgb-16\" (a fraction's JPEG, PNG or DNG would carry the whole exposure's metadata).");
|
|
97
|
+
const seed = options.sensor?.noiseSeed ?? 1;
|
|
98
|
+
if (typeof seed !== "number" || !Number.isInteger(seed) || seed < 0 || seed > 0xffffffff)
|
|
99
|
+
fail("sensor.noiseSeed must be an integer 0-4294967295.");
|
|
100
|
+
// The whole exposure, recorded: its own draws pass through unchanged, so it is simulateCapture(options) byte for byte.
|
|
101
|
+
let above = siteRecord();
|
|
102
|
+
const attach = (stage) => (raw) => { EXPOSURE_BUILD_UP_STAGES.set(raw, stage); };
|
|
103
|
+
const recorder = { photo: 0, dark: 0, read: NATIVE_SITE_READ_NOISE_STREAM_ID,
|
|
104
|
+
split(index, photoMean, darkMean, photo, dark) { recorder.photo = photo; recorder.dark = dark; record(above, index, photoMean, darkMean, photo, dark); } };
|
|
105
|
+
const whole = await runCapture(options, "capture", attach(recorder));
|
|
106
|
+
const sites = whole.raw.codes.length;
|
|
107
|
+
if (above.count !== sites)
|
|
108
|
+
fail("simulateExposureBuildUp: the capture's sensor stage did not report every site (an unsupported render path).");
|
|
109
|
+
const { fNumber, shutterSeconds, iso } = whole.exposure.settings;
|
|
110
|
+
const results = new Map([[1, whole]]);
|
|
111
|
+
// Down the fractions: each render's own means, its counts split from the next fraction's.
|
|
112
|
+
const stream = createResettableUniformStream(), below = [...fractions].filter((f) => f < 1).reverse();
|
|
113
|
+
for (const fraction of below) {
|
|
114
|
+
const j = fractions.indexOf(fraction), current = siteRecord(), from = above;
|
|
115
|
+
let nonMonotone = 0, kept = false;
|
|
116
|
+
const split = (index, mean, upperMean, upper, which) => {
|
|
117
|
+
if (upper === 0 || mean === 0)
|
|
118
|
+
return 0;
|
|
119
|
+
if (!(mean <= upperMean)) {
|
|
120
|
+
kept = true;
|
|
121
|
+
return upper;
|
|
122
|
+
}
|
|
123
|
+
stream.reset(deriveNativeSiteStreamSeedUint32(seed, index, EXPOSURE_BUILD_UP_STREAM_BASE + 3 * j + which));
|
|
124
|
+
return sampleBinomial(upper, mean / upperMean, stream);
|
|
125
|
+
};
|
|
126
|
+
const stage = { photo: 0, dark: 0, read: EXPOSURE_BUILD_UP_STREAM_BASE + 3 * j + 2,
|
|
127
|
+
split(index, photoMean, darkMean) {
|
|
128
|
+
if (!from.written[index])
|
|
129
|
+
fail("simulateExposureBuildUp: a fraction rendered a site the whole exposure did not.");
|
|
130
|
+
kept = false;
|
|
131
|
+
stage.photo = split(index, photoMean, from.photoMean[index], from.photo[index], 0);
|
|
132
|
+
stage.dark = split(index, darkMean, from.darkMean[index], from.dark[index], 1);
|
|
133
|
+
if (kept && !current.written[index])
|
|
134
|
+
nonMonotone++;
|
|
135
|
+
record(current, index, photoMean, darkMean, stage.photo, stage.dark);
|
|
136
|
+
} };
|
|
137
|
+
const lens = (options.lens ?? {}), exposure = (options.exposure ?? {});
|
|
138
|
+
const fractionOptions = { ...options, lens: { ...lens, fNumber },
|
|
139
|
+
exposure: { mode: "manual", shutterSeconds: fraction * shutterSeconds, iso, ...(exposure.metering === undefined ? {} : { metering: exposure.metering }) } };
|
|
140
|
+
// A site computed twice in one render (a verification site, or the second pass of auto white balance) is split again with the
|
|
141
|
+
// same streams: the counts are the same.
|
|
142
|
+
let result;
|
|
143
|
+
try {
|
|
144
|
+
result = await runCapture(fractionOptions, "capture", attach(stage));
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (error instanceof Error && !(options.signal?.aborted))
|
|
148
|
+
fail("Fraction " + fraction + " (manual, " + fraction * shutterSeconds + " s): " + error.message);
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
if (current.count !== sites)
|
|
152
|
+
fail("simulateExposureBuildUp: the fraction's sensor stage did not report every site (an unsupported render path).");
|
|
153
|
+
results.set(fraction, { ...result, exposure: whole.exposure, sensor: whole.sensor, assumptions: Object.freeze([...result.assumptions, Object.freeze({
|
|
154
|
+
id: "exposure.buildUp", kind: "model", value: { fraction, fractions: [...fractions], elapsedSeconds: fraction * shutterSeconds, shutterSeconds, nonMonotoneSites: nonMonotone },
|
|
155
|
+
explanation: "Exposure build-up (#534): this fraction's expected signal is a capture at the elapsed time (manual, the whole exposure's f-number and ISO); its photo and dark counts are " +
|
|
156
|
+
"split from the next fraction's by binomial draws with p = λ(this) / λ(next) per site (the conditional law of a Poisson process), then clipped at the full well and read out " +
|
|
157
|
+
"once with this fraction's own read noise. exposure and sensor describe the whole exposure. nonMonotoneSites counts sites where the quadrature put this fraction's mean " +
|
|
158
|
+
"above the next one's (kept with probability 1; an approximation of the temporal quadrature)."
|
|
159
|
+
})]) });
|
|
160
|
+
above = current;
|
|
161
|
+
}
|
|
162
|
+
return { shutterSeconds, frames: Object.freeze(fractions.map((fraction) => ({ fraction, elapsedSeconds: fraction * shutterSeconds, result: results.get(fraction) }))) };
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=exposure-build-up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exposure-build-up.js","sourceRoot":"","sources":["../../src/facade/exposure-build-up.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAA6B,MAAM,uCAAuC,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,6BAA6B,EAAE,gCAAgC,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AACjJ,OAAO,EAAE,UAAU,EAA2D,MAAM,uBAAuB,CAAC;AAE5G,6CAA6C;AAC7C,MAAM,CAAC,MAAM,mCAAmC,GAAG,EAAE,CAAC;AACtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,UAAU,CAAC;AAiCxD,SAAS,IAAI,CAAC,OAAe,IAAW,MAAM,IAAI,yBAAyB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAIvF,SAAS,UAAU;IACjB,OAAO,EAAE,SAAS,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AACxK,CAAC;AACD,+GAA+G;AAC/G,SAAS,MAAM,CAAC,CAAa,EAAE,KAAa,EAAE,SAAiB,EAAE,QAAgB,EAAE,KAAa,EAAE,IAAY;IAC5G,IAAI,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,CAAC,CAAe,EAAgB,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1G,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/G,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;IAC3D,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AAC7G,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAA+B,EAAE,OAAuC;IACpH,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;QAAE,IAAI,CAAC,wDAAwD,CAAC,CAAC;IACzJ,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,IAAI,GAAG,KAAK,WAAW;YAAE,IAAI,CAAC,0CAA0C,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IAC9H,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,mCAAmC;QAAE,IAAI,CAAC,uBAAuB,GAAG,mCAAmC,GAAG,UAAU,CAAC,CAAC;IACrK,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAE,IAAI,CAAC,8CAA8C,CAAC,CAAC;QACtG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;YAAE,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IACH,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;QAAE,IAAI,CAAC,oDAAoD,CAAC,CAAC;IAChH,MAAM,MAAM,GAAI,OAAO,CAAC,MAA2C,EAAE,MAAM,IAAI,QAAQ,CAAC;IACxF,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,+JAA+J,CAAC,CAAC;IACvN,MAAM,IAAI,GAAI,OAAO,CAAC,MAA8C,EAAE,SAAS,IAAI,CAAC,CAAC;IACrF,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,UAAU;QAAE,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAEpJ,uHAAuH;IACvH,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,CAAC,KAA2B,EAAE,EAAE,CAAC,CAAC,GAAW,EAAQ,EAAE,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrH,MAAM,QAAQ,GAAyB,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,gCAAgC;QAChG,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,IAAI,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7J,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAA0B,CAAC;IAC9F,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;IACrC,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK;QAAE,IAAI,CAAC,6GAA6G,CAAC,CAAC;IAC/I,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACjE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAgC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAErE,0FAA0F;IAC1F,MAAM,MAAM,GAAG,6BAA6B,EAAE,EAAE,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACtG,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,UAAU,EAAE,EAAE,IAAI,GAAG,KAAK,CAAC;QAC5E,IAAI,WAAW,GAAG,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,IAAY,EAAE,SAAiB,EAAE,KAAa,EAAE,KAAY,EAAU,EAAE;YACpG,IAAI,KAAK,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,CAAC,CAAC;YACxC,IAAI,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,EAAE,CAAC;gBAAC,IAAI,GAAG,IAAI,CAAC;gBAAC,OAAO,KAAK,CAAC;YAAC,CAAC;YACxD,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,IAAI,EAAE,KAAK,EAAE,6BAA6B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;YAC3G,OAAO,cAAc,CAAC,KAAK,EAAE,IAAI,GAAG,SAAS,EAAE,MAAM,CAAC,CAAC;QACzD,CAAC,CAAC;QACF,MAAM,KAAK,GAAyB,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,6BAA6B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;YACtG,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ;gBAC9B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;oBAAE,IAAI,CAAC,iFAAiF,CAAC,CAAC;gBAClH,IAAI,GAAG,KAAK,CAAC;gBACb,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAE,EAAE,CAAC,CAAC,CAAC;gBACrF,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAE,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAE,EAAE,CAAC,CAAC,CAAC;gBACjF,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;oBAAE,WAAW,EAAE,CAAC;gBACnD,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvE,CAAC,EAAE,CAAC;QACN,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAA4B,EAAE,QAAQ,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAA4B,CAAC;QAC7H,MAAM,eAAe,GAA2B,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAiD;YACrI,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,GAAG,cAAc,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;QACvK,8HAA8H;QAC9H,yCAAyC;QACzC,IAAI,MAA6B,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,UAAU,CAAC,eAAe,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAA0B,CAAC;QAChG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;gBAAE,IAAI,CAAC,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5J,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK;YAAE,IAAI,CAAC,8GAA8G,CAAC,CAAC;QAClJ,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC;oBAClJ,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,OAAgB,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,cAAc,EAAE,QAAQ,GAAG,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE;oBACxL,WAAW,EAAE,4KAA4K;wBACvL,8KAA8K;wBAC9K,yKAAyK;wBACzK,8FAA8F;iBAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3G,KAAK,GAAG,OAAO,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,GAAG,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3K,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Exposure build-up (#534): fractions of one exposure, read out as it accumulates.\n * @see docs/QUICK_START.md, \"Exposure build-up\".\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { EXPOSURE_BUILD_UP_STAGES, type ExposureBuildUpStage } from \"../capture/exposure-build-up-stage.js\";\nimport { sampleBinomial } from \"../sensor/binomial-sample.js\";\nimport { createResettableUniformStream, deriveNativeSiteStreamSeedUint32, NATIVE_SITE_READ_NOISE_STREAM_ID } from \"../sensor/stochastic-seed.js\";\nimport { runCapture, type SimulateCaptureOptions, type SimulateCaptureResult } from \"./simulate-capture.js\";\n\n/** The most fractions one build-up takes. */\nexport const EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS = 64;\n/**\n * The first stream ID of the build-up's per-site random streams (`deriveNativeSiteStreamSeedUint32`): fraction j's photo split,\n * dark split and readout use streams base + 3j, + 3j + 1 and + 3j + 2 (j = 0 … 63). The whole exposure keeps the ordinary\n * streams 0 (charge) and 1 (read noise).\n */\nexport const EXPOSURE_BUILD_UP_STREAM_BASE = 0x42550000;\n\n/** The build-up to render with {@link simulateExposureBuildUp}. */\nexport interface SimulateExposureBuildUpOptions {\n /**\n * Fractions of `exposure.shutterSeconds` to read out, strictly increasing, each above 0 and at most 1 (1 to 64 of them), for\n * example `[0.2, 0.4, 0.6, 0.8, 1]`. A fraction of 1 is the whole exposure: `simulateCapture` of the request.\n */\n fractions: readonly number[];\n}\n\n/** One readout of a build-up. */\nexport interface SimulateExposureBuildUpFrame {\n /** The fraction of the exposure collected. */\n fraction: number;\n /** fraction × the request's shutter time, in s. */\n elapsedSeconds: number;\n /**\n * The fraction developed as its own photo. At fraction 1 it is `simulateCapture(options)` itself, byte for byte. Below 1 it is\n * the result of the fraction's capture (manual, the whole exposure's f-number and ISO, shutter fraction·t: its `image`, `raw`,\n * `plan` and `request`), with the build-up's counts, the `exposure.buildUp` assumption, and the whole exposure's `exposure` and\n * `sensor` reports (the camera's settings and noise figure, not the elapsed part's).\n */\n result: SimulateCaptureResult;\n}\n\n/** The readouts of {@link simulateExposureBuildUp}, in the order of `fractions`. */\nexport interface SimulateExposureBuildUpResult {\n /** The whole exposure's shutter time, in s. */\n shutterSeconds: number;\n frames: readonly SimulateExposureBuildUpFrame[];\n}\n\nfunction fail(message: string): never { throw new InvalidConfigurationError(message); }\n\n/** One render's per-site record: its expected photo and dark means and the counts its readout used. */\ninterface SiteRecord { photoMean: Float64Array; darkMean: Float64Array; photo: Float64Array; dark: Float64Array; written: Uint8Array; count: number }\nfunction siteRecord(): SiteRecord {\n return { photoMean: new Float64Array(0), darkMean: new Float64Array(0), photo: new Float64Array(0), dark: new Float64Array(0), written: new Uint8Array(0), count: 0 };\n}\n/** Records site `index` (growing the arrays as needed; a site computed twice writes the same values again). */\nfunction record(r: SiteRecord, index: number, photoMean: number, darkMean: number, photo: number, dark: number): void {\n if (index >= r.written.length) {\n const size = Math.max(1024, 2 * r.written.length, index + 1);\n const grow = (a: Float64Array): Float64Array => { const b = new Float64Array(size); b.set(a); return b; };\n r.photoMean = grow(r.photoMean); r.darkMean = grow(r.darkMean); r.photo = grow(r.photo); r.dark = grow(r.dark);\n const w = new Uint8Array(size); w.set(r.written); r.written = w;\n }\n if (!r.written[index]) { r.written[index] = 1; r.count++; }\n r.photoMean[index] = photoMean; r.darkMean[index] = darkMean; r.photo[index] = photo; r.dark[index] = dark;\n}\n\n/**\n * Renders fractions of one exposure as one accumulating process (#534), the way a camera's live readout of a long exposure\n * would show the light building up. Each fraction is read out and developed as its own photo.\n *\n * The model: photon and dark-charge arrivals at a site are Poisson processes (photon shot noise: EMVA 1288 Release 4.0,\n * section 2, free), with any rate over time. Given the count n over [0, t] of a Poisson process with mean Λ(t), its arrival\n * times are n independent times with distribution Λ(s)/Λ(t) on [0, t], so its count over [0, s] is Binomial(n, Λ(s)/Λ(t))\n * (R. G. Gallager, Discrete Stochastic Processes, chapter 2, sections 2.4 and 2.5, MIT OpenCourseWare 6.262, free).\n *\n * The method: the whole exposure is `simulateCapture(options)` itself, with its ordinary draws and seeds. Each earlier fraction\n * fⱼ is a capture of the same request in manual mode at the whole exposure's resolved f-number and ISO and the shutter fⱼ·t,\n * so its expected signal at every site is integrated from the spectrum over the window [0, fⱼ·t] by the capture itself (the\n * camera rotation, `motion.subject` and mixed lighting included, and each row's own window with a rolling shutter). Its\n * counts are not drawn anew: going down the fractions, each site's photo and dark counts are N(fⱼ) ~ Binomial(N(fⱼ₊₁), λ(fⱼ) /\n * λ(fⱼ₊₁)), with λ the site's expected mean in each render (after PRNU and DSNU). So every fraction's counts are Poisson with\n * that fraction's own mean (the mean and variance of `simulateCapture` at fⱼ·t), they never decrease from one fraction to the\n * next, and two fractions' counts covary by the earlier one's mean. Fixed-pattern noise is the sensor's own and the same in\n * every fraction. Each fraction's charge is clipped at the full well, then read once: its own read noise (dual gain as the ISO\n * selects), pre-ADC and ADC saturation and quantization at the ADC bit depth.\n *\n * The windows are nested, so the true means never decrease; the capture's temporal midpoint quadrature can still put an\n * earlier fraction's estimate above a later one's at a site (motion blur). There the split takes probability 1 (the count is\n * kept), and the `exposure.buildUp` assumption counts those sites (`nonMonotoneSites`): an approximation of the quadrature,\n * not of the binomial law. Raise `sensor.temporalSampleCount` to remove them.\n *\n * Cost: one capture per fraction, plus about 64 bytes per native site for the chain. Exact or fast: the request's own `fast`\n * (and the format default) applies to every fraction; the build-up adds no fast method, so with `fast: false` (the calculator's\n * setting) every fraction is an exact capture. On screen only: formats \"srgb-8\" and \"srgb-16\" (a fraction's JPEG, PNG or DNG\n * is refused). A fraction's realization depends on the whole `fractions` list (each step of the chain has its own streams);\n * the same request and list always give the same frames.\n * @returns One frame per fraction, in order.\n */\nexport async function simulateExposureBuildUp(options: SimulateCaptureOptions, buildUp: SimulateExposureBuildUpOptions): Promise<SimulateExposureBuildUpResult> {\n if (typeof buildUp !== \"object\" || buildUp === null || !Array.isArray(buildUp.fractions)) fail(\"simulateExposureBuildUp needs { fractions: number[] }.\");\n for (const key of Object.keys(buildUp)) if (key !== \"fractions\") fail(\"Unknown simulateExposureBuildUp option: \" + key + \".\");\n const fractions = buildUp.fractions;\n if (fractions.length < 1 || fractions.length > EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS) fail(\"fractions takes 1 to \" + EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS + \" values.\");\n fractions.forEach((f, j) => {\n if (typeof f !== \"number\" || !(f > 0 && f <= 1)) fail(\"Each fraction must be above 0 and at most 1.\");\n if (j > 0 && !(f > fractions[j - 1]!)) fail(\"fractions must increase strictly.\");\n });\n if (typeof options !== \"object\" || options === null) fail(\"simulateExposureBuildUp needs the capture options.\");\n const format = (options.output as { format?: unknown } | undefined)?.format ?? \"srgb-8\";\n if (format !== \"srgb-8\" && format !== \"srgb-16\") fail(\"simulateExposureBuildUp renders on screen: output.format \\\"srgb-8\\\" or \\\"srgb-16\\\" (a fraction's JPEG, PNG or DNG would carry the whole exposure's metadata).\");\n const seed = (options.sensor as { noiseSeed?: unknown } | undefined)?.noiseSeed ?? 1;\n if (typeof seed !== \"number\" || !Number.isInteger(seed) || seed < 0 || seed > 0xffffffff) fail(\"sensor.noiseSeed must be an integer 0-4294967295.\");\n\n // The whole exposure, recorded: its own draws pass through unchanged, so it is simulateCapture(options) byte for byte.\n let above = siteRecord();\n const attach = (stage: ExposureBuildUpStage) => (raw: object): void => { EXPOSURE_BUILD_UP_STAGES.set(raw, stage); };\n const recorder: ExposureBuildUpStage = { photo: 0, dark: 0, read: NATIVE_SITE_READ_NOISE_STREAM_ID,\n split(index, photoMean, darkMean, photo, dark) { recorder.photo = photo; recorder.dark = dark; record(above, index, photoMean, darkMean, photo, dark); } };\n const whole = await runCapture(options, \"capture\", attach(recorder)) as SimulateCaptureResult;\n const sites = whole.raw.codes.length;\n if (above.count !== sites) fail(\"simulateExposureBuildUp: the capture's sensor stage did not report every site (an unsupported render path).\");\n const { fNumber, shutterSeconds, iso } = whole.exposure.settings;\n const results = new Map<number, SimulateCaptureResult>([[1, whole]]);\n\n // Down the fractions: each render's own means, its counts split from the next fraction's.\n const stream = createResettableUniformStream(), below = [...fractions].filter((f) => f < 1).reverse();\n for (const fraction of below) {\n const j = fractions.indexOf(fraction), current = siteRecord(), from = above;\n let nonMonotone = 0, kept = false;\n const split = (index: number, mean: number, upperMean: number, upper: number, which: 0 | 1): number => {\n if (upper === 0 || mean === 0) return 0;\n if (!(mean <= upperMean)) { kept = true; return upper; }\n stream.reset(deriveNativeSiteStreamSeedUint32(seed, index, EXPOSURE_BUILD_UP_STREAM_BASE + 3 * j + which));\n return sampleBinomial(upper, mean / upperMean, stream);\n };\n const stage: ExposureBuildUpStage = { photo: 0, dark: 0, read: EXPOSURE_BUILD_UP_STREAM_BASE + 3 * j + 2,\n split(index, photoMean, darkMean) {\n if (!from.written[index]) fail(\"simulateExposureBuildUp: a fraction rendered a site the whole exposure did not.\");\n kept = false;\n stage.photo = split(index, photoMean, from.photoMean[index]!, from.photo[index]!, 0);\n stage.dark = split(index, darkMean, from.darkMean[index]!, from.dark[index]!, 1);\n if (kept && !current.written[index]) nonMonotone++;\n record(current, index, photoMean, darkMean, stage.photo, stage.dark);\n } };\n const lens = (options.lens ?? {}) as Record<string, unknown>, exposure = (options.exposure ?? {}) as Record<string, unknown>;\n const fractionOptions: SimulateCaptureOptions = { ...options, lens: { ...lens, fNumber } as NonNullable<SimulateCaptureOptions[\"lens\"]>,\n exposure: { mode: \"manual\", shutterSeconds: fraction * shutterSeconds, iso, ...(exposure.metering === undefined ? {} : { metering: exposure.metering as never }) } };\n // A site computed twice in one render (a verification site, or the second pass of auto white balance) is split again with the\n // same streams: the counts are the same.\n let result: SimulateCaptureResult;\n try {\n result = await runCapture(fractionOptions, \"capture\", attach(stage)) as SimulateCaptureResult;\n } catch (error) {\n if (error instanceof Error && !(options.signal?.aborted)) fail(\"Fraction \" + fraction + \" (manual, \" + fraction * shutterSeconds + \" s): \" + error.message);\n throw error;\n }\n if (current.count !== sites) fail(\"simulateExposureBuildUp: the fraction's sensor stage did not report every site (an unsupported render path).\");\n results.set(fraction, { ...result, exposure: whole.exposure, sensor: whole.sensor, assumptions: Object.freeze([...result.assumptions, Object.freeze({\n id: \"exposure.buildUp\", kind: \"model\" as const, value: { fraction, fractions: [...fractions], elapsedSeconds: fraction * shutterSeconds, shutterSeconds, nonMonotoneSites: nonMonotone },\n explanation: \"Exposure build-up (#534): this fraction's expected signal is a capture at the elapsed time (manual, the whole exposure's f-number and ISO); its photo and dark counts are \" +\n \"split from the next fraction's by binomial draws with p = λ(this) / λ(next) per site (the conditional law of a Poisson process), then clipped at the full well and read out \" +\n \"once with this fraction's own read noise. exposure and sensor describe the whole exposure. nonMonotoneSites counts sites where the quadrature put this fraction's mean \" +\n \"above the next one's (kept with probability 1; an approximation of the temporal quadrature).\" })]) });\n above = current;\n }\n return { shutterSeconds, frames: Object.freeze(fractions.map((fraction) => ({ fraction, elapsedSeconds: fraction * shutterSeconds, result: results.get(fraction)! }))) };\n}\n"]}
|
|
@@ -22,7 +22,7 @@ export interface SimulateCaptureFastMethod {
|
|
|
22
22
|
/** "fast-and-exact": both methods exist; "exact-only": the record takes `fast`, but there is no fast method yet (reports false). */
|
|
23
23
|
methods: "fast-and-exact" | "exact-only";
|
|
24
24
|
/** Where it applies. */
|
|
25
|
-
runs: readonly ("simulateCapture" | "simulateDisplayView" | "prepareDisplayView")[];
|
|
25
|
+
runs: readonly ("simulateCapture" | "simulateDisplayView" | "prepareDisplayView" | "developDngStageImage")[];
|
|
26
26
|
/** The fast method and the exact one, in words (empty for exact-only). */
|
|
27
27
|
fast: string;
|
|
28
28
|
exact: string;
|
|
@@ -3,9 +3,13 @@ const CAPTURE = "src/facade/simulate-capture.ts", VIEW = "src/facade/simulate-di
|
|
|
3
3
|
/** 2.20.0: every speed-versus-accuracy choice of the capture facade and the display view (see the module comment). */
|
|
4
4
|
export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
5
5
|
{ id: "lens.catalogue/field-grid", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture"],
|
|
6
|
-
fast: "#568: the PSF blended over a field grid
|
|
6
|
+
fast: "#568: the PSF blended over a field grid, with each site's expected electrons integrated from its taps' material spectra at use, verified per CFA phase against the exact chain",
|
|
7
7
|
exact: "the environment PSF quadrature with the PSF resolved at each query point", followsFormatDefault: true,
|
|
8
8
|
resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "fast.lens.catalogue" } },
|
|
9
|
+
{ id: "lens.catalogue/field-grid-cells", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture"],
|
|
10
|
+
fast: "#603: when the field-grid method runs on a fast request, at least 4 grid cells per field interval (2.20.0's grid), except for the measured lenses of CATALOGUE_FAST_GRID_FULL_ON_SCREEN, whose fallbacks made 4 cells slower",
|
|
11
|
+
exact: "at least 10 cells per field interval when the field-grid method runs on an exact request (lens.catalogue fast: true with an export or fast: false)", followsFormatDefault: true,
|
|
12
|
+
resolver: { file: CAPTURE, call: "catalogueFastGridSubdivisions(catalogue!.lensId, fastTop)" }, report: { assumption: "fast.lens.catalogue" } },
|
|
9
13
|
{ id: "lens.catalogue/cats-eye", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
10
14
|
fast: "#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)",
|
|
11
15
|
exact: "the cat's eye shaped at each field point (fast wides and normals)", followsFormatDefault: true,
|
|
@@ -15,13 +19,13 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
15
19
|
exact: "one zone per site: the PSF at each site centre", followsFormatDefault: true,
|
|
16
20
|
resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "view.lensPsf" } },
|
|
17
21
|
{ id: "lens.diffraction/rolling-shutter-taps", override: "lens.diffraction", methods: "fast-and-exact", runs: ["simulateCapture"],
|
|
18
|
-
fast: "#565: under rolling-shutter rotation, each PSF tap reads the scene at its own source point",
|
|
22
|
+
fast: "#565: under rolling-shutter rotation (#551: or subject motion), each PSF tap reads the scene at its own source point",
|
|
19
23
|
exact: "each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)", followsFormatDefault: true,
|
|
20
24
|
resolver: { file: CAPTURE, call: "resolveFast(diffractionFast, fastTop)" }, report: { applied: "lens.diffraction", assumption: "fast.lens.diffraction" } },
|
|
21
|
-
{ id: "
|
|
22
|
-
fast: "
|
|
23
|
-
exact: "
|
|
24
|
-
resolver: { file: CAPTURE, call: "resolveFast(
|
|
25
|
+
{ id: "lens.catalogue/rolling-shutter-taps", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture"],
|
|
26
|
+
fast: "#588: under rolling-shutter rotation, each catalogue PSF tap reads the scene at its own source point",
|
|
27
|
+
exact: "each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)", followsFormatDefault: true,
|
|
28
|
+
resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "fast.lens.catalogue" } },
|
|
25
29
|
{ id: "view.uniform-pixel-sampling", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
26
30
|
fast: "(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail",
|
|
27
31
|
exact: "the full samples per axis in every display pixel", followsFormatDefault: true,
|
|
@@ -31,9 +35,42 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
31
35
|
exact: "gpu \"off\": the CPU reference; an explicit gpu wins", followsFormatDefault: true,
|
|
32
36
|
resolver: { file: VIEW, call: "parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)" },
|
|
33
37
|
report: { field: "diagnostics.fast.execution" } },
|
|
38
|
+
{ id: "illumination/image-plane-gpu", override: "fast", methods: "fast-and-exact", runs: ["prepareDisplayView"],
|
|
39
|
+
fast: "#597: gpu \"auto\": an image-plane print under mixed lighting on WebGPU (float32, a bounded approximation): the print's Quality passes light each lattice " +
|
|
40
|
+
"point per spectral node from the light's spectra and parts (Speed requests too, without site kernels); flagged points resolved on the host",
|
|
41
|
+
exact: "gpu \"off\": the CPU reference integrates each site from the lit radiance per spectral node in float64; an explicit gpu wins", followsFormatDefault: true,
|
|
42
|
+
resolver: { file: VIEW, call: "parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)" },
|
|
43
|
+
report: { field: "diagnostics.fast.execution" } },
|
|
44
|
+
{ id: "sensor.spectralStepNanometers", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
45
|
+
fast: "#590: the default spectral step is 20 nm under any light; under a spiky one (R(20) > 0.01) sensor.spectralSpikiness notes the possible cast",
|
|
46
|
+
exact: "5 nm under a spiky light, else 20 nm (an explicit sensor.spectralStepNanometers always wins)", followsFormatDefault: true,
|
|
47
|
+
resolver: { file: CAPTURE, call: "fastTop || !spiky" }, report: { applied: "sensor.spectralStepNanometers", assumption: "sensor.spectralSpikiness" } },
|
|
34
48
|
{ id: "sensor.midGrey", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
35
49
|
fast: "#535: the mid-gray noise figure is not computed (about 0.3 ms)", exact: "result.sensor.midGrey is computed", followsFormatDefault: true,
|
|
36
50
|
resolver: { file: CAPTURE, call: "fastTop ? undefined : 0" }, report: { field: "sensor.midGrey" } },
|
|
51
|
+
{ id: "motion.subject/temporal-midpoints", override: "motion.subject", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
52
|
+
fast: "#551: with the default count and a still camera, one temporal midpoint per site of the subject's streak plus one, when that is fewer than 8",
|
|
53
|
+
exact: "the default 8 temporal midpoints (an explicit sensor.temporalSampleCount always wins)", followsFormatDefault: true,
|
|
54
|
+
resolver: { file: CAPTURE, call: "resolveFast(subjectFast, fastTop)" }, report: { applied: "motion.subject", assumption: "fast.motion.subject" } },
|
|
55
|
+
{ id: "dngImport.warpRectilinear", override: "fast", methods: "fast-and-exact", runs: ["developDngStageImage"],
|
|
56
|
+
fast: "#600: an imported DNG's WarpRectilinear opcode resampled bilinearly", exact: "cubic convolution (Keys, a = −0.75, the DNG SDK's kernel); default fast unless format names an export", followsFormatDefault: true,
|
|
57
|
+
resolver: { file: "src/capture/dng-stage-image.ts", call: "resolveFast(options.fast, fastFormatDefault(format, \"capture\"))" }, report: { field: "fast" } },
|
|
58
|
+
{ id: "output.toneCurve/view-luminance-moments", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
59
|
+
fast: "#593: a luminance tone curve's moments by an 8-point Gauss–Hermite rule in luminance where its range stays clear of L = 0 (else the full rule)",
|
|
60
|
+
exact: "a composite 4 × 16-point Gauss–Legendre rule over the luminance's ±8.5σ, split at L = 0", followsFormatDefault: true,
|
|
61
|
+
resolver: { file: CAPTURE, call: "rendering: fastTop" }, report: { assumption: "view.rendering" } },
|
|
62
|
+
{ id: "output.highlightMode.reconstruct/view-moments", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
63
|
+
fast: "#593, #601: where the reconstruct blend or the desaturation is within reach, the development chain integrated with 6 Gauss–Hermite points per axis (216 nodes)",
|
|
64
|
+
exact: "16 points per axis (4,096 nodes)", followsFormatDefault: true,
|
|
65
|
+
resolver: { file: CAPTURE, call: "rendering: fastTop" }, report: { assumption: "view.rendering" } },
|
|
66
|
+
{ id: "prepareDisplayView.gpu/view-coupled-moments", override: "fast", methods: "fast-and-exact", runs: ["prepareDisplayView"],
|
|
67
|
+
fast: "#593, #601: the WebGPU Speed and Quality kernels' coupled steps with the fast rules (8-point Gauss–Hermite in luminance; 6 points per axis for the chain), float32 within the a-priori bound",
|
|
68
|
+
exact: "the same kernels with the full rules (4 × 16 Gauss–Legendre; 16 points per axis), fast: false with an explicit gpu", followsFormatDefault: true,
|
|
69
|
+
resolver: { file: "src/gpu/wgsl-display-view-coupled.ts", call: "out[C.fast] = r.fast ? 1 : 0" }, report: { assumption: "view.rendering" } },
|
|
70
|
+
{ id: "output.highlightMode.reconstruct-neighbors/region-ratios", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
71
|
+
fast: "#602: each clipped region takes the mean color ratios of the unclipped pixels within 2 pixels of it",
|
|
72
|
+
exact: "the ratios' harmonic (Laplace) interpolation inward from the region's unclipped neighbors (successive over-relaxation)", followsFormatDefault: true,
|
|
73
|
+
resolver: { file: CAPTURE, call: "const neighborFast = fastTop" }, report: { assumption: "output.highlightMode.reconstructNeighbors" } },
|
|
37
74
|
{ id: "lens.diffraction", override: "lens.diffraction", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
38
75
|
fast: "", exact: "the diffraction kernels (a fast method only under rolling-shutter rotation, above)", followsFormatDefault: true,
|
|
39
76
|
resolver: { file: CAPTURE, call: "resolveFast(diffractionFast, fastTop)" }, report: { applied: "lens.diffraction" } },
|
|
@@ -43,8 +80,8 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
43
80
|
{ id: "sensor.pixelAperture.box", override: "sensor.pixelAperture", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
44
81
|
fast: "", exact: "the N × N midpoint rule", followsFormatDefault: true,
|
|
45
82
|
resolver: { file: CAPTURE, call: "fastInUse" }, report: { applied: "sensor.pixelAperture.box" } },
|
|
46
|
-
{ id: "output.demosaic.ahd", override: "output.demosaic", methods: "exact-only", runs: ["simulateCapture"],
|
|
47
|
-
fast: "", exact: "the AHD demosaic of the capture
|
|
48
|
-
resolver: { file: CAPTURE, call: "
|
|
83
|
+
{ id: "output.demosaic.ahd", override: "output.demosaic", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
84
|
+
fast: "", exact: "the AHD demosaic of the capture; in the display view, AHD's two linear candidates and its choice on the noise-free mosaic (2.22.0: no low-signal correction, so no fast method)", followsFormatDefault: true,
|
|
85
|
+
resolver: { file: CAPTURE, call: "[\"output.demosaic.ahd\", ahd, demosaicFast]" }, report: { applied: "output.demosaic.ahd" } }
|
|
49
86
|
]);
|
|
50
87
|
//# sourceMappingURL=fast-methods.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fast-methods.js","sourceRoot":"","sources":["../../src/facade/fast-methods.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The registry of every speed-versus-accuracy choice (#395, owner rule of 2.20.0): one entry per choice that has a fast and an\n * exact (full) method, and per option record that accepts `fast` without a fast method yet. Every entry resolves through\n * `resolveFast` and `fastFormatDefault` (fast-resolution.ts): an option record's `fast`, else the top-level `fast`, else the\n * format default (fast for \"srgb-8\", \"srgb-16\" and the display view; exact for \"dng\", \"jpeg\", \"png\" and `simulateIdealReference`).\n *\n * Data only (a root export, so developers can read which choices exist), read by `test/fast-methods-registry.test.ts`, which\n * fails when an option accepts `fast` without an entry here, an entry lacks its resolver or its report, or a format's default\n * leaves the rule. Captures and display views do not import this module (tree-shaking leaves it out of their bundles). A new\n * fast method adds its entry here and to docs/API_STYLE.md, \"Exact and fast modes\".\n * @see docs/API_STYLE.md, \"Exact and fast modes\".\n */\n\n/** One speed-versus-accuracy choice of {@link SIMULATE_CAPTURE_FAST_METHODS} (2.20.0). */\nexport interface SimulateCaptureFastMethod {\n /** A short id: the option path and, where one option has several fast methods, the method. */\n id: string;\n /**\n * The request path whose record takes the `fast` override (`allowKeys` path in simulate-capture.ts), or \"fast\" when only the\n * top-level flag sets it (a choice with no option record of its own).\n */\n override: string;\n /** \"fast-and-exact\": both methods exist; \"exact-only\": the record takes `fast`, but there is no fast method yet (reports false). */\n methods: \"fast-and-exact\" | \"exact-only\";\n /** Where it applies. */\n runs: readonly (\"simulateCapture\" | \"simulateDisplayView\" | \"prepareDisplayView\")[];\n /** The fast method and the exact one, in words (empty for exact-only). */\n fast: string;\n exact: string;\n /** Always true: no choice keeps its own default (the test checks it). */\n followsFormatDefault: true;\n /**\n * The resolver call in the source (`resolveFast(<record flag>, fastTop)`, or `fastTop` itself for a top-level choice), which the\n * test finds in the named file.\n */\n resolver: { file: string; call: string };\n /**\n * How the result reports it: the `diagnostics.fast.applied` key (true where the fast method ran), an assumption id the fast\n * method adds, or another result field. At least one; the test finds each assumption id in the source.\n */\n report: { applied?: string; assumption?: string; field?: string };\n}\n\nconst CAPTURE = \"src/facade/simulate-capture.ts\", VIEW = \"src/facade/simulate-display-view.ts\";\n\n/** 2.20.0: every speed-versus-accuracy choice of the capture facade and the display view (see the module comment). */\nexport const SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = /* @__PURE__ */ Object.freeze([\n { id: \"lens.catalogue/field-grid\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#568: the PSF blended over a field grid and tabulated expected electrons, verified per CFA phase against the exact chain\",\n exact: \"the environment PSF quadrature with the PSF resolved at each query point\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"lens.catalogue/cats-eye\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)\",\n exact: \"the cat's eye shaped at each field point (fast wides and normals)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue.catsEye\" } },\n { id: \"lens.catalogue/view-psf-zones\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#569 (H1): 64 field zones along the longer side, each with the PSF at its centre\",\n exact: \"one zone per site: the PSF at each site centre\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"view.lensPsf\" } },\n { id: \"lens.diffraction/rolling-shutter-taps\", override: \"lens.diffraction\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#565: under rolling-shutter rotation, each PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\", assumption: \"fast.lens.diffraction\" } },\n { id: \"output.demosaic.ahd/view-low-signal-correction\", override: \"output.demosaic\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"(H3) 2048 draws per correction state, applied where a pixel's linear noise exceeds 0.01\",\n exact: \"8192 draws per state, at the same 0.01 threshold\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(demosaicFast, fastTop)\" }, report: { applied: \"output.demosaic.ahd\", assumption: \"view.demosaic\" } },\n { id: \"view.uniform-pixel-sampling\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail\",\n exact: \"the full samples per axis in every display pixel\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"uniformSampling: fastTop\" }, report: { assumption: \"view.estimation\" } },\n { id: \"prepareDisplayView.gpu\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n fast: \"gpu \\\"auto\\\": WebGPU float32 where a conforming device supports the request (a bounded approximation), else the CPU reference\",\n exact: \"gpu \\\"off\\\": the CPU reference; an explicit gpu wins\", followsFormatDefault: true,\n resolver: { file: VIEW, call: \"parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)\" },\n report: { field: \"diagnostics.fast.execution\" } },\n { id: \"sensor.midGrey\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#535: the mid-gray noise figure is not computed (about 0.3 ms)\", exact: \"result.sensor.midGrey is computed\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastTop ? undefined : 0\" }, report: { field: \"sensor.midGrey\" } },\n { id: \"lens.diffraction\", override: \"lens.diffraction\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the diffraction kernels (a fast method only under rolling-shutter rotation, above)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\" } },\n { id: \"sensor.antiAliasing\", override: \"sensor.antiAliasing\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the point-splitting filter\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.antiAliasing\" } },\n { id: \"sensor.pixelAperture.box\", override: \"sensor.pixelAperture\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the N × N midpoint rule\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.pixelAperture.box\" } },\n { id: \"output.demosaic.ahd\", override: \"output.demosaic\", methods: \"exact-only\", runs: [\"simulateCapture\"],\n fast: \"\", exact: \"the AHD demosaic of the capture (a fast method only in the display view's correction, above)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(demosaicFast, fastTop)\" }, report: { applied: \"output.demosaic.ahd\" } }\n] as const satisfies readonly SimulateCaptureFastMethod[]);\n"]}
|
|
1
|
+
{"version":3,"file":"fast-methods.js","sourceRoot":"","sources":["../../src/facade/fast-methods.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The registry of every speed-versus-accuracy choice (#395, owner rule of 2.20.0): one entry per choice that has a fast and an\n * exact (full) method, and per option record that accepts `fast` without a fast method yet. Every entry resolves through\n * `resolveFast` and `fastFormatDefault` (fast-resolution.ts): an option record's `fast`, else the top-level `fast`, else the\n * format default (fast for \"srgb-8\", \"srgb-16\" and the display view; exact for \"dng\", \"jpeg\", \"png\" and `simulateIdealReference`).\n *\n * Data only (a root export, so developers can read which choices exist), read by `test/fast-methods-registry.test.ts`, which\n * fails when an option accepts `fast` without an entry here, an entry lacks its resolver or its report, or a format's default\n * leaves the rule. Captures and display views do not import this module (tree-shaking leaves it out of their bundles). A new\n * fast method adds its entry here and to docs/API_STYLE.md, \"Exact and fast modes\".\n * @see docs/API_STYLE.md, \"Exact and fast modes\".\n */\n\n/** One speed-versus-accuracy choice of {@link SIMULATE_CAPTURE_FAST_METHODS} (2.20.0). */\nexport interface SimulateCaptureFastMethod {\n /** A short id: the option path and, where one option has several fast methods, the method. */\n id: string;\n /**\n * The request path whose record takes the `fast` override (`allowKeys` path in simulate-capture.ts), or \"fast\" when only the\n * top-level flag sets it (a choice with no option record of its own).\n */\n override: string;\n /** \"fast-and-exact\": both methods exist; \"exact-only\": the record takes `fast`, but there is no fast method yet (reports false). */\n methods: \"fast-and-exact\" | \"exact-only\";\n /** Where it applies. */\n runs: readonly (\"simulateCapture\" | \"simulateDisplayView\" | \"prepareDisplayView\" | \"developDngStageImage\")[];\n /** The fast method and the exact one, in words (empty for exact-only). */\n fast: string;\n exact: string;\n /** Always true: no choice keeps its own default (the test checks it). */\n followsFormatDefault: true;\n /**\n * The resolver call in the source (`resolveFast(<record flag>, fastTop)`, or `fastTop` itself for a top-level choice), which the\n * test finds in the named file.\n */\n resolver: { file: string; call: string };\n /**\n * How the result reports it: the `diagnostics.fast.applied` key (true where the fast method ran), an assumption id the fast\n * method adds, or another result field. At least one; the test finds each assumption id in the source.\n */\n report: { applied?: string; assumption?: string; field?: string };\n}\n\nconst CAPTURE = \"src/facade/simulate-capture.ts\", VIEW = \"src/facade/simulate-display-view.ts\";\n\n/** 2.20.0: every speed-versus-accuracy choice of the capture facade and the display view (see the module comment). */\nexport const SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = /* @__PURE__ */ Object.freeze([\n { id: \"lens.catalogue/field-grid\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#568: the PSF blended over a field grid, with each site's expected electrons integrated from its taps' material spectra at use, verified per CFA phase against the exact chain\",\n exact: \"the environment PSF quadrature with the PSF resolved at each query point\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"lens.catalogue/field-grid-cells\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#603: when the field-grid method runs on a fast request, at least 4 grid cells per field interval (2.20.0's grid), except for the measured lenses of CATALOGUE_FAST_GRID_FULL_ON_SCREEN, whose fallbacks made 4 cells slower\",\n exact: \"at least 10 cells per field interval when the field-grid method runs on an exact request (lens.catalogue fast: true with an export or fast: false)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"catalogueFastGridSubdivisions(catalogue!.lensId, fastTop)\" }, report: { assumption: \"fast.lens.catalogue\" } },\n { id: \"lens.catalogue/cats-eye\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)\",\n exact: \"the cat's eye shaped at each field point (fast wides and normals)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue.catsEye\" } },\n { id: \"lens.catalogue/view-psf-zones\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#569 (H1): 64 field zones along the longer side, each with the PSF at its centre\",\n exact: \"one zone per site: the PSF at each site centre\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"view.lensPsf\" } },\n { id: \"lens.diffraction/rolling-shutter-taps\", override: \"lens.diffraction\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#565: under rolling-shutter rotation (#551: or subject motion), each PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\", assumption: \"fast.lens.diffraction\" } },\n { id: \"lens.catalogue/rolling-shutter-taps\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#588: under rolling-shutter rotation, each catalogue PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"view.uniform-pixel-sampling\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail\",\n exact: \"the full samples per axis in every display pixel\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"uniformSampling: fastTop\" }, report: { assumption: \"view.estimation\" } },\n { id: \"prepareDisplayView.gpu\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n fast: \"gpu \\\"auto\\\": WebGPU float32 where a conforming device supports the request (a bounded approximation), else the CPU reference\",\n exact: \"gpu \\\"off\\\": the CPU reference; an explicit gpu wins\", followsFormatDefault: true,\n resolver: { file: VIEW, call: \"parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)\" },\n report: { field: \"diagnostics.fast.execution\" } },\n { id: \"illumination/image-plane-gpu\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n fast: \"#597: gpu \\\"auto\\\": an image-plane print under mixed lighting on WebGPU (float32, a bounded approximation): the print's Quality passes light each lattice \" +\n \"point per spectral node from the light's spectra and parts (Speed requests too, without site kernels); flagged points resolved on the host\",\n exact: \"gpu \\\"off\\\": the CPU reference integrates each site from the lit radiance per spectral node in float64; an explicit gpu wins\", followsFormatDefault: true,\n resolver: { file: VIEW, call: \"parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)\" },\n report: { field: \"diagnostics.fast.execution\" } },\n { id: \"sensor.spectralStepNanometers\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#590: the default spectral step is 20 nm under any light; under a spiky one (R(20) > 0.01) sensor.spectralSpikiness notes the possible cast\",\n exact: \"5 nm under a spiky light, else 20 nm (an explicit sensor.spectralStepNanometers always wins)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastTop || !spiky\" }, report: { applied: \"sensor.spectralStepNanometers\", assumption: \"sensor.spectralSpikiness\" } },\n { id: \"sensor.midGrey\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#535: the mid-gray noise figure is not computed (about 0.3 ms)\", exact: \"result.sensor.midGrey is computed\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastTop ? undefined : 0\" }, report: { field: \"sensor.midGrey\" } },\n { id: \"motion.subject/temporal-midpoints\", override: \"motion.subject\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#551: with the default count and a still camera, one temporal midpoint per site of the subject's streak plus one, when that is fewer than 8\",\n exact: \"the default 8 temporal midpoints (an explicit sensor.temporalSampleCount always wins)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(subjectFast, fastTop)\" }, report: { applied: \"motion.subject\", assumption: \"fast.motion.subject\" } },\n { id: \"dngImport.warpRectilinear\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"developDngStageImage\"],\n fast: \"#600: an imported DNG's WarpRectilinear opcode resampled bilinearly\", exact: \"cubic convolution (Keys, a = −0.75, the DNG SDK's kernel); default fast unless format names an export\", followsFormatDefault: true,\n resolver: { file: \"src/capture/dng-stage-image.ts\", call: \"resolveFast(options.fast, fastFormatDefault(format, \\\"capture\\\"))\" }, report: { field: \"fast\" } },\n { id: \"output.toneCurve/view-luminance-moments\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#593: a luminance tone curve's moments by an 8-point Gauss–Hermite rule in luminance where its range stays clear of L = 0 (else the full rule)\",\n exact: \"a composite 4 × 16-point Gauss–Legendre rule over the luminance's ±8.5σ, split at L = 0\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"rendering: fastTop\" }, report: { assumption: \"view.rendering\" } },\n { id: \"output.highlightMode.reconstruct/view-moments\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#593, #601: where the reconstruct blend or the desaturation is within reach, the development chain integrated with 6 Gauss–Hermite points per axis (216 nodes)\",\n exact: \"16 points per axis (4,096 nodes)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"rendering: fastTop\" }, report: { assumption: \"view.rendering\" } },\n { id: \"prepareDisplayView.gpu/view-coupled-moments\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n fast: \"#593, #601: the WebGPU Speed and Quality kernels' coupled steps with the fast rules (8-point Gauss–Hermite in luminance; 6 points per axis for the chain), float32 within the a-priori bound\",\n exact: \"the same kernels with the full rules (4 × 16 Gauss–Legendre; 16 points per axis), fast: false with an explicit gpu\", followsFormatDefault: true,\n resolver: { file: \"src/gpu/wgsl-display-view-coupled.ts\", call: \"out[C.fast] = r.fast ? 1 : 0\" }, report: { assumption: \"view.rendering\" } },\n { id: \"output.highlightMode.reconstruct-neighbors/region-ratios\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#602: each clipped region takes the mean color ratios of the unclipped pixels within 2 pixels of it\",\n exact: \"the ratios' harmonic (Laplace) interpolation inward from the region's unclipped neighbors (successive over-relaxation)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"const neighborFast = fastTop\" }, report: { assumption: \"output.highlightMode.reconstructNeighbors\" } },\n { id: \"lens.diffraction\", override: \"lens.diffraction\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the diffraction kernels (a fast method only under rolling-shutter rotation, above)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\" } },\n { id: \"sensor.antiAliasing\", override: \"sensor.antiAliasing\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the point-splitting filter\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.antiAliasing\" } },\n { id: \"sensor.pixelAperture.box\", override: \"sensor.pixelAperture\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the N × N midpoint rule\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.pixelAperture.box\" } },\n { id: \"output.demosaic.ahd\", override: \"output.demosaic\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the AHD demosaic of the capture; in the display view, AHD's two linear candidates and its choice on the noise-free mosaic (2.22.0: no low-signal correction, so no fast method)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"[\\\"output.demosaic.ahd\\\", ahd, demosaicFast]\" }, report: { applied: \"output.demosaic.ahd\" } }\n] as const satisfies readonly SimulateCaptureFastMethod[]);\n"]}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* that never asks for one) does not load the catalogue's data or its PSF builder. It also holds the developed-image lens
|
|
4
4
|
* corrections (`output.lensCorrections`, #570) and their DNG opcodes (`output.dng.lensCorrectionOpcodes`, #587), which need a catalogue lens.
|
|
5
5
|
*/
|
|
6
|
-
export { GENERIC_LENS_EVIDENCE,
|
|
6
|
+
export { GENERIC_LENS_EVIDENCE, genericLensDistortionProfile, genericLensVignettingProfile, resolveGenericLens, simulateGenericLensFocusError } from "../equipment/generic-lens-catalogue.js";
|
|
7
7
|
export { createGenericLensPsfProfile, genericLensBokehKernel, genericLensPsfKernelRadius, GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES } from "../optics/generic-lens-psf.js";
|
|
8
|
-
export { CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
9
|
-
export { applyDevelopedLensCorrection, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
8
|
+
export { catalogueFastGridSubdivisions, CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
9
|
+
export { applyDevelopedLensCorrection, channelEffectiveDispersion, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
10
10
|
export { createDngLensCorrectionOpcodes } from "../capture/dng-lens-correction-opcodes.js";
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* that never asks for one) does not load the catalogue's data or its PSF builder. It also holds the developed-image lens
|
|
5
5
|
* corrections (`output.lensCorrections`, #570) and their DNG opcodes (`output.dng.lensCorrectionOpcodes`, #587), which need a catalogue lens.
|
|
6
6
|
*/
|
|
7
|
-
export { GENERIC_LENS_EVIDENCE,
|
|
7
|
+
export { GENERIC_LENS_EVIDENCE, genericLensDistortionProfile, genericLensVignettingProfile, resolveGenericLens, simulateGenericLensFocusError } from "../equipment/generic-lens-catalogue.js";
|
|
8
8
|
export { createGenericLensPsfProfile, genericLensBokehKernel, genericLensPsfKernelRadius, GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES } from "../optics/generic-lens-psf.js";
|
|
9
|
-
export { CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
10
|
-
export { applyDevelopedLensCorrection, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
9
|
+
export { catalogueFastGridSubdivisions, CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
10
|
+
export { applyDevelopedLensCorrection, channelEffectiveDispersion, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
11
11
|
export { createDngLensCorrectionOpcodes } from "../capture/dng-lens-correction-opcodes.js";
|
|
12
12
|
//# sourceMappingURL=generic-lens-capture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-lens-capture.js","sourceRoot":"","sources":["../../src/facade/generic-lens-capture.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"generic-lens-capture.js","sourceRoot":"","sources":["../../src/facade/generic-lens-capture.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAC9L,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,8CAA8C,EAAE,MAAM,+BAA+B,CAAC;AAChL,OAAO,EAAE,6BAA6B,EAAE,qCAAqC,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvK,OAAO,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,iCAAiC,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AACtL,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * What `simulateCapture` needs for `lens.catalogue` (#549), loaded on demand: a capture without a catalogue lens (and a bundle\n * that never asks for one) does not load the catalogue's data or its PSF builder. It also holds the developed-image lens\n * corrections (`output.lensCorrections`, #570) and their DNG opcodes (`output.dng.lensCorrectionOpcodes`, #587), which need a catalogue lens.\n */\nexport { GENERIC_LENS_EVIDENCE, genericLensDistortionProfile, genericLensVignettingProfile, resolveGenericLens, simulateGenericLensFocusError } from \"../equipment/generic-lens-catalogue.js\";\nexport { createGenericLensPsfProfile, genericLensBokehKernel, genericLensPsfKernelRadius, GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES } from \"../optics/generic-lens-psf.js\";\nexport { catalogueFastGridSubdivisions, CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from \"./catalogue-lens-signal.js\";\nexport { applyDevelopedLensCorrection, channelEffectiveDispersion, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from \"../output/developed-lens-corrections.js\";\nexport { createDngLensCorrectionOpcodes } from \"../capture/dng-lens-correction-opcodes.js\";\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 2.21 (#581): enables `{ kind: "image-plane" }` scenes (a photo as a flat print, docs/IMAGE_PLANE.md) in this JavaScript realm by
|
|
3
|
+
* loading their module (a lazy chunk of about 14 KB gzip with its lattice data). Call it once, in the worker that captures, before
|
|
4
|
+
* the first request with such a scene; later calls resolve at once. A request with an image-plane scene before it fails with a
|
|
5
|
+
* message saying so.
|
|
6
|
+
*/
|
|
7
|
+
export declare function prepareImagePlaneScenes(): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* `prepareImagePlaneScenes()` (2.21, #581), in a module of its own: the dynamic import below is the only reference to the
|
|
4
|
+
* image-plane module, so a bundler includes that module (as a lazy chunk) only in bundles that import this function.
|
|
5
|
+
*/
|
|
6
|
+
import { imagePlaneSupport, setImagePlaneSupport } from "./image-plane-support.js";
|
|
7
|
+
/**
|
|
8
|
+
* 2.21 (#581): enables `{ kind: "image-plane" }` scenes (a photo as a flat print, docs/IMAGE_PLANE.md) in this JavaScript realm by
|
|
9
|
+
* loading their module (a lazy chunk of about 14 KB gzip with its lattice data). Call it once, in the worker that captures, before
|
|
10
|
+
* the first request with such a scene; later calls resolve at once. A request with an image-plane scene before it fails with a
|
|
11
|
+
* message saying so.
|
|
12
|
+
*/
|
|
13
|
+
export async function prepareImagePlaneScenes() {
|
|
14
|
+
if (!imagePlaneSupport())
|
|
15
|
+
setImagePlaneSupport(await import("./image-plane.js"));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=image-plane-enable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-plane-enable.js","sourceRoot":"","sources":["../../src/facade/image-plane-enable.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,IAAI,CAAC,iBAAiB,EAAE;QAAE,oBAAoB,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACnF,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * `prepareImagePlaneScenes()` (2.21, #581), in a module of its own: the dynamic import below is the only reference to the\n * image-plane module, so a bundler includes that module (as a lazy chunk) only in bundles that import this function.\n */\n\nimport { imagePlaneSupport, setImagePlaneSupport } from \"./image-plane-support.js\";\n\n/**\n * 2.21 (#581): enables `{ kind: \"image-plane\" }` scenes (a photo as a flat print, docs/IMAGE_PLANE.md) in this JavaScript realm by\n * loading their module (a lazy chunk of about 14 KB gzip with its lattice data). Call it once, in the worker that captures, before\n * the first request with such a scene; later calls resolve at once. A request with an image-plane scene before it fails with a\n * message saying so.\n */\nexport async function prepareImagePlaneScenes(): Promise<void> {\n if (!imagePlaneSupport()) setImagePlaneSupport(await import(\"./image-plane.js\"));\n}\n"]}
|