euler-preprocess 3.18.0__tar.gz → 3.20.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.20.0/CHANGELOG.md +73 -0
- {euler_preprocess-3.18.0/euler_preprocess.egg-info → euler_preprocess-3.20.0}/PKG-INFO +138 -3
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/README.md +135 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/docs/plans/coherent-cropping.md +198 -40
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/cli.py +44 -2
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/intrinsics.py +26 -6
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/output.py +157 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/__init__.py +1 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/calibration.py +103 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/files.py +84 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/label_files.py +183 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/roles.py +208 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/run.py +915 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/spec.py +444 -0
- euler_preprocess-3.20.0/euler_preprocess/crop/verify.py +109 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0/euler_preprocess.egg-info}/PKG-INFO +138 -3
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess.egg-info/SOURCES.txt +14 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess.egg-info/requires.txt +2 -2
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/pyproject.toml +3 -3
- euler_preprocess-3.20.0/tests/test_crop.py +423 -0
- euler_preprocess-3.20.0/tests/test_crop_labels.py +255 -0
- euler_preprocess-3.20.0/tests/test_crop_muses.py +267 -0
- euler_preprocess-3.20.0/tests/test_crop_roles.py +84 -0
- euler_preprocess-3.20.0/tests/test_crop_spec.py +195 -0
- euler_preprocess-3.20.0/tests/test_intrinsics.py +30 -0
- euler_preprocess-3.18.0/CHANGELOG.md +0 -14
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/LICENSE +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/MANIFEST.in +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/docs/spatial.md +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/__init__.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/__init__.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/color.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/dataset.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/device.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/io.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/logging.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/noise.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/normalize.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/sampling.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/common/transform.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/__init__.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/airlight_from_sky.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/atmospheric_light.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/augmentations.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/capture.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/dcp_airlight.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/dcp_airlight_torch.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/dcp_heuristic_airlight.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/dcp_heuristic_airlight_torch.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/inference.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/logging.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/models.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/pipeline.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/fog/transform.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/lidar_motion/__init__.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/lidar_motion/compensation.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/lidar_motion/transform.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/radial/__init__.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/radial/transform.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/sky_depth/__init__.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/sky_depth/transform.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess/spatial.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess.egg-info/dependency_links.txt +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess.egg-info/entry_points.txt +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/euler_preprocess.egg-info/top_level.txt +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/examples/spatial-five-field.json +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/setup.cfg +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_airlight_fallback.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_cli_sample_selection.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_dcp_heuristic_airlight.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_dense_gloomy_daylight_config.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_fog_aux_outputs.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_fog_aware_auto_exposure.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_fog_cpu_gpu_parity.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_fog_input_normalization.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_fog_integration.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_lidar_motion.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_modality_roles.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_radial.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_real_drive_sim_scenario_profiles.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_scene_illumination.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_sensor_identity.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_sky_depth.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_source_backed_output.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_spatial.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_tone_map_lut.py +0 -0
- {euler_preprocess-3.18.0 → euler_preprocess-3.20.0}/tests/test_zip_output.py +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- `crop` crops label rasters in the stored file: semantic segmentation (the
|
|
6
|
+
ground truth that also holds the sky), instance and panoptic segmentation,
|
|
7
|
+
and sky masks.
|
|
8
|
+
- PNG, TIFF and BMP keep their mode, palette, bit depth and every channel;
|
|
9
|
+
`.npy`/`.npz` keep their dtype and other arrays.
|
|
10
|
+
- The result must decode exactly as the crop of the source labels.
|
|
11
|
+
- So no class is lost to a writer that re-encodes only what one loader
|
|
12
|
+
function returns: Real Drive Sim's non-red channels, or every class but
|
|
13
|
+
the sky for a dataset read through `sky_mask`. Label modalities no longer
|
|
14
|
+
need a writer.
|
|
15
|
+
- Files that cannot be kept (JPEG, 16-bit colour PNGs) are re-encoded with
|
|
16
|
+
the writer, with a warning.
|
|
17
|
+
- Labels can only be resized with `nearest`; another `resize.interpolation`
|
|
18
|
+
for them is an error.
|
|
19
|
+
|
|
20
|
+
- `crop` supports MUSES (with euler-loading 2.35.0's MUSES writers):
|
|
21
|
+
- `calib.json` holds the frame camera's `K` and every extrinsic. The
|
|
22
|
+
`intrinsics` modality patches it once, and every other modality indexing
|
|
23
|
+
the same file, or a byte-identical copy (`camera_extrinsics`,
|
|
24
|
+
`lidar_to_gnss`), is written with the patched bytes, so the bundle holds
|
|
25
|
+
one `K`. What each of them reads from the patched file must stay as it was;
|
|
26
|
+
two intrinsics modalities patching one file differently are refused.
|
|
27
|
+
- GNSS records (`gnss`) and `meta.json` timing (`sensor_timing`) are copied
|
|
28
|
+
unchanged by default.
|
|
29
|
+
- `configs/crop_muses_hood_config.json` cuts the engine hood off the
|
|
30
|
+
1920×1080 frame camera images (bottom 160 rows, 1920×920 stay), with
|
|
31
|
+
`configs/crop_muses_dataset_config.json` as the dataset config.
|
|
32
|
+
- Require euler-loading 2.35.0 for the MUSES writers.
|
|
33
|
+
|
|
34
|
+
- Add `euler-preprocess lidar-motion`, which compensates scanning-lidar points for
|
|
35
|
+
the vehicle's motion during the sweep. It follows the MUSES SDK, moving each
|
|
36
|
+
point to the frame camera's mid-exposure using the `gnss`, `sensor_timing`
|
|
37
|
+
and `lidar_to_gnss` modalities.
|
|
38
|
+
- Require euler-loading 2.32.0, the first release with `muses.gnss`,
|
|
39
|
+
`muses.sensor_timing`, `muses.read_lidar_to_gnss` and `muses.write_sparse_depth`.
|
|
40
|
+
- Add `euler-preprocess crop`, which crops RGB, depth, intrinsics and
|
|
41
|
+
extrinsics coherently. The box is given as fractions or pixels, either removed
|
|
42
|
+
per edge or kept with an anchor, relative to a reference raster. Rasters are
|
|
43
|
+
sliced, pinhole intrinsics get `cx -= left`, `cy -= top` merged into a copy of
|
|
44
|
+
their file, and lidar point clouds and extrinsics are copied unchanged. Each
|
|
45
|
+
modality's treatment comes from its loader annotation, not its name. Shared
|
|
46
|
+
calibration files are written once, and samples with different crops cannot
|
|
47
|
+
share one. The outputs are reopened and checked against the crop.
|
|
48
|
+
`configs/crop_stf_valid_region_config.json` removes SeeingThroughFog's black
|
|
49
|
+
rectification border.
|
|
50
|
+
- `crop` phase 3:
|
|
51
|
+
- `point_clouds: "prune_to_crop"` keeps only the lidar points that project
|
|
52
|
+
into the output image (`z > 0`, `rint(K'·T·X)` inside), the projection
|
|
53
|
+
consumers such as dmd3c-euler use;
|
|
54
|
+
- `resize` (`size` or `scale`) after the crop, with `K' = S·C·K`; colour
|
|
55
|
+
images are interpolated bilinearly, all other rasters take the nearest
|
|
56
|
+
pixel;
|
|
57
|
+
- `"output_layout": "scoped"` writes one root (directory or zip) with one
|
|
58
|
+
metadata scope per modality, as dmd3c-euler's `--dataset-root` reads;
|
|
59
|
+
- every encoded raster or pruned cloud is decoded again and must reproduce
|
|
60
|
+
the values;
|
|
61
|
+
- `euler-preprocess crop-box` prints the pixel box and the matching
|
|
62
|
+
`spatial` preprocessing block.
|
|
63
|
+
- `crop` uses the new public euler-loading accessors (`get_loader_meta`,
|
|
64
|
+
`get_hierarchical_files`) and ds-crawler's `set_modality_meta` / `path_prefix`.
|
|
65
|
+
Requires euler-loading 2.33.0 and ds-crawler 2.14.0.
|
|
66
|
+
- `extract_intrinsics` (radial, fog) also uses a hierarchical intrinsics file
|
|
67
|
+
that is not named `intrinsics` when it is the only one, such as SeeingThroughFog's
|
|
68
|
+
`calib_cam_stereo_left`. Several matching files now raise instead of being
|
|
69
|
+
ignored.
|
|
70
|
+
|
|
71
|
+
## 3.14.0 (unreleased)
|
|
72
|
+
|
|
73
|
+
Consume shared preprocessing config and add the opt-in spatial producer, explicit variants/mappings and captured source-backed outputs. Preserve ordinary pipeline APIs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-preprocess
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.20.0
|
|
4
4
|
Summary: Physics-based preprocessing (fog, etc.) for RGB+depth datasets
|
|
5
5
|
Author-email: Daniel Rothenpieler <rothenpielerdaniel@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,8 +9,8 @@ Description-Content-Type: text/markdown
|
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
Requires-Dist: numpy
|
|
11
11
|
Requires-Dist: Pillow
|
|
12
|
-
Requires-Dist: euler-loading>=2.
|
|
13
|
-
Requires-Dist: ds-crawler>=2.
|
|
12
|
+
Requires-Dist: euler-loading>=2.35.0
|
|
13
|
+
Requires-Dist: ds-crawler>=2.14.0
|
|
14
14
|
Requires-Dist: euler-dataset-contract>=0.5.0
|
|
15
15
|
Provides-Extra: gpu
|
|
16
16
|
Requires-Dist: torch; extra == "gpu"
|
|
@@ -65,6 +65,8 @@ qualitative review.
|
|
|
65
65
|
| `euler-preprocess sky-depth` | Override depth values in sky regions with a constant |
|
|
66
66
|
| `euler-preprocess radial` | Convert planar (z-buffer) depth to radial (Euclidean) depth |
|
|
67
67
|
| `euler-preprocess lidar-motion` | Compensate scanning-lidar points for the vehicle's motion during a sweep |
|
|
68
|
+
| `euler-preprocess crop` | Crop RGB, depth, intrinsics and extrinsics coherently |
|
|
69
|
+
| `euler-preprocess crop-box` | Print the pixel box a crop config gives for an image size |
|
|
68
70
|
|
|
69
71
|
## Installation
|
|
70
72
|
|
|
@@ -79,6 +81,7 @@ euler-preprocess fog -c configs/example_dataset_config.json
|
|
|
79
81
|
euler-preprocess sky-depth -c configs/sky_depth_dataset_config.json
|
|
80
82
|
euler-preprocess radial -c configs/radial_dataset_config.json
|
|
81
83
|
euler-preprocess lidar-motion -c configs/lidar_motion_dataset_config.json
|
|
84
|
+
euler-preprocess crop -c configs/crop_stf_dataset_config.json
|
|
82
85
|
```
|
|
83
86
|
|
|
84
87
|
## Dataset Config
|
|
@@ -737,6 +740,138 @@ holds the target time and the speed and rates used. Point
|
|
|
737
740
|
|
|
738
741
|
---
|
|
739
742
|
|
|
743
|
+
## Coherent Crop
|
|
744
|
+
|
|
745
|
+
`crop` cuts the same box out of every image-shaped modality and corrects
|
|
746
|
+
everything that refers to the pixel grid, so a cropped bundle projects exactly
|
|
747
|
+
like the original:
|
|
748
|
+
|
|
749
|
+
| Modality kind | Crop |
|
|
750
|
+
|---|---|
|
|
751
|
+
| Rasters: RGB, dense depth | Sliced; no resampling, so values are unchanged |
|
|
752
|
+
| Label rasters: semantic segmentation (the ground truth that also holds the sky), instance and panoptic segmentation, sky masks | Cropped in the stored file, so every class, channel, palette and bit depth is kept; resized only by nearest |
|
|
753
|
+
| Pinhole intrinsics `K` (or `P` for rectified images) | `cx -= left`, `cy -= top`; `fx`, `fy`, skew unchanged |
|
|
754
|
+
| Lidar point clouds | Copied byte for byte, or pruned to the points that project into the crop |
|
|
755
|
+
| Extrinsics | Copied byte for byte |
|
|
756
|
+
|
|
757
|
+
The extrinsics need no change, because `C·K·[R|t]·X = K'·[R|t]·X` with
|
|
758
|
+
`C = [[1,0,-left],[0,1,-top],[0,0,1]]`: the whole correction lives in the
|
|
759
|
+
camera matrix, which is also what the official SeeingThroughFog tools do. An
|
|
760
|
+
optional resize afterwards adds `S` (an `align_corners=False` rescale), so
|
|
761
|
+
`K' = S·C·K`, still with untouched extrinsics.
|
|
762
|
+
Which kind a modality is comes from its euler-loading loader annotation
|
|
763
|
+
(`shape`, `type`), never from its name.
|
|
764
|
+
|
|
765
|
+
The dataset config lists every modality to crop; whether a modality is
|
|
766
|
+
per-sample or hierarchical (shared calibration) is inferred from its index:
|
|
767
|
+
|
|
768
|
+
```json
|
|
769
|
+
{
|
|
770
|
+
"transform_config_path": "crop_stf_valid_region_config.json",
|
|
771
|
+
"output_path": "/data/stf_crop",
|
|
772
|
+
"modalities": {
|
|
773
|
+
"rgb": "/data/stf/cam_stereo_left_lut",
|
|
774
|
+
"sparse_depth": "/data/stf/lidar_hdl64_strongest",
|
|
775
|
+
"intrinsics": "/data/stf/calib_cam_stereo_left",
|
|
776
|
+
"camera_extrinsics": "/data/stf/calib_tf_tree"
|
|
777
|
+
},
|
|
778
|
+
"samples": {"start": 0, "count": 100}
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
Each modality is written to `<output_path>/<name>`, or to its
|
|
783
|
+
`pipeline.output_targets[]` entry (`slot` = the modality name; directory or zip).
|
|
784
|
+
With pipeline targets, every modality needs one and the outputs manifest lists
|
|
785
|
+
them all. `"output_layout": "scoped"` writes one root at `output_path` instead
|
|
786
|
+
(a directory or `.zip`): one ds-crawler metadata scope per modality, named after
|
|
787
|
+
it, with its files below `<name>/`. That is the layout dmd3c-euler's
|
|
788
|
+
`--dataset-root` reads. The dataset config must not contain `preprocessing`.
|
|
789
|
+
|
|
790
|
+
The crop config (`configs/crop_config.json`) describes the box relative to the
|
|
791
|
+
`reference` raster:
|
|
792
|
+
|
|
793
|
+
```json
|
|
794
|
+
{
|
|
795
|
+
"reference": "rgb",
|
|
796
|
+
"crop": {"remove": {"top": 0.20, "bottom": 0.05, "left": 0.15, "right": 0.19}},
|
|
797
|
+
"point_clouds": "keep",
|
|
798
|
+
"verify": "all"
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
| Key | Meaning |
|
|
803
|
+
|---|---|
|
|
804
|
+
| `crop.remove` | What to cut off each edge (`top`, `bottom`, `left`, `right`) |
|
|
805
|
+
| `crop.keep` + `crop.anchor` | The kept `height` / `width`, placed at `center` (default), `top`, `bottom`, `left`, `right`, `top_left`, `top_right`, `bottom_left` or `bottom_right` |
|
|
806
|
+
| `crop.unit` | `fraction` (default) or `pixel`. Fractions lie in `[0, 1)` (`keep`: `(0, 1]`) and round half up per edge: `floor(f · size + 0.5)` |
|
|
807
|
+
| `crop.multiple_of` | Trim the kept size down to a multiple, e.g. a network stride; the extra rows and columns come off both sides evenly |
|
|
808
|
+
| `resize` | Optional, after the crop: `{"size": [h, w]}` or `{"scale": 0.5}` (or `[sy, sx]`); `interpolation` maps modality names to `nearest`, `bilinear` or `bicubic` |
|
|
809
|
+
| `point_clouds` | `keep` (default): copy every point, consumers clip to the image. `prune_to_crop`: keep only the points with `z > 0` whose pixel `rint(K'·T·X)` lies in the output image, as consumers such as dmd3c-euler project them |
|
|
810
|
+
| `projection` | For `prune_to_crop`: the `intrinsics` and `extrinsics` modalities to project with, when the dataset has more than one candidate |
|
|
811
|
+
| `verify` | `all` (default), `none`, or a sample count: reopen the outputs and check every file against the crop (rasters and pruned clouds as encoded, intrinsics to 1e-3 px, copies byte-identical) |
|
|
812
|
+
| `roles` | Override a modality's kind with `raster` or `copy`, for loaders whose annotation the crop does not know, or to copy an intrinsics file of another camera (e.g. MUSES `sensor: event`) instead of cropping it |
|
|
813
|
+
|
|
814
|
+
Pixel units reproduce the official boxes exactly, e.g. `RGB2Gatedv2` is
|
|
815
|
+
`{"remove": {"top": 202, "bottom": 54, "left": 280, "right": 360}, "unit": "pixel"}`.
|
|
816
|
+
`configs/crop_stf_valid_region_config.json` removes the black border the
|
|
817
|
+
SeeingThroughFog rectification leaves on `_lut` frames (top 34, bottom 46,
|
|
818
|
+
left 16 px), keeping a fully valid 1904×944 image.
|
|
819
|
+
|
|
820
|
+
MUSES keeps the frame camera's `K` and every extrinsic in one `calib.json`,
|
|
821
|
+
indexed as `intrinsics`, `camera_extrinsics` (and `lidar_to_gnss`). The crop
|
|
822
|
+
patches `intrinsics.rgb.K` once and writes that file for every modality that
|
|
823
|
+
indexes it, also when it is indexed as separate byte-identical copies, so the
|
|
824
|
+
bundle holds one `K`. `D`, the event camera and all extrinsics stay as they
|
|
825
|
+
are. `configs/crop_muses_hood_config.json` cuts the engine hood off the
|
|
826
|
+
1920×1080 frame camera images: the bottom 160 rows, leaving 1920×920. Rows come
|
|
827
|
+
off the bottom only, so `K` and every `calib.json` stay byte-identical. Run
|
|
828
|
+
`lidar-motion` first and crop its output (`configs/crop_muses_dataset_config.json`).
|
|
829
|
+
GNSS records and `meta.json` sensor timing are copied unchanged, like the
|
|
830
|
+
extrinsics. MUSES label images (`gt_semantic`, `gt_panoptic`) are cropped in place like
|
|
831
|
+
any label raster.
|
|
832
|
+
|
|
833
|
+
Label rasters (loader types `semantic_segmentation`, `semantic_segmentation_color`,
|
|
834
|
+
`instance_segmentation`, `panoptic_segmentation`, `sky_mask`) are cropped in the
|
|
835
|
+
file itself: PNG, TIFF and BMP through Pillow in their own mode and palette,
|
|
836
|
+
`.npy`/`.npz` through NumPy. A semantic segmentation is the ground truth for
|
|
837
|
+
every class including the sky, and consumers read it through different
|
|
838
|
+
functions (`class_segmentation`, or `sky_mask` for sky-depth). Re-encoding the
|
|
839
|
+
decoded labels would drop what one function does not return: Real Drive Sim's
|
|
840
|
+
non-red channels, an indexed PNG's palette, or every class but the sky when a
|
|
841
|
+
dataset only has a `sky_mask` function. The in-place crop must decode exactly
|
|
842
|
+
as the crop of the source labels. Files it cannot keep (JPEG, 16-bit colour
|
|
843
|
+
PNGs, ambiguous array layouts) fall back to the writer with a warning. Labels
|
|
844
|
+
are never interpolated: a `resize.interpolation` other than `nearest` for them
|
|
845
|
+
is an error.
|
|
846
|
+
|
|
847
|
+
Other rasters are re-encoded with the dataset's euler-loading writer, so a raster
|
|
848
|
+
modality needs one (SeeingThroughFog's raw `rccb` TIFFs have none). Each
|
|
849
|
+
encoded file is decoded again right away and must give back the cropped values:
|
|
850
|
+
exactly, or for an interpolated resize within half an 8-bit step. A resize
|
|
851
|
+
interpolates colour images (`rgb`, `rccb`) bilinearly and takes the nearest
|
|
852
|
+
pixel for everything else, so depth and label values stay real values;
|
|
853
|
+
sparse-depth rasters are not resized. Pruned point clouds need a writer too
|
|
854
|
+
(`princeton_dense.write_sparse_depth`, `muses.write_sparse_depth`). Intrinsics
|
|
855
|
+
are written by copying the source file and letting its writer move the matrices
|
|
856
|
+
onto the new grid: for a ROS CameraInfo file such as
|
|
857
|
+
`calib_cam_stereo_left.json`, `K` and `P` shift by exact integers, `width` and
|
|
858
|
+
`height` become the crop size, and `D`, `R`, `roi` and the header are kept. A
|
|
859
|
+
calibration file that records another image size than the reference rasters
|
|
860
|
+
is refused. A hierarchical file is written once, so every sample sharing it
|
|
861
|
+
must get the same box; mixed image sizes under one calibration file are an
|
|
862
|
+
error. Every output head records `meta.crop` (reference, spec and boxes), and
|
|
863
|
+
every file its own `attributes.crop` box; pruned clouds also record
|
|
864
|
+
`attributes.point_clouds` (source and kept point counts).
|
|
865
|
+
|
|
866
|
+
To reproduce a crop with `euler-preprocess spatial`, print its pixel box and
|
|
867
|
+
the matching `preprocessing` block for a reference size:
|
|
868
|
+
|
|
869
|
+
```bash
|
|
870
|
+
euler-preprocess crop-box -c configs/crop_config.json --size 1024 1920
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
---
|
|
874
|
+
|
|
740
875
|
## License
|
|
741
876
|
|
|
742
877
|
[MIT](LICENSE) © Daniel Rothenpieler
|
|
@@ -45,6 +45,8 @@ qualitative review.
|
|
|
45
45
|
| `euler-preprocess sky-depth` | Override depth values in sky regions with a constant |
|
|
46
46
|
| `euler-preprocess radial` | Convert planar (z-buffer) depth to radial (Euclidean) depth |
|
|
47
47
|
| `euler-preprocess lidar-motion` | Compensate scanning-lidar points for the vehicle's motion during a sweep |
|
|
48
|
+
| `euler-preprocess crop` | Crop RGB, depth, intrinsics and extrinsics coherently |
|
|
49
|
+
| `euler-preprocess crop-box` | Print the pixel box a crop config gives for an image size |
|
|
48
50
|
|
|
49
51
|
## Installation
|
|
50
52
|
|
|
@@ -59,6 +61,7 @@ euler-preprocess fog -c configs/example_dataset_config.json
|
|
|
59
61
|
euler-preprocess sky-depth -c configs/sky_depth_dataset_config.json
|
|
60
62
|
euler-preprocess radial -c configs/radial_dataset_config.json
|
|
61
63
|
euler-preprocess lidar-motion -c configs/lidar_motion_dataset_config.json
|
|
64
|
+
euler-preprocess crop -c configs/crop_stf_dataset_config.json
|
|
62
65
|
```
|
|
63
66
|
|
|
64
67
|
## Dataset Config
|
|
@@ -717,6 +720,138 @@ holds the target time and the speed and rates used. Point
|
|
|
717
720
|
|
|
718
721
|
---
|
|
719
722
|
|
|
723
|
+
## Coherent Crop
|
|
724
|
+
|
|
725
|
+
`crop` cuts the same box out of every image-shaped modality and corrects
|
|
726
|
+
everything that refers to the pixel grid, so a cropped bundle projects exactly
|
|
727
|
+
like the original:
|
|
728
|
+
|
|
729
|
+
| Modality kind | Crop |
|
|
730
|
+
|---|---|
|
|
731
|
+
| Rasters: RGB, dense depth | Sliced; no resampling, so values are unchanged |
|
|
732
|
+
| Label rasters: semantic segmentation (the ground truth that also holds the sky), instance and panoptic segmentation, sky masks | Cropped in the stored file, so every class, channel, palette and bit depth is kept; resized only by nearest |
|
|
733
|
+
| Pinhole intrinsics `K` (or `P` for rectified images) | `cx -= left`, `cy -= top`; `fx`, `fy`, skew unchanged |
|
|
734
|
+
| Lidar point clouds | Copied byte for byte, or pruned to the points that project into the crop |
|
|
735
|
+
| Extrinsics | Copied byte for byte |
|
|
736
|
+
|
|
737
|
+
The extrinsics need no change, because `C·K·[R|t]·X = K'·[R|t]·X` with
|
|
738
|
+
`C = [[1,0,-left],[0,1,-top],[0,0,1]]`: the whole correction lives in the
|
|
739
|
+
camera matrix, which is also what the official SeeingThroughFog tools do. An
|
|
740
|
+
optional resize afterwards adds `S` (an `align_corners=False` rescale), so
|
|
741
|
+
`K' = S·C·K`, still with untouched extrinsics.
|
|
742
|
+
Which kind a modality is comes from its euler-loading loader annotation
|
|
743
|
+
(`shape`, `type`), never from its name.
|
|
744
|
+
|
|
745
|
+
The dataset config lists every modality to crop; whether a modality is
|
|
746
|
+
per-sample or hierarchical (shared calibration) is inferred from its index:
|
|
747
|
+
|
|
748
|
+
```json
|
|
749
|
+
{
|
|
750
|
+
"transform_config_path": "crop_stf_valid_region_config.json",
|
|
751
|
+
"output_path": "/data/stf_crop",
|
|
752
|
+
"modalities": {
|
|
753
|
+
"rgb": "/data/stf/cam_stereo_left_lut",
|
|
754
|
+
"sparse_depth": "/data/stf/lidar_hdl64_strongest",
|
|
755
|
+
"intrinsics": "/data/stf/calib_cam_stereo_left",
|
|
756
|
+
"camera_extrinsics": "/data/stf/calib_tf_tree"
|
|
757
|
+
},
|
|
758
|
+
"samples": {"start": 0, "count": 100}
|
|
759
|
+
}
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
Each modality is written to `<output_path>/<name>`, or to its
|
|
763
|
+
`pipeline.output_targets[]` entry (`slot` = the modality name; directory or zip).
|
|
764
|
+
With pipeline targets, every modality needs one and the outputs manifest lists
|
|
765
|
+
them all. `"output_layout": "scoped"` writes one root at `output_path` instead
|
|
766
|
+
(a directory or `.zip`): one ds-crawler metadata scope per modality, named after
|
|
767
|
+
it, with its files below `<name>/`. That is the layout dmd3c-euler's
|
|
768
|
+
`--dataset-root` reads. The dataset config must not contain `preprocessing`.
|
|
769
|
+
|
|
770
|
+
The crop config (`configs/crop_config.json`) describes the box relative to the
|
|
771
|
+
`reference` raster:
|
|
772
|
+
|
|
773
|
+
```json
|
|
774
|
+
{
|
|
775
|
+
"reference": "rgb",
|
|
776
|
+
"crop": {"remove": {"top": 0.20, "bottom": 0.05, "left": 0.15, "right": 0.19}},
|
|
777
|
+
"point_clouds": "keep",
|
|
778
|
+
"verify": "all"
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
| Key | Meaning |
|
|
783
|
+
|---|---|
|
|
784
|
+
| `crop.remove` | What to cut off each edge (`top`, `bottom`, `left`, `right`) |
|
|
785
|
+
| `crop.keep` + `crop.anchor` | The kept `height` / `width`, placed at `center` (default), `top`, `bottom`, `left`, `right`, `top_left`, `top_right`, `bottom_left` or `bottom_right` |
|
|
786
|
+
| `crop.unit` | `fraction` (default) or `pixel`. Fractions lie in `[0, 1)` (`keep`: `(0, 1]`) and round half up per edge: `floor(f · size + 0.5)` |
|
|
787
|
+
| `crop.multiple_of` | Trim the kept size down to a multiple, e.g. a network stride; the extra rows and columns come off both sides evenly |
|
|
788
|
+
| `resize` | Optional, after the crop: `{"size": [h, w]}` or `{"scale": 0.5}` (or `[sy, sx]`); `interpolation` maps modality names to `nearest`, `bilinear` or `bicubic` |
|
|
789
|
+
| `point_clouds` | `keep` (default): copy every point, consumers clip to the image. `prune_to_crop`: keep only the points with `z > 0` whose pixel `rint(K'·T·X)` lies in the output image, as consumers such as dmd3c-euler project them |
|
|
790
|
+
| `projection` | For `prune_to_crop`: the `intrinsics` and `extrinsics` modalities to project with, when the dataset has more than one candidate |
|
|
791
|
+
| `verify` | `all` (default), `none`, or a sample count: reopen the outputs and check every file against the crop (rasters and pruned clouds as encoded, intrinsics to 1e-3 px, copies byte-identical) |
|
|
792
|
+
| `roles` | Override a modality's kind with `raster` or `copy`, for loaders whose annotation the crop does not know, or to copy an intrinsics file of another camera (e.g. MUSES `sensor: event`) instead of cropping it |
|
|
793
|
+
|
|
794
|
+
Pixel units reproduce the official boxes exactly, e.g. `RGB2Gatedv2` is
|
|
795
|
+
`{"remove": {"top": 202, "bottom": 54, "left": 280, "right": 360}, "unit": "pixel"}`.
|
|
796
|
+
`configs/crop_stf_valid_region_config.json` removes the black border the
|
|
797
|
+
SeeingThroughFog rectification leaves on `_lut` frames (top 34, bottom 46,
|
|
798
|
+
left 16 px), keeping a fully valid 1904×944 image.
|
|
799
|
+
|
|
800
|
+
MUSES keeps the frame camera's `K` and every extrinsic in one `calib.json`,
|
|
801
|
+
indexed as `intrinsics`, `camera_extrinsics` (and `lidar_to_gnss`). The crop
|
|
802
|
+
patches `intrinsics.rgb.K` once and writes that file for every modality that
|
|
803
|
+
indexes it, also when it is indexed as separate byte-identical copies, so the
|
|
804
|
+
bundle holds one `K`. `D`, the event camera and all extrinsics stay as they
|
|
805
|
+
are. `configs/crop_muses_hood_config.json` cuts the engine hood off the
|
|
806
|
+
1920×1080 frame camera images: the bottom 160 rows, leaving 1920×920. Rows come
|
|
807
|
+
off the bottom only, so `K` and every `calib.json` stay byte-identical. Run
|
|
808
|
+
`lidar-motion` first and crop its output (`configs/crop_muses_dataset_config.json`).
|
|
809
|
+
GNSS records and `meta.json` sensor timing are copied unchanged, like the
|
|
810
|
+
extrinsics. MUSES label images (`gt_semantic`, `gt_panoptic`) are cropped in place like
|
|
811
|
+
any label raster.
|
|
812
|
+
|
|
813
|
+
Label rasters (loader types `semantic_segmentation`, `semantic_segmentation_color`,
|
|
814
|
+
`instance_segmentation`, `panoptic_segmentation`, `sky_mask`) are cropped in the
|
|
815
|
+
file itself: PNG, TIFF and BMP through Pillow in their own mode and palette,
|
|
816
|
+
`.npy`/`.npz` through NumPy. A semantic segmentation is the ground truth for
|
|
817
|
+
every class including the sky, and consumers read it through different
|
|
818
|
+
functions (`class_segmentation`, or `sky_mask` for sky-depth). Re-encoding the
|
|
819
|
+
decoded labels would drop what one function does not return: Real Drive Sim's
|
|
820
|
+
non-red channels, an indexed PNG's palette, or every class but the sky when a
|
|
821
|
+
dataset only has a `sky_mask` function. The in-place crop must decode exactly
|
|
822
|
+
as the crop of the source labels. Files it cannot keep (JPEG, 16-bit colour
|
|
823
|
+
PNGs, ambiguous array layouts) fall back to the writer with a warning. Labels
|
|
824
|
+
are never interpolated: a `resize.interpolation` other than `nearest` for them
|
|
825
|
+
is an error.
|
|
826
|
+
|
|
827
|
+
Other rasters are re-encoded with the dataset's euler-loading writer, so a raster
|
|
828
|
+
modality needs one (SeeingThroughFog's raw `rccb` TIFFs have none). Each
|
|
829
|
+
encoded file is decoded again right away and must give back the cropped values:
|
|
830
|
+
exactly, or for an interpolated resize within half an 8-bit step. A resize
|
|
831
|
+
interpolates colour images (`rgb`, `rccb`) bilinearly and takes the nearest
|
|
832
|
+
pixel for everything else, so depth and label values stay real values;
|
|
833
|
+
sparse-depth rasters are not resized. Pruned point clouds need a writer too
|
|
834
|
+
(`princeton_dense.write_sparse_depth`, `muses.write_sparse_depth`). Intrinsics
|
|
835
|
+
are written by copying the source file and letting its writer move the matrices
|
|
836
|
+
onto the new grid: for a ROS CameraInfo file such as
|
|
837
|
+
`calib_cam_stereo_left.json`, `K` and `P` shift by exact integers, `width` and
|
|
838
|
+
`height` become the crop size, and `D`, `R`, `roi` and the header are kept. A
|
|
839
|
+
calibration file that records another image size than the reference rasters
|
|
840
|
+
is refused. A hierarchical file is written once, so every sample sharing it
|
|
841
|
+
must get the same box; mixed image sizes under one calibration file are an
|
|
842
|
+
error. Every output head records `meta.crop` (reference, spec and boxes), and
|
|
843
|
+
every file its own `attributes.crop` box; pruned clouds also record
|
|
844
|
+
`attributes.point_clouds` (source and kept point counts).
|
|
845
|
+
|
|
846
|
+
To reproduce a crop with `euler-preprocess spatial`, print its pixel box and
|
|
847
|
+
the matching `preprocessing` block for a reference size:
|
|
848
|
+
|
|
849
|
+
```bash
|
|
850
|
+
euler-preprocess crop-box -c configs/crop_config.json --size 1024 1920
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
---
|
|
854
|
+
|
|
720
855
|
## License
|
|
721
856
|
|
|
722
857
|
[MIT](LICENSE) © Daniel Rothenpieler
|