@photivra/engine 0.2.0 → 0.4.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 +68 -0
- package/CITATION.cff +1 -1
- package/README.md +58 -10
- package/dist/camera/equivalent-focal-length.d.ts +34 -0
- package/dist/camera/equivalent-focal-length.d.ts.map +1 -0
- package/dist/camera/equivalent-focal-length.js +33 -0
- package/dist/camera/equivalent-focal-length.js.map +1 -0
- package/dist/camera/field-of-view.d.ts +40 -3
- package/dist/camera/field-of-view.d.ts.map +1 -1
- package/dist/camera/field-of-view.js +66 -24
- package/dist/camera/field-of-view.js.map +1 -1
- package/dist/core/calculation-result.d.ts.map +1 -1
- package/dist/core/calculation-result.js +14 -2
- package/dist/core/calculation-result.js.map +1 -1
- package/dist/core/configuration-error.d.ts +9 -0
- package/dist/core/configuration-error.d.ts.map +1 -0
- package/dist/core/configuration-error.js +13 -0
- package/dist/core/configuration-error.js.map +1 -0
- package/dist/core/evidence-provenance.d.ts +40 -0
- package/dist/core/evidence-provenance.d.ts.map +1 -0
- package/dist/core/evidence-provenance.js +79 -0
- package/dist/core/evidence-provenance.js.map +1 -0
- package/dist/core/image-formation.d.ts +70 -0
- package/dist/core/image-formation.d.ts.map +1 -0
- package/dist/core/image-formation.js +335 -0
- package/dist/core/image-formation.js.map +1 -0
- package/dist/index.d.ts +15 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -3
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.d.ts +91 -0
- package/dist/motion/camera-rotation.d.ts.map +1 -0
- package/dist/motion/camera-rotation.js +157 -0
- package/dist/motion/camera-rotation.js.map +1 -0
- package/dist/optics/focus-breathing.d.ts +73 -0
- package/dist/optics/focus-breathing.d.ts.map +1 -0
- package/dist/optics/focus-breathing.js +77 -0
- package/dist/optics/focus-breathing.js.map +1 -0
- package/dist/optics/illumination-vignetting.d.ts +59 -0
- package/dist/optics/illumination-vignetting.d.ts.map +1 -0
- package/dist/optics/illumination-vignetting.js +107 -0
- package/dist/optics/illumination-vignetting.js.map +1 -0
- package/dist/optics/lateral-chromatic-aberration.d.ts +93 -0
- package/dist/optics/lateral-chromatic-aberration.d.ts.map +1 -0
- package/dist/optics/lateral-chromatic-aberration.js +174 -0
- package/dist/optics/lateral-chromatic-aberration.js.map +1 -0
- package/dist/optics/psf-foundation.d.ts +102 -0
- package/dist/optics/psf-foundation.d.ts.map +1 -0
- package/dist/optics/psf-foundation.js +164 -0
- package/dist/optics/psf-foundation.js.map +1 -0
- package/dist/optics/radial-distortion.d.ts +91 -0
- package/dist/optics/radial-distortion.d.ts.map +1 -0
- package/dist/optics/radial-distortion.js +198 -0
- package/dist/optics/radial-distortion.js.map +1 -0
- package/dist/output/capture-geometry.d.ts +225 -0
- package/dist/output/capture-geometry.d.ts.map +1 -0
- package/dist/output/capture-geometry.js +478 -0
- package/dist/output/capture-geometry.js.map +1 -0
- package/dist/schema/validation.d.ts +1 -8
- package/dist/schema/validation.d.ts.map +1 -1
- package/dist/schema/validation.js +2 -11
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/architecture.d.ts +40 -0
- package/dist/sensor/architecture.d.ts.map +1 -0
- package/dist/sensor/architecture.js +98 -0
- package/dist/sensor/architecture.js.map +1 -0
- package/dist/sensor/radiometry-readiness.d.ts +111 -0
- package/dist/sensor/radiometry-readiness.d.ts.map +1 -0
- package/dist/sensor/radiometry-readiness.js +294 -0
- package/dist/sensor/radiometry-readiness.js.map +1 -0
- package/dist/sensor/sensor-geometry.d.ts +99 -0
- package/dist/sensor/sensor-geometry.d.ts.map +1 -0
- package/dist/sensor/sensor-geometry.js +71 -0
- package/dist/sensor/sensor-geometry.js.map +1 -0
- package/dist/simulation/poc-simulation.d.ts +93 -1
- package/dist/simulation/poc-simulation.d.ts.map +1 -1
- package/dist/simulation/poc-simulation.js +308 -24
- package/dist/simulation/poc-simulation.js.map +1 -1
- package/docs/API_STYLE.md +35 -2
- package/docs/ARCHITECTURE.md +179 -1
- package/docs/IMAGE_FORMATION.md +142 -0
- package/docs/MOTION_AND_SIGNAL.md +52 -1
- package/docs/PHYSICS_FOUNDATION.md +190 -3
- package/docs/POC_API.md +73 -7
- package/docs/PROVENANCE.md +24 -0
- package/docs/PSF_FOUNDATION.md +133 -0
- package/docs/STABILIZATION.md +17 -4
- package/docs/USAGE.md +657 -3
- package/package.json +1 -1
|
@@ -14,14 +14,71 @@ where `d` is the relevant sensor dimension and `v` is the projection/image-plane
|
|
|
14
14
|
|
|
15
15
|
When no focus distance is supplied, `v = f` is the infinity-focus/pinhole compatibility approximation. When focus distance is supplied, `v` is the ideal Gaussian thin-lens image distance.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
For a centered sensor interval, the usual symmetric form is sufficient. For an off-center sensor interval, Photivra uses signed sensor-plane bounds relative to the optical axis:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
`FOV = atan(x_max / v) - atan(x_min / v)`
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
This preserves asymmetric left/right or top/bottom angular limits instead of pretending every active crop is centered.
|
|
22
|
+
|
|
23
|
+
### Sensor geometry, sampling, capture, and crop
|
|
24
|
+
|
|
25
|
+
Photivra separates physical image-formation geometry from digital sampling.
|
|
26
|
+
|
|
27
|
+
`SensorImagingArea` represents the physical photosensitive area used for image formation. It is not a sensor package/die dimension.
|
|
28
|
+
|
|
29
|
+
`NativeImageRaster` represents the effective native image-sampling grid. It does not imply that one output/image sample corresponds one-to-one with one physical photodiode. Generic active/output rasters use `RasterDimensions`.
|
|
30
|
+
|
|
31
|
+
Geometric sample pitch is derived independently on each axis:
|
|
32
|
+
|
|
33
|
+
- `pitchX = imagingWidth / nativePixelWidth`;
|
|
34
|
+
- `pitchY = imagingHeight / nativePixelHeight`.
|
|
35
|
+
|
|
36
|
+
These pitches are geometric sample spacing only. They are not fill factor, effective collection area, or photon-collection area.
|
|
37
|
+
|
|
38
|
+
The capture pipeline is staged:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
physical imaging area + native raster
|
|
42
|
+
↓
|
|
43
|
+
native active-capture rectangle
|
|
44
|
+
↓
|
|
45
|
+
physical camera orientation
|
|
46
|
+
↓
|
|
47
|
+
oriented active capture
|
|
48
|
+
↓
|
|
49
|
+
digital/output crop
|
|
50
|
+
↓
|
|
51
|
+
output raster
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Native raster coordinates use a top-left origin with +X right and +Y down. Integer rectangles are half-open. Physical camera rotation does not redefine the native coordinate system; Photivra transforms points, vectors, and rectangles explicitly between native and oriented coordinates.
|
|
55
|
+
|
|
56
|
+
For the generic sensor model, active physical dimensions and optical-axis offset are derived by assuming the native sampling grid uniformly spans the declared physical imaging area. This assumption is recorded because a future calibrated camera profile may need explicit physical active-area data instead.
|
|
57
|
+
|
|
58
|
+
An off-center active rectangle changes both retained physical extent and angular position relative to the optical axis. It must therefore use asymmetric angular bounds rather than a centered FOV formula.
|
|
59
|
+
|
|
60
|
+
For an off-center rectangular active area, the two opposite-corner diagonal angular spans need not be equal. `calculateActiveCaptureFieldOfView()` reports both and uses the larger span for its compatibility `diagonalDegrees` summary.
|
|
61
|
+
|
|
62
|
+
Output crop/resampling is digital geometry. It does not mutate physical sensor identity or active-capture geometry. Output raster aspect ratio must remain consistent with the selected output crop; implicit geometric stretching is rejected.
|
|
63
|
+
|
|
64
|
+
Centered crop dimensions are derived from a linear crop factor while preserving source aspect ratio, subject to integer pixel flooring.
|
|
22
65
|
|
|
23
66
|
Subject-height framing crop computes the additional same-aspect crop needed to target a requested subject-height fraction. It assumes the crop can be positioned around the subject and does not check subject position against image edges.
|
|
24
67
|
|
|
68
|
+
### Crop factor and 35 mm-equivalent focal length
|
|
69
|
+
|
|
70
|
+
Physical crop factor is diagonal-based relative to a 36 × 24 mm reference frame:
|
|
71
|
+
|
|
72
|
+
`cropFactor = diagonal_35mm / activeCaptureDiagonal`
|
|
73
|
+
|
|
74
|
+
Conventional 35 mm-equivalent focal length is:
|
|
75
|
+
|
|
76
|
+
`equivalentFocalLength = actualFocalLength × cropFactor`
|
|
77
|
+
|
|
78
|
+
The actual focal length remains the optical focal length. Equivalent focal length is a derived framing convention; it does not replace physical focal length in projection or depth-of-field calculations.
|
|
79
|
+
|
|
80
|
+
Photivra bases equivalence on the active physical capture area, not later digital/output crop. Physical orientation leaves the active diagonal unchanged and therefore does not change diagonal-based equivalent focal length. Different aspect ratios can still produce different horizontal/vertical FOV even when the single diagonal-equivalent number is the same.
|
|
81
|
+
|
|
25
82
|
### Projection, focus extension, object size, and motion
|
|
26
83
|
|
|
27
84
|
Field of view, projected fronto-parallel object size, projected representative-point subject motion, and camera-shake projection support two explicit projection modes:
|
|
@@ -37,18 +94,110 @@ The focus-aware model improves internal consistency with thin-lens DOF/defocus c
|
|
|
37
94
|
|
|
38
95
|
Projected subject motion is a representative-point displacement model with constant linear world velocity. It does not yet describe scale blur of an extended object whose magnification changes materially during the exposure.
|
|
39
96
|
|
|
97
|
+
### Generic illumination vignetting
|
|
98
|
+
|
|
99
|
+
The engine exposes a generic rotationally symmetric **relative linear illumination** model:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
T(rho) = 1 + r2*rho² + r4*rho⁴ + r6*rho⁶
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
where `rho` is ideal image-plane field radius divided by the caller-declared physical normalization radius.
|
|
106
|
+
|
|
107
|
+
The optical axis is normalized to `T(0) = 1`.
|
|
108
|
+
|
|
109
|
+
The declared `maximumNormalizedRadius` is a scientific operating envelope. Photivra evaluates the polynomial endpoints and all real internal extrema over the full interval and rejects profiles that:
|
|
110
|
+
|
|
111
|
+
- produce zero/negative throughput; or
|
|
112
|
+
- exceed the center-normalized throughput of 1.
|
|
113
|
+
|
|
114
|
+
The result is a linear-light multiplicative attenuation plus equivalent positive stop loss.
|
|
115
|
+
|
|
116
|
+
This slice is **not mechanical/pupil vignetting**. It does not clip the pupil or change bokeh/PSF shape. It also does not claim calibrated radiometry or named-lens behavior.
|
|
117
|
+
|
|
118
|
+
### Generic lateral chromatic aberration
|
|
119
|
+
|
|
120
|
+
The standalone lateral-CA foundation uses the green channel as the reference field mapping.
|
|
121
|
+
|
|
122
|
+
A shared base radial-distortion profile defines the common geometric lens mapping. Red and blue coefficient offsets are added to that base before each channel is mapped:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
green coefficients = base
|
|
126
|
+
red coefficients = base + red offset
|
|
127
|
+
blue coefficients = base + blue offset
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This keeps ordinary geometric distortion and lateral chromatic separation distinct while allowing one renderer pass to consume the combined per-channel mapping.
|
|
131
|
+
|
|
132
|
+
The model deliberately does **not** represent CA as finished-image RGB blur. Forward mapping reports per-channel field coordinates and vector separation; inverse mapping reports the per-channel ideal source coordinate required for one distorted destination.
|
|
133
|
+
|
|
134
|
+
All combined channel profiles share one physical normalization radius and operating envelope and must remain individually invertible.
|
|
135
|
+
|
|
136
|
+
The RGB labels are representative renderer channels only. The model does not define wavelengths, sensor CFA responses, longitudinal chromatic aberration, wavelength-dependent PSFs, or calibrated real-lens color behavior.
|
|
137
|
+
|
|
138
|
+
### Generic radial distortion
|
|
139
|
+
|
|
140
|
+
The engine includes a standalone rotationally symmetric radial field-mapping approximation:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
p_distorted = p_ideal × (1 + k1 r² + k2 r⁴ + k3 r⁶)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
where `r` is image-plane radius divided by a caller-declared physical normalization radius.
|
|
147
|
+
|
|
148
|
+
The declared `maximumNormalizedRadius` is part of the scientific contract. Photivra checks the derivative of the radial mapping over that interval and rejects profiles that are not strictly one-to-one. This makes deterministic inverse destination-to-source sampling well-defined.
|
|
149
|
+
|
|
150
|
+
The model is centered on the optical axis and does not yet include tangential/decentering terms. Coefficients are generic inputs, not real-lens calibration data.
|
|
151
|
+
|
|
152
|
+
### Declared-scale focus breathing
|
|
153
|
+
|
|
154
|
+
The root engine exposes a generic focus-breathing projection approximation.
|
|
155
|
+
|
|
156
|
+
For one selected focus state:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
effective projection distance
|
|
160
|
+
= ideal thin-lens image distance × caller-declared breathing projection scale
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Scale `1` exactly preserves the existing thin-lens projection.
|
|
164
|
+
|
|
165
|
+
The model intentionally does not infer a focus-breathing curve. It represents focus-dependent framing/magnification only when the caller supplies the scale for that state. Physical focal length remains unchanged.
|
|
166
|
+
|
|
167
|
+
This simplified scale does not model principal-plane movement, pupil magnification, distortion, aberrations, or a named commercial lens. Those require separate models and, for calibrated profiles, defensible provenance.
|
|
168
|
+
|
|
40
169
|
### Thin-lens focus and depth of field
|
|
41
170
|
|
|
42
171
|
The geometric depth-of-field model uses the conventional hyperfocal/near/far equations with a caller-supplied acceptable circle of confusion.
|
|
43
172
|
|
|
44
173
|
The circle-of-confusion criterion is a viewing/acceptability input, not a physical sensor threshold. The optional equivalent-viewing helper scales a caller-supplied reference criterion by sensor-diagonal ratio and is explicitly labeled an approximation.
|
|
45
174
|
|
|
175
|
+
In composed POC capture mode, the equivalent-viewing helper uses the final retained physical image region that will be enlarged to the assumed final viewing size. Active capture, digital output crop, and centered subject framing can therefore change the viewing criterion; output pixel resolution alone cannot. This changes only the viewing/acceptability convention, not the physical optical blur. An explicit caller-supplied `circleOfConfusionMm` is never rescaled.
|
|
176
|
+
|
|
46
177
|
The model is not a macro calibration model and does not include diffraction, pupil magnification, aberrations, focus breathing, or lens-specific principal-plane behavior in its DOF criterion.
|
|
47
178
|
|
|
48
179
|
### Defocus circle
|
|
49
180
|
|
|
50
181
|
Defocus is calculated geometrically by comparing the selected sensor plane for the focus distance with the ideal image plane for the subject distance and projecting an ideal circular entrance-pupil cone to the sensor.
|
|
51
182
|
|
|
183
|
+
### PSF/pupil foundation
|
|
184
|
+
|
|
185
|
+
The engine now exposes a PSF/pupil foundation that evaluates existing geometric defocus and circular diffraction diagnostics in one explicit context while keeping the numerical contributions separate.
|
|
186
|
+
|
|
187
|
+
The context declares:
|
|
188
|
+
|
|
189
|
+
- physical image-plane field position;
|
|
190
|
+
- a comparison-only field normalization radius;
|
|
191
|
+
- focus and subject depth;
|
|
192
|
+
- monochromatic wavelength basis;
|
|
193
|
+
- ideal circular f-number-derived pupil size.
|
|
194
|
+
|
|
195
|
+
The current foundation does **not** calculate a combined point-spread function or MTF. Defocus-circle diameter and Airy first-zero diameter are not added together or collapsed into one sharpness value.
|
|
196
|
+
|
|
197
|
+
Reserved future contributions include non-circular diffraction, mechanical pupil clipping, field curvature, field-dependent aberration structure, and field-dependent bokeh.
|
|
198
|
+
|
|
199
|
+
Illumination vignetting remains outside the PSF contribution list because it is currently modeled as throughput-only.
|
|
200
|
+
|
|
52
201
|
### Diffraction
|
|
53
202
|
|
|
54
203
|
For an ideal circular aperture, first-zero Airy diameter is:
|
|
@@ -79,6 +228,44 @@ The current model returns one global image-plane vector. It does not compute the
|
|
|
79
228
|
|
|
80
229
|
Equivalent stabilization stops attenuate angular displacement by `2^-stops`; that attenuation is explicitly an educational approximation rather than a real IBIS/OIS or CIPA performance model.
|
|
81
230
|
|
|
231
|
+
### Radiometry readiness boundary
|
|
232
|
+
|
|
233
|
+
Absolute scene luminance or relative exposure alone is not enough to derive a defensible photon count.
|
|
234
|
+
|
|
235
|
+
Before any future composed photon simulation, Photivra requires an explicit prerequisite package covering:
|
|
236
|
+
|
|
237
|
+
- scene spectral radiance or a documented spectral approximation;
|
|
238
|
+
- optical transmission;
|
|
239
|
+
- pupil/vignetting behavior;
|
|
240
|
+
- photosite collection-area semantics;
|
|
241
|
+
- exposure integration;
|
|
242
|
+
- sensor spectral response / quantum efficiency;
|
|
243
|
+
- evidence and uncertainty/limitation metadata for each component.
|
|
244
|
+
|
|
245
|
+
`assessRadiometryReadiness()` can classify a declared package as `not-ready`, `approximate-only`, or `calibrated-ready`. This classification validates the declared model/evidence structure; it does not prove that the calibration is scientifically correct and does not itself calculate photons.
|
|
246
|
+
|
|
247
|
+
Geometric sample pitch is intentionally insufficient as a collection-area model. A profile must provide either an effective collection area or geometric cell area plus explicit fill factor.
|
|
248
|
+
|
|
249
|
+
Approximate inputs remain approximate even when every prerequisite category is present. A calibrated-ready declaration requires calibrated components with quantified uncertainty.
|
|
250
|
+
|
|
251
|
+
The composed POC continues to emit no photon/photoelectron/SNR output from scene settings. Low-level `calculatePhotoelectrons()` remains a separate primitive for callers that already possess a defensible incident-photon count and QE.
|
|
252
|
+
|
|
253
|
+
## Image-formation domain boundary
|
|
254
|
+
|
|
255
|
+
Future optical and sensor models must follow `getImageFormationContract()`.
|
|
256
|
+
|
|
257
|
+
The contract intentionally avoids describing all image formation as independent serial post-processing. Some quantities are coupled:
|
|
258
|
+
|
|
259
|
+
- focus-dependent projection and lens mapping;
|
|
260
|
+
- wavelength-dependent field mapping and PSF basis;
|
|
261
|
+
- pupil clipping, throughput, and bokeh/PSF shape;
|
|
262
|
+
- time-varying scene/camera mapping and sensor readout schedule;
|
|
263
|
+
- native sensor sampling and reconstruction.
|
|
264
|
+
|
|
265
|
+
Current analytical primitives remain valid and separately named. Adding a broader stage must not silently reinterpret existing focal length, defocus, diffraction, motion, crop, or sensor-sampling outputs.
|
|
266
|
+
|
|
267
|
+
Reserved sensor stages in the contract are ordering placeholders only; they do not establish OLPF, CFA, photon, ADC, or reconstruction capabilities.
|
|
268
|
+
|
|
82
269
|
## Source provenance
|
|
83
270
|
|
|
84
271
|
These implementations were written independently from established mathematical/physical relations. No third-party source code, calibration dataset, table, or model weight is incorporated by these scientific modules.
|
package/docs/POC_API.md
CHANGED
|
@@ -50,7 +50,7 @@ Example:
|
|
|
50
50
|
{
|
|
51
51
|
"ok": true,
|
|
52
52
|
"service": "photivra-engine",
|
|
53
|
-
"apiVersion": "0.
|
|
53
|
+
"apiVersion": "0.20.0"
|
|
54
54
|
}
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -62,13 +62,48 @@ Requests must use `Content-Type: application/json`.
|
|
|
62
62
|
|
|
63
63
|
All physical quantities use explicit units in their property names.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
The POC transport reports the composed simulation contract version, not the root library `ENGINE_API_VERSION`. The current composed contract is exposed as `POC_SIMULATION_API_VERSION`.
|
|
66
|
+
|
|
67
|
+
POC simulation API 0.20 composes projection using the selected focus plane. The response includes a `projection` block with ideal thin-lens image distance, scale relative to the infinity-focus approximation, and model provenance. Full-sensor field of view, crop field of view, object sampling, subject motion, and camera-shake projection use that same selected projection plane.
|
|
68
|
+
|
|
69
|
+
### Sensor/capture composition in POC API 0.20
|
|
70
|
+
|
|
71
|
+
POC simulation API 0.20 begins composing the standalone sensor/capture foundation **additively**.
|
|
72
|
+
|
|
73
|
+
The existing request remains valid. New callers may opt into staged capture geometry with a `capture` object containing:
|
|
74
|
+
|
|
75
|
+
- physical `orientation`;
|
|
76
|
+
- optional native `activeCaptureRect`;
|
|
77
|
+
- optional oriented `outputCropRect`;
|
|
78
|
+
- optional final `outputRaster`.
|
|
79
|
+
|
|
80
|
+
Compatibility rules are intentionally strict:
|
|
81
|
+
|
|
82
|
+
- legacy `crop.factor` remains available for existing callers;
|
|
83
|
+
- when `capture` is supplied, legacy `crop.factor` must be `1` so two crop models are not silently stacked;
|
|
84
|
+
- legacy top-level `subjectCrop` response semantics remain unchanged when staged capture is absent;
|
|
85
|
+
- with staged capture, subject framing is reported under `capture.subjectFraming` and is applied after declared output crop/resampling;
|
|
86
|
+
- equivalent-viewing CoC in staged capture is based on the final retained physical image region used for viewing, including subject framing when present; output pixel count alone does not change it.
|
|
87
|
+
|
|
88
|
+
The response keeps existing full-sensor/native-vector fields intact and adds an optional `capture` block with:
|
|
89
|
+
|
|
90
|
+
- resolved native/active/oriented/output geometry, including final retained physical bounds;
|
|
91
|
+
- active-capture and final-output FOV, including asymmetric bounds for off-center capture/output crop;
|
|
92
|
+
- physical actual focal length plus active-capture diagonal-based 35 mm equivalence;
|
|
93
|
+
- explicit oriented-capture→output pixel scaling;
|
|
94
|
+
- optional capture-specific subject framing with final retained physical area and effective FOV;
|
|
95
|
+
- explicit native-raster, oriented-capture, and final-output motion-vector diagnostics;
|
|
96
|
+
- corresponding native-raster/oriented/output camera-shake vectors when camera shake is requested.
|
|
97
|
+
|
|
98
|
+
Final digital/output crop does not redefine physical focal length or active-capture 35 mm equivalence. Physical `lens.focalLengthMm` remains the optical input.
|
|
99
|
+
|
|
100
|
+
Sensor architecture metadata and radiometry-readiness profiles remain standalone foundations and are not yet composed into the POC.
|
|
66
101
|
|
|
67
102
|
### Required request groups
|
|
68
103
|
|
|
69
104
|
The request includes:
|
|
70
105
|
|
|
71
|
-
- sensor dimensions and
|
|
106
|
+
- sensor physical imaging dimensions and native effective raster;
|
|
72
107
|
- focal length and aperture;
|
|
73
108
|
- shutter duration and ISO;
|
|
74
109
|
- focus distance;
|
|
@@ -109,9 +144,33 @@ The top-level `fieldOfView` always describes the full sensor before digital crop
|
|
|
109
144
|
|
|
110
145
|
This remains ideal paraxial geometry, not a real-lens focus-breathing calibration.
|
|
111
146
|
|
|
112
|
-
###
|
|
147
|
+
### Sensor and staged capture geometry
|
|
113
148
|
|
|
114
|
-
`
|
|
149
|
+
The `sensor` response now includes the shared `SensorGeometryMetrics` result in addition to the backwards-compatible representative pitch fields. This exposes physical imaging-area crop factor, exact native-raster megapixels, and independent X/Y geometric sample pitch without treating sample pitch as photosite collection area.
|
|
150
|
+
|
|
151
|
+
When the opt-in `capture` request is present, the response additionally exposes the staged geometry pipeline:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
native physical imaging area + native raster
|
|
155
|
+
↓
|
|
156
|
+
native active-capture rectangle
|
|
157
|
+
↓
|
|
158
|
+
physical camera orientation
|
|
159
|
+
↓
|
|
160
|
+
oriented active capture
|
|
161
|
+
↓
|
|
162
|
+
digital/output crop
|
|
163
|
+
↓
|
|
164
|
+
final output raster
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Native sensor coordinates remain invariant under orientation. Active-capture FOV is calculated from the physical retained area, including off-center asymmetric angular bounds.
|
|
168
|
+
|
|
169
|
+
Legacy projected-motion/camera-shake X/Y values use the existing image-plane basis (+X right, +Y up). Capture raster coordinates use +X right, +Y down. The capture diagnostics therefore expose the explicit conversion to `nativeRasterDeltaPixels` before rotating to `orientedCaptureDeltaPixels` and scaling to `outputDeltaPixels`; legacy fields remain unchanged.
|
|
170
|
+
|
|
171
|
+
### Legacy crop
|
|
172
|
+
|
|
173
|
+
`crop` reports the requested legacy centered crop factor, retained pixel dimensions/area, megapixels, and its effective field of view.
|
|
115
174
|
|
|
116
175
|
If `subjectCrop` is requested, subject framing is composed **after** the fixed crop. The response distinguishes:
|
|
117
176
|
|
|
@@ -122,8 +181,13 @@ If `subjectCrop` is requested, subject framing is composed **after** the fixed c
|
|
|
122
181
|
|
|
123
182
|
The framing calculation assumes the crop can be positioned around the subject; it does not validate subject position against source-image edges.
|
|
124
183
|
|
|
184
|
+
### Sensor sampling
|
|
185
|
+
|
|
186
|
+
The response exposes horizontal and vertical geometric sampling pitch plus their relative difference. The composed POC still uses the backwards-compatible horizontal pitch as its representative scalar for blur/sampling calculations and therefore rejects sensor geometry whose X/Y pitch differs by more than 1%. This prevents silent directional error until the composed POC becomes fully axis-aware.
|
|
187
|
+
|
|
125
188
|
### Subject/object sampling
|
|
126
189
|
|
|
190
|
+
|
|
127
191
|
When physical subject/object dimensions are supplied, projected dimensions are returned in sensor millimetres and pixels using the focus-aware projection plane.
|
|
128
192
|
|
|
129
193
|
These values can drive pre-authored asset/detail selection without moving projection math into a renderer.
|
|
@@ -156,9 +220,11 @@ Polygon aperture geometry does not convert the circular Airy result into a polyg
|
|
|
156
220
|
|
|
157
221
|
### Focus criterion
|
|
158
222
|
|
|
159
|
-
For cross-format comparisons, the equivalent-viewing helper scales a caller-supplied reference CoC by
|
|
223
|
+
For cross-format comparisons, the equivalent-viewing helper scales a caller-supplied reference CoC by the diagonal of the physical image region assumed to be enlarged to the final viewing size.
|
|
224
|
+
|
|
225
|
+
Legacy requests continue to use the full physical sensor. In staged capture mode the target is the final physical region retained by active capture + output crop and, when requested, centered subject framing. Changing only the encoded output raster does not change this viewing criterion.
|
|
160
226
|
|
|
161
|
-
|
|
227
|
+
This remains explicitly a viewing approximation, not a physical lens/sensor blur threshold. An explicit caller-supplied `circleOfConfusionMm` is never changed by crop or output geometry.
|
|
162
228
|
|
|
163
229
|
### Primary-subject diagnostics
|
|
164
230
|
|
package/docs/PROVENANCE.md
CHANGED
|
@@ -15,6 +15,20 @@ An implementation may be based on:
|
|
|
15
15
|
|
|
16
16
|
A paper, standard, or patent publication may explain a method without granting copyright permission to copy its expression and without granting a patent license. Independent implementation addresses source-code/prose provenance; it does not by itself resolve active third-party patent claims.
|
|
17
17
|
|
|
18
|
+
## Source evidence and reuse rights
|
|
19
|
+
|
|
20
|
+
Factual/source evidence keeps **origin** separate from **reuse rights**.
|
|
21
|
+
|
|
22
|
+
- `sourceOrigin` identifies who originated the referenced fact or data: manufacturer, third party, or Photivra.
|
|
23
|
+
- `reuseStatus` identifies how Photivra may use it: factual-reference-only, reusable-data, or Photivra-owned.
|
|
24
|
+
- Reusable data requires an explicit license.
|
|
25
|
+
- Photivra-owned material must originate from Photivra.
|
|
26
|
+
- Manufacturer or third-party sources may be either factual-reference-only or explicitly reusable when licensing supports that use.
|
|
27
|
+
|
|
28
|
+
One evidence record must not silently support unrelated facts. Scalar metadata may cite multiple evidence records, and multi-valued capabilities should carry evidence per value.
|
|
29
|
+
|
|
30
|
+
Evidence provenance is not a confidence score and does not establish scientific effect by itself. Descriptive hardware facts only affect calculations when a separate documented model explicitly consumes them.
|
|
31
|
+
|
|
18
32
|
## Independent implementation
|
|
19
33
|
|
|
20
34
|
When a reference explains a method but does not license its implementation or text for reuse:
|
|
@@ -82,6 +96,16 @@ Valid-range metadata describes where a model/calibration is considered applicabl
|
|
|
82
96
|
|
|
83
97
|
When composing models, preserve uncertainty components separately unless a documented model provides a defensible combination rule. Do not imply statistical independence, add errors in quadrature, or publish a single aggregate confidence score without evidence.
|
|
84
98
|
|
|
99
|
+
## Radiometry readiness evidence
|
|
100
|
+
|
|
101
|
+
Radiometry readiness is a declaration/validation gate, not proof that a calibration is correct.
|
|
102
|
+
|
|
103
|
+
A component labeled `calibrated` must identify its model/version, supporting evidence, and quantified uncertainty. If uncertainty cannot yet be quantified, the component may still be represented, but the overall assessment cannot become `calibrated-ready`.
|
|
104
|
+
|
|
105
|
+
Data-bearing calibration artifacts are referenced by stable identifier plus SHA-256 checksum. Publicly viewable curves/tables without reuse rights must not be copied into those artifacts. Manufacturer-published factual specifications may support independently authored models, while copied calibration datasets require explicit reusable licensing or Photivra ownership.
|
|
106
|
+
|
|
107
|
+
An `approximation` remains explicitly approximate even when all prerequisite categories are present. Readiness must never be used to upgrade approximation provenance into calibration provenance.
|
|
108
|
+
|
|
85
109
|
## Release gate
|
|
86
110
|
|
|
87
111
|
Ambiguous licensing, unresolved material patent risk, uncertain provenance, unexplained copied material, fabricated uncertainty, undocumented uncertainty combination, or unsupported scientific claims block release until resolved.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# PSF and Pupil Foundation
|
|
2
|
+
|
|
3
|
+
Photivra's PSF/pupil foundation keeps optical blur contributions **separate and explicitly contextualized** until a defensible composition model exists.
|
|
4
|
+
|
|
5
|
+
Use:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import {
|
|
9
|
+
calculatePsfFoundationComponents,
|
|
10
|
+
getPsfFoundationContract
|
|
11
|
+
} from "@photivra/engine";
|
|
12
|
+
|
|
13
|
+
const contract = getPsfFoundationContract();
|
|
14
|
+
|
|
15
|
+
const components = calculatePsfFoundationComponents({
|
|
16
|
+
focalLengthMm: 85,
|
|
17
|
+
aperture: 2.8,
|
|
18
|
+
focusDistanceM: 10,
|
|
19
|
+
subjectDistanceM: 20,
|
|
20
|
+
fieldPointMm: { x: 12, y: 8 },
|
|
21
|
+
fieldNormalizationRadiusMm: 21.6,
|
|
22
|
+
spectralBasis: {
|
|
23
|
+
kind: "monochromatic",
|
|
24
|
+
wavelengthNm: 550
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What is implemented
|
|
30
|
+
|
|
31
|
+
The current foundation evaluates two existing diagnostics in one explicit context:
|
|
32
|
+
|
|
33
|
+
- **geometric defocus circle** — the existing thin-lens defocus-circle diameter;
|
|
34
|
+
- **circular diffraction first-zero diameter** — the existing ideal circular-pupil Airy diagnostic.
|
|
35
|
+
|
|
36
|
+
Each contribution retains the provenance of its underlying primitive.
|
|
37
|
+
|
|
38
|
+
The foundation records:
|
|
39
|
+
|
|
40
|
+
- physical image-plane field position;
|
|
41
|
+
- normalized field radius for comparison;
|
|
42
|
+
- focus and subject depth;
|
|
43
|
+
- monochromatic wavelength basis;
|
|
44
|
+
- ideal circular f-number-derived pupil diameter.
|
|
45
|
+
|
|
46
|
+
## What is deliberately not calculated
|
|
47
|
+
|
|
48
|
+
The foundation does **not** currently calculate:
|
|
49
|
+
|
|
50
|
+
- a combined PSF;
|
|
51
|
+
- a convolution kernel;
|
|
52
|
+
- MTF;
|
|
53
|
+
- one combined blur diameter;
|
|
54
|
+
- a lens-sharpness score.
|
|
55
|
+
|
|
56
|
+
Defocus and diffraction are independent diagnostics. A future combined PSF must document the mathematical composition method and assumptions rather than adding their diameters or scores ad hoc.
|
|
57
|
+
|
|
58
|
+
## Reserved contributions
|
|
59
|
+
|
|
60
|
+
The public contract reserves ownership for:
|
|
61
|
+
|
|
62
|
+
- non-circular diffraction;
|
|
63
|
+
- mechanical/pupil clipping;
|
|
64
|
+
- field curvature;
|
|
65
|
+
- field-dependent aberration/PSF structure;
|
|
66
|
+
- field-dependent bokeh.
|
|
67
|
+
|
|
68
|
+
A reserved contribution is not an implemented capability.
|
|
69
|
+
|
|
70
|
+
## Field position
|
|
71
|
+
|
|
72
|
+
Field position uses physical image-plane coordinates:
|
|
73
|
+
|
|
74
|
+
- optical axis at the origin;
|
|
75
|
+
- +X right;
|
|
76
|
+
- +Y up;
|
|
77
|
+
- millimetres.
|
|
78
|
+
|
|
79
|
+
`fieldNormalizationRadiusMm` exists only to make center/mid/edge/corner comparisons reproducible. It is not a real-lens calibration or model-validity limit by itself.
|
|
80
|
+
|
|
81
|
+
The current defocus and circular Airy diagnostics are field invariant. Recording field position now gives future field-dependent contributions a stable context without changing those existing calculations.
|
|
82
|
+
|
|
83
|
+
## Spectral basis
|
|
84
|
+
|
|
85
|
+
The current foundation accepts an explicit monochromatic wavelength because the circular Airy diagnostic is wavelength dependent.
|
|
86
|
+
|
|
87
|
+
This does not create:
|
|
88
|
+
|
|
89
|
+
- a spectral lens model;
|
|
90
|
+
- longitudinal chromatic aberration;
|
|
91
|
+
- sensor spectral response;
|
|
92
|
+
- CFA/color calibration.
|
|
93
|
+
|
|
94
|
+
Future wavelength-dependent PSFs must declare their basis explicitly.
|
|
95
|
+
|
|
96
|
+
## Pupil boundary
|
|
97
|
+
|
|
98
|
+
The current context records an ideal circular, f-number-derived pupil diameter because the existing defocus/Airy diagnostics use circular-pupil assumptions.
|
|
99
|
+
|
|
100
|
+
Polygon aperture geometry is not automatically a non-circular diffraction PSF.
|
|
101
|
+
|
|
102
|
+
Mechanical/pupil vignetting is also separate from illumination vignetting:
|
|
103
|
+
|
|
104
|
+
- illumination vignetting changes throughput only;
|
|
105
|
+
- pupil clipping can change throughput **and** PSF/bokeh shape.
|
|
106
|
+
|
|
107
|
+
## Preview and reference fidelity
|
|
108
|
+
|
|
109
|
+
Browser preview and higher-fidelity reference implementations may use different numerical approximations or sampling budgets.
|
|
110
|
+
|
|
111
|
+
They must preserve the same:
|
|
112
|
+
|
|
113
|
+
- contribution identities;
|
|
114
|
+
- field/depth/spectral context;
|
|
115
|
+
- pupil semantics;
|
|
116
|
+
- engine-owned parameters;
|
|
117
|
+
- scientific limitations.
|
|
118
|
+
|
|
119
|
+
A preview approximation must not redefine the science merely because it is cheaper to render.
|
|
120
|
+
|
|
121
|
+
## Test Fixture relationship
|
|
122
|
+
|
|
123
|
+
Test Fixture v0.3 provides deterministic center/mid/edge/corner detail and point-highlight targets for integration regression.
|
|
124
|
+
|
|
125
|
+
It does not establish:
|
|
126
|
+
|
|
127
|
+
- calibrated MTF;
|
|
128
|
+
- a measured real-lens PSF;
|
|
129
|
+
- spectral lens behavior;
|
|
130
|
+
- calibrated mechanical vignetting;
|
|
131
|
+
- named-lens performance.
|
|
132
|
+
|
|
133
|
+
Engine analytical/reference tests remain the scientific source of truth.
|
package/docs/STABILIZATION.md
CHANGED
|
@@ -26,11 +26,24 @@ Projection has two modes:
|
|
|
26
26
|
|
|
27
27
|
When pixel pitch is supplied, the same displacement is also reported in sensor pixels.
|
|
28
28
|
|
|
29
|
+
The returned X/Y shake components are expressed in the primitive's sensor/image-plane axes. `estimateCameraShakeBlur()` does not accept `CaptureOrientation` and does not rotate its vector into portrait/oriented output coordinates. A caller combining this primitive with the capture-orientation layer must explicitly transform the vector with the orientation helpers.
|
|
30
|
+
|
|
29
31
|
The supplied shake profile is synthetic input. The model is not an empirical statement about how much a particular photographer shakes.
|
|
30
32
|
|
|
31
|
-
### Spatial limitation
|
|
33
|
+
### Spatial limitation and the separate rotation primitive
|
|
34
|
+
|
|
35
|
+
`estimateCameraShakeBlur()` intentionally remains one global image-plane yaw/pitch vector for backwards compatibility with the existing stabilization-equivalent teaching model.
|
|
36
|
+
|
|
37
|
+
The root engine now separately exposes `calculateCameraRotationImageMapping()`, which models field-position-dependent **pure camera rotation** for yaw/pitch/roll at arbitrary physical time from exposure start.
|
|
38
|
+
|
|
39
|
+
The two APIs do not share sign semantics:
|
|
40
|
+
|
|
41
|
+
- the legacy shake estimator preserves its historical direct image-plane displacement convention;
|
|
42
|
+
- the spatial rotation primitive represents physical camera rotation using right-hand pitch/yaw/roll, then maps a stationary world ray through the inverse camera rotation.
|
|
43
|
+
|
|
44
|
+
Do not substitute one result for the other without an explicit migration.
|
|
32
45
|
|
|
33
|
-
The
|
|
46
|
+
The spatial primitive does not apply stabilization stops. Real IBIS/OIS behavior and translation/parallax remain separate future models.
|
|
34
47
|
|
|
35
48
|
## Equivalent stabilization stops
|
|
36
49
|
|
|
@@ -60,11 +73,11 @@ Only the public standard identifier and high-level terminology are referenced he
|
|
|
60
73
|
|
|
61
74
|
## Not yet modeled
|
|
62
75
|
|
|
63
|
-
The
|
|
76
|
+
The legacy stabilization-equivalent model intentionally omits:
|
|
64
77
|
|
|
65
78
|
- roll;
|
|
66
79
|
- translational camera shake;
|
|
67
|
-
- spatially varying rotational optical flow;
|
|
80
|
+
- spatially varying rotational optical flow inside this compatibility API;
|
|
68
81
|
- frequency-dependent shake spectra;
|
|
69
82
|
- photographer-to-photographer variation;
|
|
70
83
|
- shutter-button impulse;
|