├── requirements.txt
├── res
├── pyaer_cover_img.png
└── appveyor.yml
├── docs
├── css
│ └── highlight-fix.css
├── README.md
├── Makefile
├── mkdocs.yml
└── pages
│ ├── dvs128.md
│ ├── edvs.md
│ ├── index.md
│ ├── davis.md
│ └── dynapse.md
├── scripts
├── device_discovery.py
├── configs
│ ├── edvs_config.json
│ ├── evk_config.json
│ ├── dvs_noise_filter_config.json
│ ├── dvxplorer_config.json
│ ├── dvs128_config.json
│ ├── davis240c_config.json
│ ├── davis346_config.json
│ └── dynapse_config.json
├── aer_comm
│ ├── sample_viewer.yml
│ ├── sample_recorder.yml
│ ├── sample_config.yml
│ ├── test_hdf5_reader.py
│ ├── aer_hub
│ ├── aer_lstopic
│ ├── aer_subscriber
│ ├── aer_pubsuber
│ ├── custom_comm.py
│ ├── aer_publisher
│ ├── aer_saver
│ └── aer_launch
├── dvs128_test.py
├── dynapse_test.py
├── dvxplorer_test.py
├── edvs_test.py
├── davis240_test.py
├── event_container_test.py
├── dvs_noise_filter_test.py
├── dvs128_thread_test.py
├── dvs128_glumpy.py
├── davis346_test.py
├── davis346_color_test.py
├── davis346_color_events.py
├── dvs128_vispy.py
└── timer.py
├── pyaer
├── __about__.py
├── __init__.py
├── log.py
├── container.py
├── pyfragments.swg
├── filters.py
├── utils.py
├── edvs.py
└── dvs128.py
├── custom_build
├── compile.conf.bak
├── README.md
├── install-libcaer.sh
├── .travis.yml
└── compile
├── LICENSE
├── install-udev.sh
├── README-RPI.md
├── INSTALL_FROM_SOURCE.md
├── .gitignore
├── Makefile
├── .github
└── workflows
│ └── main.yml
├── setup.py
└── README.md
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | pyzmq
3 | h5py
4 |
--------------------------------------------------------------------------------
/res/pyaer_cover_img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duguyue100/pyaer/HEAD/res/pyaer_cover_img.png
--------------------------------------------------------------------------------
/docs/css/highlight-fix.css:
--------------------------------------------------------------------------------
1 | pre {
2 | background-color: transparent;
3 | border: none;
4 | }
5 |
6 | code {
7 | background-color: transparent;
8 | }
9 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Generate docs
2 |
3 | ## Generate and push to website
4 |
5 | ```
6 | $ mkdocs gh-deploy --config-file ../pyaer/docs/mkdocs.yml --remote-branch master
7 | ```
8 |
--------------------------------------------------------------------------------
/scripts/device_discovery.py:
--------------------------------------------------------------------------------
1 | """Check device discovery."""
2 |
3 | from pyaer import libcaer
4 |
5 |
6 | discovered_result = libcaer.device_discover_new(-1)
7 |
8 | print(discovered_result.deviceInfo.davisInfo.deviceString)
9 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Generate docs
2 | #
3 | # Author: Yuhuang Hu
4 | # Email : yuhuang.hu@ini.uzh.ch
5 |
6 | serve-docs:
7 | python ./autogen.py
8 | mkdocs serve
9 |
10 | build-docs:
11 | python ./autogen.py
12 | mkdocs build
13 |
--------------------------------------------------------------------------------
/pyaer/__about__.py:
--------------------------------------------------------------------------------
1 | """About page."""
2 | __all__ = ["__version__", "__author__", "__author_email__", "__url__"]
3 |
4 | __version__ = "0.2.7a0"
5 | __author__ = "Yuhuang Hu"
6 | __author_email__ = "duguyue100@gmail.com"
7 | __url__ = "https://github.com/duguyue100/pyaer"
8 |
--------------------------------------------------------------------------------
/scripts/configs/edvs_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "cas": 54,
3 | "injGnd": 1108364,
4 | "reqPd": 16777215,
5 | "puX": 8159221,
6 | "diffOff": 132,
7 | "req": 159147,
8 | "refr": 6,
9 | "puY": 16777215,
10 | "diffOn": 482443,
11 | "diff": 30153,
12 | "foll": 51,
13 | "Pr": 3
14 | }
15 |
--------------------------------------------------------------------------------
/scripts/configs/evk_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "bias_simple": "default",
3 | "global_hold_enable": true,
4 | "global_reset_enable": false,
5 | "global_reset_during_readout": false,
6 | "fixed_read_time_enable": false,
7 | "event_flatten": false,
8 | "event_on_only": false,
9 | "event_off_only": false,
10 | "subsample_enable": false,
11 | "area_blocking_enable": false,
12 | "dual_binning_enable": false
13 | }
14 |
--------------------------------------------------------------------------------
/scripts/aer_comm/sample_viewer.yml:
--------------------------------------------------------------------------------
1 | "Hub":
2 | "use_default": true
3 |
4 | "Subscriber-frame":
5 | "topic": ""
6 | "use_default_sub": false
7 | "custom_sub": "./custom_comm.py/DVViewerSubscriber"
8 | "name": "dv_subscriber"
9 |
10 | "Publisher-davis":
11 | "master_topic": "davis_1"
12 | "use_default_pub": true
13 | "device": "DAVIS"
14 | "noise_filter": true
15 | "bias_file": "../configs/davis346_config.json"
16 | "name": "dvxplorer_publisher"
17 |
--------------------------------------------------------------------------------
/scripts/configs/dvs_noise_filter_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "sw_background_activity_two_levels": true,
3 | "sw_background_activity_check_polarity": true,
4 | "sw_background_activity_support_min": 2,
5 | "sw_background_activity_support_max": 8,
6 | "sw_background_activity_time": 2000,
7 | "sw_background_activity_enable": true,
8 | "sw_refractory_period_time": 200,
9 | "sw_refractory_period_enable": true,
10 | "sw_hotpixel_enable": true,
11 | "sw_hotpixel_learn": true
12 | }
13 |
--------------------------------------------------------------------------------
/custom_build/compile.conf.bak:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Turn it to true if you are not building the repository for the first time
4 | REBUILDING=false
5 |
6 | # defien python version (experimental)
7 | # only support python 2 at this moment
8 | PYTHON_VERSION=2
9 |
10 | # define python executable
11 | CONDA_LIB_PATH=$HOME/anaconda2/lib
12 | CONDA_PKG_CONFIG_PATH=$CONDA_LIB_PATH/pkgconfig
13 |
14 | # false if build libcaer locally
15 | # true if you have a system installed libcaer
16 | LIBCAER_INSTALLED=false
17 |
--------------------------------------------------------------------------------
/scripts/aer_comm/sample_recorder.yml:
--------------------------------------------------------------------------------
1 | "Hub":
2 | "use_default": true
3 |
4 | "Saver-hdf5":
5 | "name": "aer_saver"
6 | "topic": ""
7 | "filename": "~/data/dark/dark_1.hdf5"
8 |
9 | "Subscriber-frame":
10 | "name": "frame_subscriber"
11 | "topic": ""
12 | "use_default_sub": false
13 | "custom_sub": "./custom_comm.py/CustomSubscriber"
14 |
15 | "Publisher-davis":
16 | "name": "davis_publisher"
17 | "master_topic": "davis_1"
18 | "use_default_pub": true
19 | # "custom_pub": "./custom_comm.py/CustomPublisher"
20 | "device": "DAVIS"
21 | "bias_file": "../configs/davis346_config.json"
22 | "noise_filter": true
23 |
--------------------------------------------------------------------------------
/scripts/configs/dvxplorer_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "mux_timestamp_reset": false,
3 | "drop_extinput_on_transfer_stall": true,
4 | "mux_drop_dvs_on_transfer_stall": false,
5 | "extinput_detect_rising_edges": false,
6 | "extinput_detect_falling_edges": false,
7 | "extinput_detect_pulses": true,
8 | "extinput_detect_pulse_polarity": true,
9 | "extinput_detect_pulse_length": 10,
10 | "extinput_ran_generator": false,
11 | "extinput_generate_pulse_polarity": true,
12 | "extinput_generate_pulse_interval": 10,
13 | "extinput_generate_pulse_length": 5,
14 | "extinput_generate_inject_on_rising_edge": false,
15 | "extinput_generate_inject_on_falling_edge": false,
16 | "usb_early_packet_delay": 8,
17 | "bias_simple": "default"
18 | }
19 |
--------------------------------------------------------------------------------
/scripts/configs/dvs128_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "cas": 54,
3 | "injGnd": 1108364,
4 | "reqPd": 16777215,
5 | "puX": 8159221,
6 | "diffOff": 132,
7 | "req": 159147,
8 | "refr": 6,
9 | "puY": 16777215,
10 | "diffOn": 482443,
11 | "diff": 30153,
12 | "foll": 51,
13 | "Pr": 3,
14 | "noise_filter_configs": {
15 | "sw_background_activity_two_levels": true,
16 | "sw_background_activity_check_polarity": true,
17 | "sw_background_activity_support_min": 2,
18 | "sw_background_activity_support_max": 8,
19 | "sw_background_activity_time": 2000,
20 | "sw_background_activity_enable": true,
21 | "sw_refractory_period_time": 200,
22 | "sw_refractory_period_enable": true,
23 | "sw_hotpixel_enable": true,
24 | "sw_hotpixel_learn": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/docs/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: PyAER Documentation
2 | theme: readthedocs
3 |
4 | markdown_extensions:
5 | - codehilite:
6 | guess_lang: false
7 | use_pygments: true
8 | noclasses: true
9 |
10 | # theme_dir: theme
11 | docs_dir: sources
12 | repo_url: https://github.com/duguyue100/pyaer
13 | site_url: https://dgyblog.com/pyaer-doc
14 | site_description: 'Documentation for PyAER.'
15 |
16 | markdown_extensions:
17 | - codehilite
18 |
19 | dev_addr: '0.0.0.0:8000'
20 |
21 | extra_css:
22 | - css/highlight-fix.css
23 |
24 | pages:
25 | - Home: index.md
26 | - USB Device: usb-device.md
27 | - Serial Device: serial-device.md
28 | - DVS128: dvs128.md
29 | - DAVIS: davis.md
30 | - eDVS: edvs.md
31 | - DYNAPSE: dynapse.md
32 | - Filters: filters.md
33 | - Utils: utils.md
34 | - Logging: log.md
35 |
--------------------------------------------------------------------------------
/docs/pages/dvs128.md:
--------------------------------------------------------------------------------
1 | {{autogenerated}}
2 |
3 | ---
4 |
5 | ## Bias Example
6 |
7 | ```json
8 | {
9 | "cas": 54,
10 | "injGnd": 1108364,
11 | "reqPd": 16777215,
12 | "puX": 8159221,
13 | "diffOff": 132,
14 | "req": 159147,
15 | "refr": 6,
16 | "puY": 16777215,
17 | "diffOn": 482443,
18 | "diff": 30153,
19 | "foll": 51,
20 | "Pr": 3,
21 | "noise_filter_configs": {
22 | "sw_background_activity_two_levels": true,
23 | "sw_background_activity_check_polarity": true,
24 | "sw_background_activity_support_min": 2,
25 | "sw_background_activity_support_max": 8,
26 | "sw_background_activity_time": 2000,
27 | "sw_background_activity_enable": true,
28 | "sw_refractory_period_time": 200,
29 | "sw_refractory_period_enable": true,
30 | "sw_hotpixel_enable": true,
31 | "sw_hotpixel_learn": true
32 | }
33 | }
34 | ```
35 |
--------------------------------------------------------------------------------
/docs/pages/edvs.md:
--------------------------------------------------------------------------------
1 |
2 | {{autogenerated}}
3 |
4 | ---
5 |
6 | ## Bias Example
7 |
8 | ```json
9 | {
10 | "cas": 54,
11 | "injGnd": 1108364,
12 | "reqPd": 16777215,
13 | "puX": 8159221,
14 | "diffOff": 132,
15 | "req": 159147,
16 | "refr": 6,
17 | "puY": 16777215,
18 | "diffOn": 482443,
19 | "diff": 30153,
20 | "foll": 51,
21 | "Pr": 3,
22 | "noise_filter_configs": {
23 | "sw_background_activity_two_levels": true,
24 | "sw_background_activity_check_polarity": true,
25 | "sw_background_activity_support_min": 2,
26 | "sw_background_activity_support_max": 8,
27 | "sw_background_activity_time": 2000,
28 | "sw_background_activity_enable": true,
29 | "sw_refractory_period_time": 200,
30 | "sw_refractory_period_enable": true,
31 | "sw_hotpixel_enable": true,
32 | "sw_hotpixel_learn": true
33 | }
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/scripts/aer_comm/sample_config.yml:
--------------------------------------------------------------------------------
1 | "Hub":
2 | "use_default": true
3 |
4 | "Subscriber-frame":
5 | "use_default": true
6 | "url": "tcp://127.0.0.1"
7 | "port": 5099
8 | "name": "frame-subscriber"
9 | "topic": ""
10 | "use_default_sub": false
11 | "custom_sub": "./custom_comm.py"
12 | "custom_class": "CustomSubscriber"
13 | "custom_1": 1234
14 | "custom_2": "something else"
15 | "custom_3": true
16 |
17 | "Publisher-davis":
18 | "use_default": true
19 | "url": "tcp://127.0.0.1"
20 | "port": 5100
21 | "master_topic": "davis_1"
22 | "name": "davis_publisher"
23 | "device": "DAVIS"
24 | "noise_filter": true
25 | "use_default_pub": false
26 | "bias_file": "../configs/davis346_config.json"
27 | "custom_pub": "./custom_comm.py"
28 | "custom_class": "CustomPublisher"
29 | "custom_1": 123
30 | "custom_2": "something"
31 | "custom_3": false
32 |
--------------------------------------------------------------------------------
/pyaer/__init__.py:
--------------------------------------------------------------------------------
1 | """Properly init the package.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import absolute_import
7 | from __future__ import print_function
8 |
9 | import os
10 |
11 | from pyaer import log
12 | from pyaer.__about__ import __author__ # noqa
13 | from pyaer.__about__ import __version__ # noqa
14 |
15 | FILE_PATH = os.path.realpath(__file__)
16 | CURR_PATH = os.path.dirname(os.path.realpath(__file__))
17 | PKG_PATH = os.path.dirname(CURR_PATH)
18 |
19 | # System logging level
20 | LOG_LEVEL = log.DEBUG
21 |
22 | try:
23 | from pyaer import libcaer_wrap as libcaer # noqa
24 | except ImportError:
25 | raise ImportError(
26 | "libcaer might not be in the LD_LIBRARY_PATH "
27 | "or your numpy might not be the required version. "
28 | "Try to load _libcaer_wrap.so from the package "
29 | "directory, this will provide more information."
30 | )
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2022 Yuhuang Hu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/scripts/aer_comm/test_hdf5_reader.py:
--------------------------------------------------------------------------------
1 | """Test the HDF5 reader.
2 |
3 | Author: Yuhuang Hu
4 | Email : yuhuang.hu@ini.uzh.ch
5 | """
6 |
7 | from __future__ import print_function, absolute_import
8 |
9 | import os
10 | from contextlib import suppress
11 | from pyaer.comm import AERHDF5Reader
12 |
13 |
14 | data_path = os.path.join(
15 | os.environ["HOME"], "data", "pyaer_test.hdf5")
16 |
17 | reader = AERHDF5Reader(data_path)
18 |
19 | for device, groups in reader.get_keys().items():
20 | for group_name in groups:
21 |
22 | frame = reader.get_frame(device, group_name)
23 | events = reader.get_polarity_events(device, group_name)
24 | imu = reader.get_imu_events(device, group_name)
25 | special = reader.get_special_events(device, group_name)
26 |
27 | print("-"*50)
28 | with suppress(Exception):
29 | print("Frame:", frame.shape)
30 |
31 | with suppress(Exception):
32 | print("Events:", events.shape)
33 |
34 | with suppress(Exception):
35 | print("IMU:", imu.shape)
36 |
37 | with suppress(Exception):
38 | print("Special:", special.shape)
39 |
--------------------------------------------------------------------------------
/install-udev.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | touch /tmp/65-inivation.rules
3 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="152a", ATTR{idProduct}=="84[0-1]?", MODE="0666"
4 | ' >> /tmp/65-inivation.rules
5 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6014", MODE="0666"' >> /tmp/65-inivation.rules
6 |
7 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1134", ATTR{idProduct}=="8001", MODE="0666"' >> /tmp/65-inivation.rules
8 |
9 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="8613", MODE="0666"' >> /tmp/65-inivation.rules
10 |
11 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="0053", MODE="0666"' >> /tmp/65-inivation.rules
12 |
13 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="00f3", MODE="0666"' >> /tmp/65-inivation.rules
14 |
15 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="00f1", MODE="0666"' >> /tmp/65-inivation.rules
16 |
17 | # copied from https://gitlab.com/inivation/libcaer
18 | echo "Copying udev rule (needs root privileges)."
19 | sudo cp /tmp/65-inivation.rules /etc/udev/rules.d/
20 |
21 | echo "Reloading udev rules."
22 | sudo udevadm control --reload-rules
23 | sudo udevadm trigger
24 |
25 | echo "Done!"
26 |
--------------------------------------------------------------------------------
/README-RPI.md:
--------------------------------------------------------------------------------
1 | # Build PyAER on Raspberry Pi
2 |
3 | This is a working build instruction on Raspberry Pi 3B with Raspbian Stretch.
4 |
5 | ## Install dependencies
6 |
7 | ```bash
8 | sudo apt-get install build-essential cmake pkg-config libusb-1.0-0-dev
9 | sudo apt-get install automake bison libpcre3-dev
10 | ```
11 |
12 | ## Install `libcaer`
13 |
14 | The `libcaer` can be installed as follows
15 |
16 | ```bash
17 | git clone https://gitlab.com/inivation/dv/libcaer.git
18 | cd libcaer
19 | cmake -DCMAKE_INSTALL_PREFIX=/usr .
20 | make -j4
21 | sudo make install
22 | ```
23 |
24 | ## Install `swig`
25 |
26 | You can compile `swig` with the following steps:
27 |
28 | ```bash
29 | git clone https://github.com/duguyue100/swig
30 | cd swig
31 | ./autogen.sh
32 | # choose one of the configure settings
33 | ./configure --with-python=$(command -v python) --without-python2 --without-pcre # for python 3
34 | make -j4
35 | sudo make install
36 | ```
37 |
38 | ## Compile `pyaer`
39 |
40 | Compile `pyaer` with the following steps:
41 |
42 | ```bash
43 | git clone https://github.com/duguyue100/pyaer
44 | sudo make install
45 | ```
46 |
47 | ## Contacts
48 |
49 | Yuhuang Hu
50 | Email: duguyue100@gmail.com
51 |
--------------------------------------------------------------------------------
/pyaer/log.py:
--------------------------------------------------------------------------------
1 | """Logger for PyAER.
2 |
3 | NOTE: this is different from libcaer's logger.
4 |
5 | Author: Yuhuang Hu
6 | Email : duguyue100@gmail.com
7 | """
8 | import logging
9 | from logging import Logger
10 | from typing import Optional
11 | from typing import TextIO
12 |
13 | # Remaps logging levels for easy access.
14 | NOTSET = logging.NOTSET
15 | DEBUG = logging.DEBUG
16 | INFO = logging.INFO
17 | WARNING = logging.WARNING
18 | ERROR = logging.ERROR
19 | CRITICAL = logging.CRITICAL
20 |
21 |
22 | def get_logger(
23 | logger_name: Optional[str], logger_level: int, stream: Optional[TextIO] = None
24 | ) -> Logger:
25 | """Gets a logger for the script.
26 |
27 | Args:
28 | logger_name: the name of the logger.
29 | logger_level: the minimal level that trigger the logger.
30 | stream: If None, sys.stderr will be used.
31 |
32 | Returns:
33 | A logger to handel the logging in the script.
34 | """
35 | logger = logging.getLogger(name=logger_name)
36 | logger.setLevel(level=logger_level)
37 |
38 | ch = logging.StreamHandler(stream)
39 | ch.setLevel(level=logger_level)
40 |
41 | formatter = logging.Formatter(
42 | fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
43 | datefmt="%Y/%m/%d %I:%M:%S %p",
44 | )
45 | ch.setFormatter(formatter)
46 |
47 | logger.addHandler(ch)
48 |
49 | return logger
50 |
--------------------------------------------------------------------------------
/INSTALL_FROM_SOURCE.md:
--------------------------------------------------------------------------------
1 | # Install PyAER from Source
2 |
3 | ## Install `libcaer`
4 |
5 | ```bash
6 | # for Ubuntu
7 | sudo apt-get install libcaer-dev
8 | # for macOS
9 | brew install libcaer
10 | ```
11 |
12 | ## Install `swig`
13 |
14 | This repository uses SWIG to create Python bindings. And you will need to
15 | compile the latest SWIG from source. The reason is because current SWIG
16 | cannot handle some cases in `libcaer`, we made a modified SWIG for this purpose.
17 |
18 | 1. Install compilation dependency
19 |
20 | ```bash
21 | sudo apt-get install automake
22 | sudo apt-get install bison
23 | ```
24 |
25 | _There might be other dependencies for compiling SWIG_.
26 |
27 | 2. Compile SIWG
28 |
29 | ```bash
30 | git clone https://github.com/duguyue100/swig
31 | cd swig
32 | ./autogen.sh
33 | ./configure
34 | # For compiling SWIG with Python
35 | ./configure --without-alllang --with-python=$(command -v python)
36 | make -j4
37 | sudo make install
38 | ```
39 |
40 | __NOTE:__ For ARM-based Linux, you may also add `--without-pcre` to ignore the error during compilation.
41 |
42 | __NOTE:__ If you are not compile the SWIG with system Python distribution,
43 | it won't link to the custom Python automatically.
44 |
45 | You will need to configure `LD_LIBRARY_PATH` for swig running properly, i.e.,
46 |
47 | ```bash
48 | LD_LIBRARY_PATH=$HOME/miniconda/lib:$LD_LIBRARY_PATH swig
49 | ```
50 |
51 | ## Build `pyaer` from source
52 |
53 | ```bash
54 | git clone https://github.com/duguyue100/pyaer.git
55 | cd pyaer
56 | make develop
57 | ```
58 |
--------------------------------------------------------------------------------
/scripts/dvs128_test.py:
--------------------------------------------------------------------------------
1 | """DVS128 Test.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import numpy as np
9 | import cv2
10 |
11 | from pyaer.dvs128 import DVS128
12 |
13 | device = DVS128()
14 |
15 | print ("Device ID:", device.device_id)
16 | if device.device_is_master:
17 | print ("Device is master.")
18 | else:
19 | print ("Device is slave.")
20 | print ("Device Serial Number:", device.device_serial_number)
21 | print ("Device String:", device.device_string)
22 | print ("Device USB bus Number:", device.device_usb_bus_number)
23 | print ("Device USB device address:", device.device_usb_device_address)
24 | print ("Device size X:", device.dvs_size_X)
25 | print ("Device size Y:", device.dvs_size_Y)
26 | print ("Logic Version:", device.logic_version)
27 |
28 | device.start_data_stream()
29 | # load new config
30 | device.set_bias_from_json("./scripts/configs/dvs128_config.json")
31 | print (device.get_bias())
32 |
33 | clip_value = 3
34 | histrange = [(0, v) for v in (128, 128)]
35 |
36 | while True:
37 | try:
38 | (pol_events, num_pol_event,
39 | special_events, num_special_event) = \
40 | device.get_event("events_hist")
41 | if num_pol_event != 0:
42 | img = pol_events[..., 1]-pol_events[..., 0]
43 | img = np.clip(img, -clip_value, clip_value)
44 | img = img+clip_value
45 |
46 | cv2.imshow("image", img/float(clip_value*2))
47 | print ("Number of events:", num_pol_event, "Number of special events:",
48 | num_special_event)
49 |
50 | if cv2.waitKey(1) & 0xFF == ord('q'):
51 | break
52 |
53 | except KeyboardInterrupt:
54 | device.shutdown()
55 | break
56 |
--------------------------------------------------------------------------------
/scripts/dynapse_test.py:
--------------------------------------------------------------------------------
1 | """DYNAP-SE Test Example.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | from pyaer.dynapse import DYNAPSE
9 | from pyaer import utils
10 |
11 | device = DYNAPSE()
12 |
13 | print ("Device ID:", device.device_id)
14 | if device.device_is_master:
15 | print ("Device is master.")
16 | else:
17 | print ("Device is slave.")
18 | print ("Device Serial Number:", device.device_serial_number)
19 | print ("Device String:", device.device_string)
20 | print ("Device USB bus Number:", device.device_usb_bus_number)
21 | print ("Device USB device address:", device.device_usb_device_address)
22 | print ("Logic Version:", device.logic_version)
23 | print ("Logic Clock:", device.logic_clock)
24 | print ("Chip ID:", device.chip_id)
25 | print ("AER has statistics:", device.aer_has_statistics)
26 | print ("MUX has statistics:", device.mux_has_statistics)
27 |
28 | device.start_data_stream()
29 |
30 | bias_obj = utils.load_dynapse_bias("./scripts/configs/dynapse_config.json")
31 |
32 | # set bias from json file
33 | scope = {
34 | 0: [0, 1, 2, 3],
35 | }
36 |
37 | device.set_bias_from_json("./scripts/configs/dynapse_config.json",
38 | clear_sram=False, setup_sram=False,
39 | fpga_bias=True, scope=scope)
40 | # print FPGA biases
41 | print (device.get_fpga_bias())
42 |
43 | # set biases for a single chip
44 | device.set_chip_bias(bias_obj, chip_id=1)
45 |
46 | while True:
47 | try:
48 | events = device.get_event()
49 |
50 | if events is not None:
51 | print ("Number of events from DYNAPSE : %d" %
52 | (events[1]))
53 | except KeyboardInterrupt:
54 | print ("Device shutting down...")
55 | device.shutdown()
56 | break
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | swigpy/
2 | libcaer_wrap.py
3 | compile.conf
4 | pyflags_wrap.c
5 | *.lprof
6 |
7 | # Byte-compiled / optimized / DLL files
8 | __pycache__/
9 | *.py[cod]
10 | *$py.class
11 |
12 | # C extensions
13 | *.so
14 |
15 | # Distribution / packaging
16 | .Python
17 | env/
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | *.egg-info/
31 | .installed.cfg
32 | *.egg
33 |
34 | # PyInstaller
35 | # Usually these files are written by a python script from a template
36 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
37 | *.manifest
38 | *.spec
39 |
40 | # Installer logs
41 | pip-log.txt
42 | pip-delete-this-directory.txt
43 |
44 | # Unit test / coverage reports
45 | htmlcov/
46 | .tox/
47 | .coverage
48 | .coverage.*
49 | .cache
50 | nosetests.xml
51 | coverage.xml
52 | *.cover
53 | .hypothesis/
54 |
55 | # Translations
56 | *.mo
57 | *.pot
58 |
59 | # Django stuff:
60 | *.log
61 | local_settings.py
62 |
63 | # Flask stuff:
64 | instance/
65 | .webassets-cache
66 |
67 | # Scrapy stuff:
68 | .scrapy
69 |
70 | # Sphinx documentation
71 | docs/_build/
72 |
73 | # PyBuilder
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # pyenv
80 | .python-version
81 |
82 | # celery beat schedule file
83 | celerybeat-schedule
84 |
85 | # SageMath parsed files
86 | *.sage.py
87 |
88 | # dotenv
89 | .env
90 |
91 | # virtualenv
92 | .venv
93 | venv/
94 | ENV/
95 |
96 | # Spyder project settings
97 | .spyderproject
98 | .spyproject
99 |
100 | # Rope project settings
101 | .ropeproject
102 |
103 | # mkdocs documentation
104 | docs/site
105 | docs/sources
106 |
107 | # mypy
108 | .mypy_cache/
109 |
110 | # Mac
111 | .DS_Store
112 |
113 | # idea (jetbrains's ide)
114 | .idea
115 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_hub:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """AER Hub.
4 |
5 | Author: Yuhuang Hu
6 | Email : yuhuang.hu@ini.uzh.ch
7 | """
8 |
9 | from __future__ import print_function, absolute_import
10 |
11 | import json
12 | import argparse
13 |
14 | from pyaer.comm import AERHub
15 |
16 | parser = argparse.ArgumentParser("AER Hub")
17 |
18 | parser.add_argument("--url", type=str,
19 | default="tcp://127.0.0.1",
20 | help="AERHub URL")
21 |
22 | # Note that the publisher port and subscriber port are
23 | # hub_sub_port and hub_pub_port respectively.
24 | # This reversed order is intentional.
25 | # User doesn't need to know.
26 | parser.add_argument("--publisher_port", type=int,
27 | default=5100,
28 | help="the port that connects all publishers")
29 | parser.add_argument("--subscriber_port", type=int,
30 | default=5099,
31 | help="the port that connects all subscribers")
32 |
33 | parser.add_argument("--aer_hub_name", type=str,
34 | default="PyAER Message Hub")
35 |
36 | args = parser.parse_args()
37 |
38 | # print all options
39 | print("="*50)
40 | print(json.dumps(args.__dict__, indent=4, sort_keys=True))
41 | print("="*50)
42 |
43 |
44 | aer_hub = AERHub(url=args.url,
45 | hub_pub_port=args.subscriber_port,
46 | hub_sub_port=args.publisher_port,
47 | aer_hub_name=args.aer_hub_name)
48 |
49 | aer_hub.logger.info("="*50)
50 | aer_hub.logger.info("Tools")
51 | aer_hub.logger.info("aer_hub: launch a central message relay hub")
52 | aer_hub.logger.info("aer_lstopic: display all published topics")
53 | aer_hub.logger.info("aer_publisher: add a custom publisher")
54 | aer_hub.logger.info("aer_subscriber: add a custom subscriber")
55 | aer_hub.logger.info("aer_saver: add an AER Saver")
56 | aer_hub.logger.info("="*50)
57 |
58 | # run the hub
59 | aer_hub.run()
60 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_lstopic:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """List all available topics.
4 |
5 | Author: Yuhuang Hu
6 | Email : yuhuang.hu@ini.uzh.ch
7 | """
8 |
9 | from __future__ import print_function, absolute_import
10 |
11 | import os
12 | import argparse
13 | from pyaer.comm import AERSubscriber
14 |
15 |
16 | class ListSubscriber(AERSubscriber):
17 | def __init__(self, url="tcp://127.0.0.1",
18 | port=5099, topic='', name="Topic List"):
19 | """ListSubscriber.
20 |
21 | Used for list all the topics.
22 | """
23 | super().__init__(url=url, port=port, topic=topic, name=name)
24 |
25 | def run(self):
26 | topic_list = []
27 | while True:
28 | data = self.socket.recv_multipart()
29 |
30 | topic_name = self.unpack_data_name(
31 | data[:2], topic_name_only=True)
32 |
33 | if topic_name not in topic_list:
34 | topic_list.append(topic_name)
35 | topic_list.sort()
36 |
37 | # Clear screen and write
38 | os.system('cls' if os.name == 'nt' else 'clear')
39 | print("="*50)
40 | print("List of topic names")
41 | print("="*50)
42 | for tn in topic_list:
43 | print(tn)
44 | print("="*50)
45 |
46 |
47 | parser = argparse.ArgumentParser("AER List Topics")
48 |
49 | parser.add_argument("--url", type=str,
50 | default="tcp://127.0.0.1",
51 | help="AER list topic URL")
52 |
53 | # Note that the publisher port and subscriber port are
54 | # hub_sub_port and hub_pub_port respectively.
55 | # This reversed order is intentional.
56 | # User doesn't need to know.
57 | parser.add_argument("--port", type=int,
58 | default=5099,
59 | help="the port that connects all subscribers")
60 |
61 | args = parser.parse_args()
62 |
63 | list_sub = ListSubscriber(url=args.url, port=args.port)
64 |
65 | list_sub.run()
66 |
--------------------------------------------------------------------------------
/scripts/dvxplorer_test.py:
--------------------------------------------------------------------------------
1 | """DVXplorer Test.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function, absolute_import
7 |
8 | import numpy as np
9 | import cv2
10 |
11 | from pyaer.dvxplorer import DVXPLORER
12 |
13 | device = DVXPLORER()
14 |
15 | print("Device ID:", device.device_id)
16 | print("Device Serial Number:", device.device_serial_number)
17 | print("Device USB bus Number:", device.device_usb_bus_number)
18 | print("Device USB device address:", device.device_usb_device_address)
19 | print("Device String:", device.device_string)
20 | print("Device Firmware Version:", device.firmware_version)
21 | print("Logic Version:", device.logic_version)
22 | print("Device Chip ID:", device.chip_id)
23 | if device.device_is_master:
24 | print("Device is master.")
25 | else:
26 | print("Device is slave.")
27 | print("MUX has statistics:", device.mux_has_statistics)
28 | print("Device size X:", device.dvs_size_X)
29 | print("Device size Y:", device.dvs_size_Y)
30 | print("DVS has statistics:", device.dvs_has_statistics)
31 | print("IMU Type:", device.imu_type)
32 | print("EXT input has generator:", device.ext_input_has_generator)
33 |
34 | clip_value = 3
35 | histrange = [(0, v) for v in (device.dvs_size_Y, device.dvs_size_X)]
36 |
37 | device.start_data_stream()
38 | # load new config
39 | device.set_bias_from_json("./scripts/configs/dvxplorer_config.json")
40 |
41 | print(device.get_bias())
42 |
43 | while True:
44 | try:
45 | (pol_events, num_pol_event,
46 | special_events, num_special_event,
47 | imu_events, num_imu_event) = \
48 | device.get_event("events_hist")
49 |
50 | print("Number of events:", num_pol_event)
51 |
52 | if num_pol_event != 0:
53 | img = pol_events[..., 1]-pol_events[..., 0]
54 | img = np.clip(img, -clip_value, clip_value)
55 | img = (img+clip_value)/float(clip_value*2)
56 |
57 | cv2.imshow("image", img)
58 |
59 | cv2.waitKey(1)
60 |
61 | except KeyboardInterrupt:
62 | device.shutdown()
63 | cv2.destroyAllWindows()
64 | break
65 |
--------------------------------------------------------------------------------
/scripts/edvs_test.py:
--------------------------------------------------------------------------------
1 | """DVS128 Test.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import numpy as np
9 | import cv2
10 |
11 | from pyaer.edvs import eDVS
12 |
13 | device = eDVS()
14 |
15 | print ("Device ID:", device.device_id)
16 | if device.device_is_master:
17 | print ("Device is master.")
18 | else:
19 | print ("Device is slave.")
20 | print ("Device String:", device.device_string)
21 | print ("Device size X:", device.dvs_size_X)
22 | print ("Device size Y:", device.dvs_size_Y)
23 |
24 | device.start_data_stream()
25 | # load new config
26 | device.set_bias_from_json("./scripts/configs/edvs_config.json")
27 | print (device.get_bias())
28 |
29 | device.close()
30 |
31 | clip_value = 1
32 | histrange = [(0, v) for v in (128, 128)]
33 |
34 |
35 | # @profile
36 | def get_event(device):
37 | (pol_events, num_pol_event,
38 | special_events, num_special_event) = \
39 | device.get_event()
40 | if num_pol_event != 0:
41 | pol_on = (pol_events[:, 3] == 1)
42 | pol_off = np.logical_not(pol_on)
43 | img_on, _, _ = np.histogram2d(
44 | pol_events[pol_on, 2], pol_events[pol_on, 1],
45 | bins=(128, 128), range=histrange)
46 | img_off, _, _ = np.histogram2d(
47 | pol_events[pol_off, 2], pol_events[pol_off, 1],
48 | bins=(128, 128), range=histrange)
49 | if clip_value is not None:
50 | integrated_img = np.clip(
51 | (img_on-img_off), -clip_value, clip_value)
52 | else:
53 | integrated_img = (img_on-img_off)
54 | img = integrated_img+clip_value
55 |
56 | cv2.imshow("image", img/float(clip_value*2))
57 | print ("Number of events:", num_pol_event, "Number of special events:",
58 | num_special_event)
59 | del pol_events, num_pol_event, special_events, num_special_event
60 |
61 | if cv2.waitKey(1) & 0xFF == ord('q'):
62 | return
63 |
64 |
65 | while True:
66 | try:
67 | get_event(device)
68 |
69 | except KeyboardInterrupt:
70 | device.shutdown()
71 | break
72 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # This is a Python template Makefile, do modification as you want
2 | #
3 | # Project: PyAER
4 | # Author: Yuhuang Hu
5 | # Email : duguyue100@gmail.com
6 |
7 | PYTHONPATH="$(shell printenv PYTHONPATH):$(PWD)"
8 | PYTHONLIBPATH="$(shell python -c 'from sysconfig import get_paths; print(get_paths()["stdlib"]+"/..")')"
9 | PYTHONLIBPATHWIN="$(shell python -c 'from sysconfig import get_paths; print(get_paths()["stdlib"]+"\..")')"
10 |
11 | clean:
12 | find . -name '*.pyc' -exec rm --force {} +
13 | find . -name '*.pyo' -exec rm --force {} +
14 | find . -name '*~' -exec rm --force {} +
15 |
16 | dvs128-test:
17 | python ./scripts/dvs128_test.py
18 |
19 | edvs-test:
20 | python ./scripts/edvs_test.py
21 |
22 | dvs128-thread-test:
23 | python ./scripts/dvs128_thread_test.py
24 |
25 | dvs128-vispy:
26 | python ./scripts/dvs128_vispy.py
27 |
28 | dvs128-glumpy:
29 | python ./scripts/dvs128_glumpy.py
30 |
31 | davis240-test:
32 | python ./scripts/davis240_test.py
33 |
34 | davis346-test:
35 | python ./scripts/davis346_test.py
36 |
37 | davis346-color-test:
38 | python ./scripts/davis346_color_test.py
39 |
40 | davis346-color-events:
41 | python ./scripts/davis346_color_events.py
42 |
43 | dvxplorer-test:
44 | python ./scripts/dvxplorer_test.py
45 |
46 | dynapse-test:
47 | python ./scripts/dynapse_test.py
48 |
49 | dvs-noise-filter-test:
50 | python ./scripts/dvs_noise_filter_test.py
51 |
52 | device-discovery:
53 | python ./scripts/device_discovery.py
54 |
55 | event-container-test:
56 | python ./scripts/event_container_test.py
57 |
58 | install:
59 | LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(PYTHONLIBPATH) python setup.py install
60 |
61 | develop:
62 | LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(PYTHONLIBPATH) python setup.py develop
63 |
64 | develop-uninstall:
65 | LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(PYTHONLIBPATH) python setup.py develop --uninstall
66 |
67 | build-pyaer:
68 | LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(PYTHONLIBPATH) python setup.py build
69 |
70 | build-win:
71 | LD_LIBRARY_PATH=$(PYTHONLIBPATHWIN) python setup.py build -cmingw32
72 |
73 | build-wheel:
74 | LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(PYTHONLIBPATH) python setup.py bdist_wheel
75 |
76 | cleanall:
77 |
--------------------------------------------------------------------------------
/scripts/configs/davis240c_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "DiffBn_coarse": 4,
3 | "DiffBn_fine": 39,
4 | "ONBn_coarse": 6,
5 | "ONBn_fine": 200,
6 | "OFFBn_coarse": 4,
7 | "OFFBn_fine": 0,
8 | "APSCasEPC_coarse": 5,
9 | "APSCasEPC_fine": 185,
10 | "DiffCasBNC_coarse": 5,
11 | "DiffCasBNC_fine": 115,
12 | "APSROSFBn_coarse": 6,
13 | "APSROSFBn_fine": 219,
14 | "LocalBufBn_coarse": 5,
15 | "LocalBufBn_fine": 164,
16 | "PixInvBn_coarse": 5,
17 | "PixInvBn_fine": 129,
18 | "PrBp_coarse": 2,
19 | "PrBp_fine": 58,
20 | "PrSFBp_coarse": 1,
21 | "PrSFBp_fine": 33,
22 | "RefrBp_coarse": 4,
23 | "RefrBp_fine": 25,
24 | "AEPdBn_coarse": 6,
25 | "AEPdBn_fine": 91,
26 | "LcolTimeoutBn_coarse": 5,
27 | "LcolTimeoutBn_fine": 49,
28 | "AEPuXBp_coarse": 4,
29 | "AEPuXBp_fine": 80,
30 | "AEPuYBp_coarse": 7,
31 | "AEPuYBp_fine": 152,
32 | "IFThrBn_coarse": 5,
33 | "IFThrBn_fine": 255,
34 | "IFRefrBn_coarse": 5,
35 | "IFRefrBn_fine": 255,
36 | "PadFollBn_coarse": 7,
37 | "PadFollBn_fine": 215,
38 | "APSOverflowLevelBn_coarse": 6,
39 | "APSOverflowLevelBn_fine": 253,
40 | "BiasBuffer_coarse": 5,
41 | "BiasBuffer_fine": 254,
42 | "aps_enabled": true,
43 | "dvs_enabled": true,
44 | "exposure": 4000,
45 | "autoexposure": true,
46 | "frame_interval": 0,
47 | "imu_enabled": true,
48 | "imu_acc_scale": 3,
49 | "imu_gyro_scale": 3,
50 | "imu_low_pass_filter": 0,
51 | "noise_filter_configs": {
52 | "sw_background_activity_two_levels": true,
53 | "sw_background_activity_check_polarity": true,
54 | "sw_background_activity_support_min": 2,
55 | "sw_background_activity_support_max": 8,
56 | "sw_background_activity_time": 2000,
57 | "sw_background_activity_enable": true,
58 | "sw_refractory_period_time": 200,
59 | "sw_refractory_period_enable": true,
60 | "sw_hotpixel_enable": true,
61 | "sw_hotpixel_learn": true
62 | },
63 | "ext_input_enabled": false,
64 | "detect_falling_edges": false,
65 | "detect_rising_edges": false,
66 | "detect_pulses": false,
67 | "detect_pulse_length": 60,
68 | "detect_pulse_polarity": false
69 | }
70 |
--------------------------------------------------------------------------------
/custom_build/README.md:
--------------------------------------------------------------------------------
1 | # Customize Building Process
2 |
3 | This folder contains a compile script that performs
4 | customized build for pyaer.
5 | We replaced this version of build to a easier building process.
6 | This script is here for the legacy reasons.
7 |
8 |
9 | ## Some old logs
10 |
11 | 1. Install `libcaer` dependency
12 |
13 | ```
14 | $ sudo apt-get install libusb-1.0-0-dev
15 | ```
16 |
17 | __NOTE:__ For more information, see [`libcaer` repo](https://github.com/inilabs/libcaer).
18 |
19 | 2. Download this repo
20 |
21 | ```
22 | $ git clone --recursive https://github.com/duguyue100/pyaer-beta.git
23 | ```
24 | 3. Change `compile.conf.bak` to `compile.conf` and configure Python executable
25 |
26 | ```
27 | cd pyaer-beta
28 | cp compile.conf.bak compile.conf
29 | ```
30 |
31 | The configuration file looks like
32 |
33 | ```bash
34 | # Turn it to true if you are building the repository for the first time
35 | REBUILDING=false
36 |
37 | # defien python version (experimental)
38 | # only support python 2 at this moment
39 | PYTHON_VERSION=2
40 |
41 | # define python executable
42 | CONDA_LIB_PATH=$HOME/anaconda2/lib
43 | CONDA_PKG_CONFIG_PATH=$CONDA_LIB_PATH/pkgconfig
44 |
45 | # false if build libcaer locally
46 | # true if you have a system installed libcaer
47 | LIBCAER_INSTALLED=false
48 | ```
49 |
50 | 4. Make this repository and install it!
51 |
52 | ```
53 | $ ./compile make
54 | $ ./compile make.install
55 | ```
56 |
57 | __NOTE:__ This repository is designed to be compiled and run within local
58 | directory, nothing to pollute your system because this is in active
59 | development.
60 |
61 | 5. (Optional) if you want to clean the installation, just type
62 |
63 | ```
64 | $ ./compile clean
65 | ```
66 |
67 | 6. (Optional) The available commands for the compilation script are:
68 |
69 | + `make`: make `libcaer` and SWIG binding
70 | + `make.swig`: make SWIG binding only
71 | + `make.lib` : make `libcaer`
72 | + `make.install`: Install compiled wrapper to the package
73 | + `clean`: clean SWIG compilation, `libcaer` and installation
74 | + `clean.swig`: clean SWIG
75 | + `clean.lib` : clean `libcaer` compilation
76 | + `clean.install` : clean installation
77 | + `help`: print help info
78 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_subscriber:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """AER Subscriber
4 |
5 | Author: Yuhuang Hu
6 | Email : duguyue100@gmail.com
7 | """
8 |
9 | from __future__ import print_function, absolute_import
10 |
11 | import json
12 | import argparse
13 |
14 | from pyaer.utils import expandpath, import_custom_module
15 | from pyaer.utils import parse_custom_args
16 | from pyaer.comm import AERSubscriber
17 |
18 | parser = argparse.ArgumentParser()
19 | parser.add_argument("--url", type=str,
20 | default="tcp://127.0.0.1",
21 | help="AER Subscriber URL")
22 | parser.add_argument("--port", type=int,
23 | default=5099,
24 | help="the port that connects this subscriber")
25 | parser.add_argument("--topic", type=str,
26 | default="",
27 | help="Topic to subscribe")
28 | parser.add_argument("--name", type=str,
29 | default="",
30 | help="Name of the subscriber")
31 |
32 | parser.add_argument("--use_default_sub", action="store_true")
33 |
34 | parser.add_argument("--custom_sub", type=expandpath,
35 | default="",
36 | help="path to the custom publisher class")
37 | parser.add_argument("--custom_class", type=str,
38 | default="",
39 | help="custom publisher class name")
40 |
41 |
42 | args, custom_args = parser.parse_known_args()
43 |
44 | custom_args_dict = parse_custom_args(custom_args)
45 |
46 | # print all options
47 | print("="*50)
48 | print(json.dumps(
49 | {**args.__dict__, **custom_args_dict},
50 | indent=4, sort_keys=True))
51 | print("="*50)
52 |
53 | # define subscriber
54 | if args.use_default_sub:
55 | # fall back to the default publisher
56 | subscriber = AERSubscriber(
57 | url=args.url, port=args.port, topic=args.topic,
58 | name=args.name)
59 | subscriber.logger.info("Use default subscriber")
60 | else:
61 | # use custom publisher
62 | CustomSubscriber = import_custom_module(args.custom_sub, args.custom_class)
63 | subscriber = CustomSubscriber(
64 | url=args.url, port=args.port, topic=args.topic, name=args.name,
65 | **custom_args_dict)
66 | subscriber.logger.info(
67 | "Use custom subscriber {}".format(args.custom_class))
68 |
69 | # Start sending data
70 | subscriber.run()
71 |
--------------------------------------------------------------------------------
/scripts/davis240_test.py:
--------------------------------------------------------------------------------
1 | """DAVIS240 test example.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import numpy as np
9 | import cv2
10 |
11 | from pyaer import libcaer
12 | from pyaer.davis import DAVIS
13 |
14 | device = DAVIS(noise_filter=True)
15 |
16 | print ("Device ID:", device.device_id)
17 | if device.device_is_master:
18 | print ("Device is master.")
19 | else:
20 | print ("Device is slave.")
21 | print ("Device Serial Number:", device.device_serial_number)
22 | print ("Device String:", device.device_string)
23 | print ("Device USB bus Number:", device.device_usb_bus_number)
24 | print ("Device USB device address:", device.device_usb_device_address)
25 | print ("Device size X:", device.dvs_size_X)
26 | print ("Device size Y:", device.dvs_size_Y)
27 | print ("Logic Version:", device.logic_version)
28 | print ("Background Activity Filter:",
29 | device.dvs_has_background_activity_filter)
30 |
31 |
32 | device.start_data_stream()
33 | # set new bias after data streaming
34 | device.set_bias_from_json("./scripts/configs/davis240c_config.json")
35 |
36 | clip_value = 3
37 | histrange = [(0, v) for v in (180, 240)]
38 |
39 |
40 | def get_event(device):
41 | data = device.get_event("events_hist")
42 |
43 | return data
44 |
45 |
46 | # num_packet_before_disable = 1000
47 |
48 | while True:
49 | try:
50 | data = get_event(device)
51 | if data is not None:
52 | (pol_events, num_pol_event,
53 | special_events, num_special_event,
54 | frames_ts, frames, imu_events,
55 | num_imu_event) = data
56 | if frames.shape[0] != 0:
57 | cv2.imshow("frame", frames[0])
58 |
59 | print ("Number of events:", num_pol_event, "Number of Frames:",
60 | frames.shape, "Exposure:",
61 | device.get_config(
62 | libcaer.DAVIS_CONFIG_APS,
63 | libcaer.DAVIS_CONFIG_APS_EXPOSURE))
64 |
65 | if num_pol_event != 0:
66 | img = pol_events[..., 1]-pol_events[..., 0]
67 | img = np.clip(img, -clip_value, clip_value)
68 | img = img+clip_value
69 |
70 | cv2.imshow("image", img/float(clip_value*2))
71 |
72 | if cv2.waitKey(1) & 0xFF == ord('q'):
73 | break
74 |
75 | else:
76 | pass
77 |
78 | except KeyboardInterrupt:
79 | device.shutdown()
80 | break
81 |
--------------------------------------------------------------------------------
/scripts/configs/davis346_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "ADC_RefHigh_volt": 32,
3 | "ADC_RefHigh_curr": 7,
4 | "ADC_RefLow_volt": 1,
5 | "ADC_RefLow_curr": 7,
6 | "LocalBufBn_coarse": 5,
7 | "LocalBufBn_fine": 164,
8 | "PadFollBn_coarse": 7,
9 | "PadFollBn_fine": 215,
10 | "DiffBn_coarse": 4,
11 | "DiffBn_fine": 39,
12 | "ONBn_coarse": 6,
13 | "ONBn_fine": 255,
14 | "OFFBn_coarse": 4,
15 | "OFFBn_fine": 1,
16 | "PixInvBn_coarse": 5,
17 | "PixInvBn_fine": 129,
18 | "PrBp_coarse": 2,
19 | "PrBp_fine": 58,
20 | "PrSFBp_coarse": 1,
21 | "PrSFBp_fine": 16,
22 | "RefrBp_coarse": 4,
23 | "RefrBp_fine": 25,
24 | "ReadoutBufBp_coarse": 6,
25 | "ReadoutBufBp_fine": 20,
26 | "APSROSFBn_coarse": 6,
27 | "APSROSFBn_fine": 219,
28 | "ADCCompBp_coarse": 5,
29 | "ADCCompBp_fine": 20,
30 | "COLSELLowBn_coarse": 0,
31 | "COLSELLowBn_fine": 1,
32 | "DACBufBp_coarse": 6,
33 | "DACBufBp_fine": 60,
34 | "LcolTimeoutBn_coarse": 5,
35 | "LcolTimeoutBn_fine": 49,
36 | "AEPdBn_coarse": 6,
37 | "AEPdBn_fine": 91,
38 | "AEPuXBp_coarse": 4,
39 | "AEPuXBp_fine": 80,
40 | "AEPuYBp_coarse": 7,
41 | "AEPuYBp_fine": 152,
42 | "IFRefrBn_coarse": 5,
43 | "IFRefrBn_fine": 255,
44 | "IFThrBn_coarse": 5,
45 | "IFThrBn_fine": 255,
46 | "BiasBuffer_coarse": 5,
47 | "BiasBuffer_fine": 254,
48 | "aps_enabled": true,
49 | "dvs_enabled": true,
50 | "exposure": 30000,
51 | "autoexposure": false,
52 | "frame_interval": 0,
53 | "imu_enabled": true,
54 | "imu_acc_scale": 3,
55 | "imu_gyro_scale": 3,
56 | "imu_low_pass_filter": 0,
57 | "background_activity_filter_enabled": true,
58 | "background_activity_filter_time": 80,
59 | "refractory_period_enabled": true,
60 | "refractory_period_time": 2,
61 | "noise_filter_configs": {
62 | "sw_background_activity_two_levels": true,
63 | "sw_background_activity_check_polarity": true,
64 | "sw_background_activity_support_min": 2,
65 | "sw_background_activity_support_max": 8,
66 | "sw_background_activity_time": 2000,
67 | "sw_background_activity_enable": true,
68 | "sw_refractory_period_time": 200,
69 | "sw_refractory_period_enable": true,
70 | "sw_hotpixel_enable": true,
71 | "sw_hotpixel_learn": true
72 | },
73 | "ext_input_enabled": false,
74 | "detect_falling_edges": false,
75 | "detect_rising_edges": false,
76 | "detect_pulses": false,
77 | "detect_pulse_length": 60,
78 | "detect_pulse_polarity": false
79 | }
80 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_pubsuber:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """AER PubSuber.
4 |
5 | Because PubSuber mainly serves as a processing unit,
6 | so we support only custom implementation.
7 |
8 | Author: Yuhuang Hu
9 | Email : duguyue100@gmail.com
10 | """
11 |
12 | from __future__ import print_function, absolute_import
13 |
14 | import argparse
15 | import json
16 |
17 | from pyaer.utils import expandpath, import_custom_module
18 | from pyaer.utils import parse_custom_args
19 |
20 | parser = argparse.ArgumentParser()
21 | parser.add_argument("--url", type=str,
22 | default="tcp://127.0.0.1",
23 | help="AER Publisher URL")
24 |
25 | parser.add_argument("--pub_port", type=int,
26 | default=5100,
27 | help="the port that connects this publisher")
28 | parser.add_argument("--pub_topic", type=str,
29 | default="device",
30 | help="publish topic name for the publisher")
31 | parser.add_argument("--pub_name", type=str,
32 | default="",
33 | help="Name of the publisher")
34 |
35 | parser.add_argument("--sub_port", type=int,
36 | default=5099,
37 | help="the port that connects this subscriber")
38 | parser.add_argument("--sub_topic", type=str,
39 | default="",
40 | help="subscriber topic name for the subscriber")
41 | parser.add_argument("--sub_name", type=str,
42 | default="",
43 | help="Name of the subscriber")
44 |
45 | parser.add_argument("--custom_pubsuber", type=expandpath,
46 | default="",
47 | help="path to the custom PubSuber class")
48 | parser.add_argument("--custom_class", type=str,
49 | default="",
50 | help="custom publisher class name")
51 |
52 | args, custom_args = parser.parse_known_args()
53 |
54 | custom_args_dict = parse_custom_args(custom_args)
55 |
56 | # print all options
57 | print("="*50)
58 | print(json.dumps(
59 | {**args.__dict__, **custom_args_dict},
60 | indent=4, sort_keys=True))
61 | print("="*50)
62 |
63 |
64 | # define publisher
65 | # use custom publisher
66 | CustomPubSuber = import_custom_module(args.custom_pubsuber, args.custom_class)
67 | pubsuber = CustomPubSuber(
68 | url=args.url,
69 | pub_port=args.pub_port, pub_topic=args.pub_topic, pub_name=args.pub_name,
70 | sub_port=args.sub_port, sub_topic=args.sub_topic, sub_name=args.sub_name,
71 | **custom_args_dict)
72 | pubsuber.logger.info("Use custom PubSuber {}".format(args.custom_class))
73 |
74 | # Start sending data
75 | pubsuber.run()
76 |
--------------------------------------------------------------------------------
/custom_build/install-libcaer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This file has become a legacy script for CI building.
4 | # Now we are using the official libcaer build for CI/CD
5 |
6 | CI_BUILD=false
7 | # TODO: To support
8 | LIBSERIAL_PORT_OPTION=false
9 |
10 | # parse option
11 | if [ ! -z "$1" -a "$1" = "ci" ]; then
12 | echo "[MESSAGE] This is a CI build."
13 | CI_BUILD=true
14 | elif [ ! -z "$1" -a "$1" = "libserial" ]; then
15 | echo "[MESSAGE] Enable libserial."
16 | LIBSERIAL_PORT_OPTION=true
17 | elif [ ! -z "$1" -a "$1" = "ci.libserial" ]; then
18 | echo "[MESSAGE] This is a CI build and enable libserial."
19 | CI_BUILD=true
20 | LIBSERIAL_PORT_OPTION=true
21 | fi
22 |
23 | case "$(uname -s)" in
24 | Darwin)
25 | echo 'Installing libcaer to a macOS'
26 | if [ $CI_BUILD = false ]; then
27 | brew install cmake pkg-config libusb
28 | git clone https://gitlab.com/inivation/dv/libcaer /tmp/libcaer
29 | cd /tmp/libcaer
30 | else
31 | git clone https://gitlab.com/inivation/dv/libcaer
32 | cd libcaer
33 | fi
34 | cmake -DCMAKE_INSTALL_PREFIX=/usr/local .
35 | make -j2
36 | sudo make install
37 | ;;
38 |
39 | Linux)
40 | echo 'Installing libcaer to a Debian platform'
41 | if [ $CI_BUILD = false ]; then
42 | sudo apt-get update
43 | sudo apt-get install build-essential pkg-config libusb-1.0-0-dev
44 | git clone https://gitlab.com/inivation/dv/libcaer /tmp/libcaer
45 | cd /tmp/libcaer
46 | else
47 | git clone https://gitlab.com/inivation/dv/libcaer
48 | cd libcaer
49 | fi
50 | # wget https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.sh -O $HOME/cmake.sh
51 | # sudo bash $HOME/cmake.sh --prefix=/usr/local --skip-license
52 | cmake -DCMAKE_INSTALL_PREFIX=/usr .
53 | make -j2
54 | sudo make install
55 | ;;
56 |
57 | CYGWIN*|MINGW*|MSYS*)
58 | echo 'Installing libcaer to MS Windows'
59 | if [ $CI_BUILD = false ]; then
60 | pacman --noconfirm -S mingw-w64-x86_64-gcc
61 | pacman --noconfirm -S make mingw-w64-x86_64-cmake
62 | pacman --noconfirm -S mingw-w64-x86_64-pkg-config
63 | pacman --noconfirm -S mingw-w64-x86_64-libusb
64 | pacman --noconfirm -S automake bison
65 | git clone https://gitlab.com/inivation/dv/libcaer /home/libcaer
66 | fi
67 | cd /home/libcaer
68 | cmake -G 'MSYS Makefiles' -DCMAKE_INSTALL_PREFIX=/mingw64 .
69 | make -j2
70 | make install
71 | ;;
72 |
73 | *)
74 | echo 'other OS'
75 | ;;
76 | esac
77 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: PyAER Build and Test
2 |
3 | on:
4 | push:
5 | release:
6 | types: [published]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ${{ matrix.os }}
12 | strategy:
13 | matrix:
14 | os: [ubuntu-latest, macos-latest]
15 | python-version: ["3.8", "3.9", "3.10"]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up Python ${{ matrix.python-version }}
20 | uses: actions/setup-python@v2
21 | with:
22 | python-version: ${{ matrix.python-version }}
23 | - name: Install Ubuntu dependencies
24 | if: ${{ matrix.os == 'ubuntu-latest' }}
25 | run: |
26 | gcc --version;
27 | sudo apt-get install build-essential -y;
28 | sudo apt-get install libusb-1.0-0-dev -y;
29 | sudo apt-get install cmake -y;
30 | sudo add-apt-repository ppa:inivation-ppa/inivation -y;
31 | sudo apt-get update;
32 | sudo apt-get install libcaer-dev -y;
33 | - name: Install macos dependencies
34 | if: ${{ matrix.os == 'macos-latest' }}
35 | run: |
36 | gcc --version;
37 | brew install automake;
38 | brew install bison;
39 | brew tap inivation/inivation;
40 | brew install libcaer --with-libserialport --with-opencv;
41 | - name: Install PyAER specific dependencies
42 | run: |
43 | git clone https://github.com/duguyue100/swig
44 | cd swig
45 | ./autogen.sh
46 | ./configure --without-alllang --with-python=$(command -v python) --without-pcre
47 | make -j4
48 | sudo make install
49 | cd ..
50 | pip install pip -U
51 | pip install numpy
52 | pip install wheel
53 | - name: Build PyAER
54 | run: |
55 | make build-wheel
56 | make build-wheel
57 | make install
58 | - name: Find and manage file
59 | run: |
60 | cd $GITHUB_WORKSPACE/dist
61 | ls -a
62 | for file in *.whl ; do mv $file ${file//linux/manylinux1} ; done;
63 | rm *.egg;
64 | ls -a
65 | cd ..
66 | - name: Publish package to Github releases
67 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
68 | uses: svenstaro/upload-release-action@v2
69 | with:
70 | repo_token: ${{ secrets.GITHUB_TOKEN }}
71 | file: dist/*.*
72 | tag: ${{ github.ref }}
73 | file_glob: true
74 | - name: Publish package to PyPI
75 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
76 | run: |
77 | pip install twine;
78 | twine upload -u __token__ -p ${{ secrets.PYPI_API_TOKEN }} dist/*.whl;
79 |
--------------------------------------------------------------------------------
/scripts/event_container_test.py:
--------------------------------------------------------------------------------
1 | """Testing Event Container.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import cv2
9 | import numpy as np
10 |
11 | from pyaer import libcaer
12 | from pyaer.davis import DAVIS
13 |
14 | from timer import Timer
15 |
16 | device = DAVIS(noise_filter=True)
17 |
18 | print("Device ID:", device.device_id)
19 | if device.device_is_master:
20 | print("Device is master.")
21 | else:
22 | print("Device is slave.")
23 | print("Device Serial Number:", device.device_serial_number)
24 | print("Device String:", device.device_string)
25 | print("Device USB bus Number:", device.device_usb_bus_number)
26 | print("Device USB device address:", device.device_usb_device_address)
27 | print("Device size X:", device.dvs_size_X)
28 | print("Device size Y:", device.dvs_size_Y)
29 | print("Logic Version:", device.logic_version)
30 | print("Background Activity Filter:",
31 | device.dvs_has_background_activity_filter)
32 | print("Color Filter", device.aps_color_filter, type(device.aps_color_filter))
33 | print(device.aps_color_filter == 1)
34 |
35 | device.start_data_stream()
36 | # setting bias after data stream started
37 | device.set_bias_from_json("./scripts/configs/davis346_config.json")
38 |
39 | clip_value = 3
40 | histrange = [(0, v) for v in (260, 346)]
41 |
42 |
43 | def get_event(device):
44 | data = device.get_event()
45 |
46 | return data
47 |
48 |
49 | num_packet_before_disable = 1000
50 |
51 | while True:
52 | try:
53 | with Timer("container_test", show_hist=True):
54 | event_container = device.get_event_container()
55 |
56 | if event_container is not None:
57 | print("Duration (s): {}, Num Events: {}, Event Rate (ev/s): {}"
58 | .format(
59 | event_container.pol_event_duration,
60 | event_container.num_pol_events,
61 | event_container.pol_event_rate))
62 | print("Signal Rate (ev/s): {}, Noise Rate (ev/s): {}"
63 | .format(
64 | event_container.valid_pol_events_rate,
65 | event_container.invalid_pol_events_rate))
66 |
67 | # print("Number of events:", num_pol_event, "Number of Frames:",
68 | # frames.shape, "Exposure:",
69 | # device.get_config(
70 | # libcaer.DAVIS_CONFIG_APS,
71 | # libcaer.DAVIS_CONFIG_APS_EXPOSURE),
72 | # "Autoexposure:", device.get_config(
73 | # libcaer.DAVIS_CONFIG_APS,
74 | # libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE))
75 | else:
76 | pass
77 |
78 | except KeyboardInterrupt:
79 | device.shutdown()
80 | break
81 |
--------------------------------------------------------------------------------
/pyaer/container.py:
--------------------------------------------------------------------------------
1 | """Event Container.
2 |
3 | Motivation: After the events are read from the event packet,
4 | it's difficult to use and less informative to return them
5 | as single variables, therefore, I decide to introduce a
6 | container that can manage all the returned Python variables.
7 |
8 | Author: Yuhuang Hu
9 | Email : duguyue100@gmail.com
10 | """
11 |
12 | from typing import Optional
13 |
14 | import numpy as np
15 |
16 |
17 | class EventContainer(object):
18 | """Event container that packs everything.
19 |
20 | Args:
21 | pol_events: polarity events array.
22 | special_events: special events.
23 | frames: APS frame events.
24 | frames_ts: APS frame time stamp.
25 | imu_events: IMU events.
26 | """
27 |
28 | def __init__(
29 | self,
30 | pol_events: np.ndarray,
31 | special_events: Optional[np.ndarray] = None,
32 | frames: Optional[np.ndarray] = None,
33 | frames_ts: Optional[np.ndarray] = None,
34 | imu_events: Optional[np.ndarray] = None,
35 | ) -> None:
36 | self.pol_events = pol_events
37 | self.num_pol_events = 0 if pol_events is None else pol_events.shape[0]
38 | self.compute_event_stats()
39 |
40 | self.special_events = special_events
41 | self.num_special_events = (
42 | None if special_events is None else special_events.shape[0]
43 | )
44 |
45 | self.frames = frames
46 | self.frames_ts = frames_ts
47 |
48 | self.imu_events = imu_events
49 | self.num_imu_events = None if imu_events is None else imu_events.shape[0]
50 |
51 | def compute_event_stats(self) -> None:
52 | """Calculate event stats."""
53 | self.pol_event_duration = None
54 | self.pol_event_rate = None
55 |
56 | self.num_valid_pol_events = None
57 | self.num_invalid_pol_events = None
58 | self.valid_pol_events_rate = None
59 | self.invalid_pol_events_rate = None
60 |
61 | if self.num_pol_events > 1:
62 | # in seconds
63 | self.pol_event_duration = (
64 | self.pol_events[-1, 0] - self.pol_events[0, 0]
65 | ) / 1e6
66 |
67 | self.pol_event_rate = self.num_pol_events / self.pol_event_duration
68 |
69 | # additional stats if has background filter
70 | if self.pol_events.shape[1] == 5:
71 | self.num_valid_pol_events = self.pol_events[:, -1].sum()
72 | self.num_invalid_pol_events = (
73 | self.num_pol_events - self.num_valid_pol_events
74 | )
75 |
76 | self.valid_pol_events_rate = (
77 | self.num_valid_pol_events / self.pol_event_duration
78 | )
79 | self.invalid_pol_events_rate = (
80 | self.num_invalid_pol_events / self.pol_event_duration
81 | )
82 |
--------------------------------------------------------------------------------
/scripts/dvs_noise_filter_test.py:
--------------------------------------------------------------------------------
1 | """Testing DVS Noise filter implementation.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function, absolute_import
7 |
8 | import cv2
9 | import numpy as np
10 |
11 | from pyaer.dvs128 import DVS128
12 |
13 | device = DVS128(noise_filter=True)
14 |
15 | print ("Device ID:", device.device_id)
16 | if device.device_is_master:
17 | print ("Device is master.")
18 | else:
19 | print ("Device is slave.")
20 | print ("Device Serial Number:", device.device_serial_number)
21 | print ("Device String:", device.device_string)
22 | print ("Device USB bus Number:", device.device_usb_bus_number)
23 | print ("Device USB device address:", device.device_usb_device_address)
24 | print ("Device size X:", device.dvs_size_X)
25 | print ("Device size Y:", device.dvs_size_Y)
26 | print ("Logic Version:", device.logic_version)
27 |
28 | device.start_data_stream()
29 | # load new config
30 | device.set_bias_from_json("./scripts/configs/dvs128_config.json")
31 | print (device.get_bias())
32 |
33 | clip_value = 1
34 | histrange = [(0, v) for v in (128, 128)]
35 |
36 |
37 | num_packet_before_disable = 1000
38 |
39 |
40 | def get_event(device):
41 | global num_packet_before_disable
42 | (pol_events, num_pol_event,
43 | special_events, num_special_event) = \
44 | device.get_event()
45 | if num_pol_event != 0:
46 | if num_packet_before_disable > 0:
47 | pol_events = pol_events[pol_events[:, 4] == 1]
48 | num_packet_before_disable -= 1
49 | else:
50 | device.disable_noise_filter()
51 | print ("Noise filter disabled")
52 |
53 | pol_on = (pol_events[:, 3] == 1)
54 | pol_off = np.logical_not(pol_on)
55 | img_on, _, _ = np.histogram2d(
56 | pol_events[pol_on, 2], pol_events[pol_on, 1],
57 | bins=(128, 128), range=histrange)
58 | img_off, _, _ = np.histogram2d(
59 | pol_events[pol_off, 2], pol_events[pol_off, 1],
60 | bins=(128, 128), range=histrange)
61 | if clip_value is not None:
62 | integrated_img = np.clip(
63 | (img_on-img_off), -clip_value, clip_value)
64 | else:
65 | integrated_img = (img_on-img_off)
66 | img = integrated_img+clip_value
67 |
68 | cv2.imshow("image", img/float(clip_value*2))
69 | print ("Number of events:", num_pol_event, "Number of special events:",
70 | num_special_event)
71 | del pol_events, num_pol_event, special_events, num_special_event
72 |
73 | if cv2.waitKey(1) & 0xFF == ord('q'):
74 | return
75 |
76 |
77 | while True:
78 | try:
79 | get_event(device)
80 |
81 | except KeyboardInterrupt:
82 | hot_pixels = device.noise_filter.get_hot_pixels()
83 | print (hot_pixels)
84 | print (device.noise_filter.get_bias())
85 | device.shutdown()
86 | break
87 |
--------------------------------------------------------------------------------
/docs/pages/index.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://github.com/duguyue100/pyaer)
4 | [](https://pypi.org/project/pyaer/)
5 | [](https://travis-ci.org/duguyue100/pyaer)
6 | [](https://ci.appveyor.com/project/duguyue100/pyaer/branch/master)
7 | [](https://github.com/duguyue100/pyaer/blob/master/LICENSE)
8 |
9 | 
10 | 
11 | 
12 | 
13 |
14 | PyAER with Swig Bindings
15 |
16 | Special thanks to [iniLabs](http://inilabs.com/) for making this possible.
17 |
18 | The project is in its Beta development stage, please submit an [issue](https://github.com/duguyue100/pyaer/issues) if you need our help.
19 |
20 | ## Design Principle
21 |
22 | + Minimum installation effort
23 | + Keep Python 2 and 3 in mind
24 | + Clean, simple, easy to manage
25 | + Well documented, human-readable code
26 |
27 | ## Installation
28 |
29 | #### 1. Install bleeding-edge `libcaer` dependency (RECOMMEND)
30 |
31 | ```bash
32 | $ bash <(curl -s https://raw.githubusercontent.com/duguyue100/pyaer/master/install-libcaer.sh)
33 | ```
34 |
35 | __NOTE:__ To build `libcaer` on Windows, please follow [this description](https://github.com/inilabs/libcaer/blob/master/README.Windows).
36 |
37 | __NOTE:__ For more information, see [`libcaer` repo](https://github.com/inilabs/libcaer).
38 |
39 | __NOTE:__ From 0.1.0a18, we support eDVS, you will need to install `libserialport` so that the package can work properly, follow the building instructions from [here](https://sigrok.org/wiki/Libserialport). Currently, this support is not built into the release since we are not clear how useful is this feature. If you are interested, you can build the project from scratch.
40 |
41 | #### 2. Directly install from pypi (RECOMMEND)
42 |
43 | ```bash
44 | $ pip install pyaer -U
45 | ```
46 |
47 | #### 3. Install from source
48 |
49 | ```bash
50 | $ git clone https://github.com/duguyue100/pyaer.git
51 | $ make install
52 | ```
53 |
54 | ## Got a Linux?
55 |
56 | `libcaer` relies on `libusb` based driver, you won't be able
57 | to access the camera unless fixing the `udev` rules. Refer to details
58 | at [here](https://inivation.com/support/hardware/davis240/#linux).
59 |
60 | ```bash
61 | $ bash <(curl -s https://raw.githubusercontent.com/duguyue100/pyaer/master/install-udev.sh)
62 | ```
63 |
64 |
65 |
--------------------------------------------------------------------------------
/scripts/aer_comm/custom_comm.py:
--------------------------------------------------------------------------------
1 | """Custom Publisher and Subscriber.
2 |
3 | Author: Yuhuang Hu
4 | Email : yuhuang.hu@ini.uzh.ch
5 | """
6 |
7 | from __future__ import print_function, absolute_import
8 |
9 | import time
10 | import cv2
11 |
12 | from pyaer.comm import AERPublisher, AERSubscriber
13 |
14 |
15 | class CustomPublisher(AERPublisher):
16 |
17 | def __init__(self, device, url, port, master_topic, name, **kwargs):
18 | super().__init__(
19 | device=device, url=url, port=port, master_topic=master_topic,
20 | **kwargs)
21 |
22 | def run_once(self, verbose=False):
23 | data = self.device.get_event()
24 |
25 | if data is not None:
26 | # data = self.pack_frame_events
27 | #
28 | # self.socket.send_multipart(data)
29 |
30 | t = time.localtime()
31 |
32 | curr_time = time.strftime("%H:%M:%S", t)
33 |
34 | print("Publishing {}".format(curr_time))
35 |
36 |
37 | class CustomSubscriber(AERSubscriber):
38 |
39 | def __init__(self, url, port, topic, name, **kwargs):
40 | super().__init__(url, port, topic, name, **kwargs)
41 |
42 | for arg in kwargs.values():
43 | print(arg)
44 |
45 | def run_once(self, verbose=False):
46 | data = self.socket.recv_multipart()
47 |
48 | topic_name = self.unpack_data_name(
49 | data[:2], topic_name_only=True)
50 |
51 | if "frame" in topic_name:
52 | data_id, frame_events, frame_ts = \
53 | self.unpack_frame_events(data)
54 |
55 | if frame_events is not None:
56 | try:
57 | frame = cv2.cvtColor(
58 | frame_events[0],
59 | cv2.COLOR_BGR2RGB)
60 | frame = cv2.resize(frame, (1384, 1040))
61 | cv2.imshow("frame", frame)
62 | if cv2.waitKey(1) & 0xFF == ord('q'):
63 | return
64 | except Exception:
65 | pass
66 |
67 |
68 | class DVViewerSubscriber(AERSubscriber):
69 |
70 | def __init__(self, url, port, topic, name, **kwargs):
71 | super().__init__(url, port, topic, name, **kwargs)
72 |
73 | for arg in kwargs.values():
74 | print(arg)
75 |
76 | def run_once(self, verbose=False):
77 | data = self.socket.recv_multipart()
78 |
79 | topic_name = self.unpack_data_name(
80 | data[:2], topic_name_only=True)
81 |
82 | if "frame" in topic_name:
83 | data_id, frame_events, frame_ts = \
84 | self.unpack_frame_events(data)
85 |
86 | if frame_events is not None:
87 | try:
88 | cv2.imshow(
89 | "frame",
90 | cv2.cvtColor(
91 | frame_events[0],
92 | cv2.COLOR_BGR2RGB))
93 | if cv2.waitKey(1) & 0xFF == ord('q'):
94 | return
95 | except Exception:
96 | pass
97 |
--------------------------------------------------------------------------------
/scripts/dvs128_thread_test.py:
--------------------------------------------------------------------------------
1 | """DVS128 Threaded Test.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | from queue import Queue
9 | import threading
10 | import numpy as np
11 | import cv2
12 |
13 | from pyaer.dvs128 import DVS128
14 |
15 | device = DVS128()
16 |
17 | print ("Device ID:", device.device_id)
18 | if device.device_is_master:
19 | print ("Device is master.")
20 | else:
21 | print ("Device is slave.")
22 | print ("Device Serial Number:", device.device_serial_number)
23 | print ("Device String:", device.device_string)
24 | print ("Device USB bus Number:", device.device_usb_bus_number)
25 | print ("Device USB device address:", device.device_usb_device_address)
26 | print ("Device size X:", device.dvs_size_X)
27 | print ("Device size Y:", device.dvs_size_Y)
28 | print ("Logic Version:", device.logic_version)
29 |
30 | # load new config
31 | device.set_bias_from_json("./scripts/configs/dvs128_config.json")
32 | print (device.get_bias())
33 |
34 | device.start_data_stream()
35 |
36 | # global variable
37 | clip_value = 3
38 | histrange = [(0, v) for v in (128, 128)]
39 |
40 |
41 | def drawing_func(in_q):
42 | while threading.currentThread().isAlive():
43 | try:
44 | (pol_events, num_pol_event,
45 | special_events, num_special_event) = in_q.get()
46 | if num_pol_event != 0:
47 | pol_on = (pol_events[:, 3] == 1)
48 | pol_off = np.logical_not(pol_on)
49 | img_on, _, _ = np.histogram2d(
50 | pol_events[pol_on, 2], pol_events[pol_on, 1],
51 | bins=(128, 128), range=histrange)
52 | img_off, _, _ = np.histogram2d(
53 | pol_events[pol_off, 1], pol_events[pol_off, 0],
54 | bins=(128, 128), range=histrange)
55 | if clip_value is not None:
56 | integrated_img = np.clip(
57 | (img_on-img_off), -clip_value, clip_value)
58 | else:
59 | integrated_img = (img_on-img_off)
60 | img = integrated_img+clip_value
61 | cv2.imshow("image", img/float(clip_value*2))
62 | cv2.waitKey(1)
63 | except KeyboardInterrupt:
64 | device.shutdown()
65 | break
66 |
67 |
68 | def fetching_func(out_q):
69 | while threading.currentThread().isAlive():
70 | try:
71 | event_packet = device.get_event()
72 | print ("Number of events:", event_packet[1],
73 | "Number of special events:",
74 | event_packet[3])
75 | out_q.put(event_packet)
76 | except KeyboardInterrupt:
77 | device.shutdown()
78 | break
79 |
80 |
81 | if __name__ == "__main__":
82 | # define thread
83 | q = Queue(maxsize=1)
84 | drawer = threading.Thread(
85 | name="drawer", target=drawing_func, args=(q, ))
86 | fetcher = threading.Thread(
87 | name="fetcher", target=fetching_func, args=(q, ))
88 |
89 | fetcher.start()
90 | print ("fetcher started")
91 | drawer.start()
92 | print ("drawer started")
93 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """Setup script for the pyaer package.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import absolute_import
7 | from __future__ import print_function
8 |
9 | import os
10 | from sys import platform
11 | from sysconfig import get_paths
12 |
13 | import numpy
14 | from setuptools import find_packages
15 | from setuptools import setup
16 | from setuptools.extension import Extension
17 |
18 | classifiers = """
19 | Development Status :: 4 - Beta
20 | Intended Audience :: Science/Research
21 | Natural Language :: English
22 | Operating System :: OS Independent
23 | Programming Language :: Python :: 3.8
24 | Programming Language :: Python :: 3.9
25 | Programming Language :: Python :: 3.10
26 | Topic :: Utilities
27 | Topic :: Scientific/Engineering
28 | Topic :: Scientific/Engineering :: Artificial Intelligence
29 | Topic :: Software Development :: Libraries :: Python Modules
30 | License :: OSI Approved :: MIT License
31 | """
32 |
33 | try:
34 | from pyaer import __about__
35 |
36 | about = __about__.__dict__
37 | except ImportError:
38 | about = dict()
39 | exec(open("pyaer/__about__.py").read(), about)
40 |
41 | python_paths = get_paths()
42 |
43 | try:
44 | numpy_include = numpy.get_include()
45 | except AttributeError:
46 | numpy_include = numpy.get_numpy_include() # type: ignore
47 |
48 | if platform in ["linux", "linux2"]:
49 | libcaer_include = "/usr/include"
50 | libcaer_lib = "/usr/lib/x86_64-linux-gnu"
51 |
52 | # for Raspberry Pi support
53 | if os.uname()[1] == "raspberrypi":
54 | libcaer_lib = "/usr/lib/arm-linux-gnueabihf"
55 | elif platform == "darwin":
56 | libcaer_include = "/opt/homebrew/include"
57 | libcaer_lib = "/opt/homebrew/lib"
58 | elif "win" in platform:
59 | libcaer_include = "C:/msys64/mingw64/include"
60 | libcaer_lib = "C:/msys64/mingw64/lib"
61 |
62 | include_dirs = [libcaer_include, python_paths["include"], numpy_include]
63 | library_dirs = [libcaer_lib, python_paths["stdlib"]]
64 | swig_opts = ["-I" + libcaer_include]
65 | if platform == "darwin":
66 | include_dirs += ["/usr/local/include"]
67 | library_dirs += ["/usr/local/lib"]
68 | swig_opts += ["-I/usr/local/include"]
69 |
70 | libcaer_wrap = Extension(
71 | name="pyaer._libcaer_wrap",
72 | sources=["./pyaer/pyflags.i"],
73 | include_dirs=include_dirs,
74 | library_dirs=library_dirs,
75 | swig_opts=swig_opts,
76 | # extra_compile_args=["-std=c11"],
77 | extra_link_args=["-lcaer"],
78 | )
79 |
80 | setup(
81 | name="pyaer",
82 | version=about["__version__"],
83 | author=about["__author__"],
84 | author_email=about["__author_email__"],
85 | url=about["__url__"],
86 | install_requires=["numpy"],
87 | packages=find_packages(),
88 | ext_modules=[libcaer_wrap],
89 | scripts=[
90 | "scripts/aer_comm/aer_hub",
91 | "scripts/aer_comm/aer_lstopic",
92 | "scripts/aer_comm/aer_publisher",
93 | "scripts/aer_comm/aer_subscriber",
94 | "scripts/aer_comm/aer_pubsuber",
95 | "scripts/aer_comm/aer_launch",
96 | "scripts/aer_comm/aer_saver",
97 | ],
98 | classifiers=list(filter(None, classifiers.split("\n"))),
99 | description="PyAER: Low-level Python APIs for Accessing Neuromorphic Devices.",
100 | )
101 |
--------------------------------------------------------------------------------
/pyaer/pyfragments.swg:
--------------------------------------------------------------------------------
1 | /*-*- C -*-*/
2 |
3 | /**********************************************************************/
4 |
5 | /* For numpy versions prior to 1.0, the names of certain data types
6 | * are different than in later versions. This fragment provides macro
7 | * substitutions that allow us to support old and new versions of
8 | * numpy.
9 | */
10 |
11 | /**********************************************************************/
12 |
13 | /* Override the SWIG_AsVal_frag(long) fragment so that it also checks
14 | * for numpy scalar array types. The code through the %#endif is
15 | * essentially cut-and-paste from pyprimtype.swg
16 | */
17 |
18 | %fragment(SWIG_AsVal_frag(long), "header",
19 | fragment="SWIG_CanCastAsInteger",
20 | fragment="NumPy_Backward_Compatibility")
21 | {
22 | SWIGINTERN int
23 | SWIG_AsVal_dec(long)(PyObject * obj, long * val)
24 | {
25 | if (PyLong_Check(obj)) {
26 | long v = PyLong_AsLong(obj);
27 | if (v != -1 || !PyErr_Occurred()) {
28 | if (val) *val = v;
29 | return SWIG_OK;
30 | } else {
31 | PyErr_Clear();
32 | }
33 | }
34 | %#ifdef SWIG_PYTHON_CAST_MODE
35 | {
36 | int dispatch = 0;
37 | long v = PyLong_AsLong(obj);
38 | if (v != -1 || !PyErr_Occurred()) {
39 | if (val) *val = v;
40 | return SWIG_AddCast(SWIG_OK);
41 | } else {
42 | PyErr_Clear();
43 | }
44 | if (!dispatch) {
45 | double d;
46 | int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d));
47 | if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
48 | if (val) *val = (long)(d);
49 | return res;
50 | }
51 | }
52 | }
53 | %#endif
54 | if (!PyArray_IsScalar(obj,Integer)) return SWIG_TypeError;
55 | PyArray_Descr * longDescr = PyArray_DescrFromType(NPY_LONG);
56 | PyArray_CastScalarToCtype(obj, (void*)val, longDescr);
57 | Py_DECREF(longDescr);
58 | return SWIG_OK;
59 | }
60 | }
61 |
62 |
63 | /* Override the SWIG_AsVal_frag(unsigned long) fragment so that it
64 | * also checks for numpy scalar array types. The code through the
65 | * %#endif is essentially cut-and-paste from pyprimtype.swg
66 | */
67 |
68 | %fragment(SWIG_AsVal_frag(unsigned long),"header",
69 | fragment="SWIG_CanCastAsInteger",
70 | fragment="NumPy_Backward_Compatibility")
71 | {
72 | SWIGINTERN int
73 | SWIG_AsVal_dec(unsigned long)(PyObject *obj, unsigned long *val)
74 | {
75 | if (PyLong_Check(obj)) {
76 | unsigned long v = PyLong_AsUnsignedLong(obj);
77 | if (!PyErr_Occurred()) {
78 | if (val) *val = v;
79 | return SWIG_OK;
80 | } else {
81 | PyErr_Clear();
82 | }
83 | }
84 | %#ifdef SWIG_PYTHON_CAST_MODE
85 | {
86 | int dispatch = 0;
87 | unsigned long v = PyLong_AsUnsignedLong(obj);
88 | if (!PyErr_Occurred()) {
89 | if (val) *val = v;
90 | return SWIG_AddCast(SWIG_OK);
91 | } else {
92 | PyErr_Clear();
93 | }
94 | if (!dispatch) {
95 | double d;
96 | int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d));
97 | if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) {
98 | if (val) *val = (unsigned long)(d);
99 | return res;
100 | }
101 | }
102 | }
103 | %#endif
104 | if (!PyArray_IsScalar(obj,Integer)) return SWIG_TypeError;
105 | PyArray_Descr * ulongDescr = PyArray_DescrFromType(NPY_ULONG);
106 | PyArray_CastScalarToCtype(obj, (void*)val, ulongDescr);
107 | Py_DECREF(ulongDescr);
108 | return SWIG_OK;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/scripts/dvs128_glumpy.py:
--------------------------------------------------------------------------------
1 | """DVS128 Test.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import threading
9 |
10 | import numpy as np
11 | from glumpy import app, gloo, gl
12 |
13 | from pyaer.dvs128 import DVS128
14 |
15 |
16 | device = DVS128()
17 |
18 | print ("Device ID:", device.device_id)
19 | if device.device_is_master:
20 | print ("Device is master.")
21 | else:
22 | print ("Device is slave.")
23 | print ("Device Serial Number:", device.device_serial_number)
24 | print ("Device String:", device.device_string)
25 | print ("Device USB bus Number:", device.device_usb_bus_number)
26 | print ("Device USB device address:", device.device_usb_device_address)
27 | print ("Device size X:", device.dvs_size_X)
28 | print ("Device size Y:", device.dvs_size_Y)
29 | print ("Logic Version:", device.logic_version)
30 |
31 | data_stream = False
32 |
33 | lock = threading.Lock()
34 |
35 | clip_value = 3
36 | histrange = [(0, v) for v in (128, 128)]
37 |
38 | vertex = """
39 | attribute vec2 position;
40 | attribute vec2 texcoord;
41 | varying vec2 v_texcoord;
42 | void main()
43 | {
44 | gl_Position = vec4(position, 0.0, 1.0);
45 | v_texcoord = texcoord;
46 | }
47 | """
48 |
49 | fragment = """
50 | uniform sampler2D texture;
51 | varying vec2 v_texcoord;
52 | void main()
53 | {
54 | gl_FragColor = texture2D(texture, v_texcoord);
55 | }
56 | """
57 |
58 | window = app.Window(width=1024, height=1024, aspect=1)
59 |
60 | img_array = (np.random.uniform(
61 | 0, 1, (128, 128, 3))*250).astype(np.uint8)
62 |
63 |
64 | @window.event
65 | def on_close():
66 | global device
67 |
68 | print ("Shutting down the device")
69 | device.shutdown()
70 | del device
71 |
72 |
73 | @window.event
74 | def on_draw(dt):
75 | global data_stream, device, event_list
76 | window.clear()
77 |
78 | if data_stream is False:
79 | device.start_data_stream()
80 | # setting bias after data stream
81 | device.set_bias_from_json("./scripts/configs/dvs128_config.json")
82 | data_stream = True
83 |
84 | lock.acquire()
85 | (pol_events, num_pol_event,
86 | special_events, num_special_event) = \
87 | device.get_event()
88 |
89 | if num_pol_event != 0:
90 | pol_on = (pol_events[:, 3] == 1)
91 | pol_off = np.logical_not(pol_on)
92 | img_on, _, _ = np.histogram2d(
93 | pol_events[pol_on, 2], pol_events[pol_on, 1],
94 | bins=(128, 128), range=histrange)
95 | img_off, _, _ = np.histogram2d(
96 | pol_events[pol_off, 2], pol_events[pol_off, 1],
97 | bins=(128, 128), range=histrange)
98 | if clip_value is not None:
99 | integrated_img = np.clip(
100 | (img_on-img_off), -clip_value, clip_value)
101 | else:
102 | integrated_img = (img_on-img_off)
103 |
104 | img_array = ((integrated_img+clip_value)/float(
105 | clip_value*2)*255).astype(np.uint8)
106 | img_array = img_array[..., np.newaxis].repeat(3, axis=2)
107 | else:
108 | img_array = (np.random.uniform(
109 | 0, 1, (128, 128, 3))*250).astype(np.uint8)
110 |
111 | quad["texture"] = img_array
112 | quad.draw(gl.GL_TRIANGLE_STRIP)
113 | lock.release()
114 |
115 |
116 | quad = gloo.Program(vertex, fragment, count=4)
117 | quad['position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)]
118 | quad['texcoord'] = [(0, 1), (0, 0), (1, 1), (1, 0)]
119 | quad['texture'] = img_array
120 | app.run(framerate=150)
121 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_publisher:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """AER Publisher.
4 |
5 | Author: Yuhuang Hu
6 | Email : duguyue100@gmail.com
7 | """
8 |
9 | from __future__ import print_function, absolute_import
10 |
11 | import argparse
12 | import json
13 |
14 | from pyaer.davis import DAVIS
15 | from pyaer.dvs128 import DVS128
16 | from pyaer.dvxplorer import DVXPLORER
17 | from pyaer.utils import expandpath, import_custom_module
18 | from pyaer.utils import parse_custom_args
19 | from pyaer.comm import AERPublisher
20 |
21 | parser = argparse.ArgumentParser()
22 | parser.add_argument("--url", type=str,
23 | default="tcp://127.0.0.1",
24 | help="AER Publisher URL")
25 | parser.add_argument("--port", type=int,
26 | default=5100,
27 | help="the port that connects this publisher")
28 | parser.add_argument("--master_topic", type=str,
29 | default="device",
30 | help="Master topic name for the publisher")
31 | parser.add_argument("--name", type=str,
32 | default="",
33 | help="Name of the publisher")
34 |
35 | parser.add_argument("--device", type=str,
36 | default="DAVIS",
37 | help="Currently supported options: DAVIS, DVS, DVXPLORER")
38 | parser.add_argument("--noise_filter", action="store_true",
39 | help="Add option to enable noise filter.")
40 | parser.add_argument("--bias_file", type=expandpath,
41 | default=None,
42 | help="Optional bias file")
43 |
44 | parser.add_argument("--use_default_pub", action="store_true")
45 |
46 | parser.add_argument("--custom_pub", type=expandpath,
47 | default="",
48 | help="path to the custom publisher class")
49 | parser.add_argument("--custom_class", type=str,
50 | default="",
51 | help="custom publisher class name")
52 |
53 | args, custom_args = parser.parse_known_args()
54 |
55 | custom_args_dict = parse_custom_args(custom_args)
56 |
57 | # print all options
58 | print("="*50)
59 | print(json.dumps(
60 | {**args.__dict__, **custom_args_dict},
61 | indent=4, sort_keys=True))
62 | print("="*50)
63 |
64 | # open the device
65 | if args.device == "None":
66 | device = None
67 | else:
68 | if args.device == "DAVIS":
69 | device = DAVIS(noise_filter=args.noise_filter)
70 | elif args.device == "DVS":
71 | device = DVS128(noise_filter=args.noise_filter)
72 | elif args.device == "DVXPLORER":
73 | device = DVXPLORER(noise_filter=args.noise_filter)
74 |
75 | device.start_data_stream()
76 | if args.bias_file is not None:
77 | device.set_bias_from_json(args.bias_file)
78 |
79 | # define publisher
80 | if args.use_default_pub:
81 | # fall back to the default publisher
82 | publisher = AERPublisher(device=device,
83 | url=args.url,
84 | port=args.port,
85 | master_topic=args.master_topic,
86 | name=args.name)
87 | publisher.logger.info("Use default publisher")
88 | else:
89 | # use custom publisher
90 | CustomPublisher = import_custom_module(args.custom_pub, args.custom_class)
91 | publisher = CustomPublisher(
92 | device=device,
93 | url=args.url, port=args.port, master_topic=args.master_topic,
94 | name=args.name,
95 | **custom_args_dict)
96 | publisher.logger.info("Use custom publisher {}".format(args.custom_class))
97 |
98 | # Start sending data
99 | publisher.run()
100 |
--------------------------------------------------------------------------------
/scripts/davis346_test.py:
--------------------------------------------------------------------------------
1 | """DAVIS346 test example.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import cv2
9 | import numpy as np
10 |
11 | from pyaer import libcaer
12 | from pyaer.davis import DAVIS
13 |
14 | device = DAVIS(noise_filter=True)
15 |
16 | print ("Device ID:", device.device_id)
17 | if device.device_is_master:
18 | print ("Device is master.")
19 | else:
20 | print ("Device is slave.")
21 | print ("Device Serial Number:", device.device_serial_number)
22 | print ("Device String:", device.device_string)
23 | print ("Device USB bus Number:", device.device_usb_bus_number)
24 | print ("Device USB device address:", device.device_usb_device_address)
25 | print ("Device size X:", device.dvs_size_X)
26 | print ("Device size Y:", device.dvs_size_Y)
27 | print ("Logic Version:", device.logic_version)
28 | print ("Background Activity Filter:",
29 | device.dvs_has_background_activity_filter)
30 |
31 | device.start_data_stream()
32 | # setting bias after data stream started
33 | device.set_bias_from_json("./scripts/configs/davis346_config.json")
34 |
35 | clip_value = 3
36 | histrange = [(0, v) for v in (260, 346)]
37 |
38 |
39 | def get_event(device):
40 | data = device.get_event()
41 |
42 | return data
43 |
44 |
45 | num_packet_before_disable = 1000
46 |
47 | while True:
48 | try:
49 | data = get_event(device)
50 | if data is not None:
51 | (pol_events, num_pol_event,
52 | special_events, num_special_event,
53 | frames_ts, frames, imu_events,
54 | num_imu_event) = data
55 | if frames.shape[0] != 0:
56 | cv2.imshow("frame", frames[0])
57 |
58 | print("Number of events:", num_pol_event, "Number of Frames:",
59 | frames.shape, "Exposure:",
60 | device.get_config(
61 | libcaer.DAVIS_CONFIG_APS,
62 | libcaer.DAVIS_CONFIG_APS_EXPOSURE),
63 | "Autoexposure:", device.get_config(
64 | libcaer.DAVIS_CONFIG_APS,
65 | libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE))
66 |
67 | if num_pol_event != 0:
68 | if num_packet_before_disable > 0:
69 | print(pol_events[:, 4].sum())
70 | pol_events = pol_events[pol_events[:, 4] == 1]
71 | num_packet_before_disable -= 1
72 | else:
73 | device.disable_noise_filter()
74 | print("Noise filter disabled")
75 | pol_on = (pol_events[:, 3] == 1)
76 | pol_off = np.logical_not(pol_on)
77 | img_on, _, _ = np.histogram2d(
78 | pol_events[pol_on, 2], pol_events[pol_on, 1],
79 | bins=(260, 346), range=histrange)
80 | img_off, _, _ = np.histogram2d(
81 | pol_events[pol_off, 2], pol_events[pol_off, 1],
82 | bins=(260, 346), range=histrange)
83 | if clip_value is not None:
84 | integrated_img = np.clip(
85 | (img_on-img_off), -clip_value, clip_value)
86 | else:
87 | integrated_img = (img_on-img_off)
88 | img = integrated_img+clip_value
89 |
90 | cv2.imshow("image", img/float(clip_value*2))
91 |
92 | if cv2.waitKey(1) & 0xFF == ord('q'):
93 | break
94 | else:
95 | pass
96 |
97 | except KeyboardInterrupt:
98 | device.shutdown()
99 | break
100 |
--------------------------------------------------------------------------------
/scripts/davis346_color_test.py:
--------------------------------------------------------------------------------
1 | """DAVIS346 test example.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import cv2
9 | import numpy as np
10 |
11 | from pyaer import libcaer
12 | from pyaer.davis import DAVIS
13 |
14 | device = DAVIS(noise_filter=True, color_filter=True)
15 |
16 | print("Device ID:", device.device_id)
17 | if device.device_is_master:
18 | print("Device is master.")
19 | else:
20 | print("Device is slave.")
21 | print("Device Serial Number:", device.device_serial_number)
22 | print("Device String:", device.device_string)
23 | print("Device USB bus Number:", device.device_usb_bus_number)
24 | print("Device USB device address:", device.device_usb_device_address)
25 | print("Device size X:", device.dvs_size_X)
26 | print("Device size Y:", device.dvs_size_Y)
27 | print("Logic Version:", device.logic_version)
28 | print("Background Activity Filter:",
29 | device.dvs_has_background_activity_filter)
30 | print("Color Filter", device.aps_color_filter, type(device.aps_color_filter))
31 | print(device.aps_color_filter == 1)
32 |
33 | device.start_data_stream()
34 | # setting bias after data stream started
35 | device.set_bias_from_json("./scripts/configs/davis346_config.json")
36 |
37 | clip_value = 3
38 | histrange = [(0, v) for v in (260, 346)]
39 |
40 |
41 | def get_event(device):
42 | data = device.get_event()
43 |
44 | return data
45 |
46 |
47 | num_packet_before_disable = 1000
48 |
49 | while True:
50 | try:
51 | data = get_event(device)
52 | if data is not None:
53 | (pol_events, num_pol_event,
54 | special_events, num_special_event,
55 | frames_ts, frames, imu_events,
56 | num_imu_event) = data
57 | if frames.shape[0] != 0:
58 | frame = cv2.cvtColor(frames[0], cv2.COLOR_BGR2RGB)
59 | cv2.imshow("frame", frame)
60 |
61 | if pol_events is not None:
62 | print("Number of events:", pol_events.shape,
63 | "Number of Frames:",
64 | frames.shape, "Exposure:",
65 | device.get_config(
66 | libcaer.DAVIS_CONFIG_APS,
67 | libcaer.DAVIS_CONFIG_APS_EXPOSURE),
68 | "Autoexposure:", device.get_config(
69 | libcaer.DAVIS_CONFIG_APS,
70 | libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE),
71 | "Color:", pol_events[0, 5])
72 |
73 | if num_pol_event != 0:
74 | if num_packet_before_disable > 0:
75 | print(pol_events[:, 4].sum())
76 | pol_events = pol_events[pol_events[:, 4] == 1]
77 | num_packet_before_disable -= 1
78 | else:
79 | device.disable_noise_filter()
80 | print("Noise filter disabled")
81 | pol_on = (pol_events[:, 3] == 1)
82 | pol_off = np.logical_not(pol_on)
83 | img_on, _, _ = np.histogram2d(
84 | pol_events[pol_on, 2], pol_events[pol_on, 1],
85 | bins=(260, 346), range=histrange)
86 | img_off, _, _ = np.histogram2d(
87 | pol_events[pol_off, 2], pol_events[pol_off, 1],
88 | bins=(260, 346), range=histrange)
89 | if clip_value is not None:
90 | integrated_img = np.clip(
91 | (img_on-img_off), -clip_value, clip_value)
92 | else:
93 | integrated_img = (img_on-img_off)
94 | img = integrated_img+clip_value
95 |
96 | cv2.imshow("image", img/float(clip_value*2))
97 |
98 | if cv2.waitKey(1) & 0xFF == ord('q'):
99 | break
100 | else:
101 | pass
102 |
103 | except KeyboardInterrupt:
104 | device.shutdown()
105 | break
106 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_saver:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """AER Saver.
4 |
5 | Author: Yuhuang Hu
6 | Email : duguyue100@gmail.com
7 | """
8 |
9 | from __future__ import print_function, absolute_import
10 |
11 | import json
12 | import argparse
13 |
14 | from pyaer.utils import expandpath
15 | from pyaer.comm import AERSubscriber
16 | from pyaer.comm import AERHDF5Saver, AERZarrSaver
17 |
18 |
19 | class AERSaverSubscriber(AERSubscriber):
20 | def __init__(self, url, port, topic, name):
21 | super().__init__(url=url, port=port, topic=topic, name=name)
22 |
23 | def set_saver(self, saver):
24 | self.saver = saver
25 |
26 | def run(self):
27 | while True:
28 | try:
29 | data = self.socket.recv_multipart()
30 |
31 | topic_name = self.unpack_data_name(
32 | data[:2], topic_name_only=True)
33 |
34 | # you can select some of these functions to use
35 | if "polarity" in topic_name:
36 | data_id, polarity_events = \
37 | self.unpack_polarity_events(data)
38 | if polarity_events is not None:
39 | self.saver.save(data_id, polarity_events)
40 | elif "special" in topic_name:
41 | data_id, special_events = self.unpack_special_events(data)
42 | if special_events is not None:
43 | self.saver.save(data_id, special_events)
44 | elif "frame" in topic_name:
45 | data_id, frame_events, frame_ts = \
46 | self.unpack_frame_events(data)
47 | if frame_events is not None:
48 | self.saver.save(data_id, frame_events)
49 | elif "imu" in topic_name:
50 | data_id, imu_events = self.unpack_imu_events(data)
51 | if imu_events is not None:
52 | self.saver.save(data_id, imu_events)
53 | except KeyboardInterrupt:
54 | self.logger.info("Closing saver before shutting down")
55 | self.saver.close()
56 | break
57 |
58 |
59 | parser = argparse.ArgumentParser()
60 | parser.add_argument("--url", type=str,
61 | default="tcp://127.0.0.1",
62 | help="AER Subscriber URL")
63 | parser.add_argument("--port", type=int,
64 | default=5099,
65 | help="the port that connects this subscriber")
66 | parser.add_argument("--topic", type=str,
67 | default="",
68 | help="Topic to subscribe")
69 | parser.add_argument("--name", type=str,
70 | default="")
71 |
72 | parser.add_argument("--filename", type=expandpath,
73 | default="record.hdf5",
74 | help="Path to save record")
75 | parser.add_argument("--mode", type=str,
76 | default="w-",
77 | help="opening mode")
78 |
79 | parser.add_argument("--hdf5", action="store_true",
80 | help="use HDF5 as saver")
81 | parser.add_argument("--zarr", action="store_true",
82 | help="use Zarr as saver")
83 |
84 | # HDF5 specific arguments
85 | parser.add_argument("--libver", type=str,
86 | default="latest",
87 | help="HDF5 library version.")
88 |
89 | # Zarr specific arguments
90 |
91 |
92 | args = parser.parse_args()
93 |
94 | # print all options
95 | print("="*50)
96 | print(json.dumps(args.__dict__, indent=4, sort_keys=True))
97 | print("="*50)
98 |
99 |
100 | if args.hdf5:
101 | # use HDF5 as saver
102 | saver = AERHDF5Saver(filename=args.filename,
103 | mode=args.mode,
104 | libver=args.libver)
105 | elif args.zarr:
106 | # use Zarr as saver
107 | saver = AERZarrSaver(filename=args.filename, mode=args.mode)
108 | raise ValueError("It's not so useful right now")
109 | else:
110 | raise ValueError("No saver selected, use --hdf5 or --zarr")
111 |
112 | saver_sub = AERSaverSubscriber(
113 | url=args.url, port=args.port, topic=args.topic,
114 | name=args.name)
115 |
116 | # set saver
117 | saver_sub.set_saver(saver)
118 |
119 | saver_sub.logger.info("AER Saver initialized.")
120 |
121 | # Start sending data
122 | saver_sub.run()
123 |
--------------------------------------------------------------------------------
/docs/pages/davis.md:
--------------------------------------------------------------------------------
1 | {{autogenerated}}
2 |
3 | ---
4 |
5 | ## DAVIS240C Bias Example
6 |
7 | ```json
8 | {
9 | "DiffBn_coarse": 4,
10 | "DiffBn_fine": 39,
11 | "ONBn_coarse": 6,
12 | "ONBn_fine": 200,
13 | "OFFBn_coarse": 4,
14 | "OFFBn_fine": 0,
15 | "APSCasEPC_coarse": 5,
16 | "APSCasEPC_fine": 185,
17 | "DiffCasBNC_coarse": 5,
18 | "DiffCasBNC_fine": 115,
19 | "APSROSFBn_coarse": 6,
20 | "APSROSFBn_fine": 219,
21 | "LocalBufBn_coarse": 5,
22 | "LocalBufBn_fine": 164,
23 | "PixInvBn_coarse": 5,
24 | "PixInvBn_fine": 129,
25 | "PrBp_coarse": 2,
26 | "PrBp_fine": 58,
27 | "PrSFBp_coarse": 1,
28 | "PrSFBp_fine": 33,
29 | "RefrBp_coarse": 4,
30 | "RefrBp_fine": 25,
31 | "AEPdBn_coarse": 6,
32 | "AEPdBn_fine": 91,
33 | "LcolTimeoutBn_coarse": 5,
34 | "LcolTimeoutBn_fine": 49,
35 | "AEPuXBp_coarse": 4,
36 | "AEPuXBp_fine": 80,
37 | "AEPuYBp_coarse": 7,
38 | "AEPuYBp_fine": 152,
39 | "IFThrBn_coarse": 5,
40 | "IFThrBn_fine": 255,
41 | "IFRefrBn_coarse": 5,
42 | "IFRefrBn_fine": 255,
43 | "PadFollBn_coarse": 7,
44 | "PadFollBn_fine": 215,
45 | "APSOverflowLevelBn_coarse": 6,
46 | "APSOverflowLevelBn_fine": 253,
47 | "BiasBuffer_coarse": 5,
48 | "BiasBuffer_fine": 254,
49 | "aps_enabled": true,
50 | "dvs_enabled": true,
51 | "exposure": 4000,
52 | "autoexposure": true,
53 | "frame_delay": 0,
54 | "imu_enabled": true,
55 | "imu_acc_scale": 3,
56 | "imu_gyro_scale": 3,
57 | "imu_low_pass_filter": 0,
58 | "noise_filter_configs": {
59 | "sw_background_activity_two_levels": true,
60 | "sw_background_activity_check_polarity": true,
61 | "sw_background_activity_support_min": 2,
62 | "sw_background_activity_support_max": 8,
63 | "sw_background_activity_time": 2000,
64 | "sw_background_activity_enable": true,
65 | "sw_refractory_period_time": 200,
66 | "sw_refractory_period_enable": true,
67 | "sw_hotpixel_enable": true,
68 | "sw_hotpixel_learn": true
69 | }
70 | }
71 | ```
72 |
73 | ## DAVIS346B Bias Example
74 |
75 | ```json
76 | {
77 | "ADC_RefHigh_volt": 24,
78 | "ADC_RefHigh_curr": 7,
79 | "ADC_RefLow_volt": 1,
80 | "ADC_RefLow_curr": 7,
81 | "LocalBufBn_coarse": 5,
82 | "LocalBufBn_fine": 164,
83 | "PadFollBn_coarse": 7,
84 | "PadFollBn_fine": 215,
85 | "DiffBn_coarse": 4,
86 | "DiffBn_fine": 39,
87 | "ONBn_coarse": 6,
88 | "ONBn_fine": 255,
89 | "OFFBn_coarse": 4,
90 | "OFFBn_fine": 0,
91 | "PixInvBn_coarse": 5,
92 | "PixInvBn_fine": 129,
93 | "PrBp_coarse": 2,
94 | "PrBp_fine": 255,
95 | "PrSFBp_coarse": 1,
96 | "PrSFBp_fine": 199,
97 | "RefrBp_coarse": 3,
98 | "RefrBp_fine": 7,
99 | "ReadoutBufBp_coarse": 6,
100 | "ReadoutBufBp_fine": 20,
101 | "APSROSFBn_coarse": 6,
102 | "APSROSFBn_fine": 219,
103 | "ADCCompBp_coarse": 5,
104 | "ADCCompBp_fine": 20,
105 | "COLSELLowBn_coarse": 0,
106 | "COLSELLowBn_fine": 1,
107 | "DACBufBp_coarse": 6,
108 | "DACBufBp_fine": 60,
109 | "LcolTimeoutBn_coarse": 5,
110 | "LcolTimeoutBn_fine": 49,
111 | "AEPdBn_coarse": 6,
112 | "AEPdBn_fine": 91,
113 | "AEPuXBp_coarse": 4,
114 | "AEPuXBp_fine": 80,
115 | "AEPuYBp_coarse": 7,
116 | "AEPuYBp_fine": 152,
117 | "IFRefrBn_coarse": 5,
118 | "IFRefrBn_fine": 255,
119 | "IFThrBn_coarse": 5,
120 | "IFThrBn_fine": 255,
121 | "BiasBuffer_coarse": 5,
122 | "BiasBuffer_fine": 254,
123 | "aps_enabled": true,
124 | "dvs_enabled": true,
125 | "exposure": 4000,
126 | "autoexposure": true,
127 | "frame_delay": 0,
128 | "imu_enabled": true,
129 | "imu_acc_scale": 3,
130 | "imu_gyro_scale": 3,
131 | "imu_low_pass_filter": 0,
132 | "background_activity_filter_enabled": false,
133 | "background_activity_filter_time": 80,
134 | "refractory_period_enabled": true,
135 | "refractory_period_time": 2,
136 | "noise_filter_configs": {
137 | "sw_background_activity_two_levels": true,
138 | "sw_background_activity_check_polarity": true,
139 | "sw_background_activity_support_min": 2,
140 | "sw_background_activity_support_max": 8,
141 | "sw_background_activity_time": 2000,
142 | "sw_background_activity_enable": true,
143 | "sw_refractory_period_time": 200,
144 | "sw_refractory_period_enable": true,
145 | "sw_hotpixel_enable": true,
146 | "sw_hotpixel_learn": true
147 | }
148 | }
149 | ```
150 |
--------------------------------------------------------------------------------
/res/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - compiler: msys2
4 | ARCH: x64
5 | PYTHON_VERSION: "2.7"
6 | PYTHON: python3
7 | MSYS2_ARCH: x86_64
8 | MSYS2_DIR: msys64
9 | MSYSTEM: MINGW64
10 | MINICONDA: Miniconda-x64
11 | # - compiler: msys2
12 | # ARCH: x64
13 | # PYTHON_VERSION: "3.4"
14 | # PYTHON: python3
15 | # MSYS2_ARCH: x86_64
16 | # MSYS2_DIR: msys64
17 | # MSYSTEM: MINGW64
18 | # MINICONDA: Miniconda-x64
19 | - compiler: msys2
20 | ARCH: x64
21 | PYTHON_VERSION: "3.5"
22 | PYTHON: python3
23 | MSYS2_ARCH: x86_64
24 | MSYS2_DIR: msys64
25 | MSYSTEM: MINGW64
26 | MINICONDA: Miniconda-x64
27 | - compiler: msys2
28 | ARCH: x64
29 | PYTHON_VERSION: "3.6"
30 | PYTHON: python3
31 | MSYS2_ARCH: x86_64
32 | MSYS2_DIR: msys64
33 | MSYSTEM: MINGW64
34 | MINICONDA: Miniconda-x64
35 | - compiler: msys2
36 | ARCH: x64
37 | PYTHON_VERSION: "3.7"
38 | PYTHON: python3
39 | MSYS2_ARCH: x86_64
40 | MSYS2_DIR: msys64
41 | MSYSTEM: MINGW64
42 | MINICONDA: Miniconda-x64
43 | deploy:
44 | provider: GitHub
45 | description: ''
46 | auth_token:
47 | secure: QE/sriy9Y07epK5S7dQvJqzStTbHuncavO4ODI7tJVRhR26YDL819doQed6tfT2C
48 | artifact: /.*\.whl/ # upload all wheel files to release assets
49 | draft: false
50 | prerelease: false
51 | on:
52 | appveyor_repo_tag: true # deploy on tag push only
53 |
54 | platform:
55 | - x64
56 |
57 | matrix:
58 | fast_finish: true
59 |
60 | install:
61 | - set PATH=C:\%MINICONDA%\Scripts;%PATH%
62 | - cd C:\%MSYS2_DIR%\home
63 | - git clone https://github.com/inilabs/libcaer
64 | - git clone https://github.com/duguyue100/swig
65 | - conda config --set always_yes yes --set changeps1 no
66 | - conda update --yes conda
67 | - conda create -q --name python%PYTHON_VERSION% python=%PYTHON_VERSION% -c conda-forge
68 | - activate python%PYTHON_VERSION%
69 | - pip install numpy==1.16.1
70 | - pip install future -U
71 | - conda list
72 | - if [%PYTHON_VERSION%]==[3.5] (
73 | C:\%MSYS2_DIR%\usr\bin\bash -lc "cp /c/projects/pyaer/res/cygwinccompiler-py35.py /c/%MINICONDA%/envs/python%PYTHON_VERSION%/Lib/distutils/cygwinccompiler.py"
74 | &&
75 | C:\%MSYS2_DIR%\usr\bin\bash -lc "cp /c/%MINICONDA%/envs/python%PYTHON_VERSION%/vcruntime140.dll /c/%MINICONDA%/envs/python%PYTHON_VERSION%/libs"
76 | &&
77 | C:\%MSYS2_DIR%\usr\bin\bash -lc "echo 'File copied'"
78 | )
79 | - if [%PYTHON_VERSION%]==[3.6] (
80 | C:\%MSYS2_DIR%\usr\bin\bash -lc "cp /c/projects/pyaer/res/cygwinccompiler-py36.py /c/%MINICONDA%/envs/python%PYTHON_VERSION%/Lib/distutils/cygwinccompiler.py"
81 | &&
82 | C:\%MSYS2_DIR%\usr\bin\bash -lc "cp /c/%MINICONDA%/envs/python%PYTHON_VERSION%/vcruntime140.dll /c/%MINICONDA%/envs/python%PYTHON_VERSION%/libs"
83 | &&
84 | C:\%MSYS2_DIR%\usr\bin\bash -lc "echo 'File copied'"
85 | )
86 | - if [%PYTHON_VERSION%]==[3.7] (
87 | C:\%MSYS2_DIR%\usr\bin\bash -lc "cp /c/projects/pyaer/res/cygwinccompiler-py37.py /c/%MINICONDA%/envs/python%PYTHON_VERSION%/Lib/distutils/cygwinccompiler.py"
88 | &&
89 | C:\%MSYS2_DIR%\usr\bin\bash -lc "cp /c/%MINICONDA%/envs/python%PYTHON_VERSION%/vcruntime140.dll /c/%MINICONDA%/envs/python%PYTHON_VERSION%/libs"
90 | &&
91 | C:\%MSYS2_DIR%\usr\bin\bash -lc "echo 'File copied'"
92 | )
93 | - C:\%MSYS2_DIR%\usr\bin\pacman --noconfirm -S mingw-w64-x86_64-gcc
94 | - C:\%MSYS2_DIR%\usr\bin\pacman --noconfirm -S make mingw-w64-x86_64-cmake
95 | - C:\%MSYS2_DIR%\usr\bin\pacman --noconfirm -S mingw-w64-x86_64-pkg-config
96 | - C:\%MSYS2_DIR%\usr\bin\pacman --noconfirm -S mingw-w64-x86_64-libusb
97 | - C:\%MSYS2_DIR%\usr\bin\pacman --noconfirm -S automake bison
98 | - C:\%MSYS2_DIR%\usr\bin\bash -lc "/c/projects/pyaer/install-libcaer.sh ci"
99 | - C:\%MSYS2_DIR%\usr\bin\bash -lc "cd /home/swig && ./autogen.sh && ./configure --without-alllang --with-python=$(command -v python) --without-pcre && make -j4 && make install"
100 | - C:\%MSYS2_DIR%\usr\bin\bash -lc "cd /c/projects/pyaer && make build-win && make build-wheel && make build-wheel"
101 | - >
102 | IF "%APPVEYOR_REPO_TAG%" == "true"
103 | (
104 | pip install twine
105 | &&
106 | cd C:\projects\pyaer
107 | &&
108 | twine upload -u %TWINE_USERNAME% -p %TWINE_PASSWORD% dist/*.whl
109 | )
110 |
111 | build: off
112 |
113 | artifacts:
114 | - path: "dist\\*.whl"
115 | name: Wheels
116 |
--------------------------------------------------------------------------------
/scripts/davis346_color_events.py:
--------------------------------------------------------------------------------
1 | """DAVIS346 test example.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import cv2
9 | import numpy as np
10 |
11 | from pyaer import libcaer
12 | from pyaer.davis import DAVIS
13 |
14 | device = DAVIS(noise_filter=False, color_filter=True)
15 |
16 | print("Device ID:", device.device_id)
17 | if device.device_is_master:
18 | print("Device is master.")
19 | else:
20 | print("Device is slave.")
21 | print("Device Serial Number:", device.device_serial_number)
22 | print("Device String:", device.device_string)
23 | print("Device USB bus Number:", device.device_usb_bus_number)
24 | print("Device USB device address:", device.device_usb_device_address)
25 | print("Device size X:", device.dvs_size_X)
26 | print("Device size Y:", device.dvs_size_Y)
27 | print("Logic Version:", device.logic_version)
28 | print("Background Activity Filter:",
29 | device.dvs_has_background_activity_filter)
30 | print("Color Filter", device.aps_color_filter, type(device.aps_color_filter))
31 | print(device.aps_color_filter == 1)
32 |
33 | device.start_data_stream()
34 | # setting bias after data stream started
35 | device.set_bias_from_json("./scripts/configs/davis346_config.json")
36 |
37 | clip_value = 1
38 | histrange = [(0, v) for v in (260, 346)]
39 |
40 |
41 | def get_event(device):
42 | data = device.get_event()
43 |
44 | return data
45 |
46 |
47 | empty_img = np.zeros((260, 346, 3), dtype=np.float)
48 |
49 |
50 | while True:
51 | try:
52 | data = get_event(device)
53 | if data is not None:
54 | (pol_events, num_pol_event,
55 | special_events, num_special_event,
56 | frames_ts, frames, imu_events,
57 | num_imu_event) = data
58 | if frames.shape[0] != 0:
59 | frame = cv2.cvtColor(frames[0], cv2.COLOR_BGR2RGB)
60 | frame = cv2.resize(frame, dsize=(692, 520),
61 | interpolation=cv2.INTER_LINEAR)
62 | cv2.imshow("frame", frame)
63 |
64 | if pol_events is not None:
65 | print("Number of events:", pol_events.shape,
66 | "Number of Frames:",
67 | frames.shape, "Exposure:",
68 | device.get_config(
69 | libcaer.DAVIS_CONFIG_APS,
70 | libcaer.DAVIS_CONFIG_APS_EXPOSURE),
71 | "Autoexposure:", device.get_config(
72 | libcaer.DAVIS_CONFIG_APS,
73 | libcaer.DAVIS_CONFIG_APS_AUTOEXPOSURE),
74 | "Color:", pol_events[0, 4])
75 |
76 | if num_pol_event != 0:
77 | # extract color events
78 | pol_g_1 = (pol_events[:, 4] == 1) # lower left green
79 | pol_b = (pol_events[:, 4] == 2) # lower right blue
80 | pol_r = (pol_events[:, 4] == 3) # upper left red
81 | pol_g_2 = (pol_events[:, 4] == 4) # upper right green
82 |
83 | g_1, _, _ = np.histogram2d(
84 | pol_events[pol_g_1, 2], pol_events[pol_g_1, 1],
85 | bins=(260, 346), range=histrange)
86 | b, _, _ = np.histogram2d(
87 | pol_events[pol_b, 2], pol_events[pol_b, 1],
88 | bins=(260, 346), range=histrange)
89 | r, _, _ = np.histogram2d(
90 | pol_events[pol_r, 2], pol_events[pol_r, 1],
91 | bins=(260, 346), range=histrange)
92 | g_2, _, _ = np.histogram2d(
93 | pol_events[pol_g_2, 2], pol_events[pol_g_2, 1],
94 | bins=(260, 346), range=histrange)
95 |
96 | g_1 = np.clip(g_1, None, clip_value)/float(clip_value)
97 | b = np.clip(b, None, clip_value)/float(clip_value)
98 | r = np.clip(r, None, clip_value)/float(clip_value)
99 | g_2 = np.clip(g_2, None, clip_value)/float(clip_value)
100 |
101 | ig_1 = np.zeros((260, 346, 3), dtype=np.float)
102 | ib = np.zeros((260, 346, 3), dtype=np.float)
103 | ir = np.zeros((260, 346, 3), dtype=np.float)
104 | ig_2 = np.zeros((260, 346, 3), dtype=np.float)
105 |
106 | # ig_1[..., 0], ig_1[..., 2] = g_1, g_1
107 | # ib[..., 1], ib[..., 2] = b, b
108 | # ir[..., 0], ir[..., 1] = r, r
109 | # ig_2[..., 0], ig_2[..., 2] = g_2, g_2
110 |
111 | ig_1[..., 1] = g_1
112 | ib[..., 0], ib[..., 1] = b, b
113 | ir[..., 2] = r
114 | ig_2[..., 1] = g_2
115 |
116 | img = np.vstack((
117 | np.hstack((ir, ig_2)),
118 | np.hstack((ig_1, ib))))
119 |
120 | cv2.imshow("image", img)
121 |
122 | if cv2.waitKey(1) & 0xFF == ord('q'):
123 | break
124 | else:
125 | pass
126 |
127 | except KeyboardInterrupt:
128 | device.shutdown()
129 | break
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ---
4 |
5 | [](https://github.com/duguyue100/pyaer/releases/latest)
6 | []((https://pypi.org/project/pyaer/))
7 | [](https://github.com/duguyue100/pyaer/actions/workflows/main.yml)
8 | [](https://github.com/duguyue100/pyaer/blob/master/LICENSE)
9 | [](https://doi.org/10.5281/zenodo.1346279)
10 |
11 | 
12 | 
13 | 
14 | 
15 |
16 | 
17 | 
18 | 
19 | 
20 | 
21 | 
22 | 
23 |
24 | __WARNING__: This repository is under major refactor. There is no specific timeline.
25 | You are advised to build from scratch from the master branch.
26 |
27 | Special thanks to [iniVation](https://inivation.com/) for making this possible!
28 |
29 | The project is in its Beta development stage, please submit an
30 | [issue](https://github.com/duguyue100/pyaer/issues) if you encountered a problem.
31 |
32 | __NEWS__ As from 0.2.5, we switched CI/CD from Travis CI to Github Actions because the
33 | building on travis-ci.org is ceased. We are looking for solutions to produce ARM64 build.
34 |
35 | ## Why PyAER?
36 |
37 | iniVation has released [DV](https://gitlab.com/inivation/dv), a new platform and an SDK
38 | for accessing and developing with event cameras.
39 |
40 | For robotics projects, you may find [rpg_dvs_ros](https://github.com/uzh-rpg/rpg_dvs_ros)
41 | when you use ROS.
42 |
43 | So the natural question is: why PyAER?
44 |
45 | In a nutshell, PyAER is a combination of a Pythonic `libcaer` and a light-weight "ROS".
46 | PyAER serves as an agile package that focus on fast development and extensibility.
47 | In fact, in some scenario, e.g., edge devices, PyAER is more user friendly than other
48 | alternatives.
49 |
50 | ### Design Principle
51 |
52 | + Minimum installation effort.
53 | + Clean, simple, easy to manage.
54 | + Well documented, human-readable code.
55 |
56 | ## Installation
57 |
58 | 1. Install `libcaer` dependency (RECOMMEND)
59 |
60 | ```bash
61 | # for Ubuntu
62 | sudo apt-get install libcaer-dev
63 | # for macOS
64 | brew tap inivation/inivation
65 | brew install libcaer --with-libserialport --with-opencv
66 | ```
67 |
68 | Update `udev` rules if you use a Linux system:
69 |
70 | ```bash
71 | $ bash <(curl -s https://raw.githubusercontent.com/duguyue100/pyaer/master/install-udev.sh)
72 | ```
73 |
74 | __NOTE__: The `libcaer` installation has taken care of the `udev` update.
75 | However, if the problem persists, please try it.
76 |
77 | 2. Install `pyaer` from pypi (RECOMMEND)
78 |
79 | ```bash
80 | $ pip install pyaer
81 | ```
82 |
83 | 3. Install `pyzmq` and `h5py`
84 | ```
85 | $ pip install pyzmq
86 | $ pip install h5py
87 | ```
88 |
89 | __NOTE:__ `pyzmq` is not available on ARM-based computer, you will need to build
90 | yourself.
91 |
92 | ### Development
93 |
94 | For development purpose, you might build `pyaer` from source.
95 | Please follow the instructions in [INSTALL_FROM_SOURCE.md](./INSTALL_FROM_SOURCE.md)
96 |
97 | ## Running Examples
98 |
99 | + The [scripts](./scripts) folder provides some examples for you to play with.
100 |
101 | + Extra more advanced demos are available at [pyaer-demo](https://github.com/duguyue100/pyaer-demo).
102 |
103 | ## Limitations and Notes
104 |
105 | + __2022-08-05__: Address the building issue with the latest `libcaer` release.
106 |
107 | + __2022-06-07__: We now switch to follow `libcaer` official release.
108 |
109 | + __2021-12-01__: For DAVIS346 Color model, we now support color events.
110 |
111 | + __2021-01-13__: DVXplorer cameras are officially supported
112 | (Thanks [iniVation](https://inivation.com/))
113 | for borrowing devices. Samsung EVK support is yet to be tested.
114 |
115 | + __2020-12-02__: From 0.2.0, we support a `zeromq`-based communication
116 | module that allow users to leverage multiple processes during development.
117 | It can support multiple devices and concurrent logging and
118 | visualization. If you are familiar with ROS, you should
119 | find this feature comfortable.
120 |
121 | + DYNAP is generally supported. We are currently looking for the correct
122 | bias configuration mechanism so that it can easily support the use of the
123 | device. We have mapped some core functions that are essential to device
124 | configuration.
125 |
126 | ## Contacts
127 |
128 | Yuhuang Hu
129 | Email: duguyue100@gmail.com
130 |
--------------------------------------------------------------------------------
/scripts/dvs128_vispy.py:
--------------------------------------------------------------------------------
1 | """DVS128 Test.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from __future__ import print_function
7 |
8 | import numpy as np
9 | import vispy
10 | from vispy import app, scene, visuals, gloo
11 | from vispy.util.transforms import ortho
12 |
13 | from pyaer.dvs128 import DVS128
14 |
15 |
16 | device = DVS128()
17 |
18 | print ("Device ID:", device.device_id)
19 | if device.device_is_master:
20 | print ("Device is master.")
21 | else:
22 | print ("Device is slave.")
23 | print ("Device Serial Number:", device.device_serial_number)
24 | print ("Device String:", device.device_string)
25 | print ("Device USB bus Number:", device.device_usb_bus_number)
26 | print ("Device USB device address:", device.device_usb_device_address)
27 | print ("Device size X:", device.dvs_size_X)
28 | print ("Device size Y:", device.dvs_size_Y)
29 | print ("Logic Version:", device.logic_version)
30 |
31 | # load new config
32 | device.set_bias_from_json("./scripts/configs/dvs128_config.json")
33 | print (device.get_bias())
34 |
35 | device.start_data_stream()
36 |
37 | clip_value = 3
38 | histrange = [(0, v) for v in (128, 128)]
39 |
40 | app.use_app("pyside")
41 |
42 | W, H = 128, 128
43 | img_array = np.random.uniform(0, 1, (W, H)).astype(np.float32)
44 |
45 | data = np.zeros(4, dtype=[('a_position', np.float32, 2),
46 | ('a_texcoord', np.float32, 2)])
47 | data['a_position'] = np.array([[0, 0], [W, 0], [0, H], [W, H]])
48 | data['a_texcoord'] = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
49 |
50 | VERT_SHADER = """
51 | // Uniforms
52 | uniform mat4 u_model;
53 | uniform mat4 u_view;
54 | uniform mat4 u_projection;
55 | uniform float u_antialias;
56 | // Attributes
57 | attribute vec2 a_position;
58 | attribute vec2 a_texcoord;
59 | // Varyings
60 | varying vec2 v_texcoord;
61 | // Main
62 | void main (void)
63 | {
64 | v_texcoord = a_texcoord;
65 | gl_Position = u_projection * u_view * u_model * vec4(a_position,0.0,1.0);
66 | }
67 | """
68 |
69 | FRAG_SHADER = """
70 | uniform sampler2D u_texture;
71 | varying vec2 v_texcoord;
72 | void main()
73 | {
74 | gl_FragColor = texture2D(u_texture, v_texcoord);
75 | gl_FragColor.a = 1.0;
76 | }
77 | """
78 |
79 |
80 | class Canvas(vispy.app.Canvas):
81 | def __init__(self):
82 | vispy.app.Canvas.__init__(self, keys='interactive', size=(300, 300))
83 | self.program = gloo.Program(VERT_SHADER, FRAG_SHADER)
84 | self.texture = gloo.Texture2D(
85 | img_array, interpolation="linear")
86 |
87 | self.program['u_texture'] = self.texture
88 | self.program.bind(gloo.VertexBuffer(data))
89 |
90 | self.view = np.eye(4, dtype=np.float32)
91 | self.model = np.eye(4, dtype=np.float32)
92 | self.projection = np.eye(4, dtype=np.float32)
93 |
94 | self.program['u_model'] = self.model
95 | self.program['u_view'] = self.view
96 | self.projection = ortho(0, W, 0, H, -1, 1)
97 | self.program['u_projection'] = self.projection
98 |
99 | gloo.set_clear_color('white')
100 |
101 | self._timer = app.Timer('auto', connect=self.update, start=True)
102 | self.show()
103 |
104 | # @profile
105 | def on_draw(self, ev):
106 | gloo.clear(color=True, depth=True)
107 |
108 | (pol_events, num_pol_event,
109 | special_events, num_special_event) = \
110 | device.get_event()
111 |
112 | if num_pol_event != 0:
113 | pol_on = (pol_events[:, 3] == 1)
114 | pol_off = np.logical_not(pol_on)
115 | img_on, _, _ = np.histogram2d(
116 | pol_events[pol_on, 1], 127-pol_events[pol_on, 2],
117 | bins=(128, 128), range=histrange)
118 | img_off, _, _ = np.histogram2d(
119 | pol_events[pol_off, 1], 127-pol_events[pol_off, 2],
120 | bins=(128, 128), range=histrange)
121 | if clip_value is not None:
122 | integrated_img = np.clip(
123 | (img_on-img_off), -clip_value, clip_value)
124 | else:
125 | integrated_img = (img_on-img_off)
126 |
127 | img_array = ((integrated_img+clip_value)/float(
128 | clip_value*2)).astype(np.float32)
129 | else:
130 | img_array[...] = np.zeros(
131 | (128, 128), dtype=np.uint8).astype(np.float32)
132 |
133 | self.texture.set_data(img_array)
134 | self.program.draw('triangle_strip')
135 |
136 | # @profile
137 | def on_resize(self, event):
138 | width, height = event.physical_size
139 | gloo.set_viewport(0, 0, width, height)
140 | self.projection = ortho(0, width, 0, height, -100, 100)
141 | self.program['u_projection'] = self.projection
142 |
143 | # Compute thje new size of the quad
144 | r = width / float(height)
145 | R = W / float(H)
146 | if r < R:
147 | w, h = width, width / R
148 | x, y = 0, int((height - h) / 2)
149 | else:
150 | w, h = height * R, height
151 | x, y = int((width - w) / 2), 0
152 | data['a_position'] = np.array(
153 | [[x, y], [x + w, y], [x, y + h], [x + w, y + h]])
154 | self.program.bind(gloo.VertexBuffer(data))
155 |
156 | # @profile
157 | def run():
158 | win = Canvas()
159 | app.run()
160 |
161 |
162 | run()
163 |
--------------------------------------------------------------------------------
/custom_build/.travis.yml:
--------------------------------------------------------------------------------
1 | cache:
2 | directories:
3 | - $HOME/download
4 | - $HOME/.cache/pip
5 |
6 | language: generic
7 |
8 | os: linux
9 |
10 | env:
11 | global:
12 | - TWINE_USERNAME=duguyue100
13 |
14 | jobs:
15 | include:
16 | - os: linux
17 | language: python
18 | python: "3.5"
19 | env: TOXENV=py35
20 | - os: linux
21 | language: python
22 | python: "3.6"
23 | env: TOXENV=py36
24 | - os: linux
25 | language: python
26 | python: "3.7"
27 | env: TOXENV=py37
28 | - os: linux
29 | language: python
30 | python: "3.8"
31 | env: TOXENV=py38
32 | # - os: linux
33 | # language: python
34 | # python: "3.9"
35 | # env: TOXENV=py39
36 | - os: osx
37 | env:
38 | - TOXENV=3.5
39 | - HOMEBREW_NO_AUTO_UPDATE=1
40 | - os: osx
41 | env:
42 | - TOXENV=3.6
43 | - HOMEBREW_NO_AUTO_UPDATE=1
44 | - os: osx
45 | env:
46 | - TOXENV=3.7
47 | - HOMEBREW_NO_AUTO_UPDATE=1
48 | - os: osx
49 | env:
50 | - TOXENV=3.8
51 | - HOMEBREW_NO_AUTO_UPDATE=1
52 | # - os: osx
53 | # env:
54 | # - TOXENV=3.9
55 | # - HOMEBREW_NO_AUTO_UPDATE=1
56 | - os: linux
57 | arch: arm64
58 | language: python
59 | python: "3.5"
60 | env: TOXENV=py35
61 | - os: linux
62 | arch: arm64
63 | language: python
64 | python: "3.6"
65 | env: TOXENV=py36
66 | - os: linux
67 | arch: arm64
68 | language: python
69 | python: "3.7"
70 | env: TOXENV=py37
71 | - os: linux
72 | arch: arm64
73 | language: python
74 | python: "3.8"
75 | env: TOXENV=py38
76 | # - os: linux
77 | # arch: arm64
78 | # language: python
79 | # python: "3.9"
80 | # env: TOXENV=py39
81 |
82 | deploy:
83 | provider: releases
84 | token: $GITHUB_TOKEN
85 | file_glob: true
86 | file: dist/*.whl
87 | skip_cleanup: true
88 | on:
89 | tags: true
90 |
91 | before_install:
92 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
93 | mkdir -p download;
94 | cd download;
95 | wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh;
96 | chmod +x miniconda.sh;
97 | ./miniconda.sh -b -p $HOME/miniconda;
98 | export PATH=$HOME/miniconda/bin:$PATH;
99 | conda info -a;
100 | conda update --yes conda;
101 | conda create -n pyenv python=$TOXENV --yes;
102 | source activate pyenv;
103 | cd ..;
104 | fi
105 | - python --version
106 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
107 | sudo apt-add-repository -y "ppa:ubuntu-toolchain-r/test";
108 | sudo apt-get -qq update;
109 | sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-5 g++-5;
110 | sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-5 /usr/bin/gcc;
111 | sudo unlink /usr/bin/g++ && sudo ln -s /usr/bin/g++-5 /usr/bin/g++;
112 | gcc --version;
113 | fi
114 | - if [[ "$TRAVIS_CPU_ARCH" == "arm64" ]]; then
115 | sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-7 g++-7;
116 | sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-7 /usr/bin/gcc;
117 | sudo unlink /usr/bin/g++ && sudo ln -s /usr/bin/g++-7 /usr/bin/g++;
118 | gcc --version;
119 | fi
120 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
121 | sudo apt-get install build-essential -y;
122 | sudo apt-get install libusb-1.0-0-dev -y;
123 | sudo apt-get install automake -y;
124 | sudo apt-get install bison -y;
125 |
126 | sudo apt-get install snapd;
127 | sudo snap install cmake --classic;
128 | export PATH=/snap/bin:$PATH;
129 | else
130 | brew install libusb;
131 | brew install automake;
132 | brew install bison;
133 | fi
134 | - git clone git://sigrok.org/libserialport
135 | - cd libserialport
136 | - ./autogen.sh
137 | - ./configure
138 | - make -j4
139 | - sudo make install
140 | - cd ..
141 | - $HOME/build/duguyue100/pyaer/install-libcaer.sh ci
142 | - git clone https://github.com/duguyue100/swig
143 | - cd swig
144 | - ./autogen.sh
145 | - ./configure --without-alllang --with-python=$(command -v python) --without-pcre
146 | - make
147 | - sudo make install
148 | - cd ..
149 |
150 | install:
151 | - pip install pip -U
152 | - pip install numpy==1.18.0
153 | - pip install wheel
154 | - if [[ $TRAVIS_TAG ]]; then
155 | pip install twine;
156 | fi
157 |
158 | script:
159 | - make build-wheel
160 | - make build-wheel
161 | - make install
162 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
163 | cd dist;
164 | for file in *.whl ; do mv $file ${file//linux/manylinux1} ; done;
165 | cd ..;
166 | fi
167 | - if [[ $TRAVIS_TAG && "$TRAVIS_CPU_ARCH" != "arm64" ]]; then
168 | twine upload -u ${TWINE_USERNAME} -p ${TWINE_PASSWORD} dist/*.whl;
169 | fi
170 |
171 | branches:
172 | except:
173 | - refactor-compiling
174 |
175 | notifications:
176 | email: false
177 |
--------------------------------------------------------------------------------
/scripts/timer.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import time
3 | import numpy as np
4 | import matplotlib.pyplot as plt
5 | from engineering_notation import EngNumber as eng # only from pip
6 | import atexit
7 |
8 |
9 | LOGGING_LEVEL = logging.INFO
10 |
11 |
12 | class CustomFormatter(logging.Formatter):
13 | """Logging Formatter to add colors and count warning / errors"""
14 |
15 | grey = "\x1b[38;21m"
16 | yellow = "\x1b[33;21m"
17 | red = "\x1b[31;21m"
18 | bold_red = "\x1b[31;1m"
19 | reset = "\x1b[0m"
20 | format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
21 |
22 | FORMATS = {
23 | logging.DEBUG: grey + format + reset,
24 | logging.INFO: grey + format + reset,
25 | logging.WARNING: yellow + format + reset,
26 | logging.ERROR: red + format + reset,
27 | logging.CRITICAL: bold_red + format + reset
28 | }
29 |
30 | def format(self, record):
31 | log_fmt = self.FORMATS.get(record.levelno)
32 | formatter = logging.Formatter(log_fmt)
33 | return formatter.format(record)
34 |
35 |
36 | def my_logger(name):
37 | # logging.basicConfig(stream=sys.stdout, level=logging.INFO)
38 | logger = logging.getLogger(name)
39 | logger.setLevel(LOGGING_LEVEL)
40 | # create console handler
41 | ch = logging.StreamHandler()
42 | ch.setFormatter(CustomFormatter())
43 | logger.addHandler(ch)
44 | return logger
45 |
46 |
47 | log = my_logger(__name__)
48 |
49 | timers = {}
50 | times = {}
51 |
52 |
53 | class Timer:
54 | def __init__(self, timer_name='', delay=None,
55 | show_hist=False, numpy_file=None):
56 | """ Make a Timer() in a _with_ statement for a block of code.
57 | The timer is started when the block is entered and stopped when exited.
58 | The Timer _must_ be used in a with statement.
59 | :param timer_name: the str by which this timer is repeatedly called
60 | and which it is named when summary is printed on exit
61 | :param delay: set this to a value to simply accumulate
62 | this externally determined interval
63 | :param show_hist: whether to plot a histogram with pyplot
64 | :param numpy_file: optional numpy file path
65 | """
66 | self.timer_name = timer_name
67 | self.show_hist = show_hist
68 | self.numpy_file = numpy_file
69 | self.delay = delay
70 |
71 | if self.timer_name not in timers.keys():
72 | timers[self.timer_name] = self
73 | if self.timer_name not in times.keys():
74 | times[self.timer_name] = []
75 |
76 | def __enter__(self):
77 | if self.delay is None:
78 | self.start = time.time()
79 | return self
80 |
81 | def __exit__(self, *args):
82 | if self.delay is None:
83 | self.end = time.time()
84 | self.interval = self.end - self.start # measured in seconds
85 | else:
86 | self.interval = self.delay
87 | times[self.timer_name].append(self.interval)
88 |
89 | def print_timing_info(self, logger=None):
90 | """ Prints the timing information accumulated for this Timer
91 | :param logger: write to the supplied logger,
92 | otherwise use the built-in logger
93 | """
94 | if len(times) == 0:
95 | log.error(f'Timer {self.timer_name} has no statistics; was it used without a "with" statement?')
96 | return
97 | a = np.array(times[self.timer_name])
98 | timing_mean = np.mean(a) # todo use built in print method for timer
99 | timing_std = np.std(a)
100 | timing_median = np.median(a)
101 | timing_min = np.min(a)
102 | timing_max = np.max(a)
103 | s='{} n={}: {}s +/- {}s (median {}s, min {}s max {}s)'.format(self.timer_name, len(a),
104 | eng(timing_mean), eng(timing_std),
105 | eng(timing_median), eng(timing_min),
106 | eng(timing_max))
107 |
108 | if logger is not None:
109 | logger.info(s)
110 | else:
111 | log.info(s)
112 |
113 |
114 | def print_timing_info():
115 | for k, v in times.items(): # k is the name, v is the list of times
116 | a = np.array(v)
117 | timing_mean = np.mean(a)
118 | timing_std = np.std(a)
119 | timing_median = np.median(a)
120 | timing_min = np.min(a)
121 | timing_max = np.max(a)
122 | log.info('== Timing statistics from all Timer ==\n{} n={}: {}s +/- {}s (median {}s, min {}s max {}s)'.format(k, len(a),
123 | eng(timing_mean), eng(timing_std),
124 | eng(timing_median), eng(timing_min),
125 | eng(timing_max)))
126 | if timers[k].numpy_file is not None:
127 | try:
128 | log.info(f'saving timing data for {k} in numpy file {timers[k].numpy_file}')
129 | log.info('there are {} times'.format(len(a)))
130 | np.save(timers[k].numpy_file, a)
131 | except Exception as e:
132 | log.error(f'could not save numpy file {timers[k].numpy_file}; caught {e}')
133 |
134 | if timers[k].show_hist:
135 |
136 | def plot_loghist(x, bins):
137 | hist, bins = np.histogram(x, bins=bins) # histogram x linearly
138 | if len(bins)<2 or bins[0]<=0:
139 | log.error(f'cannot plot histogram since bins={bins}')
140 | return
141 | logbins = np.logspace(np.log10(bins[0]), np.log10(bins[-1]), len(bins)) # use resulting bin ends to get log bins
142 | plt.hist(x, bins=logbins) # now again histogram x, but with the log-spaced bins, and plot this histogram
143 | plt.xscale('log')
144 |
145 | dt = np.clip(a,1e-6, None)
146 | # logbins = np.logspace(np.log10(bins[0]), np.log10(bins[-1]), len(bins))
147 | try:
148 | plot_loghist(dt,bins=100)
149 | plt.xlabel('interval[ms]')
150 | plt.ylabel('frequency')
151 | plt.title(k)
152 | plt.show()
153 | except Exception as e:
154 | log.error(f'could not plot histogram: got {e}')
155 |
156 |
157 | atexit.register(print_timing_info)
158 |
--------------------------------------------------------------------------------
/scripts/configs/dynapse_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "mux_timestamp_reset": false,
3 | "mux_force_chip_bias_enable": false,
4 | "mux_drop_aer_on_transfer_stall": false,
5 | "aer_ack_delay": 0,
6 | "aer_ack_extension": 0,
7 | "aer_wait_on_transfer_stall": false,
8 | "aer_external_aer_control": false,
9 | "chip_req_delay": 30,
10 | "chip_req_extension": 30,
11 | "usb_early_packet_delay": 8,
12 |
13 | "c0_if_buf_p_coarse": 3,
14 | "c0_if_buf_p_fine": 80,
15 | "c0_if_rfr_n_coarse": 3,
16 | "c0_if_rfr_n_fine": 3,
17 | "c0_if_nmda_n_coarse": 7,
18 | "c0_if_nmda_n_fine": 0,
19 | "c0_if_dc_p_coarse": 7,
20 | "c0_if_dc_p_fine": 30,
21 | "c0_if_tau1_coarse": 7,
22 | "c0_if_tau1_fine": 5,
23 | "c0_if_tau2_coarse": 6,
24 | "c0_if_tau2_fine": 100,
25 | "c0_if_thr_n_coarse": 4,
26 | "c0_if_thr_n_fine": 120,
27 | "c0_if_ahw_p_coarse": 7,
28 | "c0_if_ahw_p_fine": 0,
29 | "c0_if_ahtau_n_coarse": 7,
30 | "c0_if_ahtau_n_fine": 35,
31 | "c0_if_ahthr_n_coarse": 7,
32 | "c0_if_ahthr_n_fine": 0,
33 | "c0_if_casc_n_coarse": 7,
34 | "c0_if_casc_n_fine": 0,
35 | "c0_pulse_pwlk_p_coarse": 3,
36 | "c0_pulse_pwlk_p_fine": 106,
37 | "c0_ps_weight_inh_s_n_coarse": 7,
38 | "c0_ps_weight_inh_s_n_fine": 0,
39 | "c0_ps_weight_inh_f_n_coarse": 7,
40 | "c0_ps_weight_inh_f_n_fine": 0,
41 | "c0_ps_weight_exc_s_n_coarse": 7,
42 | "c0_ps_weight_exc_s_n_fine": 0,
43 | "c0_ps_weight_exc_f_n_coarse": 7,
44 | "c0_ps_weight_exc_f_n_fine": 0,
45 | "c0_npdpii_tau_s_p_coarse": 7,
46 | "c0_npdpii_tau_s_p_fine": 40,
47 | "c0_npdpii_tau_f_p_coarse": 7,
48 | "c0_npdpii_tau_f_p_fine": 0,
49 | "c0_npdpii_thr_s_p_coarse": 7,
50 | "c0_npdpii_thr_s_p_fine": 40,
51 | "c0_npdpii_thr_f_p_coarse": 7,
52 | "c0_npdpii_thr_f_p_fine": 0,
53 | "c0_npdpie_tau_s_p_coarse": 7,
54 | "c0_npdpie_tau_s_p_fine": 0,
55 | "c0_npdpie_tau_f_p_coarse": 7,
56 | "c0_npdpie_tau_f_p_fine": 40,
57 | "c0_npdpie_thr_s_p_coarse": 7,
58 | "c0_npdpie_thr_s_p_fine": 0,
59 | "c0_npdpie_thr_f_p_coarse": 7,
60 | "c0_npdpie_thr_f_p_fine": 0,
61 | "c0_r2r_p_coarse": 4,
62 | "c0_r2r_p_fine": 85,
63 |
64 | "c1_if_buf_p_coarse": 3,
65 | "c1_if_buf_p_fine": 80,
66 | "c1_if_rfr_n_coarse": 3,
67 | "c1_if_rfr_n_fine": 3,
68 | "c1_if_nmda_n_coarse": 7,
69 | "c1_if_nmda_n_fine": 0,
70 | "c1_if_dc_p_coarse": 7,
71 | "c1_if_dc_p_fine": 30,
72 | "c1_if_tau1_coarse": 0,
73 | "c1_if_tau1_fine": 5,
74 | "c1_if_tau2_coarse": 6,
75 | "c1_if_tau2_fine": 100,
76 | "c1_if_thr_n_coarse": 4,
77 | "c1_if_thr_n_fine": 120,
78 | "c1_if_ahw_p_coarse": 7,
79 | "c1_if_ahw_p_fine": 0,
80 | "c1_if_ahtau_n_coarse": 7,
81 | "c1_if_ahtau_n_fine": 35,
82 | "c1_if_ahthr_n_coarse": 7,
83 | "c1_if_ahthr_n_fine": 0,
84 | "c1_if_casc_n_coarse": 7,
85 | "c1_if_casc_n_fine": 0,
86 | "c1_pulse_pwlk_p_coarse": 3,
87 | "c1_pulse_pwlk_p_fine": 106,
88 | "c1_ps_weight_inh_s_n_coarse": 7,
89 | "c1_ps_weight_inh_s_n_fine": 0,
90 | "c1_ps_weight_inh_f_n_coarse": 7,
91 | "c1_ps_weight_inh_f_n_fine": 0,
92 | "c1_ps_weight_exc_s_n_coarse": 7,
93 | "c1_ps_weight_exc_s_n_fine": 0,
94 | "c1_ps_weight_exc_f_n_coarse": 7,
95 | "c1_ps_weight_exc_f_n_fine": 0,
96 | "c1_npdpii_tau_s_p_coarse": 7,
97 | "c1_npdpii_tau_s_p_fine": 40,
98 | "c1_npdpii_tau_f_p_coarse": 7,
99 | "c1_npdpii_tau_f_p_fine": 0,
100 | "c1_npdpii_thr_s_p_coarse": 7,
101 | "c1_npdpii_thr_s_p_fine": 40,
102 | "c1_npdpii_thr_f_p_coarse": 7,
103 | "c1_npdpii_thr_f_p_fine": 0,
104 | "c1_npdpie_tau_s_p_coarse": 7,
105 | "c1_npdpie_tau_s_p_fine": 0,
106 | "c1_npdpie_tau_f_p_coarse": 7,
107 | "c1_npdpie_tau_f_p_fine": 40,
108 | "c1_npdpie_thr_s_p_coarse": 7,
109 | "c1_npdpie_thr_s_p_fine": 0,
110 | "c1_npdpie_thr_f_p_coarse": 7,
111 | "c1_npdpie_thr_f_p_fine": 0,
112 | "c1_r2r_p_coarse": 4,
113 | "c1_r2r_p_fine": 85,
114 |
115 | "c2_if_buf_p_coarse": 3,
116 | "c2_if_buf_p_fine": 80,
117 | "c2_if_rfr_n_coarse": 3,
118 | "c2_if_rfr_n_fine": 3,
119 | "c2_if_nmda_n_coarse": 7,
120 | "c2_if_nmda_n_fine": 0,
121 | "c2_if_dc_p_coarse": 7,
122 | "c2_if_dc_p_fine": 30,
123 | "c2_if_tau1_coarse": 0,
124 | "c2_if_tau1_fine": 5,
125 | "c2_if_tau2_coarse": 6,
126 | "c2_if_tau2_fine": 100,
127 | "c2_if_thr_n_coarse": 4,
128 | "c2_if_thr_n_fine": 120,
129 | "c2_if_ahw_p_coarse": 7,
130 | "c2_if_ahw_p_fine": 0,
131 | "c2_if_ahtau_n_coarse": 7,
132 | "c2_if_ahtau_n_fine": 35,
133 | "c2_if_ahthr_n_coarse": 7,
134 | "c2_if_ahthr_n_fine": 0,
135 | "c2_if_casc_n_coarse": 7,
136 | "c2_if_casc_n_fine": 0,
137 | "c2_pulse_pwlk_p_coarse": 3,
138 | "c2_pulse_pwlk_p_fine": 106,
139 | "c2_ps_weight_inh_s_n_coarse": 7,
140 | "c2_ps_weight_inh_s_n_fine": 0,
141 | "c2_ps_weight_inh_f_n_coarse": 7,
142 | "c2_ps_weight_inh_f_n_fine": 0,
143 | "c2_ps_weight_exc_s_n_coarse": 7,
144 | "c2_ps_weight_exc_s_n_fine": 0,
145 | "c2_ps_weight_exc_f_n_coarse": 7,
146 | "c2_ps_weight_exc_f_n_fine": 0,
147 | "c2_npdpii_tau_s_p_coarse": 7,
148 | "c2_npdpii_tau_s_p_fine": 40,
149 | "c2_npdpii_tau_f_p_coarse": 7,
150 | "c2_npdpii_tau_f_p_fine": 0,
151 | "c2_npdpii_thr_s_p_coarse": 7,
152 | "c2_npdpii_thr_s_p_fine": 40,
153 | "c2_npdpii_thr_f_p_coarse": 7,
154 | "c2_npdpii_thr_f_p_fine": 0,
155 | "c2_npdpie_tau_s_p_coarse": 7,
156 | "c2_npdpie_tau_s_p_fine": 0,
157 | "c2_npdpie_tau_f_p_coarse": 7,
158 | "c2_npdpie_tau_f_p_fine": 40,
159 | "c2_npdpie_thr_s_p_coarse": 7,
160 | "c2_npdpie_thr_s_p_fine": 0,
161 | "c2_npdpie_thr_f_p_coarse": 7,
162 | "c2_npdpie_thr_f_p_fine": 0,
163 | "c2_r2r_p_coarse": 4,
164 | "c2_r2r_p_fine": 85,
165 |
166 | "c3_if_buf_p_coarse": 3,
167 | "c3_if_buf_p_fine": 80,
168 | "c3_if_rfr_n_coarse": 3,
169 | "c3_if_rfr_n_fine": 3,
170 | "c3_if_nmda_n_coarse": 7,
171 | "c3_if_nmda_n_fine": 0,
172 | "c3_if_dc_p_coarse": 7,
173 | "c3_if_dc_p_fine": 30,
174 | "c3_if_tau1_coarse": 0,
175 | "c3_if_tau1_fine": 5,
176 | "c3_if_tau2_coarse": 6,
177 | "c3_if_tau2_fine": 100,
178 | "c3_if_thr_n_coarse": 4,
179 | "c3_if_thr_n_fine": 120,
180 | "c3_if_ahw_p_coarse": 7,
181 | "c3_if_ahw_p_fine": 0,
182 | "c3_if_ahtau_n_coarse": 7,
183 | "c3_if_ahtau_n_fine": 35,
184 | "c3_if_ahthr_n_coarse": 7,
185 | "c3_if_ahthr_n_fine": 0,
186 | "c3_if_casc_n_coarse": 7,
187 | "c3_if_casc_n_fine": 0,
188 | "c3_pulse_pwlk_p_coarse": 3,
189 | "c3_pulse_pwlk_p_fine": 106,
190 | "c3_ps_weight_inh_s_n_coarse": 7,
191 | "c3_ps_weight_inh_s_n_fine": 0,
192 | "c3_ps_weight_inh_f_n_coarse": 7,
193 | "c3_ps_weight_inh_f_n_fine": 0,
194 | "c3_ps_weight_exc_s_n_coarse": 7,
195 | "c3_ps_weight_exc_s_n_fine": 0,
196 | "c3_ps_weight_exc_f_n_coarse": 7,
197 | "c3_ps_weight_exc_f_n_fine": 0,
198 | "c3_npdpii_tau_s_p_coarse": 7,
199 | "c3_npdpii_tau_s_p_fine": 40,
200 | "c3_npdpii_tau_f_p_coarse": 7,
201 | "c3_npdpii_tau_f_p_fine": 0,
202 | "c3_npdpii_thr_s_p_coarse": 7,
203 | "c3_npdpii_thr_s_p_fine": 40,
204 | "c3_npdpii_thr_f_p_coarse": 7,
205 | "c3_npdpii_thr_f_p_fine": 0,
206 | "c3_npdpie_tau_s_p_coarse": 7,
207 | "c3_npdpie_tau_s_p_fine": 0,
208 | "c3_npdpie_tau_f_p_coarse": 7,
209 | "c3_npdpie_tau_f_p_fine": 40,
210 | "c3_npdpie_thr_s_p_coarse": 7,
211 | "c3_npdpie_thr_s_p_fine": 0,
212 | "c3_npdpie_thr_f_p_coarse": 7,
213 | "c3_npdpie_thr_f_p_fine": 0,
214 | "c3_r2r_p_coarse": 4,
215 | "c3_r2r_p_fine": 85,
216 |
217 | "d_buffer_coarse": 1,
218 | "d_buffer_fine": 2,
219 | "d_ssp_coarse": 0,
220 | "d_ssp_fine": 7,
221 | "d_ssn_coarse": 0,
222 | "d_ssn_fine": 15,
223 | "u_buffer_coarse": 1,
224 | "u_buffer_fine": 2,
225 | "u_ssp_coarse": 0,
226 | "u_ssp_fine": 7,
227 | "u_ssn_coarse": 0,
228 | "u_ssn_fine": 15
229 | }
230 |
--------------------------------------------------------------------------------
/docs/pages/dynapse.md:
--------------------------------------------------------------------------------
1 | {{autogenerated}}
2 |
3 | ---
4 |
5 | ## Bias Example
6 |
7 | ```json
8 | {
9 | "mux_timestamp_reset": false,
10 | "mux_force_chip_bias_enable": false,
11 | "mux_drop_aer_on_transfer_stall": false,
12 | "aer_ack_delay": 0,
13 | "aer_ack_extension": 0,
14 | "aer_wait_on_transfer_stall": false,
15 | "aer_external_aer_control": false,
16 | "chip_req_delay": 30,
17 | "chip_req_extension": 30,
18 | "usb_early_packet_delay": 8,
19 |
20 | "c0_if_buf_p_coarse": 3,
21 | "c0_if_buf_p_fine": 80,
22 | "c0_if_rfr_n_coarse": 3,
23 | "c0_if_rfr_n_fine": 3,
24 | "c0_if_nmda_n_coarse": 7,
25 | "c0_if_nmda_n_fine": 0,
26 | "c0_if_dc_p_coarse": 7,
27 | "c0_if_dc_p_fine": 30,
28 | "c0_if_tau1_coarse": 7,
29 | "c0_if_tau1_fine": 5,
30 | "c0_if_tau2_coarse": 6,
31 | "c0_if_tau2_fine": 100,
32 | "c0_if_thr_n_coarse": 4,
33 | "c0_if_thr_n_fine": 120,
34 | "c0_if_ahw_p_coarse": 7,
35 | "c0_if_ahw_p_fine": 0,
36 | "c0_if_ahtau_n_coarse": 7,
37 | "c0_if_ahtau_n_fine": 35,
38 | "c0_if_ahthr_n_coarse": 7,
39 | "c0_if_ahthr_n_fine": 0,
40 | "c0_if_casc_n_coarse": 7,
41 | "c0_if_casc_n_fine": 0,
42 | "c0_pulse_pwlk_p_coarse": 3,
43 | "c0_pulse_pwlk_p_fine": 106,
44 | "c0_ps_weight_inh_s_n_coarse": 7,
45 | "c0_ps_weight_inh_s_n_fine": 0,
46 | "c0_ps_weight_inh_f_n_coarse": 7,
47 | "c0_ps_weight_inh_f_n_fine": 0,
48 | "c0_ps_weight_exc_s_n_coarse": 7,
49 | "c0_ps_weight_exc_s_n_fine": 0,
50 | "c0_ps_weight_exc_f_n_coarse": 7,
51 | "c0_ps_weight_exc_f_n_fine": 0,
52 | "c0_npdpii_tau_s_p_coarse": 7,
53 | "c0_npdpii_tau_s_p_fine": 40,
54 | "c0_npdpii_tau_f_p_coarse": 7,
55 | "c0_npdpii_tau_f_p_fine": 0,
56 | "c0_npdpii_thr_s_p_coarse": 7,
57 | "c0_npdpii_thr_s_p_fine": 40,
58 | "c0_npdpii_thr_f_p_coarse": 7,
59 | "c0_npdpii_thr_f_p_fine": 0,
60 | "c0_npdpie_tau_s_p_coarse": 7,
61 | "c0_npdpie_tau_s_p_fine": 0,
62 | "c0_npdpie_tau_f_p_coarse": 7,
63 | "c0_npdpie_tau_f_p_fine": 40,
64 | "c0_npdpie_thr_s_p_coarse": 7,
65 | "c0_npdpie_thr_s_p_fine": 0,
66 | "c0_npdpie_thr_f_p_coarse": 7,
67 | "c0_npdpie_thr_f_p_fine": 0,
68 | "c0_r2r_p_coarse": 4,
69 | "c0_r2r_p_fine": 85,
70 |
71 | "c1_if_buf_p_coarse": 3,
72 | "c1_if_buf_p_fine": 80,
73 | "c1_if_rfr_n_coarse": 3,
74 | "c1_if_rfr_n_fine": 3,
75 | "c1_if_nmda_n_coarse": 7,
76 | "c1_if_nmda_n_fine": 0,
77 | "c1_if_dc_p_coarse": 7,
78 | "c1_if_dc_p_fine": 30,
79 | "c1_if_tau1_coarse": 0,
80 | "c1_if_tau1_fine": 5,
81 | "c1_if_tau2_coarse": 6,
82 | "c1_if_tau2_fine": 100,
83 | "c1_if_thr_n_coarse": 4,
84 | "c1_if_thr_n_fine": 120,
85 | "c1_if_ahw_p_coarse": 7,
86 | "c1_if_ahw_p_fine": 0,
87 | "c1_if_ahtau_n_coarse": 7,
88 | "c1_if_ahtau_n_fine": 35,
89 | "c1_if_ahthr_n_coarse": 7,
90 | "c1_if_ahthr_n_fine": 0,
91 | "c1_if_casc_n_coarse": 7,
92 | "c1_if_casc_n_fine": 0,
93 | "c1_pulse_pwlk_p_coarse": 3,
94 | "c1_pulse_pwlk_p_fine": 106,
95 | "c1_ps_weight_inh_s_n_coarse": 7,
96 | "c1_ps_weight_inh_s_n_fine": 0,
97 | "c1_ps_weight_inh_f_n_coarse": 7,
98 | "c1_ps_weight_inh_f_n_fine": 0,
99 | "c1_ps_weight_exc_s_n_coarse": 7,
100 | "c1_ps_weight_exc_s_n_fine": 0,
101 | "c1_ps_weight_exc_f_n_coarse": 7,
102 | "c1_ps_weight_exc_f_n_fine": 0,
103 | "c1_npdpii_tau_s_p_coarse": 7,
104 | "c1_npdpii_tau_s_p_fine": 40,
105 | "c1_npdpii_tau_f_p_coarse": 7,
106 | "c1_npdpii_tau_f_p_fine": 0,
107 | "c1_npdpii_thr_s_p_coarse": 7,
108 | "c1_npdpii_thr_s_p_fine": 40,
109 | "c1_npdpii_thr_f_p_coarse": 7,
110 | "c1_npdpii_thr_f_p_fine": 0,
111 | "c1_npdpie_tau_s_p_coarse": 7,
112 | "c1_npdpie_tau_s_p_fine": 0,
113 | "c1_npdpie_tau_f_p_coarse": 7,
114 | "c1_npdpie_tau_f_p_fine": 40,
115 | "c1_npdpie_thr_s_p_coarse": 7,
116 | "c1_npdpie_thr_s_p_fine": 0,
117 | "c1_npdpie_thr_f_p_coarse": 7,
118 | "c1_npdpie_thr_f_p_fine": 0,
119 | "c1_r2r_p_coarse": 4,
120 | "c1_r2r_p_fine": 85,
121 |
122 | "c2_if_buf_p_coarse": 3,
123 | "c2_if_buf_p_fine": 80,
124 | "c2_if_rfr_n_coarse": 3,
125 | "c2_if_rfr_n_fine": 3,
126 | "c2_if_nmda_n_coarse": 7,
127 | "c2_if_nmda_n_fine": 0,
128 | "c2_if_dc_p_coarse": 7,
129 | "c2_if_dc_p_fine": 30,
130 | "c2_if_tau1_coarse": 0,
131 | "c2_if_tau1_fine": 5,
132 | "c2_if_tau2_coarse": 6,
133 | "c2_if_tau2_fine": 100,
134 | "c2_if_thr_n_coarse": 4,
135 | "c2_if_thr_n_fine": 120,
136 | "c2_if_ahw_p_coarse": 7,
137 | "c2_if_ahw_p_fine": 0,
138 | "c2_if_ahtau_n_coarse": 7,
139 | "c2_if_ahtau_n_fine": 35,
140 | "c2_if_ahthr_n_coarse": 7,
141 | "c2_if_ahthr_n_fine": 0,
142 | "c2_if_casc_n_coarse": 7,
143 | "c2_if_casc_n_fine": 0,
144 | "c2_pulse_pwlk_p_coarse": 3,
145 | "c2_pulse_pwlk_p_fine": 106,
146 | "c2_ps_weight_inh_s_n_coarse": 7,
147 | "c2_ps_weight_inh_s_n_fine": 0,
148 | "c2_ps_weight_inh_f_n_coarse": 7,
149 | "c2_ps_weight_inh_f_n_fine": 0,
150 | "c2_ps_weight_exc_s_n_coarse": 7,
151 | "c2_ps_weight_exc_s_n_fine": 0,
152 | "c2_ps_weight_exc_f_n_coarse": 7,
153 | "c2_ps_weight_exc_f_n_fine": 0,
154 | "c2_npdpii_tau_s_p_coarse": 7,
155 | "c2_npdpii_tau_s_p_fine": 40,
156 | "c2_npdpii_tau_f_p_coarse": 7,
157 | "c2_npdpii_tau_f_p_fine": 0,
158 | "c2_npdpii_thr_s_p_coarse": 7,
159 | "c2_npdpii_thr_s_p_fine": 40,
160 | "c2_npdpii_thr_f_p_coarse": 7,
161 | "c2_npdpii_thr_f_p_fine": 0,
162 | "c2_npdpie_tau_s_p_coarse": 7,
163 | "c2_npdpie_tau_s_p_fine": 0,
164 | "c2_npdpie_tau_f_p_coarse": 7,
165 | "c2_npdpie_tau_f_p_fine": 40,
166 | "c2_npdpie_thr_s_p_coarse": 7,
167 | "c2_npdpie_thr_s_p_fine": 0,
168 | "c2_npdpie_thr_f_p_coarse": 7,
169 | "c2_npdpie_thr_f_p_fine": 0,
170 | "c2_r2r_p_coarse": 4,
171 | "c2_r2r_p_fine": 85,
172 |
173 | "c3_if_buf_p_coarse": 3,
174 | "c3_if_buf_p_fine": 80,
175 | "c3_if_rfr_n_coarse": 3,
176 | "c3_if_rfr_n_fine": 3,
177 | "c3_if_nmda_n_coarse": 7,
178 | "c3_if_nmda_n_fine": 0,
179 | "c3_if_dc_p_coarse": 7,
180 | "c3_if_dc_p_fine": 30,
181 | "c3_if_tau1_coarse": 0,
182 | "c3_if_tau1_fine": 5,
183 | "c3_if_tau2_coarse": 6,
184 | "c3_if_tau2_fine": 100,
185 | "c3_if_thr_n_coarse": 4,
186 | "c3_if_thr_n_fine": 120,
187 | "c3_if_ahw_p_coarse": 7,
188 | "c3_if_ahw_p_fine": 0,
189 | "c3_if_ahtau_n_coarse": 7,
190 | "c3_if_ahtau_n_fine": 35,
191 | "c3_if_ahthr_n_coarse": 7,
192 | "c3_if_ahthr_n_fine": 0,
193 | "c3_if_casc_n_coarse": 7,
194 | "c3_if_casc_n_fine": 0,
195 | "c3_pulse_pwlk_p_coarse": 3,
196 | "c3_pulse_pwlk_p_fine": 106,
197 | "c3_ps_weight_inh_s_n_coarse": 7,
198 | "c3_ps_weight_inh_s_n_fine": 0,
199 | "c3_ps_weight_inh_f_n_coarse": 7,
200 | "c3_ps_weight_inh_f_n_fine": 0,
201 | "c3_ps_weight_exc_s_n_coarse": 7,
202 | "c3_ps_weight_exc_s_n_fine": 0,
203 | "c3_ps_weight_exc_f_n_coarse": 7,
204 | "c3_ps_weight_exc_f_n_fine": 0,
205 | "c3_npdpii_tau_s_p_coarse": 7,
206 | "c3_npdpii_tau_s_p_fine": 40,
207 | "c3_npdpii_tau_f_p_coarse": 7,
208 | "c3_npdpii_tau_f_p_fine": 0,
209 | "c3_npdpii_thr_s_p_coarse": 7,
210 | "c3_npdpii_thr_s_p_fine": 40,
211 | "c3_npdpii_thr_f_p_coarse": 7,
212 | "c3_npdpii_thr_f_p_fine": 0,
213 | "c3_npdpie_tau_s_p_coarse": 7,
214 | "c3_npdpie_tau_s_p_fine": 0,
215 | "c3_npdpie_tau_f_p_coarse": 7,
216 | "c3_npdpie_tau_f_p_fine": 40,
217 | "c3_npdpie_thr_s_p_coarse": 7,
218 | "c3_npdpie_thr_s_p_fine": 0,
219 | "c3_npdpie_thr_f_p_coarse": 7,
220 | "c3_npdpie_thr_f_p_fine": 0,
221 | "c3_r2r_p_coarse": 4,
222 | "c3_r2r_p_fine": 85,
223 |
224 | "d_buffer_coarse": 1,
225 | "d_buffer_fine": 2,
226 | "d_ssp_coarse": 0,
227 | "d_ssp_fine": 7,
228 | "d_ssn_coarse": 0,
229 | "d_ssn_fine": 15,
230 | "u_buffer_coarse": 1,
231 | "u_buffer_fine": 2,
232 | "u_ssp_coarse": 0,
233 | "u_ssp_fine": 7,
234 | "u_ssn_coarse": 0,
235 | "u_ssn_fine": 15
236 | }
237 | ```
238 |
--------------------------------------------------------------------------------
/pyaer/filters.py:
--------------------------------------------------------------------------------
1 | """Implementation of software filters in libcaer.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | from typing import Any
7 | from typing import Dict
8 |
9 | from pyaer import libcaer
10 | from pyaer import utils
11 |
12 |
13 | class DVSNoise(object):
14 | """Software DVS background activity filter.
15 |
16 | # Args:
17 | size_x: maximum X axis resolution.
18 | size_y: maximum Y axis resolution.
19 | """
20 |
21 | def __init__(self, size_x: int, size_y: int) -> None:
22 | """DVS Noise."""
23 | self.size_x = size_x
24 | self.size_y = size_y
25 | self.handle = None
26 |
27 | self.initialize()
28 |
29 | if self.handle is None:
30 | raise ValueError(
31 | "Software background activity filter" "initialization failed."
32 | )
33 |
34 | def initialize(self) -> None:
35 | """Initializes."""
36 | if self.handle is None:
37 | self.handle = libcaer.caerFilterDVSNoiseInitialize(
38 | sizeX=self.size_x, sizeY=self.size_y
39 | )
40 |
41 | def destroy(self) -> None:
42 | """Destroys DVS noise filter to free up memory."""
43 | libcaer.caerFilterDVSNoiseDestroy(self.handle)
44 |
45 | def set_bias_from_json(self, file_path: str, verbose: bool = False) -> None:
46 | """Sets bias from loading JSON configuration file.
47 |
48 | # Args:
49 | file_path: absolute path of the JSON bias file.
50 | verbose: print verbosely if True.
51 | """
52 | bias_obj = utils.load_dvs_bias(file_path, verbose)
53 | self.set_bias(bias_obj)
54 |
55 | def set_bias(self, bias_obj: Dict[str, Any]) -> None:
56 | """Configures filter.
57 |
58 | # Args:
59 | bias_obj: A dictionary that contains the configuration of the filter.
60 | """
61 | self.set_config(
62 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_TWO_LEVELS,
63 | bias_obj["sw_background_activity_two_levels"],
64 | )
65 | self.set_config(
66 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_CHECK_POLARITY,
67 | bias_obj["sw_background_activity_check_polarity"],
68 | )
69 | self.set_config(
70 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_SUPPORT_MIN,
71 | bias_obj["sw_background_activity_support_min"],
72 | )
73 | self.set_config(
74 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_SUPPORT_MAX,
75 | bias_obj["sw_background_activity_support_max"],
76 | )
77 | self.set_config(
78 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_TIME,
79 | bias_obj["sw_background_activity_time"],
80 | )
81 | self.set_config(
82 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_ENABLE,
83 | bias_obj["sw_background_activity_enable"],
84 | )
85 |
86 | self.set_config(
87 | libcaer.CAER_FILTER_DVS_REFRACTORY_PERIOD_TIME,
88 | bias_obj["sw_refractory_period_time"],
89 | )
90 | self.set_config(
91 | libcaer.CAER_FILTER_DVS_REFRACTORY_PERIOD_ENABLE,
92 | bias_obj["sw_refractory_period_enable"],
93 | )
94 |
95 | self.set_config(
96 | libcaer.CAER_FILTER_DVS_HOTPIXEL_ENABLE, bias_obj["sw_hotpixel_enable"]
97 | )
98 |
99 | if bias_obj["sw_hotpixel_enable"] is True:
100 | self.set_config(
101 | libcaer.CAER_FILTER_DVS_HOTPIXEL_LEARN, bias_obj["sw_hotpixel_learn"]
102 | )
103 | # self.set_config(
104 | # libcaer.CAER_FILTER_DVS_HOTPIXEL_TIME,
105 | # bias_obj["sw_hotpixel_time"])
106 | # self.set_config(
107 | # libcaer.CAER_FILTER_DVS_HOTPIXEL_COUNT,
108 | # bias_obj["sw_hotpixel_count"])
109 |
110 | def get_bias(self) -> Dict[str, Any]:
111 | """Exports configuration.
112 |
113 | # Returns:
114 | bias_obj: A dictionary that contains the configuration of the filter.
115 | """
116 | bias_obj = {}
117 |
118 | bias_obj["sw_background_activity_two_levels"] = bool(
119 | self.get_config(libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_TWO_LEVELS)
120 | )
121 | bias_obj["sw_background_activity_check_polarity"] = bool(
122 | self.get_config(libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_CHECK_POLARITY)
123 | )
124 | bias_obj["sw_background_activity_support_min"] = self.get_config(
125 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_SUPPORT_MIN
126 | )
127 | bias_obj["sw_background_activity_support_max"] = self.get_config(
128 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_SUPPORT_MAX
129 | )
130 | bias_obj["sw_background_activity_time"] = self.get_config(
131 | libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_TIME
132 | )
133 | bias_obj["sw_background_activity_enable"] = bool(
134 | self.get_config(libcaer.CAER_FILTER_DVS_BACKGROUND_ACTIVITY_ENABLE)
135 | )
136 |
137 | bias_obj["sw_refractory_period_time"] = self.get_config(
138 | libcaer.CAER_FILTER_DVS_REFRACTORY_PERIOD_TIME
139 | )
140 | bias_obj["sw_refractory_period_enable"] = bool(
141 | self.get_config(libcaer.CAER_FILTER_DVS_REFRACTORY_PERIOD_ENABLE)
142 | )
143 |
144 | bias_obj["sw_hotpixel_enable"] = bool(
145 | self.get_config(libcaer.CAER_FILTER_DVS_HOTPIXEL_ENABLE)
146 | )
147 |
148 | bias_obj["sw_hotpixel_learn"] = bool(
149 | self.get_config(libcaer.CAER_FILTER_DVS_HOTPIXEL_LEARN)
150 | )
151 | if bias_obj["sw_hotpixel_enable"] is True:
152 | bias_obj["sw_hotpixel_time"] = self.get_config(
153 | libcaer.CAER_FILTER_DVS_HOTPIXEL_TIME
154 | )
155 | bias_obj["sw_hotpixel_count"] = self.get_config(
156 | libcaer.CAER_FILTER_DVS_HOTPIXEL_COUNT
157 | )
158 |
159 | return bias_obj
160 |
161 | def save_bias_to_json(self, file_path: str) -> bool:
162 | """Saves filter configuration to JSON.
163 |
164 | # Args:
165 | file_path: the absolute path to the destiation.
166 |
167 | # Returns:
168 | flag: returns True if success in writing, False otherwise.
169 | """
170 | bias_obj = self.get_bias()
171 | return utils.write_json(file_path, bias_obj)
172 |
173 | def set_config(self, param_addr: str, param: Any) -> bool:
174 | """Sets configuration.
175 |
176 | # Args:
177 | param_addr: a configuration parameter address, see defines
178 | `CAER_FILTER_DVS_*`.
179 | param: a configuration parameter value integer.
180 |
181 | # Returns:
182 | True if operation successful, false otherwise.
183 | """
184 | if self.handle is not None:
185 | set_sucess = libcaer.caerFilterDVSNoiseConfigSet(
186 | noiseFilter=self.handle, paramAddr=param_addr, param=param
187 | )
188 | return set_sucess
189 | else:
190 | return False
191 |
192 | def get_config(self, param_addr: str) -> Any:
193 | """Gets configuration.
194 |
195 | # Args:
196 | param_addr: a configuration parameter address, see defines
197 | `CAER_FILTER_DVS_*`.
198 |
199 | # Returns:
200 | The value of the configuration.
201 | """
202 | if self.handle is not None:
203 | return libcaer.caerFilterDVSNoiseConfigGet(self.handle, param_addr)
204 | else:
205 | return None
206 |
207 | def apply(self, event_packet: Any) -> Any:
208 | """Apply the filter to a event_packet.
209 |
210 | # Args:
211 | event_packet: `caerEventPacket`
212 | the event packet to filter.
213 |
214 | # Returns:
215 | The filtered event packet.
216 | """
217 | return libcaer.apply_dvs_noise_filter(self.handle, event_packet)
218 |
--------------------------------------------------------------------------------
/pyaer/utils.py:
--------------------------------------------------------------------------------
1 | """Utilities Functions.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | import importlib.util as imutil
7 | import json
8 | import os
9 | import time
10 | from collections import OrderedDict
11 |
12 | import numpy as np
13 | import yaml
14 |
15 | import pyaer
16 | from pyaer import libcaer
17 | from pyaer import log
18 |
19 | logger = log.get_logger("utils", pyaer.LOG_LEVEL)
20 |
21 |
22 | def get_nanotime():
23 | return str(int(time.time() * 1e9)).encode("utf-8")
24 |
25 |
26 | def import_custom_module(custom_file, custom_class):
27 | """Load custom module by file path.
28 |
29 | # Arguments
30 | custom_file: str
31 | absolute file path to the custom module file.
32 | custom_class: str
33 | the class name to import that is in the custom_file
34 | """
35 | module_name = os.path.basename(custom_file).split(".")[0]
36 | spec = imutil.spec_from_file_location(module_name, custom_file)
37 | custom_pub = imutil.module_from_spec(spec)
38 | spec.loader.exec_module(custom_pub)
39 |
40 | return getattr(custom_pub, custom_class)
41 |
42 |
43 | def parse_type(custom_str):
44 | """Parse custom string to its corresponding type."""
45 |
46 | # check integer
47 | try:
48 | return int(custom_str)
49 | except ValueError:
50 | pass
51 |
52 | # check float
53 | try:
54 | return float(custom_str)
55 | except ValueError:
56 | pass
57 |
58 | # check boolean
59 | if custom_str in ["True", "False"]:
60 | return custom_str == "True"
61 |
62 | # Return string
63 | return custom_str
64 |
65 |
66 | def parse_custom_args(custom_args):
67 | """Parse custom arguments.
68 |
69 | NOTE: DO NOT USE "-" IN YOUR CUSTOM ARGUMENTS
70 |
71 | # Arguments
72 | custom_args: list
73 | the custom args supplied by parse_known_args()
74 | function
75 |
76 | # Returns
77 | custom_args_dict: dict
78 | a dictionary that contains formatted custom args.
79 | """
80 | # empty list
81 | if len(custom_args) == 0:
82 | return {}
83 |
84 | custom_args_dict = dict(
85 | zip(
86 | [opt.replace("-", "") for opt in custom_args[::2]],
87 | [parse_type(val) for val in custom_args[1::2]],
88 | )
89 | )
90 |
91 | return custom_args_dict
92 |
93 |
94 | def ordered_yml_load(stream, Loader=yaml.SafeLoader, object_pairs_hook=OrderedDict):
95 | """Load YAML configs in order."""
96 |
97 | class OrderedLoader(Loader):
98 | pass
99 |
100 | def construct_mapping(loader, node):
101 | loader.flatten_mapping(node)
102 | return object_pairs_hook(loader.construct_pairs(node))
103 |
104 | OrderedLoader.add_constructor(
105 | yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, construct_mapping
106 | )
107 |
108 | return yaml.load(stream, OrderedLoader)
109 |
110 |
111 | def ordered_yml_dump(data, stream=None, Dumper=yaml.SafeDumper, **kwds):
112 | """Dump YAML configs in order."""
113 |
114 | class OrderedDumper(Dumper):
115 | pass
116 |
117 | def _dict_representer(dumper, data):
118 | return dumper.represent_mapping(
119 | yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, data.items()
120 | )
121 |
122 | OrderedDumper.add_representer(OrderedDict, _dict_representer)
123 | return yaml.dump(data, stream, OrderedDumper, **kwds)
124 |
125 |
126 | def expandpath(path):
127 | return os.path.abspath(os.path.expandvars(os.path.expanduser(path)))
128 |
129 |
130 | def load_json(file_path):
131 | """Load JSON string.
132 |
133 | # Arguments
134 | file_path: `str`
135 | the absolute path to the JSON string.
136 |
137 | # Returns
138 | json_obj: `dict`
139 | A JSON object
140 | """
141 | try:
142 | json_obj = json.load(open(file_path))
143 | return json_obj
144 | except IOError:
145 | return None
146 |
147 |
148 | def write_json(file_path, json_obj):
149 | """Write JSON string.
150 |
151 | # Arguments
152 | file_path: `str`
153 | the absolute path to the JSON string.
154 | json_obj: `dict`
155 | a dictionary
156 |
157 | # Returns
158 | flag : bool
159 | True if saved successfully
160 | False otherwise
161 | """
162 | try:
163 | with open(file_path, "w") as f:
164 | json.dump(json_obj, f)
165 | f.close()
166 | return True
167 | except IOError:
168 | return False
169 |
170 |
171 | def load_dvs_bias(file_path, verbose=False):
172 | """Load bias for DVS128.
173 |
174 | # Arguments
175 | file_path : `str`
`
176 | the absolute path to the JSON string.
177 |
178 | # Returns
179 | bias_obj: `dict`
180 | A dictionary that contains valid DVS128 bias.
181 | """
182 | bias_obj = load_json(file_path)
183 |
184 | if bias_obj is not None:
185 | if verbose:
186 | for key, value in bias_obj.iteritems():
187 | logger.debug("%s: %d" % (key, value))
188 | # TODO: to check validity of the bias file
189 | return bias_obj
190 | else:
191 | return None
192 |
193 |
194 | def load_davis_bias(file_path, verbose=False):
195 | """Load DAVIS bias.
196 |
197 | TODO: to investigate bias differences between 240C and 346.
198 |
199 | # Arguments
200 | file_path : `str`
`
201 | the absolute path to the JSON string.
202 |
203 | # Returns
204 | bias_obj: `dict`
205 | A dictionary that contains valid DAVIS bias.
206 | """
207 | bias_obj = load_json(file_path)
208 |
209 | if bias_obj is not None:
210 | if verbose:
211 | for key, value in bias_obj.iteritems():
212 | logger.debug("%s: %d" % (key, value))
213 | # TODO: to check validity of the bias file
214 | return bias_obj
215 | else:
216 | return None
217 |
218 |
219 | def load_dvxplorer_bias(file_path, verbose=False):
220 | """Load DVXPLORER bias.
221 |
222 | # Arguments
223 | file_path : `str`
`
224 | the absolute path to the JSON string.
225 |
226 | # Returns
227 | bias_obj: `dict`
228 | A dictionary that contains valid DVXPLORER bias.
229 | """
230 | bias_obj = load_json(file_path)
231 |
232 | if bias_obj is not None:
233 | if verbose:
234 | for key, value in bias_obj.iteritems():
235 | logger.debug("%s: %d" % (key, value))
236 | # TODO: to check validity of the bias file
237 | return bias_obj
238 | else:
239 | return None
240 |
241 |
242 | def load_evk_bias(file_path, verbose=False):
243 | """Load EVK bias.
244 |
245 | # Arguments
246 | file_path : `str`
`
247 | the absolute path to the JSON string.
248 |
249 | # Returns
250 | bias_obj: `dict`
251 | A dictionary that contains valid EVK bias.
252 | """
253 | bias_obj = load_json(file_path)
254 |
255 | if bias_obj is not None:
256 | if verbose:
257 | for key, value in bias_obj.iteritems():
258 | logger.debug("%s: %d" % (key, value))
259 | # TODO: to check validity of the bias file
260 | return bias_obj
261 | else:
262 | return None
263 |
264 |
265 | def load_dynapse_bias(file_path, verbose=False):
266 | """Load DYNAPSE bias.
267 |
268 | # Arguments
269 | file_path: `str`
`
270 | the absolute path to the JSON string.
271 |
272 | # Returns
273 | bias_obj: `dict`
274 | A dictionary that contains valid DYNAPSE bias.
275 | """
276 | bias_obj = load_json(file_path)
277 |
278 | if bias_obj is not None:
279 | if verbose:
280 | for key, value in bias_obj.iteritems():
281 | logger.debug("%s: %d" % (key, value))
282 | # TODO: to check validity of the bias file
283 | return bias_obj
284 | else:
285 | return None
286 |
287 |
288 | def discover_devices(device_type, max_devices=100):
289 | """Automatic discover devices.
290 |
291 | # Arguments
292 | device_type: `int`
293 | * -1 - CAER_DEVICE_DISCOVER_ALL
294 | * 0 - CAER_DEVICE_DVS128
295 | * 1 - CAER_DEVICE_DAVIS_FX2
296 | * 2 - CAER_DEVICE_DAVIS_FX3
297 | * 3 - CAER_DEVICE_DYNAPSE
298 | * 4 - CAER_DEVICE_DAVIS
299 | * 5 - CAER_DEVICE_EDVS
300 | * 6 - CAER_DEVICE_DAVIS_RPI
301 |
302 | # Returns
303 | discovered_devices: `numpy.ndarray`
304 | a (num_devices, 3) array
305 | the first column is device type
306 | the second column is device USB bus number or
307 | serial port name for EDVS
308 | (cannot detect string, set to 0)
309 | the third column is device USB device address or
310 | serial Baud rate (if EDVS)
311 | discovered devices type with the order
312 | Note that the array has the data type uint64,
313 | please reformat the number if necessary.
314 | num_devices: `int`
315 | number of available devices
316 | """
317 | discovered_devices = libcaer.device_discover(device_type, (max_devices + 1) * 3)
318 |
319 | discovered_devices = discovered_devices.reshape((max_devices + 1), 3)
320 | num_devices = np.argwhere(discovered_devices == 42)[0][0]
321 |
322 | return discovered_devices[:num_devices], num_devices
323 |
--------------------------------------------------------------------------------
/scripts/aer_comm/aer_launch:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Parse and Launch AER Communication Programs.
4 |
5 | Author: Yuhuang Hu
6 | Email : yuhuang.hu@ini.uzh.ch
7 | """
8 |
9 | from __future__ import print_function, absolute_import
10 |
11 | import os
12 | import sys
13 | import argparse
14 | import time
15 |
16 | from pyaer.utils import expandpath
17 | from pyaer.utils import ordered_yml_load
18 | from pyaer.comm import AERProcess
19 | from pyaer import log
20 |
21 | HUB = "Hub"
22 | PUB = "Publisher"
23 | SUB = "Subscriber"
24 | PUBSUB = "PubSuber"
25 | SAVER = "Saver"
26 |
27 | USE_DEFAULT = "use_default"
28 | USE_DEFAULT_PUB = "use_default_pub"
29 | USE_DEFAULT_SUB = "use_default_sub"
30 | DEFAULT_URL = "tcp://127.0.0.1"
31 | DEFAULT_PUBLISHER_PORT = "5100"
32 | DEFAULT_SUBSCRIBER_PORT = "5099"
33 | DEFAULT_AER_HUB_NAME = "PyAER Message Hub"
34 | DEFAULT_AER_PUBLISHER_PROGRAM = "aer_publisher"
35 | DEFAULT_AER_SUBSCRIBER_PROGRAM = "aer_subscriber"
36 | DEFAULT_AER_PUBSUBER_PROGRAM = "aer_pubsuber"
37 |
38 | DEFAULT_HDF5_MODE = "w"
39 | DEFAULT_LIBVER_VERSION = "earliest"
40 |
41 | PROGRAM_KEY = "program"
42 |
43 | launch_logger = log.get_logger(
44 | "AER Launcher",
45 | log.INFO, stream=sys.stdout)
46 |
47 |
48 | def parse_hub(hub_desc):
49 | parsed_cmd = ["aer_hub"]
50 |
51 | if hub_desc[USE_DEFAULT] is True:
52 | parsed_cmd += ["--url", DEFAULT_URL]
53 | parsed_cmd += ["--publisher_port", DEFAULT_PUBLISHER_PORT]
54 | parsed_cmd += ["--subscriber_port", DEFAULT_SUBSCRIBER_PORT]
55 | parsed_cmd += ["--aer_hub_name", DEFAULT_AER_HUB_NAME]
56 |
57 | return parsed_cmd
58 |
59 | parsed_cmd += ["--url", hub_desc["url"]]
60 | parsed_cmd += ["--publisher_port", str(hub_desc["publisher_port"])]
61 | parsed_cmd += ["--subscriber_port", str(hub_desc["subscriber_port"])]
62 | parsed_cmd += ["--aer_hub_name", hub_desc["aer_hub_name"]]
63 |
64 | return parsed_cmd
65 |
66 |
67 | def parse_publisher(pub_desc):
68 | parsed_cmd = []
69 |
70 | # select program
71 | if PROGRAM_KEY in pub_desc:
72 | parsed_cmd += [expandpath(pub_desc[PROGRAM_KEY])]
73 | else:
74 | parsed_cmd += [DEFAULT_AER_PUBLISHER_PROGRAM]
75 |
76 | parsed_cmd += [
77 | "--url",
78 | DEFAULT_URL if "url" not in pub_desc else pub_desc.pop("url")]
79 | parsed_cmd += [
80 | "--port",
81 | DEFAULT_PUBLISHER_PORT if "port" not in pub_desc else
82 | str(pub_desc.pop("port"))]
83 |
84 | parsed_cmd += ["--name", pub_desc.pop("name")]
85 | parsed_cmd += ["--master_topic", pub_desc.pop("master_topic")]
86 |
87 | if "custom_pub" in pub_desc:
88 | # parse custom command
89 | # follows the form /file/path/class_name
90 | custom_pub, custom_class = os.path.split(pub_desc.pop("custom_pub"))
91 |
92 | parsed_cmd += ["--custom_pub", expandpath(custom_pub)]
93 | parsed_cmd += ["--custom_class", custom_class]
94 | else:
95 | parsed_cmd += ["--use_default_pub"]
96 |
97 | pub_desc.pop(USE_DEFAULT_PUB)
98 |
99 | try:
100 | parsed_cmd += ["--device", pub_desc.pop("device")]
101 | if pub_desc.pop("noise_filter", default=False):
102 | parsed_cmd += ["--noise_filter"]
103 | if "bias_file" in pub_desc:
104 | parsed_cmd += [
105 | "--bias_file", expandpath(pub_desc.pop("bias_file"))]
106 | except Exception:
107 | pass
108 |
109 | try:
110 | for (option, value) in pub_desc.items():
111 | parsed_cmd += ["--{}".format(option), str(value)]
112 | except Exception:
113 | pass
114 |
115 | return parsed_cmd
116 |
117 |
118 | def parse_subscriber(sub_desc):
119 | parsed_cmd = []
120 |
121 | # select program
122 | if PROGRAM_KEY in sub_desc:
123 | parsed_cmd += [expandpath(sub_desc[PROGRAM_KEY])]
124 | else:
125 | parsed_cmd += [DEFAULT_AER_SUBSCRIBER_PROGRAM]
126 |
127 | parsed_cmd += [
128 | "--url",
129 | DEFAULT_URL if "url" not in sub_desc else sub_desc.pop("url")]
130 | parsed_cmd += [
131 | "--port",
132 | DEFAULT_SUBSCRIBER_PORT if "port" not in sub_desc else
133 | str(sub_desc.pop("port"))]
134 | parsed_cmd += ["--name", sub_desc.pop("name")]
135 | parsed_cmd += ["--topic", sub_desc.pop("topic")]
136 |
137 | if "custom_sub" in sub_desc:
138 | # parse custom command
139 | # follows the form /file/path/class_name
140 | custom_sub, custom_class = os.path.split(sub_desc.pop("custom_sub"))
141 |
142 | parsed_cmd += ["--custom_sub", expandpath(custom_sub)]
143 | parsed_cmd += ["--custom_class", custom_class]
144 | else:
145 | parsed_cmd += ["--use_default_sub"]
146 |
147 | sub_desc.pop(USE_DEFAULT_SUB)
148 |
149 | try:
150 | for (option, value) in sub_desc.items():
151 | parsed_cmd += ["--{}".format(option), str(value)]
152 | except Exception:
153 | pass
154 |
155 | return parsed_cmd
156 |
157 |
158 | def parse_pubsuber(pubsuber_desc):
159 | parsed_cmd = []
160 |
161 | # select program
162 | if PROGRAM_KEY in pubsuber_desc:
163 | parsed_cmd += [expandpath(pubsuber_desc[PROGRAM_KEY])]
164 | else:
165 | parsed_cmd += [DEFAULT_AER_PUBSUBER_PROGRAM]
166 |
167 | parsed_cmd += [
168 | "--url",
169 | DEFAULT_URL if "url" not in pubsuber_desc else
170 | pubsuber_desc.pop("url")]
171 | parsed_cmd += [
172 | "--pub_port",
173 | DEFAULT_PUBLISHER_PORT if "pub_port" not in pubsuber_desc else
174 | str(pubsuber_desc.pop("pub_port"))]
175 | parsed_cmd += ["--pub_name", pubsuber_desc.pop("pub_name")]
176 | parsed_cmd += ["--pub_topic", pubsuber_desc.pop("pub_topic")]
177 |
178 | parsed_cmd += [
179 | "--sub_port",
180 | DEFAULT_SUBSCRIBER_PORT if "sub_port" not in pubsuber_desc else
181 | str(pubsuber_desc.pop("sub_port"))]
182 | parsed_cmd += ["--sub_name", pubsuber_desc.pop("sub_name")]
183 | parsed_cmd += ["--sub_topic", pubsuber_desc.pop("sub_topic")]
184 |
185 | custom_pubsuber, custom_class = os.path.split(
186 | pubsuber_desc.pop("custom_pubsuber"))
187 | parsed_cmd += ["--custom_pubsuber", expandpath(custom_pubsuber)]
188 | parsed_cmd += ["--custom_class", custom_class]
189 |
190 | # Leave this here, maybe useful
191 | try:
192 | parsed_cmd += ["--device", pubsuber_desc.pop("device")]
193 | if pubsuber_desc.pop("noise_filter", default=False):
194 | parsed_cmd += ["--noise_filter"]
195 | if "bias_file" in pubsuber_desc:
196 | parsed_cmd += ["--bias_file", expandpath(
197 | pubsuber_desc.pop("bias_file"))]
198 | except Exception:
199 | pass
200 |
201 | try:
202 | for (option, value) in pubsuber_desc.items():
203 | parsed_cmd += ["--{}".format(option), str(value)]
204 | except Exception:
205 | pass
206 |
207 | return parsed_cmd
208 |
209 |
210 | def parse_saver(saver_desc):
211 | parsed_cmd = ["aer_saver"]
212 |
213 | parsed_cmd += [
214 | "--url",
215 | DEFAULT_URL if "url" not in saver_desc else saver_desc["url"]]
216 | parsed_cmd += [
217 | "--port",
218 | DEFAULT_SUBSCRIBER_PORT if "port" not in saver_desc else
219 | str(saver_desc["port"])]
220 | parsed_cmd += ["--name", saver_desc["name"]]
221 | parsed_cmd += ["--topic", saver_desc["topic"]]
222 |
223 | parsed_cmd += ["--filename", expandpath(saver_desc["filename"])]
224 |
225 | parsed_cmd += [
226 | "--mode",
227 | DEFAULT_HDF5_MODE if "mode" not in saver_desc else
228 | saver_desc["mode"]]
229 | parsed_cmd += [
230 | "--libver",
231 | DEFAULT_LIBVER_VERSION if "libver" not in saver_desc else
232 | saver_desc["libver"]]
233 |
234 | # Use HDF5 as the default saver
235 | try:
236 | if saver_desc["zarr"] is True:
237 | parsed_cmd += ["--zarr"]
238 | except Exception:
239 | parsed_cmd += ["--hdf5"]
240 |
241 | return parsed_cmd
242 |
243 |
244 | parser = argparse.ArgumentParser("AER Launch")
245 | parser.add_argument("--launch_file", type=expandpath,
246 | help="AER Launch File")
247 |
248 | args = parser.parse_args()
249 |
250 | # load launch file
251 | with open(args.launch_file, "r") as launch_file:
252 | launch_desc = ordered_yml_load(launch_file)
253 |
254 | # main parsing loop
255 | process_collector = [] # collect all active processes
256 |
257 | try:
258 | for pg_i, (pg_type, pg_desc) in enumerate(launch_desc.items()):
259 | # if the first one is not a hub type, then start the default hub
260 | if pg_i == 0 and pg_type != HUB:
261 | parsed_hub_cmd = parse_hub({"use_default": True})
262 | process_collector.append(
263 | AERProcess(parsed_hub_cmd, daemon=True))
264 |
265 | if pg_type == HUB:
266 | parsed_hub_cmd = parse_hub(pg_desc)
267 | process_collector.append(
268 | AERProcess(parsed_hub_cmd))
269 | elif PUB in pg_type:
270 | parsed_pub_cmd = parse_publisher(pg_desc)
271 | process_collector.append(
272 | AERProcess(parsed_pub_cmd))
273 | elif SUB in pg_type:
274 | parsed_sub_cmd = parse_subscriber(pg_desc)
275 | process_collector.append(
276 | AERProcess(parsed_sub_cmd))
277 | elif PUBSUB in pg_type:
278 | parsed_pubsuber_cmd = parse_pubsuber(pg_desc)
279 | process_collector.append(
280 | AERProcess(parsed_pubsuber_cmd))
281 | elif SAVER in pg_type:
282 | parsed_saver_cmd = parse_saver(pg_desc)
283 | process_collector.append(
284 | AERProcess(parsed_saver_cmd))
285 | else:
286 | launch_logger.error("Unsupported Type {}".format(pg_type))
287 |
288 | # launching
289 | for process in process_collector:
290 | process.run()
291 | except Exception:
292 | launch_logger.info("Error launching, terminating all processes.")
293 | for process in reversed(process_collector):
294 | try:
295 | process.stop()
296 | except Exception:
297 | pass
298 | del process
299 | sys.exit(1)
300 |
301 | while True:
302 | try:
303 | time.sleep(1)
304 | except Exception:
305 | launch_logger.info("Exiting launcher, terminating all processes.")
306 | for process in reversed(process_collector):
307 | try:
308 | process.stop()
309 | except Exception:
310 | pass
311 | del process
312 | break
313 |
--------------------------------------------------------------------------------
/custom_build/compile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # This script is to compile libcaer library and Python 2 interface
4 | # Author: Yuhuang Hu
5 | # Email : duguyue100@gmail.com
6 |
7 | # option
8 | fn=$1
9 |
10 | # for installation check
11 | INSTALL_OPT="no"
12 | ENABLE_INSTALL=false
13 |
14 | # customize this to the right configuration
15 | REBUILDING=false
16 | PYTHON_VERSION=2 # TODO: support Python 3 as well
17 | CONDA_LIB_PATH=$HOME/anaconda2/lib
18 | CONDA_PKG_CONFIG_PATH=$CONDA_LIB_PATH/pkgconfig
19 | LIBCAER_INSTALLED=false
20 |
21 | # Color Profile
22 | RED='\033[0;31m'
23 | LIGHT_BLUE='\033[1;34m'
24 | BLUE='\033[0;34m'
25 | GREEN='\033[0;32m'
26 | CYAN='\033[0;36m'
27 | PURPLE='\033[0;35m'
28 | COLOR_END='\033[0m'
29 |
30 | print_help()
31 | {
32 | echo -e "${PURPLE} --------------------------------------------------------------------${COLOR_END}"
33 | echo -e "${PURPLE} Compilation Sequences for PyAER${COLOR_END}"
34 | echo -e "${PURPLE} This script is developed by Yuhuang Hu@INI@UZH/ETHz${COLOR_END}"
35 | echo -e "${PURPLE} Contact: yuhuang.hu@ini.uzh.ch${COLOR_END}"
36 | echo -e "${PURPLE} ${COLOR_END}"
37 | echo -e "${PURPLE} Available functions:${COLOR_END}"
38 | echo -e "${PURPLE} make : make libcaer and SWIG Python bindings${COLOR_END}"
39 | echo -e "${PURPLE} make.lib : make libcaer${COLOR_END}"
40 | echo -e "${PURPLE} make.swig : make Python bindings based on SWIG${COLOR_END}"
41 | echo -e "${PURPLE} make.install : Install Python bindings${COLOR_END}"
42 | echo -e "${PURPLE} clean : Clean installation and compilation files.${COLOR_END}"
43 | echo -e "${PURPLE} clean.lib : Clean libcaer compilation files${COLOR_END}"
44 | echo -e "${PURPLE} clean.swig : Clean SWIG bindings${COLOR_END}"
45 | echo -e "${PURPLE} clean.install : Clean installation${COLOR_END}"
46 | echo -e "${PURPLE} help : Print help${COLOR_END}"
47 | echo -e "${PURPLE} ${COLOR_END}"
48 | echo -e "${PURPLE} Available configuration:${COLOR_END}"
49 | echo -e "${PURPLE} REBUILDING (bool) : false if first time, true if not${COLOR_END}"
50 | echo -e "${PURPLE} PYTHON_VERSION (int) : 2 for Python 2, 3 for Python 3${COLOR_END}"
51 | echo -e "${PURPLE} CONDA_LIB_PATH (str) : Path to custom Python library${COLOR_END}"
52 | echo -e "${PURPLE} CONDA_PKG_CONFIG_PATH (str) : Path to custom Python pkg-config files${COLOR_END}"
53 | echo -e "${PURPLE} LIBCAER_INSTALLED (bool) : false if build libcaer locally,${COLOR_END}"
54 | echo -e "${PURPLE} true if you have libcaer installed in system${COLOR_END}"
55 | echo -e "${PURPLE} --------------------------------------------------------------------${COLOR_END}"
56 | }
57 |
58 | is_yes()
59 | {
60 | yesses={y,Y,yes,Yes,YES}
61 | if [[ $yesses =~ $1 ]]; then
62 | echo 1
63 | fi
64 | }
65 |
66 | print_conf()
67 | {
68 | echo -e "${LIGHT_BLUE}PYTHON VERSION : $PYTHON_VERSION${COLOR_END}"
69 | echo -e "${LIGHT_BLUE}CONDA LIB PATH : $CONDA_LIB_PATH${COLOR_END}"
70 | echo -e "${LIGHT_BLUE}CONDA PKG CONFIG PATH: $CONDA_PKG_CONFIG_PATH${COLOR_END}"
71 | }
72 |
73 |
74 | continue_install()
75 | {
76 | echo -e "${RED}[MESSAGE] Continue installation? (yes/no) [$INSTALL_OPT]${COLOR_END}"
77 | read opt
78 | if [[ $opt == "" ]]; then
79 | opt=$INSTALL_OPT
80 | fi
81 |
82 | if [[ $(is_yes $opt) ]]; then
83 | ENABLE_INSTALL=true
84 | print_conf
85 | fi
86 | }
87 |
88 |
89 | config_installation()
90 | {
91 | if [ -f $PWD/compile.conf ]; then
92 | source $PWD/compile.conf
93 | echo -e "${RED}[MESSAGE] Using customize configuration in the file compile.conf.${COLOR_END}"
94 | continue_install
95 | else
96 | echo -e "${RED}[MESSAGE] No compile.conf found, use default configuration settings if continue installation.${COLOR_END}"
97 | echo -e "${RED}[MESSAGE] Use:${COLOR_END}"
98 | echo -e "${BLUE} cp compile.conf.bak compile.conf${COLOR_END}"
99 | echo -e "${RED} to create your configuration file if you need.${COLOR_END}"
100 | continue_install
101 | fi
102 | }
103 |
104 | compile_swigpy()
105 | {
106 | echo -e "${BLUE}[MESSAGE] Compiling libcaer swig binding${COLOR_END}"
107 | if [ ! -d "$PWD/swigpy" ]; then
108 | if [ $LIBCAER_INSTALLED == false ]; then
109 | export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$PWD/libcaer/build/lib/pkgconfig
110 | fi
111 | export PKG_CONFIG_PATH=$CONDA_PKG_CONFIG_PATH:$PKG_CONFIG_PATH
112 | export LD_LIBRARY_PATH=$CONDA_LIB_PATH:$(pkg-config --variable=libdir libcaer):$LD_LIBRARY_PATH
113 |
114 | # summary information
115 | echo -e "${LIGHT_BLUE}[MESSAGE] libcaer include directory: "$(pkg-config --variable=includedir libcaer)${COLOR_END}
116 | echo -e "${LIGHT_BLUE}[MESSAGE] libcaer library directory: "$(pkg-config --variable=libdir libcaer)${COLOR_END}
117 | echo -e "${LIGHT_BLUE}[MESSAGE] LD_LIBRARY_PATH : "$LD_LIBRARY_PATH ${COLOR_END}
118 |
119 | # compile swig interface
120 | mkdir swigpy
121 | cd swigpy
122 | cp $PWD/../libcaer/bindings/python_swig/pyflags.i .
123 | swig -python -I$(pkg-config --variable=includedir libcaer) -cpperraswarn pyflags.i
124 | if [ $PYTHON_VERSION == 2 ]; then
125 | echo -e "${BLUE}[MESSAGE] Your swig installation should be compile with python 2 library${COLOR_END}"
126 | if [ "$(uname)" == "Darwin" ]; then
127 | # gcc -std=c11 -O2 -fPIC -c pyflags_wrap.c $(pkg-config --cflags python2) -I$(pkg-config --variable=includedir libcaer) -v
128 | clang -O2 -fPIC -c pyflags_wrap.c -I$HOME/anaconda/include/python2.7 -I$(pkg-config --variable=includedir libcaer)
129 | # cc -stdlib=libstdc++ -lstdc++ -arch x86_64 -O2 -fPIC -c pyflags_wrap.c $(pkg-config --cflags python2) -I$(pkg-config --variable=includedir libcaer) -v
130 | elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
131 | gcc -std=c11 -O2 -fPIC -c pyflags_wrap.c $(pkg-config --cflags python2) -I$(pkg-config --variable=includedir libcaer)
132 | fi
133 | elif [ $PYTHON_VERSION == 3]; then
134 | echo -e "${BLUE}[MESSAGE] Your swig installation should be compile with python 3 library${COLOR_END}"
135 | gcc -std=c11 -O2 -fPIC -c pyflags_wrap.c $(pkg-config --cflags python3) -I$(pkg-config --variable=includedir libcaer)
136 | fi
137 | if [ "$(uname)" == "Darwin" ]; then
138 | # ld -macosx_version_min 10.10.0 -L $(pkg-config --variable=libdir libcaer) -lcaer pyflags_wrap.o -o _libcaer_wrap.so
139 | clang pyflags_wrap.o -L$(pkg-config --variable=libdir libcaer) -lpython -lcaer -o _libcaer_wrap.so
140 | elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
141 | ld -L $(pkg-config --variable=libdir libcaer) -shared -lcaer pyflags_wrap.o -o _libcaer_wrap.so
142 | fi
143 |
144 | # configure path
145 | if [ $LIBCAER_INSTALLED == false ]; then
146 | if [[ $REBUILDING == false ]]; then
147 | NEW_LD_PATH="export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"$(pkg-config --variable=libdir libcaer)
148 | # for .bashrc
149 | if [ -f $HOME/.bashrc ]; then
150 | cp $HOME/.bashrc $HOME/.bashrc.pyaer.bak
151 | echo $NEW_LD_PATH >> $HOME/.bashrc
152 | echo -e "${GREEN}LD_LIBRARY_PATH is appended in "$HOME/.bashrc${COLOR_END}
153 | fi
154 | # for .zshrc
155 | if [ -f $HOME/.zshrc ]; then
156 | cp $HOME/.zshrc $HOME/.zshrc.pyaer.bak
157 | echo $NEW_LD_PATH >> $HOME/.zshrc
158 | echo -e "${GREEN}LD_LIBRARY_PATH is appended in "$HOME/.zshrc${COLOR_END}
159 | fi
160 | echo -e "${BLUE}[MESSAGE] LD_LIBRARY_PATH configured.${COLOR_END}"
161 | echo -e "${BLUE}[MESSAGE] Please restart your terminal or source your shell profile.${COLOR_END}"
162 | else
163 | # not appending LD_LIBRARY_PATH if true
164 | echo -e "${RED}[MESSAGE] Rebuilding enabled, no LD_LIBRARY_PATH appended.${COLOR_END}"
165 | fi
166 | fi
167 | else
168 | if [ $LIBCAER_INSTALLED == false ]; then
169 | export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$PWD/libcaer/build/lib/pkgconfig
170 | fi
171 | export PKG_CONFIG_PATH=$CONDA_PKG_CONFIG_PATH:$PKG_CONFIG_PATH
172 | export LD_LIBRARY_PATH=$CONDA_LIB_PATH:$(pkg-config --variable=libdir libcaer):$LD_LIBRARY_PATH
173 |
174 | echo -e "${LIGHT_BLUE}[MESSAGE] libcaer include directory: "$(pkg-config --variable=includedir libcaer)${COLOR_END}
175 | echo -e "${LIGHT_BLUE}[MESSAGE] libcaer library directory: "$(pkg-config --variable=libdir libcaer)${COLOR_END}
176 | echo -e "${LIGHT_BLUE}[MESSAGE] LD_LIBRARY_PATH : "$LD_LIBRARY_PATH ${COLOR_END}
177 | fi
178 | }
179 |
180 | compile_libcaer()
181 | {
182 | echo -e "${BLUE}[MESSAGE] Compiling libcaer${COLOR_END}"
183 | cd libcaer
184 | if [ ! -d "$PWD/libcaer/build" ]; then
185 | mkdir compiled
186 | mkdir build
187 | fi
188 | cd compiled
189 | cmake -DCMAKE_INSTALL_PREFIX=../build ..
190 | make -j8
191 | make install
192 | cd ../..
193 | rm -rf $PWD/libcaer/compiled
194 | }
195 |
196 | make_install()
197 | {
198 | echo -e "${BLUE}[MESSAGE] Installing Python bindings...${COLOR_END}"
199 | cp $PWD/swigpy/_libcaer_wrap.so $PWD/pyaer
200 | cp $PWD/swigpy/libcaer_wrap.py $PWD/pyaer
201 | echo -e "${BLUE}[MESSAGE] Installation completed.${COLOR_END}"
202 | }
203 |
204 | # cleaning functions
205 | clean_swigpy()
206 | {
207 | echo -e "${BLUE}[MESSAGE] Cleaning SWIG files.${COLOR_END}"
208 | rm -rf $PWD/swigpy
209 | echo -e "${BLUE}[MESSAGE] SWIG files removed.${COLOR_END}"
210 | }
211 |
212 | clean_libcaer()
213 | {
214 | echo -e "${BLUE}[MESSAGE] Cleaning libcaer installation.${COLOR_END}"
215 | rm -rf $PWD/libcaer/build
216 | echo -e "${BLUE}[MESSAGE] libcaer files removed.${COLOR_END}"
217 | }
218 |
219 | clean_install()
220 | {
221 | echo -e "${BLUE}[MESSAGE] Cleaning Compiled interface.${COLOR_END}"
222 | rm $PWD/pyaer/_libcaer_wrap.so
223 | rm $PWD/pyaer/libcaer_wrap.py
224 |
225 | # restore bash profile
226 | if [ -f $HOME/.bashrc.pyaer.bak ]; then
227 | cp $HOME/.bashrc.pyaer.bak $HOME/.bashrc
228 | fi
229 | if [ -f $HOME/.zshrc.pyaer.bak ]; then
230 | cp $HOME/.zshrc.pyaer.bask $HOME/.zshrc
231 | fi
232 |
233 | echo -e "${BLUE}[MESSAGE] Installation removed.${COLOR_END}"
234 | }
235 |
236 | if [ "$fn" == "help" ]; then
237 | print_help
238 | exit 1
239 | fi
240 |
241 | config_installation
242 |
243 | # main work flow
244 | if [ $ENABLE_INSTALL = true ]; then
245 | case "$fn" in
246 | "make.swig")
247 | compile_swigpy
248 | ;;
249 |
250 | "clean.swig")
251 | clean_swigpy
252 | ;;
253 |
254 | "make.lib")
255 | compile_libcaer
256 | ;;
257 |
258 | "clean.lib")
259 | clean_libcaer
260 | ;;
261 |
262 | "make.install")
263 | make_install
264 | ;;
265 |
266 | "clean.install")
267 | clean_install
268 | ;;
269 |
270 | "make")
271 | # compile libcaer
272 | if [ $LIBCAER_INSTALLED == false ]; then
273 | compile_libcaer
274 | fi
275 |
276 | # compile swigpy
277 | compile_swigpy
278 | ;;
279 |
280 | "clean")
281 | # SWIG
282 | clean_swigpy
283 |
284 | # remove compiled SWIG
285 | clean_install
286 |
287 | # remove libcaer files
288 | clean_libcaer
289 | ;;
290 | esac
291 | else
292 | echo -e "${RED}[MESSAGE] Installation interrupted.${COLOR_END}"
293 | fi
294 |
--------------------------------------------------------------------------------
/pyaer/edvs.py:
--------------------------------------------------------------------------------
1 | """eDVS.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | import numpy as np
7 |
8 | from pyaer import libcaer
9 | from pyaer import utils
10 | from pyaer.device import SerialDevice
11 | from pyaer.filters import DVSNoise
12 |
13 |
14 | class eDVS(SerialDevice):
15 | """eDVS.
16 |
17 | # Arguments
18 | device_id: `int`
19 | a unique ID to identify the device from others.
20 | Will be used as the source for EventPackets being
21 | generate from its data.
22 | `default is 1`.
23 | serial_port_name: `str`
24 | name of the serial port device to open.
25 | `default is /dev/ttyUSB0`
26 | serial_baud_rate: `uint32_t`
27 | baud-rate for serial port communication.
28 | `default is 12M`
29 | """
30 |
31 | def __init__(
32 | self,
33 | device_id=1,
34 | serial_port_name="/dev/ttyUSB0",
35 | serial_baud_rate=libcaer.CAER_HOST_CONFIG_SERIAL_BAUD_RATE_12M,
36 | noise_filter=False,
37 | ):
38 | """eDVS."""
39 | super(eDVS, self).__init__()
40 | # open device
41 | self.open(device_id, serial_port_name, serial_baud_rate)
42 | # get camera information
43 | self.obtain_device_info(self.handle)
44 |
45 | # noise filter
46 | self.filter_noise = noise_filter
47 | if noise_filter is True:
48 | self.noise_filter = DVSNoise(self.dvs_size_X, self.dvs_size_Y)
49 | else:
50 | self.noise_filter = None
51 |
52 | self.configs_list = [
53 | ("cas", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_CAS),
54 | ("injGnd", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_INJGND),
55 | ("reqPd", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_REQPD),
56 | ("puX", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_PUX),
57 | ("diffOff", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_DIFFOFF),
58 | ("req", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_REQ),
59 | ("refr", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_REFR),
60 | ("puY", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_PUY),
61 | ("diffOn", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_DIFFON),
62 | ("diff", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_DIFF),
63 | ("foll", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_FOLL),
64 | ("Pr", libcaer.EDVS_CONFIG_BIAS, libcaer.EDVS_CONFIG_BIAS_PR),
65 | ]
66 |
67 | def set_noise_filter(self, noise_filter):
68 | """Set noise filter.
69 |
70 | # Arguments
71 | noise_filter: `filters.DVSNoise`
72 | A valid `DVSNoise` object. This filter implements
73 | software-level background activity filter.
74 | """
75 | if noise_filter is not None:
76 | self.noise_filter = noise_filter
77 |
78 | def enable_noise_filter(self):
79 | """Enalbe DVS noise filter.
80 |
81 | This function enables the DVS noise filter. Note that this function will
82 | initialize a `DVSNoise` filter if there is None.
83 | """
84 | if self.filter_noise is False:
85 | self.filter_noise = True
86 |
87 | if self.noise_filter is None:
88 | self.noise_filter = DVSNoise(self.dvs_size_X, self.dvs_size_Y)
89 |
90 | def disable_noise_filter(self):
91 | """Disable noise filter.
92 |
93 | This method disable the noise filter. Note that this function doesn't destroy
94 | the existed noise filter. It simply switches off the function.
95 | """
96 | if self.filter_noise is True:
97 | self.filter_noise = False
98 |
99 | def obtain_device_info(self, handle):
100 | """Obtain eDVS info.
101 |
102 | This function collects the following information from the device:
103 |
104 | - Deveice ID
105 | - Device string
106 | - If the device is a master camera
107 | - Camera width
108 | - Camera height
109 |
110 | # Arguments
111 | handle: `caerDeviceHandle`
112 | a valid device handle that can be used with the other
113 | `libcaer` functions, or `None` on error.
114 | """
115 | if handle is not None:
116 | info = libcaer.caerEDVSInfoGet(handle)
117 |
118 | # port all info data field out
119 | self.device_id = info.deviceID
120 | self.device_string = info.deviceString
121 | self.device_is_master = info.deviceIsMaster
122 | self.dvs_size_X = info.dvsSizeX
123 | self.dvs_size_Y = info.dvsSizeY
124 | self.serial_port_name = info.serialPortName
125 | self.serial_baud_rate = info.serialBaudRate
126 |
127 | def open(
128 | self,
129 | device_id=1,
130 | serial_port_name="/dev/ttyUSB0",
131 | serial_baud_rate=libcaer.CAER_HOST_CONFIG_SERIAL_BAUD_RATE_12M,
132 | ):
133 | """Open device.
134 |
135 | # Arguments
136 | device_id: `int`
137 | a unique ID to identify the device from others.
138 | Will be used as the source for EventPackets being
139 | generate from its data.
140 | `default is 1`.
141 | serial_port_name: `str`
142 | name of the serial port device to open.
143 | `default is /dev/ttyUSB0`
144 | serial_baud_rate: `uint32_t`
145 | baud-rate for serial port communication.
146 | `default is 12M`
147 | """
148 | super(eDVS, self).open(
149 | libcaer.CAER_DEVICE_EDVS, device_id, serial_port_name, serial_baud_rate
150 | )
151 |
152 | def set_bias_from_json(self, file_path, verbose=False):
153 | """Set bias from loading JSON configuration file.
154 |
155 | # Arguments
156 | file_path: `str`
157 | absolute path of the JSON bias file.
158 | verbose: `bool`
159 | optional debugging message.
160 | """
161 | bias_obj = utils.load_dvs_bias(file_path, verbose)
162 | self.set_bias(bias_obj)
163 |
164 | def set_bias(self, bias_obj):
165 | """Set bias from bias dictionary.
166 |
167 | # Arguments
168 | bias_obj: `dict`
169 | dictionary that contains eDVS biases.
170 |
171 | # Returns
172 | flag: `bool`
173 | True if set successful, False otherwise.
174 | """
175 | for bias_name, module_address, parameter_address in self.configs_list:
176 | self.set_config(module_address, parameter_address, bias_obj[bias_name])
177 |
178 | def get_bias(self):
179 | """Get bias settings.
180 |
181 | # Returns
182 | bias_obj: `dict`
183 | dictionary that contains eDVS current bias settings.
184 | """
185 | bias_obj = {}
186 |
187 | for bias_name, module_address, parameter_address in self.configs_list:
188 | bias_obj[bias_name] = self.get_config(module_address, parameter_address)
189 |
190 | return bias_obj
191 |
192 | def save_bias_to_json(self, file_path):
193 | """Save bias to JSON.
194 |
195 | # Arguments
196 | file_path: `str`
197 | the absolute path to the destiation.
198 |
199 | # Returns
200 | flag: `bool`
201 | returns True if success in writing, False otherwise.
202 | """
203 | bias_obj = self.get_bias()
204 | return utils.write_json(file_path, bias_obj)
205 |
206 | def start_data_stream(self):
207 | """Start streaming data.
208 |
209 | # Arguments
210 | send_default_config: `bool`
211 | send default config to the device before starting
212 | the data streaming.
213 | `default is True`
214 | """
215 | self.data_start()
216 | self.set_data_exchange_blocking()
217 |
218 | def get_polarity_event(self, packet_header, noise_filter=False):
219 | """Get a packet of polarity event.
220 |
221 | # Arguments
222 | packet_header: `caerEventPacketHeader`
223 | the header that represents a event packet
224 | noise_filter: `bool`
225 | the background activity filter is applied if True.
226 |
227 | # Returns
228 | events: `numpy.ndarray`
229 | a 2-D array that has the shape of (N, 4) where N
230 | is the number of events in the event packet.
231 | Each row in the array represents a single polarity event.
232 | The first number is the timestamp.
233 | The second number is the X position of the event.
234 | The third number is the Y position of the event.
235 | The fourth number represents the polarity of the event
236 | (positive or negative).
237 | If the `noise_filter` option is set to `True`,
238 | this array has an additional column at the end.
239 | The last column represents the validity of the corresponding
240 | event. Filtered events will be marked as 0.
241 | num_events: `int`
242 | number of the polarity events available in the packet.
243 | """
244 | num_events, polarity = self.get_event_packet(
245 | packet_header, libcaer.POLARITY_EVENT
246 | )
247 |
248 | if noise_filter is True:
249 | polarity = self.noise_filter.apply(polarity)
250 |
251 | events = libcaer.get_filtered_polarity_event(
252 | polarity, num_events * 5
253 | ).reshape(num_events, 5)
254 | else:
255 | events = libcaer.get_polarity_event(polarity, num_events * 4).reshape(
256 | num_events, 4
257 | )
258 |
259 | return events, num_events
260 |
261 | def get_event(self):
262 | """Get event.
263 |
264 | # Returns
265 | pol_events: `numpy.ndarray`
266 | a 2-D array that has the shape of (N, 4) where N
267 | is the number of events in the event packet.
268 | Each row in the array represents a single polarity event.
269 | The first number is the timestamp.
270 | The second number is the X position of the event.
271 | The third number is the Y position of the event.
272 | The fourth number represents the polarity of the event
273 | (positive or negative).
274 | If the `noise_filter` option is set to `True`,
275 | this array has an additional column at the end.
276 | The last column represents the validity of the corresponding
277 | event. Filtered events will be marked as 0.
278 | num_pol_events: `int`
279 | number of the polarity events available in the packet.
280 | special_events: `numpy.ndarray`
281 | a 2-D array that has the shape of (N, 2) where N
282 | is the number of events in the event packet.
283 | Each row in the array represents a single special event.
284 | The first value is the timestamp of the event.
285 | The second value is the special event data.
286 | num_special_events: `int`
287 | number of the special events in the packet.
288 | """
289 | packet_container, packet_number = self.get_packet_container()
290 | if packet_container is not None:
291 | num_pol_event = 0
292 | num_special_event = 0
293 | pol_events = None
294 | special_events = None
295 | for packet_id in range(packet_number):
296 | packet_header, packet_type = self.get_packet_header(
297 | packet_container, packet_id
298 | )
299 | if packet_type == libcaer.POLARITY_EVENT:
300 | events, num_events = self.get_polarity_event(packet_header)
301 | pol_events = (
302 | np.hstack((pol_events, events))
303 | if pol_events is not None
304 | else events
305 | )
306 | num_pol_event += num_events
307 | elif packet_type == libcaer.SPECIAL_EVENT:
308 | events, num_events = self.get_special_event(packet_header)
309 | special_events = (
310 | np.hstack((special_events, events))
311 | if special_events is not None
312 | else events
313 | )
314 | num_special_event += num_events
315 | libcaer.caerEventPacketContainerFree(packet_container)
316 |
317 | return (pol_events, num_pol_event, special_events, num_special_event)
318 | else:
319 | return None
320 |
--------------------------------------------------------------------------------
/pyaer/dvs128.py:
--------------------------------------------------------------------------------
1 | """DVS128.
2 |
3 | Author: Yuhuang Hu
4 | Email : duguyue100@gmail.com
5 | """
6 | import numpy as np
7 |
8 | from pyaer import libcaer
9 | from pyaer import utils
10 | from pyaer.device import USBDevice
11 | from pyaer.filters import DVSNoise
12 |
13 |
14 | class DVS128(USBDevice):
15 | """DVS128.
16 |
17 | # Arguments
18 | device_id: `int`
19 | a unique ID to identify the device from others.
20 | Will be used as the source for EventPackets being
21 | generate from its data.
22 | `default is 1`
23 | bus_number_restrict: `int`
24 | restrict the search for viable devices to only this USB
25 | bus number.
26 | `default is 0`
27 | dev_address_restrict: `int`
28 | restrict the search for viable devices to only this USB
29 | device address.
30 | `default is 0`
31 | serial_number: `str`
32 | restrict the search for viable devices to only devices which do
33 | possess the given Serial Number in their USB
34 | SerialNumber descriptor.
35 | `default is ""`
36 | noise_filter: `bool`
37 | if enable noise filter,
38 | `default is False`.
39 | """
40 |
41 | def __init__(
42 | self,
43 | device_id=1,
44 | bus_number_restrict=0,
45 | dev_address_restrict=0,
46 | serial_number="",
47 | noise_filter=False,
48 | ):
49 | """DVS128."""
50 | super(DVS128, self).__init__()
51 | # open device
52 | self.open(device_id, bus_number_restrict, dev_address_restrict, serial_number)
53 | # get camera information
54 | self.obtain_device_info(self.handle)
55 |
56 | # noise filter
57 | self.filter_noise = noise_filter
58 | if noise_filter is True:
59 | self.noise_filter = DVSNoise(self.dvs_size_X, self.dvs_size_Y)
60 | else:
61 | self.noise_filter = None
62 |
63 | # Bias configuration list
64 | self.configs_list = [
65 | ("cas", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_CAS),
66 | ("injGnd", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_INJGND),
67 | ("reqPd", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_REQPD),
68 | ("puX", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_PUX),
69 | ("diffOff", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_DIFFOFF),
70 | ("req", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_REQ),
71 | ("refr", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_REFR),
72 | ("puY", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_PUY),
73 | ("diffOn", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_DIFFON),
74 | ("diff", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_DIFF),
75 | ("foll", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_FOLL),
76 | ("Pr", libcaer.DVS128_CONFIG_BIAS, libcaer.DVS128_CONFIG_BIAS_PR),
77 | ]
78 |
79 | def set_noise_filter(self, noise_filter):
80 | """Set noise filter.
81 |
82 | # Arguments
83 | noise_filter: `filters.DVSNoise`
84 | A valid `DVSNoise` object. This filter implements
85 | software-level background activity filter.
86 | """
87 | if noise_filter is not None:
88 | self.noise_filter = noise_filter
89 |
90 | def enable_noise_filter(self):
91 | """Enalbe DVS noise filter.
92 |
93 | This function enables the DVS noise filter. Note that this function will
94 | initialize a `DVSNoise` filter if there is None.
95 | """
96 | if self.filter_noise is False:
97 | self.filter_noise = True
98 |
99 | if self.noise_filter is None:
100 | self.noise_filter = DVSNoise(self.dvs_size_X, self.dvs_size_Y)
101 |
102 | def disable_noise_filter(self):
103 | """Disable noise filter.
104 |
105 | This method disable the noise filter. Note that this function doesn't destroy
106 | the existed noise filter. It simply switches off the function.
107 | """
108 | if self.filter_noise is True:
109 | self.filter_noise = False
110 |
111 | def obtain_device_info(self, handle):
112 | """Obtain DVS128 info.
113 |
114 | This function collects the following information from the device:
115 |
116 | - Deveice ID
117 | - If the device is a master camera
118 | - Device string
119 | - Device USB bus number
120 | - Device USB device address
121 | - Camera width
122 | - Camera height
123 | - Logic version
124 |
125 | # Arguments
126 | handle: `caerDeviceHandle`
127 | a valid device handle that can be used with the other
128 | `libcaer` functions, or `None` on error.
129 | """
130 | if handle is not None:
131 | info = libcaer.caerDVS128InfoGet(handle)
132 |
133 | # port all info data field out
134 | self.device_id = info.deviceID
135 | self.device_serial_number = info.deviceSerialNumber
136 | self.device_usb_bus_number = info.deviceUSBBusNumber
137 | self.device_usb_device_address = info.deviceUSBDeviceAddress
138 | self.device_string = info.deviceString
139 | self.firmware_version = info.firmwareVersion
140 | self.device_is_master = info.deviceIsMaster
141 | self.dvs_size_X = info.dvsSizeX
142 | self.dvs_size_Y = info.dvsSizeY
143 |
144 | def open(
145 | self,
146 | device_id=1,
147 | bus_number_restrict=0,
148 | dev_address_restrict=0,
149 | serial_number="",
150 | ):
151 | """Open device.
152 |
153 | # Arguments
154 | device_id: `int`
155 | a unique ID to identify the device from others.
156 | Will be used as the source for EventPackets being
157 | generate from its data.
158 | `default is 1`.
159 | bus_number_restrict: `int`
160 | restrict the search for viable devices to only this USB
161 | bus number.
162 | `default is 0`.
163 | dev_address_restrict: `int`
164 | restrict the search for viable devices to only this USB
165 | device address.
166 | `default is 0`.
167 | serial_number: `str`
168 | restrict the search for viable devices to only devices which do
169 | possess the given Serial Number in their USB
170 | SerialNumber descriptor.
171 | `default is ""`
172 | """
173 | super(DVS128, self).open(
174 | libcaer.CAER_DEVICE_DVS128,
175 | device_id,
176 | bus_number_restrict,
177 | dev_address_restrict,
178 | serial_number,
179 | )
180 |
181 | def set_bias_from_json(self, file_path, verbose=False):
182 | """Set bias from loading JSON configuration file.
183 |
184 | # Arguments
185 | file_path: `str`
186 | absolute path of the JSON bias file.
187 | verbose: `bool`
188 | optional debugging message.
189 | """
190 | bias_obj = utils.load_dvs_bias(file_path, verbose)
191 | self.set_bias(bias_obj)
192 |
193 | def set_bias(self, bias_obj):
194 | """Set bias from bias dictionary.
195 |
196 | # Arguments
197 | bias_obj: `dict`
198 | dictionary that contains DVS128 biases.
199 |
200 | # Returns
201 | flag: `bool`
202 | True if set successful, False otherwise.
203 | """
204 | for bias_name, module_address, parameter_address in self.configs_list:
205 | self.set_config(module_address, parameter_address, bias_obj[bias_name])
206 |
207 | # setting for noise filter
208 | if self.filter_noise is True:
209 | self.noise_filter.set_bias(bias_obj["noise_filter_configs"])
210 |
211 | def get_bias(self):
212 | """Get bias settings.
213 |
214 | # Returns
215 | bias_obj: `dict`
216 | dictionary that contains DVS128 current bias settings.
217 | """
218 | bias_obj = {}
219 |
220 | for bias_name, module_address, parameter_address in self.configs_list:
221 | bias_obj[bias_name] = self.get_config(module_address, parameter_address)
222 |
223 | # get noise filter configs
224 | if self.noise_filter is not None:
225 | bias_obj["noise_filter_configs"] = self.noise_filter.get_bias()
226 |
227 | return bias_obj
228 |
229 | def save_bias_to_json(self, file_path):
230 | """Save bias to JSON.
231 |
232 | # Arguments
233 | file_path: `str`
234 | the absolute path to the destiation.
235 |
236 | # Returns
237 | flag: `bool`
238 | returns True if success in writing, False otherwise.
239 | """
240 | bias_obj = self.get_bias()
241 | return utils.write_json(file_path, bias_obj)
242 |
243 | def start_data_stream(
244 | self, send_default_config=True, max_packet_size=None, max_packet_interval=None
245 | ):
246 | """Start streaming data.
247 |
248 | # Arguments
249 | send_default_config: `bool`
250 | send default config to the device before starting
251 | the data streaming.
252 | `default is True`
253 | max_packet_size: `int`
254 | set the maximum number of events any of a packet container's
255 | packets may hold before it's made available to the user.
256 | Set to zero to disable.
257 | The default is `None` (use default setting: 0).
258 | max_packet_interval: `int`
259 | set the time interval between subsequent packet containers.
260 | Must be at least 1 microsecond.
261 | The value is in microseconds, and is checked across all
262 | types of events contained in the EventPacketContainer.
263 | The default is `None` (use default setting: 10ms)
264 | """
265 | if send_default_config is True:
266 | self.send_default_config()
267 |
268 | if max_packet_size is not None:
269 | self.set_max_container_packet_size(max_packet_size)
270 | if max_packet_interval is not None:
271 | self.set_max_container_interval(max_packet_interval)
272 |
273 | self.data_start()
274 | self.set_data_exchange_blocking()
275 |
276 | def get_polarity_event(self, packet_header, noise_filter=False):
277 | """Get a packet of polarity event.
278 |
279 | # Arguments
280 | packet_header: `caerEventPacketHeader`
281 | the header that represents a event packet
282 | noise_filter: `bool`
283 | the background activity filter is applied if True.
284 |
285 | # Returns
286 | events: `numpy.ndarray`
287 | a 2-D array that has the shape of (N, 4) where N
288 | is the number of events in the event packet.
289 | Each row in the array represents a single polarity event.
290 | The first number is the timestamp.
291 | The second number is the X position of the event.
292 | The third number is the Y position of the event.
293 | The fourth number represents the polarity of the event
294 | (positive or negative).
295 | If the `noise_filter` option is set to `True`,
296 | this array has an additional column at the end.
297 | The last column represents the validity of the corresponding
298 | event. Filtered events will be marked as 0.
299 | num_events: `int`
300 | number of the polarity events available in the packet.
301 | """
302 | num_events, polarity = self.get_event_packet(
303 | packet_header, libcaer.POLARITY_EVENT
304 | )
305 |
306 | if noise_filter is True:
307 | polarity = self.noise_filter.apply(polarity)
308 |
309 | events = libcaer.get_filtered_polarity_event(
310 | polarity, num_events * 5
311 | ).reshape(num_events, 5)
312 | else:
313 | events = libcaer.get_polarity_event(polarity, num_events * 4).reshape(
314 | num_events, 4
315 | )
316 |
317 | return events, num_events
318 |
319 | def get_event(self, mode="events"):
320 | """Get event.
321 |
322 | # Returns
323 | pol_events: `numpy.ndarray`
324 | a 2-D array that has the shape of (N, 4) where N
325 | is the number of events in the event packet.
326 | Each row in the array represents a single polarity event.
327 | The first number is the timestamp.
328 | The second number is the X position of the event.
329 | The third number is the Y position of the event.
330 | The fourth number represents the polarity of the event
331 | (positive or negative).
332 | If the `noise_filter` option is set to `True`,
333 | this array has an additional column at the end.
334 | The last column represents the validity of the corresponding
335 | event. Filtered events will be marked as 0.
336 | num_pol_events: `int`
337 | number of the polarity events available in the packet.
338 | special_events: `numpy.ndarray`
339 | a 2-D array that has the shape of (N, 2) where N
340 | is the number of events in the event packet.
341 | Each row in the array represents a single special event.
342 | The first value is the timestamp of the event.
343 | The second value is the special event data.
344 | num_special_events: `int`
345 | number of the special events in the packet.
346 | """
347 | packet_container, packet_number = self.get_packet_container()
348 | if packet_container is not None:
349 | num_pol_event = 0
350 | num_special_event = 0
351 | pol_events = None
352 | special_events = None
353 | for packet_id in range(packet_number):
354 | packet_header, packet_type = self.get_packet_header(
355 | packet_container, packet_id
356 | )
357 | if packet_type == libcaer.POLARITY_EVENT:
358 | if mode == "events":
359 | events, num_events = self.get_polarity_event(
360 | packet_header, self.filter_noise
361 | )
362 | pol_events = (
363 | np.hstack((pol_events, events))
364 | if pol_events is not None
365 | else events
366 | )
367 | elif mode == "events_hist":
368 | hist, num_events = self.get_polarity_hist(
369 | packet_header, device_type="DVS128"
370 | )
371 | pol_events = hist if pol_events is None else pol_events + hist
372 |
373 | num_pol_event += num_events
374 | elif packet_type == libcaer.SPECIAL_EVENT:
375 | events, num_events = self.get_special_event(packet_header)
376 | special_events = (
377 | np.hstack((special_events, events))
378 | if special_events is not None
379 | else events
380 | )
381 | num_special_event += num_events
382 | libcaer.caerEventPacketContainerFree(packet_container)
383 |
384 | return (pol_events, num_pol_event, special_events, num_special_event)
385 | else:
386 | return None
387 |
--------------------------------------------------------------------------------