evutils 0.3.10__tar.gz → 0.3.12__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 (160) hide show
  1. {evutils-0.3.10 → evutils-0.3.12}/.github/workflows/release.yaml +52 -3
  2. {evutils-0.3.10 → evutils-0.3.12}/PKG-INFO +48 -26
  3. {evutils-0.3.10 → evutils-0.3.12}/README.md +36 -20
  4. evutils-0.3.12/benchmarks/README.md +145 -0
  5. evutils-0.3.12/benchmarks/conftest.py +171 -0
  6. evutils-0.3.12/benchmarks/docker/Dockerfile.openeb +56 -0
  7. evutils-0.3.12/benchmarks/readers.py +144 -0
  8. {evutils-0.3.10 → evutils-0.3.12}/benchmarks/test_compare.py +11 -6
  9. evutils-0.3.12/benchmarks/test_formats.py +187 -0
  10. evutils-0.3.12/benchmarks/test_read.py +54 -0
  11. evutils-0.3.12/benchmarks/test_write.py +59 -0
  12. evutils-0.3.12/csrc/aer.c +70 -0
  13. evutils-0.3.12/csrc/dat.c +67 -0
  14. {evutils-0.3.10 → evutils-0.3.12}/csrc/evt2.c +1 -0
  15. {evutils-0.3.10 → evutils-0.3.12}/csrc/evt21.c +1 -0
  16. {evutils-0.3.10 → evutils-0.3.12}/csrc/evt3.c +10 -0
  17. evutils-0.3.12/csrc/include/evutils/aer.h +55 -0
  18. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/compat.h +6 -0
  19. evutils-0.3.12/csrc/include/evutils/dat.h +40 -0
  20. {evutils-0.3.10 → evutils-0.3.12}/docs/source/conf.py +14 -5
  21. evutils-0.3.12/docs/source/formats.md +128 -0
  22. {evutils-0.3.10 → evutils-0.3.12}/docs/source/index.rst +1 -0
  23. {evutils-0.3.10 → evutils-0.3.12}/pyproject.toml +62 -6
  24. evutils-0.3.12/scripts/generate_benchmark_table.py +117 -0
  25. evutils-0.3.12/scripts/generate_metadata.py +102 -0
  26. evutils-0.3.12/src/evutils/_jit.py +34 -0
  27. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/augment/_drop.py +4 -3
  28. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/chunking.py +16 -16
  29. evutils-0.3.12/src/evutils/io/_aedat.py +565 -0
  30. evutils-0.3.12/src/evutils/io/_aer.py +305 -0
  31. evutils-0.3.12/src/evutils/io/_bin.py +88 -0
  32. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/io/_csv.py +73 -21
  33. evutils-0.3.12/src/evutils/io/_dat.py +321 -0
  34. evutils-0.3.12/src/evutils/io/_event_reader.py +568 -0
  35. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/io/_event_writer.py +55 -32
  36. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/io/_evt.py +224 -77
  37. evutils-0.3.12/src/evutils/io/_hdf5.py +364 -0
  38. evutils-0.3.12/src/evutils/io/_native_evt.py +1012 -0
  39. evutils-0.3.12/src/evutils/io/_npz.py +303 -0
  40. evutils-0.3.12/src/evutils/io/_prefetch.py +147 -0
  41. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/io/_source.py +61 -14
  42. evutils-0.3.12/src/evutils/io/buffer.py +203 -0
  43. evutils-0.3.12/src/evutils/io/common.py +321 -0
  44. evutils-0.3.12/src/evutils/io/decoders.py +174 -0
  45. evutils-0.3.12/src/evutils/io/encoders.py +85 -0
  46. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/processing/_masking.py +9 -2
  47. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/processing/_utils.py +3 -0
  48. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/random.py +5 -8
  49. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/repr/_frame.py +39 -43
  50. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/repr/_histogram.py +28 -26
  51. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/repr/_timesurface.py +10 -9
  52. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/repr/_tore.py +16 -14
  53. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/repr/_voxel.py +8 -8
  54. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/torch/__init__.py +3 -2
  55. evutils-0.3.12/src/evutils/types.py +299 -0
  56. evutils-0.3.12/src/evutils/utils/_checker.py +105 -0
  57. evutils-0.3.12/src/evutils/vis/__init__.py +9 -0
  58. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/open3d.py +13 -3
  59. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/plot3d.py +39 -7
  60. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/_base.py +28 -9
  61. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/metavision.py +37 -17
  62. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg.py +73 -21
  63. evutils-0.3.12/tests/aedat_synth.py +146 -0
  64. {evutils-0.3.10 → evutils-0.3.12}/tests/conftest.py +22 -24
  65. evutils-0.3.12/tests/conftest_utils.py +119 -0
  66. {evutils-0.3.10 → evutils-0.3.12}/tests/io/conftest.py +6 -4
  67. evutils-0.3.12/tests/io/test_aedat.py +145 -0
  68. evutils-0.3.12/tests/io/test_aer.py +98 -0
  69. {evutils-0.3.10 → evutils-0.3.12}/tests/io/test_csv.py +4 -3
  70. evutils-0.3.12/tests/io/test_dat.py +85 -0
  71. evutils-0.3.12/tests/io/test_evt.py +420 -0
  72. evutils-0.3.12/tests/io/test_hdf5.py +159 -0
  73. evutils-0.3.12/tests/io/test_npz.py +99 -0
  74. evutils-0.3.12/tests/io/test_prefetch.py +147 -0
  75. evutils-0.3.12/tests/io/test_roundtrip_matrix.py +162 -0
  76. {evutils-0.3.10 → evutils-0.3.12}/tests/test_random.py +3 -3
  77. {evutils-0.3.10 → evutils-0.3.12}/tests/test_types.py +2 -2
  78. {evutils-0.3.10 → evutils-0.3.12}/tests/test_vis.py +1 -1
  79. {evutils-0.3.10 → evutils-0.3.12}/uv.lock +598 -507
  80. evutils-0.3.10/benchmarks/README.md +0 -102
  81. evutils-0.3.10/benchmarks/conftest.py +0 -75
  82. evutils-0.3.10/benchmarks/docker/Dockerfile.openeb +0 -57
  83. evutils-0.3.10/benchmarks/readers.py +0 -88
  84. evutils-0.3.10/benchmarks/test_read.py +0 -34
  85. evutils-0.3.10/benchmarks/test_write.py +0 -31
  86. evutils-0.3.10/src/evutils/io/_aedat.py +0 -33
  87. evutils-0.3.10/src/evutils/io/_aer.py +0 -32
  88. evutils-0.3.10/src/evutils/io/_bin.py +0 -31
  89. evutils-0.3.10/src/evutils/io/_dat.py +0 -30
  90. evutils-0.3.10/src/evutils/io/_event_reader.py +0 -379
  91. evutils-0.3.10/src/evutils/io/_hdf5.py +0 -187
  92. evutils-0.3.10/src/evutils/io/_native_evt.py +0 -481
  93. evutils-0.3.10/src/evutils/io/_npz.py +0 -30
  94. evutils-0.3.10/src/evutils/io/buffer.py +0 -98
  95. evutils-0.3.10/src/evutils/io/common.py +0 -207
  96. evutils-0.3.10/src/evutils/io/decoders.py +0 -131
  97. evutils-0.3.10/src/evutils/io/encoders.py +0 -68
  98. evutils-0.3.10/src/evutils/types.py +0 -127
  99. evutils-0.3.10/src/evutils/utils/_checker.py +0 -32
  100. evutils-0.3.10/src/evutils/vis/__init__.py +0 -5
  101. evutils-0.3.10/tests/io/test_dat.py +0 -0
  102. evutils-0.3.10/tests/io/test_evt.py +0 -203
  103. evutils-0.3.10/tests/io/test_hdf5.py +0 -0
  104. evutils-0.3.10/tests/io/test_npz.py +0 -0
  105. {evutils-0.3.10 → evutils-0.3.12}/.dockerignore +0 -0
  106. {evutils-0.3.10 → evutils-0.3.12}/.github/workflows/test.yaml +0 -0
  107. {evutils-0.3.10 → evutils-0.3.12}/.gitignore +0 -0
  108. {evutils-0.3.10 → evutils-0.3.12}/.gitmodules +0 -0
  109. {evutils-0.3.10 → evutils-0.3.12}/CMakeLists.txt +0 -0
  110. {evutils-0.3.10 → evutils-0.3.12}/LICENSE +0 -0
  111. {evutils-0.3.10 → evutils-0.3.12}/csrc/evutils.c +0 -0
  112. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/evt2.h +0 -0
  113. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/evt21.h +0 -0
  114. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/evt3.h +0 -0
  115. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/evutils.h +0 -0
  116. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/parser.h +0 -0
  117. {evutils-0.3.10 → evutils-0.3.12}/csrc/include/evutils/types.h +0 -0
  118. {evutils-0.3.10 → evutils-0.3.12}/docker/Dockerfile +0 -0
  119. {evutils-0.3.10 → evutils-0.3.12}/docs/Makefile +0 -0
  120. {evutils-0.3.10 → evutils-0.3.12}/docs/make.bat +0 -0
  121. {evutils-0.3.10 → evutils-0.3.12}/docs/source/_static/event_hexagon_broken.webp +0 -0
  122. {evutils-0.3.10 → evutils-0.3.12}/docs/source/_templates/autoapi/python/module.rst +0 -0
  123. {evutils-0.3.10 → evutils-0.3.12}/docs/source/benchmarks/README.md +0 -0
  124. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/__init__.py +0 -0
  125. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/augment/__init__.py +0 -0
  126. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/dataset/__init__.py +0 -0
  127. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/io/__init__.py +0 -0
  128. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/processing/__init__.py +0 -0
  129. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/repr/__init__.py +0 -0
  130. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/utils/__init__.py +0 -0
  131. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/__init__.py +0 -0
  132. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/.git +0 -0
  133. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/.gitignore +0 -0
  134. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/LICENSE +0 -0
  135. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/README.md +0 -0
  136. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/__init__.py +0 -0
  137. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/base/__init__.py +0 -0
  138. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/base/base_model.py +0 -0
  139. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/data/.gitignore +0 -0
  140. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/image_reconstructor.py +0 -0
  141. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/model/__init__.py +0 -0
  142. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/model/model.py +0 -0
  143. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/model/submodules.py +0 -0
  144. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/model/unet.py +0 -0
  145. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/options/__init__.py +0 -0
  146. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/options/inference_options.py +0 -0
  147. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/pretrained/.gitignore +0 -0
  148. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/run_reconstruction.py +0 -0
  149. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/embed_reconstructed_images_in_rosbag.py +0 -0
  150. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/extract_events_from_rosbag.py +0 -0
  151. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/image_folder_to_rosbag.py +0 -0
  152. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/resample_reconstructions.py +0 -0
  153. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/__init__.py +0 -0
  154. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/event_readers.py +0 -0
  155. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/inference_utils.py +0 -0
  156. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/loading_utils.py +0 -0
  157. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/path_utils.py +0 -0
  158. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/timers.py +0 -0
  159. {evutils-0.3.10 → evutils-0.3.12}/src/evutils/vis/reconstructor/rpg_e2vid/utils/util.py +0 -0
  160. {evutils-0.3.10 → evutils-0.3.12}/tests/io/test_bin.py +0 -0
@@ -51,7 +51,7 @@ jobs:
51
51
  CIBW_ARCHS_MACOS: "x86_64 arm64"
52
52
 
53
53
  - name: Upload wheels
54
- uses: actions/upload-artifact@v4
54
+ uses: actions/upload-artifact@v7
55
55
  with:
56
56
  name: dist-${{ matrix.os }}
57
57
  path: wheelhouse/*.whl
@@ -75,7 +75,7 @@ jobs:
75
75
  run: pipx run build --sdist
76
76
 
77
77
  - name: Upload sdist
78
- uses: actions/upload-artifact@v4
78
+ uses: actions/upload-artifact@v7
79
79
  with:
80
80
  name: dist-sdist
81
81
  path: dist/*.tar.gz
@@ -140,4 +140,53 @@ jobs:
140
140
 
141
141
  - name: Deploy to GitHub Pages
142
142
  id: deployment
143
- uses: actions/deploy-pages@v4
143
+ uses: actions/deploy-pages@v5
144
+
145
+ test_pypi_wheels:
146
+ name: Test PyPI Wheel (${{ matrix.os }}, Py ${{ matrix.python }})
147
+ needs: publish_pypi
148
+ runs-on: ${{ matrix.os }}
149
+ if: github.event_name == 'release'
150
+ strategy:
151
+ fail-fast: false
152
+ matrix:
153
+ os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-14]
154
+ python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
155
+ steps:
156
+ - name: Checkout repository
157
+ uses: actions/checkout@v7
158
+ with:
159
+ submodules: recursive
160
+
161
+ - name: Install uv
162
+ uses: astral-sh/setup-uv@v8.2.0
163
+ with:
164
+ enable-cache: false
165
+
166
+ - name: Set up Python
167
+ uses: actions/setup-python@v6
168
+ with:
169
+ python-version: ${{ matrix.python }}
170
+
171
+ - name: Install evutils from PyPI
172
+ shell: bash
173
+ run: |
174
+ # Retry loop to wait for PyPI index to update with the new release
175
+ # GITHUB_REF_NAME contains the tag name (e.g. v1.0.0). We strip the 'v' for pip.
176
+ VERSION=${GITHUB_REF_NAME#v}
177
+ for i in {1..12}; do
178
+ uv pip install --system "evutils[test]==$VERSION" --no-cache && break
179
+ echo "Waiting for PyPI index..."
180
+ sleep 10
181
+ done
182
+
183
+ - name: Remove local source tree
184
+ shell: bash
185
+ run: |
186
+ # Remove local source so Python is forced to import from the installed PyPI wheel
187
+ rm -rf src/evutils
188
+
189
+ - name: Run tests against PyPI wheel
190
+ shell: bash
191
+ run: |
192
+ python -m pytest -s -v tests/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: evutils
3
- Version: 0.3.10
3
+ Version: 0.3.12
4
4
  Summary: Utilities for event-based vision
5
5
  Keywords: events,dvs,neuromorphic,vision,event-based
6
6
  Author-Email: Jakub Mandula <jakub.mandula@pbl.ee.ethz.ch>
@@ -30,25 +30,31 @@ Project-URL: Homepage, https://mandulaj.github.io/evutils/
30
30
  Requires-Python: >=3.10
31
31
  Requires-Dist: numpy>=2.0.0
32
32
  Requires-Dist: opencv-python>=4.2
33
+ Requires-Dist: numba>=0.57
34
+ Provides-Extra: aedat
35
+ Requires-Dist: lz4>=4.0; extra == "aedat"
36
+ Requires-Dist: zstandard>=0.22; python_version < "3.14" and extra == "aedat"
33
37
  Provides-Extra: pandas
34
38
  Requires-Dist: pandas>=2.3.3; extra == "pandas"
35
- Provides-Extra: numba
36
- Requires-Dist: numba>=0.57; extra == "numba"
37
39
  Provides-Extra: torch
38
40
  Requires-Dist: torch>=2.0; extra == "torch"
39
41
  Provides-Extra: hdf5
40
42
  Requires-Dist: hdf5plugin==6.0.0; extra == "hdf5"
41
- Requires-Dist: h5py==3.16.0; extra == "hdf5"
43
+ Requires-Dist: h5py>=3.16.0; extra == "hdf5"
42
44
  Provides-Extra: vis
43
45
  Requires-Dist: matplotlib>=3.1; extra == "vis"
46
+ Requires-Dist: open3d>=0.19.0; python_version < "3.13" and extra == "vis"
44
47
  Requires-Dist: scipy>=1.15.3; extra == "vis"
45
48
  Requires-Dist: tqdm>=4.41; extra == "vis"
46
49
  Provides-Extra: test
47
50
  Requires-Dist: pytest>=9.0.2; extra == "test"
48
51
  Requires-Dist: pytest-benchmark>=5.2.3; extra == "test"
52
+ Requires-Dist: zstandard>=0.22; python_version < "3.14" and extra == "test"
49
53
  Provides-Extra: compare
50
54
  Requires-Dist: expelliarmus>=1.1.0; extra == "compare"
51
- Requires-Dist: evlib; extra == "compare"
55
+ Requires-Dist: evlib>=0.12.0; python_version >= "3.11" and extra == "compare"
56
+ Requires-Dist: evlib>=0.8.0; python_version < "3.11" and extra == "compare"
57
+ Requires-Dist: evt3>=0.3; extra == "compare"
52
58
  Provides-Extra: docs
53
59
  Requires-Dist: sphinx>=8.0.0; extra == "docs"
54
60
  Requires-Dist: sphinx-autoapi>=3.6.1; extra == "docs"
@@ -58,7 +64,7 @@ Requires-Dist: sphinx_book_theme>=1.0.0; extra == "docs"
58
64
  Requires-Dist: pydata_sphinx_theme>=0.19.0; extra == "docs"
59
65
  Requires-Dist: myst-parser>=4.0.0; extra == "docs"
60
66
  Provides-Extra: all
61
- Requires-Dist: evutils[hdf5,numba,pandas,torch,vis]; extra == "all"
67
+ Requires-Dist: evutils[aedat,hdf5,pandas,torch,vis]; extra == "all"
62
68
  Provides-Extra: dev
63
69
  Requires-Dist: evutils[all,docs,test]; extra == "dev"
64
70
  Description-Content-Type: text/markdown
@@ -68,7 +74,13 @@ Description-Content-Type: text/markdown
68
74
  [![Test](https://github.com/mandulaj/evutils/actions/workflows/test.yaml/badge.svg)](https://github.com/mandulaj/evutils/actions/workflows/test.yaml)
69
75
 
70
76
  ## Overview
71
- EV-Utils (``evutils``) is a performant collection of utilities for working with event-based vision data. Built with minimal dependencies, it relies on compiled C backed for speed while offering a clean, modular Python interface.
77
+ EV-Utils (`evutils`) is a performant collection of utilities for working with event-based vision data. Built with minimal dependencies, it relies on a compiled C backend for speed while offering a clean, modular Python interface.
78
+
79
+ ### Core Philosophy
80
+ * **Fast & Lightweight:** Highly optimized C parsers for zero-bottleneck data ingestion.
81
+ * **Minimal Footprint:** Core features run entirely on NumPy and Numba.
82
+ * **Lazy Loading:** All heavy integrations (PyTorch, Pandas, HDF5, Polars, etc.) are lazy-loaded. If you don't use them, you don't need them installed, and they won't slow down import times.
83
+ * **Simple & Extensible:** Clean modular APIs.
72
84
 
73
85
 
74
86
 
@@ -79,14 +91,18 @@ This project draws inspiration from several excellent libraries in the event-bas
79
91
  * [event_utils](https://github.com/TimoStoff/event_utils)
80
92
  * [evlib](https://github.com/tallamjr/evlib)
81
93
  * [expelliarmus](https://github.com/open-neuromorphic/expelliarmus)
94
+ * [event-vision-library](https://github.com/shiba24/event-vision-library)
95
+ * [evt3](https://github.com/muthmann/evt3)
82
96
  * [openeb](https://github.com/prophesee-ai/openeb)
83
97
 
84
98
 
85
99
  ## Installation
86
- We recommend installing `evutils` using `uv`.
100
+ We recommend installing `evutils` using `uv`.
87
101
  ### From PyPi
88
102
  ```bash
89
- uv add evutils[all]
103
+ uv add evutils # Basic library
104
+ uv add evutils[all] # All groups (pandas, numba, torch, hdf5, etc..)
105
+ uv add evutils[dev] # Dev group
90
106
  ```
91
107
 
92
108
  ### From Git
@@ -131,6 +147,20 @@ Wrappers for various dataset loaders -->
131
147
 
132
148
  The `io` module provides methods for reading and writing events into various event formats. It provides a simple `.read()` and `.write()` interface as well as more advanced interfaces using iterators and slicing.
133
149
 
150
+ Supported formats (see the [formats documentation](https://mandulaj.github.io/evutils/formats.html) for details):
151
+
152
+ | Format | Extensions | Read | Write | Notes |
153
+ |---|---|:---:|:---:|---|
154
+ | EVT3 / EVT2.1 / EVT2 (Prophesee RAW) | `.raw`, `.evt*` | ✅ | ✅ | native C decoder, external triggers |
155
+ | DAT (Prophesee) | `.dat` | ✅ | ✅ | native C decoder |
156
+ | AER (Prophesee) | `.aer` | ✅ | ✅ | timestamp generation selectable |
157
+ | AEDAT 1.0 / 2.0 / 3.1 / 4.0 | `.aedat`, `.aedat4` | ✅ | 🚧 | AEDAT4 compression: `evutils[aedat]` |
158
+ | HDF5 (DSEC/RVT layout) | `.h5`, `.hdf5` | ✅ | ✅ | `evutils[hdf5]`, ms-index random access |
159
+ | HDF5 (Prophesee layout) | `.h5`, `.hdf5` | ✅ | 🚧 | ECF-compressed files need the ECF plugin |
160
+ | NPZ | `.npz` | ✅ | ✅ | streaming, `np.load`-compatible |
161
+ | CSV / TXT | `.csv`, `.txt` | ✅ | ✅ | `evutils[pandas]` |
162
+ | BIN | `.bin` | 🚧 | 🚧 | planned |
163
+
134
164
  ```python
135
165
  from evutils.io import EventReader
136
166
 
@@ -187,25 +217,17 @@ uv run pytest benchmarks/ --benchmark-group-by=param:fmt # compare libraries
187
217
 
188
218
  The benchmarks download a real Prophesee recording on first use. Optional cross-library comparisons run automatically once the libraries are installed (`uv pip install -e ".[compare]"`); OpenEB/Metavision is compared via the Docker image in `benchmarks/docker/`. See [`benchmarks/README.md`](benchmarks/README.md) for details.
189
219
 
190
- Decode/encode throughput on a 12th Gen Intel Core i7-1280P (millions of events per second, higher is better):
191
-
192
- **Read** (full-file decode)
193
-
194
- | Format | evutils | expelliarmus | evlib |
195
- | ------ | ------: | -----------: | ----: |
196
- | EVT2 | 91 | 105 | 5 |
197
- | EVT2.1 | 72 | – | – |
198
- | EVT3 | 53 | 41 | 5 |
199
-
200
- **Write** (evutils; expelliarmus/evlib are read-only for these formats)
201
220
 
202
- | Format | evutils |
203
- | ------ | ------: |
204
- | EVT2 | 146 |
205
- | EVT2.1 | 110 |
206
- | EVT3 | 74 |
207
221
 
208
- (`–` = format not supported by that library.)
222
+ ## & Roadmap
223
+ We aim for universal event format support, prioritizing blazing fast read/write speeds, completeness, and extensibility.
224
+ - [x] Universal format support (`.raw`, `.evt2`, `.dat`, `.aedat4`, `.hdf5`, `.npz`, `.csv`, etc.)
225
+ - [x] Full Read/Write parity where possible
226
+ - [x] Chunked & Streaming access
227
+ - [x] External trigger data parsing
228
+ - [ ] **Random access / Timestamp indexing** (Big TODO for the future)
229
+ - [ ] **Arbitrary input sources:** memory-mapped IO, pure in-memory streams, HTTP streams
230
+ - [ ] **On-the-fly Compression wrappers:** passing file handles through `zstd` or `lz4` compression transparently before decoding
209
231
 
210
232
 
211
233
  ## Acknowledgements
@@ -3,7 +3,13 @@
3
3
  [![Test](https://github.com/mandulaj/evutils/actions/workflows/test.yaml/badge.svg)](https://github.com/mandulaj/evutils/actions/workflows/test.yaml)
4
4
 
5
5
  ## Overview
6
- EV-Utils (``evutils``) is a performant collection of utilities for working with event-based vision data. Built with minimal dependencies, it relies on compiled C backed for speed while offering a clean, modular Python interface.
6
+ EV-Utils (`evutils`) is a performant collection of utilities for working with event-based vision data. Built with minimal dependencies, it relies on a compiled C backend for speed while offering a clean, modular Python interface.
7
+
8
+ ### Core Philosophy
9
+ * **Fast & Lightweight:** Highly optimized C parsers for zero-bottleneck data ingestion.
10
+ * **Minimal Footprint:** Core features run entirely on NumPy and Numba.
11
+ * **Lazy Loading:** All heavy integrations (PyTorch, Pandas, HDF5, Polars, etc.) are lazy-loaded. If you don't use them, you don't need them installed, and they won't slow down import times.
12
+ * **Simple & Extensible:** Clean modular APIs.
7
13
 
8
14
 
9
15
 
@@ -14,14 +20,18 @@ This project draws inspiration from several excellent libraries in the event-bas
14
20
  * [event_utils](https://github.com/TimoStoff/event_utils)
15
21
  * [evlib](https://github.com/tallamjr/evlib)
16
22
  * [expelliarmus](https://github.com/open-neuromorphic/expelliarmus)
23
+ * [event-vision-library](https://github.com/shiba24/event-vision-library)
24
+ * [evt3](https://github.com/muthmann/evt3)
17
25
  * [openeb](https://github.com/prophesee-ai/openeb)
18
26
 
19
27
 
20
28
  ## Installation
21
- We recommend installing `evutils` using `uv`.
29
+ We recommend installing `evutils` using `uv`.
22
30
  ### From PyPi
23
31
  ```bash
24
- uv add evutils[all]
32
+ uv add evutils # Basic library
33
+ uv add evutils[all] # All groups (pandas, numba, torch, hdf5, etc..)
34
+ uv add evutils[dev] # Dev group
25
35
  ```
26
36
 
27
37
  ### From Git
@@ -66,6 +76,20 @@ Wrappers for various dataset loaders -->
66
76
 
67
77
  The `io` module provides methods for reading and writing events into various event formats. It provides a simple `.read()` and `.write()` interface as well as more advanced interfaces using iterators and slicing.
68
78
 
79
+ Supported formats (see the [formats documentation](https://mandulaj.github.io/evutils/formats.html) for details):
80
+
81
+ | Format | Extensions | Read | Write | Notes |
82
+ |---|---|:---:|:---:|---|
83
+ | EVT3 / EVT2.1 / EVT2 (Prophesee RAW) | `.raw`, `.evt*` | ✅ | ✅ | native C decoder, external triggers |
84
+ | DAT (Prophesee) | `.dat` | ✅ | ✅ | native C decoder |
85
+ | AER (Prophesee) | `.aer` | ✅ | ✅ | timestamp generation selectable |
86
+ | AEDAT 1.0 / 2.0 / 3.1 / 4.0 | `.aedat`, `.aedat4` | ✅ | 🚧 | AEDAT4 compression: `evutils[aedat]` |
87
+ | HDF5 (DSEC/RVT layout) | `.h5`, `.hdf5` | ✅ | ✅ | `evutils[hdf5]`, ms-index random access |
88
+ | HDF5 (Prophesee layout) | `.h5`, `.hdf5` | ✅ | 🚧 | ECF-compressed files need the ECF plugin |
89
+ | NPZ | `.npz` | ✅ | ✅ | streaming, `np.load`-compatible |
90
+ | CSV / TXT | `.csv`, `.txt` | ✅ | ✅ | `evutils[pandas]` |
91
+ | BIN | `.bin` | 🚧 | 🚧 | planned |
92
+
69
93
  ```python
70
94
  from evutils.io import EventReader
71
95
 
@@ -122,25 +146,17 @@ uv run pytest benchmarks/ --benchmark-group-by=param:fmt # compare libraries
122
146
 
123
147
  The benchmarks download a real Prophesee recording on first use. Optional cross-library comparisons run automatically once the libraries are installed (`uv pip install -e ".[compare]"`); OpenEB/Metavision is compared via the Docker image in `benchmarks/docker/`. See [`benchmarks/README.md`](benchmarks/README.md) for details.
124
148
 
125
- Decode/encode throughput on a 12th Gen Intel Core i7-1280P (millions of events per second, higher is better):
126
-
127
- **Read** (full-file decode)
128
-
129
- | Format | evutils | expelliarmus | evlib |
130
- | ------ | ------: | -----------: | ----: |
131
- | EVT2 | 91 | 105 | 5 |
132
- | EVT2.1 | 72 | – | – |
133
- | EVT3 | 53 | 41 | 5 |
134
-
135
- **Write** (evutils; expelliarmus/evlib are read-only for these formats)
136
149
 
137
- | Format | evutils |
138
- | ------ | ------: |
139
- | EVT2 | 146 |
140
- | EVT2.1 | 110 |
141
- | EVT3 | 74 |
142
150
 
143
- (`–` = format not supported by that library.)
151
+ ## & Roadmap
152
+ We aim for universal event format support, prioritizing blazing fast read/write speeds, completeness, and extensibility.
153
+ - [x] Universal format support (`.raw`, `.evt2`, `.dat`, `.aedat4`, `.hdf5`, `.npz`, `.csv`, etc.)
154
+ - [x] Full Read/Write parity where possible
155
+ - [x] Chunked & Streaming access
156
+ - [x] External trigger data parsing
157
+ - [ ] **Random access / Timestamp indexing** (Big TODO for the future)
158
+ - [ ] **Arbitrary input sources:** memory-mapped IO, pure in-memory streams, HTTP streams
159
+ - [ ] **On-the-fly Compression wrappers:** passing file handles through `zstd` or `lz4` compression transparently before decoding
144
160
 
145
161
 
146
162
  ## Acknowledgements
@@ -0,0 +1,145 @@
1
+ # Benchmarks
2
+
3
+ Read/write throughput benchmarks for the native EVT2 / EVT2.1 / EVT3 codecs, plus optional comparisons against other event libraries.
4
+
5
+ These benchmarks are **not** part of the normal test run (which uses `testpaths = ["tests"]`). They must be executed explicitly from the repository root.
6
+
7
+ ## Quick Start
8
+
9
+ Run the default suite (evutils only, plus any installed comparison libraries):
10
+ ```bash
11
+ pytest benchmarks/
12
+ ```
13
+
14
+ Run specific benchmarks:
15
+ ```bash
16
+ pytest benchmarks/test_read.py # just reads
17
+ pytest benchmarks/test_write.py # just writes
18
+ ```
19
+
20
+ ## Benchmark Options
21
+
22
+ ### Datasets
23
+ You can benchmark against two datasets using the `--dataset` flag. The necessary files are automatically downloaded and cached on first use.
24
+ - `--dataset small` (default): A ~1GB memory footprint dataset (hand recordings).
25
+ - `--dataset large`: A massive multi-GB dataset designed to test the streaming and chunking capabilities of the decoders.
26
+
27
+ ```bash
28
+ pytest benchmarks/ --dataset large
29
+ ```
30
+
31
+ ### Filtering Readers
32
+ The benchmark tests are fully parametrized by the reader name. You can effortlessly exclude specific third-party libraries using pytest's standard `-k` flag (for example, if they are slow or misbehaving on large datasets):
33
+
34
+ ```bash
35
+ pytest benchmarks/ -k "not evlib" --dataset large
36
+ pytest benchmarks/ -k "not evlib and not openeb"
37
+ ```
38
+
39
+ ## File Structure
40
+
41
+ | File | What it benchmarks |
42
+ |------|--------------------|
43
+ | `test_read.py` | `evutils` decode throughput on the full real recordings (evt2/evt21/evt3), asserts count vs reference |
44
+ | `test_write.py` | `evutils` encode throughput (payload = first 5M events of the real evt3 file) |
45
+ | `test_formats.py` | **uniform per-format read/write**: the same 5M real events transcoded into every format (EVT3/EVT2.1/EVT2, DAT, AER, NPZ, HDF5, CSV, AEDAT4), so numbers are comparable across formats; expelliarmus (DAT) and evlib (HDF5, AEDAT4) compared on the identical files |
46
+ | `test_compare.py` | third-party readers from `readers.py` on the full real recordings (auto-skip if not installed) |
47
+ | `readers.py` | adapter registry — one entry per external library |
48
+
49
+ *Note: in `test_formats.py` AER is the one lossy transcode — the format has no timestamps and 9-bit coordinates, so the same events are written with coordinates masked to 0–511 (identical event count).*
50
+
51
+ ## Comparing Against Other Libraries
52
+
53
+ Install the optional readers and run with grouping so every library lines up per format:
54
+
55
+ ```bash
56
+ pip install evutils[compare] # expelliarmus, evlib
57
+ pytest benchmarks/ --benchmark-group-by=param:fmt --benchmark-columns=mean,ops
58
+ ```
59
+
60
+ Each library reads inside a lazy import. If a library is uninstalled or broken, its benchmarks simply **skip**. To add another library, append a `Reader(...)` entry to `readers.py`.
61
+
62
+ ## Benchmark Comparison (Mean Time in Seconds)
63
+
64
+ ### Reading
65
+
66
+ | Library | EVT2 | EVT21 | EVT3 |
67
+ |---|---|---|---|
68
+ | **evutils** | 0.138 s | 0.070 s | 0.292 s |
69
+ | **evlib** | 4.410 s | N/A | 4.327 s |
70
+ | **expelliarmus** | 0.128 s | N/A | 0.341 s |
71
+
72
+ ### Writing
73
+
74
+ | Library | EVT2 | EVT21 | EVT3 |
75
+ |---|---|---|---|
76
+ | **evutils** | 0.013 s | 0.028 s | 0.041 s |
77
+ | **expelliarmus** | 0.077 s | N/A | 0.097 s |
78
+
79
+ **Hardware:** 12th Gen Intel(R) Core(TM) i7-1280P | **OS:** Linux 7.1.1-3-MANJARO | **Python:** 3.12.13
80
+
81
+ *Lower is better. Generated dynamically by `scripts/generate_benchmark_table.py`.*
82
+
83
+ > **Note**: `tonic` is intentionally not included. It has no standalone EVT reader and reads Prophesee data through `expelliarmus` internally, so benchmarking it would just re-measure `expelliarmus`.
84
+
85
+ ## OpenEB / Metavision (via Docker)
86
+
87
+ OpenEB isn't on PyPI and is painful to build locally, so there's an image that builds it once. Both commands must be run **from the repo root** (the build context must be the whole project so `evutils` is copied in):
88
+
89
+ ```bash
90
+ # Build the image (compiles OpenEB from source + installs evutils; slow, one-time)
91
+ docker build -t evutils-openeb -f benchmarks/docker/Dockerfile.openeb .
92
+
93
+ # Run the full suite (evutils + OpenEB), grouped per format
94
+ docker run --rm evutils-openeb
95
+ ```
96
+
97
+ The container's default command is `pytest benchmarks/ --benchmark-group-by=param:fmt`, so you get `evutils` and OpenEB side by side per format.
98
+
99
+ ### Useful Variations
100
+
101
+ The recordings are **not** baked into the image (`.dockerignore` excludes the
102
+ data and cache directories), so the fixture tries to download them on first
103
+ use. If the container has no network access, mount the host's already-cached
104
+ recordings and point `EVUTILS_BENCH_DATA` at them:
105
+
106
+ ```bash
107
+ # after benchmarks have run at least once on the host:
108
+ docker run --rm \
109
+ -v "$(pwd)/.pytest_cache/d/event_files:/data:ro" \
110
+ -e EVUTILS_BENCH_DATA=/data \
111
+ evutils-openeb
112
+ ```
113
+
114
+ Alternatively, persist the container's own download across runs with a named
115
+ volume (note the workdir is `/home/user/work`):
116
+
117
+ ```bash
118
+ docker run --rm -v evutils-cache:/home/user/work/.pytest_cache evutils-openeb
119
+ ```
120
+
121
+ Run only the OpenEB comparison (skip the `evutils` rows):
122
+
123
+ ```bash
124
+ docker run --rm evutils-openeb \
125
+ pytest benchmarks/test_compare.py --benchmark-group-by=param:fmt -q
126
+ ```
127
+
128
+ Drop into a shell to debug the build/run:
129
+
130
+ ```bash
131
+ docker run --rm -it evutils-openeb bash
132
+ ```
133
+
134
+ Build a different OpenEB release if the default fails to build:
135
+
136
+ ```bash
137
+ docker build -t evutils-openeb --build-arg OPENEB_VERSION=5.0.0 \
138
+ -f benchmarks/docker/Dockerfile.openeb .
139
+ ```
140
+
141
+ ### Caveats
142
+
143
+ - The image targets **OpenEB 5.x on Ubuntu 22.04**; OpenEB's apt dependencies and install layout drift between releases, so the `apt-get`/`PYTHONPATH` lines may need tweaking. The Dockerfile imports `metavision_core` at build time, so a broken OpenEB install fails during `docker build` rather than silently skipping at run time.
144
+ - The first pass is slow: it compiles OpenEB (`-j$(nproc)`) and downloads the reference recording on first run.
145
+ - A repo-root `.dockerignore` keeps the build context small (excludes `.venv`, `build/`, `.git`, `data/`, `*.raw`, etc.).
@@ -0,0 +1,171 @@
1
+ """Benchmark fixtures.
2
+
3
+ ``EventFile`` and ``real_event_files`` are duplicated from ``tests/conftest.py``
4
+ on purpose: pytest only shares conftest fixtures downward, and ``benchmarks/``
5
+ is a sibling of ``tests/``, so there is no clean way to reuse them without a
6
+ repo-root conftest. Keep the two copies in sync.
7
+ """
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import numpy as np
12
+ import pytest
13
+ from typing import Any, cast
14
+
15
+ from evutils.io import EventReader
16
+
17
+ sys.path.append(str(Path(__file__).parent.parent / "tests"))
18
+ from conftest_utils import EventFile, download_and_extract_gdrive, load_event_files # type: ignore
19
+
20
+ #: Cap on how many events are held in memory for the write benchmarks. Large
21
+ #: enough for a stable throughput measurement, small enough to stay light.
22
+ N_REFERENCE = 5_000_000
23
+
24
+
25
+ @pytest.fixture(scope='session')
26
+ def real_event_files(request: Any, benchmark_dataset: str) -> dict[str, list[Any]]:
27
+ """Real Prophesee recordings (downloaded + cached on first use).
28
+
29
+ Returns ``{format: [EventFile(path, count)]}``.
30
+
31
+ Set ``EVUTILS_BENCH_DATA`` to a directory that already contains the
32
+ extracted recordings (+ JSON metadata) to skip the download entirely --
33
+ useful in offline environments such as the OpenEB benchmark container
34
+ (mount the host cache there).
35
+ """
36
+ import os
37
+ override = os.environ.get("EVUTILS_BENCH_DATA")
38
+ if override:
39
+ data_dir = Path(override)
40
+ if not data_dir.is_dir():
41
+ pytest.skip(f"EVUTILS_BENCH_DATA={override} is not a directory")
42
+ return cast(dict[str, list[Any]], load_event_files(data_dir))
43
+
44
+ if benchmark_dataset == "large":
45
+ temp_dir = request.config.cache.mkdir("event_files_huge")
46
+ file_id = "1QPuilR1VD0rKyhVOlu1Y-HtkO4ZBc2Cz"
47
+
48
+ json_files = list(temp_dir.glob("*.json"))
49
+ if not json_files:
50
+ download_and_extract_gdrive(file_id, temp_dir, "huge.tar.zst")
51
+
52
+ return cast(dict[str, list[Any]], load_event_files(temp_dir))
53
+ else:
54
+ temp_dir = request.config.cache.mkdir("event_files")
55
+ file_id = "1uhOsWbp2o3CktsHrFkzGCNFbx0bQLsct"
56
+ filenames = {
57
+ 'evt3': "hand_evt3.raw",
58
+ 'evt21': "hand_evt21.raw",
59
+ 'evt2': "hand_evt2.raw",
60
+ }
61
+ paths = {fmt: temp_dir / name for fmt, name in filenames.items()}
62
+
63
+ for key, path in paths.items():
64
+ if not path.exists():
65
+ download_and_extract_gdrive(file_id, temp_dir, "hand.tar.zst")
66
+ break
67
+
68
+ return cast(dict[str, list[Any]], load_event_files(temp_dir))
69
+
70
+
71
+ @pytest.fixture(scope='session')
72
+ def reference_events(real_event_files: dict[str, list[Any]]) -> Any:
73
+ """First ``N_REFERENCE`` events of the real EVT3 recording as an AoS array.
74
+
75
+ Decoded once and reused as the payload for every write benchmark, so the
76
+ write benchmarks measure encoding cost only (not decoding).
77
+ """
78
+ parts = []
79
+ total = 0
80
+ if 'evt3' not in real_event_files or not real_event_files['evt3']:
81
+ pytest.skip("No evt3 files available for reference events")
82
+ # Use the hand_evt3.raw file for reference events
83
+ ef = next((f for f in real_event_files['evt3'] if 'hand' in f.path.name), real_event_files['evt3'][0])
84
+ with EventReader(ef.path, n_events=1_000_000) as reader:
85
+ for chunk in reader:
86
+ parts.append(chunk.to_aos())
87
+ total += len(chunk)
88
+ if total >= N_REFERENCE:
89
+ break
90
+ return np.concatenate(parts)[:N_REFERENCE]
91
+
92
+
93
+ def pytest_addoption(parser: Any) -> None:
94
+ parser.addoption(
95
+ "--rounds", action="store", default=4, type=int, help="Number of benchmark rounds"
96
+ )
97
+ parser.addoption(
98
+ "--dataset", action="store", default="small", choices=["small", "large"],
99
+ help="Dataset size to use for benchmarks ('small' or 'large')"
100
+ )
101
+
102
+ @pytest.fixture(scope="session")
103
+ def benchmark_rounds(request: Any) -> int:
104
+ return int(request.config.getoption("--rounds"))
105
+
106
+ @pytest.fixture(scope="session")
107
+ def benchmark_dataset(request: Any) -> str:
108
+ return str(request.config.getoption("--dataset"))
109
+
110
+
111
+ @pytest.hookimpl(hookwrapper=True)
112
+ def pytest_benchmark_group_stats(config: Any, benchmarks: list[dict[str, Any]], group_by: str) -> Any:
113
+ """Guard against a pytest-benchmark crash with ``--benchmark-group-by=param:<name>``.
114
+
115
+ Benchmarks collected from non-parametrized tests have ``params = None``,
116
+ which the plugin's param-grouping code cannot handle (TypeError) -- and the
117
+ crash also swallows the whole error/summary report. Give such benchmarks an
118
+ explicit null param instead, so they group under ``<name>=None``.
119
+ """
120
+ if isinstance(group_by, str) and group_by.startswith("param:"):
121
+ names = group_by.split(":", 1)[1].split(",")
122
+ for bench in benchmarks:
123
+ if bench.get("params") is None:
124
+ bench["params"] = {}
125
+ for name in names:
126
+ bench["params"].setdefault(name, None)
127
+ yield
128
+
129
+
130
+ @pytest.fixture(scope="session")
131
+ def uniform_files(reference_events: Any, tmp_path_factory: Any) -> dict[str, Any]:
132
+ """The same ``N_REFERENCE`` real events transcoded into every format.
133
+
134
+ All per-format read/write benchmarks (benchmarks/test_formats.py) operate
135
+ on these files, so throughput numbers are comparable across formats: same
136
+ events, same count. AER is the one lossy exception -- it has no timestamps
137
+ and 9-bit coordinates, so its file carries the same events with coordinates
138
+ masked to 0..511 (the event count is identical).
139
+ """
140
+ from evutils.io import EventWriter
141
+
142
+ sys.path.append(str(Path(__file__).parent.parent / "tests"))
143
+ from aedat_synth import make_aedat4 # type: ignore
144
+
145
+ d = tmp_path_factory.mktemp("uniform")
146
+ ev = reference_events
147
+ files = {}
148
+
149
+ for fmt in ("evt3", "evt21", "evt2"):
150
+ files[fmt] = d / f"ref_{fmt}.raw"
151
+ with EventWriter(files[fmt], width=1280, height=720, format=fmt) as w:
152
+ w.write(ev)
153
+
154
+ for fmt, name in (("dat", "ref.dat"), ("npz", "ref.npz"),
155
+ ("hdf5", "ref.h5"), ("csv", "ref.csv")):
156
+ files[fmt] = d / name
157
+ with EventWriter(files[fmt], width=1280, height=720) as w:
158
+ w.write(ev)
159
+
160
+ aer = ev.copy()
161
+ aer["x"] &= 0x1FF
162
+ aer["y"] &= 0x1FF
163
+ files["aer"] = d / "ref.aer"
164
+ with EventWriter(files["aer"]) as w:
165
+ w.write(aer)
166
+
167
+ files["aedat4"] = d / "ref.aedat4"
168
+ files["aedat4"].write_bytes(
169
+ make_aedat4(ev["t"], ev["x"], ev["y"], ev["p"], events_per_packet=65536)
170
+ )
171
+ return files
@@ -0,0 +1,56 @@
1
+ # OpenEB (Metavision SDK, open-source edition) + evutils, for running the
2
+ # comparison benchmarks against OpenEB's RawReader.
3
+ #
4
+ # OpenEB is not on PyPI and is fiddly to build; this image does it once.
5
+ #
6
+ # Build (from the repo root, so the whole project is the build context):
7
+ # docker build -t evutils-openeb -f benchmarks/docker/Dockerfile.openeb .
8
+ #
9
+ # Run the benchmarks (downloads the reference recordings on first run):
10
+ # docker run --rm evutils-openeb
11
+ #
12
+ # Tip: add a repo-root .dockerignore (.venv, build/, .git, *.raw, data/) to keep
13
+ # the build context small.
14
+ #
15
+ # NOTE: OpenEB's exact apt dependencies and layout shift between releases. This
16
+ # targets OpenEB 5.x on Ubuntu 22.04 -- bump OPENEB_VERSION / tweak deps if the
17
+ # build fails.
18
+ FROM registry.git.ee.ethz.ch/pbl/research/event-camera/docker/open-eb-docker/openeb_base:latest
19
+
20
+ ARG USERNAME=user
21
+ ARG PASSWORD=password
22
+ ARG USER_ID=1000
23
+ ARG GROUP_ID=1000
24
+
25
+ # Validate that all required arguments are set
26
+ RUN : \
27
+ && if [ -z "$USERNAME" ]; then echo "ERROR: USERNAME is not set."; exit 1; fi \
28
+ && if [ -z "$PASSWORD" ]; then echo "ERROR: PASSWORD is not set."; exit 1; fi \
29
+ && if [ -z "$USER_ID" ]; then echo "ERROR: USER_ID is not set."; exit 1; fi \
30
+ && if [ -z "$GROUP_ID" ]; then echo "ERROR: GROUP_ID is not set."; exit 1; fi
31
+
32
+ RUN groupadd -g ${GROUP_ID} ${USERNAME} && useradd -u ${USER_ID} -g ${GROUP_ID} -ms /bin/bash ${USERNAME} && usermod -aG sudo ${USERNAME} && echo "${USERNAME}:${PASSWORD}" | chpasswd
33
+
34
+ USER ${USERNAME}
35
+ RUN echo "source /openeb/build/utils/scripts/setup_env.sh" >> /home/${USERNAME}/.bashrc
36
+
37
+ WORKDIR /home/${USERNAME}/work
38
+ COPY . /home/${USERNAME}/work
39
+
40
+
41
+
42
+ # 2. Omit --python 3.12 so it defaults to the system Python (3.10) to match OpenEB
43
+ RUN uv venv --system-site-packages
44
+ RUN uv pip install --no-cache-dir -e ".[test,compare]"
45
+
46
+ ENV PATH="/home/${USERNAME}/work/.venv/bin:$PATH"
47
+
48
+ # 3. Source the OpenEB setup script directly during the RUN step
49
+ RUN . /openeb/build/utils/scripts/setup_env.sh && \
50
+ python3 -c "from metavision_core.event_io import RawReader; print('OpenEB OK')"
51
+
52
+ # 4. Use an ENTRYPOINT script to ensure OpenEB vars are loaded for ANY command you run
53
+ ENTRYPOINT ["/bin/bash", "-c", "source /openeb/build/utils/scripts/setup_env.sh && exec \"$@\"", "--"]
54
+
55
+ CMD ["pytest", "benchmarks/", "--benchmark-group-by=param:fmt", \
56
+ "--benchmark-columns=mean,ops", "-q"]