From 055233832621a2de80a7d1a9bad41d6b0c6f8db1 Mon Sep 17 00:00:00 2001 From: Yuhuang Hu Date: Sat, 16 Mar 2024 01:58:18 +0100 Subject: [PATCH 1/6] formatted by ruff --- .pre-commit-config.yaml | 12 ++++ pyaer/__about__.py | 1 + pyaer/__init__.py | 2 + pyaer/comm.py | 8 +-- pyaer/davis.py | 5 +- pyaer/device.py | 1 + pyaer/dvs128.py | 1 + pyaer/dvxplorer.py | 1 + pyaer/dynapse.py | 7 +- pyaer/edvs.py | 1 + pyaer/evk.py | 1 + pyaer/filters.py | 1 + pyaer/log.py | 2 + pyaer/utils.py | 3 +- ruff.toml | 77 +++++++++++++++++++++ scripts/aer_comm/aer_hub | 49 +++++++------ scripts/aer_comm/aer_launch | 99 +++++++++++++------------- scripts/aer_comm/aer_lstopic | 32 ++++----- scripts/aer_comm/aer_publisher | 98 +++++++++++++++----------- scripts/aer_comm/aer_pubsuber | 88 ++++++++++++----------- scripts/aer_comm/aer_saver | 76 +++++++++----------- scripts/aer_comm/aer_subscriber | 71 ++++++++++--------- scripts/aer_comm/custom_comm.py | 40 +++++------ scripts/aer_comm/test_hdf5_reader.py | 10 +-- scripts/davis240_test.py | 64 ++++++++++------- scripts/davis346_color_events.py | 100 +++++++++++++++++---------- scripts/davis346_color_test.py | 72 ++++++++++++------- scripts/davis346_test.py | 88 ++++++++++++++--------- scripts/dvs128_glumpy.py | 69 +++++++++--------- scripts/dvs128_test.py | 46 ++++++------ scripts/dvs128_thread_test.py | 76 +++++++++++--------- scripts/dvs128_vispy.py | 93 +++++++++++++------------ scripts/dvs_noise_filter_test.py | 74 +++++++++++--------- scripts/dvxplorer_test.py | 23 +++--- scripts/dynapse_test.py | 49 +++++++------ scripts/edvs_test.py | 57 ++++++++------- scripts/event_container_test.py | 25 +++---- scripts/timer.py | 99 ++++++++++++++++---------- setup.py | 2 + 39 files changed, 951 insertions(+), 672 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 ruff.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..11a7d15 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,12 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.3.2 + hooks: + # Run the linter. + - id: ruff + types_or: [ python, pyi, jupyter ] + args: [ "--fix"] + # Run the formatter. + - id: ruff-format + types_or: [ python, pyi, jupyter ] diff --git a/pyaer/__about__.py b/pyaer/__about__.py index 8790941..bd96a42 100644 --- a/pyaer/__about__.py +++ b/pyaer/__about__.py @@ -1,4 +1,5 @@ """About page.""" + __all__ = ["__version__", "__author__", "__author_email__", "__url__"] __version__ = "0.2.7a0" diff --git a/pyaer/__init__.py b/pyaer/__init__.py index 009f1ca..38ae5ce 100644 --- a/pyaer/__init__.py +++ b/pyaer/__init__.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import absolute_import from __future__ import print_function @@ -12,6 +13,7 @@ from pyaer.__about__ import __author__ # noqa from pyaer.__about__ import __version__ # noqa + FILE_PATH = os.path.realpath(__file__) CURR_PATH = os.path.dirname(os.path.realpath(__file__)) PKG_PATH = os.path.dirname(CURR_PATH) diff --git a/pyaer/comm.py b/pyaer/comm.py index 93b5dfa..be7cc08 100644 --- a/pyaer/comm.py +++ b/pyaer/comm.py @@ -13,6 +13,7 @@ Author: Yuhuang Hu Email : yuhuang.hu@ini.uzh.ch """ + import json import signal import subprocess @@ -25,6 +26,7 @@ import numpy as np import zmq + try: import zarr except Exception: @@ -181,7 +183,6 @@ def __init__( name : str the name of the publisher """ - self.__dict__.update(kwargs) self.url = url @@ -271,7 +272,7 @@ def __init__( port=5100, master_topic="", name="", - **kwargs + **kwargs, ): """AERPublisher. @@ -605,7 +606,7 @@ def __init__( sub_port=5099, sub_topic="", sub_name="", - **kwargs + **kwargs, ): """Publisher-Subscriber. @@ -760,7 +761,6 @@ def get_keys(self): def get_frame(self, device_name, group_name): """Get frame events at this packet.""" - try: frame_events = self.aer_file[device_name][group_name]["frame_events"][()] diff --git a/pyaer/davis.py b/pyaer/davis.py index 9ef0b17..5180592 100644 --- a/pyaer/davis.py +++ b/pyaer/davis.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import numpy as np from pyaer import libcaer @@ -855,7 +856,6 @@ def get_bias(self): bias_obj: `dict`
dictionary that contains DAVIS current bias settings. """ - bias_obj = {} # output sources bias_obj["aps_enabled"] = self.get_config( @@ -1310,7 +1310,6 @@ def get_event_container(self): Instead of returning different variables, return an event container. """ - data = self.get_event() if data is None: @@ -1447,7 +1446,7 @@ def get_event(self, mode="events"): num_imu_event, ) else: - return None,0,None,0,None,0,None,0 + return None, 0, None, 0, None, 0, None, 0 class DAVISFX2(DAVIS): diff --git a/pyaer/device.py b/pyaer/device.py index 548d2ff..9d8e6a7 100644 --- a/pyaer/device.py +++ b/pyaer/device.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import abc from pyaer import libcaer diff --git a/pyaer/dvs128.py b/pyaer/dvs128.py index c6e2040..1be6f0a 100644 --- a/pyaer/dvs128.py +++ b/pyaer/dvs128.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import numpy as np from pyaer import libcaer diff --git a/pyaer/dvxplorer.py b/pyaer/dvxplorer.py index 5f51f1d..8268158 100644 --- a/pyaer/dvxplorer.py +++ b/pyaer/dvxplorer.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import numpy as np from pyaer import libcaer diff --git a/pyaer/dynapse.py b/pyaer/dynapse.py index 238522f..2d058ce 100644 --- a/pyaer/dynapse.py +++ b/pyaer/dynapse.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import time import numpy as np @@ -186,7 +187,7 @@ def set_bias_from_json( 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3], - } + } ``` """ bias_obj = utils.load_dynapse_bias(file_path, verbose) @@ -369,7 +370,7 @@ def set_bias( 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3], - } + } ``` # Returns @@ -408,7 +409,7 @@ def set_bias( assert isinstance(scope, dict) # Set biases for some activity - for (chip_id, core_ids) in scope.items(): + for chip_id, core_ids in scope.items(): self.set_activity_bias( bias_obj, self.chip_config[chip_id], core_ids=core_ids ) diff --git a/pyaer/edvs.py b/pyaer/edvs.py index f4b3d6b..a7174bb 100644 --- a/pyaer/edvs.py +++ b/pyaer/edvs.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import numpy as np from pyaer import libcaer diff --git a/pyaer/evk.py b/pyaer/evk.py index 3be174b..8ee1c2b 100644 --- a/pyaer/evk.py +++ b/pyaer/evk.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import numpy as np from pyaer import libcaer diff --git a/pyaer/filters.py b/pyaer/filters.py index 77b49b6..22f2da1 100644 --- a/pyaer/filters.py +++ b/pyaer/filters.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from typing import Any from typing import Dict diff --git a/pyaer/log.py b/pyaer/log.py index 8aa9302..b88c71c 100644 --- a/pyaer/log.py +++ b/pyaer/log.py @@ -5,11 +5,13 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import logging from logging import Logger from typing import Optional from typing import TextIO + # Remaps logging levels for easy access. NOTSET = logging.NOTSET DEBUG = logging.DEBUG diff --git a/pyaer/utils.py b/pyaer/utils.py index 8a97e6a..eeb0d31 100644 --- a/pyaer/utils.py +++ b/pyaer/utils.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + import importlib.util as imutil import json import os @@ -16,6 +17,7 @@ from pyaer import libcaer from pyaer import log + logger = log.get_logger("utils", pyaer.LOG_LEVEL) @@ -42,7 +44,6 @@ def import_custom_module(custom_file, custom_class): def parse_type(custom_str): """Parse custom string to its corresponding type.""" - # check integer try: return int(custom_str) diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..42da16c --- /dev/null +++ b/ruff.toml @@ -0,0 +1,77 @@ +line-length = 88 + +exclude = [ + ".git/", + "__pycache__/", + "build/", + "dist/", + "venv*/", + "docs/", + "docs/*", + "res/", + "res/*", +] + +[lint] + +extend-select = [ + # Enable the isort rules. + "I", + # Enable all `pydocstyle` rules, limiting to those that adhere to the + # Google convention via `convention = "google"`, below. + "D", + # Doc line length. + "W505" +] + +ignore = [ + "E203", + "E501", + # On top of the Google convention, disable `D417`, which requires + # documentation for every function parameter. + "D417", + # Missing docstring in public module + "D100", + # Missing docstring in public class + "D101", + # Missing docstring in public method + "D102", + # Missing docstring in public function + "D103", + # Missing docstring in public package + "D104", + # Missing docstring in magic method + "D105", + # Missing docstring in `__init__` + "D107", + # 1 blank line required between summary line and description. + # This is needed because sometimes our summaries span multiple lines. + "D205", + # Multi-line docstring closing quotes should be on a separate line + # This is a result of summary lines spanning more than one line. + "D209", + # Multi-line docstring summary should start at the first line. + "D212", + # Use `r"""` if any backslashes in a docstring. + "D301", + # Doc line too long + # This is needed because we have ~400 errors otherwise. + "W505", +] + + +[lint.isort] +order-by-type = false +case-sensitive = false +split-on-trailing-comma = true +force-single-line = true +lines-after-imports = 2 + +[lint.pydocstyle] +convention = "google" + +[lint.pycodestyle] +max-doc-length = 88 + +[format] +docstring-code-format = true diff --git a/scripts/aer_comm/aer_hub b/scripts/aer_comm/aer_hub index 557db9d..9539b93 100755 --- a/scripts/aer_comm/aer_hub +++ b/scripts/aer_comm/aer_hub @@ -6,54 +6,61 @@ Author: Yuhuang Hu Email : yuhuang.hu@ini.uzh.ch """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function -import json import argparse +import json from pyaer.comm import AERHub + parser = argparse.ArgumentParser("AER Hub") -parser.add_argument("--url", type=str, - default="tcp://127.0.0.1", - help="AERHub URL") +parser.add_argument("--url", type=str, default="tcp://127.0.0.1", help="AERHub URL") # Note that the publisher port and subscriber port are # hub_sub_port and hub_pub_port respectively. # This reversed order is intentional. # User doesn't need to know. -parser.add_argument("--publisher_port", type=int, - default=5100, - help="the port that connects all publishers") -parser.add_argument("--subscriber_port", type=int, - default=5099, - help="the port that connects all subscribers") +parser.add_argument( + "--publisher_port", + type=int, + default=5100, + help="the port that connects all publishers", +) +parser.add_argument( + "--subscriber_port", + type=int, + default=5099, + help="the port that connects all subscribers", +) -parser.add_argument("--aer_hub_name", type=str, - default="PyAER Message Hub") +parser.add_argument("--aer_hub_name", type=str, default="PyAER Message Hub") args = parser.parse_args() # print all options -print("="*50) +print("=" * 50) print(json.dumps(args.__dict__, indent=4, sort_keys=True)) -print("="*50) +print("=" * 50) -aer_hub = AERHub(url=args.url, - hub_pub_port=args.subscriber_port, - hub_sub_port=args.publisher_port, - aer_hub_name=args.aer_hub_name) +aer_hub = AERHub( + url=args.url, + hub_pub_port=args.subscriber_port, + hub_sub_port=args.publisher_port, + aer_hub_name=args.aer_hub_name, +) -aer_hub.logger.info("="*50) +aer_hub.logger.info("=" * 50) aer_hub.logger.info("Tools") aer_hub.logger.info("aer_hub: launch a central message relay hub") aer_hub.logger.info("aer_lstopic: display all published topics") aer_hub.logger.info("aer_publisher: add a custom publisher") aer_hub.logger.info("aer_subscriber: add a custom subscriber") aer_hub.logger.info("aer_saver: add an AER Saver") -aer_hub.logger.info("="*50) +aer_hub.logger.info("=" * 50) # run the hub aer_hub.run() diff --git a/scripts/aer_comm/aer_launch b/scripts/aer_comm/aer_launch index 9bd5b8c..8710dde 100755 --- a/scripts/aer_comm/aer_launch +++ b/scripts/aer_comm/aer_launch @@ -6,17 +6,19 @@ Author: Yuhuang Hu Email : yuhuang.hu@ini.uzh.ch """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function +import argparse import os import sys -import argparse import time +from pyaer import log +from pyaer.comm import AERProcess from pyaer.utils import expandpath from pyaer.utils import ordered_yml_load -from pyaer.comm import AERProcess -from pyaer import log + HUB = "Hub" PUB = "Publisher" @@ -40,9 +42,7 @@ DEFAULT_LIBVER_VERSION = "earliest" PROGRAM_KEY = "program" -launch_logger = log.get_logger( - "AER Launcher", - log.INFO, stream=sys.stdout) +launch_logger = log.get_logger("AER Launcher", log.INFO, stream=sys.stdout) def parse_hub(hub_desc): @@ -75,11 +75,12 @@ def parse_publisher(pub_desc): parsed_cmd += [ "--url", - DEFAULT_URL if "url" not in pub_desc else pub_desc.pop("url")] + DEFAULT_URL if "url" not in pub_desc else pub_desc.pop("url"), + ] parsed_cmd += [ "--port", - DEFAULT_PUBLISHER_PORT if "port" not in pub_desc else - str(pub_desc.pop("port"))] + DEFAULT_PUBLISHER_PORT if "port" not in pub_desc else str(pub_desc.pop("port")), + ] parsed_cmd += ["--name", pub_desc.pop("name")] parsed_cmd += ["--master_topic", pub_desc.pop("master_topic")] @@ -101,13 +102,12 @@ def parse_publisher(pub_desc): if pub_desc.pop("noise_filter", default=False): parsed_cmd += ["--noise_filter"] if "bias_file" in pub_desc: - parsed_cmd += [ - "--bias_file", expandpath(pub_desc.pop("bias_file"))] + parsed_cmd += ["--bias_file", expandpath(pub_desc.pop("bias_file"))] except Exception: pass try: - for (option, value) in pub_desc.items(): + for option, value in pub_desc.items(): parsed_cmd += ["--{}".format(option), str(value)] except Exception: pass @@ -126,11 +126,14 @@ def parse_subscriber(sub_desc): parsed_cmd += [ "--url", - DEFAULT_URL if "url" not in sub_desc else sub_desc.pop("url")] + DEFAULT_URL if "url" not in sub_desc else sub_desc.pop("url"), + ] parsed_cmd += [ "--port", - DEFAULT_SUBSCRIBER_PORT if "port" not in sub_desc else - str(sub_desc.pop("port"))] + DEFAULT_SUBSCRIBER_PORT + if "port" not in sub_desc + else str(sub_desc.pop("port")), + ] parsed_cmd += ["--name", sub_desc.pop("name")] parsed_cmd += ["--topic", sub_desc.pop("topic")] @@ -147,7 +150,7 @@ def parse_subscriber(sub_desc): sub_desc.pop(USE_DEFAULT_SUB) try: - for (option, value) in sub_desc.items(): + for option, value in sub_desc.items(): parsed_cmd += ["--{}".format(option), str(value)] except Exception: pass @@ -166,24 +169,27 @@ def parse_pubsuber(pubsuber_desc): parsed_cmd += [ "--url", - DEFAULT_URL if "url" not in pubsuber_desc else - pubsuber_desc.pop("url")] + DEFAULT_URL if "url" not in pubsuber_desc else pubsuber_desc.pop("url"), + ] parsed_cmd += [ "--pub_port", - DEFAULT_PUBLISHER_PORT if "pub_port" not in pubsuber_desc else - str(pubsuber_desc.pop("pub_port"))] + DEFAULT_PUBLISHER_PORT + if "pub_port" not in pubsuber_desc + else str(pubsuber_desc.pop("pub_port")), + ] parsed_cmd += ["--pub_name", pubsuber_desc.pop("pub_name")] parsed_cmd += ["--pub_topic", pubsuber_desc.pop("pub_topic")] parsed_cmd += [ "--sub_port", - DEFAULT_SUBSCRIBER_PORT if "sub_port" not in pubsuber_desc else - str(pubsuber_desc.pop("sub_port"))] + DEFAULT_SUBSCRIBER_PORT + if "sub_port" not in pubsuber_desc + else str(pubsuber_desc.pop("sub_port")), + ] parsed_cmd += ["--sub_name", pubsuber_desc.pop("sub_name")] parsed_cmd += ["--sub_topic", pubsuber_desc.pop("sub_topic")] - custom_pubsuber, custom_class = os.path.split( - pubsuber_desc.pop("custom_pubsuber")) + custom_pubsuber, custom_class = os.path.split(pubsuber_desc.pop("custom_pubsuber")) parsed_cmd += ["--custom_pubsuber", expandpath(custom_pubsuber)] parsed_cmd += ["--custom_class", custom_class] @@ -193,13 +199,12 @@ def parse_pubsuber(pubsuber_desc): if pubsuber_desc.pop("noise_filter", default=False): parsed_cmd += ["--noise_filter"] if "bias_file" in pubsuber_desc: - parsed_cmd += ["--bias_file", expandpath( - pubsuber_desc.pop("bias_file"))] + parsed_cmd += ["--bias_file", expandpath(pubsuber_desc.pop("bias_file"))] except Exception: pass try: - for (option, value) in pubsuber_desc.items(): + for option, value in pubsuber_desc.items(): parsed_cmd += ["--{}".format(option), str(value)] except Exception: pass @@ -212,11 +217,14 @@ def parse_saver(saver_desc): parsed_cmd += [ "--url", - DEFAULT_URL if "url" not in saver_desc else saver_desc["url"]] + DEFAULT_URL if "url" not in saver_desc else saver_desc["url"], + ] parsed_cmd += [ "--port", - DEFAULT_SUBSCRIBER_PORT if "port" not in saver_desc else - str(saver_desc["port"])] + DEFAULT_SUBSCRIBER_PORT + if "port" not in saver_desc + else str(saver_desc["port"]), + ] parsed_cmd += ["--name", saver_desc["name"]] parsed_cmd += ["--topic", saver_desc["topic"]] @@ -224,12 +232,12 @@ def parse_saver(saver_desc): parsed_cmd += [ "--mode", - DEFAULT_HDF5_MODE if "mode" not in saver_desc else - saver_desc["mode"]] + DEFAULT_HDF5_MODE if "mode" not in saver_desc else saver_desc["mode"], + ] parsed_cmd += [ "--libver", - DEFAULT_LIBVER_VERSION if "libver" not in saver_desc else - saver_desc["libver"]] + DEFAULT_LIBVER_VERSION if "libver" not in saver_desc else saver_desc["libver"], + ] # Use HDF5 as the default saver try: @@ -242,8 +250,7 @@ def parse_saver(saver_desc): parser = argparse.ArgumentParser("AER Launch") -parser.add_argument("--launch_file", type=expandpath, - help="AER Launch File") +parser.add_argument("--launch_file", type=expandpath, help="AER Launch File") args = parser.parse_args() @@ -259,29 +266,23 @@ try: # if the first one is not a hub type, then start the default hub if pg_i == 0 and pg_type != HUB: parsed_hub_cmd = parse_hub({"use_default": True}) - process_collector.append( - AERProcess(parsed_hub_cmd, daemon=True)) + process_collector.append(AERProcess(parsed_hub_cmd, daemon=True)) if pg_type == HUB: parsed_hub_cmd = parse_hub(pg_desc) - process_collector.append( - AERProcess(parsed_hub_cmd)) + process_collector.append(AERProcess(parsed_hub_cmd)) elif PUB in pg_type: parsed_pub_cmd = parse_publisher(pg_desc) - process_collector.append( - AERProcess(parsed_pub_cmd)) + process_collector.append(AERProcess(parsed_pub_cmd)) elif SUB in pg_type: parsed_sub_cmd = parse_subscriber(pg_desc) - process_collector.append( - AERProcess(parsed_sub_cmd)) + process_collector.append(AERProcess(parsed_sub_cmd)) elif PUBSUB in pg_type: parsed_pubsuber_cmd = parse_pubsuber(pg_desc) - process_collector.append( - AERProcess(parsed_pubsuber_cmd)) + process_collector.append(AERProcess(parsed_pubsuber_cmd)) elif SAVER in pg_type: parsed_saver_cmd = parse_saver(pg_desc) - process_collector.append( - AERProcess(parsed_saver_cmd)) + process_collector.append(AERProcess(parsed_saver_cmd)) else: launch_logger.error("Unsupported Type {}".format(pg_type)) diff --git a/scripts/aer_comm/aer_lstopic b/scripts/aer_comm/aer_lstopic index a93fff5..2476bd6 100755 --- a/scripts/aer_comm/aer_lstopic +++ b/scripts/aer_comm/aer_lstopic @@ -6,16 +6,17 @@ Author: Yuhuang Hu Email : yuhuang.hu@ini.uzh.ch """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function -import os import argparse +import os + from pyaer.comm import AERSubscriber class ListSubscriber(AERSubscriber): - def __init__(self, url="tcp://127.0.0.1", - port=5099, topic='', name="Topic List"): + def __init__(self, url="tcp://127.0.0.1", port=5099, topic="", name="Topic List"): """ListSubscriber. Used for list all the topics. @@ -27,36 +28,35 @@ class ListSubscriber(AERSubscriber): while True: data = self.socket.recv_multipart() - topic_name = self.unpack_data_name( - data[:2], topic_name_only=True) + topic_name = self.unpack_data_name(data[:2], topic_name_only=True) if topic_name not in topic_list: topic_list.append(topic_name) topic_list.sort() # Clear screen and write - os.system('cls' if os.name == 'nt' else 'clear') - print("="*50) + os.system("cls" if os.name == "nt" else "clear") + print("=" * 50) print("List of topic names") - print("="*50) + print("=" * 50) for tn in topic_list: print(tn) - print("="*50) + print("=" * 50) parser = argparse.ArgumentParser("AER List Topics") -parser.add_argument("--url", type=str, - default="tcp://127.0.0.1", - help="AER list topic URL") +parser.add_argument( + "--url", type=str, default="tcp://127.0.0.1", help="AER list topic URL" +) # Note that the publisher port and subscriber port are # hub_sub_port and hub_pub_port respectively. # This reversed order is intentional. # User doesn't need to know. -parser.add_argument("--port", type=int, - default=5099, - help="the port that connects all subscribers") +parser.add_argument( + "--port", type=int, default=5099, help="the port that connects all subscribers" +) args = parser.parse_args() diff --git a/scripts/aer_comm/aer_publisher b/scripts/aer_comm/aer_publisher index dd79553..29cc844 100755 --- a/scripts/aer_comm/aer_publisher +++ b/scripts/aer_comm/aer_publisher @@ -6,60 +6,69 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function import argparse import json +from pyaer.comm import AERPublisher from pyaer.davis import DAVIS from pyaer.dvs128 import DVS128 from pyaer.dvxplorer import DVXPLORER -from pyaer.utils import expandpath, import_custom_module +from pyaer.utils import expandpath +from pyaer.utils import import_custom_module from pyaer.utils import parse_custom_args -from pyaer.comm import AERPublisher + parser = argparse.ArgumentParser() -parser.add_argument("--url", type=str, - default="tcp://127.0.0.1", - help="AER Publisher URL") -parser.add_argument("--port", type=int, - default=5100, - help="the port that connects this publisher") -parser.add_argument("--master_topic", type=str, - default="device", - help="Master topic name for the publisher") -parser.add_argument("--name", type=str, - default="", - help="Name of the publisher") - -parser.add_argument("--device", type=str, - default="DAVIS", - help="Currently supported options: DAVIS, DVS, DVXPLORER") -parser.add_argument("--noise_filter", action="store_true", - help="Add option to enable noise filter.") -parser.add_argument("--bias_file", type=expandpath, - default=None, - help="Optional bias file") +parser.add_argument( + "--url", type=str, default="tcp://127.0.0.1", help="AER Publisher URL" +) +parser.add_argument( + "--port", type=int, default=5100, help="the port that connects this publisher" +) +parser.add_argument( + "--master_topic", + type=str, + default="device", + help="Master topic name for the publisher", +) +parser.add_argument("--name", type=str, default="", help="Name of the publisher") + +parser.add_argument( + "--device", + type=str, + default="DAVIS", + help="Currently supported options: DAVIS, DVS, DVXPLORER", +) +parser.add_argument( + "--noise_filter", action="store_true", help="Add option to enable noise filter." +) +parser.add_argument( + "--bias_file", type=expandpath, default=None, help="Optional bias file" +) parser.add_argument("--use_default_pub", action="store_true") -parser.add_argument("--custom_pub", type=expandpath, - default="", - help="path to the custom publisher class") -parser.add_argument("--custom_class", type=str, - default="", - help="custom publisher class name") +parser.add_argument( + "--custom_pub", + type=expandpath, + default="", + help="path to the custom publisher class", +) +parser.add_argument( + "--custom_class", type=str, default="", help="custom publisher class name" +) args, custom_args = parser.parse_known_args() custom_args_dict = parse_custom_args(custom_args) # print all options -print("="*50) -print(json.dumps( - {**args.__dict__, **custom_args_dict}, - indent=4, sort_keys=True)) -print("="*50) +print("=" * 50) +print(json.dumps({**args.__dict__, **custom_args_dict}, indent=4, sort_keys=True)) +print("=" * 50) # open the device if args.device == "None": @@ -79,20 +88,25 @@ else: # define publisher if args.use_default_pub: # fall back to the default publisher - publisher = AERPublisher(device=device, - url=args.url, - port=args.port, - master_topic=args.master_topic, - name=args.name) + publisher = AERPublisher( + device=device, + url=args.url, + port=args.port, + master_topic=args.master_topic, + name=args.name, + ) publisher.logger.info("Use default publisher") else: # use custom publisher CustomPublisher = import_custom_module(args.custom_pub, args.custom_class) publisher = CustomPublisher( device=device, - url=args.url, port=args.port, master_topic=args.master_topic, + url=args.url, + port=args.port, + master_topic=args.master_topic, name=args.name, - **custom_args_dict) + **custom_args_dict, + ) publisher.logger.info("Use custom publisher {}".format(args.custom_class)) # Start sending data diff --git a/scripts/aer_comm/aer_pubsuber b/scripts/aer_comm/aer_pubsuber index 2852aaa..05ea7f6 100755 --- a/scripts/aer_comm/aer_pubsuber +++ b/scripts/aer_comm/aer_pubsuber @@ -9,56 +9,59 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function import argparse import json -from pyaer.utils import expandpath, import_custom_module +from pyaer.utils import expandpath +from pyaer.utils import import_custom_module from pyaer.utils import parse_custom_args + parser = argparse.ArgumentParser() -parser.add_argument("--url", type=str, - default="tcp://127.0.0.1", - help="AER Publisher URL") - -parser.add_argument("--pub_port", type=int, - default=5100, - help="the port that connects this publisher") -parser.add_argument("--pub_topic", type=str, - default="device", - help="publish topic name for the publisher") -parser.add_argument("--pub_name", type=str, - default="", - help="Name of the publisher") - -parser.add_argument("--sub_port", type=int, - default=5099, - help="the port that connects this subscriber") -parser.add_argument("--sub_topic", type=str, - default="", - help="subscriber topic name for the subscriber") -parser.add_argument("--sub_name", type=str, - default="", - help="Name of the subscriber") - -parser.add_argument("--custom_pubsuber", type=expandpath, - default="", - help="path to the custom PubSuber class") -parser.add_argument("--custom_class", type=str, - default="", - help="custom publisher class name") +parser.add_argument( + "--url", type=str, default="tcp://127.0.0.1", help="AER Publisher URL" +) + +parser.add_argument( + "--pub_port", type=int, default=5100, help="the port that connects this publisher" +) +parser.add_argument( + "--pub_topic", + type=str, + default="device", + help="publish topic name for the publisher", +) +parser.add_argument("--pub_name", type=str, default="", help="Name of the publisher") + +parser.add_argument( + "--sub_port", type=int, default=5099, help="the port that connects this subscriber" +) +parser.add_argument( + "--sub_topic", type=str, default="", help="subscriber topic name for the subscriber" +) +parser.add_argument("--sub_name", type=str, default="", help="Name of the subscriber") + +parser.add_argument( + "--custom_pubsuber", + type=expandpath, + default="", + help="path to the custom PubSuber class", +) +parser.add_argument( + "--custom_class", type=str, default="", help="custom publisher class name" +) args, custom_args = parser.parse_known_args() custom_args_dict = parse_custom_args(custom_args) # print all options -print("="*50) -print(json.dumps( - {**args.__dict__, **custom_args_dict}, - indent=4, sort_keys=True)) -print("="*50) +print("=" * 50) +print(json.dumps({**args.__dict__, **custom_args_dict}, indent=4, sort_keys=True)) +print("=" * 50) # define publisher @@ -66,9 +69,14 @@ print("="*50) CustomPubSuber = import_custom_module(args.custom_pubsuber, args.custom_class) pubsuber = CustomPubSuber( url=args.url, - pub_port=args.pub_port, pub_topic=args.pub_topic, pub_name=args.pub_name, - sub_port=args.sub_port, sub_topic=args.sub_topic, sub_name=args.sub_name, - **custom_args_dict) + pub_port=args.pub_port, + pub_topic=args.pub_topic, + pub_name=args.pub_name, + sub_port=args.sub_port, + sub_topic=args.sub_topic, + sub_name=args.sub_name, + **custom_args_dict, +) pubsuber.logger.info("Use custom PubSuber {}".format(args.custom_class)) # Start sending data diff --git a/scripts/aer_comm/aer_saver b/scripts/aer_comm/aer_saver index cb2de02..478040f 100755 --- a/scripts/aer_comm/aer_saver +++ b/scripts/aer_comm/aer_saver @@ -6,14 +6,16 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function -import json import argparse +import json -from pyaer.utils import expandpath +from pyaer.comm import AERHDF5Saver from pyaer.comm import AERSubscriber -from pyaer.comm import AERHDF5Saver, AERZarrSaver +from pyaer.comm import AERZarrSaver +from pyaer.utils import expandpath class AERSaverSubscriber(AERSubscriber): @@ -28,13 +30,11 @@ class AERSaverSubscriber(AERSubscriber): try: data = self.socket.recv_multipart() - topic_name = self.unpack_data_name( - data[:2], topic_name_only=True) + topic_name = self.unpack_data_name(data[:2], topic_name_only=True) # you can select some of these functions to use if "polarity" in topic_name: - data_id, polarity_events = \ - self.unpack_polarity_events(data) + data_id, polarity_events = self.unpack_polarity_events(data) if polarity_events is not None: self.saver.save(data_id, polarity_events) elif "special" in topic_name: @@ -42,8 +42,7 @@ class AERSaverSubscriber(AERSubscriber): if special_events is not None: self.saver.save(data_id, special_events) elif "frame" in topic_name: - data_id, frame_events, frame_ts = \ - self.unpack_frame_events(data) + data_id, frame_events, frame_ts = self.unpack_frame_events(data) if frame_events is not None: self.saver.save(data_id, frame_events) elif "imu" in topic_name: @@ -57,34 +56,27 @@ class AERSaverSubscriber(AERSubscriber): parser = argparse.ArgumentParser() -parser.add_argument("--url", type=str, - default="tcp://127.0.0.1", - help="AER Subscriber URL") -parser.add_argument("--port", type=int, - default=5099, - help="the port that connects this subscriber") -parser.add_argument("--topic", type=str, - default="", - help="Topic to subscribe") -parser.add_argument("--name", type=str, - default="") - -parser.add_argument("--filename", type=expandpath, - default="record.hdf5", - help="Path to save record") -parser.add_argument("--mode", type=str, - default="w-", - help="opening mode") - -parser.add_argument("--hdf5", action="store_true", - help="use HDF5 as saver") -parser.add_argument("--zarr", action="store_true", - help="use Zarr as saver") +parser.add_argument( + "--url", type=str, default="tcp://127.0.0.1", help="AER Subscriber URL" +) +parser.add_argument( + "--port", type=int, default=5099, help="the port that connects this subscriber" +) +parser.add_argument("--topic", type=str, default="", help="Topic to subscribe") +parser.add_argument("--name", type=str, default="") + +parser.add_argument( + "--filename", type=expandpath, default="record.hdf5", help="Path to save record" +) +parser.add_argument("--mode", type=str, default="w-", help="opening mode") + +parser.add_argument("--hdf5", action="store_true", help="use HDF5 as saver") +parser.add_argument("--zarr", action="store_true", help="use Zarr as saver") # HDF5 specific arguments -parser.add_argument("--libver", type=str, - default="latest", - help="HDF5 library version.") +parser.add_argument( + "--libver", type=str, default="latest", help="HDF5 library version." +) # Zarr specific arguments @@ -92,16 +84,14 @@ parser.add_argument("--libver", type=str, args = parser.parse_args() # print all options -print("="*50) +print("=" * 50) print(json.dumps(args.__dict__, indent=4, sort_keys=True)) -print("="*50) +print("=" * 50) if args.hdf5: # use HDF5 as saver - saver = AERHDF5Saver(filename=args.filename, - mode=args.mode, - libver=args.libver) + saver = AERHDF5Saver(filename=args.filename, mode=args.mode, libver=args.libver) elif args.zarr: # use Zarr as saver saver = AERZarrSaver(filename=args.filename, mode=args.mode) @@ -110,8 +100,8 @@ else: raise ValueError("No saver selected, use --hdf5 or --zarr") saver_sub = AERSaverSubscriber( - url=args.url, port=args.port, topic=args.topic, - name=args.name) + url=args.url, port=args.port, topic=args.topic, name=args.name +) # set saver saver_sub.set_saver(saver) diff --git a/scripts/aer_comm/aer_subscriber b/scripts/aer_comm/aer_subscriber index d3af01d..69a758b 100755 --- a/scripts/aer_comm/aer_subscriber +++ b/scripts/aer_comm/aer_subscriber @@ -1,42 +1,44 @@ #!/usr/bin/env python -"""AER Subscriber +"""AER Subscriber. Author: Yuhuang Hu Email : duguyue100@gmail.com """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function -import json import argparse +import json -from pyaer.utils import expandpath, import_custom_module -from pyaer.utils import parse_custom_args from pyaer.comm import AERSubscriber +from pyaer.utils import expandpath +from pyaer.utils import import_custom_module +from pyaer.utils import parse_custom_args + parser = argparse.ArgumentParser() -parser.add_argument("--url", type=str, - default="tcp://127.0.0.1", - help="AER Subscriber URL") -parser.add_argument("--port", type=int, - default=5099, - help="the port that connects this subscriber") -parser.add_argument("--topic", type=str, - default="", - help="Topic to subscribe") -parser.add_argument("--name", type=str, - default="", - help="Name of the subscriber") +parser.add_argument( + "--url", type=str, default="tcp://127.0.0.1", help="AER Subscriber URL" +) +parser.add_argument( + "--port", type=int, default=5099, help="the port that connects this subscriber" +) +parser.add_argument("--topic", type=str, default="", help="Topic to subscribe") +parser.add_argument("--name", type=str, default="", help="Name of the subscriber") parser.add_argument("--use_default_sub", action="store_true") -parser.add_argument("--custom_sub", type=expandpath, - default="", - help="path to the custom publisher class") -parser.add_argument("--custom_class", type=str, - default="", - help="custom publisher class name") +parser.add_argument( + "--custom_sub", + type=expandpath, + default="", + help="path to the custom publisher class", +) +parser.add_argument( + "--custom_class", type=str, default="", help="custom publisher class name" +) args, custom_args = parser.parse_known_args() @@ -44,27 +46,28 @@ args, custom_args = parser.parse_known_args() custom_args_dict = parse_custom_args(custom_args) # print all options -print("="*50) -print(json.dumps( - {**args.__dict__, **custom_args_dict}, - indent=4, sort_keys=True)) -print("="*50) +print("=" * 50) +print(json.dumps({**args.__dict__, **custom_args_dict}, indent=4, sort_keys=True)) +print("=" * 50) # define subscriber if args.use_default_sub: # fall back to the default publisher subscriber = AERSubscriber( - url=args.url, port=args.port, topic=args.topic, - name=args.name) + url=args.url, port=args.port, topic=args.topic, name=args.name + ) subscriber.logger.info("Use default subscriber") else: # use custom publisher CustomSubscriber = import_custom_module(args.custom_sub, args.custom_class) subscriber = CustomSubscriber( - url=args.url, port=args.port, topic=args.topic, name=args.name, - **custom_args_dict) - subscriber.logger.info( - "Use custom subscriber {}".format(args.custom_class)) + url=args.url, + port=args.port, + topic=args.topic, + name=args.name, + **custom_args_dict, + ) + subscriber.logger.info("Use custom subscriber {}".format(args.custom_class)) # Start sending data subscriber.run() diff --git a/scripts/aer_comm/custom_comm.py b/scripts/aer_comm/custom_comm.py index 2c2257f..5f75670 100644 --- a/scripts/aer_comm/custom_comm.py +++ b/scripts/aer_comm/custom_comm.py @@ -4,20 +4,22 @@ Email : yuhuang.hu@ini.uzh.ch """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function import time + import cv2 -from pyaer.comm import AERPublisher, AERSubscriber +from pyaer.comm import AERPublisher +from pyaer.comm import AERSubscriber class CustomPublisher(AERPublisher): - def __init__(self, device, url, port, master_topic, name, **kwargs): super().__init__( - device=device, url=url, port=port, master_topic=master_topic, - **kwargs) + device=device, url=url, port=port, master_topic=master_topic, **kwargs + ) def run_once(self, verbose=False): data = self.device.get_event() @@ -35,7 +37,6 @@ def run_once(self, verbose=False): class CustomSubscriber(AERSubscriber): - def __init__(self, url, port, topic, name, **kwargs): super().__init__(url, port, topic, name, **kwargs) @@ -45,28 +46,23 @@ def __init__(self, url, port, topic, name, **kwargs): def run_once(self, verbose=False): data = self.socket.recv_multipart() - topic_name = self.unpack_data_name( - data[:2], topic_name_only=True) + topic_name = self.unpack_data_name(data[:2], topic_name_only=True) if "frame" in topic_name: - data_id, frame_events, frame_ts = \ - self.unpack_frame_events(data) + data_id, frame_events, frame_ts = self.unpack_frame_events(data) if frame_events is not None: try: - frame = cv2.cvtColor( - frame_events[0], - cv2.COLOR_BGR2RGB) + frame = cv2.cvtColor(frame_events[0], cv2.COLOR_BGR2RGB) frame = cv2.resize(frame, (1384, 1040)) cv2.imshow("frame", frame) - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): return except Exception: pass class DVViewerSubscriber(AERSubscriber): - def __init__(self, url, port, topic, name, **kwargs): super().__init__(url, port, topic, name, **kwargs) @@ -76,21 +72,17 @@ def __init__(self, url, port, topic, name, **kwargs): def run_once(self, verbose=False): data = self.socket.recv_multipart() - topic_name = self.unpack_data_name( - data[:2], topic_name_only=True) + topic_name = self.unpack_data_name(data[:2], topic_name_only=True) if "frame" in topic_name: - data_id, frame_events, frame_ts = \ - self.unpack_frame_events(data) + data_id, frame_events, frame_ts = self.unpack_frame_events(data) if frame_events is not None: try: cv2.imshow( - "frame", - cv2.cvtColor( - frame_events[0], - cv2.COLOR_BGR2RGB)) - if cv2.waitKey(1) & 0xFF == ord('q'): + "frame", cv2.cvtColor(frame_events[0], cv2.COLOR_BGR2RGB) + ) + if cv2.waitKey(1) & 0xFF == ord("q"): return except Exception: pass diff --git a/scripts/aer_comm/test_hdf5_reader.py b/scripts/aer_comm/test_hdf5_reader.py index 8293f2b..b70af04 100644 --- a/scripts/aer_comm/test_hdf5_reader.py +++ b/scripts/aer_comm/test_hdf5_reader.py @@ -4,27 +4,27 @@ Email : yuhuang.hu@ini.uzh.ch """ -from __future__ import print_function, absolute_import +from __future__ import absolute_import +from __future__ import print_function import os from contextlib import suppress + from pyaer.comm import AERHDF5Reader -data_path = os.path.join( - os.environ["HOME"], "data", "pyaer_test.hdf5") +data_path = os.path.join(os.environ["HOME"], "data", "pyaer_test.hdf5") reader = AERHDF5Reader(data_path) for device, groups in reader.get_keys().items(): for group_name in groups: - frame = reader.get_frame(device, group_name) events = reader.get_polarity_events(device, group_name) imu = reader.get_imu_events(device, group_name) special = reader.get_special_events(device, group_name) - print("-"*50) + print("-" * 50) with suppress(Exception): print("Frame:", frame.shape) diff --git a/scripts/davis240_test.py b/scripts/davis240_test.py index 7c88ea0..6250919 100644 --- a/scripts/davis240_test.py +++ b/scripts/davis240_test.py @@ -3,30 +3,31 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function -import numpy as np import cv2 +import numpy as np from pyaer import libcaer from pyaer.davis import DAVIS + device = DAVIS(noise_filter=True) -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) -print ("Background Activity Filter:", - device.dvs_has_background_activity_filter) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) +print("Background Activity Filter:", device.dvs_has_background_activity_filter) device.start_data_stream() @@ -49,27 +50,38 @@ def get_event(device): try: data = get_event(device) if data is not None: - (pol_events, num_pol_event, - special_events, num_special_event, - frames_ts, frames, imu_events, - num_imu_event) = data + ( + pol_events, + num_pol_event, + special_events, + num_special_event, + frames_ts, + frames, + imu_events, + num_imu_event, + ) = data if frames.shape[0] != 0: cv2.imshow("frame", frames[0]) - print ("Number of events:", num_pol_event, "Number of Frames:", - frames.shape, "Exposure:", - device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_EXPOSURE)) + print( + "Number of events:", + num_pol_event, + "Number of Frames:", + frames.shape, + "Exposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_EXPOSURE + ), + ) if num_pol_event != 0: - img = pol_events[..., 1]-pol_events[..., 0] + img = pol_events[..., 1] - pol_events[..., 0] img = np.clip(img, -clip_value, clip_value) - img = img+clip_value + img = img + clip_value - cv2.imshow("image", img/float(clip_value*2)) + cv2.imshow("image", img / float(clip_value * 2)) - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): break else: diff --git a/scripts/davis346_color_events.py b/scripts/davis346_color_events.py index 06b3406..2c49118 100644 --- a/scripts/davis346_color_events.py +++ b/scripts/davis346_color_events.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function import cv2 @@ -11,6 +12,7 @@ from pyaer import libcaer from pyaer.davis import DAVIS + device = DAVIS(noise_filter=False, color_filter=True) print("Device ID:", device.device_id) @@ -25,8 +27,7 @@ print("Device size X:", device.dvs_size_X) print("Device size Y:", device.dvs_size_Y) print("Logic Version:", device.logic_version) -print("Background Activity Filter:", - device.dvs_has_background_activity_filter) +print("Background Activity Filter:", device.dvs_has_background_activity_filter) print("Color Filter", device.aps_color_filter, type(device.aps_color_filter)) print(device.aps_color_filter == 1) @@ -51,52 +52,77 @@ def get_event(device): try: data = get_event(device) if data is not None: - (pol_events, num_pol_event, - special_events, num_special_event, - frames_ts, frames, imu_events, - num_imu_event) = data + ( + pol_events, + num_pol_event, + special_events, + num_special_event, + frames_ts, + frames, + imu_events, + num_imu_event, + ) = data if frames.shape[0] != 0: frame = cv2.cvtColor(frames[0], cv2.COLOR_BGR2RGB) - frame = cv2.resize(frame, dsize=(692, 520), - interpolation=cv2.INTER_LINEAR) + frame = cv2.resize( + frame, dsize=(692, 520), interpolation=cv2.INTER_LINEAR + ) cv2.imshow("frame", frame) if pol_events is not None: - print("Number of events:", pol_events.shape, - "Number of Frames:", - frames.shape, "Exposure:", - device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_EXPOSURE), - "Autoexposure:", device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE), - "Color:", pol_events[0, 4]) + print( + "Number of events:", + pol_events.shape, + "Number of Frames:", + frames.shape, + "Exposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_EXPOSURE + ), + "Autoexposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE + ), + "Color:", + pol_events[0, 4], + ) if num_pol_event != 0: # extract color events - pol_g_1 = (pol_events[:, 4] == 1) # lower left green - pol_b = (pol_events[:, 4] == 2) # lower right blue - pol_r = (pol_events[:, 4] == 3) # upper left red - pol_g_2 = (pol_events[:, 4] == 4) # upper right green + pol_g_1 = pol_events[:, 4] == 1 # lower left green + pol_b = pol_events[:, 4] == 2 # lower right blue + pol_r = pol_events[:, 4] == 3 # upper left red + pol_g_2 = pol_events[:, 4] == 4 # upper right green g_1, _, _ = np.histogram2d( - pol_events[pol_g_1, 2], pol_events[pol_g_1, 1], - bins=(260, 346), range=histrange) + pol_events[pol_g_1, 2], + pol_events[pol_g_1, 1], + bins=(260, 346), + range=histrange, + ) b, _, _ = np.histogram2d( - pol_events[pol_b, 2], pol_events[pol_b, 1], - bins=(260, 346), range=histrange) + pol_events[pol_b, 2], + pol_events[pol_b, 1], + bins=(260, 346), + range=histrange, + ) r, _, _ = np.histogram2d( - pol_events[pol_r, 2], pol_events[pol_r, 1], - bins=(260, 346), range=histrange) + pol_events[pol_r, 2], + pol_events[pol_r, 1], + bins=(260, 346), + range=histrange, + ) g_2, _, _ = np.histogram2d( - pol_events[pol_g_2, 2], pol_events[pol_g_2, 1], - bins=(260, 346), range=histrange) + pol_events[pol_g_2, 2], + pol_events[pol_g_2, 1], + bins=(260, 346), + range=histrange, + ) - g_1 = np.clip(g_1, None, clip_value)/float(clip_value) - b = np.clip(b, None, clip_value)/float(clip_value) - r = np.clip(r, None, clip_value)/float(clip_value) - g_2 = np.clip(g_2, None, clip_value)/float(clip_value) + g_1 = np.clip(g_1, None, clip_value) / float(clip_value) + b = np.clip(b, None, clip_value) / float(clip_value) + r = np.clip(r, None, clip_value) / float(clip_value) + g_2 = np.clip(g_2, None, clip_value) / float(clip_value) ig_1 = np.zeros((260, 346, 3), dtype=np.float) ib = np.zeros((260, 346, 3), dtype=np.float) @@ -113,13 +139,11 @@ def get_event(device): ir[..., 2] = r ig_2[..., 1] = g_2 - img = np.vstack(( - np.hstack((ir, ig_2)), - np.hstack((ig_1, ib)))) + img = np.vstack((np.hstack((ir, ig_2)), np.hstack((ig_1, ib)))) cv2.imshow("image", img) - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): break else: pass diff --git a/scripts/davis346_color_test.py b/scripts/davis346_color_test.py index c6defdc..2008e50 100644 --- a/scripts/davis346_color_test.py +++ b/scripts/davis346_color_test.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function import cv2 @@ -11,6 +12,7 @@ from pyaer import libcaer from pyaer.davis import DAVIS + device = DAVIS(noise_filter=True, color_filter=True) print("Device ID:", device.device_id) @@ -25,8 +27,7 @@ print("Device size X:", device.dvs_size_X) print("Device size Y:", device.dvs_size_Y) print("Logic Version:", device.logic_version) -print("Background Activity Filter:", - device.dvs_has_background_activity_filter) +print("Background Activity Filter:", device.dvs_has_background_activity_filter) print("Color Filter", device.aps_color_filter, type(device.aps_color_filter)) print(device.aps_color_filter == 1) @@ -50,25 +51,37 @@ def get_event(device): try: data = get_event(device) if data is not None: - (pol_events, num_pol_event, - special_events, num_special_event, - frames_ts, frames, imu_events, - num_imu_event) = data + ( + pol_events, + num_pol_event, + special_events, + num_special_event, + frames_ts, + frames, + imu_events, + num_imu_event, + ) = data if frames.shape[0] != 0: frame = cv2.cvtColor(frames[0], cv2.COLOR_BGR2RGB) cv2.imshow("frame", frame) if pol_events is not None: - print("Number of events:", pol_events.shape, - "Number of Frames:", - frames.shape, "Exposure:", - device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_EXPOSURE), - "Autoexposure:", device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE), - "Color:", pol_events[0, 5]) + print( + "Number of events:", + pol_events.shape, + "Number of Frames:", + frames.shape, + "Exposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_EXPOSURE + ), + "Autoexposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE + ), + "Color:", + pol_events[0, 5], + ) if num_pol_event != 0: if num_packet_before_disable > 0: @@ -78,24 +91,31 @@ def get_event(device): else: device.disable_noise_filter() print("Noise filter disabled") - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 2], pol_events[pol_on, 1], - bins=(260, 346), range=histrange) + pol_events[pol_on, 2], + pol_events[pol_on, 1], + bins=(260, 346), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 2], pol_events[pol_off, 1], - bins=(260, 346), range=histrange) + pol_events[pol_off, 2], + pol_events[pol_off, 1], + bins=(260, 346), + range=histrange, + ) if clip_value is not None: integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + (img_on - img_off), -clip_value, clip_value + ) else: - integrated_img = (img_on-img_off) - img = integrated_img+clip_value + integrated_img = img_on - img_off + img = integrated_img + clip_value - cv2.imshow("image", img/float(clip_value*2)) + cv2.imshow("image", img / float(clip_value * 2)) - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): break else: pass diff --git a/scripts/davis346_test.py b/scripts/davis346_test.py index 956218b..31890f2 100644 --- a/scripts/davis346_test.py +++ b/scripts/davis346_test.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function import cv2 @@ -11,22 +12,22 @@ from pyaer import libcaer from pyaer.davis import DAVIS + device = DAVIS(noise_filter=True) -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) -print ("Background Activity Filter:", - device.dvs_has_background_activity_filter) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) +print("Background Activity Filter:", device.dvs_has_background_activity_filter) device.start_data_stream() # setting bias after data stream started @@ -48,21 +49,33 @@ def get_event(device): try: data = get_event(device) if data is not None: - (pol_events, num_pol_event, - special_events, num_special_event, - frames_ts, frames, imu_events, - num_imu_event) = data + ( + pol_events, + num_pol_event, + special_events, + num_special_event, + frames_ts, + frames, + imu_events, + num_imu_event, + ) = data if frames.shape[0] != 0: cv2.imshow("frame", frames[0]) - print("Number of events:", num_pol_event, "Number of Frames:", - frames.shape, "Exposure:", - device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_EXPOSURE), - "Autoexposure:", device.get_config( - libcaer.DAVIS_CONFIG_APS, - libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE)) + print( + "Number of events:", + num_pol_event, + "Number of Frames:", + frames.shape, + "Exposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_EXPOSURE + ), + "Autoexposure:", + device.get_config( + libcaer.DAVIS_CONFIG_APS, libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE + ), + ) if num_pol_event != 0: if num_packet_before_disable > 0: @@ -72,24 +85,31 @@ def get_event(device): else: device.disable_noise_filter() print("Noise filter disabled") - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 2], pol_events[pol_on, 1], - bins=(260, 346), range=histrange) + pol_events[pol_on, 2], + pol_events[pol_on, 1], + bins=(260, 346), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 2], pol_events[pol_off, 1], - bins=(260, 346), range=histrange) + pol_events[pol_off, 2], + pol_events[pol_off, 1], + bins=(260, 346), + range=histrange, + ) if clip_value is not None: integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + (img_on - img_off), -clip_value, clip_value + ) else: - integrated_img = (img_on-img_off) - img = integrated_img+clip_value + integrated_img = img_on - img_off + img = integrated_img + clip_value - cv2.imshow("image", img/float(clip_value*2)) + cv2.imshow("image", img / float(clip_value * 2)) - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): break else: pass diff --git a/scripts/dvs128_glumpy.py b/scripts/dvs128_glumpy.py index 41b09b1..317c973 100644 --- a/scripts/dvs128_glumpy.py +++ b/scripts/dvs128_glumpy.py @@ -3,30 +3,33 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function import threading import numpy as np -from glumpy import app, gloo, gl +from glumpy import app +from glumpy import gl +from glumpy import gloo from pyaer.dvs128 import DVS128 device = DVS128() -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) data_stream = False @@ -57,15 +60,14 @@ window = app.Window(width=1024, height=1024, aspect=1) -img_array = (np.random.uniform( - 0, 1, (128, 128, 3))*250).astype(np.uint8) +img_array = (np.random.uniform(0, 1, (128, 128, 3)) * 250).astype(np.uint8) @window.event def on_close(): global device - print ("Shutting down the device") + print("Shutting down the device") device.shutdown() del device @@ -82,31 +84,34 @@ def on_draw(dt): data_stream = True lock.acquire() - (pol_events, num_pol_event, - special_events, num_special_event) = \ - device.get_event() + (pol_events, num_pol_event, special_events, num_special_event) = device.get_event() if num_pol_event != 0: - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 2], pol_events[pol_on, 1], - bins=(128, 128), range=histrange) + pol_events[pol_on, 2], + pol_events[pol_on, 1], + bins=(128, 128), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 2], pol_events[pol_off, 1], - bins=(128, 128), range=histrange) + pol_events[pol_off, 2], + pol_events[pol_off, 1], + bins=(128, 128), + range=histrange, + ) if clip_value is not None: - integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + integrated_img = np.clip((img_on - img_off), -clip_value, clip_value) else: - integrated_img = (img_on-img_off) + integrated_img = img_on - img_off - img_array = ((integrated_img+clip_value)/float( - clip_value*2)*255).astype(np.uint8) + img_array = ( + (integrated_img + clip_value) / float(clip_value * 2) * 255 + ).astype(np.uint8) img_array = img_array[..., np.newaxis].repeat(3, axis=2) else: - img_array = (np.random.uniform( - 0, 1, (128, 128, 3))*250).astype(np.uint8) + img_array = (np.random.uniform(0, 1, (128, 128, 3)) * 250).astype(np.uint8) quad["texture"] = img_array quad.draw(gl.GL_TRIANGLE_STRIP) @@ -114,7 +119,7 @@ def on_draw(dt): quad = gloo.Program(vertex, fragment, count=4) -quad['position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)] -quad['texcoord'] = [(0, 1), (0, 0), (1, 1), (1, 0)] -quad['texture'] = img_array +quad["position"] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)] +quad["texcoord"] = [(0, 1), (0, 0), (1, 1), (1, 0)] +quad["texture"] = img_array app.run(framerate=150) diff --git a/scripts/dvs128_test.py b/scripts/dvs128_test.py index e2044aa..e1b94a6 100644 --- a/scripts/dvs128_test.py +++ b/scripts/dvs128_test.py @@ -3,51 +3,57 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function -import numpy as np import cv2 +import numpy as np from pyaer.dvs128 import DVS128 + device = DVS128() -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) device.start_data_stream() # load new config device.set_bias_from_json("./scripts/configs/dvs128_config.json") -print (device.get_bias()) +print(device.get_bias()) clip_value = 3 histrange = [(0, v) for v in (128, 128)] while True: try: - (pol_events, num_pol_event, - special_events, num_special_event) = \ + (pol_events, num_pol_event, special_events, num_special_event) = ( device.get_event("events_hist") + ) if num_pol_event != 0: - img = pol_events[..., 1]-pol_events[..., 0] + img = pol_events[..., 1] - pol_events[..., 0] img = np.clip(img, -clip_value, clip_value) - img = img+clip_value + img = img + clip_value - cv2.imshow("image", img/float(clip_value*2)) - print ("Number of events:", num_pol_event, "Number of special events:", - num_special_event) + cv2.imshow("image", img / float(clip_value * 2)) + print( + "Number of events:", + num_pol_event, + "Number of special events:", + num_special_event, + ) - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): break except KeyboardInterrupt: diff --git a/scripts/dvs128_thread_test.py b/scripts/dvs128_thread_test.py index 0c37644..4853c18 100644 --- a/scripts/dvs128_thread_test.py +++ b/scripts/dvs128_thread_test.py @@ -3,33 +3,36 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function -from queue import Queue import threading -import numpy as np +from queue import Queue + import cv2 +import numpy as np from pyaer.dvs128 import DVS128 + device = DVS128() -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) # load new config device.set_bias_from_json("./scripts/configs/dvs128_config.json") -print (device.get_bias()) +print(device.get_bias()) device.start_data_stream() @@ -41,24 +44,30 @@ def drawing_func(in_q): while threading.currentThread().isAlive(): try: - (pol_events, num_pol_event, - special_events, num_special_event) = in_q.get() + (pol_events, num_pol_event, special_events, num_special_event) = in_q.get() if num_pol_event != 0: - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 2], pol_events[pol_on, 1], - bins=(128, 128), range=histrange) + pol_events[pol_on, 2], + pol_events[pol_on, 1], + bins=(128, 128), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 1], pol_events[pol_off, 0], - bins=(128, 128), range=histrange) + pol_events[pol_off, 1], + pol_events[pol_off, 0], + bins=(128, 128), + range=histrange, + ) if clip_value is not None: integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + (img_on - img_off), -clip_value, clip_value + ) else: - integrated_img = (img_on-img_off) - img = integrated_img+clip_value - cv2.imshow("image", img/float(clip_value*2)) + integrated_img = img_on - img_off + img = integrated_img + clip_value + cv2.imshow("image", img / float(clip_value * 2)) cv2.waitKey(1) except KeyboardInterrupt: device.shutdown() @@ -69,9 +78,12 @@ def fetching_func(out_q): while threading.currentThread().isAlive(): try: event_packet = device.get_event() - print ("Number of events:", event_packet[1], - "Number of special events:", - event_packet[3]) + print( + "Number of events:", + event_packet[1], + "Number of special events:", + event_packet[3], + ) out_q.put(event_packet) except KeyboardInterrupt: device.shutdown() @@ -81,12 +93,10 @@ def fetching_func(out_q): if __name__ == "__main__": # define thread q = Queue(maxsize=1) - drawer = threading.Thread( - name="drawer", target=drawing_func, args=(q, )) - fetcher = threading.Thread( - name="fetcher", target=fetching_func, args=(q, )) + drawer = threading.Thread(name="drawer", target=drawing_func, args=(q,)) + fetcher = threading.Thread(name="fetcher", target=fetching_func, args=(q,)) fetcher.start() - print ("fetcher started") + print("fetcher started") drawer.start() - print ("drawer started") + print("drawer started") diff --git a/scripts/dvs128_vispy.py b/scripts/dvs128_vispy.py index b11f845..618e671 100644 --- a/scripts/dvs128_vispy.py +++ b/scripts/dvs128_vispy.py @@ -3,11 +3,13 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function import numpy as np import vispy -from vispy import app, scene, visuals, gloo +from vispy import app +from vispy import gloo from vispy.util.transforms import ortho from pyaer.dvs128 import DVS128 @@ -15,22 +17,22 @@ device = DVS128() -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) # load new config device.set_bias_from_json("./scripts/configs/dvs128_config.json") -print (device.get_bias()) +print(device.get_bias()) device.start_data_stream() @@ -42,10 +44,9 @@ W, H = 128, 128 img_array = np.random.uniform(0, 1, (W, H)).astype(np.float32) -data = np.zeros(4, dtype=[('a_position', np.float32, 2), - ('a_texcoord', np.float32, 2)]) -data['a_position'] = np.array([[0, 0], [W, 0], [0, H], [W, H]]) -data['a_texcoord'] = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) +data = np.zeros(4, dtype=[("a_position", np.float32, 2), ("a_texcoord", np.float32, 2)]) +data["a_position"] = np.array([[0, 0], [W, 0], [0, H], [W, H]]) +data["a_texcoord"] = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) VERT_SHADER = """ // Uniforms @@ -79,66 +80,70 @@ class Canvas(vispy.app.Canvas): def __init__(self): - vispy.app.Canvas.__init__(self, keys='interactive', size=(300, 300)) + vispy.app.Canvas.__init__(self, keys="interactive", size=(300, 300)) self.program = gloo.Program(VERT_SHADER, FRAG_SHADER) - self.texture = gloo.Texture2D( - img_array, interpolation="linear") + self.texture = gloo.Texture2D(img_array, interpolation="linear") - self.program['u_texture'] = self.texture + self.program["u_texture"] = self.texture self.program.bind(gloo.VertexBuffer(data)) self.view = np.eye(4, dtype=np.float32) self.model = np.eye(4, dtype=np.float32) self.projection = np.eye(4, dtype=np.float32) - self.program['u_model'] = self.model - self.program['u_view'] = self.view + self.program["u_model"] = self.model + self.program["u_view"] = self.view self.projection = ortho(0, W, 0, H, -1, 1) - self.program['u_projection'] = self.projection + self.program["u_projection"] = self.projection - gloo.set_clear_color('white') + gloo.set_clear_color("white") - self._timer = app.Timer('auto', connect=self.update, start=True) + self._timer = app.Timer("auto", connect=self.update, start=True) self.show() # @profile def on_draw(self, ev): gloo.clear(color=True, depth=True) - (pol_events, num_pol_event, - special_events, num_special_event) = \ + (pol_events, num_pol_event, special_events, num_special_event) = ( device.get_event() + ) if num_pol_event != 0: - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 1], 127-pol_events[pol_on, 2], - bins=(128, 128), range=histrange) + pol_events[pol_on, 1], + 127 - pol_events[pol_on, 2], + bins=(128, 128), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 1], 127-pol_events[pol_off, 2], - bins=(128, 128), range=histrange) + pol_events[pol_off, 1], + 127 - pol_events[pol_off, 2], + bins=(128, 128), + range=histrange, + ) if clip_value is not None: - integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + integrated_img = np.clip((img_on - img_off), -clip_value, clip_value) else: - integrated_img = (img_on-img_off) + integrated_img = img_on - img_off - img_array = ((integrated_img+clip_value)/float( - clip_value*2)).astype(np.float32) + img_array = ((integrated_img + clip_value) / float(clip_value * 2)).astype( + np.float32 + ) else: - img_array[...] = np.zeros( - (128, 128), dtype=np.uint8).astype(np.float32) + img_array[...] = np.zeros((128, 128), dtype=np.uint8).astype(np.float32) self.texture.set_data(img_array) - self.program.draw('triangle_strip') + self.program.draw("triangle_strip") # @profile def on_resize(self, event): width, height = event.physical_size gloo.set_viewport(0, 0, width, height) self.projection = ortho(0, width, 0, height, -100, 100) - self.program['u_projection'] = self.projection + self.program["u_projection"] = self.projection # Compute thje new size of the quad r = width / float(height) @@ -149,13 +154,13 @@ def on_resize(self, event): else: w, h = height * R, height x, y = int((width - w) / 2), 0 - data['a_position'] = np.array( - [[x, y], [x + w, y], [x, y + h], [x + w, y + h]]) + data["a_position"] = np.array([[x, y], [x + w, y], [x, y + h], [x + w, y + h]]) self.program.bind(gloo.VertexBuffer(data)) + # @profile def run(): - win = Canvas() + win = Canvas() # noqa app.run() diff --git a/scripts/dvs_noise_filter_test.py b/scripts/dvs_noise_filter_test.py index 0d0acfe..11996cd 100644 --- a/scripts/dvs_noise_filter_test.py +++ b/scripts/dvs_noise_filter_test.py @@ -3,32 +3,35 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ -from __future__ import print_function, absolute_import + +from __future__ import absolute_import +from __future__ import print_function import cv2 import numpy as np from pyaer.dvs128 import DVS128 + device = DVS128(noise_filter=True) -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) -print ("Logic Version:", device.logic_version) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) +print("Logic Version:", device.logic_version) device.start_data_stream() # load new config device.set_bias_from_json("./scripts/configs/dvs128_config.json") -print (device.get_bias()) +print(device.get_bias()) clip_value = 1 histrange = [(0, v) for v in (128, 128)] @@ -39,38 +42,45 @@ def get_event(device): global num_packet_before_disable - (pol_events, num_pol_event, - special_events, num_special_event) = \ - device.get_event() + (pol_events, num_pol_event, special_events, num_special_event) = device.get_event() if num_pol_event != 0: if num_packet_before_disable > 0: pol_events = pol_events[pol_events[:, 4] == 1] num_packet_before_disable -= 1 else: device.disable_noise_filter() - print ("Noise filter disabled") + print("Noise filter disabled") - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 2], pol_events[pol_on, 1], - bins=(128, 128), range=histrange) + pol_events[pol_on, 2], + pol_events[pol_on, 1], + bins=(128, 128), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 2], pol_events[pol_off, 1], - bins=(128, 128), range=histrange) + pol_events[pol_off, 2], + pol_events[pol_off, 1], + bins=(128, 128), + range=histrange, + ) if clip_value is not None: - integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + integrated_img = np.clip((img_on - img_off), -clip_value, clip_value) else: - integrated_img = (img_on-img_off) - img = integrated_img+clip_value - - cv2.imshow("image", img/float(clip_value*2)) - print ("Number of events:", num_pol_event, "Number of special events:", - num_special_event) + integrated_img = img_on - img_off + img = integrated_img + clip_value + + cv2.imshow("image", img / float(clip_value * 2)) + print( + "Number of events:", + num_pol_event, + "Number of special events:", + num_special_event, + ) del pol_events, num_pol_event, special_events, num_special_event - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): return @@ -80,7 +90,7 @@ def get_event(device): except KeyboardInterrupt: hot_pixels = device.noise_filter.get_hot_pixels() - print (hot_pixels) - print (device.noise_filter.get_bias()) + print(hot_pixels) + print(device.noise_filter.get_bias()) device.shutdown() break diff --git a/scripts/dvxplorer_test.py b/scripts/dvxplorer_test.py index bc61df7..cc81552 100644 --- a/scripts/dvxplorer_test.py +++ b/scripts/dvxplorer_test.py @@ -3,13 +3,16 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ -from __future__ import print_function, absolute_import -import numpy as np +from __future__ import absolute_import +from __future__ import print_function + import cv2 +import numpy as np from pyaer.dvxplorer import DVXPLORER + device = DVXPLORER() print("Device ID:", device.device_id) @@ -42,17 +45,21 @@ while True: try: - (pol_events, num_pol_event, - special_events, num_special_event, - imu_events, num_imu_event) = \ - device.get_event("events_hist") + ( + pol_events, + num_pol_event, + special_events, + num_special_event, + imu_events, + num_imu_event, + ) = device.get_event("events_hist") print("Number of events:", num_pol_event) if num_pol_event != 0: - img = pol_events[..., 1]-pol_events[..., 0] + img = pol_events[..., 1] - pol_events[..., 0] img = np.clip(img, -clip_value, clip_value) - img = (img+clip_value)/float(clip_value*2) + img = (img + clip_value) / float(clip_value * 2) cv2.imshow("image", img) diff --git a/scripts/dynapse_test.py b/scripts/dynapse_test.py index 9ae8f81..27a390f 100644 --- a/scripts/dynapse_test.py +++ b/scripts/dynapse_test.py @@ -3,27 +3,29 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function -from pyaer.dynapse import DYNAPSE from pyaer import utils +from pyaer.dynapse import DYNAPSE + device = DYNAPSE() -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device Serial Number:", device.device_serial_number) -print ("Device String:", device.device_string) -print ("Device USB bus Number:", device.device_usb_bus_number) -print ("Device USB device address:", device.device_usb_device_address) -print ("Logic Version:", device.logic_version) -print ("Logic Clock:", device.logic_clock) -print ("Chip ID:", device.chip_id) -print ("AER has statistics:", device.aer_has_statistics) -print ("MUX has statistics:", device.mux_has_statistics) + print("Device is slave.") +print("Device Serial Number:", device.device_serial_number) +print("Device String:", device.device_string) +print("Device USB bus Number:", device.device_usb_bus_number) +print("Device USB device address:", device.device_usb_device_address) +print("Logic Version:", device.logic_version) +print("Logic Clock:", device.logic_clock) +print("Chip ID:", device.chip_id) +print("AER has statistics:", device.aer_has_statistics) +print("MUX has statistics:", device.mux_has_statistics) device.start_data_stream() @@ -32,13 +34,17 @@ # set bias from json file scope = { 0: [0, 1, 2, 3], - } - -device.set_bias_from_json("./scripts/configs/dynapse_config.json", - clear_sram=False, setup_sram=False, - fpga_bias=True, scope=scope) +} + +device.set_bias_from_json( + "./scripts/configs/dynapse_config.json", + clear_sram=False, + setup_sram=False, + fpga_bias=True, + scope=scope, +) # print FPGA biases -print (device.get_fpga_bias()) +print(device.get_fpga_bias()) # set biases for a single chip device.set_chip_bias(bias_obj, chip_id=1) @@ -48,9 +54,8 @@ events = device.get_event() if events is not None: - print ("Number of events from DYNAPSE : %d" % - (events[1])) + print("Number of events from DYNAPSE : %d" % (events[1])) except KeyboardInterrupt: - print ("Device shutting down...") + print("Device shutting down...") device.shutdown() break diff --git a/scripts/edvs_test.py b/scripts/edvs_test.py index 3ca2ab7..cef8fc1 100644 --- a/scripts/edvs_test.py +++ b/scripts/edvs_test.py @@ -3,28 +3,30 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function -import numpy as np import cv2 +import numpy as np from pyaer.edvs import eDVS + device = eDVS() -print ("Device ID:", device.device_id) +print("Device ID:", device.device_id) if device.device_is_master: - print ("Device is master.") + print("Device is master.") else: - print ("Device is slave.") -print ("Device String:", device.device_string) -print ("Device size X:", device.dvs_size_X) -print ("Device size Y:", device.dvs_size_Y) + print("Device is slave.") +print("Device String:", device.device_string) +print("Device size X:", device.dvs_size_X) +print("Device size Y:", device.dvs_size_Y) device.start_data_stream() # load new config device.set_bias_from_json("./scripts/configs/edvs_config.json") -print (device.get_bias()) +print(device.get_bias()) device.close() @@ -34,31 +36,38 @@ # @profile def get_event(device): - (pol_events, num_pol_event, - special_events, num_special_event) = \ - device.get_event() + (pol_events, num_pol_event, special_events, num_special_event) = device.get_event() if num_pol_event != 0: - pol_on = (pol_events[:, 3] == 1) + pol_on = pol_events[:, 3] == 1 pol_off = np.logical_not(pol_on) img_on, _, _ = np.histogram2d( - pol_events[pol_on, 2], pol_events[pol_on, 1], - bins=(128, 128), range=histrange) + pol_events[pol_on, 2], + pol_events[pol_on, 1], + bins=(128, 128), + range=histrange, + ) img_off, _, _ = np.histogram2d( - pol_events[pol_off, 2], pol_events[pol_off, 1], - bins=(128, 128), range=histrange) + pol_events[pol_off, 2], + pol_events[pol_off, 1], + bins=(128, 128), + range=histrange, + ) if clip_value is not None: - integrated_img = np.clip( - (img_on-img_off), -clip_value, clip_value) + integrated_img = np.clip((img_on - img_off), -clip_value, clip_value) else: - integrated_img = (img_on-img_off) - img = integrated_img+clip_value + integrated_img = img_on - img_off + img = integrated_img + clip_value - cv2.imshow("image", img/float(clip_value*2)) - print ("Number of events:", num_pol_event, "Number of special events:", - num_special_event) + cv2.imshow("image", img / float(clip_value * 2)) + print( + "Number of events:", + num_pol_event, + "Number of special events:", + num_special_event, + ) del pol_events, num_pol_event, special_events, num_special_event - if cv2.waitKey(1) & 0xFF == ord('q'): + if cv2.waitKey(1) & 0xFF == ord("q"): return diff --git a/scripts/event_container_test.py b/scripts/event_container_test.py index 5026770..16d1cc5 100644 --- a/scripts/event_container_test.py +++ b/scripts/event_container_test.py @@ -3,15 +3,13 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import print_function -import cv2 -import numpy as np +from timer import Timer -from pyaer import libcaer from pyaer.davis import DAVIS -from timer import Timer device = DAVIS(noise_filter=True) @@ -27,8 +25,7 @@ print("Device size X:", device.dvs_size_X) print("Device size Y:", device.dvs_size_Y) print("Logic Version:", device.logic_version) -print("Background Activity Filter:", - device.dvs_has_background_activity_filter) +print("Background Activity Filter:", device.dvs_has_background_activity_filter) print("Color Filter", device.aps_color_filter, type(device.aps_color_filter)) print(device.aps_color_filter == 1) @@ -54,15 +51,19 @@ def get_event(device): event_container = device.get_event_container() if event_container is not None: - print("Duration (s): {}, Num Events: {}, Event Rate (ev/s): {}" - .format( + print( + "Duration (s): {}, Num Events: {}, Event Rate (ev/s): {}".format( event_container.pol_event_duration, event_container.num_pol_events, - event_container.pol_event_rate)) - print("Signal Rate (ev/s): {}, Noise Rate (ev/s): {}" - .format( + event_container.pol_event_rate, + ) + ) + print( + "Signal Rate (ev/s): {}, Noise Rate (ev/s): {}".format( event_container.valid_pol_events_rate, - event_container.invalid_pol_events_rate)) + event_container.invalid_pol_events_rate, + ) + ) # print("Number of events:", num_pol_event, "Number of Frames:", # frames.shape, "Exposure:", diff --git a/scripts/timer.py b/scripts/timer.py index d6a65c2..5dacd9a 100644 --- a/scripts/timer.py +++ b/scripts/timer.py @@ -1,30 +1,33 @@ +import atexit import logging import time -import numpy as np + import matplotlib.pyplot as plt +import numpy as np from engineering_notation import EngNumber as eng # only from pip -import atexit LOGGING_LEVEL = logging.INFO class CustomFormatter(logging.Formatter): - """Logging Formatter to add colors and count warning / errors""" + """Logging Formatter to add colors and count warning / errors.""" grey = "\x1b[38;21m" yellow = "\x1b[33;21m" red = "\x1b[31;21m" bold_red = "\x1b[31;1m" reset = "\x1b[0m" - format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" + format = ( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" + ) FORMATS = { logging.DEBUG: grey + format + reset, logging.INFO: grey + format + reset, logging.WARNING: yellow + format + reset, logging.ERROR: red + format + reset, - logging.CRITICAL: bold_red + format + reset + logging.CRITICAL: bold_red + format + reset, } def format(self, record): @@ -51,11 +54,12 @@ def my_logger(name): class Timer: - def __init__(self, timer_name='', delay=None, - show_hist=False, numpy_file=None): - """ Make a Timer() in a _with_ statement for a block of code. - The timer is started when the block is entered and stopped when exited. - The Timer _must_ be used in a with statement. + def __init__(self, timer_name="", delay=None, show_hist=False, numpy_file=None): + """Make a Timer() in a _with_ statement for a block of code. + + The timer is started when the block is entered and stopped when exited. The Timer _must_ be + used in a with statement. + :param timer_name: the str by which this timer is repeatedly called and which it is named when summary is printed on exit :param delay: set this to a value to simply accumulate @@ -87,23 +91,31 @@ def __exit__(self, *args): times[self.timer_name].append(self.interval) def print_timing_info(self, logger=None): - """ Prints the timing information accumulated for this Timer + """Prints the timing information accumulated for this Timer. + :param logger: write to the supplied logger, otherwise use the built-in logger """ if len(times) == 0: - log.error(f'Timer {self.timer_name} has no statistics; was it used without a "with" statement?') + log.error( + f'Timer {self.timer_name} has no statistics; was it used without a "with" statement?' + ) return a = np.array(times[self.timer_name]) - timing_mean = np.mean(a) # todo use built in print method for timer + timing_mean = np.mean(a) # todo use built in print method for timer timing_std = np.std(a) timing_median = np.median(a) timing_min = np.min(a) timing_max = np.max(a) - s='{} n={}: {}s +/- {}s (median {}s, min {}s max {}s)'.format(self.timer_name, len(a), - eng(timing_mean), eng(timing_std), - eng(timing_median), eng(timing_min), - eng(timing_max)) + s = "{} n={}: {}s +/- {}s (median {}s, min {}s max {}s)".format( + self.timer_name, + len(a), + eng(timing_mean), + eng(timing_std), + eng(timing_median), + eng(timing_min), + eng(timing_max), + ) if logger is not None: logger.info(s) @@ -119,39 +131,54 @@ def print_timing_info(): timing_median = np.median(a) timing_min = np.min(a) timing_max = np.max(a) - log.info('== Timing statistics from all Timer ==\n{} n={}: {}s +/- {}s (median {}s, min {}s max {}s)'.format(k, len(a), - eng(timing_mean), eng(timing_std), - eng(timing_median), eng(timing_min), - eng(timing_max))) + log.info( + "== Timing statistics from all Timer ==\n{} n={}: {}s +/- {}s (median {}s, min {}s max {}s)".format( + k, + len(a), + eng(timing_mean), + eng(timing_std), + eng(timing_median), + eng(timing_min), + eng(timing_max), + ) + ) if timers[k].numpy_file is not None: try: - log.info(f'saving timing data for {k} in numpy file {timers[k].numpy_file}') - log.info('there are {} times'.format(len(a))) + log.info( + f"saving timing data for {k} in numpy file {timers[k].numpy_file}" + ) + log.info("there are {} times".format(len(a))) np.save(timers[k].numpy_file, a) except Exception as e: - log.error(f'could not save numpy file {timers[k].numpy_file}; caught {e}') + log.error( + f"could not save numpy file {timers[k].numpy_file}; caught {e}" + ) if timers[k].show_hist: def plot_loghist(x, bins): - hist, bins = np.histogram(x, bins=bins) # histogram x linearly - if len(bins)<2 or bins[0]<=0: - log.error(f'cannot plot histogram since bins={bins}') + hist, bins = np.histogram(x, bins=bins) # histogram x linearly + if len(bins) < 2 or bins[0] <= 0: + log.error(f"cannot plot histogram since bins={bins}") return - logbins = np.logspace(np.log10(bins[0]), np.log10(bins[-1]), len(bins)) # use resulting bin ends to get log bins - plt.hist(x, bins=logbins) # now again histogram x, but with the log-spaced bins, and plot this histogram - plt.xscale('log') - - dt = np.clip(a,1e-6, None) + logbins = np.logspace( + np.log10(bins[0]), np.log10(bins[-1]), len(bins) + ) # use resulting bin ends to get log bins + plt.hist( + x, bins=logbins + ) # now again histogram x, but with the log-spaced bins, and plot this histogram + plt.xscale("log") + + dt = np.clip(a, 1e-6, None) # logbins = np.logspace(np.log10(bins[0]), np.log10(bins[-1]), len(bins)) try: - plot_loghist(dt,bins=100) - plt.xlabel('interval[ms]') - plt.ylabel('frequency') + plot_loghist(dt, bins=100) + plt.xlabel("interval[ms]") + plt.ylabel("frequency") plt.title(k) plt.show() except Exception as e: - log.error(f'could not plot histogram: got {e}') + log.error(f"could not plot histogram: got {e}") atexit.register(print_timing_info) diff --git a/setup.py b/setup.py index c7ccea6..6c6b63a 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ Author: Yuhuang Hu Email : duguyue100@gmail.com """ + from __future__ import absolute_import from __future__ import print_function @@ -15,6 +16,7 @@ from setuptools import setup from setuptools.extension import Extension + classifiers = """ Development Status :: 4 - Beta Intended Audience :: Science/Research From 8d4e3e83d511af228ec657580f4581d8b6537d19 Mon Sep 17 00:00:00 2001 From: Yuhuang Hu Date: Sat, 16 Mar 2024 02:16:45 +0100 Subject: [PATCH 2/6] remove and add --- pyaer/__about__.py | 2 -- pyaer/__init__.py | 6 ------ pyaer/comm.py | 24 +++++++++--------------- pyaer/container.py | 11 +---------- pyaer/davis.py | 6 +----- pyaer/device.py | 6 +----- pyaer/dvs128.py | 6 +----- pyaer/dvxplorer.py | 6 +----- pyaer/dynapse.py | 6 +----- pyaer/edvs.py | 6 +----- pyaer/evk.py | 6 +----- pyaer/filters.py | 6 +----- pyaer/log.py | 8 +------- pyaer/utils.py | 6 +----- setup.cfg | 10 ++++++++++ setup.py | 9 +-------- 16 files changed, 31 insertions(+), 93 deletions(-) create mode 100644 setup.cfg diff --git a/pyaer/__about__.py b/pyaer/__about__.py index bd96a42..87498d8 100644 --- a/pyaer/__about__.py +++ b/pyaer/__about__.py @@ -1,5 +1,3 @@ -"""About page.""" - __all__ = ["__version__", "__author__", "__author_email__", "__url__"] __version__ = "0.2.7a0" diff --git a/pyaer/__init__.py b/pyaer/__init__.py index 38ae5ce..1b8b2cb 100644 --- a/pyaer/__init__.py +++ b/pyaer/__init__.py @@ -1,9 +1,3 @@ -"""Properly init the package. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" - from __future__ import absolute_import from __future__ import print_function diff --git a/pyaer/comm.py b/pyaer/comm.py index be7cc08..448008e 100644 --- a/pyaer/comm.py +++ b/pyaer/comm.py @@ -1,17 +1,12 @@ """Communication Module. -This script includes class definitions for communication -between processes. Example usage is to have a process for -fetching data from the event cameras and other processes for -processing the data. -The communication protocol is implemented through zeromq package. - -The design principle is similar to ROS where there is a hub for -central scheduling, a group of publishers for sending data, and -a group of subscribers to get/process data. - -Author: Yuhuang Hu -Email : yuhuang.hu@ini.uzh.ch +This script includes class definitions for communication between processes. Example +usage is to have a process for fetching data from the event cameras and other processes +for processing the data. The communication protocol is implemented through zeromq +package. + +The design principle is similar to ROS where there is a hub for central scheduling, a +group of publishers for sending data, and a group of subscribers to get/process data. """ import json @@ -612,9 +607,8 @@ def __init__( This is a shell implementation. - Intend to use as a processing unit. - First subscribe on a topic, process it, and then publish to - a topic + Intend to use as a processing unit. First subscribe on a topic, process it, and + then publish to a topic """ self.__dict__.update(kwargs) diff --git a/pyaer/container.py b/pyaer/container.py index 6a486d4..5932ac8 100644 --- a/pyaer/container.py +++ b/pyaer/container.py @@ -1,13 +1,4 @@ -"""Event Container. - -Motivation: After the events are read from the event packet, -it's difficult to use and less informative to return them -as single variables, therefore, I decide to introduce a -container that can manage all the returned Python variables. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations from typing import Optional diff --git a/pyaer/davis.py b/pyaer/davis.py index 5180592..1e76df6 100644 --- a/pyaer/davis.py +++ b/pyaer/davis.py @@ -1,8 +1,4 @@ -"""DAVIS Camera. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import numpy as np diff --git a/pyaer/device.py b/pyaer/device.py index 9d8e6a7..7a1d80a 100644 --- a/pyaer/device.py +++ b/pyaer/device.py @@ -1,8 +1,4 @@ -"""Generic Device. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import abc diff --git a/pyaer/dvs128.py b/pyaer/dvs128.py index 1be6f0a..fa4b8ff 100644 --- a/pyaer/dvs128.py +++ b/pyaer/dvs128.py @@ -1,8 +1,4 @@ -"""DVS128. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import numpy as np diff --git a/pyaer/dvxplorer.py b/pyaer/dvxplorer.py index 8268158..a8731fd 100644 --- a/pyaer/dvxplorer.py +++ b/pyaer/dvxplorer.py @@ -1,8 +1,4 @@ -"""DVXPLORER Camera. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import numpy as np diff --git a/pyaer/dynapse.py b/pyaer/dynapse.py index 2d058ce..531f6c6 100644 --- a/pyaer/dynapse.py +++ b/pyaer/dynapse.py @@ -1,8 +1,4 @@ -"""DYNAPSE. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import time diff --git a/pyaer/edvs.py b/pyaer/edvs.py index a7174bb..6820293 100644 --- a/pyaer/edvs.py +++ b/pyaer/edvs.py @@ -1,8 +1,4 @@ -"""eDVS. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import numpy as np diff --git a/pyaer/evk.py b/pyaer/evk.py index 8ee1c2b..2d35bb4 100644 --- a/pyaer/evk.py +++ b/pyaer/evk.py @@ -1,8 +1,4 @@ -"""Samsung EVK Camera. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import numpy as np diff --git a/pyaer/filters.py b/pyaer/filters.py index 22f2da1..065ddcf 100644 --- a/pyaer/filters.py +++ b/pyaer/filters.py @@ -1,8 +1,4 @@ -"""Implementation of software filters in libcaer. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations from typing import Any from typing import Dict diff --git a/pyaer/log.py b/pyaer/log.py index b88c71c..033442b 100644 --- a/pyaer/log.py +++ b/pyaer/log.py @@ -1,10 +1,4 @@ -"""Logger for PyAER. - -NOTE: this is different from libcaer's logger. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import logging from logging import Logger diff --git a/pyaer/utils.py b/pyaer/utils.py index eeb0d31..c64615a 100644 --- a/pyaer/utils.py +++ b/pyaer/utils.py @@ -1,8 +1,4 @@ -"""Utilities Functions. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" +from __future__ import annotations import importlib.util as imutil import json diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b0a6e9e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[mypy] + +[mypy-h5py.*] +ignore_missing_imports = True + +[mypy-zarr.*] +ignore_missing_imports = True + +[mypy-yaml.*] +ignore_missing_imports = True diff --git a/setup.py b/setup.py index 6c6b63a..e169017 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,4 @@ -"""Setup script for the pyaer package. - -Author: Yuhuang Hu -Email : duguyue100@gmail.com -""" - -from __future__ import absolute_import -from __future__ import print_function +from __future__ import annotations import os from sys import platform From d68f897e01538bcd292063f2c09518bdb63d9659 Mon Sep 17 00:00:00 2001 From: Yuhuang Hu Date: Sat, 16 Mar 2024 02:44:12 +0100 Subject: [PATCH 3/6] simplify --- pyaer/__about__.py | 6 -- pyaer/__init__.py | 12 +-- pyaer/constants.py | 2 + pyaer/device.py | 238 +++++++++++++++++++++------------------------ setup.py | 19 ++-- 5 files changed, 120 insertions(+), 157 deletions(-) delete mode 100644 pyaer/__about__.py create mode 100644 pyaer/constants.py diff --git a/pyaer/__about__.py b/pyaer/__about__.py deleted file mode 100644 index 87498d8..0000000 --- a/pyaer/__about__.py +++ /dev/null @@ -1,6 +0,0 @@ -__all__ = ["__version__", "__author__", "__author_email__", "__url__"] - -__version__ = "0.2.7a0" -__author__ = "Yuhuang Hu" -__author_email__ = "duguyue100@gmail.com" -__url__ = "https://github.com/duguyue100/pyaer" diff --git a/pyaer/__init__.py b/pyaer/__init__.py index 1b8b2cb..362cbd6 100644 --- a/pyaer/__init__.py +++ b/pyaer/__init__.py @@ -1,18 +1,8 @@ -from __future__ import absolute_import -from __future__ import print_function - -import os - from pyaer import log -from pyaer.__about__ import __author__ # noqa -from pyaer.__about__ import __version__ # noqa -FILE_PATH = os.path.realpath(__file__) -CURR_PATH = os.path.dirname(os.path.realpath(__file__)) -PKG_PATH = os.path.dirname(CURR_PATH) - # System logging level + LOG_LEVEL = log.DEBUG try: diff --git a/pyaer/constants.py b/pyaer/constants.py new file mode 100644 index 0000000..3c7d9de --- /dev/null +++ b/pyaer/constants.py @@ -0,0 +1,2 @@ +DISABLE_MAX_CONTAINER_SIZE = 0 +DEFAULT_MAX_PACKET_INTERVAL = 10000 # 10ms diff --git a/pyaer/device.py b/pyaer/device.py index 7a1d80a..64b1fc0 100644 --- a/pyaer/device.py +++ b/pyaer/device.py @@ -1,18 +1,20 @@ from __future__ import annotations import abc +from typing import Any from pyaer import libcaer +from pyaer.constants import DEFAULT_MAX_PACKET_INTERVAL +from pyaer.constants import DISABLE_MAX_CONTAINER_SIZE -class USBDevice(object): +class USBDevice: """Base class for all USB devices. This class is the base of DVS128, DAVIS240, DAVIS346 and DYNAPSE. """ - def __init__(self): - """Device.""" + def __init__(self) -> None: self.handle = None # functions for get events number and packet functions @@ -33,29 +35,27 @@ def __init__(self): } @abc.abstractmethod - def obtain_device_info(self, handle): - """Obtain device handle. + def obtain_device_info(self, handle: Any) -> None: + """Obtains device handle. - This abstract method should be implemented in all derived classes. - This method collects the general information about the USB device - such as the width and height of the camera or the serial number - of the device. + This abstract method should be implemented in all derived classes. This method + collects the general information about the device such as the width and height + of the camera or the serial number of the device. - # Arguments - handle: `caerDeviceHandle`
- a valid device handle that can be used with the other - `libcaer` functions, or `None` on error. + # Args: + handle: a valid device handle that can be used with the other `libcaer` + functions, or `None` on error. """ - return + raise NotADirectoryError() @abc.abstractmethod - def get_event(self): - """Get Event. + def get_event(self) -> None: + """Gets Event. This abstract method should be implemented in all derived classes. This method returns a packet of events according to the type of the sensor. """ - return + raise NotImplementedError() def open( self, @@ -106,15 +106,15 @@ def open( if self.handle is None: raise ValueError("The device is failed to open.") - def close(self): - """Close USB device. + def close(self) -> None: + """Closes USB device. This method closes an opened USB device if the respective handle is not None. """ if self.handle is not None: libcaer.caerDeviceClose(self.handle) - def shutdown(self): + def shutdown(self) -> None: """Shutdown device. This method is a combination of `data_stop` and `close`. This is a preferred way @@ -123,13 +123,12 @@ def shutdown(self): self.data_stop() self.close() - def data_start(self): - """Start data transmission. + def data_start(self) -> bool: + """Starts data transmission. - # Returns - flag: `bool`
- Return `True` if the data transmission is - initialized successfully. Otherwise `False`. + Returns: + flag: Return `True` if the data transmission is initialized successfully. + Otherwise `False`. """ # TODO figure out the parameter meaning if self.handle is not None: @@ -140,25 +139,24 @@ def data_start(self): else: return False - def data_stop(self): - """Stop data transmission. + def data_stop(self) -> None: + """Stops data transmission. This method stops the data transmission only. Note that this method does not destroy the respective device `handle`. """ libcaer.caerDeviceDataStop(self.handle) - def send_default_config(self): + def send_default_config(self) -> bool: """Send default configuration. - Each type of devices has a set of default configurations (e.g. bias) + Each type of devices has a set of default configurations (e.g., bias) that are pre-defined in the `libcaer` library. - Note that the default configuration might not be suitable for your - needs. + Note that the default configuration might not be suitable for your needs. - # Returns - flag: `bool`
- return `True` if the default config is set successfully, + + Returns: + flag: Return `True` if the default config is set successfully, `False` otherwise. """ if self.handle is not None: @@ -167,15 +165,41 @@ def send_default_config(self): else: return False - def set_max_container_packet_size(self, max_packet_size=0): + def set_config(self, mod_addr: int, param_addr: int, param: int | bool) -> bool: + """Sets configuration. + + The main function of setting configurations (e.g., bias). + + # Args: + mod_addr: a module address, used to specify which configuration module one + wants to update. Negative addresses are used for host-side + configuration, while positive addresses (including zero) are used for + device-side configuration. + param_addr: a parameter address, to select a specific parameter to update + from this particular configuration module. Only positive numbers + (including zero) are allowed. + param: a configuration parameter's new value. + + # Returns: + `True` if the config is set successfully, `False` otherwise. + """ + if self.handle is not None: + set_success = libcaer.caerDeviceConfigSet( + self.handle, mod_addr, param_addr, param + ) + return set_success + else: + return False + + def set_max_container_packet_size( + self, max_packet_size: int = DISABLE_MAX_CONTAINER_SIZE + ) -> bool: """Set max container packet size. - # Arguments - max_packet_size: `int`
- set the maximum number of events any of a packet container's - packets may hold before it's made available to the user. - Set to zero to disable.
- The default is `0`. + Args: + max_packet_size: set the maximum number of events any of a packet + container's packets may hold before it's made available to the user. + Set to `pyaer.constants.DISABLE_MAX_CONTAINER_SIZE` to disable. """ return self.set_config( libcaer.CAER_HOST_CONFIG_PACKETS, @@ -183,16 +207,16 @@ def set_max_container_packet_size(self, max_packet_size=0): max_packet_size, ) - def set_max_container_interval(self, max_packet_interval=10000): - """Set max packet interval. + def set_max_container_interval( + self, max_packet_interval: int = DEFAULT_MAX_PACKET_INTERVAL + ) -> bool: + """Sets max packet interval. - # Arguments - max_packet_interval: `int`
- set the time interval between subsequent packet containers. - Must be at least 1 microsecond. - The value is in microseconds, and is checked across all - types of events contained in the EventPacketContainer.
- The default is `10000` (10ms or 100 packets/s) + Args: + max_packet_interval: set the time interval between subsequent packet + containers. Must be at least 1 microsecond. The value is in + microseconds, and is checked across all types of events contained in + the EventPacketContainer. The default is `10000` (10ms or 100 packets/s) """ return self.set_config( libcaer.CAER_HOST_CONFIG_PACKETS, @@ -200,18 +224,16 @@ def set_max_container_interval(self, max_packet_interval=10000): max_packet_interval, ) - def set_data_exchange_blocking(self, exchange_blocking=True): - """Set data exchange blocking. + def set_data_exchange_blocking(self, exchange_blocking: bool = True) -> bool: + """Sets data exchange blocking. - # Arguments - exchange_blocking: `bool`
- whether to start all the data producer modules on the device - (DVS, APS, Mux, ...) automatically when starting the - data transfer thread with `caerDeviceDataStart()` or not. - If disabled, be aware you will have to start the right modules - manually, which can be useful if you need precise control - over which ones are running at any time.
- The default is `True`. + Arg: + exchange_blocking: Whether to start all the data producer modules on the + device (DVS, APS, Mux, ...) automatically when starting the data + transfer thread with `caerDeviceDataStart()` or not. If disabled, be + aware you will have to start the right modules manually, which can be + useful if you need precise control over which ones are running at any + time. The default is `True`. """ return self.set_config( libcaer.CAER_HOST_CONFIG_DATAEXCHANGE, @@ -219,71 +241,32 @@ def set_data_exchange_blocking(self, exchange_blocking=True): exchange_blocking, ) - def set_config(self, mod_addr, param_addr, param): - """Set configuration. - - The main function of setting configurations (e.g., bias). + def get_config(self, mod_addr: int, param_addr: int) -> int | bool | None: + """Gets Configuration. - # Arguments - mod_addr: `int`
- a module address, used to specify which configuration module - one wants to update. Negative addresses are used for host-side - configuration, while positive addresses (including zero) are - used for device-side configuration. - param_addr: `int`
- a parameter address, to select a specific parameter to update - from this particular configuration module. - Only positive numbers + Args: + mod_addr: a module address, used to specify which configuration module one + wants to update. Negative addresses are used for host-side + configuration, while positive addresses (including zero) are used for + device-side configuration. + param_addr: a parameter address, to select a specific parameter to update + from this particular configuration module. Only positive numbers (including zero) are allowed. - param: `int` or `bool`
- a configuration parameter's new value. - # Returns - flag: `bool`
- returns `True` if the config is set successfully, - `False` otherwise. - """ - if self.handle is not None: - set_success = libcaer.caerDeviceConfigSet( - self.handle, mod_addr, param_addr, param - ) - return set_success - else: - return False - - def get_config(self, mod_addr, param_addr): - """Get Configuration. - - # Arguments - mod_addr: `int`
- a module address, used to specify which configuration module - one wants to update. Negative addresses are used for host-side - configuration, while positive addresses (including zero) are - used for device-side configuration. - param_addr: `int`
- a parameter address, to select a specific parameter to update - from this particular configuration module. - Only positive numbers - (including zero) are allowed. - - # Returns - param: `int` or `bool`
- a configuration parameter's new value. Returns None - if the handle is not valid. + Returns: + A configuration parameter's new value. Returns None if the handle is not + valid. """ if self.handle is not None: return libcaer.caerDeviceConfigGet(self.handle, mod_addr, param_addr) else: return None - def get_packet_container(self): - """Get event packet container. + def get_packet_container(self) -> tuple[Any | None, int | None]: + """Gets event packet container. - # Returns - packet_container: `caerEventPacketContainer`
- a container that consists of event packets. - packet_number: `int`
- number of event packet in the container. + Returns: + A tuple of `(packet_container, num_event_packets)`. """ packet_container = libcaer.caerDeviceDataGet(self.handle) if packet_container is not None: @@ -294,20 +277,17 @@ def get_packet_container(self): else: return None, None - def get_packet_header(self, packet_container, idx): - """Get a single packet header. + def get_packet_header( + self, packet_container: Any, idx: int + ) -> tuple[Any | None, Any | None]: + """Gets a single packet header. - # Arguments - packet_container: `caerEventPacketContainer`
- the event packet container - idx: `int`
- the index of the packet header + Args: + packet_container: the event packet container + idx: the index of the packet header - # Returns - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - packet_type: `caerEventPacketType`
- the type of the event packet + Returns: + A tuple of `(packet_header, packet_type)`. """ packet_header = libcaer.caerEventPacketContainerGetEventPacket( packet_container, idx diff --git a/setup.py b/setup.py index e169017..ad4ec78 100644 --- a/setup.py +++ b/setup.py @@ -25,13 +25,10 @@ License :: OSI Approved :: MIT License """ -try: - from pyaer import __about__ - - about = __about__.__dict__ -except ImportError: - about = dict() - exec(open("pyaer/__about__.py").read(), about) +__version__ = "0.2.7a0" +__author__ = "Yuhuang Hu" +__author_email__ = "duguyue100@gmail.com" +__url__ = "https://github.com/duguyue100/pyaer" python_paths = get_paths() @@ -74,10 +71,10 @@ setup( name="pyaer", - version=about["__version__"], - author=about["__author__"], - author_email=about["__author_email__"], - url=about["__url__"], + version=__version__, + author=__author__, + author_email=__author_email__, + url=__url__, install_requires=["numpy"], packages=find_packages(), ext_modules=[libcaer_wrap], From 103ce9b80182c7125bc7ec649142eeaaa809a01a Mon Sep 17 00:00:00 2001 From: Yuhuang Hu Date: Sat, 16 Mar 2024 02:49:13 +0100 Subject: [PATCH 4/6] apply refactor --- pyaer/device.py | 832 ++++++++++++++++++------------------------------ pyaer/dtypes.py | 10 + 2 files changed, 327 insertions(+), 515 deletions(-) create mode 100644 pyaer/dtypes.py diff --git a/pyaer/device.py b/pyaer/device.py index 64b1fc0..c7b0df2 100644 --- a/pyaer/device.py +++ b/pyaer/device.py @@ -1,31 +1,50 @@ from __future__ import annotations -import abc +from abc import abstractmethod from typing import Any +from typing import Callable +from typing import TYPE_CHECKING + +import numpy as np from pyaer import libcaer from pyaer.constants import DEFAULT_MAX_PACKET_INTERVAL from pyaer.constants import DISABLE_MAX_CONTAINER_SIZE +from pyaer.dtypes import BiasObjectType +from pyaer.dtypes import DeviceType +from pyaer.dtypes import EventType +from pyaer.dtypes import ModuleAddressType +from pyaer.dtypes import ParameterAddressType +from pyaer.utils import load_json +from pyaer.utils import write_json -class USBDevice: - """Base class for all USB devices. +if TYPE_CHECKING: + from pyaer.filters import DVSNoise - This class is the base of DVS128, DAVIS240, DAVIS346 and DYNAPSE. - """ + +class Device: + """Generic device.""" def __init__(self) -> None: self.handle = None - # functions for get events number and packet functions - self.get_event_number_funcs = { + self.filter_noise = False + self.noise_filter: "DVSNoise" | None = None + + self.configs_list: list[ + tuple[str, ModuleAddressType, ParameterAddressType] + ] = [] + + # Functions for get events number and packet functions + self.get_event_number_funcs: dict[EventType, Callable] = { libcaer.POLARITY_EVENT: libcaer.caerEventPacketHeaderGetEventNumber, libcaer.SPECIAL_EVENT: libcaer.caerEventPacketHeaderGetEventNumber, libcaer.IMU6_EVENT: libcaer.caerEventPacketHeaderGetEventNumber, libcaer.IMU9_EVENT: libcaer.caerEventPacketHeaderGetEventNumber, libcaer.SPIKE_EVENT: libcaer.caerEventPacketHeaderGetEventNumber, } - self.get_event_packet_funcs = { + self.get_event_packet_funcs: dict[EventType, Callable] = { libcaer.POLARITY_EVENT: libcaer.caerPolarityEventPacketFromPacketHeader, libcaer.SPECIAL_EVENT: libcaer.caerSpecialEventPacketFromPacketHeader, libcaer.FRAME_EVENT: libcaer.caerFrameEventPacketFromPacketHeader, @@ -34,7 +53,7 @@ def __init__(self) -> None: libcaer.SPIKE_EVENT: libcaer.caerSpikeEventPacketFromPacketHeader, } - @abc.abstractmethod + @abstractmethod def obtain_device_info(self, handle: Any) -> None: """Obtains device handle. @@ -46,9 +65,9 @@ def obtain_device_info(self, handle: Any) -> None: handle: a valid device handle that can be used with the other `libcaer` functions, or `None` on error. """ - raise NotADirectoryError() + raise NotImplementedError() - @abc.abstractmethod + @abstractmethod def get_event(self) -> None: """Gets Event. @@ -57,78 +76,28 @@ def get_event(self) -> None: """ raise NotImplementedError() - def open( - self, - device_type, - device_id=1, - bus_number_restrict=0, - dev_address_restrict=0, - serial_number="", - ): - """Open USB deivce. - - # Arguments - device_type: `int`
- Device type:
- `libcaer.CAER_DEVICE_DVS128`, - `libcaer.CAER_DEVICE_EDVS`, - `libcaer.CAER_DEVICE_DAVIS`, - `libcaer.CAER_DEVICE_DAVIS_FX2`, - `libcaer.CAER_DEVICE_DAVIS_FX3`, - `libcaer.CAER_DEVICE_DAVIS_RPI`, - `libcaer.CAER_DEVICE_DYNAPSE`. - device_id: `int`
- a unique ID to identify the device from others. - Will be used as the source for EventPackets being - generate from its data.
- `default is 1`. - bus_number_restrict: `int`
- restrict the search for viable devices to only this USB - bus number.
- `default is 0`. - dev_address_restrict: `int`
- restrict the search for viable devices to only this USB - device address.
- `default is 0`. - serial_number: `str`
- restrict the search for viable devices to only devices which do - possess the given Serial Number in their USB - SerialNumber descriptor.
- `default is ""` + @abstractmethod + def open(self) -> None: + """Opens a device. + + The acutal implementation depends on the subclass. """ - self.handle = libcaer.caerDeviceOpen( - device_id, - device_type, - bus_number_restrict, - dev_address_restrict, - serial_number, - ) - if self.handle is None: - raise ValueError("The device is failed to open.") + raise NotImplementedError() def close(self) -> None: """Closes USB device. - This method closes an opened USB device if the respective handle is not None. + This method closes an opened device if the respective handle is not None. """ if self.handle is not None: libcaer.caerDeviceClose(self.handle) - def shutdown(self) -> None: - """Shutdown device. - - This method is a combination of `data_stop` and `close`. This is a preferred way - of shutting down a device. - """ - self.data_stop() - self.close() - def data_start(self) -> bool: """Starts data transmission. Returns: - flag: Return `True` if the data transmission is initialized successfully. - Otherwise `False`. + `True` if the data transmission is initialized successfully. + Otherwise `False`. """ # TODO figure out the parameter meaning if self.handle is not None: @@ -147,21 +116,27 @@ def data_stop(self) -> None: """ libcaer.caerDeviceDataStop(self.handle) - def send_default_config(self) -> bool: - """Send default configuration. + def shutdown(self) -> None: + """Shuts down device. - Each type of devices has a set of default configurations (e.g., bias) - that are pre-defined in the `libcaer` library. - Note that the default configuration might not be suitable for your needs. + This method is a combination of `data_stop` and `close`. This is a preferred way + of shutting down a device. + """ + self.data_stop() + self.close() + + def send_default_config(self) -> bool: + """Sends default configuration. + Each type of devices has a set of default configurations (e.g. bias) that are + pre-defined in the `libcaer` library. Note that the default configuration might + not be suitable for your needs. Returns: - flag: Return `True` if the default config is set successfully, - `False` otherwise. + `True` if the default config is set successfully, `False` otherwise. """ if self.handle is not None: - send_success = libcaer.caerDeviceSendDefaultConfig(self.handle) - return send_success + return libcaer.caerDeviceSendDefaultConfig(self.handle) else: return False @@ -170,7 +145,7 @@ def set_config(self, mod_addr: int, param_addr: int, param: int | bool) -> bool: The main function of setting configurations (e.g., bias). - # Args: + Args: mod_addr: a module address, used to specify which configuration module one wants to update. Negative addresses are used for host-side configuration, while positive addresses (including zero) are used for @@ -180,26 +155,23 @@ def set_config(self, mod_addr: int, param_addr: int, param: int | bool) -> bool: (including zero) are allowed. param: a configuration parameter's new value. - # Returns: + Returns: `True` if the config is set successfully, `False` otherwise. """ if self.handle is not None: - set_success = libcaer.caerDeviceConfigSet( - self.handle, mod_addr, param_addr, param - ) - return set_success + return libcaer.caerDeviceConfigSet(self.handle, mod_addr, param_addr, param) else: return False def set_max_container_packet_size( self, max_packet_size: int = DISABLE_MAX_CONTAINER_SIZE ) -> bool: - """Set max container packet size. + """Sets max container packet size. Args: - max_packet_size: set the maximum number of events any of a packet + max_packet_size: Set the maximum number of events any of a packet container's packets may hold before it's made available to the user. - Set to `pyaer.constants.DISABLE_MAX_CONTAINER_SIZE` to disable. + Set to zero to disable. The default is `0`. """ return self.set_config( libcaer.CAER_HOST_CONFIG_PACKETS, @@ -213,7 +185,7 @@ def set_max_container_interval( """Sets max packet interval. Args: - max_packet_interval: set the time interval between subsequent packet + max_packet_interval: Set the time interval between subsequent packet containers. Must be at least 1 microsecond. The value is in microseconds, and is checked across all types of events contained in the EventPacketContainer. The default is `10000` (10ms or 100 packets/s) @@ -241,6 +213,36 @@ def set_data_exchange_blocking(self, exchange_blocking: bool = True) -> bool: exchange_blocking, ) + def start_data_stream( + self, + send_default_config: bool = True, + max_packet_size: int | None = None, + max_packet_interval: int | None = None, + ) -> None: + """Starts streaming data. + + Args: + send_default_config: Send default config to the device before starting + the data streaming. `default is True` + max_packet_size: Set the maximum number of events any of a packet + container's packets may hold before it's made available to the user. + Set to zero to disable. The default is `None` (use default setting: 0). + max_packet_interval: Set the time interval between subsequent packet + containers. Must be at least 1 microsecond. The value is in + microseconds, and is checked across all types of events contained in the + EventPacketContainer. The default is `None` (use default setting: 10ms) + """ + if send_default_config: + self.send_default_config() + + if max_packet_size is not None: + self.set_max_container_packet_size(max_packet_size) + if max_packet_interval is not None: + self.set_max_container_interval(max_packet_interval) + + self.data_start() + self.set_data_exchange_blocking() + def get_config(self, mod_addr: int, param_addr: int) -> int | bool | None: """Gets Configuration. @@ -255,7 +257,7 @@ def get_config(self, mod_addr: int, param_addr: int) -> int | bool | None: Returns: A configuration parameter's new value. Returns None if the handle is not - valid. + valid. """ if self.handle is not None: return libcaer.caerDeviceConfigGet(self.handle, mod_addr, param_addr) @@ -266,7 +268,7 @@ def get_packet_container(self) -> tuple[Any | None, int | None]: """Gets event packet container. Returns: - A tuple of `(packet_container, num_event_packets)`. + A tuple of ``(packet_container, num_event_packets)``. """ packet_container = libcaer.caerDeviceDataGet(self.handle) if packet_container is not None: @@ -287,36 +289,33 @@ def get_packet_header( idx: the index of the packet header Returns: - A tuple of `(packet_header, packet_type)`. + A tuple of ``(packet_header, packet_type)``. """ packet_header = libcaer.caerEventPacketContainerGetEventPacket( packet_container, idx ) - if packet_header is None: - return (None, None) - else: + if packet_header is not None: packet_type = libcaer.caerEventPacketHeaderGetEventType(packet_header) return packet_header, packet_type + else: + return None, None + + def get_event_packet( + self, packet_header: Any, packet_type: EventType + ) -> tuple[int, Any]: + """Gets event packet from packet header. - def get_event_packet(self, packet_header, packet_type): - """Get event packet from packet header. - - # Arguments - packet_header: `caerEventPacketHeader`
- the header that represents a event packet. - packet_type: `caerEventPacketType`
- the type of the event packet, can be one of the following: - `libcaer.POLARITY_EVENT`, - `libcaer.SPECIAL_EVENT`, - `libcaer.FRAME_EVENT`, - `libcaer.IMU6_EVENT`, - `libcaer.SPIKE_EVENT` - - # Returns - num_events: `int`
- number of events, return None if there is no events. - event_packet: `caerEventPacket`
- a packet of events that are ready to be read. + Arguments: + packet_header: the header that represents a event packet. + packet_type: the type of the event packet, can be one of the following: + - `libcaer.POLARITY_EVENT`, + - `libcaer.SPECIAL_EVENT`, + - `libcaer.FRAME_EVENT`, + - `libcaer.IMU6_EVENT`, + - `libcaer.SPIKE_EVENT` + + Returns: + A tuple of ``(num_events, event_packet)``. """ num_events = ( self.get_event_number_funcs[packet_type](packet_header) @@ -332,40 +331,152 @@ def get_event_packet(self, packet_header, packet_type): return num_events, event_packet - def get_polarity_event(self, packet_header): - """Get a packet of polarity event. - - # Arguments - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - - # Returns - events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 4) where N - is the number of events in the event packet. - Each row in the array represents a single polarity event. - The first number is the timestamp. - The second number is the X position of the event. - The third number is the Y position of the event. - The fourth number represents the polarity of the event - (positive or negative). - num_events: `int`
- number of the polarity events available in the packet. + def set_bias(self, bias_obj: BiasObjectType) -> None: + """Sets bias from bias dictionary. + + Args: + bias_obj: Dictionary that contains biases. + + Returns: + True if set successful, False otherwise. + """ + for bias_name, module_address, parameter_address in self.configs_list: + self.set_config(module_address, parameter_address, bias_obj[bias_name]) + + # setting for noise filter + if self.noise_filter is not None and self.filter_noise is True: + self.noise_filter.set_bias(bias_obj["noise_filter_configs"]) + + def get_bias(self) -> BiasObjectType: + """Gets bias settings. + + Returns: + Dictionary that contains DVS128 current bias settings. + """ + bias_obj: BiasObjectType = {} + + for bias_name, module_address, parameter_address in self.configs_list: + bias_obj[bias_name] = self.get_config(module_address, parameter_address) + + # get noise filter configs + if self.noise_filter is not None: + bias_obj["noise_filter_configs"] = self.noise_filter.get_bias() + + return bias_obj + + def set_bias_from_json(self, file_path: str) -> None: + """Set bias from loading JSON configuration file. + + Args: + file_path: absolute path of the JSON bias file. + """ + bias_obj = load_json(file_path) + self.set_bias(bias_obj) + + def save_bias_to_json(self, file_path: str) -> bool: + """Save bias to JSON. + + Args: + file_path: the absolute path to the destiation. + + Returns: + returns True if success in writing, False otherwise. + """ + bias_obj = self.get_bias() + return write_json(file_path, bias_obj) + + def get_polarity_event(self, packet_header: Any) -> tuple[np.ndarray, int]: + """Gets a packet of polarity event. + + Args: + packet_header: the header that represents a event packet + noise_filter: the background activity filter is applied if True. """ num_events, polarity = self.get_event_packet( packet_header, libcaer.POLARITY_EVENT ) - # TODO: to implement a noise filtering process - # or reimplement this function into specific classes + if self.filter_noise is True and self.noise_filter is not None: + polarity = self.noise_filter.apply(polarity) - events = libcaer.get_polarity_event(polarity, num_events * 4).reshape( - num_events, 4 + events = libcaer.get_filtered_polarity_event( + polarity, num_events * 5 + ).reshape(num_events, 5) + else: + events = libcaer.get_polarity_event(polarity, num_events * 4).reshape( + num_events, 4 + ) + + return events, num_events + + def get_special_event(self, packet_header: Any) -> tuple[np.ndarray, int]: + """Get a packet of special event. + + Args: + packet_header: the header that represents a event packet. + """ + num_events, special = self.get_event_packet( + packet_header, libcaer.SPECIAL_EVENT + ) + + events = libcaer.get_special_event(special, num_events * 2).reshape( + num_events, 2 ) return events, num_events - def get_polarity_hist(self, packet_header, device_type=None): + +class USBDevice(Device): + """Base class for all USB devices. + + This class is the base of DVS128, DAVIS240, DAVIS346 and DYNAPSE. + """ + + def __init__(self) -> None: + super().__init__() + + def open( # type: ignore + self, + device_type: DeviceType, + device_id: int = 1, + bus_number_restrict: int = 0, + dev_address_restrict: int = 0, + serial_number: str = "", + ) -> None: + """Open an USB deivce. + + Args: + device_type: + - `libcaer.CAER_DEVICE_DVS128`, + - `libcaer.CAER_DEVICE_DAVIS`, + - `libcaer.CAER_DEVICE_DAVIS_FX2`, + - `libcaer.CAER_DEVICE_DAVIS_FX3`, + - `libcaer.CAER_DEVICE_DAVIS_RPI`, + - `libcaer.CAER_DEVICE_DYNAPSE`. + device_id: An unique ID to identify the device from others. Will be used as + the source for EventPackets being generate from its data. + `default is 1`. + bus_number_restrict: restrict the search for viable devices to only this USB + bus number. `default is 0`. + dev_address_restrict: restrict the search for viable devices to only this + USB device address. `default is 0`. + serial_number: restrict the search for viable devices to only devices which + do possess the given Serial Number in their USB SerialNumber descriptor. + `default is ""` + """ + self.handle = libcaer.caerDeviceOpen( + device_id, + device_type, + bus_number_restrict, + dev_address_restrict, + serial_number, + ) + if self.handle is None: + raise ValueError("The device is failed to open.") + + def get_polarity_hist( + self, packet_header: Any, device_type: str | int | None = None + ) -> tuple[np.ndarray, int]: """Get the positive and negative histogram for a packet.""" num_events, polarity = self.get_event_packet( packet_header, libcaer.POLARITY_EVENT @@ -383,74 +494,26 @@ def get_polarity_hist(self, packet_header, device_type=None): hist = libcaer.get_polarity_event_histogram_dvxplorer_lite( polarity, num_events ) - else: - return None, 0 return hist, num_events - def get_counter_neuron_event(self, packet_header, device_type=None): - """Get the positive and negative histogram for a packet.""" - num_events, polarity = self.get_event_packet( - packet_header, libcaer.POLARITY_EVENT - ) - - if device_type == libcaer.DAVIS_CHIP_DAVIS240C: - hist = libcaer.get_counter_neuron_frame_240(polarity, num_events) - elif device_type == libcaer.DAVIS_CHIP_DAVIS346B: - hist = libcaer.get_polarity_event_histogram_346(polarity, num_events) - elif device_type == "DVS128": - hist = libcaer.get_polarity_event_histogram_128(polarity, num_events) - else: - return None, 0 - - return hist, num_events - - def get_special_event(self, packet_header): - """Get a packet of special event. - - # Arguments - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - - # Returns - events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 2) where N - is the number of events in the event packet. - Each row in the array represents a single special event. - The first value is the timestamp of the event. - The second value is the special event data. - num_events: `int`
- number of the special events in the packet. - """ - num_events, special = self.get_event_packet( - packet_header, libcaer.SPECIAL_EVENT - ) - - events = libcaer.get_special_event(special, num_events * 2).reshape( - num_events, 2 - ) - - return events, num_events - def get_frame_event( - self, packet_header, device_type=None, aps_filter_type=libcaer.MONO - ): + self, + packet_header: Any, + device_type: int | None = None, + aps_filter_type: int = libcaer.MONO, + ) -> tuple[np.ndarray, int]: """Get a packet of frame event. - # Arguments - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - - # Returns - frame_mat: `numpy.ndarray`
- a 2-D array that has the shape of (height, width). - The height and width of the APS frame is determined by - the specific DAVIS device (e.g., DAVIS240 will have - a 180x240 APS frame. - For DAVIS346Red that has RGB outputs, the output array - has the shape of (height, width, 3) - frame_ts: `int`
- the APS frame timestamp. + Args: + packet_header: the header that represents a event packet + + Returns: + frame_mat: a 2-D array that has the shape of (height, width). The height and + width of the APS frame is determined by the specific DAVIS device (e.g., + DAVIS240 will have a 180x240 APS frame. For DAVIS346Red that has RGB + outputs, the output array has the shape of (height, width, 3) + frame_ts: the APS frame timestamp. """ _, frame = self.get_event_packet(packet_header, libcaer.FRAME_EVENT) first_event = libcaer.caerFrameEventPacketGetEventConst(frame, 0) @@ -479,25 +542,20 @@ def get_frame_event( return frame_mat, frame_ts - def get_imu6_event(self, packet_header): + def get_imu6_event(self, packet_header: Any) -> tuple[np.ndarray, int]: """Get IMU6 event. - # Arguments - packet_header: `caerEventPacketHeader` - the header that represents a event packet - - # Returns - events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 8) where N - is the number of IMU6 events in the packet. - Each row of the array consists a single IMU6 event. - The first value is the timestamp of the event. - The next three values are accelerations on the X, Y, and Z - axes. The next three values are angular velocity - on the X, Y and Z axes. - The last value is the temperature in Celsius scale. - num_events: `int`
- number of the IMU6 events. + # Args: + packet_header: the header that represents a event packet + + # Returns: + events: a 2-D array that has the shape of (N, 8) where N is the number of + IMU6 events in the packet. Each row of the array consists a single IMU6 + event. The first value is the timestamp of the event. The next three + values are accelerations on the X, Y, and Z axes. The next three values + are angular velocity on the X, Y and Z axes. The last value is the + temperature in Celsius scale. + num_events: number of the IMU6 events. """ num_events, imu = self.get_event_packet(packet_header, libcaer.IMU6_EVENT) @@ -505,26 +563,21 @@ def get_imu6_event(self, packet_header): return events, num_events - def get_imu9_event(self, packet_header): + def get_imu9_event(self, packet_header: Any) -> tuple[np.ndarray, int]: """Get IMU9 event. - # Arguments - packet_header: `caerEventPacketHeader` - the header that represents a event packet - - # Returns - events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 11) where N - is the number of IMU9 events in the packet. - Each row of the array consists a single IMU9 event. - The first value is the timestamp of the event. - The next three values are accelerations on the X, Y, and Z - axes. The next three values are angular velocity - on the X, Y and Z axes. The next three values are - X, Y, Z axis compass heading. - The last value is the temperature in Celsius scale. - num_events: `int`
- number of the IMU9 events. + # Args: + packet_header: the header that represents a event packet + + # Returns: + events: a 2-D array that has the shape of (N, 11) where N is the number of + IMU9 events in the packet. Each row of the array consists a single IMU9 + event. The first value is the timestamp of the event. The next three + values are accelerations on the X, Y, and Z axes. The next three values + are angular velocity on the X, Y and Z axes. The next three values are + X, Y, Z axis compass heading. The last value is the temperature in + Celsius scale. + num_events: number of the IMU9 events. """ num_events, imu = self.get_event_packet(packet_header, libcaer.IMU9_EVENT) @@ -532,97 +585,54 @@ def get_imu9_event(self, packet_header): return events, num_events - def get_spike_event(self, packet_header): + def get_spike_event(self, packet_header: Any) -> tuple[np.ndarray, int]: """Get Spike Event. - # Arguments - packet_header: `caerEventPacketHeader` - the header that represents a event packet - - # Returns - events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 4) where N - is the number of spike events in the packet. - Each row of the array has a single spike event. - The first value is the timestamp of the event. - The second value is the neuron ID. - The third value is the chip ID. - The last value is the source core ID. - num_events: `int`
- the number of the spike events. + # Args: + packet_header: the header that represents a event packet + + # Returns: + events: a 2-D array that has the shape of (N, 4) where N is the number of + spike events in the packet. Each row of the array has a single spike + event. The first value is the timestamp of the event. The second value + is the neuron ID. The third value is the chip ID. The last value is the + source core ID. + num_events: the number of the spike events. """ - num_events, spike = self.get_event_packet(packet_header, self.SPIKE_EVENT) + num_events, spike = self.get_event_packet(packet_header, libcaer.SPIKE_EVENT) events = libcaer.get_spike_event(spike, num_events * 4).reshape(num_events, 4) return events, num_events -class SerialDevice(object): +class SerialDevice(Device): """Base class for serial devices. The base class for devices that use the serial port. eDVS is the only current supported device in this family. """ - def __init__(self): - """Device.""" - self.handle = None - - @abc.abstractmethod - def obtain_device_info(self, handle): - """Obtain device handle. - - This abstract method should be implemented in all derived classes. - This method collects the general information about the USB device - such as the width and height of the camera or the serial number - of the device. - - # Arguments - handle: `caerDeviceHandle`
- a valid device handle that can be used with the other - `libcaer` functions, or `None` on error. - """ - return - - @abc.abstractmethod - def get_event(self): - """Get Event. - - This abstract method should be implemented in all derived classes. This method - returns a packet of events according to the type of the sensor. - """ - return + def __init__(self) -> None: + super().__init__() - def open( + def open( # type: ignore self, - device_type, - device_id=1, - serial_port_name="/dev/ttyUSB0", - serial_baud_rate=libcaer.CAER_HOST_CONFIG_SERIAL_BAUD_RATE_12M, - ): - """Open USB deivce. - - # Arguments - device_type: `int`
- Device type:
- `libcaer.CAER_DEVICE_DVS128`, - `libcaer.CAER_DEVICE_EDVS`, - `libcaer.CAER_DEVICE_DAVIS`, - `libcaer.CAER_DEVICE_DAVIS_FX2`, - `libcaer.CAER_DEVICE_DAVIS_FX3`, - `libcaer.CAER_DEVICE_DAVIS_RPI`, - `libcaer.CAER_DEVICE_DYNAPSE`. - device_id: `int`
- a unique ID to identify the device from others. - Will be used as the source for EventPackets being - generate from its data.
+ device_type: DeviceType, + device_id: int = 1, + serial_port_name: str = "/dev/ttyUSB0", + serial_baud_rate: int = libcaer.CAER_HOST_CONFIG_SERIAL_BAUD_RATE_12M, + ) -> None: + """Open a serial deivce. + + # Args: + device_type: `libcaer.CAER_DEVICE_EDVS`, + device_id: a unique ID to identify the device from others. Will be used as + the source for EventPackets being generate from its data. `default is 1`. - serial_port_name: `str`
- name of the serial port device to open.
+ serial_port_name: name of the serial port device to open. `default is /dev/ttyUSB0` - serial_baud_rate: `uint32_t` - baud-rate for serial port communication.
+ serial_baud_rate: baud-rate for serial port communication. `default is 12M` """ self.handle = libcaer.caerDeviceOpenSerial( @@ -630,211 +640,3 @@ def open( ) if self.handle is None: raise ValueError("The device is failed to open.") - - def close(self): - """Close USB device. - - This method closes an opened USB device if the respective handle is not None. - """ - if self.handle is not None: - libcaer.caerDeviceClose(self.handle) - - def shutdown(self): - """Shutdown device. - - This method is a combination of `data_stop` and `close`. This is a preferred way - of shutting down a device. - """ - self.data_stop() - self.close() - - def data_start(self): - """Start data transmission. - - # Returns - flag: `bool`
- Return `True` if the data transmission is - initialized successfully. Otherwise `False`. - """ - # TODO figure out the parameter meaning - if self.handle is not None: - data_start_success = libcaer.caerDeviceDataStart( - self.handle, None, None, None, None, None - ) - return data_start_success - else: - return False - - def data_stop(self): - """Stop data transmission. - - This method stops the data transmission only. Note that this method does not - destroy the respective device `handle`. - """ - libcaer.caerDeviceDataStop(self.handle) - - def send_default_config(self): - """Send default configuration. - - Each type of devices has a set of default configurations (e.g. bias) - that are pre-defined in the `libcaer` library. - Note that the default configuration might not be suitable for your - needs. - - # Returns - flag: `bool`
- return `True` if the default config is set successfully, - `False` otherwise. - """ - if self.handle is not None: - send_success = libcaer.caerDeviceSendDefaultConfig(self.handle) - return send_success - else: - return False - - def set_data_exchange_blocking(self, exchange_blocking=True): - """Set data exchange blocking. - - # Arguments - exchange_blocking: `bool`
- whether to start all the data producer modules on the device - (DVS, APS, Mux, ...) automatically when starting the - data transfer thread with `caerDeviceDataStart()` or not. - If disabled, be aware you will have to start the right modules - manually, which can be useful if you need precise control - over which ones are running at any time.
- The default is `True`. - """ - return self.set_config( - libcaer.CAER_HOST_CONFIG_DATAEXCHANGE, - libcaer.CAER_HOST_CONFIG_DATAEXCHANGE_BLOCKING, - exchange_blocking, - ) - - def set_config(self, mod_addr, param_addr, param): - """Set configuration. - - The main function of setting configurations (e.g., bias). - - # Arguments - mod_addr: `int`
- a module address, used to specify which configuration module - one wants to update. Negative addresses are used for host-side - configuration, while positive addresses (including zero) are - used for device-side configuration. - param_addr: `int`
- a parameter address, to select a specific parameter to update - from this particular configuration module. - Only positive numbers - (including zero) are allowed. - param: `int` or `bool`
- a configuration parameter's new value. - - # Returns - flag: `bool`
- returns `True` if the config is set successfully, - `False` otherwise. - """ - if self.handle is not None: - set_success = libcaer.caerDeviceConfigSet( - self.handle, mod_addr, param_addr, param - ) - return set_success - else: - return False - - def get_config(self, mod_addr, param_addr): - """Get Configuration. - - # Arguments - mod_addr: `int`
- a module address, used to specify which configuration module - one wants to update. Negative addresses are used for host-side - configuration, while positive addresses (including zero) are - used for device-side configuration. - param_addr: `int`
- a parameter address, to select a specific parameter to update - from this particular configuration module. - Only positive numbers - (including zero) are allowed. - - # Returns - param: `int` or `bool`
- a configuration parameter's new value. Returns None - if the handle is not valid. - """ - if self.handle is not None: - return libcaer.caerDeviceConfigGet(self.handle, mod_addr, param_addr) - else: - return None - - def get_packet_container(self): - """Get event packet container. - - # Returns - packet_container: `caerEventPacketContainer`
- a container that consists of event packets. - packet_number: `int`
- number of event packet in the container. - """ - packet_container = libcaer.caerDeviceDataGet(self.handle) - if packet_container is not None: - packet_number = libcaer.caerEventPacketContainerGetEventPacketsNumber( - packet_container - ) - return packet_container, packet_number - else: - return None, None - - def get_packet_header(self, packet_container, idx): - """Get a single packet header. - - # Arguments - packet_container: `caerEventPacketContainer`
- the event packet container - idx: `int`
- the index of the packet header - - # Returns - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - packet_type: `caerEventPacketType`
- the type of the event packet - """ - packet_header = libcaer.caerEventPacketContainerGetEventPacket( - packet_container, idx - ) - if packet_header is None: - return (None, None) - else: - packet_type = libcaer.caerEventPacketHeaderGetEventType(packet_header) - return packet_header, packet_type - - def get_polarity_event(self, packet_header): - """Get a packet of polarity event. - - # Arguments - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - - # Returns - events: `numpy.ndarray` - a 2-D array that has the shape of (N, 4) where N - is the number of events in the event packet. - Each row in the array represents a single polarity event. - The first number is the timestamp. - The second number is the X position of the event. - The third number is the Y position of the event. - The fourth number represents the polarity of the event - (positive or negative). - num_events: `int` - number of the polarity events available in the packet. - """ - num_events = libcaer.caerEventPacketHeaderGetEventNumber(packet_header) - polarity = libcaer.caerPolarityEventPacketFromPacketHeader(packet_header) - - events = libcaer.get_polarity_event(polarity, num_events * 4).reshape( - num_events, 4 - ) - - return events, num_events diff --git a/pyaer/dtypes.py b/pyaer/dtypes.py new file mode 100644 index 0000000..19e2087 --- /dev/null +++ b/pyaer/dtypes.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from typing import Any + + +EventType = int +DeviceType = int +ModuleAddressType = int +ParameterAddressType = int +BiasObjectType = dict[str, Any] From 9f010e1e3bec54570aa70ce0228247ae180d5c0f Mon Sep 17 00:00:00 2001 From: Yuhuang Hu Date: Sat, 16 Mar 2024 02:49:42 +0100 Subject: [PATCH 5/6] docs --- pyaer/device.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyaer/device.py b/pyaer/device.py index c7b0df2..82c6527 100644 --- a/pyaer/device.py +++ b/pyaer/device.py @@ -61,7 +61,7 @@ def obtain_device_info(self, handle: Any) -> None: collects the general information about the device such as the width and height of the camera or the serial number of the device. - # Args: + Args: handle: a valid device handle that can be used with the other `libcaer` functions, or `None` on error. """ @@ -545,10 +545,10 @@ def get_frame_event( def get_imu6_event(self, packet_header: Any) -> tuple[np.ndarray, int]: """Get IMU6 event. - # Args: + Args: packet_header: the header that represents a event packet - # Returns: + Returns: events: a 2-D array that has the shape of (N, 8) where N is the number of IMU6 events in the packet. Each row of the array consists a single IMU6 event. The first value is the timestamp of the event. The next three @@ -566,10 +566,10 @@ def get_imu6_event(self, packet_header: Any) -> tuple[np.ndarray, int]: def get_imu9_event(self, packet_header: Any) -> tuple[np.ndarray, int]: """Get IMU9 event. - # Args: + Args: packet_header: the header that represents a event packet - # Returns: + Returns: events: a 2-D array that has the shape of (N, 11) where N is the number of IMU9 events in the packet. Each row of the array consists a single IMU9 event. The first value is the timestamp of the event. The next three @@ -588,10 +588,10 @@ def get_imu9_event(self, packet_header: Any) -> tuple[np.ndarray, int]: def get_spike_event(self, packet_header: Any) -> tuple[np.ndarray, int]: """Get Spike Event. - # Args: + Args: packet_header: the header that represents a event packet - # Returns: + Returns: events: a 2-D array that has the shape of (N, 4) where N is the number of spike events in the packet. Each row of the array has a single spike event. The first value is the timestamp of the event. The second value @@ -625,7 +625,7 @@ def open( # type: ignore ) -> None: """Open a serial deivce. - # Args: + Args: device_type: `libcaer.CAER_DEVICE_EDVS`, device_id: a unique ID to identify the device from others. Will be used as the source for EventPackets being generate from its data. From 319c05c684ed85d22e5f9fc51882f0ffdfdbda9a Mon Sep 17 00:00:00 2001 From: Yuhuang Hu Date: Sat, 16 Mar 2024 03:21:12 +0100 Subject: [PATCH 6/6] trying to setup context manager --- pyaer/__init__.py | 7 +- pyaer/dvs128.py | 354 ++++++++---------------------------------- pyaer/event_camera.py | 10 ++ 3 files changed, 80 insertions(+), 291 deletions(-) create mode 100644 pyaer/event_camera.py diff --git a/pyaer/__init__.py b/pyaer/__init__.py index 362cbd6..d014a35 100644 --- a/pyaer/__init__.py +++ b/pyaer/__init__.py @@ -6,7 +6,7 @@ LOG_LEVEL = log.DEBUG try: - from pyaer import libcaer_wrap as libcaer # noqa + from pyaer import libcaer_wrap as libcaer except ImportError: raise ImportError( "libcaer might not be in the LD_LIBRARY_PATH " @@ -14,3 +14,8 @@ "Try to load _libcaer_wrap.so from the package " "directory, this will provide more information." ) + +from pyaer.event_camera import EventCamera # noqa # noreorder + + +__all__ = ["libcaer", "EventCamera"] diff --git a/pyaer/dvs128.py b/pyaer/dvs128.py index fa4b8ff..afb2df8 100644 --- a/pyaer/dvs128.py +++ b/pyaer/dvs128.py @@ -1,9 +1,10 @@ from __future__ import annotations +from typing import Any + import numpy as np from pyaer import libcaer -from pyaer import utils from pyaer.device import USBDevice from pyaer.filters import DVSNoise @@ -11,51 +12,44 @@ class DVS128(USBDevice): """DVS128. - # Arguments - device_id: `int`
- a unique ID to identify the device from others. - Will be used as the source for EventPackets being - generate from its data.
- `default is 1` - bus_number_restrict: `int`
- restrict the search for viable devices to only this USB - bus number.
- `default is 0` - dev_address_restrict: `int`
- restrict the search for viable devices to only this USB - device address.
- `default is 0` - serial_number: `str`
- restrict the search for viable devices to only devices which do - possess the given Serial Number in their USB - SerialNumber descriptor.
+ Args: + device_id: a unique ID to identify the device from others. Will be used as the + source for EventPackets being generate from its data. `default is 1` + bus_number_restrict: restrict the search for viable devices to only this USB + bus number. `default is 0` + dev_address_restrict: restrict the search for viable devices to only this USB + device address. `default is 0` + serial_number: restrict the search for viable devices to only devices which do + possess the given Serial Number in their USB SerialNumber descriptor. `default is ""` - noise_filter: `bool`
- if enable noise filter,
- `default is False`. + filter_noise: if enable noise filter, `default is False`. """ def __init__( self, - device_id=1, - bus_number_restrict=0, - dev_address_restrict=0, - serial_number="", - noise_filter=False, - ): - """DVS128.""" - super(DVS128, self).__init__() - # open device - self.open(device_id, bus_number_restrict, dev_address_restrict, serial_number) - # get camera information + device_id: int = 1, + bus_number_restrict: int = 0, + dev_address_restrict: int = 0, + serial_number: str = "", + filter_noise: bool = False, + ) -> None: + super().__init__() + # Opens device. + self.open( + libcaer.CAER_DEVICE_DVS128, + device_id, + bus_number_restrict, + dev_address_restrict, + serial_number, + ) + # Gets camera information. self.obtain_device_info(self.handle) - # noise filter - self.filter_noise = noise_filter - if noise_filter is True: - self.noise_filter = DVSNoise(self.dvs_size_X, self.dvs_size_Y) - else: - self.noise_filter = None + # Sets noise filter + self.filter_noise = filter_noise + self.noise_filter = ( + DVSNoise(self.dvs_size_X, self.dvs_size_Y) if filter_noise else None + ) # Bias configuration list self.configs_list = [ @@ -73,39 +67,7 @@ def __init__( ("Pr", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_PR), ] - def set_noise_filter(self, noise_filter): - """Set noise filter. - - # Arguments - noise_filter: `filters.DVSNoise`
- A valid `DVSNoise` object. This filter implements - software-level background activity filter. - """ - if noise_filter is not None: - self.noise_filter = noise_filter - - def enable_noise_filter(self): - """Enalbe DVS noise filter. - - This function enables the DVS noise filter. Note that this function will - initialize a `DVSNoise` filter if there is None. - """ - if self.filter_noise is False: - self.filter_noise = True - - if self.noise_filter is None: - self.noise_filter = DVSNoise(self.dvs_size_X, self.dvs_size_Y) - - def disable_noise_filter(self): - """Disable noise filter. - - This method disable the noise filter. Note that this function doesn't destroy - the existed noise filter. It simply switches off the function. - """ - if self.filter_noise is True: - self.filter_noise = False - - def obtain_device_info(self, handle): + def obtain_device_info(self, handle: Any) -> None: """Obtain DVS128 info. This function collects the following information from the device: @@ -119,7 +81,7 @@ def obtain_device_info(self, handle): - Camera height - Logic version - # Arguments + Args: handle: `caerDeviceHandle`
a valid device handle that can be used with the other `libcaer` functions, or `None` on error. @@ -127,7 +89,7 @@ def obtain_device_info(self, handle): if handle is not None: info = libcaer.caerDVS128InfoGet(handle) - # port all info data field out + # Ports all info data field out self.device_id = info.deviceID self.device_serial_number = info.deviceSerialNumber self.device_usb_bus_number = info.deviceUSBBusNumber @@ -138,243 +100,55 @@ def obtain_device_info(self, handle): self.dvs_size_X = info.dvsSizeX self.dvs_size_Y = info.dvsSizeY - def open( - self, - device_id=1, - bus_number_restrict=0, - dev_address_restrict=0, - serial_number="", - ): - """Open device. - - # Arguments - device_id: `int`
- a unique ID to identify the device from others. - Will be used as the source for EventPackets being - generate from its data.
- `default is 1`. - bus_number_restrict: `int`
- restrict the search for viable devices to only this USB - bus number.
- `default is 0`. - dev_address_restrict: `int`
- restrict the search for viable devices to only this USB - device address.
- `default is 0`. - serial_number: `str`
- restrict the search for viable devices to only devices which do - possess the given Serial Number in their USB - SerialNumber descriptor.
- `default is ""` - """ - super(DVS128, self).open( - libcaer.CAER_DEVICE_DVS128, - device_id, - bus_number_restrict, - dev_address_restrict, - serial_number, - ) - - def set_bias_from_json(self, file_path, verbose=False): - """Set bias from loading JSON configuration file. - - # Arguments - file_path: `str`
- absolute path of the JSON bias file. - verbose: `bool`
- optional debugging message. - """ - bias_obj = utils.load_dvs_bias(file_path, verbose) - self.set_bias(bias_obj) - - def set_bias(self, bias_obj): - """Set bias from bias dictionary. - - # Arguments - bias_obj: `dict`
- dictionary that contains DVS128 biases. - - # Returns - flag: `bool`
- True if set successful, False otherwise. - """ - for bias_name, module_address, parameter_address in self.configs_list: - self.set_config(module_address, parameter_address, bias_obj[bias_name]) - - # setting for noise filter - if self.filter_noise is True: - self.noise_filter.set_bias(bias_obj["noise_filter_configs"]) - - def get_bias(self): - """Get bias settings. - - # Returns - bias_obj: `dict`
- dictionary that contains DVS128 current bias settings. - """ - bias_obj = {} - - for bias_name, module_address, parameter_address in self.configs_list: - bias_obj[bias_name] = self.get_config(module_address, parameter_address) - - # get noise filter configs - if self.noise_filter is not None: - bias_obj["noise_filter_configs"] = self.noise_filter.get_bias() - - return bias_obj - - def save_bias_to_json(self, file_path): - """Save bias to JSON. - - # Arguments - file_path: `str`
- the absolute path to the destiation. - - # Returns - flag: `bool`
- returns True if success in writing, False otherwise. - """ - bias_obj = self.get_bias() - return utils.write_json(file_path, bias_obj) - - def start_data_stream( - self, send_default_config=True, max_packet_size=None, max_packet_interval=None - ): - """Start streaming data. - - # Arguments - send_default_config: `bool`
- send default config to the device before starting - the data streaming.
- `default is True` - max_packet_size: `int`
- set the maximum number of events any of a packet container's - packets may hold before it's made available to the user. - Set to zero to disable.
- The default is `None` (use default setting: 0). - max_packet_interval: `int`
- set the time interval between subsequent packet containers. - Must be at least 1 microsecond. - The value is in microseconds, and is checked across all - types of events contained in the EventPacketContainer.
- The default is `None` (use default setting: 10ms) - """ - if send_default_config is True: - self.send_default_config() - - if max_packet_size is not None: - self.set_max_container_packet_size(max_packet_size) - if max_packet_interval is not None: - self.set_max_container_interval(max_packet_interval) - - self.data_start() - self.set_data_exchange_blocking() - - def get_polarity_event(self, packet_header, noise_filter=False): - """Get a packet of polarity event. - - # Arguments - packet_header: `caerEventPacketHeader`
- the header that represents a event packet - noise_filter: `bool`
- the background activity filter is applied if True. - - # Returns - events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 4) where N - is the number of events in the event packet. - Each row in the array represents a single polarity event. - The first number is the timestamp. - The second number is the X position of the event. - The third number is the Y position of the event. - The fourth number represents the polarity of the event - (positive or negative).
- If the `noise_filter` option is set to `True`, - this array has an additional column at the end. - The last column represents the validity of the corresponding - event. Filtered events will be marked as 0. - num_events: `int`
- number of the polarity events available in the packet. - """ - num_events, polarity = self.get_event_packet( - packet_header, libcaer.POLARITY_EVENT - ) - - if noise_filter is True: - polarity = self.noise_filter.apply(polarity) - - events = libcaer.get_filtered_polarity_event( - polarity, num_events * 5 - ).reshape(num_events, 5) - else: - events = libcaer.get_polarity_event(polarity, num_events * 4).reshape( - num_events, 4 - ) - - return events, num_events - - def get_event(self, mode="events"): + def get_event( # type: ignore + self, mode: str = "events" + ) -> tuple[np.ndarray, int, np.ndarray, int] | None: """Get event. - # Returns - pol_events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 4) where N - is the number of events in the event packet. - Each row in the array represents a single polarity event. - The first number is the timestamp. - The second number is the X position of the event. - The third number is the Y position of the event. - The fourth number represents the polarity of the event - (positive or negative).
- If the `noise_filter` option is set to `True`, - this array has an additional column at the end. - The last column represents the validity of the corresponding - event. Filtered events will be marked as 0. - num_pol_events: `int`
- number of the polarity events available in the packet. - special_events: `numpy.ndarray`
- a 2-D array that has the shape of (N, 2) where N - is the number of events in the event packet. - Each row in the array represents a single special event. - The first value is the timestamp of the event. + Returns: + pol_events: a 2-D array of shape (N, 4) where N is the number of events in + the event packet. Each row in the array represents a single polarity + event. The first number is the timestamp. The second number is the X + position of the event. The third number is the Y position of the event. + The fourth number represents the polarity of the event (positive or + negative). If the `noise_filter` option is set to `True`, this array + has an additional column at the end. The last column represents the + validity of the corresponding event. Filtered events are marked as 0. + num_pol_events: number of the polarity events available in the packet. + special_events: a 2-D array that has the shape of (N, 2) where N is the + number of events in the event packet. Each row in the array represents + a single special event. The first value is the timestamp of the event. The second value is the special event data. - num_special_events: `int`
- number of the special events in the packet. + num_special_events: number of the special events in the packet. """ packet_container, packet_number = self.get_packet_container() - if packet_container is not None: + if packet_container is not None and packet_number is not None: num_pol_event = 0 num_special_event = 0 - pol_events = None - special_events = None + pol_events = ( + np.zeros((0, int(4 + self.filter_noise)), dtype=np.uint64) + if mode == "events" + else np.zeros((128, 128, 2), dtype=np.uint64) + ) + special_events = np.zeros((0, 2), dtype=np.uint64) for packet_id in range(packet_number): packet_header, packet_type = self.get_packet_header( packet_container, packet_id ) if packet_type == libcaer.POLARITY_EVENT: if mode == "events": - events, num_events = self.get_polarity_event( - packet_header, self.filter_noise - ) - pol_events = ( - np.hstack((pol_events, events)) - if pol_events is not None - else events - ) + events, num_events = self.get_polarity_event(packet_header) + pol_events = np.hstack((pol_events, events)) elif mode == "events_hist": hist, num_events = self.get_polarity_hist( packet_header, device_type="DVS128" ) - pol_events = hist if pol_events is None else pol_events + hist + pol_events += hist num_pol_event += num_events elif packet_type == libcaer.SPECIAL_EVENT: events, num_events = self.get_special_event(packet_header) - special_events = ( - np.hstack((special_events, events)) - if special_events is not None - else events - ) + special_events = np.hstack((special_events, events)) num_special_event += num_events libcaer.caerEventPacketContainerFree(packet_container) diff --git a/pyaer/event_camera.py b/pyaer/event_camera.py new file mode 100644 index 0000000..7907a13 --- /dev/null +++ b/pyaer/event_camera.py @@ -0,0 +1,10 @@ +class EventCamera: + def __init__(self) -> None: + self.camera = None + + def __enter__(self) -> None: + return self.camera + + # context manager exist method with typing + def __exit__(self, exc_type, exc_value, traceback) -> None: + self.camera.shutdown()