euler-preprocess 3.6.0__tar.gz → 3.9.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.9.0/MANIFEST.in +1 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/PKG-INFO +1 -1
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/inference.py +5 -9
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/models.py +260 -5
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/pipeline.py +87 -23
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/transform.py +198 -115
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess.egg-info/PKG-INFO +1 -1
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess.egg-info/SOURCES.txt +3 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/pyproject.toml +1 -1
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_dense_gloomy_daylight_config.py +42 -5
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_fog_aux_outputs.py +87 -0
- euler_preprocess-3.9.0/tests/test_fog_cpu_gpu_parity.py +522 -0
- euler_preprocess-3.9.0/tests/test_real_drive_sim_scenario_profiles.py +425 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/README.md +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/__init__.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/cli.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/__init__.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/color.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/dataset.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/device.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/intrinsics.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/io.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/logging.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/noise.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/normalize.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/output.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/sampling.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/common/transform.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/__init__.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/airlight_from_sky.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/atmospheric_light.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/augmentations.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/capture.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/dcp_airlight.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/dcp_airlight_torch.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/dcp_heuristic_airlight.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/dcp_heuristic_airlight_torch.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/foggify.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/foggify_logging.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/fog/logging.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/radial/__init__.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/radial/transform.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/sky_depth/__init__.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess/sky_depth/transform.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess.egg-info/dependency_links.txt +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess.egg-info/entry_points.txt +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess.egg-info/requires.txt +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/euler_preprocess.egg-info/top_level.txt +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/setup.cfg +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_airlight_fallback.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_cli_sample_selection.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_dcp_heuristic_airlight.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_fog_aware_auto_exposure.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_foggify_integration.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_radial.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_scene_illumination.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_sensor_identity.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_sky_depth.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_source_backed_output.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_tone_map_lut.py +0 -0
- {euler_preprocess-3.6.0 → euler_preprocess-3.9.0}/tests/test_zip_output.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-exclude tests/fixtures *.zip
|
|
@@ -264,6 +264,7 @@ def _render_cpu(
|
|
|
264
264
|
intrinsics=intrinsics_np,
|
|
265
265
|
airlight_method=plan.airlight_method,
|
|
266
266
|
capture_artifacts=plan.capture_artifacts,
|
|
267
|
+
clear_weather=plan.clear_weather,
|
|
267
268
|
)
|
|
268
269
|
return FogInferenceResult(
|
|
269
270
|
rgb=np.asarray(result.rgb, dtype=np.float32),
|
|
@@ -300,30 +301,25 @@ def _render_gpu(
|
|
|
300
301
|
depth_t = planar_to_radial_depth_torch(depth_t, K_t)
|
|
301
302
|
|
|
302
303
|
sky_mask_t = torch.from_numpy(sky_mask).to(device=device, dtype=torch.bool)
|
|
303
|
-
estimated_airlight = transform._estimate_airlight_torch(
|
|
304
|
-
rgb_t,
|
|
305
|
-
sky_mask_t,
|
|
306
|
-
sample_id=sample_id,
|
|
307
|
-
method=plan.airlight_method,
|
|
308
|
-
)
|
|
309
304
|
torch_gen = torch_generator_for_index(
|
|
310
305
|
transform.torch_device,
|
|
311
306
|
transform.seed,
|
|
312
307
|
transform.base_rng,
|
|
313
308
|
sample_index,
|
|
314
309
|
)
|
|
315
|
-
foggy_t, beta, airlight_t, k_map_t, ls_map_t = transform.
|
|
310
|
+
foggy_t, beta, airlight_t, k_map_t, ls_map_t = transform._process_torch_pipeline(
|
|
316
311
|
rgb_t,
|
|
317
312
|
depth_t,
|
|
313
|
+
sky_mask_t,
|
|
318
314
|
plan.model_name,
|
|
319
315
|
plan.model_cfg,
|
|
320
316
|
rng,
|
|
321
|
-
estimated_airlight,
|
|
322
317
|
torch_gen,
|
|
323
318
|
sample_id=sample_id,
|
|
324
319
|
intrinsics=intrinsics_np,
|
|
325
|
-
|
|
320
|
+
airlight_method=plan.airlight_method,
|
|
326
321
|
capture_artifacts=plan.capture_artifacts,
|
|
322
|
+
clear_weather=plan.clear_weather,
|
|
327
323
|
)
|
|
328
324
|
return FogInferenceResult(
|
|
329
325
|
rgb=torch.clamp(foggy_t, 0.0, 1.0).detach().cpu().numpy().astype(np.float32),
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import math
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
import numpy as np
|
|
7
8
|
|
|
@@ -1088,6 +1089,115 @@ def apply_scene_illumination_np(
|
|
|
1088
1089
|
return (radiance * scale[..., None]).astype(np.float32, copy=False), ev_map
|
|
1089
1090
|
|
|
1090
1091
|
|
|
1092
|
+
def apply_scene_illumination_torch(
|
|
1093
|
+
rgb_lin: "torch.Tensor",
|
|
1094
|
+
depth_m: "torch.Tensor",
|
|
1095
|
+
k_field,
|
|
1096
|
+
model_cfg: dict,
|
|
1097
|
+
rng: np.random.Generator,
|
|
1098
|
+
sky_mask: "torch.Tensor | None" = None,
|
|
1099
|
+
) -> tuple["torch.Tensor", "torch.Tensor"]:
|
|
1100
|
+
"""Torch equivalent of :func:`apply_scene_illumination_np`."""
|
|
1101
|
+
height, width = int(depth_m.shape[0]), int(depth_m.shape[1])
|
|
1102
|
+
cfg = _resolve_scene_illumination_config(model_cfg)
|
|
1103
|
+
enabled = cfg.get("enabled", False)
|
|
1104
|
+
if not isinstance(enabled, bool):
|
|
1105
|
+
raise ValueError("scene_illumination.enabled must be a boolean")
|
|
1106
|
+
if not enabled:
|
|
1107
|
+
return rgb_lin.to(dtype=torch.float32), torch.zeros(
|
|
1108
|
+
(height, width),
|
|
1109
|
+
device=rgb_lin.device,
|
|
1110
|
+
dtype=torch.float32,
|
|
1111
|
+
)
|
|
1112
|
+
|
|
1113
|
+
global_ev = _sample_float(
|
|
1114
|
+
cfg.get("global_ev", 0.0),
|
|
1115
|
+
rng,
|
|
1116
|
+
"scene_illumination.global_ev",
|
|
1117
|
+
)
|
|
1118
|
+
near_ev = _sample_float(
|
|
1119
|
+
cfg.get("near_ev", 0.0),
|
|
1120
|
+
rng,
|
|
1121
|
+
"scene_illumination.near_ev",
|
|
1122
|
+
)
|
|
1123
|
+
decay_depth = max(
|
|
1124
|
+
_sample_float(
|
|
1125
|
+
cfg.get("near_decay_depth_m", 15.0),
|
|
1126
|
+
rng,
|
|
1127
|
+
"scene_illumination.near_decay_depth_m",
|
|
1128
|
+
),
|
|
1129
|
+
1e-6,
|
|
1130
|
+
)
|
|
1131
|
+
fog_ev = _sample_float(
|
|
1132
|
+
cfg.get("fog_coupled_ev", 0.0),
|
|
1133
|
+
rng,
|
|
1134
|
+
"scene_illumination.fog_coupled_ev",
|
|
1135
|
+
)
|
|
1136
|
+
|
|
1137
|
+
depth = _sanitize_depth_torch(depth_m).to(
|
|
1138
|
+
device=rgb_lin.device,
|
|
1139
|
+
dtype=rgb_lin.dtype,
|
|
1140
|
+
)
|
|
1141
|
+
k_map = torch.clamp(
|
|
1142
|
+
broadcast_k_field_torch(
|
|
1143
|
+
k_field,
|
|
1144
|
+
height,
|
|
1145
|
+
width,
|
|
1146
|
+
device=rgb_lin.device,
|
|
1147
|
+
dtype=rgb_lin.dtype,
|
|
1148
|
+
),
|
|
1149
|
+
min=0.0,
|
|
1150
|
+
)
|
|
1151
|
+
near_weight = torch.exp(-depth / decay_depth)
|
|
1152
|
+
fog_opacity = 1.0 - torch.exp(-k_map * depth)
|
|
1153
|
+
ev_map = (
|
|
1154
|
+
global_ev + near_ev * near_weight + fog_ev * torch.clamp(fog_opacity, 0.0, 1.0)
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
if sky_mask is not None:
|
|
1158
|
+
sky = torch.as_tensor(
|
|
1159
|
+
sky_mask,
|
|
1160
|
+
device=rgb_lin.device,
|
|
1161
|
+
dtype=rgb_lin.dtype,
|
|
1162
|
+
)
|
|
1163
|
+
if tuple(sky.shape) != (height, width):
|
|
1164
|
+
raise ValueError(
|
|
1165
|
+
f"sky_mask must have shape ({height}, {width}); got {tuple(sky.shape)}"
|
|
1166
|
+
)
|
|
1167
|
+
sky_weight = float(
|
|
1168
|
+
np.clip(
|
|
1169
|
+
_sample_float(
|
|
1170
|
+
cfg.get("sky_weight", 0.0),
|
|
1171
|
+
rng,
|
|
1172
|
+
"scene_illumination.sky_weight",
|
|
1173
|
+
),
|
|
1174
|
+
0.0,
|
|
1175
|
+
1.0,
|
|
1176
|
+
)
|
|
1177
|
+
)
|
|
1178
|
+
ev_map = ev_map * (1.0 - torch.clamp(sky, 0.0, 1.0) * (1.0 - sky_weight))
|
|
1179
|
+
|
|
1180
|
+
min_scale = max(
|
|
1181
|
+
_sample_float(
|
|
1182
|
+
cfg.get("min_radiance_scale", 0.08),
|
|
1183
|
+
rng,
|
|
1184
|
+
"scene_illumination.min_radiance_scale",
|
|
1185
|
+
),
|
|
1186
|
+
0.0,
|
|
1187
|
+
)
|
|
1188
|
+
scale = torch.maximum(
|
|
1189
|
+
torch.exp2(-ev_map),
|
|
1190
|
+
torch.full_like(ev_map, min_scale),
|
|
1191
|
+
)
|
|
1192
|
+
radiance = torch.nan_to_num(
|
|
1193
|
+
rgb_lin.to(dtype=torch.float32),
|
|
1194
|
+
nan=0.0,
|
|
1195
|
+
posinf=1.0,
|
|
1196
|
+
neginf=0.0,
|
|
1197
|
+
)
|
|
1198
|
+
return radiance * scale[..., None], ev_map
|
|
1199
|
+
|
|
1200
|
+
|
|
1091
1201
|
def _apply_scene_airlight_dampening_np(
|
|
1092
1202
|
ls_field: np.ndarray,
|
|
1093
1203
|
ev_map: np.ndarray,
|
|
@@ -1109,6 +1219,33 @@ def _apply_scene_airlight_dampening_np(
|
|
|
1109
1219
|
return np.clip(ls_map * scale[..., None], 0.0, 1.0).astype(np.float32, copy=False)
|
|
1110
1220
|
|
|
1111
1221
|
|
|
1222
|
+
def _apply_scene_airlight_dampening_torch(
|
|
1223
|
+
ls_field: "torch.Tensor",
|
|
1224
|
+
ev_map: "torch.Tensor",
|
|
1225
|
+
model_cfg: dict,
|
|
1226
|
+
rng: np.random.Generator,
|
|
1227
|
+
) -> "torch.Tensor":
|
|
1228
|
+
cfg = _resolve_scene_illumination_config(model_cfg)
|
|
1229
|
+
if not bool(cfg.get("enabled", False)):
|
|
1230
|
+
return ls_field.to(dtype=torch.float32)
|
|
1231
|
+
ratio = _sample_float(
|
|
1232
|
+
cfg.get("airlight_ev_ratio", 0.0),
|
|
1233
|
+
rng,
|
|
1234
|
+
"scene_illumination.airlight_ev_ratio",
|
|
1235
|
+
)
|
|
1236
|
+
if ratio <= 0.0:
|
|
1237
|
+
return ls_field.to(dtype=torch.float32)
|
|
1238
|
+
scale = torch.exp2(-torch.clamp(ev_map, min=0.0) * ratio)
|
|
1239
|
+
ls_map = broadcast_ls_field_torch(
|
|
1240
|
+
ls_field,
|
|
1241
|
+
int(ev_map.shape[0]),
|
|
1242
|
+
int(ev_map.shape[1]),
|
|
1243
|
+
device=ev_map.device,
|
|
1244
|
+
dtype=ev_map.dtype,
|
|
1245
|
+
)
|
|
1246
|
+
return torch.clamp(ls_map * scale[..., None], 0.0, 1.0)
|
|
1247
|
+
|
|
1248
|
+
|
|
1112
1249
|
def apply_fog(
|
|
1113
1250
|
rgb: np.ndarray, depth_m: np.ndarray, k_field: np.ndarray, ls_field: np.ndarray
|
|
1114
1251
|
) -> np.ndarray:
|
|
@@ -1140,6 +1277,127 @@ def apply_fog_torch(
|
|
|
1140
1277
|
return rgb * t + ls_field * (1.0 - t)
|
|
1141
1278
|
|
|
1142
1279
|
|
|
1280
|
+
def broadcast_k_field_torch(
|
|
1281
|
+
k_field,
|
|
1282
|
+
height: int,
|
|
1283
|
+
width: int,
|
|
1284
|
+
*,
|
|
1285
|
+
device,
|
|
1286
|
+
dtype,
|
|
1287
|
+
) -> "torch.Tensor":
|
|
1288
|
+
"""Return ``k_field`` as a Torch ``(H, W)`` map."""
|
|
1289
|
+
field = torch.as_tensor(k_field, device=device, dtype=dtype)
|
|
1290
|
+
if field.ndim == 0:
|
|
1291
|
+
return field.expand(height, width)
|
|
1292
|
+
if tuple(field.shape) == (height, width):
|
|
1293
|
+
return field
|
|
1294
|
+
raise ValueError(
|
|
1295
|
+
f"k_field must be scalar or shape ({height}, {width}); got {tuple(field.shape)}"
|
|
1296
|
+
)
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
def broadcast_ls_field_torch(
|
|
1300
|
+
ls_field,
|
|
1301
|
+
height: int,
|
|
1302
|
+
width: int,
|
|
1303
|
+
*,
|
|
1304
|
+
device,
|
|
1305
|
+
dtype,
|
|
1306
|
+
) -> "torch.Tensor":
|
|
1307
|
+
"""Return ``ls_field`` as a Torch ``(H, W, 3)`` map."""
|
|
1308
|
+
field = torch.as_tensor(ls_field, device=device, dtype=dtype)
|
|
1309
|
+
if tuple(field.shape) == (3,):
|
|
1310
|
+
return field.view(1, 1, 3).expand(height, width, 3)
|
|
1311
|
+
if tuple(field.shape) == (1, 1, 3):
|
|
1312
|
+
return field.expand(height, width, 3)
|
|
1313
|
+
if tuple(field.shape) == (height, width, 3):
|
|
1314
|
+
return field
|
|
1315
|
+
raise ValueError(
|
|
1316
|
+
f"ls_field must have shape (3,), (1, 1, 3), or "
|
|
1317
|
+
f"({height}, {width}, 3); got {tuple(field.shape)}"
|
|
1318
|
+
)
|
|
1319
|
+
|
|
1320
|
+
|
|
1321
|
+
def render_fog_fields_np(
|
|
1322
|
+
rgb: np.ndarray,
|
|
1323
|
+
depth_m: np.ndarray,
|
|
1324
|
+
k_field,
|
|
1325
|
+
ls_field: np.ndarray,
|
|
1326
|
+
model_cfg: dict,
|
|
1327
|
+
rng: np.random.Generator,
|
|
1328
|
+
*,
|
|
1329
|
+
sky_mask: np.ndarray | None = None,
|
|
1330
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
1331
|
+
"""Render resolved fog fields with the shared CPU scene semantics."""
|
|
1332
|
+
height, width = depth_m.shape
|
|
1333
|
+
scene_rgb, ev_map = apply_scene_illumination_np(
|
|
1334
|
+
rgb,
|
|
1335
|
+
depth_m,
|
|
1336
|
+
k_field,
|
|
1337
|
+
model_cfg,
|
|
1338
|
+
rng,
|
|
1339
|
+
sky_mask=sky_mask,
|
|
1340
|
+
)
|
|
1341
|
+
rendered_ls_field = _apply_scene_airlight_dampening_np(
|
|
1342
|
+
ls_field,
|
|
1343
|
+
ev_map,
|
|
1344
|
+
model_cfg,
|
|
1345
|
+
rng,
|
|
1346
|
+
)
|
|
1347
|
+
foggy = apply_fog(scene_rgb, depth_m, k_field, rendered_ls_field)
|
|
1348
|
+
return (
|
|
1349
|
+
foggy,
|
|
1350
|
+
broadcast_k_field(k_field, height, width),
|
|
1351
|
+
broadcast_ls_field(rendered_ls_field, height, width),
|
|
1352
|
+
)
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
def render_fog_fields_torch(
|
|
1356
|
+
rgb: "torch.Tensor",
|
|
1357
|
+
depth_m: "torch.Tensor",
|
|
1358
|
+
k_field,
|
|
1359
|
+
ls_field: "torch.Tensor",
|
|
1360
|
+
model_cfg: dict,
|
|
1361
|
+
rng: np.random.Generator,
|
|
1362
|
+
*,
|
|
1363
|
+
sky_mask: "torch.Tensor | None" = None,
|
|
1364
|
+
) -> tuple["torch.Tensor", "torch.Tensor", "torch.Tensor"]:
|
|
1365
|
+
"""Render resolved fog fields with CPU-equivalent Torch semantics."""
|
|
1366
|
+
height, width = int(depth_m.shape[0]), int(depth_m.shape[1])
|
|
1367
|
+
scene_rgb, ev_map = apply_scene_illumination_torch(
|
|
1368
|
+
rgb,
|
|
1369
|
+
depth_m,
|
|
1370
|
+
k_field,
|
|
1371
|
+
model_cfg,
|
|
1372
|
+
rng,
|
|
1373
|
+
sky_mask=sky_mask,
|
|
1374
|
+
)
|
|
1375
|
+
rendered_ls_field = _apply_scene_airlight_dampening_torch(
|
|
1376
|
+
ls_field,
|
|
1377
|
+
ev_map,
|
|
1378
|
+
model_cfg,
|
|
1379
|
+
rng,
|
|
1380
|
+
)
|
|
1381
|
+
foggy = apply_fog_torch(scene_rgb, depth_m, k_field, rendered_ls_field)
|
|
1382
|
+
return (
|
|
1383
|
+
foggy,
|
|
1384
|
+
broadcast_k_field_torch(
|
|
1385
|
+
k_field,
|
|
1386
|
+
height,
|
|
1387
|
+
width,
|
|
1388
|
+
device=rgb.device,
|
|
1389
|
+
dtype=rgb.dtype,
|
|
1390
|
+
),
|
|
1391
|
+
broadcast_ls_field_torch(
|
|
1392
|
+
rendered_ls_field,
|
|
1393
|
+
height,
|
|
1394
|
+
width,
|
|
1395
|
+
device=rgb.device,
|
|
1396
|
+
dtype=rgb.dtype,
|
|
1397
|
+
),
|
|
1398
|
+
)
|
|
1399
|
+
|
|
1400
|
+
|
|
1143
1401
|
def select_model(config: dict, rng: np.random.Generator) -> str:
|
|
1144
1402
|
selection = config.get("selection")
|
|
1145
1403
|
if selection is None:
|
|
@@ -1288,16 +1546,13 @@ def apply_model(
|
|
|
1288
1546
|
else:
|
|
1289
1547
|
ls_field = ls_base.reshape(1, 1, 3)
|
|
1290
1548
|
|
|
1291
|
-
|
|
1549
|
+
foggy, k_map, ls_map = render_fog_fields_np(
|
|
1292
1550
|
rgb,
|
|
1293
1551
|
depth_m,
|
|
1294
1552
|
k_field,
|
|
1553
|
+
ls_field,
|
|
1295
1554
|
model_cfg,
|
|
1296
1555
|
rng,
|
|
1297
1556
|
sky_mask=sky_mask,
|
|
1298
1557
|
)
|
|
1299
|
-
ls_field = _apply_scene_airlight_dampening_np(ls_field, ev_map, model_cfg, rng)
|
|
1300
|
-
foggy = apply_fog(scene_rgb, depth_m, k_field, ls_field)
|
|
1301
|
-
k_map = broadcast_k_field(k_field, height, width)
|
|
1302
|
-
ls_map = broadcast_ls_field(ls_field, height, width)
|
|
1303
1558
|
return foggy, k_mean, ls_base, k_map, ls_map
|
|
@@ -5,7 +5,12 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
|
-
from euler_preprocess.common.color import
|
|
8
|
+
from euler_preprocess.common.color import (
|
|
9
|
+
linear_to_srgb,
|
|
10
|
+
linear_to_srgb_torch,
|
|
11
|
+
srgb_to_linear,
|
|
12
|
+
srgb_to_linear_torch,
|
|
13
|
+
)
|
|
9
14
|
from euler_preprocess.fog.atmospheric_light import AtmosphericLightResolver
|
|
10
15
|
from euler_preprocess.fog.capture import CaptureArtifactPipeline, CaptureContext
|
|
11
16
|
from euler_preprocess.fog.models import apply_model
|
|
@@ -71,9 +76,7 @@ class FogProcessingPipeline:
|
|
|
71
76
|
sample_id: str | None,
|
|
72
77
|
airlight_method: str | None = None,
|
|
73
78
|
) -> FogPipelineResult:
|
|
74
|
-
render_input_space =
|
|
75
|
-
model_cfg.get("render_input_space", self.render_input_space)
|
|
76
|
-
)
|
|
79
|
+
render_input_space = self.render_input_space_for(model_cfg)
|
|
77
80
|
rgb_for_render = srgb_to_linear(rgb) if render_input_space == "srgb" else rgb
|
|
78
81
|
estimated_airlight = self.atmospheric_light.estimate_np(
|
|
79
82
|
rgb_for_render,
|
|
@@ -101,6 +104,61 @@ class FogProcessingPipeline:
|
|
|
101
104
|
ls_map=ls_map,
|
|
102
105
|
)
|
|
103
106
|
|
|
107
|
+
def render_input_space_for(self, model_cfg: dict) -> str:
|
|
108
|
+
"""Resolve the input encoding used by both scene-rendering backends."""
|
|
109
|
+
return _normalize_render_input_space(
|
|
110
|
+
model_cfg.get("render_input_space", self.render_input_space)
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def prepare_render_rgb_torch(self, rgb, model_cfg: dict):
|
|
114
|
+
"""Convert display RGB to the scene-linear domain when configured."""
|
|
115
|
+
if self.render_input_space_for(model_cfg) == "srgb":
|
|
116
|
+
return srgb_to_linear_torch(rgb)
|
|
117
|
+
return rgb
|
|
118
|
+
|
|
119
|
+
def restore_render_rgb_torch(
|
|
120
|
+
self,
|
|
121
|
+
rgb,
|
|
122
|
+
model_cfg: dict,
|
|
123
|
+
*,
|
|
124
|
+
clear_weather: bool = False,
|
|
125
|
+
):
|
|
126
|
+
"""Return a rendered Torch image to the CPU pathway's output domain."""
|
|
127
|
+
if not clear_weather and self.render_input_space_for(model_cfg) == "srgb":
|
|
128
|
+
return linear_to_srgb_torch(rgb)
|
|
129
|
+
return rgb
|
|
130
|
+
|
|
131
|
+
def capture_context(
|
|
132
|
+
self,
|
|
133
|
+
*,
|
|
134
|
+
sample_id: str | None,
|
|
135
|
+
rng: np.random.Generator,
|
|
136
|
+
model_cfg: dict,
|
|
137
|
+
sky_mask,
|
|
138
|
+
airlight,
|
|
139
|
+
intrinsics=None,
|
|
140
|
+
depth_m=None,
|
|
141
|
+
k_map=None,
|
|
142
|
+
device=None,
|
|
143
|
+
) -> CaptureContext:
|
|
144
|
+
"""Build the complete capture context shared by CPU and Torch routes."""
|
|
145
|
+
return CaptureContext(
|
|
146
|
+
sample_id=sample_id,
|
|
147
|
+
rng=rng,
|
|
148
|
+
device=device,
|
|
149
|
+
intrinsics=intrinsics,
|
|
150
|
+
depth_m=depth_m,
|
|
151
|
+
k_map=k_map,
|
|
152
|
+
attributes={
|
|
153
|
+
"sky_mask": sky_mask,
|
|
154
|
+
"airlight": airlight,
|
|
155
|
+
"render_input_space": model_cfg.get(
|
|
156
|
+
"render_input_space",
|
|
157
|
+
self.render_input_space,
|
|
158
|
+
),
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
|
|
104
162
|
def process_np(
|
|
105
163
|
self,
|
|
106
164
|
*,
|
|
@@ -114,33 +172,39 @@ class FogProcessingPipeline:
|
|
|
114
172
|
intrinsics: np.ndarray | None = None,
|
|
115
173
|
airlight_method: str | None = None,
|
|
116
174
|
capture_artifacts: CaptureArtifactPipeline | None = None,
|
|
175
|
+
clear_weather: bool = False,
|
|
117
176
|
) -> FogPipelineResult:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
177
|
+
if clear_weather:
|
|
178
|
+
height, width = depth_m.shape
|
|
179
|
+
result = FogPipelineResult(
|
|
180
|
+
rgb=rgb,
|
|
181
|
+
beta=0.0,
|
|
182
|
+
airlight=np.zeros(3, dtype=np.float32),
|
|
183
|
+
k_map=np.zeros((height, width), dtype=np.float32),
|
|
184
|
+
ls_map=np.zeros((height, width, 3), dtype=np.float32),
|
|
185
|
+
)
|
|
186
|
+
else:
|
|
187
|
+
result = self.render_scene_np(
|
|
188
|
+
rgb=rgb,
|
|
189
|
+
depth_m=depth_m,
|
|
190
|
+
sky_mask=sky_mask,
|
|
191
|
+
model_name=model_name,
|
|
192
|
+
model_cfg=model_cfg,
|
|
193
|
+
rng=rng,
|
|
194
|
+
sample_id=sample_id,
|
|
195
|
+
airlight_method=airlight_method,
|
|
196
|
+
)
|
|
128
197
|
return self.apply_capture_np(
|
|
129
198
|
result,
|
|
130
|
-
context=
|
|
199
|
+
context=self.capture_context(
|
|
131
200
|
sample_id=sample_id,
|
|
132
201
|
rng=rng,
|
|
202
|
+
model_cfg=model_cfg,
|
|
203
|
+
sky_mask=sky_mask,
|
|
204
|
+
airlight=result.airlight,
|
|
133
205
|
intrinsics=intrinsics,
|
|
134
206
|
depth_m=depth_m,
|
|
135
207
|
k_map=result.k_map,
|
|
136
|
-
attributes={
|
|
137
|
-
"sky_mask": sky_mask,
|
|
138
|
-
"airlight": result.airlight,
|
|
139
|
-
"render_input_space": model_cfg.get(
|
|
140
|
-
"render_input_space",
|
|
141
|
-
self.render_input_space,
|
|
142
|
-
),
|
|
143
|
-
},
|
|
144
208
|
),
|
|
145
209
|
capture_artifacts=capture_artifacts,
|
|
146
210
|
)
|