@photivra/engine 2.18.0 → 2.20.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 +179 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +7 -5
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +14 -10
- package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
- package/dist/capture/dng-lens-correction-opcodes.js +119 -0
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
- package/dist/capture/focus-control.js +2 -75
- package/dist/capture/focus-control.js.map +1 -1
- package/dist/capture/native-environment-lean.d.ts +1 -0
- package/dist/capture/native-environment-lean.js +2 -6
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-optical-stage.d.ts +1 -0
- package/dist/capture/native-environment-optical-stage.js +2 -5
- package/dist/capture/native-environment-optical-stage.js.map +1 -1
- package/dist/capture/native-environment-raw.js +1 -5
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/native-raw-dng.d.ts +6 -0
- package/dist/capture/native-raw-dng.js +16 -2
- package/dist/capture/native-raw-dng.js.map +1 -1
- package/dist/capture/release-sequence.js +2 -47
- package/dist/capture/release-sequence.js.map +1 -1
- package/dist/capture/sensor-raw-producer.js +3 -5
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/white-balance.d.ts +2 -0
- package/dist/color/white-balance.js +3 -56
- package/dist/color/white-balance.js.map +1 -1
- package/dist/composition/image-formation-plan.d.ts +1 -0
- package/dist/composition/image-formation-plan.js +3 -49
- package/dist/composition/image-formation-plan.js.map +1 -1
- package/dist/core/evidence-provenance.js +1 -16
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/record-validation.d.ts +54 -0
- package/dist/core/record-validation.js +176 -0
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/scientific-assurance.js +1 -18
- package/dist/core/scientific-assurance.js.map +1 -1
- package/dist/core/shared-helpers.d.ts +35 -0
- package/dist/core/shared-helpers.js +38 -0
- package/dist/core/shared-helpers.js.map +1 -0
- package/dist/core/spectral-composition.js +1 -36
- package/dist/core/spectral-composition.js.map +1 -1
- package/dist/core/spectral.js +1 -19
- package/dist/core/spectral.js.map +1 -1
- 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/exposure-capabilities.d.ts +1 -0
- package/dist/equipment/exposure-capabilities.js +2 -36
- package/dist/equipment/exposure-capabilities.js.map +1 -1
- package/dist/equipment/generic-lens-catalogue.d.ts +8 -2
- package/dist/equipment/generic-lens-catalogue.js +31 -2
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.js +2 -3
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.js +2 -3
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/equipment/iso-capabilities.js +2 -49
- package/dist/equipment/iso-capabilities.js.map +1 -1
- package/dist/equipment/metering-capabilities.js +1 -26
- package/dist/equipment/metering-capabilities.js.map +1 -1
- package/dist/equipment/release-capabilities.js +1 -53
- package/dist/equipment/release-capabilities.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
- package/dist/exposure/exposure-duration-control.js +1 -16
- package/dist/exposure/exposure-duration-control.js.map +1 -1
- package/dist/exposure/exposure-mode-resolver.js +1 -17
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/filtered-exposure-time.d.ts +93 -0
- package/dist/exposure/filtered-exposure-time.js +129 -0
- package/dist/exposure/filtered-exposure-time.js.map +1 -0
- package/dist/exposure/flash-ttl.d.ts +1 -0
- package/dist/exposure/flash-ttl.js +1 -1
- package/dist/exposure/flash-ttl.js.map +1 -1
- package/dist/exposure/flash.js +1 -49
- package/dist/exposure/flash.js.map +1 -1
- package/dist/exposure/metering-scene-radiance.js +1 -25
- package/dist/exposure/metering-scene-radiance.js.map +1 -1
- package/dist/exposure/metering-target.js +1 -30
- package/dist/exposure/metering-target.js.map +1 -1
- package/dist/exposure/metering-temporal.js +1 -8
- package/dist/exposure/metering-temporal.js.map +1 -1
- package/dist/exposure/metering.js +1 -72
- package/dist/exposure/metering.js.map +1 -1
- package/dist/exposure/program-line.js +1 -45
- package/dist/exposure/program-line.js.map +1 -1
- package/dist/facade/develop-joined-parts.d.ts +29 -0
- package/dist/facade/develop-joined-parts.js +33 -0
- package/dist/facade/develop-joined-parts.js.map +1 -0
- package/dist/facade/display-view-gpu.d.ts +7 -4
- package/dist/facade/display-view-gpu.js +4 -4
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.d.ts +1 -1
- package/dist/facade/display-view-lens-signal.js +5 -3
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view.d.ts +3 -1
- package/dist/facade/display-view.js +1 -1
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/fast-methods.d.ts +50 -0
- package/dist/facade/fast-methods.js +50 -0
- package/dist/facade/fast-methods.js.map +1 -0
- package/dist/facade/fast-resolution.d.ts +12 -0
- package/dist/facade/fast-resolution.js +18 -0
- package/dist/facade/fast-resolution.js.map +1 -0
- package/dist/facade/generic-lens-capture.d.ts +6 -3
- package/dist/facade/generic-lens-capture.js +6 -3
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +88 -16
- package/dist/facade/simulate-capture.js +279 -153
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +3 -2
- package/dist/facade/simulate-display-view.js +22 -12
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.js +1 -3
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +1 -5
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
- package/dist/gpu/display-view-quality-gpu.js +4 -8
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.js +3 -25
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/sensor-stage-gpu.js +1 -5
- package/dist/gpu/sensor-stage-gpu.js.map +1 -1
- package/dist/gpu/webgpu-runtime.d.ts +2 -0
- package/dist/gpu/webgpu-runtime.js +3 -0
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.js +1 -6
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
- package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.js +2 -17
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
- package/dist/motion/extended-object-projection.js +5 -40
- package/dist/motion/extended-object-projection.js.map +1 -1
- package/dist/optics/aperture-diameter.d.ts +47 -0
- package/dist/optics/aperture-diameter.js +50 -0
- package/dist/optics/aperture-diameter.js.map +1 -0
- package/dist/optics/atmospheric-haze.js +1 -7
- package/dist/optics/atmospheric-haze.js.map +1 -1
- package/dist/optics/brown-conrady-distortion.js +1 -7
- package/dist/optics/brown-conrady-distortion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +1 -0
- package/dist/optics/complex-pupil-psf.js +2 -84
- package/dist/optics/complex-pupil-psf.js.map +1 -1
- package/dist/optics/detail-limit.d.ts +182 -0
- package/dist/optics/detail-limit.js +336 -0
- package/dist/optics/detail-limit.js.map +1 -0
- package/dist/optics/focus-state.js +1 -11
- package/dist/optics/focus-state.js.map +1 -1
- package/dist/optics/front-of-lens-filter.d.ts +5 -0
- package/dist/optics/front-of-lens-filter.js +3 -65
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/generic-lens-psf.d.ts +18 -2
- package/dist/optics/generic-lens-psf.js +25 -2
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
- package/dist/optics/generic-nd-filter-presets.js +48 -0
- package/dist/optics/generic-nd-filter-presets.js.map +1 -0
- package/dist/optics/illumination-vignetting.js +1 -6
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +4 -1
- package/dist/optics/lens-psf-profile.js +12 -111
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
- package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
- package/dist/optics/pupil-vignetting.js +1 -7
- package/dist/optics/pupil-vignetting.js.map +1 -1
- package/dist/optics/radial-distortion.js +1 -6
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
- package/dist/optics/scene-to-sensor-irradiance.js +11 -96
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/stray-light.d.ts +1 -0
- package/dist/optics/stray-light.js +1 -1
- package/dist/optics/stray-light.js.map +1 -1
- package/dist/optics/zernike-wavefront.js +1 -7
- package/dist/optics/zernike-wavefront.js.map +1 -1
- package/dist/output/capture-geometry.js +1 -8
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/crop-to-match-focal-length.d.ts +62 -0
- package/dist/output/crop-to-match-focal-length.js +63 -0
- package/dist/output/crop-to-match-focal-length.js.map +1 -0
- package/dist/output/developed-lens-corrections.d.ts +62 -0
- package/dist/output/developed-lens-corrections.js +135 -0
- package/dist/output/developed-lens-corrections.js.map +1 -0
- package/dist/output/generic-lens-corrections.d.ts +5 -7
- package/dist/output/generic-lens-corrections.js +11 -10
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/geometric-transforms.js +1 -4
- package/dist/output/geometric-transforms.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +12 -2
- package/dist/output/lens-corrections.js +22 -7
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +2 -2
- package/dist/output/native-capture-sdr.js +3 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/print-contrast-reference.js +1 -1
- package/dist/output/print-contrast-reference.js.map +1 -1
- package/dist/output/print-size-blur-noise.d.ts +110 -0
- package/dist/output/print-size-blur-noise.js +138 -0
- package/dist/output/print-size-blur-noise.js.map +1 -0
- package/dist/processing/development-detail.d.ts +29 -0
- package/dist/processing/development-detail.js +128 -107
- package/dist/processing/development-detail.js.map +1 -1
- package/dist/schema/illumination-temporal.js +3 -72
- package/dist/schema/illumination-temporal.js.map +1 -1
- package/dist/schema/illumination.d.ts +1 -0
- package/dist/schema/illumination.js +2 -65
- package/dist/schema/illumination.js.map +1 -1
- package/dist/schema/scene-radiance-temporal.js +2 -14
- package/dist/schema/scene-radiance-temporal.js.map +1 -1
- package/dist/schema/scene-radiance.js +2 -60
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/schema/validation.d.ts +2 -0
- package/dist/schema/validation.js +2 -17
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.js +2 -59
- package/dist/sensor/accumulated-charge.js.map +1 -1
- package/dist/sensor/architecture.js +1 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
- package/dist/sensor/camera-saturation-capacity.js +3 -55
- package/dist/sensor/camera-saturation-capacity.js.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.js +1 -26
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.js +1 -39
- package/dist/sensor/capture-mode-timing.js.map +1 -1
- package/dist/sensor/capture-mode.js +1 -23
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.js +1 -26
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.js +2 -46
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
- package/dist/sensor/dark-current.js +2 -45
- package/dist/sensor/dark-current.js.map +1 -1
- package/dist/sensor/eqe-electron-rate.js +2 -41
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +7 -0
- package/dist/sensor/exposure-window.js +9 -24
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/iso-gain.js +1 -7
- package/dist/sensor/iso-gain.js.map +1 -1
- package/dist/sensor/iso-signal-chain.js +1 -43
- package/dist/sensor/iso-signal-chain.js.map +1 -1
- package/dist/sensor/optical-stack.js +1 -25
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.js +1 -26
- package/dist/sensor/photon-energy.js.map +1 -1
- package/dist/sensor/physical-charge-capacity.js +3 -77
- package/dist/sensor/physical-charge-capacity.js.map +1 -1
- package/dist/sensor/radiometry-readiness.js +2 -23
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +3 -0
- package/dist/sensor/raw-readout.js +4 -66
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/raw-reconstruction.js +2 -64
- package/dist/sensor/raw-reconstruction.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +1 -9
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.js +4 -79
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +2 -0
- package/dist/sensor/response-application-compatibility.js +4 -35
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/response-operating-range.d.ts +1 -0
- package/dist/sensor/response-operating-range.js +3 -79
- package/dist/sensor/response-operating-range.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.js +4 -114
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sampling-aperture.js +1 -25
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/sensor-characteristics.d.ts +137 -0
- package/dist/sensor/sensor-characteristics.js +115 -0
- package/dist/sensor/sensor-characteristics.js.map +1 -0
- package/dist/sensor/spatial-sample-reduction.js +3 -24
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.js +1 -3
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.js +1 -18
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
- package/dist/sensor/spectral-coverage.d.ts +10 -1
- package/dist/sensor/spectral-coverage.js +1 -1
- package/dist/sensor/spectral-coverage.js.map +1 -1
- package/dist/sensor/spectral-quadrature.js +3 -41
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/spectral-response.js +1 -47
- package/dist/sensor/spectral-response.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +3 -0
- package/dist/sensor/temporal-photo-signal.js +5 -2
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/stabilization/camera-shake.js +1 -6
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +9 -0
- package/dist/stabilization/system.js +7 -86
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +5 -0
- package/docs/API_REFERENCE.md +116 -3
- package/docs/QUICK_START.md +178 -14
- package/docs/USAGE.md +111 -3
- package/docs/api/capture-native-raw-dng.md +6 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +7 -2
- package/docs/api/exports.json +203 -3
- package/docs/api/exposure-filtered-exposure-time.md +105 -0
- package/docs/api/facade-develop-joined-parts.md +32 -0
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-fast-methods.md +91 -0
- package/docs/api/facade-simulate-capture.md +72 -16
- package/docs/api/facade-simulate-display-view.md +3 -2
- package/docs/api/optics-aperture-diameter.md +51 -0
- package/docs/api/optics-detail-limit.md +203 -0
- package/docs/api/optics-generic-nd-filter-presets.md +34 -0
- package/docs/api/optics-lens-psf-profile.md +3 -1
- package/docs/api/output-crop-to-match-focal-length.md +67 -0
- package/docs/api/output-developed-lens-corrections.md +12 -0
- package/docs/api/output-generic-lens-corrections.md +3 -10
- package/docs/api/output-lens-corrections.md +11 -1
- package/docs/api/output-print-size-blur-noise.md +115 -0
- package/docs/api/sensor-sensor-characteristics.md +105 -0
- package/llms.txt +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crop-to-match-focal-length.js","sourceRoot":"","sources":["../../src/output/crop-to-match-focal-length.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,gBAAgB,EAA0B,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAgClD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,+BAA+B,CAC7C,KAA2C;IAE3C,gBAAgB,CAAC,KAAK,EAAE,iCAAiC,EAAE,CAAC,eAAe,EAAE,qBAAqB,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;IAClI,qBAAqB,CAAC,eAAe,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5D,qBAAqB,CAAC,qBAAqB,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACxE,IAAI,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;QACpD,MAAM,IAAI,2BAA2B,CACnC,sGAAsG,CACvG,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,aAAa,CAAC;IACnE,MAAM,IAAI,GAAG,qBAAqB,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC;IACvH,OAAO,gBAAgB,CACrB;QACE,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,UAAU;QACV,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,gBAAgB,EAAE,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,SAAS;QACpE,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;KAChD,EACD,4BAA4B,EAC5B,OAAO,EACP;QACE,0IAA0I;QAC1I,4HAA4H;QAC5H,kDAAkD;QAClD,mFAAmF;KACpF,CACF,CAAC;AACJ,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * How much to crop an image from a shorter lens so it matches a longer lens's framing, and the\n * pixels that leaves.\n *\n * For an ideal rectilinear lens focused at infinity, a scene point at field angle θ images at\n * height y' = f·tan θ (Greivenkamp, OPTI-502 course notes, sec. 12 (Objectives), free:\n * https://wp.optics.arizona.edu/jgreivenkamp/wp-content/uploads/sites/11/2019/08/502-12-Objectives.pdf).\n * From the same camera position the image of focal length F is the image of f scaled by F/f, so a\n * centred crop by the linear factor F/f gives the same framing and the same perspective: exact at\n * infinity focus, to whole pixels.\n *\n * At close focus the thin-lens magnification is m = f/(d − f) for an object distance d from the\n * lens, so at the same d the factor is F·(d − f)/(f·(d − F)), larger than F/f and tending to it when\n * d is much greater than F. That correction, distortion and focus breathing are not modelled.\n * @see docs/PHYSICS_FOUNDATION.md \"Crop to match a longer focal length\".\n */\n\nimport { calculatedResult, type CalculationResult } from \"../core/calculation-result.js\";\nimport { requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidScientificInputError, requirePositiveFinite } from \"../core/validation.js\";\nimport { calculateCenteredCrop } from \"./crop.js\";\n\nexport interface CalculateCropToMatchFocalLengthInput {\n /** Focal length the image was taken with, in millimetres. */\n focalLengthMm: number;\n /** Longer focal length whose framing the crop should match, in millimetres. At least `focalLengthMm`. */\n targetFocalLengthMm: number;\n /** Image width in pixels (for example the sensor's output width). */\n pixelWidth: number;\n /** Image height in pixels. */\n pixelHeight: number;\n}\n\nexport interface CropToMatchFocalLength {\n /** Focal length supplied by the caller, in millimetres. */\n focalLengthMm: number;\n /** Target focal length supplied by the caller, in millimetres. */\n targetFocalLengthMm: number;\n /** Linear crop factor targetFocalLengthMm / focalLengthMm (1 means no crop). */\n cropFactor: number;\n /** Width left after the centred crop, in pixels (as `calculateCenteredCrop`). */\n pixelWidth: number;\n /** Height left after the centred crop, in pixels. */\n pixelHeight: number;\n /** Pixels left, in millions. */\n megapixels: number;\n /** Megapixels of the uncropped image. */\n sourceMegapixels: number;\n /** Fraction of the original pixel area retained, about 1 / cropFactor². */\n retainedAreaFraction: number;\n}\n\n/**\n * The centred crop that makes an image from a shorter lens match a longer lens's framing from the\n * same position: crop factor target ÷ focal length, and the pixels and megapixels left.\n *\n * Exact for ideal rectilinear lenses focused at infinity, to whole pixels (the crop is\n * `calculateCenteredCrop`'s, which keeps the aspect ratio). At close focus the matching factor is\n * larger, F·(d − f)/(f·(d − F)) at object distance d (thin lens); that, distortion and focus\n * breathing are not modelled. The crop has the longer lens's framing and perspective but fewer\n * pixels: it records no more detail than the cropped part of the shorter lens's image.\n *\n * Example: a 24 MP (6000 × 4000) image at 50 mm cropped to match 100 mm: factor 2, 3000 × 2000,\n * 6 MP.\n *\n * @param input Focal length, longer target focal length and the image's pixel dimensions.\n * @returns Crop factor and the remaining pixel dimensions.\n */\nexport function calculateCropToMatchFocalLength(\n input: CalculateCropToMatchFocalLengthInput\n): CalculationResult<CropToMatchFocalLength> {\n requireInputKeys(input, \"calculateCropToMatchFocalLength\", [\"focalLengthMm\", \"targetFocalLengthMm\", \"pixelWidth\", \"pixelHeight\"]);\n requirePositiveFinite(\"focalLengthMm\", input.focalLengthMm);\n requirePositiveFinite(\"targetFocalLengthMm\", input.targetFocalLengthMm);\n if (input.targetFocalLengthMm < input.focalLengthMm) {\n throw new InvalidScientificInputError(\n \"targetFocalLengthMm must be greater than or equal to focalLengthMm: a crop cannot widen the framing.\"\n );\n }\n const cropFactor = input.targetFocalLengthMm / input.focalLengthMm;\n const crop = calculateCenteredCrop({ pixelWidth: input.pixelWidth, pixelHeight: input.pixelHeight, cropFactor }).value;\n return calculatedResult(\n {\n focalLengthMm: input.focalLengthMm,\n targetFocalLengthMm: input.targetFocalLengthMm,\n cropFactor,\n pixelWidth: crop.pixelWidth,\n pixelHeight: crop.pixelHeight,\n megapixels: crop.megapixels,\n sourceMegapixels: (input.pixelWidth * input.pixelHeight) / 1_000_000,\n retainedAreaFraction: crop.retainedAreaFraction\n },\n \"crop-to-match-focal-length\",\n \"1.0.0\",\n [\n \"Crop factor = target focal length / focal length: exact for ideal rectilinear lenses focused at infinity, from the same camera position.\",\n \"At close focus the thin-lens matching factor is F·(d − f)/(f·(d − F)) at object distance d, larger than F/f; not modelled.\",\n \"Distortion and focus breathing are not modelled.\",\n \"Centred crop that keeps the aspect ratio to whole pixels (calculateCenteredCrop).\"\n ]\n );\n}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { LensCorrectionChannel } from "./lens-corrections.js";
|
|
2
|
+
/**
|
|
3
|
+
* Effective wavelengths of the red, green and blue channels for the lateral-colour map, nm: a generic approximation of where
|
|
4
|
+
* a camera's channel responses peak, not a measured camera.
|
|
5
|
+
*/
|
|
6
|
+
export declare const GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM: Readonly<Record<LensCorrectionChannel, number>>;
|
|
7
|
+
/** @internal The lateral-colour scale of one channel, 1 + L·D(λ_channel) (`D` the catalogue's normalized dispersion). */
|
|
8
|
+
export declare function genericLensChannelScale(fraction: number, dispersion: (wavelengthNm: number) => number, channel: LensCorrectionChannel): number;
|
|
9
|
+
/** @internal Which corrections run. */
|
|
10
|
+
export interface DevelopedLensCorrectionSelection {
|
|
11
|
+
distortion: boolean;
|
|
12
|
+
lateralColor: boolean;
|
|
13
|
+
vignetting: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** @internal A prepared correction for one frame (pixel units). */
|
|
16
|
+
export interface DevelopedLensCorrection {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
/** Half-diagonal R in pixels. */
|
|
20
|
+
radius: number;
|
|
21
|
+
/** k1 (0 when distortion is off), the lens's own k1, and the red, green and blue scales a_c (1 when lateral colour is off). */
|
|
22
|
+
k1: number;
|
|
23
|
+
lensK1: number;
|
|
24
|
+
scales: readonly [number, number, number];
|
|
25
|
+
/** Fill factor m ≤ 1 (1/m is the magnification). */
|
|
26
|
+
fill: number;
|
|
27
|
+
}
|
|
28
|
+
type Rect = {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @internal Prepares the correction of a W × H frame. `lens` is the resolved catalogue lens (`resolveGenericLens`) on the
|
|
36
|
+
* frame; `dispersion` is `genericLensDispersion`. The mapping's source radius grows with the output radius (the catalogue's
|
|
37
|
+
* distortion is monotonic over the frame), so the sources of the border pixel centres bound every source, and the fill factor
|
|
38
|
+
* is found by bisection on them.
|
|
39
|
+
*/
|
|
40
|
+
export declare function prepareDevelopedLensCorrection(lens: {
|
|
41
|
+
halfDiagonalMm: number;
|
|
42
|
+
character: {
|
|
43
|
+
distortion: {
|
|
44
|
+
corner: number;
|
|
45
|
+
};
|
|
46
|
+
lateralColor: {
|
|
47
|
+
fraction: number;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
}, selection: DevelopedLensCorrectionSelection, width: number, height: number, pitchMm: number, dispersion: (wavelengthNm: number) => number): DevelopedLensCorrection;
|
|
51
|
+
/**
|
|
52
|
+
* @internal The developed pixels (a rectangle of the whole frame) that the corrected pixels of `region` read: the bounding box of
|
|
53
|
+
* the region border's sources over the three channels, with their bilinear neighbours, one pixel of margin, clipped to the frame.
|
|
54
|
+
*/
|
|
55
|
+
export declare function developedLensCorrectionSourceRect(c: DevelopedLensCorrection, region: Rect): Rect;
|
|
56
|
+
/**
|
|
57
|
+
* @internal Corrects developed linear RGB (`rgb`, interleaved, the frame's pixels in `source`) into the pixels of `region`, both
|
|
58
|
+
* rectangles of the whole frame. `cornerStops` is the lens's vignetting at the capture's f-number, or null to leave it.
|
|
59
|
+
* Positions outside the frame (none after the fill, up to rounding) are clamped to the edge pixel centres.
|
|
60
|
+
*/
|
|
61
|
+
export declare function applyDevelopedLensCorrection(c: DevelopedLensCorrection, rgb: Float64Array, source: Rect, region: Rect, cornerStops: number | null): Float64Array;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* @internal `output.lensCorrections` (#570): a catalogue lens's generic correction profile (`createGenericLensCorrectionProfile`)
|
|
4
|
+
* applied to the developed linear RGB of `simulateCapture`, after demosaic, colour and white balance and before the tone curve.
|
|
5
|
+
* The RAW and the DNG are never corrected.
|
|
6
|
+
*
|
|
7
|
+
* For an output pixel at p (pixels from the frame centre, +y up) and channel c, the source point is read by inverse mapping,
|
|
8
|
+
* as the profile composes it (lateral colour, then distortion):
|
|
9
|
+
* q = m · a_c · p, s = q · (1 + k1·|q|²/R²),
|
|
10
|
+
* with a_c = 1 + L·D(λ_c) the channel's lateral-colour scale, k1 the lens's corner distortion, R the half-diagonal and m ≤ 1 the
|
|
11
|
+
* fill factor (the largest that keeps every output pixel centre's source inside the frame for every channel, so the output keeps
|
|
12
|
+
* its size with no missing pixels; the image is magnified by 1/m). The channel is sampled bilinearly at s.
|
|
13
|
+
*
|
|
14
|
+
* Vignetting is corrected to a flat field: the sample is multiplied by det J(ρ_i) / E(ρ_s), the inverse of the relative
|
|
15
|
+
* illumination the capture delivered at s: the lens's E(ρ) = (1 − bρ²)² at the sensor point and its distortion's area factor
|
|
16
|
+
* 1/det J, det J = (1 + k1ρ_i²)(1 + 3k1ρ_i²) at the ideal point ρ_i that the lens images to ρ_s (the capture's
|
|
17
|
+
* "inverse-distortion-jacobian"; a relative illumination measured on a flat field contains it too). From profile 1.1.0 (#584) the
|
|
18
|
+
* profile's vignetting component carries the same area factor (`distortionAreaFactor`), and its gain equals this kernel's.
|
|
19
|
+
* Every position is computed in whole-frame pixel coordinates, so a region renders the same values as the whole frame.
|
|
20
|
+
*/
|
|
21
|
+
import { InvalidScientificResultError } from "../core/validation.js";
|
|
22
|
+
/**
|
|
23
|
+
* Effective wavelengths of the red, green and blue channels for the lateral-colour map, nm: a generic approximation of where
|
|
24
|
+
* a camera's channel responses peak, not a measured camera.
|
|
25
|
+
*/
|
|
26
|
+
export const GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM = /* @__PURE__ */ Object.freeze({ red: 610, green: 540, blue: 465 });
|
|
27
|
+
/** @internal The lateral-colour scale of one channel, 1 + L·D(λ_channel) (`D` the catalogue's normalized dispersion). */
|
|
28
|
+
export function genericLensChannelScale(fraction, dispersion, channel) {
|
|
29
|
+
return 1 + fraction * dispersion(GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM[channel]);
|
|
30
|
+
}
|
|
31
|
+
/** Source position (pixel-centre coordinates of the whole frame, unclamped) of output pixel (x, y), channel c. */
|
|
32
|
+
function sourceOf(c, m, x, y, channel, out) {
|
|
33
|
+
const a = m * c.scales[channel], px = (x + 0.5 - c.width / 2) * a, py = (c.height / 2 - y - 0.5) * a;
|
|
34
|
+
const s = 1 + c.k1 * (px * px + py * py) / (c.radius * c.radius);
|
|
35
|
+
out[0] = px * s + c.width / 2 - 0.5;
|
|
36
|
+
out[1] = c.height / 2 - 0.5 - py * s;
|
|
37
|
+
}
|
|
38
|
+
/** Calls `visit` for every pixel centre on the border of `r`. */
|
|
39
|
+
function border(r, visit) {
|
|
40
|
+
for (let x = r.x; x < r.x + r.width; x++) {
|
|
41
|
+
visit(x, r.y);
|
|
42
|
+
visit(x, r.y + r.height - 1);
|
|
43
|
+
}
|
|
44
|
+
for (let y = r.y; y < r.y + r.height; y++) {
|
|
45
|
+
visit(r.x, y);
|
|
46
|
+
visit(r.x + r.width - 1, y);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @internal Prepares the correction of a W × H frame. `lens` is the resolved catalogue lens (`resolveGenericLens`) on the
|
|
51
|
+
* frame; `dispersion` is `genericLensDispersion`. The mapping's source radius grows with the output radius (the catalogue's
|
|
52
|
+
* distortion is monotonic over the frame), so the sources of the border pixel centres bound every source, and the fill factor
|
|
53
|
+
* is found by bisection on them.
|
|
54
|
+
*/
|
|
55
|
+
export function prepareDevelopedLensCorrection(lens, selection, width, height, pitchMm, dispersion) {
|
|
56
|
+
const fraction = selection.lateralColor ? lens.character.lateralColor.fraction : 0;
|
|
57
|
+
const c = { width, height, radius: lens.halfDiagonalMm / pitchMm,
|
|
58
|
+
k1: selection.distortion ? lens.character.distortion.corner : 0, lensK1: lens.character.distortion.corner,
|
|
59
|
+
scales: [genericLensChannelScale(fraction, dispersion, "red"), genericLensChannelScale(fraction, dispersion, "green"), genericLensChannelScale(fraction, dispersion, "blue")], fill: 1 };
|
|
60
|
+
const p = new Float64Array(2), frame = { x: 0, y: 0, width, height };
|
|
61
|
+
const fits = (m) => {
|
|
62
|
+
let ok = true;
|
|
63
|
+
border(frame, (x, y) => {
|
|
64
|
+
for (let k = 0; k < 3 && ok; k++) {
|
|
65
|
+
sourceOf(c, m, x, y, k, p);
|
|
66
|
+
ok = p[0] >= 0 && p[0] <= width - 1 && p[1] >= 0 && p[1] <= height - 1;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return ok;
|
|
70
|
+
};
|
|
71
|
+
if (!fits(1)) {
|
|
72
|
+
let lo = 0.5, hi = 1;
|
|
73
|
+
for (let i = 0; i < 52; i++) {
|
|
74
|
+
const mid = (lo + hi) / 2;
|
|
75
|
+
if (fits(mid))
|
|
76
|
+
lo = mid;
|
|
77
|
+
else
|
|
78
|
+
hi = mid;
|
|
79
|
+
}
|
|
80
|
+
c.fill = lo;
|
|
81
|
+
}
|
|
82
|
+
return c;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* @internal The developed pixels (a rectangle of the whole frame) that the corrected pixels of `region` read: the bounding box of
|
|
86
|
+
* the region border's sources over the three channels, with their bilinear neighbours, one pixel of margin, clipped to the frame.
|
|
87
|
+
*/
|
|
88
|
+
export function developedLensCorrectionSourceRect(c, region) {
|
|
89
|
+
const p = new Float64Array(2);
|
|
90
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
91
|
+
border(region, (x, y) => {
|
|
92
|
+
for (let k = 0; k < 3; k++) {
|
|
93
|
+
sourceOf(c, c.fill, x, y, k, p);
|
|
94
|
+
x0 = Math.min(x0, p[0]);
|
|
95
|
+
x1 = Math.max(x1, p[0]);
|
|
96
|
+
y0 = Math.min(y0, p[1]);
|
|
97
|
+
y1 = Math.max(y1, p[1]);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const left = Math.max(0, Math.floor(x0) - 1), top = Math.max(0, Math.floor(y0) - 1);
|
|
101
|
+
return { x: left, y: top, width: Math.min(c.width - 1, Math.floor(x1) + 2) - left + 1, height: Math.min(c.height - 1, Math.floor(y1) + 2) - top + 1 };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @internal Corrects developed linear RGB (`rgb`, interleaved, the frame's pixels in `source`) into the pixels of `region`, both
|
|
105
|
+
* rectangles of the whole frame. `cornerStops` is the lens's vignetting at the capture's f-number, or null to leave it.
|
|
106
|
+
* Positions outside the frame (none after the fill, up to rounding) are clamped to the edge pixel centres.
|
|
107
|
+
*/
|
|
108
|
+
export function applyDevelopedLensCorrection(c, rgb, source, region, cornerStops) {
|
|
109
|
+
const out = new Float64Array(region.width * region.height * 3), W = c.width, H = c.height, cx = W / 2 - 0.5, cy = H / 2 - 0.5, r2 = c.radius * c.radius;
|
|
110
|
+
const b = cornerStops === null ? 0 : 1 - 2 ** (-cornerStops / 2), k1 = c.k1, lensK1 = c.lensK1;
|
|
111
|
+
for (let y = 0, o = 0; y < region.height; y++)
|
|
112
|
+
for (let x = 0; x < region.width; x++)
|
|
113
|
+
for (let k = 0; k < 3; k++, o++) {
|
|
114
|
+
// sourceOf, inlined (a call per sample is about 5 times slower here): the same arithmetic, so the region bounds hold.
|
|
115
|
+
const a = c.fill * c.scales[k], px = (region.x + x + 0.5 - W / 2) * a, py = (H / 2 - (region.y + y) - 0.5) * a, f = 1 + k1 * (px * px + py * py) / r2;
|
|
116
|
+
const su = px * f + W / 2 - 0.5, sv = H / 2 - 0.5 - py * f;
|
|
117
|
+
const u = Math.min(W - 1, Math.max(0, su)), v = Math.min(H - 1, Math.max(0, sv));
|
|
118
|
+
const i = Math.floor(u), j = Math.floor(v), dx = u - i, dy = v - j, i1 = dx === 0 ? i : i + 1, j1 = dy === 0 ? j : j + 1;
|
|
119
|
+
if (i < source.x || j < source.y || i1 >= source.x + source.width || j1 >= source.y + source.height)
|
|
120
|
+
throw new InvalidScientificResultError("Lens correction read outside the developed rectangle.");
|
|
121
|
+
const row = (j - source.y) * source.width, row1 = (j1 - source.y) * source.width, a0 = i - source.x, a1 = i1 - source.x;
|
|
122
|
+
let value = (1 - dy) * ((1 - dx) * rgb[(row + a0) * 3 + k] + dx * rgb[(row + a1) * 3 + k]) + dy * ((1 - dx) * rgb[(row1 + a0) * 3 + k] + dx * rgb[(row1 + a1) * 3 + k]);
|
|
123
|
+
if (b !== 0) {
|
|
124
|
+
// ρ_s², then ρ_i from ρ_s = ρ_i(1 + k1ρ_i²) by Newton's method (monotonic over the frame; converged to rounding in 4 steps).
|
|
125
|
+
const s2 = ((su - cx) * (su - cx) + (sv - cy) * (sv - cy)) / r2, rs = Math.sqrt(s2), e = 1 - b * s2;
|
|
126
|
+
let ri = rs;
|
|
127
|
+
for (let n = 0; n < 4; n++)
|
|
128
|
+
ri -= (ri * (1 + lensK1 * ri * ri) - rs) / (1 + 3 * lensK1 * ri * ri);
|
|
129
|
+
value *= (1 + lensK1 * ri * ri) * (1 + 3 * lensK1 * ri * ri) / (e * e);
|
|
130
|
+
}
|
|
131
|
+
out[o] = value;
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=developed-lens-corrections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"developed-lens-corrections.js","sourceRoot":"","sources":["../../src/output/developed-lens-corrections.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * @internal `output.lensCorrections` (#570): a catalogue lens's generic correction profile (`createGenericLensCorrectionProfile`)\n * applied to the developed linear RGB of `simulateCapture`, after demosaic, colour and white balance and before the tone curve.\n * The RAW and the DNG are never corrected.\n *\n * For an output pixel at p (pixels from the frame centre, +y up) and channel c, the source point is read by inverse mapping,\n * as the profile composes it (lateral colour, then distortion):\n * q = m · a_c · p, s = q · (1 + k1·|q|²/R²),\n * with a_c = 1 + L·D(λ_c) the channel's lateral-colour scale, k1 the lens's corner distortion, R the half-diagonal and m ≤ 1 the\n * fill factor (the largest that keeps every output pixel centre's source inside the frame for every channel, so the output keeps\n * its size with no missing pixels; the image is magnified by 1/m). The channel is sampled bilinearly at s.\n *\n * Vignetting is corrected to a flat field: the sample is multiplied by det J(ρ_i) / E(ρ_s), the inverse of the relative\n * illumination the capture delivered at s: the lens's E(ρ) = (1 − bρ²)² at the sensor point and its distortion's area factor\n * 1/det J, det J = (1 + k1ρ_i²)(1 + 3k1ρ_i²) at the ideal point ρ_i that the lens images to ρ_s (the capture's\n * \"inverse-distortion-jacobian\"; a relative illumination measured on a flat field contains it too). From profile 1.1.0 (#584) the\n * profile's vignetting component carries the same area factor (`distortionAreaFactor`), and its gain equals this kernel's.\n * Every position is computed in whole-frame pixel coordinates, so a region renders the same values as the whole frame.\n */\n\nimport { InvalidScientificResultError } from \"../core/validation.js\";\nimport type { LensCorrectionChannel } from \"./lens-corrections.js\";\n\n/**\n * Effective wavelengths of the red, green and blue channels for the lateral-colour map, nm: a generic approximation of where\n * a camera's channel responses peak, not a measured camera.\n */\nexport const GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM: Readonly<Record<LensCorrectionChannel, number>> = /* @__PURE__ */ Object.freeze({ red: 610, green: 540, blue: 465 });\n\n/** @internal The lateral-colour scale of one channel, 1 + L·D(λ_channel) (`D` the catalogue's normalized dispersion). */\nexport function genericLensChannelScale(fraction: number, dispersion: (wavelengthNm: number) => number, channel: LensCorrectionChannel): number {\n return 1 + fraction * dispersion(GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM[channel]);\n}\n\n/** @internal Which corrections run. */\nexport interface DevelopedLensCorrectionSelection { distortion: boolean; lateralColor: boolean; vignetting: boolean }\n/** @internal A prepared correction for one frame (pixel units). */\nexport interface DevelopedLensCorrection {\n width: number; height: number;\n /** Half-diagonal R in pixels. */\n radius: number;\n /** k1 (0 when distortion is off), the lens's own k1, and the red, green and blue scales a_c (1 when lateral colour is off). */\n k1: number; lensK1: number; scales: readonly [number, number, number];\n /** Fill factor m ≤ 1 (1/m is the magnification). */\n fill: number;\n}\ntype Rect = { x: number; y: number; width: number; height: number };\n\n/** Source position (pixel-centre coordinates of the whole frame, unclamped) of output pixel (x, y), channel c. */\nfunction sourceOf(c: DevelopedLensCorrection, m: number, x: number, y: number, channel: number, out: Float64Array): void {\n const a = m * c.scales[channel]!, px = (x + 0.5 - c.width / 2) * a, py = (c.height / 2 - y - 0.5) * a;\n const s = 1 + c.k1 * (px * px + py * py) / (c.radius * c.radius);\n out[0] = px * s + c.width / 2 - 0.5; out[1] = c.height / 2 - 0.5 - py * s;\n}\n/** Calls `visit` for every pixel centre on the border of `r`. */\nfunction border(r: Rect, visit: (x: number, y: number) => void): void {\n for (let x = r.x; x < r.x + r.width; x++) { visit(x, r.y); visit(x, r.y + r.height - 1); }\n for (let y = r.y; y < r.y + r.height; y++) { visit(r.x, y); visit(r.x + r.width - 1, y); }\n}\n\n/**\n * @internal Prepares the correction of a W × H frame. `lens` is the resolved catalogue lens (`resolveGenericLens`) on the\n * frame; `dispersion` is `genericLensDispersion`. The mapping's source radius grows with the output radius (the catalogue's\n * distortion is monotonic over the frame), so the sources of the border pixel centres bound every source, and the fill factor\n * is found by bisection on them.\n */\nexport function prepareDevelopedLensCorrection(lens: { halfDiagonalMm: number; character: { distortion: { corner: number }; lateralColor: { fraction: number } } },\n selection: DevelopedLensCorrectionSelection, width: number, height: number, pitchMm: number, dispersion: (wavelengthNm: number) => number): DevelopedLensCorrection {\n const fraction = selection.lateralColor ? lens.character.lateralColor.fraction : 0;\n const c: DevelopedLensCorrection = { width, height, radius: lens.halfDiagonalMm / pitchMm,\n k1: selection.distortion ? lens.character.distortion.corner : 0, lensK1: lens.character.distortion.corner,\n scales: [genericLensChannelScale(fraction, dispersion, \"red\"), genericLensChannelScale(fraction, dispersion, \"green\"), genericLensChannelScale(fraction, dispersion, \"blue\")], fill: 1 };\n const p = new Float64Array(2), frame = { x: 0, y: 0, width, height };\n const fits = (m: number): boolean => {\n let ok = true;\n border(frame, (x, y) => {\n for (let k = 0; k < 3 && ok; k++) { sourceOf(c, m, x, y, k, p); ok = p[0]! >= 0 && p[0]! <= width - 1 && p[1]! >= 0 && p[1]! <= height - 1; }\n });\n return ok;\n };\n if (!fits(1)) {\n let lo = 0.5, hi = 1;\n for (let i = 0; i < 52; i++) { const mid = (lo + hi) / 2; if (fits(mid)) lo = mid; else hi = mid; }\n c.fill = lo;\n }\n return c;\n}\n\n/**\n * @internal The developed pixels (a rectangle of the whole frame) that the corrected pixels of `region` read: the bounding box of\n * the region border's sources over the three channels, with their bilinear neighbours, one pixel of margin, clipped to the frame.\n */\nexport function developedLensCorrectionSourceRect(c: DevelopedLensCorrection, region: Rect): Rect {\n const p = new Float64Array(2);\n let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;\n border(region, (x, y) => {\n for (let k = 0; k < 3; k++) {\n sourceOf(c, c.fill, x, y, k, p);\n x0 = Math.min(x0, p[0]!); x1 = Math.max(x1, p[0]!); y0 = Math.min(y0, p[1]!); y1 = Math.max(y1, p[1]!);\n }\n });\n const left = Math.max(0, Math.floor(x0) - 1), top = Math.max(0, Math.floor(y0) - 1);\n return { x: left, y: top, width: Math.min(c.width - 1, Math.floor(x1) + 2) - left + 1, height: Math.min(c.height - 1, Math.floor(y1) + 2) - top + 1 };\n}\n\n/**\n * @internal Corrects developed linear RGB (`rgb`, interleaved, the frame's pixels in `source`) into the pixels of `region`, both\n * rectangles of the whole frame. `cornerStops` is the lens's vignetting at the capture's f-number, or null to leave it.\n * Positions outside the frame (none after the fill, up to rounding) are clamped to the edge pixel centres.\n */\nexport function applyDevelopedLensCorrection(c: DevelopedLensCorrection, rgb: Float64Array, source: Rect, region: Rect, cornerStops: number | null): Float64Array {\n const out = new Float64Array(region.width * region.height * 3), W = c.width, H = c.height, cx = W / 2 - 0.5, cy = H / 2 - 0.5, r2 = c.radius * c.radius;\n const b = cornerStops === null ? 0 : 1 - 2 ** (-cornerStops / 2), k1 = c.k1, lensK1 = c.lensK1;\n for (let y = 0, o = 0; y < region.height; y++) for (let x = 0; x < region.width; x++) for (let k = 0; k < 3; k++, o++) {\n // sourceOf, inlined (a call per sample is about 5 times slower here): the same arithmetic, so the region bounds hold.\n const a = c.fill * c.scales[k]!, px = (region.x + x + 0.5 - W / 2) * a, py = (H / 2 - (region.y + y) - 0.5) * a, f = 1 + k1 * (px * px + py * py) / r2;\n const su = px * f + W / 2 - 0.5, sv = H / 2 - 0.5 - py * f;\n const u = Math.min(W - 1, Math.max(0, su)), v = Math.min(H - 1, Math.max(0, sv));\n const i = Math.floor(u), j = Math.floor(v), dx = u - i, dy = v - j, i1 = dx === 0 ? i : i + 1, j1 = dy === 0 ? j : j + 1;\n if (i < source.x || j < source.y || i1 >= source.x + source.width || j1 >= source.y + source.height)\n throw new InvalidScientificResultError(\"Lens correction read outside the developed rectangle.\");\n const row = (j - source.y) * source.width, row1 = (j1 - source.y) * source.width, a0 = i - source.x, a1 = i1 - source.x;\n let value = (1 - dy) * ((1 - dx) * rgb[(row + a0) * 3 + k]! + dx * rgb[(row + a1) * 3 + k]!) + dy * ((1 - dx) * rgb[(row1 + a0) * 3 + k]! + dx * rgb[(row1 + a1) * 3 + k]!);\n if (b !== 0) {\n // ρ_s², then ρ_i from ρ_s = ρ_i(1 + k1ρ_i²) by Newton's method (monotonic over the frame; converged to rounding in 4 steps).\n const s2 = ((su - cx) * (su - cx) + (sv - cy) * (sv - cy)) / r2, rs = Math.sqrt(s2), e = 1 - b * s2;\n let ri = rs;\n for (let n = 0; n < 4; n++) ri -= (ri * (1 + lensK1 * ri * ri) - rs) / (1 + 3 * lensK1 * ri * ri);\n value *= (1 + lensK1 * ri * ri) * (1 + 3 * lensK1 * ri * ri) / (e * e);\n }\n out[o] = value;\n }\n return out;\n}\n"]}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { type OpticalProfileState } from "../optics/profile-contract.js";
|
|
2
|
-
import { type GenericLensCorrectionProfile
|
|
3
|
-
|
|
4
|
-
* Effective wavelengths of the red, green and blue channels for the lateral-colour map, nm: a generic approximation of where
|
|
5
|
-
* a camera's channel responses peak, not a measured camera.
|
|
6
|
-
*/
|
|
7
|
-
export declare const GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM: Readonly<Record<LensCorrectionChannel, number>>;
|
|
2
|
+
import { type GenericLensCorrectionProfile } from "./lens-corrections.js";
|
|
3
|
+
export { GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM } from "./developed-lens-corrections.js";
|
|
8
4
|
export interface CreateGenericLensCorrectionProfileInput {
|
|
9
5
|
/** A catalogue id (`GENERIC_LENS_IDS`); `state.lensId` must be the same id. */
|
|
10
6
|
lensId: string;
|
|
@@ -19,6 +15,8 @@ export interface CreateGenericLensCorrectionProfileInput {
|
|
|
19
15
|
/**
|
|
20
16
|
* Builds the catalogue lens's generic correction profile for one camera state: a radial distortion map (the lens's own
|
|
21
17
|
* r_d = r(1 + k1ρ²), read at each ideal destination point), per-channel lateral-colour scales 1 + L·D(λ_channel), and the
|
|
22
|
-
* relative-illumination gain at the state's aperture (strength 1).
|
|
18
|
+
* relative-illumination gain at the state's aperture (strength 1). From profile version 1.1.0 (#584) the vignetting component
|
|
19
|
+
* (version 1.1.0) carries the distortion's area factor (`distortionAreaFactor`): its gain is det J(ρ_i)/E(ρ_s) at the capture's
|
|
20
|
+
* sensor point, so it flattens a flat-field capture. The result passes `parseGenericLensCorrectionProfile`.
|
|
23
21
|
*/
|
|
24
22
|
export declare function createGenericLensCorrectionProfile(input: CreateGenericLensCorrectionProfileInput): GenericLensCorrectionProfile;
|
|
@@ -11,15 +11,14 @@ import { requireInputKeys, requireInputObject } from "../core/record-validation.
|
|
|
11
11
|
import { parseOpticalProfileState } from "../optics/profile-contract.js";
|
|
12
12
|
import { GENERIC_LENS_EVIDENCE, genericLensDispersion, resolveGenericLens } from "../equipment/generic-lens-catalogue.js";
|
|
13
13
|
import { parseGenericLensCorrectionProfile } from "./lens-corrections.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* a camera's channel responses peak, not a measured camera.
|
|
17
|
-
*/
|
|
18
|
-
export const GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM = /* @__PURE__ */ Object.freeze({ red: 610, green: 540, blue: 465 });
|
|
14
|
+
import { genericLensChannelScale } from "./developed-lens-corrections.js";
|
|
15
|
+
export { GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM } from "./developed-lens-corrections.js";
|
|
19
16
|
/**
|
|
20
17
|
* Builds the catalogue lens's generic correction profile for one camera state: a radial distortion map (the lens's own
|
|
21
18
|
* r_d = r(1 + k1ρ²), read at each ideal destination point), per-channel lateral-colour scales 1 + L·D(λ_channel), and the
|
|
22
|
-
* relative-illumination gain at the state's aperture (strength 1).
|
|
19
|
+
* relative-illumination gain at the state's aperture (strength 1). From profile version 1.1.0 (#584) the vignetting component
|
|
20
|
+
* (version 1.1.0) carries the distortion's area factor (`distortionAreaFactor`): its gain is det J(ρ_i)/E(ρ_s) at the capture's
|
|
21
|
+
* sensor point, so it flattens a flat-field capture. The result passes `parseGenericLensCorrectionProfile`.
|
|
23
22
|
*/
|
|
24
23
|
export function createGenericLensCorrectionProfile(input) {
|
|
25
24
|
requireInputObject(input, "createGenericLensCorrectionProfile input");
|
|
@@ -32,10 +31,10 @@ export function createGenericLensCorrectionProfile(input) {
|
|
|
32
31
|
throw new InvalidScientificInputError("state.focalLengthMm must be the " + lens.name + "'s focal length on this sensor, " + lens.focalLengthMm + " mm.");
|
|
33
32
|
const c = lens.character, domain = "reconstructed-linear";
|
|
34
33
|
const identity = { version: "1.0.0", domain, availability: "toggle", defaultEnabled: true, dependencies: [], requiredByStabilizationModes: [] };
|
|
35
|
-
const scale = (channel) =>
|
|
34
|
+
const scale = (channel) => genericLensChannelScale(c.lateralColor.fraction, genericLensDispersion, channel);
|
|
36
35
|
const affine = (channel) => ({ id: lens.lensId + ":lateral-ca:" + channel, version: "1.0.0", domain, purpose: "lateral-ca", kind: "affine",
|
|
37
36
|
matrix: [scale(channel), 0, 0, scale(channel)], offsetMm: { x: 0, y: 0 } });
|
|
38
|
-
return parseGenericLensCorrectionProfile({ schemaVersion: "0.1.0", id: "photivra-" + lens.lensId + ":corrections", version: "1.
|
|
37
|
+
return parseGenericLensCorrectionProfile({ schemaVersion: "0.1.0", id: "photivra-" + lens.lensId + ":corrections", version: "1.1.0", state,
|
|
39
38
|
evidence: { kind: "generic-parametric", basis: "Generic catalogue lens " + lens.name + " (#549): the inverse of its own distortion, lateral colour and vignetting.",
|
|
40
39
|
residualNote: "Generic approximation, not a measured lens; axial colour, coma and the other aberrations stay.", sources: [...GENERIC_LENS_EVIDENCE] },
|
|
41
40
|
components: [
|
|
@@ -44,8 +43,10 @@ export function createGenericLensCorrectionProfile(input) {
|
|
|
44
43
|
profile: { normalizationRadiusMm: lens.halfDiagonalMm, maximumNormalizedRadius: 1.05, coefficients: { k1: c.distortion.corner, k2: 0, k3: 0 } } } },
|
|
45
44
|
{ ...identity, id: "lateral-ca", kind: "lateral-ca", residualNote: "Registers the channels at one effective wavelength each; colour inside a channel's band and axial colour stay.",
|
|
46
45
|
transforms: { red: affine("red"), green: affine("green"), blue: affine("blue") } },
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
// #584 (component 1.1.0): the gain also undoes the distortion's area factor, so a flat field comes out flat.
|
|
47
|
+
{ ...identity, version: "1.1.0", id: "vignetting", kind: "peripheral-illumination",
|
|
48
|
+
residualNote: "Gain det J/E at the capture's sensor point and the profile's aperture (E the lens's relative illumination, 1/det J its distortion's area factor); it raises corner noise with the signal.",
|
|
49
|
+
profile: { ...c.vignetting.profile, maximumNormalizedRadius: 1.05 }, strength: 1, distortionAreaFactor: { ...c.distortion.profile, coefficients: { ...c.distortion.profile.coefficients } } }
|
|
49
50
|
] });
|
|
50
51
|
}
|
|
51
52
|
//# sourceMappingURL=generic-lens-corrections.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-lens-corrections.js","sourceRoot":"","sources":["../../src/output/generic-lens-corrections.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;GAMG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAA4B,MAAM,+BAA+B,CAAC;AACnG,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC1H,OAAO,EAAE,iCAAiC,EAAiE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"generic-lens-corrections.js","sourceRoot":"","sources":["../../src/output/generic-lens-corrections.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The generic correction profile of a catalogue lens (#549), for the post-capture lens corrections\n * (`resolveLensCorrectionPlan`, `calculateLensCorrectedCapture`): a distortion map, a lateral-colour map per channel and a\n * peripheral-illumination gain, each from the lens's own character (`resolveGenericLens`). Consumer lenses rely on it more:\n * their uncorrected distortion and vignetting are larger, so the same profile corrects more. Like every catalogue number it is\n * a labelled approximation, bound to one exact camera state (`OpticalProfileState`).\n */\n\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport { requireInputKeys, requireInputObject } from \"../core/record-validation.js\";\nimport { parseOpticalProfileState, type OpticalProfileState } from \"../optics/profile-contract.js\";\nimport { GENERIC_LENS_EVIDENCE, genericLensDispersion, resolveGenericLens } from \"../equipment/generic-lens-catalogue.js\";\nimport { parseGenericLensCorrectionProfile, type GenericLensCorrectionProfile, type LensCorrectionChannel } from \"./lens-corrections.js\";\nimport type { AffineGeometricTransform } from \"./geometric-transforms.js\";\nimport { genericLensChannelScale } from \"./developed-lens-corrections.js\";\n\nexport { GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM } from \"./developed-lens-corrections.js\";\n\nexport interface CreateGenericLensCorrectionProfileInput {\n /** A catalogue id (`GENERIC_LENS_IDS`); `state.lensId` must be the same id. */\n lensId: string;\n /** The sensor's active capture area, mm (the lens is scaled to it as in `resolveGenericLens`). */\n activeImagingArea: { widthMm: number; heightMm: number };\n /** The exact camera state the profile applies to: its focal length must be the lens's on this sensor, its aperture in range. */\n state: OpticalProfileState;\n}\n\n/**\n * Builds the catalogue lens's generic correction profile for one camera state: a radial distortion map (the lens's own\n * r_d = r(1 + k1ρ²), read at each ideal destination point), per-channel lateral-colour scales 1 + L·D(λ_channel), and the\n * relative-illumination gain at the state's aperture (strength 1). From profile version 1.1.0 (#584) the vignetting component\n * (version 1.1.0) carries the distortion's area factor (`distortionAreaFactor`): its gain is det J(ρ_i)/E(ρ_s) at the capture's\n * sensor point, so it flattens a flat-field capture. The result passes `parseGenericLensCorrectionProfile`.\n */\nexport function createGenericLensCorrectionProfile(input: CreateGenericLensCorrectionProfileInput): GenericLensCorrectionProfile {\n requireInputObject(input, \"createGenericLensCorrectionProfile input\");\n requireInputKeys(input, \"createGenericLensCorrectionProfile\", [\"lensId\", \"activeImagingArea\", \"state\"]);\n const state = parseOpticalProfileState(input.state);\n const lens = resolveGenericLens({ lensId: input.lensId, activeImagingArea: input.activeImagingArea, fNumber: state.aperture });\n if (state.lensId !== lens.lensId) throw new InvalidScientificInputError(\"state.lensId must be the catalogue id \" + lens.lensId + \".\");\n if (Math.abs(state.focalLengthMm - lens.focalLengthMm) > 1e-9 * lens.focalLengthMm)\n throw new InvalidScientificInputError(\"state.focalLengthMm must be the \" + lens.name + \"'s focal length on this sensor, \" + lens.focalLengthMm + \" mm.\");\n const c = lens.character, domain = \"reconstructed-linear\" as const;\n const identity = { version: \"1.0.0\", domain, availability: \"toggle\" as const, defaultEnabled: true, dependencies: [] as string[], requiredByStabilizationModes: [] as string[] };\n const scale = (channel: LensCorrectionChannel): number => genericLensChannelScale(c.lateralColor.fraction, genericLensDispersion, channel);\n const affine = (channel: LensCorrectionChannel): AffineGeometricTransform => ({ id: lens.lensId + \":lateral-ca:\" + channel, version: \"1.0.0\", domain, purpose: \"lateral-ca\" as const, kind: \"affine\" as const,\n matrix: [scale(channel), 0, 0, scale(channel)] as [number, number, number, number], offsetMm: { x: 0, y: 0 } });\n return parseGenericLensCorrectionProfile({ schemaVersion: \"0.1.0\", id: \"photivra-\" + lens.lensId + \":corrections\", version: \"1.1.0\", state,\n evidence: { kind: \"generic-parametric\", basis: \"Generic catalogue lens \" + lens.name + \" (#549): the inverse of its own distortion, lateral colour and vignetting.\",\n residualNote: \"Generic approximation, not a measured lens; axial colour, coma and the other aberrations stay.\", sources: [...GENERIC_LENS_EVIDENCE] },\n components: [\n { ...identity, id: \"distortion\", kind: \"geometry\", residualNote: \"Corrects the lens's radial distortion r_d = r(1 + k1ρ²); the stretched corners lose resolution.\",\n transform: { id: lens.lensId + \":distortion\", version: \"1.0.0\", domain, purpose: \"distortion\", kind: \"radial\",\n profile: { normalizationRadiusMm: lens.halfDiagonalMm, maximumNormalizedRadius: 1.05, coefficients: { k1: c.distortion.corner, k2: 0, k3: 0 } } } },\n { ...identity, id: \"lateral-ca\", kind: \"lateral-ca\", residualNote: \"Registers the channels at one effective wavelength each; colour inside a channel's band and axial colour stay.\",\n transforms: { red: affine(\"red\"), green: affine(\"green\"), blue: affine(\"blue\") } },\n // #584 (component 1.1.0): the gain also undoes the distortion's area factor, so a flat field comes out flat.\n { ...identity, version: \"1.1.0\", id: \"vignetting\", kind: \"peripheral-illumination\",\n residualNote: \"Gain det J/E at the capture's sensor point and the profile's aperture (E the lens's relative illumination, 1/det J its distortion's area factor); it raises corner noise with the signal.\",\n profile: { ...c.vignetting.profile, maximumNormalizedRadius: 1.05 }, strength: 1, distortionAreaFactor: { ...c.distortion.profile, coefficients: { ...c.distortion.profile.coefficients } } }\n ] });\n}\n"]}
|
|
@@ -23,10 +23,7 @@ import { choice, finite, list, positive, record, textValue } from "../optics/pro
|
|
|
23
23
|
import { requireInputObject, requireInputKeys } from "../core/record-validation.js";
|
|
24
24
|
import { brownConradyForwardValue, brownConradyInverseValue, validateBrownConradyDistortionProfile } from "../optics/brown-conrady-distortion.js";
|
|
25
25
|
import { lensProjectionRemapValue, lensProjectionSignedAxisAngle, parseLensProjectionModel } from "../camera/lens-projection.js";
|
|
26
|
-
|
|
27
|
-
const p = record(value, ["x", "y"]);
|
|
28
|
-
return { x: finite(p.x, "x"), y: finite(p.y, "y") };
|
|
29
|
-
}
|
|
26
|
+
import { point } from "../optics/stray-light.js";
|
|
30
27
|
function multiply(a, b) {
|
|
31
28
|
return [a[0] * b[0] + a[1] * b[2], a[0] * b[1] + a[1] * b[3],
|
|
32
29
|
a[2] * b[0] + a[3] * b[2], a[2] * b[1] + a[3] * b[3]];
|