evutils 0.3.10__cp313-cp313-win_amd64.whl
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.
- evutils/__init__.py +41 -0
- evutils/augment/__init__.py +11 -0
- evutils/augment/_drop.py +32 -0
- evutils/chunking.py +117 -0
- evutils/dataset/__init__.py +5 -0
- evutils/evutils_native.dll +0 -0
- evutils/io/__init__.py +14 -0
- evutils/io/_aedat.py +33 -0
- evutils/io/_aer.py +32 -0
- evutils/io/_bin.py +31 -0
- evutils/io/_csv.py +197 -0
- evutils/io/_dat.py +30 -0
- evutils/io/_event_reader.py +379 -0
- evutils/io/_event_writer.py +128 -0
- evutils/io/_evt.py +548 -0
- evutils/io/_hdf5.py +187 -0
- evutils/io/_native_evt.py +481 -0
- evutils/io/_npz.py +30 -0
- evutils/io/_source.py +276 -0
- evutils/io/buffer.py +98 -0
- evutils/io/common.py +207 -0
- evutils/io/decoders.py +131 -0
- evutils/io/encoders.py +68 -0
- evutils/processing/__init__.py +14 -0
- evutils/processing/_masking.py +30 -0
- evutils/processing/_utils.py +25 -0
- evutils/random.py +77 -0
- evutils/repr/__init__.py +25 -0
- evutils/repr/_frame.py +126 -0
- evutils/repr/_histogram.py +110 -0
- evutils/repr/_timesurface.py +59 -0
- evutils/repr/_tore.py +58 -0
- evutils/repr/_voxel.py +54 -0
- evutils/torch/__init__.py +19 -0
- evutils/types.py +127 -0
- evutils/utils/__init__.py +8 -0
- evutils/utils/_checker.py +32 -0
- evutils/vis/__init__.py +5 -0
- evutils/vis/open3d.py +32 -0
- evutils/vis/plot3d.py +182 -0
- evutils/vis/reconstructor/__init__.py +11 -0
- evutils/vis/reconstructor/_base.py +71 -0
- evutils/vis/reconstructor/metavision.py +71 -0
- evutils/vis/reconstructor/rpg.py +217 -0
- evutils/vis/reconstructor/rpg_e2vid/.git +1 -0
- evutils/vis/reconstructor/rpg_e2vid/.gitignore +1 -0
- evutils/vis/reconstructor/rpg_e2vid/LICENSE +674 -0
- evutils/vis/reconstructor/rpg_e2vid/README.md +179 -0
- evutils/vis/reconstructor/rpg_e2vid/__init__.py +0 -0
- evutils/vis/reconstructor/rpg_e2vid/base/__init__.py +1 -0
- evutils/vis/reconstructor/rpg_e2vid/base/base_model.py +30 -0
- evutils/vis/reconstructor/rpg_e2vid/data/.gitignore +0 -0
- evutils/vis/reconstructor/rpg_e2vid/image_reconstructor.py +112 -0
- evutils/vis/reconstructor/rpg_e2vid/model/__init__.py +0 -0
- evutils/vis/reconstructor/rpg_e2vid/model/model.py +100 -0
- evutils/vis/reconstructor/rpg_e2vid/model/submodules.py +275 -0
- evutils/vis/reconstructor/rpg_e2vid/model/unet.py +178 -0
- evutils/vis/reconstructor/rpg_e2vid/options/__init__.py +0 -0
- evutils/vis/reconstructor/rpg_e2vid/options/inference_options.py +66 -0
- evutils/vis/reconstructor/rpg_e2vid/pretrained/.gitignore +0 -0
- evutils/vis/reconstructor/rpg_e2vid/run_reconstruction.py +112 -0
- evutils/vis/reconstructor/rpg_e2vid/scripts/embed_reconstructed_images_in_rosbag.py +90 -0
- evutils/vis/reconstructor/rpg_e2vid/scripts/extract_events_from_rosbag.py +126 -0
- evutils/vis/reconstructor/rpg_e2vid/scripts/image_folder_to_rosbag.py +73 -0
- evutils/vis/reconstructor/rpg_e2vid/scripts/resample_reconstructions.py +56 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/__init__.py +0 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/event_readers.py +88 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/inference_utils.py +545 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/loading_utils.py +31 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/path_utils.py +6 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/timers.py +57 -0
- evutils/vis/reconstructor/rpg_e2vid/utils/util.py +50 -0
- evutils-0.3.10.dist-info/METADATA +227 -0
- evutils-0.3.10.dist-info/RECORD +76 -0
- evutils-0.3.10.dist-info/WHEEL +5 -0
- evutils-0.3.10.dist-info/licenses/LICENSE +19 -0
evutils/__init__.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""evutils: utilities for event-based data.
|
|
2
|
+
|
|
3
|
+
Event-based data processing and visualization utilities.
|
|
4
|
+
|
|
5
|
+
To get started::
|
|
6
|
+
|
|
7
|
+
import evutils
|
|
8
|
+
...
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Notes
|
|
13
|
+
-----
|
|
14
|
+
Anything worth calling out up front.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import importlib.metadata
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
__version__ = importlib.metadata.version("evutils")
|
|
24
|
+
except importlib.metadata.PackageNotFoundError:
|
|
25
|
+
# Fallback if the package is run without being installed
|
|
26
|
+
__version__ = "dev"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
'augment',
|
|
31
|
+
'chunking',
|
|
32
|
+
'dataset',
|
|
33
|
+
'io',
|
|
34
|
+
'utils',
|
|
35
|
+
'vis',
|
|
36
|
+
'processing',
|
|
37
|
+
'random',
|
|
38
|
+
'types',
|
|
39
|
+
'__version__'
|
|
40
|
+
]
|
|
41
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Data augmentation transforms for events.
|
|
2
|
+
|
|
3
|
+
Random and deterministic transformations for augmenting event streams
|
|
4
|
+
during training, such as spatial flips, time reversal, event dropout and
|
|
5
|
+
added noise.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from ._drop import drop_random_events
|
|
10
|
+
|
|
11
|
+
__all__ = ["drop_random_events"]
|
evutils/augment/_drop.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def drop_random_events(events: np.ndarray, drop_rate: float = 0.1):
|
|
7
|
+
"""Drops a percentage of events randomly using slicing.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
events : np.ndarray
|
|
12
|
+
Array of events to drop from.
|
|
13
|
+
drop_rate : float, optional
|
|
14
|
+
Percentage of events to drop, by default 0.1 (10%).
|
|
15
|
+
|
|
16
|
+
Returns
|
|
17
|
+
-------
|
|
18
|
+
np.ndarray:w
|
|
19
|
+
|
|
20
|
+
Array of events with the specified percentage dropped.
|
|
21
|
+
"""
|
|
22
|
+
if drop_rate <= 0 or drop_rate >= 1:
|
|
23
|
+
raise ValueError("drop_rate must be between 0 and 1")
|
|
24
|
+
|
|
25
|
+
n_events = len(events)
|
|
26
|
+
indices = np.arange(n_events)
|
|
27
|
+
np.random.shuffle(indices)
|
|
28
|
+
|
|
29
|
+
drop_count = int(n_events * drop_rate)
|
|
30
|
+
keep_indices = indices[drop_count:]
|
|
31
|
+
|
|
32
|
+
return events[keep_indices]
|
evutils/chunking.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Splitting event streams into chunks.
|
|
2
|
+
|
|
3
|
+
Slice a continuous event stream into fixed-size windows, either by event
|
|
4
|
+
count or by time interval.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def window_delta_t(events: np.ndarray, delta_t: int = 10_000):
|
|
12
|
+
'''
|
|
13
|
+
Returns a generator that chunks the events array into windows of size delta_t
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
events : np.ndarray
|
|
18
|
+
Array of events
|
|
19
|
+
delta_t : int, optional
|
|
20
|
+
Size of the window in microseconds, by default 10_000'''
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if len(events) == 0:
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
index_start = 0
|
|
27
|
+
|
|
28
|
+
ts = events["t"]
|
|
29
|
+
current_ts = ts[0]
|
|
30
|
+
|
|
31
|
+
while index_start < len(events):
|
|
32
|
+
next_index = np.searchsorted(ts[index_start:], current_ts + delta_t)
|
|
33
|
+
|
|
34
|
+
window = events[index_start:index_start + next_index]
|
|
35
|
+
yield window
|
|
36
|
+
|
|
37
|
+
current_ts += delta_t
|
|
38
|
+
index_start += next_index
|
|
39
|
+
|
|
40
|
+
def sliding_window(events: np.ndarray, delta_t: int = 10_000, window_size: int = 20_000, full_window: bool = False):
|
|
41
|
+
'''
|
|
42
|
+
Returns a generator that chunks the events array into windows of size delta_t
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
events : np.ndarray
|
|
47
|
+
Array of events
|
|
48
|
+
delta_t : int, optional
|
|
49
|
+
Time delta between frames in microseconds, by default 10_000
|
|
50
|
+
window_size : int, optional
|
|
51
|
+
Size of the window in microseconds, by default 20_000
|
|
52
|
+
can overlap with the next frame
|
|
53
|
+
full_window : bool, optional
|
|
54
|
+
If True, the last window will be full, by default False
|
|
55
|
+
If False, the last window will be the remaining events
|
|
56
|
+
'''
|
|
57
|
+
|
|
58
|
+
if len(events) == 0:
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
index_start = 0
|
|
62
|
+
|
|
63
|
+
ts = events["t"]
|
|
64
|
+
current_ts = ts[0]
|
|
65
|
+
|
|
66
|
+
while index_start < len(events):
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
next_frame_index = np.searchsorted(ts[index_start:], current_ts + delta_t)
|
|
70
|
+
next_window_index = np.searchsorted(ts[index_start:], current_ts + window_size)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
window = events[index_start:index_start + next_window_index]
|
|
75
|
+
yield window
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# Exit if the next window index is not full
|
|
79
|
+
if full_window and index_start + next_window_index >= len(events):
|
|
80
|
+
break
|
|
81
|
+
|
|
82
|
+
current_ts += delta_t
|
|
83
|
+
index_start += next_frame_index
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def sort_events(events: np.ndarray):
|
|
89
|
+
'''Sorts the events array by timestamp
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
events : np.ndarray
|
|
94
|
+
Array of events
|
|
95
|
+
|
|
96
|
+
'''
|
|
97
|
+
return np.sort(events, order="t")
|
|
98
|
+
|
|
99
|
+
def get_dt_events(events: np.ndarray, dt: int =10_000):
|
|
100
|
+
'''
|
|
101
|
+
Returns the events that are within a time window of dt from the first event's timestamp.
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
events : np.ndarray
|
|
105
|
+
Array of events
|
|
106
|
+
dt : int, optional
|
|
107
|
+
Time window in microseconds, by default 10_000
|
|
108
|
+
'''
|
|
109
|
+
if len(events) == 0:
|
|
110
|
+
return events
|
|
111
|
+
|
|
112
|
+
first_ts = events[0]['t']
|
|
113
|
+
last_ts = first_ts + dt
|
|
114
|
+
|
|
115
|
+
next_index = np.searchsorted(events['t'], last_ts)
|
|
116
|
+
|
|
117
|
+
return events[:next_index]
|
|
Binary file
|
evutils/io/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Reading and writing events in various file formats.
|
|
2
|
+
|
|
3
|
+
Format-specific readers and writers (``bin``, ``csv``, ``dat``, ``hdf5``,
|
|
4
|
+
``npz``, ``raw``, ``txt``) built on a shared ``EventReader`` / ``EventWriter``
|
|
5
|
+
interface, plus ``EventReader_Any`` / ``EventWriter_Any`` which pick the
|
|
6
|
+
backend from the file extension. Backends that need optional dependencies
|
|
7
|
+
degrade gracefully and only raise on use.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from ._event_reader import EventReader
|
|
11
|
+
from ._event_writer import EventWriter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ["EventReader", "EventWriter"]
|
evutils/io/_aedat.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from .common import EventDecoder, EventEncoder
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EventDecoder_Aedat(EventDecoder):
|
|
10
|
+
'''
|
|
11
|
+
A decoder for reading events from AEDAT files.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
file
|
|
16
|
+
Path to the data file
|
|
17
|
+
'''
|
|
18
|
+
def __init__(self, file):
|
|
19
|
+
super().__init__(file)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EventEncoder_Aedat(EventEncoder):
|
|
23
|
+
'''
|
|
24
|
+
A encoder for writing events to AEDAT files.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
file
|
|
29
|
+
Path to the data file
|
|
30
|
+
'''
|
|
31
|
+
def __init__(self, file, width=1280, height=720):
|
|
32
|
+
super().__init__(file)
|
|
33
|
+
|
evutils/io/_aer.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from .common import EventDecoder, EventEncoder
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EventDecoder_AER(EventDecoder):
|
|
10
|
+
'''
|
|
11
|
+
A decoder for reading events from AER files.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
file
|
|
16
|
+
Path to the data file
|
|
17
|
+
'''
|
|
18
|
+
def __init__(self, file):
|
|
19
|
+
super().__init__(file)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EventEncoder_AER(EventEncoder):
|
|
23
|
+
'''
|
|
24
|
+
A encoder for writing events to AER files.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
file
|
|
29
|
+
Path to the data file
|
|
30
|
+
'''
|
|
31
|
+
def __init__(self, file, width=1280, height=720):
|
|
32
|
+
super().__init__(file, width, height)
|
evutils/io/_bin.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from .common import EventDecoder, EventEncoder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class EventDecoder_Bin(EventDecoder):
|
|
8
|
+
'''
|
|
9
|
+
A decoder for reading events from binary files.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
file
|
|
14
|
+
Path to the data file
|
|
15
|
+
'''
|
|
16
|
+
def __init__(self, file):
|
|
17
|
+
super().__init__(file)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EventEncoder_Bin(EventEncoder):
|
|
21
|
+
'''
|
|
22
|
+
A encoder for writing events to binary files.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
file
|
|
27
|
+
Path to the data file
|
|
28
|
+
'''
|
|
29
|
+
def __init__(self, file, width=1280, height=720):
|
|
30
|
+
super().__init__(file)
|
|
31
|
+
|
evutils/io/_csv.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import io
|
|
5
|
+
from io import TextIOWrapper
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from pandas._typing import CSVEngine
|
|
12
|
+
from pandas.io.parsers import TextFileReader
|
|
13
|
+
|
|
14
|
+
from ..types import Event_dtype, EventArray
|
|
15
|
+
from .common import EventDecoder, EventEncoder
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EventDecoder_Csv(EventDecoder):
|
|
19
|
+
'''
|
|
20
|
+
A reader for CSV files with events.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
file
|
|
25
|
+
Path to the data file
|
|
26
|
+
order
|
|
27
|
+
Order of the columns in the CSV file, by default ['t', 'x', 'y', 'p']
|
|
28
|
+
chunk_size
|
|
29
|
+
Size of the chunk to read, by default 10_000
|
|
30
|
+
delimiter
|
|
31
|
+
Delimiter for the CSV file, by default ","
|
|
32
|
+
engine
|
|
33
|
+
Engine to use to read the CSV file, by default 'c'
|
|
34
|
+
|
|
35
|
+
Raises
|
|
36
|
+
------
|
|
37
|
+
ValueError
|
|
38
|
+
If the order is not a list of 4 strings or if the order does not contain 't', 'x', 'y' and 'p'
|
|
39
|
+
|
|
40
|
+
'''
|
|
41
|
+
|
|
42
|
+
def __init__(self, readable:io.BufferedReader, order:list|None=None, chunk_size:int=1_000_000, delimiter:str=",", engine:CSVEngine='c'):
|
|
43
|
+
super().__init__(readable, chunk_size)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if order is None:
|
|
47
|
+
# we infer the header from the file, or use a default header
|
|
48
|
+
pass
|
|
49
|
+
else:
|
|
50
|
+
# Validate the parameters
|
|
51
|
+
if len(order) != 4:
|
|
52
|
+
raise ValueError("Order must be a list of 4 strings")
|
|
53
|
+
if "t" not in order or "x" not in order or "y" not in order or "p" not in order:
|
|
54
|
+
raise ValueError("Order must contain 't', 'x', 'y' and 'p'")
|
|
55
|
+
|
|
56
|
+
self._order = order
|
|
57
|
+
self._delimiter = delimiter
|
|
58
|
+
self._engine = engine
|
|
59
|
+
|
|
60
|
+
self._chunk_reader:TextFileReader|None= None
|
|
61
|
+
|
|
62
|
+
def _check_header(self):
|
|
63
|
+
have_header = False
|
|
64
|
+
|
|
65
|
+
# Check first line to see if it is a header
|
|
66
|
+
# TODO: Need to deal with non-seekable files
|
|
67
|
+
first_line: str = self._fd.readline().decode('utf-8').strip()
|
|
68
|
+
|
|
69
|
+
# Check if the first line is a header
|
|
70
|
+
# If we find a header, it will take precendence over the order parameter
|
|
71
|
+
|
|
72
|
+
if "t" in first_line or "x" in first_line or "y" in first_line or "p" in first_line:
|
|
73
|
+
# Header found
|
|
74
|
+
have_header = True
|
|
75
|
+
|
|
76
|
+
if have_header:
|
|
77
|
+
# We expect a header:
|
|
78
|
+
if "t" in first_line and "x" in first_line and "y" in first_line and "p" in first_line:
|
|
79
|
+
# Header found
|
|
80
|
+
order = first_line.split(",")
|
|
81
|
+
|
|
82
|
+
if self._order is not None and order != self._order:
|
|
83
|
+
print(ValueError(f"WARNING: Header order {self._order} does not match order file {order}"))
|
|
84
|
+
self._order = order
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
raise ValueError(f"Header not found or invalid: {first_line}")
|
|
89
|
+
else:
|
|
90
|
+
# No header found, just seek to start of file
|
|
91
|
+
self._fd.seek(0)
|
|
92
|
+
|
|
93
|
+
# If we still don't have a header, we use a default one
|
|
94
|
+
if self._order is None:
|
|
95
|
+
self._order = ['t', 'x', 'y', 'p']
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def init(self):
|
|
100
|
+
|
|
101
|
+
self._check_header()
|
|
102
|
+
|
|
103
|
+
self._chunk_reader = pd.read_csv(self._fd, iterator=True, header=None, names=self._order, engine=self._engine,
|
|
104
|
+
delimiter=self._delimiter, dtype={"t":"u8", "p":"u1", "x":"u2","y":"u2"})
|
|
105
|
+
|
|
106
|
+
# self.numpy_reader = np.fromtxt(self._fd, delimiter=",", dtype=np.uint64)
|
|
107
|
+
self._is_initialized = True
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def read_chunk(self, delta_t_hint:int | None = None, n_events_hint:int | None = None) -> np.ndarray[Any, np.dtype[Any]]:
|
|
111
|
+
assert self._is_initialized, "Reader is not initialized"
|
|
112
|
+
assert self._chunk_reader is not None
|
|
113
|
+
# We can use the n_events_hint to read exactly n_events
|
|
114
|
+
#n_events_hint = None
|
|
115
|
+
#if not n_events_hint is None:
|
|
116
|
+
# chunk_size = n_events_hint
|
|
117
|
+
#else:
|
|
118
|
+
# chunk_size = self.chunk_size
|
|
119
|
+
chunk_size = self._chunk_size
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
df = self._chunk_reader.get_chunk(chunk_size)
|
|
123
|
+
events = EventArray(df['t'].to_numpy(), df['x'].to_numpy(),
|
|
124
|
+
df['y'].to_numpy(), df['p'].to_numpy())
|
|
125
|
+
except StopIteration:
|
|
126
|
+
events = EventArray.empty()
|
|
127
|
+
|
|
128
|
+
# Detect end of file
|
|
129
|
+
if len(events) < chunk_size:
|
|
130
|
+
self._eof = True
|
|
131
|
+
|
|
132
|
+
return events
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def reset(self):
|
|
136
|
+
assert self._fd is not None
|
|
137
|
+
self._fd.seek(0)
|
|
138
|
+
self._check_header()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class EventEncoder_Csv(EventEncoder):
|
|
143
|
+
'''
|
|
144
|
+
A writer for CSV files with events.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
file : str
|
|
149
|
+
Path to the data file
|
|
150
|
+
width : int, optional
|
|
151
|
+
Width of the frame, by default 1280 (not relevant for this formats)
|
|
152
|
+
height : int, optional
|
|
153
|
+
Height of the frame, by default 720 (not relevant for this formats)
|
|
154
|
+
sep : str, optional
|
|
155
|
+
Separator for the CSV file, by default ","
|
|
156
|
+
order : list, optional
|
|
157
|
+
Order of the columns in the CSV file, by default ['t', 'x', 'y', 'p']
|
|
158
|
+
header : bool, optional
|
|
159
|
+
If True, a header is written on the first line, by default True
|
|
160
|
+
|
|
161
|
+
Raises
|
|
162
|
+
------
|
|
163
|
+
ValueError
|
|
164
|
+
If the order is not a list of 4 strings or if the order does not contain 't', 'x', 'y' and 'p'
|
|
165
|
+
|
|
166
|
+
'''
|
|
167
|
+
|
|
168
|
+
def __init__(self, writable: io.BufferedWriter, width:int=1280, height:int=720, sep:str=",", order:list=['t', 'x', 'y', 'p'], header:bool=True):
|
|
169
|
+
super().__init__(writable)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if len(order) != 4:
|
|
173
|
+
raise ValueError("Order must be a list of 4 strings")
|
|
174
|
+
if "t" not in order or "x" not in order or "y" not in order or "p" not in order:
|
|
175
|
+
raise ValueError("Order must contain 't', 'x', 'y' and 'p'")
|
|
176
|
+
|
|
177
|
+
self._order = order
|
|
178
|
+
self._header = header
|
|
179
|
+
self._sep = sep
|
|
180
|
+
|
|
181
|
+
def init(self):
|
|
182
|
+
|
|
183
|
+
if self._header:
|
|
184
|
+
header = self._sep.join(self._order) + "\n"
|
|
185
|
+
self._fd.write(header.encode('utf-8'))
|
|
186
|
+
|
|
187
|
+
self._is_initialized = True
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def write(self, events: np.ndarray[Any, np.dtype[Any]]) -> int:
|
|
191
|
+
if not self._is_initialized:
|
|
192
|
+
self.init()
|
|
193
|
+
|
|
194
|
+
df = pd.DataFrame(events)
|
|
195
|
+
df.to_csv(self._fd, header=False, index=False, columns=self._order, sep=self._sep)
|
|
196
|
+
return len(events)
|
|
197
|
+
|
evutils/io/_dat.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from .common import EventDecoder, EventEncoder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class EventDecoder_Dat(EventDecoder):
|
|
8
|
+
'''
|
|
9
|
+
A decoder for reading events from DAT files.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
file
|
|
14
|
+
Path to the data file
|
|
15
|
+
'''
|
|
16
|
+
def __init__(self, file):
|
|
17
|
+
super().__init__(file)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EventEncoder_Dat(EventEncoder):
|
|
21
|
+
'''
|
|
22
|
+
A encoder for writing events to DAT files.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
file
|
|
27
|
+
Path to the data file
|
|
28
|
+
'''
|
|
29
|
+
def __init__(self, file, width=1280, height=720):
|
|
30
|
+
super().__init__(file)
|