@photivra/engine 0.1.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 +87 -0
- package/CITATION.cff +1 -1
- package/README.md +61 -12
- 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/exposure/exposure.d.ts +31 -0
- package/dist/exposure/exposure.d.ts.map +1 -1
- package/dist/exposure/exposure.js +35 -0
- package/dist/exposure/exposure.js.map +1 -1
- package/dist/index.d.ts +16 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -4
- 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 +54 -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 +680 -4
- package/package.json +2 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { calculatedResult } from "../core/calculation-result.js";
|
|
3
|
+
import { InvalidScientificInputError, requirePositiveFinite } from "../core/validation.js";
|
|
4
|
+
import { calculateDefocusCircle } from "./depth-of-field.js";
|
|
5
|
+
import { calculateAiryDisk } from "./diffraction.js";
|
|
6
|
+
export const PSF_FOUNDATION_VERSION = "0.1.0";
|
|
7
|
+
const CONTRIBUTIONS = [
|
|
8
|
+
{
|
|
9
|
+
id: "geometric-defocus-circle",
|
|
10
|
+
status: "implemented-diagnostic",
|
|
11
|
+
dependsOn: ["focus-depth", "pupil"],
|
|
12
|
+
note: "Existing thin-lens geometric defocus diameter. This is a blur-circle diagnostic, not a complete intensity PSF."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "circular-diffraction-first-zero",
|
|
16
|
+
status: "implemented-diagnostic",
|
|
17
|
+
dependsOn: ["pupil", "wavelength"],
|
|
18
|
+
note: "Existing ideal circular-pupil first-zero Airy diameter. This is a diffraction-size diagnostic, not a sampled intensity PSF."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "non-circular-diffraction",
|
|
22
|
+
status: "reserved-contract",
|
|
23
|
+
dependsOn: ["pupil", "wavelength", "field-position"],
|
|
24
|
+
note: "Reserved for a defensible pupil-dependent diffraction model. Polygon aperture geometry alone does not implement this contribution."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "mechanical-pupil-clipping",
|
|
28
|
+
status: "reserved-contract",
|
|
29
|
+
dependsOn: ["pupil", "field-position"],
|
|
30
|
+
note: "Reserved for field-dependent pupil clipping/mechanical vignetting that can affect both throughput and PSF/bokeh shape."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "field-curvature",
|
|
34
|
+
status: "reserved-contract",
|
|
35
|
+
dependsOn: ["field-position", "focus-depth"],
|
|
36
|
+
note: "Reserved for field-dependent focus displacement. It must not be represented as geometric distortion."
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "field-dependent-aberration",
|
|
40
|
+
status: "reserved-contract",
|
|
41
|
+
dependsOn: ["field-position", "focus-depth", "pupil", "wavelength"],
|
|
42
|
+
note: "Reserved for defensible field-dependent aberration/PSF structure. Do not replace this with a generic lens-sharpness score."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "field-dependent-bokeh",
|
|
46
|
+
status: "reserved-contract",
|
|
47
|
+
dependsOn: ["field-position", "focus-depth", "pupil"],
|
|
48
|
+
note: "Reserved for field-dependent out-of-focus PSF/bokeh behavior, including future cat's-eye effects when pupil clipping is modeled."
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
const NOTES = [
|
|
52
|
+
"This foundation preserves PSF-related contributions separately; it does not calculate a combined PSF, MTF, or one scalar lens-sharpness result.",
|
|
53
|
+
"Existing geometric defocus and circular Airy outputs remain independently named scientific diagnostics with their own provenance.",
|
|
54
|
+
"Reserved contributions describe ownership/dependencies only and do not claim implemented visual behavior.",
|
|
55
|
+
"Illumination vignetting is a separate throughput-only model and is not a PSF contribution.",
|
|
56
|
+
"Real-lens PSF calibration requires defensible provenance, compatible reuse rights, and explicit limitations/uncertainty."
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Returns the public PSF/pupil foundation contract.
|
|
60
|
+
*
|
|
61
|
+
* The contract describes current diagnostics plus reserved future contribution
|
|
62
|
+
* ownership. It does not imply that reserved contributions are implemented.
|
|
63
|
+
*/
|
|
64
|
+
export function getPsfFoundationContract() {
|
|
65
|
+
return {
|
|
66
|
+
version: PSF_FOUNDATION_VERSION,
|
|
67
|
+
coordinateSpace: "image-plane-metric",
|
|
68
|
+
fieldAxes: "+X right, +Y up",
|
|
69
|
+
compositionPolicy: "separate-contributions-no-combined-psf",
|
|
70
|
+
contributions: CONTRIBUTIONS.map((contribution) => ({
|
|
71
|
+
...contribution,
|
|
72
|
+
dependsOn: [...contribution.dependsOn]
|
|
73
|
+
})),
|
|
74
|
+
previewReferencePolicy: {
|
|
75
|
+
previewMayApproximate: true,
|
|
76
|
+
referenceMayUseHigherFidelity: true,
|
|
77
|
+
mustPreserveContributionSemantics: true
|
|
78
|
+
},
|
|
79
|
+
notes: [...NOTES]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Evaluates the currently implemented PSF-related diagnostics in one explicit
|
|
84
|
+
* field/depth/spectral/pupil context without combining them into a synthetic
|
|
85
|
+
* PSF or blur radius.
|
|
86
|
+
*
|
|
87
|
+
* Field position is recorded even though the current defocus-circle and
|
|
88
|
+
* circular-Airy diagnostics are not field dependent. Future field-dependent
|
|
89
|
+
* contributions can consume the same context without changing these existing
|
|
90
|
+
* primitives.
|
|
91
|
+
*/
|
|
92
|
+
export function calculatePsfFoundationComponents(input) {
|
|
93
|
+
requirePositiveFinite("focalLengthMm", input.focalLengthMm);
|
|
94
|
+
requirePositiveFinite("aperture", input.aperture);
|
|
95
|
+
requirePositiveFinite("focusDistanceM", input.focusDistanceM);
|
|
96
|
+
requirePositiveFinite("subjectDistanceM", input.subjectDistanceM);
|
|
97
|
+
requirePositiveFinite("fieldNormalizationRadiusMm", input.fieldNormalizationRadiusMm);
|
|
98
|
+
if (input.spectralBasis?.kind !== "monochromatic") {
|
|
99
|
+
throw new InvalidScientificInputError('spectralBasis.kind must be "monochromatic".');
|
|
100
|
+
}
|
|
101
|
+
requirePositiveFinite("spectralBasis.wavelengthNm", input.spectralBasis.wavelengthNm);
|
|
102
|
+
if (!Number.isFinite(input.fieldPointMm.x)) {
|
|
103
|
+
throw new InvalidScientificInputError("fieldPointMm.x must be finite.");
|
|
104
|
+
}
|
|
105
|
+
if (!Number.isFinite(input.fieldPointMm.y)) {
|
|
106
|
+
throw new InvalidScientificInputError("fieldPointMm.y must be finite.");
|
|
107
|
+
}
|
|
108
|
+
const defocus = calculateDefocusCircle({
|
|
109
|
+
focalLengthMm: input.focalLengthMm,
|
|
110
|
+
aperture: input.aperture,
|
|
111
|
+
focusDistanceM: input.focusDistanceM,
|
|
112
|
+
subjectDistanceM: input.subjectDistanceM
|
|
113
|
+
});
|
|
114
|
+
const diffraction = calculateAiryDisk({
|
|
115
|
+
aperture: input.aperture,
|
|
116
|
+
wavelengthNm: input.spectralBasis.wavelengthNm
|
|
117
|
+
});
|
|
118
|
+
const radiusMm = Math.hypot(input.fieldPointMm.x, input.fieldPointMm.y);
|
|
119
|
+
return calculatedResult({
|
|
120
|
+
context: {
|
|
121
|
+
field: {
|
|
122
|
+
imagePointMm: { ...input.fieldPointMm },
|
|
123
|
+
radiusMm,
|
|
124
|
+
normalizationRadiusMm: input.fieldNormalizationRadiusMm,
|
|
125
|
+
normalizedRadius: radiusMm / input.fieldNormalizationRadiusMm
|
|
126
|
+
},
|
|
127
|
+
depth: {
|
|
128
|
+
focusDistanceM: input.focusDistanceM,
|
|
129
|
+
subjectDistanceM: input.subjectDistanceM
|
|
130
|
+
},
|
|
131
|
+
spectralBasis: {
|
|
132
|
+
kind: "monochromatic",
|
|
133
|
+
wavelengthNm: input.spectralBasis.wavelengthNm
|
|
134
|
+
},
|
|
135
|
+
pupil: {
|
|
136
|
+
kind: "ideal-circular-f-number-derived",
|
|
137
|
+
apertureFNumber: input.aperture,
|
|
138
|
+
diameterMm: input.focalLengthMm / input.aperture
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
contributions: {
|
|
142
|
+
geometricDefocus: {
|
|
143
|
+
id: "geometric-defocus-circle",
|
|
144
|
+
diameterMm: defocus.value.diameterMm,
|
|
145
|
+
provenance: { ...defocus.provenance }
|
|
146
|
+
},
|
|
147
|
+
circularDiffraction: {
|
|
148
|
+
id: "circular-diffraction-first-zero",
|
|
149
|
+
firstZeroDiameterMicrometers: diffraction.value.firstZeroDiameterMicrometers,
|
|
150
|
+
provenance: { ...diffraction.provenance }
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
composition: {
|
|
154
|
+
status: "not-composed",
|
|
155
|
+
note: "No combined PSF, MTF, convolution kernel, or scalar sharpness value has been calculated."
|
|
156
|
+
}
|
|
157
|
+
}, "psf-foundation-separated-components", "1.0.0", [
|
|
158
|
+
"Current geometric defocus and ideal circular-pupil diffraction diagnostics are evaluated independently",
|
|
159
|
+
"Field position is explicit context but does not alter the current field-invariant diagnostic primitives",
|
|
160
|
+
"The result intentionally does not combine defocus and diffraction into one blur radius or PSF",
|
|
161
|
+
"Illumination vignetting is excluded because it is a separate throughput-only stage"
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=psf-foundation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"psf-foundation.js","sourceRoot":"","sources":["../../src/optics/psf-foundation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type CalculationResult } from "../core/calculation-result.js";
|
|
2
|
+
export interface RadialDistortionCoefficients {
|
|
3
|
+
/** Dimensionless r² coefficient. */
|
|
4
|
+
k1: number;
|
|
5
|
+
/** Dimensionless r⁴ coefficient. */
|
|
6
|
+
k2: number;
|
|
7
|
+
/** Dimensionless r⁶ coefficient. */
|
|
8
|
+
k3: number;
|
|
9
|
+
}
|
|
10
|
+
export interface RadialDistortionProfile {
|
|
11
|
+
/**
|
|
12
|
+
* Physical image-plane radius used to normalize field position, in mm.
|
|
13
|
+
* Coefficients are meaningful only with this declared normalization.
|
|
14
|
+
*/
|
|
15
|
+
normalizationRadiusMm: number;
|
|
16
|
+
/**
|
|
17
|
+
* Maximum undistorted normalized radius over which this profile is declared
|
|
18
|
+
* valid and must remain one-to-one/invertible.
|
|
19
|
+
*/
|
|
20
|
+
maximumNormalizedRadius: number;
|
|
21
|
+
coefficients: RadialDistortionCoefficients;
|
|
22
|
+
}
|
|
23
|
+
export interface LensFieldPointMm {
|
|
24
|
+
/** Image-plane X coordinate relative to the optical axis, in mm. */
|
|
25
|
+
x: number;
|
|
26
|
+
/** Image-plane Y coordinate relative to the optical axis, in mm. */
|
|
27
|
+
y: number;
|
|
28
|
+
}
|
|
29
|
+
export interface CalculateRadialDistortionMappingInput {
|
|
30
|
+
/** Ideal/undistorted image-plane point. */
|
|
31
|
+
imagePointMm: LensFieldPointMm;
|
|
32
|
+
profile: RadialDistortionProfile;
|
|
33
|
+
}
|
|
34
|
+
export interface CalculateInverseRadialDistortionMappingInput {
|
|
35
|
+
/** Distorted image-plane point to inverse-map back to ideal coordinates. */
|
|
36
|
+
distortedImagePointMm: LensFieldPointMm;
|
|
37
|
+
profile: RadialDistortionProfile;
|
|
38
|
+
}
|
|
39
|
+
export interface RadialDistortionMapping {
|
|
40
|
+
direction: "undistorted-to-distorted";
|
|
41
|
+
sourceImagePointMm: LensFieldPointMm;
|
|
42
|
+
mappedImagePointMm: LensFieldPointMm;
|
|
43
|
+
sourceNormalizedRadius: number;
|
|
44
|
+
mappedNormalizedRadius: number;
|
|
45
|
+
radialScale: number;
|
|
46
|
+
deltaMm: {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
distance: number;
|
|
50
|
+
};
|
|
51
|
+
profileMinimumRadialDerivative: number;
|
|
52
|
+
}
|
|
53
|
+
export interface InverseRadialDistortionMapping {
|
|
54
|
+
direction: "distorted-to-undistorted";
|
|
55
|
+
distortedImagePointMm: LensFieldPointMm;
|
|
56
|
+
sourceImagePointMm: LensFieldPointMm;
|
|
57
|
+
distortedNormalizedRadius: number;
|
|
58
|
+
sourceNormalizedRadius: number;
|
|
59
|
+
radialScaleAtSource: number;
|
|
60
|
+
deltaMm: {
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
distance: number;
|
|
64
|
+
};
|
|
65
|
+
profileMinimumRadialDerivative: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Applies a generic radial lens-distortion field mapping to one ideal
|
|
69
|
+
* image-plane point.
|
|
70
|
+
*
|
|
71
|
+
* The mapping is rotationally symmetric about the optical axis:
|
|
72
|
+
*
|
|
73
|
+
* p_distorted = p_ideal * (1 + k1 r² + k2 r⁴ + k3 r⁶)
|
|
74
|
+
*
|
|
75
|
+
* where r is normalized by the caller-declared physical reference radius.
|
|
76
|
+
*
|
|
77
|
+
* The profile is accepted only when the radial mapping is strictly monotonic
|
|
78
|
+
* over its declared operating radius, which makes inverse destination-to-source
|
|
79
|
+
* sampling well-defined.
|
|
80
|
+
*/
|
|
81
|
+
export declare function calculateRadialDistortionMapping(input: CalculateRadialDistortionMappingInput): CalculationResult<RadialDistortionMapping>;
|
|
82
|
+
/**
|
|
83
|
+
* Inverse-maps one distorted image-plane point to its ideal/undistorted source
|
|
84
|
+
* coordinate for destination-to-source renderer sampling.
|
|
85
|
+
*
|
|
86
|
+
* The same profile monotonicity requirement used by the forward mapping makes
|
|
87
|
+
* the inverse unique over the declared operating radius. A deterministic fixed
|
|
88
|
+
* bisection count is used rather than an unconstrained iterative solver.
|
|
89
|
+
*/
|
|
90
|
+
export declare function calculateInverseRadialDistortionMapping(input: CalculateInverseRadialDistortionMappingInput): CalculationResult<InverseRadialDistortionMapping>;
|
|
91
|
+
//# sourceMappingURL=radial-distortion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radial-distortion.d.ts","sourceRoot":"","sources":["../../src/optics/radial-distortion.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AAMvC,MAAM,WAAW,4BAA4B;IAC3C,oCAAoC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,oCAAoC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,oCAAoC;IACpC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,qBAAqB,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,uBAAuB,EAAE,MAAM,CAAC;IAChC,YAAY,EAAE,4BAA4B,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,CAAC,EAAE,MAAM,CAAC;IACV,oEAAoE;IACpE,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,qCAAqC;IACpD,2CAA2C;IAC3C,YAAY,EAAE,gBAAgB,CAAC;IAC/B,OAAO,EAAE,uBAAuB,CAAC;CAClC;AAED,MAAM,WAAW,4CAA4C;IAC3D,4EAA4E;IAC5E,qBAAqB,EAAE,gBAAgB,CAAC;IACxC,OAAO,EAAE,uBAAuB,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,0BAA0B,CAAC;IACtC,kBAAkB,EAAE,gBAAgB,CAAC;IACrC,kBAAkB,EAAE,gBAAgB,CAAC;IACrC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,8BAA8B,EAAE,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,0BAA0B,CAAC;IACtC,qBAAqB,EAAE,gBAAgB,CAAC;IACxC,kBAAkB,EAAE,gBAAgB,CAAC;IACrC,yBAAyB,EAAE,MAAM,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE;QACP,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,8BAA8B,EAAE,MAAM,CAAC;CACxC;AA2JD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,qCAAqC,GAC3C,iBAAiB,CAAC,uBAAuB,CAAC,CAiD5C;AAED;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CACrD,KAAK,EAAE,4CAA4C,GAClD,iBAAiB,CAAC,8BAA8B,CAAC,CAiFnD"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { approximationResult } from "../core/calculation-result.js";
|
|
3
|
+
import { InvalidScientificInputError, requirePositiveFinite } from "../core/validation.js";
|
|
4
|
+
const INVERSE_BISECTION_ITERATIONS = 80;
|
|
5
|
+
function requireFinite(name, value) {
|
|
6
|
+
if (!Number.isFinite(value)) {
|
|
7
|
+
throw new InvalidScientificInputError(`${name} must be finite.`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function radialScale(normalizedRadius, coefficients) {
|
|
11
|
+
const r2 = normalizedRadius * normalizedRadius;
|
|
12
|
+
const r4 = r2 * r2;
|
|
13
|
+
const r6 = r4 * r2;
|
|
14
|
+
return (1 +
|
|
15
|
+
coefficients.k1 * r2 +
|
|
16
|
+
coefficients.k2 * r4 +
|
|
17
|
+
coefficients.k3 * r6);
|
|
18
|
+
}
|
|
19
|
+
function mappedNormalizedRadius(normalizedRadius, coefficients) {
|
|
20
|
+
return normalizedRadius * radialScale(normalizedRadius, coefficients);
|
|
21
|
+
}
|
|
22
|
+
function radialDerivativeFromSquaredRadius(squaredRadius, coefficients) {
|
|
23
|
+
return (1 +
|
|
24
|
+
3 * coefficients.k1 * squaredRadius +
|
|
25
|
+
5 * coefficients.k2 * squaredRadius * squaredRadius +
|
|
26
|
+
7 *
|
|
27
|
+
coefficients.k3 *
|
|
28
|
+
squaredRadius *
|
|
29
|
+
squaredRadius *
|
|
30
|
+
squaredRadius);
|
|
31
|
+
}
|
|
32
|
+
function derivativeCriticalSquaredRadii(coefficients) {
|
|
33
|
+
// d/dr² of the radial derivative:
|
|
34
|
+
// 3 k1 + 10 k2 s + 21 k3 s² = 0, where s = r².
|
|
35
|
+
const a = 21 * coefficients.k3;
|
|
36
|
+
const b = 10 * coefficients.k2;
|
|
37
|
+
const c = 3 * coefficients.k1;
|
|
38
|
+
if (a === 0) {
|
|
39
|
+
return b === 0 ? [] : [-c / b];
|
|
40
|
+
}
|
|
41
|
+
const discriminant = b * b - 4 * a * c;
|
|
42
|
+
if (discriminant < 0) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
const root = Math.sqrt(discriminant);
|
|
46
|
+
return [(-b - root) / (2 * a), (-b + root) / (2 * a)];
|
|
47
|
+
}
|
|
48
|
+
function validateProfile(profile) {
|
|
49
|
+
requirePositiveFinite("profile.normalizationRadiusMm", profile.normalizationRadiusMm);
|
|
50
|
+
requirePositiveFinite("profile.maximumNormalizedRadius", profile.maximumNormalizedRadius);
|
|
51
|
+
requireFinite("profile.coefficients.k1", profile.coefficients.k1);
|
|
52
|
+
requireFinite("profile.coefficients.k2", profile.coefficients.k2);
|
|
53
|
+
requireFinite("profile.coefficients.k3", profile.coefficients.k3);
|
|
54
|
+
const maximumSquaredRadius = profile.maximumNormalizedRadius * profile.maximumNormalizedRadius;
|
|
55
|
+
const candidates = [
|
|
56
|
+
0,
|
|
57
|
+
maximumSquaredRadius,
|
|
58
|
+
...derivativeCriticalSquaredRadii(profile.coefficients).filter((value) => value > 0 && value < maximumSquaredRadius)
|
|
59
|
+
];
|
|
60
|
+
const minimumRadialDerivative = Math.min(...candidates.map((squaredRadius) => radialDerivativeFromSquaredRadius(squaredRadius, profile.coefficients)));
|
|
61
|
+
if (!Number.isFinite(minimumRadialDerivative) ||
|
|
62
|
+
minimumRadialDerivative <= 0) {
|
|
63
|
+
throw new InvalidScientificInputError("Radial distortion profile must remain strictly monotonic over maximumNormalizedRadius so inverse mapping is single-valued.");
|
|
64
|
+
}
|
|
65
|
+
const maximumMappedRadius = mappedNormalizedRadius(profile.maximumNormalizedRadius, profile.coefficients);
|
|
66
|
+
if (!Number.isFinite(maximumMappedRadius) || maximumMappedRadius <= 0) {
|
|
67
|
+
throw new InvalidScientificInputError("Radial distortion profile produces an invalid mapped operating radius.");
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
normalizationRadiusMm: profile.normalizationRadiusMm,
|
|
71
|
+
maximumNormalizedRadius: profile.maximumNormalizedRadius,
|
|
72
|
+
coefficients: { ...profile.coefficients },
|
|
73
|
+
minimumRadialDerivative,
|
|
74
|
+
maximumMappedNormalizedRadius: maximumMappedRadius
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function requirePoint(name, point) {
|
|
78
|
+
requireFinite(`${name}.x`, point.x);
|
|
79
|
+
requireFinite(`${name}.y`, point.y);
|
|
80
|
+
}
|
|
81
|
+
function mappingAssumptions() {
|
|
82
|
+
return [
|
|
83
|
+
"Generic rotationally symmetric radial polynomial field mapping",
|
|
84
|
+
"Distortion is centered on the optical axis; decentering and tangential distortion are not modeled",
|
|
85
|
+
"Normalized radius is image-plane radius divided by the caller-declared normalizationRadiusMm",
|
|
86
|
+
"Radial scale is 1 + k1 r^2 + k2 r^4 + k3 r^6",
|
|
87
|
+
"The declared operating radius is required to remain strictly monotonic so inverse mapping is single-valued",
|
|
88
|
+
"Coefficients are generic caller inputs and do not represent a named lens unless separately calibrated with defensible provenance"
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Applies a generic radial lens-distortion field mapping to one ideal
|
|
93
|
+
* image-plane point.
|
|
94
|
+
*
|
|
95
|
+
* The mapping is rotationally symmetric about the optical axis:
|
|
96
|
+
*
|
|
97
|
+
* p_distorted = p_ideal * (1 + k1 r² + k2 r⁴ + k3 r⁶)
|
|
98
|
+
*
|
|
99
|
+
* where r is normalized by the caller-declared physical reference radius.
|
|
100
|
+
*
|
|
101
|
+
* The profile is accepted only when the radial mapping is strictly monotonic
|
|
102
|
+
* over its declared operating radius, which makes inverse destination-to-source
|
|
103
|
+
* sampling well-defined.
|
|
104
|
+
*/
|
|
105
|
+
export function calculateRadialDistortionMapping(input) {
|
|
106
|
+
requirePoint("imagePointMm", input.imagePointMm);
|
|
107
|
+
const profile = validateProfile(input.profile);
|
|
108
|
+
const sourceRadiusMm = Math.hypot(input.imagePointMm.x, input.imagePointMm.y);
|
|
109
|
+
const sourceNormalizedRadius = sourceRadiusMm / profile.normalizationRadiusMm;
|
|
110
|
+
if (sourceNormalizedRadius > profile.maximumNormalizedRadius) {
|
|
111
|
+
throw new InvalidScientificInputError("imagePointMm lies outside the radial distortion profile maximumNormalizedRadius.");
|
|
112
|
+
}
|
|
113
|
+
const scale = radialScale(sourceNormalizedRadius, profile.coefficients);
|
|
114
|
+
const mappedImagePointMm = {
|
|
115
|
+
x: input.imagePointMm.x * scale,
|
|
116
|
+
y: input.imagePointMm.y * scale
|
|
117
|
+
};
|
|
118
|
+
const mappedRadius = sourceNormalizedRadius * scale;
|
|
119
|
+
const deltaX = mappedImagePointMm.x - input.imagePointMm.x;
|
|
120
|
+
const deltaY = mappedImagePointMm.y - input.imagePointMm.y;
|
|
121
|
+
return approximationResult({
|
|
122
|
+
direction: "undistorted-to-distorted",
|
|
123
|
+
sourceImagePointMm: { ...input.imagePointMm },
|
|
124
|
+
mappedImagePointMm,
|
|
125
|
+
sourceNormalizedRadius,
|
|
126
|
+
mappedNormalizedRadius: mappedRadius,
|
|
127
|
+
radialScale: scale,
|
|
128
|
+
deltaMm: {
|
|
129
|
+
x: deltaX,
|
|
130
|
+
y: deltaY,
|
|
131
|
+
distance: Math.hypot(deltaX, deltaY)
|
|
132
|
+
},
|
|
133
|
+
profileMinimumRadialDerivative: profile.minimumRadialDerivative
|
|
134
|
+
}, "generic-radial-lens-distortion", "1.0.0", mappingAssumptions());
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Inverse-maps one distorted image-plane point to its ideal/undistorted source
|
|
138
|
+
* coordinate for destination-to-source renderer sampling.
|
|
139
|
+
*
|
|
140
|
+
* The same profile monotonicity requirement used by the forward mapping makes
|
|
141
|
+
* the inverse unique over the declared operating radius. A deterministic fixed
|
|
142
|
+
* bisection count is used rather than an unconstrained iterative solver.
|
|
143
|
+
*/
|
|
144
|
+
export function calculateInverseRadialDistortionMapping(input) {
|
|
145
|
+
requirePoint("distortedImagePointMm", input.distortedImagePointMm);
|
|
146
|
+
const profile = validateProfile(input.profile);
|
|
147
|
+
const distortedRadiusMm = Math.hypot(input.distortedImagePointMm.x, input.distortedImagePointMm.y);
|
|
148
|
+
const distortedNormalizedRadius = distortedRadiusMm / profile.normalizationRadiusMm;
|
|
149
|
+
if (distortedNormalizedRadius >
|
|
150
|
+
profile.maximumMappedNormalizedRadius) {
|
|
151
|
+
throw new InvalidScientificInputError("distortedImagePointMm lies outside the mapped radial distortion profile operating radius.");
|
|
152
|
+
}
|
|
153
|
+
let sourceNormalizedRadius = 0;
|
|
154
|
+
if (distortedNormalizedRadius > 0) {
|
|
155
|
+
let lower = 0;
|
|
156
|
+
let upper = profile.maximumNormalizedRadius;
|
|
157
|
+
for (let iteration = 0; iteration < INVERSE_BISECTION_ITERATIONS; iteration += 1) {
|
|
158
|
+
const midpoint = (lower + upper) / 2;
|
|
159
|
+
const mapped = mappedNormalizedRadius(midpoint, profile.coefficients);
|
|
160
|
+
if (mapped < distortedNormalizedRadius) {
|
|
161
|
+
lower = midpoint;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
upper = midpoint;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
sourceNormalizedRadius = (lower + upper) / 2;
|
|
168
|
+
}
|
|
169
|
+
const scaleAtSource = radialScale(sourceNormalizedRadius, profile.coefficients);
|
|
170
|
+
const sourceImagePointMm = distortedNormalizedRadius === 0
|
|
171
|
+
? { x: 0, y: 0 }
|
|
172
|
+
: {
|
|
173
|
+
x: input.distortedImagePointMm.x / scaleAtSource,
|
|
174
|
+
y: input.distortedImagePointMm.y / scaleAtSource
|
|
175
|
+
};
|
|
176
|
+
const deltaX = sourceImagePointMm.x - input.distortedImagePointMm.x;
|
|
177
|
+
const deltaY = sourceImagePointMm.y - input.distortedImagePointMm.y;
|
|
178
|
+
return approximationResult({
|
|
179
|
+
direction: "distorted-to-undistorted",
|
|
180
|
+
distortedImagePointMm: {
|
|
181
|
+
...input.distortedImagePointMm
|
|
182
|
+
},
|
|
183
|
+
sourceImagePointMm,
|
|
184
|
+
distortedNormalizedRadius,
|
|
185
|
+
sourceNormalizedRadius,
|
|
186
|
+
radialScaleAtSource: scaleAtSource,
|
|
187
|
+
deltaMm: {
|
|
188
|
+
x: deltaX,
|
|
189
|
+
y: deltaY,
|
|
190
|
+
distance: Math.hypot(deltaX, deltaY)
|
|
191
|
+
},
|
|
192
|
+
profileMinimumRadialDerivative: profile.minimumRadialDerivative
|
|
193
|
+
}, "generic-inverse-radial-lens-distortion", "1.0.0", [
|
|
194
|
+
...mappingAssumptions(),
|
|
195
|
+
`Inverse radius is solved with ${INVERSE_BISECTION_ITERATIONS} deterministic bisection iterations`
|
|
196
|
+
]);
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=radial-distortion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radial-distortion.js","sourceRoot":"","sources":["../../src/optics/radial-distortion.ts"],"names":[],"mappings":"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"}
|