euler-preprocess 3.3.0__tar.gz → 3.5.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.
Files changed (52) hide show
  1. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/PKG-INFO +20 -1
  2. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/README.md +19 -0
  3. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/models.py +21 -18
  4. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/transform.py +772 -48
  5. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess.egg-info/PKG-INFO +20 -1
  6. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/pyproject.toml +1 -1
  7. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_fog_aux_outputs.py +253 -0
  8. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/__init__.py +0 -0
  9. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/cli.py +0 -0
  10. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/__init__.py +0 -0
  11. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/dataset.py +0 -0
  12. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/device.py +0 -0
  13. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/intrinsics.py +0 -0
  14. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/io.py +0 -0
  15. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/logging.py +0 -0
  16. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/noise.py +0 -0
  17. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/normalize.py +0 -0
  18. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/output.py +0 -0
  19. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/sampling.py +0 -0
  20. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/common/transform.py +0 -0
  21. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/__init__.py +0 -0
  22. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/airlight_from_sky.py +0 -0
  23. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/atmospheric_light.py +0 -0
  24. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/augmentations.py +0 -0
  25. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/capture.py +0 -0
  26. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/dcp_airlight.py +0 -0
  27. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/dcp_airlight_torch.py +0 -0
  28. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/dcp_heuristic_airlight.py +0 -0
  29. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/dcp_heuristic_airlight_torch.py +0 -0
  30. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/foggify.py +0 -0
  31. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/foggify_logging.py +0 -0
  32. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/inference.py +0 -0
  33. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/logging.py +0 -0
  34. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/fog/pipeline.py +0 -0
  35. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/radial/__init__.py +0 -0
  36. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/radial/transform.py +0 -0
  37. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/sky_depth/__init__.py +0 -0
  38. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess/sky_depth/transform.py +0 -0
  39. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess.egg-info/SOURCES.txt +0 -0
  40. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess.egg-info/dependency_links.txt +0 -0
  41. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess.egg-info/entry_points.txt +0 -0
  42. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess.egg-info/requires.txt +0 -0
  43. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/euler_preprocess.egg-info/top_level.txt +0 -0
  44. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/setup.cfg +0 -0
  45. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_airlight_fallback.py +0 -0
  46. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_cli_sample_selection.py +0 -0
  47. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_dcp_heuristic_airlight.py +0 -0
  48. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_foggify_integration.py +0 -0
  49. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_radial.py +0 -0
  50. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_sky_depth.py +0 -0
  51. {euler_preprocess-3.3.0 → euler_preprocess-3.5.0}/tests/test_source_backed_output.py +0 -0
  52. {euler_preprocess-3.3.0 → euler_preprocess-3.5.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.0
3
+ Version: 3.5.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
+ "mode": "sample",
151
152
  "device": "cpu",
152
153
  "gpu_batch_size": 4,
153
154
  "capture": { "preset": "camera" },
@@ -165,6 +166,7 @@ Controls the fog simulation.
165
166
  | `depth_scale` | Multiplier applied to depth values after loading. |
166
167
  | `resize_depth` | Resize the depth map to match the RGB resolution (bilinear). |
167
168
  | `contrast_threshold` | Threshold *C_t* used in the visibility-to-attenuation conversion (default `0.05`). |
169
+ | `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. |
168
170
  | `device` | `"cpu"`, `"cuda"`, `"mps"`, or `"gpu"` (alias for cuda). |
169
171
  | `gpu_batch_size` | Batch size when running on GPU. Uniform-model samples are batched; heterogeneous samples are processed individually. |
170
172
  | `capture` / `capture_artifacts` | Optional post-fog camera artifact pipeline. Omit it or set `{"stages": []}` for the legacy no-op path. Set `true`, `{"preset": "camera"}`, or a custom `stages` list to enable optics, raw sensor, ISP, and compression artifacts. |
@@ -404,6 +406,19 @@ compression together:
404
406
  `condition_profiles`; if omitted, the stage continues sampling its own profile
405
407
  weights locally.
406
408
 
409
+ Set top-level `"mode": "progressive"` to emit every configured scenario for
410
+ every input image instead of sampling one scenario. Each scenario accepts
411
+ `"steps"` and `"progressive_weight"` (or `"max_weight"` / `"weight"` as
412
+ aliases); the transform writes steps from weight `0` through the scenario's
413
+ configured weight, and weight `1` matches the original scenario. Fog density is
414
+ progressed in scattering-coefficient space, while numeric camera/config values
415
+ blend from the base config toward the scenario config. Progressive blends clamp
416
+ probability-like values and non-negative physical factors back into valid
417
+ mathematical domains so extrapolated weights above `1` do not create invalid
418
+ render parameters.
419
+ Source-backed outputs are written as `fog_progression` variants under each
420
+ source file id.
421
+
407
422
  ### Fog Model
408
423
 
409
424
  The core equation is the **Koschmieder model** (atmospheric scattering):
@@ -482,6 +497,10 @@ Each fog model can override the dampening curve:
482
497
 
483
498
  The factor is:
484
499
  `min_factor + (max_factor - min_factor) / (1 + strength * beta / reference_beta)`.
500
+ `min_factor` and `max_factor` must be finite and non-negative. Values above
501
+ `1.0` are allowed when you intentionally want to brighten estimated airlight;
502
+ the final RGB output is still clamped to the valid image range. `strength`
503
+ must remain finite and non-negative.
485
504
  `reference_beta` is either `reference_scattering_coefficient` /
486
505
  `reference_beta`, or it is derived from `reference_visibility_m` using the
487
506
  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
+ "mode": "sample",
137
138
  "device": "cpu",
138
139
  "gpu_batch_size": 4,
139
140
  "capture": { "preset": "camera" },
@@ -151,6 +152,7 @@ Controls the fog simulation.
151
152
  | `depth_scale` | Multiplier applied to depth values after loading. |
152
153
  | `resize_depth` | Resize the depth map to match the RGB resolution (bilinear). |
153
154
  | `contrast_threshold` | Threshold *C_t* used in the visibility-to-attenuation conversion (default `0.05`). |
155
+ | `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. |
154
156
  | `device` | `"cpu"`, `"cuda"`, `"mps"`, or `"gpu"` (alias for cuda). |
155
157
  | `gpu_batch_size` | Batch size when running on GPU. Uniform-model samples are batched; heterogeneous samples are processed individually. |
156
158
  | `capture` / `capture_artifacts` | Optional post-fog camera artifact pipeline. Omit it or set `{"stages": []}` for the legacy no-op path. Set `true`, `{"preset": "camera"}`, or a custom `stages` list to enable optics, raw sensor, ISP, and compression artifacts. |
@@ -390,6 +392,19 @@ compression together:
390
392
  `condition_profiles`; if omitted, the stage continues sampling its own profile
391
393
  weights locally.
392
394
 
395
+ Set top-level `"mode": "progressive"` to emit every configured scenario for
396
+ every input image instead of sampling one scenario. Each scenario accepts
397
+ `"steps"` and `"progressive_weight"` (or `"max_weight"` / `"weight"` as
398
+ aliases); the transform writes steps from weight `0` through the scenario's
399
+ configured weight, and weight `1` matches the original scenario. Fog density is
400
+ progressed in scattering-coefficient space, while numeric camera/config values
401
+ blend from the base config toward the scenario config. Progressive blends clamp
402
+ probability-like values and non-negative physical factors back into valid
403
+ mathematical domains so extrapolated weights above `1` do not create invalid
404
+ render parameters.
405
+ Source-backed outputs are written as `fog_progression` variants under each
406
+ source file id.
407
+
393
408
  ### Fog Model
394
409
 
395
410
  The core equation is the **Koschmieder model** (atmospheric scattering):
@@ -468,6 +483,10 @@ Each fog model can override the dampening curve:
468
483
 
469
484
  The factor is:
470
485
  `min_factor + (max_factor - min_factor) / (1 + strength * beta / reference_beta)`.
486
+ `min_factor` and `max_factor` must be finite and non-negative. Values above
487
+ `1.0` are allowed when you intentionally want to brighten estimated airlight;
488
+ the final RGB output is still clamped to the valid image range. `strength`
489
+ must remain finite and non-negative.
471
490
  `reference_beta` is either `reference_scattering_coefficient` /
472
491
  `reference_beta`, or it is derived from `reference_visibility_m` using the
473
492
  model's contrast threshold. The default applies only when `atmospheric_light`
@@ -100,8 +100,12 @@ DEFAULT_MODEL_CONFIGS = {
100
100
 
101
101
 
102
102
  def visibility_to_k(visibility_m: float, contrast_threshold: float) -> float:
103
- if visibility_m <= 0:
103
+ if not math.isfinite(visibility_m) or visibility_m <= 0:
104
104
  raise ValueError(f"Visibility must be > 0, got {visibility_m}")
105
+ if not math.isfinite(contrast_threshold) or not 0.0 < contrast_threshold < 1.0:
106
+ raise ValueError(
107
+ f"Contrast threshold must be in (0, 1), got {contrast_threshold}"
108
+ )
105
109
  return -math.log(contrast_threshold) / visibility_m
106
110
 
107
111
 
@@ -132,7 +136,7 @@ def resolve_scattering_coefficient(
132
136
  beta_spec = model_cfg.get("scattering_coefficient", model_cfg.get("beta"))
133
137
  if beta_spec is not None:
134
138
  beta = float(sample_value(beta_spec, rng))
135
- if beta < 0:
139
+ if not math.isfinite(beta) or beta < 0:
136
140
  raise ValueError(f"Scattering coefficient must be >= 0, got {beta}")
137
141
  return beta, None, contrast_threshold
138
142
 
@@ -222,13 +226,13 @@ def resolve_airlight_dampening_config(
222
226
  rng,
223
227
  "airlight_dampening.strength",
224
228
  )
225
- if not 0.0 <= min_factor <= 1.0:
229
+ if min_factor < 0.0:
226
230
  raise ValueError(
227
- f"airlight_dampening.min_factor must be in [0, 1], got {min_factor}"
231
+ f"airlight_dampening.min_factor must be >= 0, got {min_factor}"
228
232
  )
229
- if not 0.0 <= max_factor <= 1.0:
233
+ if max_factor < 0.0:
230
234
  raise ValueError(
231
- f"airlight_dampening.max_factor must be in [0, 1], got {max_factor}"
235
+ f"airlight_dampening.max_factor must be >= 0, got {max_factor}"
232
236
  )
233
237
  if min_factor > max_factor:
234
238
  raise ValueError("airlight_dampening.min_factor must be <= max_factor")
@@ -504,9 +508,12 @@ def _scale_pixels(value, rng: np.random.Generator, name: str) -> int:
504
508
  def _sample_float(value, rng: np.random.Generator, name: str) -> float:
505
509
  sampled = sample_value(value, rng)
506
510
  try:
507
- return float(sampled)
511
+ resolved = float(sampled)
508
512
  except (TypeError, ValueError) as exc:
509
513
  raise ValueError(f"{name} must resolve to a number, got {sampled!r}") from exc
514
+ if not math.isfinite(resolved):
515
+ raise ValueError(f"{name} must be finite, got {resolved}")
516
+ return resolved
510
517
 
511
518
 
512
519
  def _unique_positive_scales(scales: list[int]) -> list[int]:
@@ -801,9 +808,11 @@ def _gradient_enabled(
801
808
  rng,
802
809
  f"{name}.probability",
803
810
  )
804
- if not 0.0 <= probability <= 1.0:
805
- raise ValueError(f"{name}.probability must be in [0, 1], got {probability}")
806
- return probability >= 1.0 or bool(rng.random() < probability)
811
+ if probability <= 0.0:
812
+ return False
813
+ if probability >= 1.0:
814
+ return True
815
+ return bool(rng.random() < probability)
807
816
 
808
817
 
809
818
  def _ls_gradient_factors_np(
@@ -885,10 +894,7 @@ def _weight_ls_gradient_by_opacity_np(
885
894
  rng,
886
895
  "ls_gradient.fog_opacity_weight",
887
896
  )
888
- if not 0.0 <= weight <= 1.0:
889
- raise ValueError(
890
- f"ls_gradient.fog_opacity_weight must be in [0, 1], got {weight}"
891
- )
897
+ weight = float(np.clip(weight, 0.0, 1.0))
892
898
  if weight <= 0.0:
893
899
  return factors
894
900
  gamma = _sample_float(
@@ -917,10 +923,7 @@ def _weight_ls_gradient_by_opacity_torch(
917
923
  rng,
918
924
  "ls_gradient.fog_opacity_weight",
919
925
  )
920
- if not 0.0 <= weight <= 1.0:
921
- raise ValueError(
922
- f"ls_gradient.fog_opacity_weight must be in [0, 1], got {weight}"
923
- )
926
+ weight = float(np.clip(weight, 0.0, 1.0))
924
927
  if weight <= 0.0:
925
928
  return factors
926
929
  gamma = _sample_float(