euler-preprocess 3.4.0__tar.gz → 3.6.0__tar.gz
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.
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/PKG-INFO +74 -7
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/README.md +73 -6
- euler_preprocess-3.6.0/euler_preprocess/common/color.py +50 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/capture.py +1034 -99
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/models.py +193 -33
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/pipeline.py +30 -2
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/transform.py +111 -9
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess.egg-info/PKG-INFO +74 -7
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess.egg-info/SOURCES.txt +6 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/pyproject.toml +1 -1
- euler_preprocess-3.6.0/tests/test_dense_gloomy_daylight_config.py +76 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_fog_aux_outputs.py +134 -0
- euler_preprocess-3.6.0/tests/test_fog_aware_auto_exposure.py +96 -0
- euler_preprocess-3.6.0/tests/test_scene_illumination.py +96 -0
- euler_preprocess-3.6.0/tests/test_sensor_identity.py +108 -0
- euler_preprocess-3.6.0/tests/test_tone_map_lut.py +37 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/__init__.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/cli.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/__init__.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/dataset.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/device.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/intrinsics.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/io.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/logging.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/noise.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/normalize.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/output.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/sampling.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/common/transform.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/__init__.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/airlight_from_sky.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/atmospheric_light.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/augmentations.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/dcp_airlight.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/dcp_airlight_torch.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/dcp_heuristic_airlight.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/dcp_heuristic_airlight_torch.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/foggify.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/foggify_logging.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/inference.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/fog/logging.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/radial/__init__.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/radial/transform.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/sky_depth/__init__.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess/sky_depth/transform.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess.egg-info/dependency_links.txt +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess.egg-info/entry_points.txt +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess.egg-info/requires.txt +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/euler_preprocess.egg-info/top_level.txt +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/setup.cfg +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_airlight_fallback.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_cli_sample_selection.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_dcp_heuristic_airlight.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_foggify_integration.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_radial.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_sky_depth.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_source_backed_output.py +0 -0
- {euler_preprocess-3.4.0 → euler_preprocess-3.6.0}/tests/test_zip_output.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-preprocess
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.0
|
|
4
4
|
Summary: Physics-based preprocessing (fog, etc.) for RGB+depth datasets
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -148,6 +148,7 @@ Controls the fog simulation.
|
|
|
148
148
|
"depth_scale": 1.0,
|
|
149
149
|
"resize_depth": true,
|
|
150
150
|
"contrast_threshold": 0.05,
|
|
151
|
+
"render_input_space": "srgb",
|
|
151
152
|
"mode": "sample",
|
|
152
153
|
"device": "cpu",
|
|
153
154
|
"gpu_batch_size": 4,
|
|
@@ -166,6 +167,7 @@ Controls the fog simulation.
|
|
|
166
167
|
| `depth_scale` | Multiplier applied to depth values after loading. |
|
|
167
168
|
| `resize_depth` | Resize the depth map to match the RGB resolution (bilinear). |
|
|
168
169
|
| `contrast_threshold` | Threshold *C_t* used in the visibility-to-attenuation conversion (default `0.05`). |
|
|
170
|
+
| `render_input_space` | Colour space of the RGB supplied to the fog renderer. Use `"srgb"` for display-encoded dataset images so fog and airlight are mixed in scene-linear RGB; use `"linear"` for legacy configs or already-linear radiance. |
|
|
169
171
|
| `mode` | Optional scenario mode. Omit it or use `"sample"` for current one-scenario-per-image behavior; use `"progressive"` to render every scenario step for every image. |
|
|
170
172
|
| `device` | `"cpu"`, `"cuda"`, `"mps"`, or `"gpu"` (alias for cuda). |
|
|
171
173
|
| `gpu_batch_size` | Batch size when running on GPU. Uniform-model samples are batched; heterogeneous samples are processed individually. |
|
|
@@ -310,6 +312,22 @@ the exposure; `resolve_iso` can raise ISO from the metering pressure, dark pixel
|
|
|
310
312
|
fraction, and fog opacity. When auto exposure is enabled, `exposure_gain` still
|
|
311
313
|
applies as scenario-specific exposure compensation.
|
|
312
314
|
|
|
315
|
+
Fog-aware metering modes use `CaptureContext.depth_m`, `k_map`, fog opacity, and
|
|
316
|
+
`attributes.sky_mask` when available. Use `"metering":
|
|
317
|
+
"fog_aware_center_weighted"` or `"sky_aware_center_weighted"` and tune
|
|
318
|
+
`sky_suppression`, `fog_meter_suppression`, `depth_meter_decay_m`, and
|
|
319
|
+
`min_meter_weight` to keep bright sky or dense far-field airlight from dominating
|
|
320
|
+
the exposure meter. Legacy metering modes are unchanged unless these suppression
|
|
321
|
+
keys are present.
|
|
322
|
+
|
|
323
|
+
Set `sensor.sensor_identity.enabled` for persistent sensor structure across
|
|
324
|
+
frames. The identity cache is deterministic for the same `sensor_id`, `seed`,
|
|
325
|
+
image shape, and Bayer pattern. `prnu_sigma` adds multiplicative pixel-response
|
|
326
|
+
non-uniformity before shot noise; `dsnu_sigma`, `persistent_row_sigma`, and
|
|
327
|
+
`persistent_column_sigma` add fixed raw-domain offsets; persistent hot/dead pixel
|
|
328
|
+
probabilities create stable bad-pixel masks that combine with the existing
|
|
329
|
+
per-image bad-pixel probabilities.
|
|
330
|
+
|
|
313
331
|
Set `sensor.shadow_recovery_noise.enabled` to add extra post-demosaic luma and
|
|
314
332
|
chroma corruption only where the pre-exposure rendered luminance was low. This
|
|
315
333
|
is useful for reducing broad global grain while keeping lifted shadows visibly
|
|
@@ -361,6 +379,20 @@ gain, read noise, banding, and dark/fog noise modulation should move together:
|
|
|
361
379
|
}
|
|
362
380
|
```
|
|
363
381
|
|
|
382
|
+
`isp.tone_map` supports `"reinhard"`, `"aces"`, `"clip"`, and `"lut"`. The LUT
|
|
383
|
+
mode uses a cheap interpolated 1D camera-response curve:
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
{
|
|
387
|
+
"type": "isp",
|
|
388
|
+
"tone_map": "lut",
|
|
389
|
+
"tone_map_strength": 1.0,
|
|
390
|
+
"tone_map_lut": [0.0, 0.006, 0.014, 0.028, 0.052, 0.090, 0.145, 0.220, 0.320, 0.450, 0.610, 0.780, 0.900, 0.965, 0.995, 1.0],
|
|
391
|
+
"tone_map_lut_domain": "linear",
|
|
392
|
+
"gamma": "srgb"
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
364
396
|
Top-level `scenario_profiles` sample one latent scene/camera condition before
|
|
365
397
|
rendering. The selected scenario is merged over the root config, so it can drive
|
|
366
398
|
fog density, atmospheric light, camera profile, capture-stage overrides, ISP, and
|
|
@@ -390,11 +422,30 @@ compression together:
|
|
|
390
422
|
"airlight_method": "dcp_heuristic",
|
|
391
423
|
"models": {
|
|
392
424
|
"heterogeneous_k_ls": {
|
|
393
|
-
"visibility_m": {"dist": "uniform", "min": 18.0, "max": 55.0}
|
|
425
|
+
"visibility_m": {"dist": "uniform", "min": 18.0, "max": 55.0},
|
|
426
|
+
"scene_illumination": {
|
|
427
|
+
"enabled": true,
|
|
428
|
+
"global_ev": {"dist": "uniform", "min": 0.25, "max": 0.85},
|
|
429
|
+
"near_ev": {"dist": "uniform", "min": 0.35, "max": 1.20},
|
|
430
|
+
"near_decay_depth_m": {"dist": "uniform", "min": 10.0, "max": 22.0},
|
|
431
|
+
"fog_coupled_ev": {"dist": "uniform", "min": 0.10, "max": 0.45},
|
|
432
|
+
"sky_weight": 0.0
|
|
433
|
+
}
|
|
394
434
|
}
|
|
395
435
|
},
|
|
396
436
|
"capture_overrides": {
|
|
397
|
-
"sensor": {
|
|
437
|
+
"sensor": {
|
|
438
|
+
"condition_profile": "underexposed_noisy",
|
|
439
|
+
"auto_exposure": {
|
|
440
|
+
"enabled": true,
|
|
441
|
+
"metering": "fog_aware_center_weighted",
|
|
442
|
+
"target_luminance": {"dist": "uniform", "min": 0.13, "max": 0.20},
|
|
443
|
+
"highlight_protection": 0.78,
|
|
444
|
+
"manual_gain_weight": 0.0,
|
|
445
|
+
"sky_suppression": 0.85,
|
|
446
|
+
"fog_meter_suppression": 0.65
|
|
447
|
+
}
|
|
448
|
+
},
|
|
398
449
|
"transport": {"jpeg": {"quality": {"dist": "uniform", "min": 54, "max": 78}}}
|
|
399
450
|
}
|
|
400
451
|
}
|
|
@@ -408,10 +459,14 @@ weights locally.
|
|
|
408
459
|
|
|
409
460
|
Set top-level `"mode": "progressive"` to emit every configured scenario for
|
|
410
461
|
every input image instead of sampling one scenario. Each scenario accepts
|
|
411
|
-
`"steps"` and `"
|
|
412
|
-
the
|
|
413
|
-
|
|
414
|
-
|
|
462
|
+
`"steps"` and `"progressive_weight"` (or `"max_weight"` / `"weight"` as
|
|
463
|
+
aliases); the transform writes steps from weight `0` through the scenario's
|
|
464
|
+
configured weight, and weight `1` matches the original scenario. Fog density is
|
|
465
|
+
progressed in scattering-coefficient space, while numeric camera/config values
|
|
466
|
+
blend from the base config toward the scenario config. Progressive blends clamp
|
|
467
|
+
probability-like values and non-negative physical factors back into valid
|
|
468
|
+
mathematical domains so extrapolated weights above `1` do not create invalid
|
|
469
|
+
render parameters.
|
|
415
470
|
Source-backed outputs are written as `fog_progression` variants under each
|
|
416
471
|
source file id.
|
|
417
472
|
|
|
@@ -432,6 +487,14 @@ where:
|
|
|
432
487
|
|
|
433
488
|
Distant objects are attenuated more (`t` approaches 0) and replaced by airlight, just as in real fog.
|
|
434
489
|
|
|
490
|
+
For gloomy conditions, add `scene_illumination` inside a fog model config. This
|
|
491
|
+
darkens pre-fog scene radiance `I(x)` before the atmospheric scattering equation,
|
|
492
|
+
so near objects can become plausibly overcast or storm-lit instead of passing
|
|
493
|
+
through unchanged. `global_ev` applies to the whole non-sky scene, `near_ev` adds
|
|
494
|
+
extra near-field darkening with `near_decay_depth_m`, `fog_coupled_ev` adds a
|
|
495
|
+
term proportional to local fog opacity, and `sky_weight: 0.0` preserves sky
|
|
496
|
+
pixels when a sky mask is available.
|
|
497
|
+
|
|
435
498
|
### How Each Modality is Used
|
|
436
499
|
|
|
437
500
|
**RGB** — The clean scene image. Normalised to float32 in [0, 1]. This is the *I(x)* term in the fog equation -- it gets blended with the airlight according to transmittance.
|
|
@@ -493,6 +556,10 @@ Each fog model can override the dampening curve:
|
|
|
493
556
|
|
|
494
557
|
The factor is:
|
|
495
558
|
`min_factor + (max_factor - min_factor) / (1 + strength * beta / reference_beta)`.
|
|
559
|
+
`min_factor` and `max_factor` must be finite and non-negative. Values above
|
|
560
|
+
`1.0` are allowed when you intentionally want to brighten estimated airlight;
|
|
561
|
+
the final RGB output is still clamped to the valid image range. `strength`
|
|
562
|
+
must remain finite and non-negative.
|
|
496
563
|
`reference_beta` is either `reference_scattering_coefficient` /
|
|
497
564
|
`reference_beta`, or it is derived from `reference_visibility_m` using the
|
|
498
565
|
model's contrast threshold. The default applies only when `atmospheric_light`
|
|
@@ -134,6 +134,7 @@ Controls the fog simulation.
|
|
|
134
134
|
"depth_scale": 1.0,
|
|
135
135
|
"resize_depth": true,
|
|
136
136
|
"contrast_threshold": 0.05,
|
|
137
|
+
"render_input_space": "srgb",
|
|
137
138
|
"mode": "sample",
|
|
138
139
|
"device": "cpu",
|
|
139
140
|
"gpu_batch_size": 4,
|
|
@@ -152,6 +153,7 @@ Controls the fog simulation.
|
|
|
152
153
|
| `depth_scale` | Multiplier applied to depth values after loading. |
|
|
153
154
|
| `resize_depth` | Resize the depth map to match the RGB resolution (bilinear). |
|
|
154
155
|
| `contrast_threshold` | Threshold *C_t* used in the visibility-to-attenuation conversion (default `0.05`). |
|
|
156
|
+
| `render_input_space` | Colour space of the RGB supplied to the fog renderer. Use `"srgb"` for display-encoded dataset images so fog and airlight are mixed in scene-linear RGB; use `"linear"` for legacy configs or already-linear radiance. |
|
|
155
157
|
| `mode` | Optional scenario mode. Omit it or use `"sample"` for current one-scenario-per-image behavior; use `"progressive"` to render every scenario step for every image. |
|
|
156
158
|
| `device` | `"cpu"`, `"cuda"`, `"mps"`, or `"gpu"` (alias for cuda). |
|
|
157
159
|
| `gpu_batch_size` | Batch size when running on GPU. Uniform-model samples are batched; heterogeneous samples are processed individually. |
|
|
@@ -296,6 +298,22 @@ the exposure; `resolve_iso` can raise ISO from the metering pressure, dark pixel
|
|
|
296
298
|
fraction, and fog opacity. When auto exposure is enabled, `exposure_gain` still
|
|
297
299
|
applies as scenario-specific exposure compensation.
|
|
298
300
|
|
|
301
|
+
Fog-aware metering modes use `CaptureContext.depth_m`, `k_map`, fog opacity, and
|
|
302
|
+
`attributes.sky_mask` when available. Use `"metering":
|
|
303
|
+
"fog_aware_center_weighted"` or `"sky_aware_center_weighted"` and tune
|
|
304
|
+
`sky_suppression`, `fog_meter_suppression`, `depth_meter_decay_m`, and
|
|
305
|
+
`min_meter_weight` to keep bright sky or dense far-field airlight from dominating
|
|
306
|
+
the exposure meter. Legacy metering modes are unchanged unless these suppression
|
|
307
|
+
keys are present.
|
|
308
|
+
|
|
309
|
+
Set `sensor.sensor_identity.enabled` for persistent sensor structure across
|
|
310
|
+
frames. The identity cache is deterministic for the same `sensor_id`, `seed`,
|
|
311
|
+
image shape, and Bayer pattern. `prnu_sigma` adds multiplicative pixel-response
|
|
312
|
+
non-uniformity before shot noise; `dsnu_sigma`, `persistent_row_sigma`, and
|
|
313
|
+
`persistent_column_sigma` add fixed raw-domain offsets; persistent hot/dead pixel
|
|
314
|
+
probabilities create stable bad-pixel masks that combine with the existing
|
|
315
|
+
per-image bad-pixel probabilities.
|
|
316
|
+
|
|
299
317
|
Set `sensor.shadow_recovery_noise.enabled` to add extra post-demosaic luma and
|
|
300
318
|
chroma corruption only where the pre-exposure rendered luminance was low. This
|
|
301
319
|
is useful for reducing broad global grain while keeping lifted shadows visibly
|
|
@@ -347,6 +365,20 @@ gain, read noise, banding, and dark/fog noise modulation should move together:
|
|
|
347
365
|
}
|
|
348
366
|
```
|
|
349
367
|
|
|
368
|
+
`isp.tone_map` supports `"reinhard"`, `"aces"`, `"clip"`, and `"lut"`. The LUT
|
|
369
|
+
mode uses a cheap interpolated 1D camera-response curve:
|
|
370
|
+
|
|
371
|
+
```json
|
|
372
|
+
{
|
|
373
|
+
"type": "isp",
|
|
374
|
+
"tone_map": "lut",
|
|
375
|
+
"tone_map_strength": 1.0,
|
|
376
|
+
"tone_map_lut": [0.0, 0.006, 0.014, 0.028, 0.052, 0.090, 0.145, 0.220, 0.320, 0.450, 0.610, 0.780, 0.900, 0.965, 0.995, 1.0],
|
|
377
|
+
"tone_map_lut_domain": "linear",
|
|
378
|
+
"gamma": "srgb"
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
350
382
|
Top-level `scenario_profiles` sample one latent scene/camera condition before
|
|
351
383
|
rendering. The selected scenario is merged over the root config, so it can drive
|
|
352
384
|
fog density, atmospheric light, camera profile, capture-stage overrides, ISP, and
|
|
@@ -376,11 +408,30 @@ compression together:
|
|
|
376
408
|
"airlight_method": "dcp_heuristic",
|
|
377
409
|
"models": {
|
|
378
410
|
"heterogeneous_k_ls": {
|
|
379
|
-
"visibility_m": {"dist": "uniform", "min": 18.0, "max": 55.0}
|
|
411
|
+
"visibility_m": {"dist": "uniform", "min": 18.0, "max": 55.0},
|
|
412
|
+
"scene_illumination": {
|
|
413
|
+
"enabled": true,
|
|
414
|
+
"global_ev": {"dist": "uniform", "min": 0.25, "max": 0.85},
|
|
415
|
+
"near_ev": {"dist": "uniform", "min": 0.35, "max": 1.20},
|
|
416
|
+
"near_decay_depth_m": {"dist": "uniform", "min": 10.0, "max": 22.0},
|
|
417
|
+
"fog_coupled_ev": {"dist": "uniform", "min": 0.10, "max": 0.45},
|
|
418
|
+
"sky_weight": 0.0
|
|
419
|
+
}
|
|
380
420
|
}
|
|
381
421
|
},
|
|
382
422
|
"capture_overrides": {
|
|
383
|
-
"sensor": {
|
|
423
|
+
"sensor": {
|
|
424
|
+
"condition_profile": "underexposed_noisy",
|
|
425
|
+
"auto_exposure": {
|
|
426
|
+
"enabled": true,
|
|
427
|
+
"metering": "fog_aware_center_weighted",
|
|
428
|
+
"target_luminance": {"dist": "uniform", "min": 0.13, "max": 0.20},
|
|
429
|
+
"highlight_protection": 0.78,
|
|
430
|
+
"manual_gain_weight": 0.0,
|
|
431
|
+
"sky_suppression": 0.85,
|
|
432
|
+
"fog_meter_suppression": 0.65
|
|
433
|
+
}
|
|
434
|
+
},
|
|
384
435
|
"transport": {"jpeg": {"quality": {"dist": "uniform", "min": 54, "max": 78}}}
|
|
385
436
|
}
|
|
386
437
|
}
|
|
@@ -394,10 +445,14 @@ weights locally.
|
|
|
394
445
|
|
|
395
446
|
Set top-level `"mode": "progressive"` to emit every configured scenario for
|
|
396
447
|
every input image instead of sampling one scenario. Each scenario accepts
|
|
397
|
-
`"steps"` and `"
|
|
398
|
-
the
|
|
399
|
-
|
|
400
|
-
|
|
448
|
+
`"steps"` and `"progressive_weight"` (or `"max_weight"` / `"weight"` as
|
|
449
|
+
aliases); the transform writes steps from weight `0` through the scenario's
|
|
450
|
+
configured weight, and weight `1` matches the original scenario. Fog density is
|
|
451
|
+
progressed in scattering-coefficient space, while numeric camera/config values
|
|
452
|
+
blend from the base config toward the scenario config. Progressive blends clamp
|
|
453
|
+
probability-like values and non-negative physical factors back into valid
|
|
454
|
+
mathematical domains so extrapolated weights above `1` do not create invalid
|
|
455
|
+
render parameters.
|
|
401
456
|
Source-backed outputs are written as `fog_progression` variants under each
|
|
402
457
|
source file id.
|
|
403
458
|
|
|
@@ -418,6 +473,14 @@ where:
|
|
|
418
473
|
|
|
419
474
|
Distant objects are attenuated more (`t` approaches 0) and replaced by airlight, just as in real fog.
|
|
420
475
|
|
|
476
|
+
For gloomy conditions, add `scene_illumination` inside a fog model config. This
|
|
477
|
+
darkens pre-fog scene radiance `I(x)` before the atmospheric scattering equation,
|
|
478
|
+
so near objects can become plausibly overcast or storm-lit instead of passing
|
|
479
|
+
through unchanged. `global_ev` applies to the whole non-sky scene, `near_ev` adds
|
|
480
|
+
extra near-field darkening with `near_decay_depth_m`, `fog_coupled_ev` adds a
|
|
481
|
+
term proportional to local fog opacity, and `sky_weight: 0.0` preserves sky
|
|
482
|
+
pixels when a sky mask is available.
|
|
483
|
+
|
|
421
484
|
### How Each Modality is Used
|
|
422
485
|
|
|
423
486
|
**RGB** — The clean scene image. Normalised to float32 in [0, 1]. This is the *I(x)* term in the fog equation -- it gets blended with the airlight according to transmittance.
|
|
@@ -479,6 +542,10 @@ Each fog model can override the dampening curve:
|
|
|
479
542
|
|
|
480
543
|
The factor is:
|
|
481
544
|
`min_factor + (max_factor - min_factor) / (1 + strength * beta / reference_beta)`.
|
|
545
|
+
`min_factor` and `max_factor` must be finite and non-negative. Values above
|
|
546
|
+
`1.0` are allowed when you intentionally want to brighten estimated airlight;
|
|
547
|
+
the final RGB output is still clamped to the valid image range. `strength`
|
|
548
|
+
must remain finite and non-negative.
|
|
482
549
|
`reference_beta` is either `reference_scattering_coefficient` /
|
|
483
550
|
`reference_beta`, or it is derived from `reference_visibility_m` using the
|
|
484
551
|
model's contrast threshold. The default applies only when `atmospheric_light`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
import torch
|
|
7
|
+
except ImportError: # pragma: no cover - torch is optional
|
|
8
|
+
torch = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def srgb_to_linear(image: np.ndarray) -> np.ndarray:
|
|
12
|
+
"""Convert display-encoded sRGB values in ``[0, 1]`` to scene-linear RGB."""
|
|
13
|
+
img = np.clip(np.asarray(image, dtype=np.float32), 0.0, 1.0)
|
|
14
|
+
return np.where(
|
|
15
|
+
img <= 0.04045,
|
|
16
|
+
img / 12.92,
|
|
17
|
+
((img + 0.055) / 1.055) ** 2.4,
|
|
18
|
+
).astype(np.float32, copy=False)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def linear_to_srgb(image: np.ndarray) -> np.ndarray:
|
|
22
|
+
"""Convert scene-linear RGB values in ``[0, 1]`` to display sRGB."""
|
|
23
|
+
img = np.clip(np.asarray(image, dtype=np.float32), 0.0, 1.0)
|
|
24
|
+
return np.where(
|
|
25
|
+
img <= 0.0031308,
|
|
26
|
+
img * 12.92,
|
|
27
|
+
1.055 * np.power(img, 1.0 / 2.4) - 0.055,
|
|
28
|
+
).astype(np.float32, copy=False)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def srgb_to_linear_torch(image):
|
|
32
|
+
if torch is None: # pragma: no cover - defensive
|
|
33
|
+
raise RuntimeError("Torch color conversion requested but torch is unavailable")
|
|
34
|
+
img = torch.clamp(image, 0.0, 1.0)
|
|
35
|
+
return torch.where(
|
|
36
|
+
img <= 0.04045,
|
|
37
|
+
img / 12.92,
|
|
38
|
+
torch.pow((img + 0.055) / 1.055, 2.4),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def linear_to_srgb_torch(image):
|
|
43
|
+
if torch is None: # pragma: no cover - defensive
|
|
44
|
+
raise RuntimeError("Torch color conversion requested but torch is unavailable")
|
|
45
|
+
img = torch.clamp(image, 0.0, 1.0)
|
|
46
|
+
return torch.where(
|
|
47
|
+
img <= 0.0031308,
|
|
48
|
+
img * 12.92,
|
|
49
|
+
1.055 * torch.pow(img, 1.0 / 2.4) - 0.055,
|
|
50
|
+
)
|