diff --git a/.github/workflows/upload_datasets.yaml b/.github/workflows/upload_datasets.yaml index 3b9c734bf..d7a4e2c14 100644 --- a/.github/workflows/upload_datasets.yaml +++ b/.github/workflows/upload_datasets.yaml @@ -8,7 +8,8 @@ on: env: # we are not using an official share URL from KDrive. We found it by analyzing the http requests. # we hope it will continue to work in the future. - dataset_download_address: "https://prophesee-bamboo.s3.eu-west-1.amazonaws.com/datasets/openeb/openeb-dataset_v5.0.0.zip" + dataset_download_address: "https://prophesee-bamboo.s3.eu-west-1.amazonaws.com/datasets/openeb/openeb-dataset_v5.1.0.zip" + jobs: get_artifacts: name: Get Datasets diff --git a/CMakeLists.txt b/CMakeLists.txt index d3170b121..cc7849afa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,11 +15,11 @@ if(NOT CMAKE_BUILD_TYPE) "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif(NOT CMAKE_BUILD_TYPE) -option(BUILD_TESTING "Build OpenEB's test suite" OFF) +option(BUILD_TESTING "Build test suites" OFF) cmake_minimum_required(VERSION 3.5) -project(metavision VERSION 5.0.0) +project(metavision VERSION 5.1.0) set(PROJECT_VERSION_SUFFIX "") if(PROJECT_VERSION_SUFFIX STREQUAL "") @@ -89,7 +89,7 @@ if (ANDROID) # Setup 3rd party prebuilt libraries dir set(ANDROID_PREBUILT_3RDPARTY_EXTRACT_DIR ${GENERATE_FILES_DIRECTORY}/android/3rdparty) if (NOT EXISTS ${ANDROID_PREBUILT_3RDPARTY_EXTRACT_DIR}) - lfs_download(${PREBUILT_BASE_DIR}/${PREBUILT_FILENAME} COMPILATION) + lfs_download(COMPILATION IMMEDIATE ${PREBUILT_BASE_DIR}/${PREBUILT_FILENAME}) message(STATUS "Unpacking ${PREBUILT_BASE_DIR}/${PREBUILT_FILENAME} in ${ANDROID_PREBUILT_3RDPARTY_EXTRACT_DIR}") file(MAKE_DIRECTORY ${ANDROID_PREBUILT_3RDPARTY_EXTRACT_DIR}) execute_process( @@ -298,6 +298,9 @@ if (BUILD_TESTING) lfs_download(datasets/openeb/aer_4bits.raw VALIDATION) lfs_download(datasets/openeb/0101_cm_mtr12_output.raw VALIDATION) lfs_download(datasets/openeb/0101_cm_mtru_output.raw VALIDATION) + lfs_download(datasets/openeb/lifo_evt21.raw VALIDATION) + lfs_download(datasets/openeb/lifo_evt2.raw VALIDATION) + lfs_download(datasets/openeb/lifo_evt3.raw VALIDATION) lfs_download(datasets/openeb/synced/recording_master.raw VALIDATION) lfs_download(datasets/openeb/synced/recording_slave_0.raw VALIDATION) lfs_download(datasets/openeb/synced/recording_slave_1.raw VALIDATION) @@ -369,32 +372,35 @@ endif(CODE_COVERAGE) ################################################### Detect which SDK modules are available -set(METAVISION_SDK_MODULES_OPEN base core stream CACHE STRING "SDK Open modules") +set(METAVISION_SDK_MODULES_OPEN base core stream) if (COMPILE_PYTHON3_BINDINGS) list(APPEND METAVISION_SDK_MODULES_OPEN core_ml) endif (COMPILE_PYTHON3_BINDINGS) -set(METAVISION_SDK_MODULES_ADVANCED analytics cv ml CACHE STRING "SDK Advanced modules") - +set(METAVISION_SDK_MODULES_ADVANCED analytics cv ml) if (NOT ANDROID) list(APPEND METAVISION_SDK_MODULES_OPEN ui) - if(NOT DISABLE_METAVISION_SDK_MODULE_CALIBRATION_AND_CV3D) list(APPEND METAVISION_SDK_MODULES_ADVANCED calibration cv3d) endif() endif (NOT ANDROID) +if(NOT EXISTS METAVISION_SELECTED_MODULES) + set(METAVISION_SELECTED_MODULES "${METAVISION_SDK_MODULES_OPEN};${METAVISION_SDK_MODULES_ADVANCED}" CACHE STRING "Metavision SDK modules selected for compilation") +endif() + set(METAVISION_SDK_MODULES_AVAILABLE) foreach(metavision_modules_set OPEN ADVANCED) set(METAVISION_SDK_${metavision_modules_set}_MODULES_AVAILABLE) message(STATUS "Building METAVISION_SDK_MODULES_${metavision_modules_set} modules : ${METAVISION_SDK_MODULES_${metavision_modules_set}}") foreach(module_name IN LISTS METAVISION_SDK_MODULES_${metavision_modules_set}) - if ((NOT METAVISION_SELECTED_MODULES OR ${module_name} IN_LIST METAVISION_SELECTED_MODULES) - AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/sdk/modules/${module_name}/CMakeLists.txt") + if (${module_name} IN_LIST METAVISION_SELECTED_MODULES AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/sdk/modules/${module_name}/CMakeLists.txt") list(APPEND METAVISION_SDK_${metavision_modules_set}_MODULES_AVAILABLE "${module_name}") endif() endforeach() list(APPEND METAVISION_SDK_MODULES_AVAILABLE ${METAVISION_SDK_${metavision_modules_set}_MODULES_AVAILABLE}) endforeach() +message(STATUS "METAVISION_SELECTED_MODULES=${METAVISION_SELECTED_MODULES}") +message(STATUS "METAVISION_SDK_MODULES_AVAILABLE=${METAVISION_SDK_MODULES_AVAILABLE}") ################################################### COMPILATION diff --git a/README.md b/README.md index d6e4d7327..830e77890 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,6 @@ Compilation and execution were tested on platforms that meet the following requi * Linux: Ubuntu 22.04 or 24.04 64-bit * Architecture: amd64 (a.k.a. x64) * Graphic card with support of OpenGL 3.0 minimum - * CPU with [support of AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#CPUs_with_AVX2) Compilation on other platforms (alternate Linux distributions, different versions of Ubuntu, ARM processor architecture etc.) was not tested. For those platforms some adjustments to this guide or to the code itself may be required. @@ -66,7 +65,7 @@ and in your environment variables (`PATH`, `PYTHONPATH` and `LD_LIBRARY_PATH`) t To retrieve OpenEB source code, you can just clone the [GitHub repository](https://github.com/prophesee-ai/openeb): ```bash -git clone https://github.com/prophesee-ai/openeb.git --branch 5.0.0 +git clone https://github.com/prophesee-ai/openeb.git --branch 5.1.0 ``` In the following sections, absolute path to this directory is called ``OPENEB_SRC_DIR`` @@ -111,7 +110,7 @@ Next, create a virtual environment and install the necessary dependencies: ```bash python3 -m venv /tmp/prophesee/py3venv --system-site-packages /tmp/prophesee/py3venv/bin/python -m pip install pip --upgrade -/tmp/prophesee/py3venv/bin/python -m pip install -r OPENEB_SRC_DIR/utils/python/python_requirements/requirements_openeb.txt +/tmp/prophesee/py3venv/bin/python -m pip install -r OPENEB_SRC_DIR/utils/python/requirements_openeb.txt ``` Note that when creating the virtual environment, it is necessary to use the `--system-site-packages` option to ensure that @@ -253,7 +252,7 @@ Remove the folders where you installed Metavision artifacts (check both the `bui To retrieve OpenEB source code, you can just clone the [GitHub repository](https://github.com/prophesee-ai/openeb): ```bash -git clone https://github.com/prophesee-ai/openeb.git --branch 5.0.0 +git clone https://github.com/prophesee-ai/openeb.git --branch 5.1.0 ``` In the following sections, absolute path to this directory is called ``OPENEB_SRC_DIR`` @@ -279,9 +278,10 @@ To compile OpenEB, you will need to install some extra tools: * install [CMake 3.26](https://cmake.org/files/v3.26/cmake-3.26.6-windows-x86_64.msi) * install Microsoft C++ compiler (64-bit). You can choose one of the following solutions: * For building only, you can install MS Build Tools (free, part of Windows 10 SDK package) - * Download and run ["Build tools for Visual Studio 2022" installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/) - * Select "C++ build tools", make sure Windows 10 SDK is checked, and add English Language Pack - * For development, you can also download and run [Visual Studio Installer](https://visualstudio.microsoft.com/downloads/) + * Install Microsoft Visual C++ compiler (MSVC, 64-bit version) included in + `Visual Studio 2022 - Fall 2023 LTSC (version 17.8) `_. + * Select "C++ build tools", check Windows 10 SDK is checked, and add English Language Pack + * For development, you can also download and run [Visual Studio Installer](https://visualstudio.microsoft.com/downloads/) * install [vcpkg](https://github.com/microsoft/vcpkg) that will be used for installing dependencies: * download and extract [vcpkg version 2024.04.26](https://github.com/microsoft/vcpkg/archive/refs/tags/2024.04.26.zip) in a folder that we will refer as `VCPKG_SRC_DIR` * `cd ` @@ -333,7 +333,7 @@ Create a virtual environment and install the necessary dependencies: ```bash python -m venv C:\tmp\prophesee\py3venv --system-site-packages C:\tmp\prophesee\py3venv\Scripts\python -m pip install pip --upgrade -C:\tmp\prophesee\py3venv\Scripts\python -m pip install -r OPENEB_SRC_DIR\utils\python\python_requirements\requirements_openeb.txt +C:\tmp\prophesee\py3venv\Scripts\python -m pip install -r OPENEB_SRC_DIR\utils\python\requirements_openeb.txt ``` When creating the virtual environment, it is necessary to use the `--system-site-packages` option to ensure that @@ -436,6 +436,13 @@ or you can deploy the OpenEB files (applications, samples, libraries etc.) in a * To deploy OpenEB, you need to build the `INSTALL` project. By default, files will be deployed in `C:\Program Files\Prophesee` + * You also need to manually edit some environment variables: + + * append `\bin` to `PATH` (`C:\Program Files\Prophesee\bin` if you used default configuration) + * append `\lib\metavision\hal\plugins` to `MV_HAL_PLUGIN_PATH` (`C:\Program Files\Prophesee\lib\metavision\hal\plugins` if you used default configuration) + * append `\lib\hdf5\plugin` to `HDF5_PLUGIN_PATH` (`C:\Program Files\Prophesee\lib\hdf5\plugin` if you used default configuration) + * append `` to `PYTHONPATH` (not needed if you used default configuration) + #### Camera Plugins diff --git a/cmake/custom_functions/add_android_app.cmake b/cmake/custom_functions/add_android_app.cmake index 9ee1f3e8c..e86bd84cf 100644 --- a/cmake/custom_functions/add_android_app.cmake +++ b/cmake/custom_functions/add_android_app.cmake @@ -41,7 +41,7 @@ function(add_android_app app) # Unpack gradle cache for faster and consistent builds set(ANDROID_GRADLE_CACHE_ARCHIVE utils/android/gradle-cache.tar.gz) if (NOT EXISTS ${ANDROID_GRADLE_CACHE_DIR}) - lfs_download(${ANDROID_GRADLE_CACHE_ARCHIVE} COMPILATION) + lfs_download(COMPILATION IMMEDIATE ${ANDROID_GRADLE_CACHE_ARCHIVE}) message(STATUS "Unpacking ${ANDROID_GRADLE_CACHE_ARCHIVE} in ${ANDROID_GRADLE_CACHE_EXTRACT_DIR}") file(MAKE_DIRECTORY ${ANDROID_GRADLE_CACHE_EXTRACT_DIR}) execute_process( diff --git a/cmake/custom_functions/add_library_version_header.cmake b/cmake/custom_functions/add_library_version_header.cmake index 000f6452d..23e3b0bbc 100644 --- a/cmake/custom_functions/add_library_version_header.cmake +++ b/cmake/custom_functions/add_library_version_header.cmake @@ -8,8 +8,8 @@ # See the License for the specific language governing permissions and limitations under the License. set(GIT_BRANCH "main") -set(GIT_COMMIT_ID "6abf87d7194ca70c33d4a599944765397fac3335") -set(GIT_COMMIT_DATE "2024-10-02 17:27:00 +0200") +set(GIT_COMMIT_ID "5010c12796e5390f500f9f75a98393acc87baf59") +set(GIT_COMMIT_DATE "2025-01-16 14:51:42 +0100") find_program(GIT_SCM git DOC "Git version control" HINTS "C:\\Program Files\\Git\\bin\\") diff --git a/cmake/custom_functions/lfs_download.cmake b/cmake/custom_functions/lfs_download.cmake index 004b4b0f5..7e5af945a 100644 --- a/cmake/custom_functions/lfs_download.cmake +++ b/cmake/custom_functions/lfs_download.cmake @@ -10,54 +10,111 @@ set(GIT_LFS_NOT_AVAILABLE True) include(CMakeParseArguments) -option(LFS_DOWNLOAD_COMPILATION_RESOURCES "Only download LFS resources required for compilation step" ON) -option(LFS_DOWNLOAD_VALIDATION_RESOURCES "Only download LFS resources required for compilation step" ON) +option(LFS_DOWNLOAD_COMPILATION_RESOURCES "Download LFS resources required for compilation step" ON) +option(LFS_DOWNLOAD_VALIDATION_RESOURCES "Download LFS resources required for validation step" ON) + +function(_call_lfs_download file_or_dir_to_download_comma_separated) + set(retries 3) + set(success FALSE) + while (NOT success AND retries GREATER 0) + execute_process( + COMMAND git lfs pull --include "${file_or_dir_to_download_comma_separated}" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE OUTPUT + ERROR_VARIABLE ERROR + RESULT_VARIABLE RESULT + ) + if (RESULT AND NOT RESULT EQUAL 0) + message(WARNING "lfs_download error : ${ERROR} output : ${OUTPUT}") + math(EXPR retries "${retries} - 1") + if (retries GREATER 0) + message(STATUS "Retrying download of LFS files") + endif () + else() + set(success TRUE) + endif() + endwhile() + if (NOT success) + message(FATAL_ERROR "lfs_download failed after 3 retries") + endif() +endfunction () + +function(_lfs_download_at_end_of_configure) + if (DEFINED LFS_ITEMS_TO_DOWNLOAD) + string(REPLACE ";" ", " files_or_dirs_to_download_comma_separated "${LFS_ITEMS_TO_DOWNLOAD}") + message(STATUS "Downloading ${files_or_dirs_to_download_comma_separated} with LFS") + _call_lfs_download("${files_or_dirs_to_download_comma_separated}") + endif() +endfunction() # Function to download files or directories with git lfs # # Usage: -# lfs_download(file_path|dir_path [file_path|dir_path]) +# lfs_download([COMPILATION] [VALIDATION] [IMMEDIATE] file_path|dir_path [file_path|dir_path]) +# COMPILATION (resp. VALIDATION) can be passed to indicate that the corresponding resources should +# only be downloaded if the variable LFS_DOWNLOAD_COMPILATION_RESOURCES (resp. LFS_DOWNLOAD_VALIDATION_RESOURCES) +# is set (by default, both are set to TRUE, but if compilation and validation steps are split, one of the variables +# should be unset to optimize the download time) +# +# IMMEDIATE indicate that the download must be done while the function is called (the default is to +# accumulate the list of files to download, and perform the actual fetch/checkout at the end of the +# configure time of the current project) function(lfs_download) - cmake_parse_arguments(LFS_DOWNLOAD_ARGS "VALIDATION;COMPILATION" "" "" ${ARGN}) + cmake_parse_arguments(LFS_DOWNLOAD_ARGS "VALIDATION;COMPILATION;IMMEDIATE" "" "" ${ARGN}) + + if (GIT_LFS_NOT_AVAILABLE) + return() + endif (GIT_LFS_NOT_AVAILABLE) + + if (NOT LFS_DOWNLOAD_ARGS_IMMEDIATE) + # Check if we already scheduled a deferred call for LFS to download items + set(_call_already_scheduled FALSE) + cmake_language(DEFER DIRECTORY ${PROJECT_SOURCE_DIR} GET_CALL_IDS _deferred_call_ids) + foreach(id ${_deferred_call_ids}) + cmake_language(DEFER DIRECTORY ${PROJECT_SOURCE_DIR} GET_CALL ${id} _deferred_call) + if("${_deferred_call}" MATCHES "_lfs_download_at_end_of_configure") + set(_call_already_scheduled TRUE) + break() + endif() + endforeach() + + # Schedule the deferred call if it hasn't been scheduled yet + if(NOT _call_already_scheduled) + set(LFS_ITEMS_TO_DOWNLOAD "" CACHE INTERNAL "List of items to download with git LFS") + cmake_language(DEFER DIRECTORY ${PROJECT_SOURCE_DIR} CALL _lfs_download_at_end_of_configure()) + endif() + endif() + if (NOT LFS_DOWNLOAD_ARGS_VALIDATION AND NOT LFS_DOWNLOAD_ARGS_COMPILATION) message(FATAL_ERROR "lfs_download must be called with at least one keyword in [COMPILATION,VALIDATION]") endif () if (NOT LFS_DOWNLOAD_ARGS_UNPARSED_ARGUMENTS) message(FATAL_ERROR "lfs_download must be called with a list of files/dirs") endif () - string(REPLACE ";" ", " file_or_dir_to_download_comma_separated "${LFS_DOWNLOAD_ARGS_UNPARSED_ARGUMENTS}") - if (NOT GIT_LFS_NOT_AVAILABLE) - foreach(file_or_dir_to_download ${LFS_DOWNLOAD_ARGS_UNPARSED_ARGUMENTS}) - if(NOT EXISTS "${PROJECT_SOURCE_DIR}/${file_or_dir_to_download}") - message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/${file_or_dir_to_download} does not exist") - endif() - endforeach(file_or_dir_to_download) + foreach(file_or_dir_to_download ${LFS_DOWNLOAD_ARGS_UNPARSED_ARGUMENTS}) + if(NOT EXISTS "${PROJECT_SOURCE_DIR}/${file_or_dir_to_download}") + message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/${file_or_dir_to_download} does not exist") + endif() + endforeach(file_or_dir_to_download) + if (LFS_DOWNLOAD_ARGS_IMMEDIATE) + string(REPLACE ";" ", " files_or_dirs_to_download_comma_separated "${LFS_DOWNLOAD_ARGS_UNPARSED_ARGUMENTS}") + message(STATUS "Downloading ${files_or_dirs_to_download_comma_separated} with LFS") + _call_lfs_download("${files_or_dirs_to_download_comma_separated}") + else() + if (DEFINED LFS_ITEMS_TO_DOWNLOAD) + set (_lfs_items_to_download "${LFS_ITEMS_TO_DOWNLOAD}") + else () + set(_lfs_items_to_download "") + endif () if ((LFS_DOWNLOAD_ARGS_COMPILATION AND LFS_DOWNLOAD_COMPILATION_RESOURCES) OR (LFS_DOWNLOAD_ARGS_VALIDATION AND LFS_DOWNLOAD_VALIDATION_RESOURCES)) - message(STATUS "Downloading ${file_or_dir_to_download_comma_separated} with lfs") - set(retries 3) - set(success FALSE) - while (NOT success AND retries GREATER 0) - execute_process( - COMMAND git lfs pull --include "${file_or_dir_to_download_comma_separated}" - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE OUTPUT - ERROR_VARIABLE ERROR - RESULT_VARIABLE RESULT - ) - if (RESULT AND NOT RESULT EQUAL 0) - message(WARNING "lfs_download error : ${ERROR} output : ${OUTPUT}") - math(EXPR retries "${retries} - 1") - if (retries GREATER 0) - message(STATUS "Retrying download of ${file_or_dir_to_download_comma_separated}") - endif () - else() - set(success TRUE) - endif() - endwhile() - if (NOT success) - message(FATAL_ERROR "lfs_download failed after 3 retries") - endif() + foreach(file_or_dir_to_download ${LFS_DOWNLOAD_ARGS_UNPARSED_ARGUMENTS}) + if (NOT "${file_or_dir_to_download}" IN_LIST _lfs_items_to_download) + list(APPEND _lfs_items_to_download ${file_or_dir_to_download}) + message(STATUS "Adding ${file_or_dir_to_download} to the list of LFS files to download") + endif () + endforeach(file_or_dir_to_download) + set(LFS_ITEMS_TO_DOWNLOAD "${_lfs_items_to_download}" CACHE INTERNAL "List of items to download with git LFS") endif () - endif (NOT GIT_LFS_NOT_AVAILABLE) + endif() endfunction() diff --git a/cmake/custom_targets/README_metavision_open.md b/cmake/custom_targets/README_metavision_open.md index d6e4d7327..830e77890 100644 --- a/cmake/custom_targets/README_metavision_open.md +++ b/cmake/custom_targets/README_metavision_open.md @@ -37,7 +37,6 @@ Compilation and execution were tested on platforms that meet the following requi * Linux: Ubuntu 22.04 or 24.04 64-bit * Architecture: amd64 (a.k.a. x64) * Graphic card with support of OpenGL 3.0 minimum - * CPU with [support of AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#CPUs_with_AVX2) Compilation on other platforms (alternate Linux distributions, different versions of Ubuntu, ARM processor architecture etc.) was not tested. For those platforms some adjustments to this guide or to the code itself may be required. @@ -66,7 +65,7 @@ and in your environment variables (`PATH`, `PYTHONPATH` and `LD_LIBRARY_PATH`) t To retrieve OpenEB source code, you can just clone the [GitHub repository](https://github.com/prophesee-ai/openeb): ```bash -git clone https://github.com/prophesee-ai/openeb.git --branch 5.0.0 +git clone https://github.com/prophesee-ai/openeb.git --branch 5.1.0 ``` In the following sections, absolute path to this directory is called ``OPENEB_SRC_DIR`` @@ -111,7 +110,7 @@ Next, create a virtual environment and install the necessary dependencies: ```bash python3 -m venv /tmp/prophesee/py3venv --system-site-packages /tmp/prophesee/py3venv/bin/python -m pip install pip --upgrade -/tmp/prophesee/py3venv/bin/python -m pip install -r OPENEB_SRC_DIR/utils/python/python_requirements/requirements_openeb.txt +/tmp/prophesee/py3venv/bin/python -m pip install -r OPENEB_SRC_DIR/utils/python/requirements_openeb.txt ``` Note that when creating the virtual environment, it is necessary to use the `--system-site-packages` option to ensure that @@ -253,7 +252,7 @@ Remove the folders where you installed Metavision artifacts (check both the `bui To retrieve OpenEB source code, you can just clone the [GitHub repository](https://github.com/prophesee-ai/openeb): ```bash -git clone https://github.com/prophesee-ai/openeb.git --branch 5.0.0 +git clone https://github.com/prophesee-ai/openeb.git --branch 5.1.0 ``` In the following sections, absolute path to this directory is called ``OPENEB_SRC_DIR`` @@ -279,9 +278,10 @@ To compile OpenEB, you will need to install some extra tools: * install [CMake 3.26](https://cmake.org/files/v3.26/cmake-3.26.6-windows-x86_64.msi) * install Microsoft C++ compiler (64-bit). You can choose one of the following solutions: * For building only, you can install MS Build Tools (free, part of Windows 10 SDK package) - * Download and run ["Build tools for Visual Studio 2022" installer](https://visualstudio.microsoft.com/visual-cpp-build-tools/) - * Select "C++ build tools", make sure Windows 10 SDK is checked, and add English Language Pack - * For development, you can also download and run [Visual Studio Installer](https://visualstudio.microsoft.com/downloads/) + * Install Microsoft Visual C++ compiler (MSVC, 64-bit version) included in + `Visual Studio 2022 - Fall 2023 LTSC (version 17.8) `_. + * Select "C++ build tools", check Windows 10 SDK is checked, and add English Language Pack + * For development, you can also download and run [Visual Studio Installer](https://visualstudio.microsoft.com/downloads/) * install [vcpkg](https://github.com/microsoft/vcpkg) that will be used for installing dependencies: * download and extract [vcpkg version 2024.04.26](https://github.com/microsoft/vcpkg/archive/refs/tags/2024.04.26.zip) in a folder that we will refer as `VCPKG_SRC_DIR` * `cd ` @@ -333,7 +333,7 @@ Create a virtual environment and install the necessary dependencies: ```bash python -m venv C:\tmp\prophesee\py3venv --system-site-packages C:\tmp\prophesee\py3venv\Scripts\python -m pip install pip --upgrade -C:\tmp\prophesee\py3venv\Scripts\python -m pip install -r OPENEB_SRC_DIR\utils\python\python_requirements\requirements_openeb.txt +C:\tmp\prophesee\py3venv\Scripts\python -m pip install -r OPENEB_SRC_DIR\utils\python\requirements_openeb.txt ``` When creating the virtual environment, it is necessary to use the `--system-site-packages` option to ensure that @@ -436,6 +436,13 @@ or you can deploy the OpenEB files (applications, samples, libraries etc.) in a * To deploy OpenEB, you need to build the `INSTALL` project. By default, files will be deployed in `C:\Program Files\Prophesee` + * You also need to manually edit some environment variables: + + * append `\bin` to `PATH` (`C:\Program Files\Prophesee\bin` if you used default configuration) + * append `\lib\metavision\hal\plugins` to `MV_HAL_PLUGIN_PATH` (`C:\Program Files\Prophesee\lib\metavision\hal\plugins` if you used default configuration) + * append `\lib\hdf5\plugin` to `HDF5_PLUGIN_PATH` (`C:\Program Files\Prophesee\lib\hdf5\plugin` if you used default configuration) + * append `` to `PYTHONPATH` (not needed if you used default configuration) + #### Camera Plugins diff --git a/hal/cpp/include/metavision/hal/decoders/evt2/evt2_decoder.h b/hal/cpp/include/metavision/hal/decoders/evt2/evt2_decoder.h index 7fd6fdbf3..4c933efcb 100644 --- a/hal/cpp/include/metavision/hal/decoders/evt2/evt2_decoder.h +++ b/hal/cpp/include/metavision/hal/decoders/evt2/evt2_decoder.h @@ -12,9 +12,14 @@ #ifndef METAVISION_HAL_EVT2_DECODER_H #define METAVISION_HAL_EVT2_DECODER_H +#include +#include + #include "metavision/hal/facilities/i_events_stream_decoder.h" #include "metavision/sdk/base/events/event_cd.h" +#include "metavision/sdk/base/events/event_erc_counter.h" #include "metavision/sdk/base/events/event_ext_trigger.h" +#include "metavision/sdk/base/events/event_monitoring.h" #include "metavision/hal/facilities/i_event_decoder.h" #include "metavision/hal/decoders/base/event_base.h" #include "metavision/hal/decoders/evt2/evt2_event_types.h" @@ -36,8 +41,21 @@ class EVT2Decoder : public I_EventsStreamDecoder { bool time_shifting_enabled, const std::shared_ptr> &event_cd_decoder = std::shared_ptr>(), const std::shared_ptr> &event_ext_trigger_decoder = - std::shared_ptr>()) : - I_EventsStreamDecoder(time_shifting_enabled, event_cd_decoder, event_ext_trigger_decoder) {} + std::shared_ptr>(), + const std::shared_ptr> &event_erc_counter_decoder = + std::shared_ptr>(), + const std::shared_ptr> &event_monitoring_decoder = + std::shared_ptr>(), + const std::set &monitoring_id_blacklist = std::set()) : + I_EventsStreamDecoder(time_shifting_enabled, event_cd_decoder, event_ext_trigger_decoder, + event_erc_counter_decoder), + event_monitoring_decoder_(event_monitoring_decoder), + monitoring_id_blacklist_(monitoring_id_blacklist) { + if (event_monitoring_decoder_) { + monitoring_event_forwarder_.reset( + new DecodedEventForwarder(event_monitoring_decoder_.get())); + } + } virtual bool get_timestamp_shift(timestamp &ts_shift) const override { ts_shift = shift_th_; @@ -96,6 +114,18 @@ class EVT2Decoder : public I_EventsStreamDecoder { void decode_events_buffer(const RawEvent *&cur_raw_ev, const RawEvent *const raw_ev_end) { auto &cd_forwarder = cd_event_forwarder(); auto &trigger_forwarder = trigger_event_forwarder(); + + // Check if last buffer ended with a possibly incomplete monitoring event + if (pending_other_.raw != 0x0 && cur_raw_ev != raw_ev_end) { + const EVT2Continued *ev_cont = nullptr; + if (cur_raw_ev->type == static_cast(EVT2EventTypes::CONTINUED)) { + ev_cont = reinterpret_cast(cur_raw_ev); + ++cur_raw_ev; + } + decode_monitoring_event(pending_other_.monitoring, ev_cont); + pending_other_.raw = 0x0; + } + for (; cur_raw_ev != raw_ev_end; ++cur_raw_ev) { const EventBase::RawEvent *ev = reinterpret_cast(cur_raw_ev); const unsigned int type = ev->type; @@ -130,10 +160,42 @@ class EVT2Decoder : public I_EventsStreamDecoder { last_timestamp_set_ = true; trigger_forwarder.forward(static_cast(ev_ext_raw->value), last_timestamp_, static_cast(ev_ext_raw->id)); + } else if (type == static_cast(EventTypesEnum::OTHER)) { + const EVT2EventMonitor *ev_monitor = reinterpret_cast(ev); + if (monitoring_id_blacklist_.count(ev_monitor->subtype) == 0) { + last_timestamp_ = base_time_ + ev_monitor->timestamp; + last_timestamp_set_ = true; + + if (ev + 1 != raw_ev_end) { + const EVT2Continued *ev_cont = nullptr; + if ((ev + 1)->type == static_cast(EVT2EventTypes::CONTINUED)) { + ++cur_raw_ev; + ev_cont = reinterpret_cast(cur_raw_ev); + } + decode_monitoring_event(*ev_monitor, ev_cont); + } else { + // Need to wait for next buffer + pending_other_.monitoring = *ev_monitor; + } + } } } } + void decode_monitoring_event(const EVT2EventMonitor &ev_monitor, const EVT2Continued *ev_continued) { + auto &erc_count_forwarder = erc_count_event_forwarder(); + auto &monitoring_forwarder = *monitoring_event_forwarder_; + + if (ev_continued && ev_monitor.subtype == EVT2EventMasterEventTypes::MASTER_IN_CD_EVENT_COUNT || + ev_monitor.subtype == EVT2EventMasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT) { + const uint32_t count = ev_continued->data & ((1U << 22) - 1); + erc_count_forwarder.forward(last_timestamp_, count, + ev_monitor.subtype == + EVT2EventMasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT); + } + monitoring_forwarder.forward(last_timestamp_, ev_monitor.subtype, ev_continued ? ev_continued->data : 0x0); + } + static bool buffer_has_time_loop(const RawEvent *const cur_raw_ev, const RawEvent *const raw_ev_end_, const timestamp base_time_us, const timestamp timeshift_us) { const RawEvent *raw_ev_end = raw_ev_end_; @@ -162,6 +224,9 @@ class EVT2Decoder : public I_EventsStreamDecoder { if (is_time_shifting_enabled() && !shift_set_) { return false; } + + pending_other_.raw = 0x0; + if (t >= 0) { constexpr int min_timer_high_val = (1 << NumBitsInTimestampLSB); base_time_ = min_timer_high_val * (t / min_timer_high_val); @@ -197,6 +262,11 @@ class EVT2Decoder : public I_EventsStreamDecoder { timestamp full_shift_{ 0}; // includes loop and shift_th in one single variable. Must be signed typed as shift can be negative. bool shift_set_{false}; + + std::shared_ptr> event_monitoring_decoder_; + std::unique_ptr> monitoring_event_forwarder_; + const std::set monitoring_id_blacklist_; + EVT2RawEvent pending_other_{0x0}; }; } // namespace Metavision diff --git a/hal/cpp/include/metavision/hal/decoders/evt2/evt2_event_types.h b/hal/cpp/include/metavision/hal/decoders/evt2/evt2_event_types.h index cd08a841f..5c54fcbd3 100644 --- a/hal/cpp/include/metavision/hal/decoders/evt2/evt2_event_types.h +++ b/hal/cpp/include/metavision/hal/decoders/evt2/evt2_event_types.h @@ -157,6 +157,13 @@ struct EVT2TimeHigh { static_assert(sizeof(EVT2TimeHigh) == 4, "The size of the packed struct EVT2TimeHigh is not the expected one (which is 4 bytes)"); +struct EVT2Continued { + std::uint32_t data : 28; + std::uint32_t type : 4; +}; +static_assert(sizeof(EVT2Continued) == 4, + "The size of the packed struct EVT2Continued is not the expected one (which is 4 bytes)"); + struct EVT2EvType { std::uint32_t unused : 28; std::uint32_t type : 4; @@ -170,10 +177,16 @@ union EVT2RawEvent { EVT2Event2D cd; EVT2TimeHigh th; EVT2EventExtTrigger trig; + EVT2EventMonitor monitoring; }; static_assert(sizeof(EVT2RawEvent) == 4, "The size of the packed union EVT2RawEvent is not the expected one (which is 4 bytes)"); +enum EVT2EventMasterEventTypes : uint16_t { + MASTER_IN_CD_EVENT_COUNT = 0x0014, + MASTER_RATE_CONTROL_CD_EVENT_COUNT = 0x0016, +}; + } // namespace Metavision #endif // METAVISION_HAL_EVT2_EVENT_TYPES_H diff --git a/hal/cpp/include/metavision/hal/decoders/evt21/evt21_decoder.h b/hal/cpp/include/metavision/hal/decoders/evt21/evt21_decoder.h index 5a1d8ce05..a00eeb491 100644 --- a/hal/cpp/include/metavision/hal/decoders/evt21/evt21_decoder.h +++ b/hal/cpp/include/metavision/hal/decoders/evt21/evt21_decoder.h @@ -12,12 +12,15 @@ #ifndef METAVISION_HAL_EVT21_DECODER_H #define METAVISION_HAL_EVT21_DECODER_H +#include +#include #include #include "metavision/sdk/base/events/event_cd.h" #include "metavision/sdk/base/events/event_cd_vector.h" #include "metavision/sdk/base/events/event_ext_trigger.h" #include "metavision/sdk/base/events/event_erc_counter.h" +#include "metavision/sdk/base/events/event_monitoring.h" #include "metavision/sdk/base/utils/detail/bitinstructions.h" #include "metavision/hal/facilities/i_event_decoder.h" #include "metavision/hal/facilities/i_events_stream_decoder.h" @@ -41,12 +44,23 @@ class EVT21GenericDecoder : public I_EventsStreamDecoder { const std::shared_ptr> &event_ext_trigger_decoder = std::shared_ptr>(), const std::shared_ptr> &erc_count_event_decoder = - std::shared_ptr>()) : + std::shared_ptr>(), + const std::shared_ptr> &event_monitoring_decoder = + std::shared_ptr>(), + const std::set &monitoring_id_blacklist = std::set()) : I_EventsStreamDecoder(time_shifting_enabled, event_cd_decoder, event_ext_trigger_decoder, - erc_count_event_decoder) { + erc_count_event_decoder), + event_monitoring_decoder_(event_monitoring_decoder), + monitoring_id_blacklist_(monitoring_id_blacklist) { static_assert(Metavision::detail::is_in_type_list_v, "Error, cannot construct EVT21GenericDecoder with specified OutputCDType... Supported types are: " "{EventCD, EventCDVector}."); + + if (event_monitoring_decoder_) { + monitoring_event_forwarder_.reset( + new DecodedEventForwarder(event_monitoring_decoder_.get())); + } + } virtual timestamp get_last_timestamp() const override final { @@ -112,6 +126,7 @@ class EVT21GenericDecoder : public I_EventsStreamDecoder { auto &cd_forwarder = cd_event_forwarder(); auto &trigger_forwarder = trigger_event_forwarder(); auto &erc_count_forwarder = erc_count_event_forwarder(); + auto &monitoring_forwarder = *monitoring_event_forwarder_; const RawEvent *&cur_ev = cur_raw_ev; // We should stop on equality but we test difference here to be sure we don't overflow @@ -159,18 +174,28 @@ class EVT21GenericDecoder : public I_EventsStreamDecoder { static_cast(ev_exttrigger->id)); ++cur_ev; } else if (type == static_cast(Evt21EventTypes_4bits::OTHERS)) { - const Event_OTHERS *ev_other = reinterpret_cast(cur_ev); - Evt21EventMasterEventTypes subtype = static_cast(ev_other->subtype); - if (subtype == Evt21EventMasterEventTypes::MASTER_IN_CD_EVENT_COUNT || - subtype == Evt21EventMasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT) { - uint32_t count = ev_other->payload & ((1 << 22) - 1); + const Event_OTHERS *ev_other = reinterpret_cast(cur_ev); + if (monitoring_id_blacklist_.count(ev_other->subtype) == 0) { + const Evt21EventMasterEventTypes subtype = + static_cast(ev_other->subtype); last_timestamp_ = (last_timestamp_ & ~((1ULL << 6) - 1)) + ev_other->ts; last_timestamp_set_ = true; - erc_count_forwarder.forward(last_timestamp(), count, - subtype == - Evt21EventMasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT); + if (subtype == Evt21EventMasterEventTypes::MASTER_IN_CD_EVENT_COUNT || + subtype == Evt21EventMasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT) { + uint32_t count = ev_other->payload & ((1 << 22) - 1); + erc_count_forwarder.forward(last_timestamp(), count, + subtype == + Evt21EventMasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT); + } + + uint32_t payload = 0x0; + // Has CONTINUED event? + if (ev_other->payload >> 28 == 0xF) { + payload = ev_other->payload & ~(0xF << 28); + } + monitoring_forwarder.forward(last_timestamp(), ev_other->subtype, payload); } ++cur_ev; } else { @@ -218,6 +243,9 @@ class EVT21GenericDecoder : public I_EventsStreamDecoder { timestamp last_timestamp_ = 0; timestamp timestamp_shift_ = 0; bool time_shifting_set_ = false; + std::shared_ptr> event_monitoring_decoder_; + std::unique_ptr> monitoring_event_forwarder_; + std::set monitoring_id_blacklist_; static constexpr uint64_t max_time_high_ = ((1ULL << 28) - 1) << 6; static constexpr int loop_shift_ = 34; static constexpr uint64_t time_high_mask_ = ((1ULL << 28) - 1) << 6; diff --git a/hal/cpp/include/metavision/hal/decoders/evt3/evt3_decoder.h b/hal/cpp/include/metavision/hal/decoders/evt3/evt3_decoder.h index 6eddd3266..2bd5346f1 100644 --- a/hal/cpp/include/metavision/hal/decoders/evt3/evt3_decoder.h +++ b/hal/cpp/include/metavision/hal/decoders/evt3/evt3_decoder.h @@ -15,9 +15,11 @@ #include #include #include +#include #include "metavision/sdk/base/events/event_cd.h" #include "metavision/sdk/base/events/event_erc_counter.h" +#include "metavision/sdk/base/events/event_monitoring.h" #include "metavision/sdk/base/utils/detail/bitinstructions.h" #include "metavision/hal/facilities/i_event_decoder.h" #include "metavision/hal/decoders/base/event_base.h" @@ -50,12 +52,22 @@ class EVT3Decoder : public I_EventsStreamDecoder { const std::shared_ptr> &event_ext_trigger_decoder = std::shared_ptr>(), const std::shared_ptr> &erc_count_event_decoder = - std::shared_ptr>()) : + std::shared_ptr>(), + const std::shared_ptr> &event_monitoring_decoder = + std::shared_ptr>(), + const std::set &monitoring_id_blacklist = std::set()) : I_EventsStreamDecoder(time_shifting_enabled, event_cd_decoder, event_ext_trigger_decoder, erc_count_event_decoder), validator(height, width), - height_(height) { + height_(height), + event_monitoring_decoder_(event_monitoring_decoder), + monitoring_id_blacklist_(monitoring_id_blacklist) { last_timestamp_.time = 0; + + if (event_monitoring_decoder_) { + monitoring_event_forwarder_.reset( + new DecodedEventForwarder(event_monitoring_decoder_.get())); + } } virtual bool get_timestamp_shift(timestamp &ts_shift) const override { @@ -153,6 +165,7 @@ class EVT3Decoder : public I_EventsStreamDecoder { auto &cd_forwarder = cd_event_forwarder(); auto &trigger_forwarder = trigger_event_forwarder(); auto &erc_count_forwarder = erc_count_event_forwarder(); + auto &monitoring_forwarder = *monitoring_event_forwarder_; for (; cur_raw_ev != raw_ev_end;) { const uint16_t type = cur_raw_ev->type; if (type == static_cast(EventTypesEnum::EVT_ADDR_X)) { @@ -235,34 +248,38 @@ class EVT3Decoder : public I_EventsStreamDecoder { ++cur_raw_ev; } else if (type == static_cast(EventTypesEnum::OTHERS)) { const uint16_t master_type = cur_raw_ev->content; - bool is_out_count_evt = false; - - switch (master_type) { - case static_cast(Evt3MasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT): - is_out_count_evt = true; - [[fallthrough]]; - case static_cast(Evt3MasterEventTypes::MASTER_IN_CD_EVENT_COUNT): { - constexpr uint32_t evt_size = 1 + sizeof(Evt3Raw::Event_Continue12_12_4) / sizeof(RawEvent); - if (cur_raw_ev + evt_size > raw_ev_end) { - // Not enough raw data to decode the continue events. Stop decoding this buffer and return the - // amount of data missing to wait for to be able to decode on the next call - return std::distance(raw_ev_end, cur_raw_ev + evt_size); - } + + if (monitoring_id_blacklist_.count(master_type) > 0) { ++cur_raw_ev; + continue; + } + + constexpr uint32_t evt_size = 1 + sizeof(Evt3Raw::Event_Continue12_12_4) / sizeof(RawEvent); + if (cur_raw_ev + evt_size > raw_ev_end) { + // Not enough raw data to decode potential continue events. Stop decoding this buffer and return the + // amount of data missing to wait for to be able to decode on the next call + return std::distance(raw_ev_end, cur_raw_ev + evt_size); + } + + uint32_t payload = 0x0; + + ++cur_raw_ev; + if (cur_raw_ev->type == static_cast(EventTypesEnum::CONTINUED_12)) { int next_offset; - if (validator.validate_continue_12_12_4_pattern(cur_raw_ev, next_offset)) { - const Evt3Raw::Event_Continue12_12_4 *data = - reinterpret_cast(cur_raw_ev); - erc_count_forwarder.forward(last_timestamp(), - Evt3Raw::Event_Continue12_12_4::decode(*data), is_out_count_evt); + if (!validator.validate_continue_12_12_4_pattern(cur_raw_ev, next_offset)) { + cur_raw_ev += next_offset; + continue; } + payload = Evt3Raw::Event_Continue12_12_4::decode( + *reinterpret_cast(cur_raw_ev)); cur_raw_ev += next_offset; - break; } - default: - // Unhandled sys event - ++cur_raw_ev; - break; + + monitoring_forwarder.forward(last_timestamp(), master_type, payload); + if (master_type == static_cast(Evt3MasterEventTypes::MASTER_RATE_CONTROL_CD_EVENT_COUNT)) { + erc_count_forwarder.forward(last_timestamp(), payload, true); + } else if (master_type == static_cast(Evt3MasterEventTypes::MASTER_IN_CD_EVENT_COUNT)) { + erc_count_forwarder.forward(last_timestamp(), payload, false); } } else { // The objective is to reduce the number of possible cases @@ -368,6 +385,9 @@ class EVT3Decoder : public I_EventsStreamDecoder { uint32_t height_ = 65536; std::vector incomplete_multiword_raw_event_; std::ptrdiff_t raw_events_missing_count_{0}; + std::shared_ptr> event_monitoring_decoder_; + std::unique_ptr> monitoring_event_forwarder_; + const std::set monitoring_id_blacklist_; }; } // namespace detail @@ -396,19 +416,25 @@ inline std::unique_ptr make_evt3_decoder( const std::shared_ptr> &event_ext_trigger_decoder = std::shared_ptr>(), const std::shared_ptr> &erc_count_event_decoder = - std::shared_ptr>()) { - std::unique_ptr decoder = std::make_unique( - time_shifting_enabled, height, width, event_cd_decoder, event_ext_trigger_decoder, erc_count_event_decoder); + std::shared_ptr>(), + const std::shared_ptr> &monitoring_event_decoder = + std::shared_ptr>(), + const std::set &monitoring_id_blacklist = std::set()) { + std::unique_ptr decoder = + std::make_unique(time_shifting_enabled, height, width, event_cd_decoder, event_ext_trigger_decoder, + erc_count_event_decoder, monitoring_event_decoder, monitoring_id_blacklist); if (std::getenv("MV_FLAGS_EVT3_THROW_ON_NON_MONOTONIC_TIME_HIGH") || std::getenv("MV_FLAGS_EVT3_ROBUST_DECODER")) { MV_HAL_LOG_INFO() << "Using EVT3 Robust decoder."; decoder = std::make_unique(time_shifting_enabled, height, width, event_cd_decoder, - event_ext_trigger_decoder, erc_count_event_decoder); + event_ext_trigger_decoder, erc_count_event_decoder, + monitoring_event_decoder, monitoring_id_blacklist); } else if (std::getenv("MV_FLAGS_EVT3_UNSAFE_DECODER")) { MV_HAL_LOG_INFO() << "Using EVT3 Unsafe decoder."; decoder = std::make_unique(time_shifting_enabled, height, width, event_cd_decoder, - event_ext_trigger_decoder, erc_count_event_decoder); + event_ext_trigger_decoder, erc_count_event_decoder, + monitoring_event_decoder, monitoring_id_blacklist); } if (std::getenv("MV_FLAGS_EVT3_THROW_ON_NON_MONOTONIC_TIME_HIGH")) { diff --git a/hal/cpp/include/metavision/hal/decoders/evt3/evt3_validator.h b/hal/cpp/include/metavision/hal/decoders/evt3/evt3_validator.h index 222bf767d..13818fc1f 100644 --- a/hal/cpp/include/metavision/hal/decoders/evt3/evt3_validator.h +++ b/hal/cpp/include/metavision/hal/decoders/evt3/evt3_validator.h @@ -59,7 +59,7 @@ class ValidatorInterface { void notify(DecoderProtocolViolation violation) { if (notifiers_map_.empty()) { std::ostringstream oss; - oss << "Evt3 protocol violation detected : " << violation; + oss << "Evt3 protocol violation detected: " << violation; if (violation == DecoderProtocolViolation::NonMonotonicTimeHigh) { MV_HAL_LOG_ERROR() << oss.str(); } else { diff --git a/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_camera_synchronization.cpp b/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_camera_synchronization.cpp index 6dbf0b9d9..883035bd9 100644 --- a/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_camera_synchronization.cpp +++ b/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_camera_synchronization.cpp @@ -42,8 +42,7 @@ bool SampleCameraSynchronization::set_mode_master() { } bool SampleCameraSynchronization::set_mode_slave() { - // TODO: when testing with metavision_hal_sync, the camera streams in slave mode without master sending signal - // There must be a problem in the Slave Mode configuration + // This code is baseline that should be checked and enhanced by reviewing the datasheet and Prophesee plugin code. // First, update register 0x00009008 (ro/time_base_ctrl) which has a default value of 0x00000640 // We write the following bits (0 being the least significant one): diff --git a/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_event_trail_filter.cpp b/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_event_trail_filter.cpp index 92273699c..e2987a728 100644 --- a/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_event_trail_filter.cpp +++ b/hal/cpp/samples/metavision_hal_evk4_sample_plugin/src/sample_event_trail_filter.cpp @@ -71,14 +71,14 @@ bool SampleEventTrailFilter::enable(bool state) { write_register(*usb_connection_, 0x0000D004, 0x01); // trail_param to 0 write_register(*usb_connection_, 0x0000D008, 0x00); - // ToDo we should update the value of stc_threshold and disable_stc_cut_trail as well + // For a fully functional facility, stc_threshold and disable_stc_cut_trail should also be updated } else if (filtering_type_ == Metavision::I_EventTrailFilterModule::Type::TRAIL) { // stc_enable to 0 write_register(*usb_connection_, 0x0000D004, 0x00); // trail_param to 1 write_register(*usb_connection_, 0x0000D008, 0x01); - // ToDo we should update the value of trail_threshold as well + // For a fully functional facility, trail_threshold should also be updated } // We write 101 (5) to stc/pipeline_control to enable the block diff --git a/hal/cpp/samples/metavision_hal_showcase/metavision_hal_showcase.cpp b/hal/cpp/samples/metavision_hal_showcase/metavision_hal_showcase.cpp index 31e9cb960..fa0d5a7c5 100644 --- a/hal/cpp/samples/metavision_hal_showcase/metavision_hal_showcase.cpp +++ b/hal/cpp/samples/metavision_hal_showcase/metavision_hal_showcase.cpp @@ -252,8 +252,19 @@ int main(int argc, char *argv[]) { Metavision::I_EventRateActivityFilterModule *i_event_rate_activity_filter_module = device->get_facility(); if (i_event_rate_activity_filter_module) { + Metavision::I_EventRateActivityFilterModule::thresholds NFL_ths; + NFL_ths.lower_bound_start = 0; + NFL_ths.lower_bound_stop = 0; + NFL_ths.upper_bound_start = 100000000; + NFL_ths.upper_bound_stop = 110000000; + i_event_rate_activity_filter_module->set_thresholds(NFL_ths); + i_event_rate_activity_filter_module->enable(true); std::cout << "Event rate activity filter: streaming from " - << i_event_rate_activity_filter_module->get_thresholds().lower_bound_start << " Kev/s" << std::endl; + << i_event_rate_activity_filter_module->get_thresholds().lower_bound_start/1000 << " - " + << i_event_rate_activity_filter_module->get_thresholds().lower_bound_stop/1000 << " Kev/s, up to " + << i_event_rate_activity_filter_module->get_thresholds().upper_bound_start/1000000 << " - " + << i_event_rate_activity_filter_module->get_thresholds().upper_bound_stop/1000000 << " Mev/s" + << std::endl; } auto tokenize = [](std::string str, std::string separator) { diff --git a/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/CMakeLists.txt b/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/CMakeLists.txt index 504e700cb..fe8f8cc2b 100644 --- a/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/CMakeLists.txt +++ b/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/CMakeLists.txt @@ -26,7 +26,7 @@ register_gtest(TEST hal-toy-sample-plugin-test-lib TARGET gtest_metavision_hal_toy_sample_plugin HAL_PLUGIN_PATH "${HAL_BUILD_PLUGIN_PATH}/sample") -set(apps_to_test metavision_platform_info metavision_file_info metavision_hal_raw_cutter metavision_file_to_csv metavision_file_to_dat) +set(apps_to_test metavision_platform_info metavision_file_info metavision_hal_raw_cutter metavision_file_to_dat) # TODO MV-167 : add app metavision_hal_ls in list above foreach(app_name IN LISTS apps_to_test) string(REPLACE "_" "-" test_name "${app_name}") diff --git a/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/metavision_file_to_csv_with_sample_plugin_pytest.py b/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/metavision_file_to_csv_with_sample_plugin_pytest.py deleted file mode 100644 index f28687426..000000000 --- a/hal/cpp/samples/metavision_hal_toy_sample_plugin/test/metavision_file_to_csv_with_sample_plugin_pytest.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) Prophesee S.A. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed -# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and limitations under the License. - -import pytest -import os -from metavision_utils import os_tools, pytest_tools - - -def get_ev_from_line(line): - items = line.strip().split(",") - assert len(items) == 4 - return {'x': int(items[0]), 'y': int(items[1]), 'p': int(items[2]), 't': int(items[3])} - - -def pytestcase_test_metavision_file_to_csv_with_sample_plugin(dataset_dir): - ''' - Checks output of metavision_file_to_csv application when using sample plugin - ''' - - filename = "sample_plugin_recording.raw" - filename_full = os.path.join(dataset_dir, "openeb", filename) - - # Before launching the app, check the dataset file exists - assert os.path.exists(filename_full) - - # Since the application metavision_file_to_csv writes the output file in the same directory - # the app is launched from, create a tmp directory from where we can run the app - tmp_dir = os_tools.TemporaryDirectoryHandler() - output_filename = os.path.join( - tmp_dir.temporary_directory(), - os.path.splitext(filename)[0] + ".csv") - - # The pytest is run from the build/bin dir (cf CMakeLists.txt), but since we'll run the command - # from the temporary directory created above, we need to get the full path to the application - application_full_path = os.path.join(os.getcwd(), "metavision_file_to_csv") - - cmd = "\"{}\" -i \"{}\" -o \"{}\"".format(application_full_path, filename_full, output_filename) - output, error_code = pytest_tools.run_cmd_setting_mv_log_file(cmd, working_directory=tmp_dir.temporary_directory()) - - # Check app exited without error - assert error_code == 0, "******\nError while executing cmd '{}':{}\n******".format(cmd, output) - - # Check CSV file has been written - assert os.path.exists(output_filename) - - # Checking all events would take long, so we just test a subset - idx_to_check = [1, 2647, 15098, 31393, 55056, 60392, 126838, 160953, 161756, 239542, 255380, 263120, 286172, - 305025, 306674, 313755, 337452, 340242, 348143, 362732, 367017, 367516, 411226, 411721, 414272, - 469949, 478421, 487793, 494067, 502675, 510576, 518535, 519037, 541733, 542226, 595092, 595579, - 599828, 615304, 653587, 655153, 663832, 665051, 665486, 671977, 676311, 689468, 697722, 700298, - 745706, 760479, 790839] - events_expected = [{'x': 294, 'y': 284, 'p': 1, 't': 0}, {'x': 302, 'y': 298, 'p': 1, 't': 16040}, - {'x': 300, 'y': 327, 'p': 0, 't': 92225}, {'x': 372, 'y': 398, 'p': 1, 't': 190475}, - {'x': 427, 'y': 430, 'p': 0, 't': 334835}, {'x': 477, 'y': 468, 'p': 1, 't': 366915}, - {'x': 487, 'y': 270, 'p': 1, 't': 771920}, {'x': 376, 'y': 180, 'p': 1, 't': 978435}, - {'x': 410, 'y': 205, 'p': 0, 't': 982450}, {'x': 160, 'y': 71, 'p': 0, 't': 1455630}, - {'x': 110, 'y': 119, 'p': 0, 't': 1551870}, {'x': 66, 'y': 143, 'p': 0, 't': 1599985}, - {'x': 3, 'y': 214, 'p': 0, 't': 1738335}, {'x': 474, 'y': 293, 'p': 1, 't': 1853820}, - {'x': 400, 'y': 497, 'p': 0, 't': 1863645}, {'x': 87, 'y': 321, 'p': 0, 't': 1906750}, - {'x': 161, 'y': 408, 'p': 1, 't': 2051110}, {'x': 207, 'y': 408, 'p': 1, 't': 2067155}, - {'x': 231, 'y': 413, 'p': 1, 't': 2115275}, {'x': 235, 'y': 446, 'p': 0, 't': 2203495}, - {'x': 285, 'y': 497, 'p': 1, 't': 2229560}, {'x': 286, 'y': 499, 'p': 1, 't': 2233565}, - {'x': 408, 'y': 367, 'p': 0, 't': 2498230}, {'x': 405, 'y': 365, 'p': 0, 't': 2502235}, - {'x': 404, 'y': 317, 'p': 1, 't': 2518275}, {'x': 567, 'y': 189, 'p': 0, 't': 2855120}, - {'x': 532, 'y': 144, 'p': 1, 't': 2907245}, {'x': 537, 'y': 135, 'p': 0, 't': 2963390}, - {'x': 522, 'y': 116, 'p': 0, 't': 3001485}, {'x': 459, 'y': 75, 'p': 1, 't': 3053615}, - {'x': 435, 'y': 32, 'p': 1, 't': 3101735}, {'x': 74, 'y': 192, 'p': 0, 't': 3151055}, - {'x': 416, 'y': 0, 'p': 1, 't': 3153865}, {'x': 353, 'y': 109, 'p': 1, 't': 3292205}, - {'x': 355, 'y': 110, 'p': 1, 't': 3294215}, {'x': 31, 'y': 307, 'p': 1, 't': 3615615}, - {'x': 177, 'y': 261, 'p': 1, 't': 3619020}, {'x': 192, 'y': 285, 'p': 1, 't': 3645085}, - {'x': 157, 'y': 326, 'p': 0, 't': 3739320}, {'x': 41, 'y': 445, 'p': 0, 't': 3971900}, - {'x': 357, 'y': 491, 'p': 0, 't': 3980725}, {'x': 42, 'y': 479, 'p': 1, 't': 4034055}, - {'x': 76, 'y': 216, 'p': 0, 't': 4040475}, {'x': 51, 'y': 484, 'p': 1, 't': 4044080}, - {'x': 54, 'y': 492, 'p': 0, 't': 4082180}, {'x': 99, 'y': 441, 'p': 1, 't': 4110245}, - {'x': 107, 'y': 440, 'p': 0, 't': 4188445}, {'x': 119, 'y': 398, 'p': 0, 't': 4239170}, - {'x': 158, 'y': 409, 'p': 0, 't': 4254610}, {'x': 278, 'y': 237, 'p': 0, 't': 4531295}, - {'x': 363, 'y': 195, 'p': 1, 't': 4621520}, {'x': 455, 'y': 103, 'p': 1, 't': 4805980}] - - # Now open the file and check for its contents - with open(output_filename, 'r') as f: - lines = f.readlines() - - # Check number of events - nr_events = len(lines) - assert nr_events == 790840 - - # Check events : - for idx in range(0, len(idx_to_check)): - ev = get_ev_from_line(lines[idx_to_check[idx]]) - assert ev == events_expected[idx], "Error on event nr {}".format(idx_to_check[idx]) diff --git a/hal/cpp/test/decoders_evt3_decoder_gtest.cpp b/hal/cpp/test/decoders_evt3_decoder_gtest.cpp index b3c874463..9b29d36d7 100644 --- a/hal/cpp/test/decoders_evt3_decoder_gtest.cpp +++ b/hal/cpp/test/decoders_evt3_decoder_gtest.cpp @@ -28,10 +28,12 @@ using namespace ::testing; using EventCdDecoder = I_EventDecoder; using EventExtDecoder = I_EventDecoder; using EventErcDecoder = I_EventDecoder; +using EventMonitoringDecoder = I_EventDecoder; using EventCdBuffer = std::vector; using EventExtBuffer = std::vector; using EventErcBuffer = std::vector; +using EventMonitoringBuffer = std::vector; using DataBuffer = std::vector; @@ -84,10 +86,11 @@ ostream &operator<<(ostream &o, const vector &evt) { } } // namespace std -using DecodedBuffers = std::tuple; +using DecodedBuffers = std::tuple; DecodedBuffers decode_buffer(const DataBuffer &data, I_Decoder &decoder, EventCdDecoder &event_cd_decoder, - EventExtDecoder &event_ext_decoder, EventErcDecoder &event_erc_decoder) { + EventExtDecoder &event_ext_decoder, EventErcDecoder &event_erc_decoder, + EventMonitoringDecoder &event_monitoring_decoder) { std::vector event_cd_buffer; auto cd_cb_id = event_cd_decoder.add_event_buffer_callback( [&](auto beg, auto end) { std::copy(beg, end, std::back_inserter(event_cd_buffer)); }); @@ -100,13 +103,18 @@ DecodedBuffers decode_buffer(const DataBuffer &data, I_Decoder &decoder, EventCd auto erc_cb_id = event_erc_decoder.add_event_buffer_callback( [&](auto beg, auto end) { std::copy(beg, end, std::back_inserter(event_erc_buffer)); }); + std::vector event_monitoring_buffer; + auto monitoring_cb_id = event_monitoring_decoder.add_event_buffer_callback( + [&](auto beg, auto end) { std::copy(beg, end, std::back_inserter(event_monitoring_buffer)); }); + decoder.decode(cbegin(data), cend(data)); event_cd_decoder.remove_callback(cd_cb_id); event_ext_decoder.remove_callback(ext_cb_id); event_erc_decoder.remove_callback(erc_cb_id); + event_monitoring_decoder.remove_callback(monitoring_cb_id); - return std::make_tuple(event_cd_buffer, event_ext_buffer, event_erc_buffer); + return std::make_tuple(event_cd_buffer, event_ext_buffer, event_erc_buffer, event_monitoring_buffer); } TEST(Evt3_decoder, should_construct_evt3_decoder) { @@ -117,8 +125,10 @@ struct Evt3DecoderTest : public ::testing::Test { std::shared_ptr event_cd_decoder = std::make_shared(); std::shared_ptr event_ext_decoder = std::make_shared(); std::shared_ptr event_erc_decoder = std::make_shared(); + std::shared_ptr event_monitoring_decoder = std::make_shared(); - EVT3Decoder decoder{false, 100, 100, event_cd_decoder, event_ext_decoder, event_erc_decoder}; + EVT3Decoder decoder{false, 100, 100, event_cd_decoder, event_ext_decoder, event_erc_decoder, + event_monitoring_decoder}; template using StrictMockFunction = StrictMock>; @@ -129,12 +139,14 @@ struct Evt3DecoderTest : public ::testing::Test { } DecodedBuffers decode(DataBuffer &&data) { - return decode_buffer(data, decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder); + return decode_buffer(data, decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder, + *event_monitoring_decoder); } template T decode(DataBuffer &&data) { - auto events_buffers = decode_buffer(data, decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder); + auto events_buffers = decode_buffer(data, decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder, + *event_monitoring_decoder); return std::get(events_buffers); } }; @@ -351,8 +363,10 @@ struct Evt3RobustDecoderTest : public ::testing::Test { std::shared_ptr event_cd_decoder = std::make_shared(); std::shared_ptr event_ext_decoder = std::make_shared(); std::shared_ptr event_erc_decoder = std::make_shared(); + std::shared_ptr event_monitoring_decoder = std::make_shared(); - RobustEVT3Decoder robust_decoder{false, 100, 100, event_cd_decoder, event_ext_decoder, event_erc_decoder}; + RobustEVT3Decoder robust_decoder{false, 100, 100, event_cd_decoder, event_ext_decoder, event_erc_decoder, + event_monitoring_decoder}; template using StrictMockFunction = StrictMock>; @@ -363,13 +377,14 @@ struct Evt3RobustDecoderTest : public ::testing::Test { } DecodedBuffers decode(DataBuffer &&data) { - return decode_buffer(data, robust_decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder); + return decode_buffer(data, robust_decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder, + *event_monitoring_decoder); } template T decode(DataBuffer &&data) { - auto events_buffers = - decode_buffer(data, robust_decoder, *event_cd_decoder, *event_ext_decoder, *event_erc_decoder); + auto events_buffers = decode_buffer(data, robust_decoder, *event_cd_decoder, *event_ext_decoder, + *event_erc_decoder, *event_monitoring_decoder); return std::get(events_buffers); } }; diff --git a/hal/python/CMakeLists.txt b/hal/python/CMakeLists.txt index a81e95006..40ef40c16 100644 --- a/hal/python/CMakeLists.txt +++ b/hal/python/CMakeLists.txt @@ -14,7 +14,9 @@ add_subdirectory(bindings) add_subdirectory(samples) # Tests -add_subdirectory(tests) +if (BUILD_TESTING) + add_subdirectory(tests) +endif() # Documentations if (GENERATE_DOC_PYTHON_BINDINGS) diff --git a/hal/python/bindings/raw_file_config_python.cpp b/hal/python/bindings/raw_file_config_python.cpp index a4569288d..80fe213ae 100644 --- a/hal/python/bindings/raw_file_config_python.cpp +++ b/hal/python/bindings/raw_file_config_python.cpp @@ -25,7 +25,9 @@ static HALClassPythonBinder bind( .def_readwrite("n_read_buffers", &RawFileConfig::n_read_buffers_, pybind_doc_hal["Metavision::RawFileConfig::n_read_buffers_"]) .def_readwrite("do_time_shifting", &RawFileConfig::do_time_shifting_, - pybind_doc_hal["Metavision::RawFileConfig::do_time_shifting_"]); + pybind_doc_hal["Metavision::RawFileConfig::do_time_shifting_"]) + .def_readwrite("build_index", &RawFileConfig::build_index_, + pybind_doc_hal["Metavision::RawFileConfig::build_index_"]); }, "RawFileConfig", pybind_doc_hal["Metavision::RawFileConfig"]); diff --git a/hal_psee_plugins/src/utils/make_decoder.cpp b/hal_psee_plugins/src/utils/make_decoder.cpp index 5fb649454..4cde2f3ba 100644 --- a/hal_psee_plugins/src/utils/make_decoder.cpp +++ b/hal_psee_plugins/src/utils/make_decoder.cpp @@ -67,6 +67,12 @@ std::shared_ptr make_decoder(DeviceBuilder &device_builde std::shared_ptr frame_decoder; auto i_geometry = device_builder.add_facility(format.geometry()); + // Set of monitoring Subtypes that have more than one CONTINUED + // Not supported by current decoders + std::set monitoring_id_blacklist = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + }; + raw_size_bytes = 0; if (format.name() == "EVT4") { auto cd_decoder = device_builder.add_facility(std::make_unique>()); @@ -82,24 +88,29 @@ std::shared_ptr make_decoder(DeviceBuilder &device_builde auto cd_decoder = device_builder.add_facility(std::make_unique>()); auto ext_trig_decoder = device_builder.add_facility(std::make_unique>()); auto erc_count_ev_decoder = device_builder.add_facility(std::make_unique>()); + auto monitoring_ev_decoder = device_builder.add_facility(std::make_unique>()); - decoder = device_builder.add_facility(make_evt3_decoder(do_time_shifting, i_geometry->get_height(), - i_geometry->get_width(), cd_decoder, ext_trig_decoder, - erc_count_ev_decoder)); + decoder = device_builder.add_facility( + make_evt3_decoder(do_time_shifting, i_geometry->get_height(), i_geometry->get_width(), cd_decoder, + ext_trig_decoder, erc_count_ev_decoder, monitoring_ev_decoder, monitoring_id_blacklist)); raw_size_bytes = decoder->get_raw_event_size_bytes(); } else if (format.name() == "EVT2") { auto cd_decoder = device_builder.add_facility(std::make_unique>()); auto ext_trig_decoder = device_builder.add_facility(std::make_unique>()); + auto erc_count_ev_decoder = device_builder.add_facility(std::make_unique>()); + auto monitoring_ev_decoder = device_builder.add_facility(std::make_unique>()); - decoder = - device_builder.add_facility(std::make_unique(do_time_shifting, cd_decoder, ext_trig_decoder)); + decoder = device_builder.add_facility( + std::make_unique(do_time_shifting, cd_decoder, ext_trig_decoder, erc_count_ev_decoder, + monitoring_ev_decoder, monitoring_id_blacklist)); raw_size_bytes = decoder->get_raw_event_size_bytes(); } else if (format.name() == "EVT21") { auto ext_trig_decoder = device_builder.add_facility(std::make_unique>()); auto erc_count_ev_decoder = device_builder.add_facility(std::make_unique>()); - auto endianness = format["endianness"]; + auto monitoring_ev_decoder = device_builder.add_facility(std::make_unique>()); + auto endianness = format["endianness"]; auto evt21_keep_vectors = config.get("evt21_keep_vectors"); @@ -110,18 +121,21 @@ std::shared_ptr make_decoder(DeviceBuilder &device_builde auto cd_vector_decoder = device_builder.add_facility(std::make_unique>()); - decoder = device_builder.add_facility( - std::make_unique(do_time_shifting, cd_vector_decoder, ext_trig_decoder, erc_count_ev_decoder)); + decoder = device_builder.add_facility(std::make_unique( + do_time_shifting, cd_vector_decoder, ext_trig_decoder, erc_count_ev_decoder, monitoring_ev_decoder, + monitoring_id_blacklist)); }else{ auto cd_decoder = device_builder.add_facility(std::make_unique>()); if (endianness == "legacy") { decoder = device_builder.add_facility(std::make_unique( - do_time_shifting, cd_decoder, ext_trig_decoder, erc_count_ev_decoder)); + do_time_shifting, cd_decoder, ext_trig_decoder, erc_count_ev_decoder, monitoring_ev_decoder, + monitoring_id_blacklist)); } else { decoder = device_builder.add_facility( - std::make_unique(do_time_shifting, cd_decoder, ext_trig_decoder, erc_count_ev_decoder)); + std::make_unique(do_time_shifting, cd_decoder, ext_trig_decoder, erc_count_ev_decoder, + monitoring_ev_decoder, monitoring_id_blacklist)); } } raw_size_bytes = decoder->get_raw_event_size_bytes(); diff --git a/hal_psee_plugins/test/psee_raw_file_decoder_gtest.cpp b/hal_psee_plugins/test/psee_raw_file_decoder_gtest.cpp index a59d2a47b..474204c4a 100644 --- a/hal_psee_plugins/test/psee_raw_file_decoder_gtest.cpp +++ b/hal_psee_plugins/test/psee_raw_file_decoder_gtest.cpp @@ -18,6 +18,7 @@ #include "metavision/utils/gtest/gtest_with_tmp_dir.h" #include "metavision/utils/gtest/gtest_custom.h" #include "metavision/sdk/base/events/event_cd.h" +#include "metavision/sdk/base/events/event_monitoring.h" #include "metavision/sdk/base/events/event_pointcloud.h" #include "metavision/sdk/base/events/raw_event_frame_diff.h" #include "metavision/sdk/base/events/raw_event_frame_histo.h" @@ -1601,3 +1602,150 @@ TEST_F_WITH_DATASET(PseeRawFileDecoder_Gtest, decode_mtru_nominal) { // THEN We decode the same MTR data that are encoded in the RAW file ASSERT_EQ(378, received_event_frame_count); } + +TEST_F_WITH_DATASET(PseeRawFileDecoder_Gtest, decode_evt2_monitoring_events) { + // GIVEN a RAW file in EVT2 format with a known content + std::string dataset_file_path = + (std::filesystem::path(GtestsParameters::instance().dataset_dir) / "openeb" / + "lifo_evt2.raw").string(); + + size_t received_cd_event_count = 0; + size_t received_monitoring_event_count = 0; + RawFileConfig cfg; + cfg.do_time_shifting_ = false; + std::unique_ptr device(DeviceDiscovery::open_raw_file(dataset_file_path, cfg)); + + ASSERT_TRUE(device) << "Failed to open raw file"; + + // AND a PSEE decoder of CD & monitoring events + auto decoder = device->get_facility(); + auto cd_decoder = device->get_facility>(); + auto monitoring_decoder = device->get_facility>(); + auto es = device->get_facility(); + + ASSERT_NE(nullptr, decoder); + ASSERT_NE(nullptr, cd_decoder); + ASSERT_NE(nullptr, es); + + cd_decoder->add_event_buffer_callback( + [&](auto ev_begin, auto ev_end) { received_cd_event_count += std::distance(ev_begin, ev_end); }); + + monitoring_decoder->add_event_buffer_callback( + [&](auto ev_begin, auto ev_end) { + for (auto it = ev_begin; it < ev_end; ++it) { + // 0x42 = MASTER_ANA_LIFO_ON + ASSERT_EQ(0x42, it->type_id); + } + received_monitoring_event_count += std::distance(ev_begin, ev_end); }); + + + es->start(); + + // WHEN we stream and decode the events in the file + while (es->wait_next_buffer() >= 0) { + auto raw_buffer = es->get_latest_raw_data(); + decoder->decode(raw_buffer); + } + + // THEN We decode the same data CD & triggers that are encoded in the RAW file + ASSERT_EQ(8314158, received_cd_event_count); + ASSERT_EQ(493, received_monitoring_event_count); +} + +TEST_F_WITH_DATASET(PseeRawFileDecoder_Gtest, decode_evt21_monitoring_events) { + // GIVEN a RAW file in EVT21 format with a known content + std::string dataset_file_path = + (std::filesystem::path(GtestsParameters::instance().dataset_dir) / "openeb" / + "lifo_evt21.raw").string(); + + size_t received_cd_event_count = 0; + size_t received_monitoring_event_count = 0; + RawFileConfig cfg; + cfg.do_time_shifting_ = false; + std::unique_ptr device(DeviceDiscovery::open_raw_file(dataset_file_path, cfg)); + + ASSERT_TRUE(device) << "Failed to open raw file"; + + // AND a PSEE decoder of CD & monitoring events + auto decoder = device->get_facility(); + auto cd_decoder = device->get_facility>(); + auto monitoring_decoder = device->get_facility>(); + auto es = device->get_facility(); + + ASSERT_NE(nullptr, decoder); + ASSERT_NE(nullptr, cd_decoder); + ASSERT_NE(nullptr, es); + + cd_decoder->add_event_buffer_callback( + [&](auto ev_begin, auto ev_end) { received_cd_event_count += std::distance(ev_begin, ev_end); }); + + monitoring_decoder->add_event_buffer_callback( + [&](auto ev_begin, auto ev_end) { + for (auto it = ev_begin; it < ev_end; ++it) { + // 0x42 = MASTER_ANA_LIFO_ON + ASSERT_EQ(0x42, it->type_id); + } + received_monitoring_event_count += std::distance(ev_begin, ev_end); }); + + + es->start(); + + // WHEN we stream and decode the events in the file + while (es->wait_next_buffer() >= 0) { + auto raw_buffer = es->get_latest_raw_data(); + decoder->decode(raw_buffer); + } + + // THEN We decode the same data CD & triggers that are encoded in the RAW file + ASSERT_EQ(8314158, received_cd_event_count); + ASSERT_EQ(493, received_monitoring_event_count); +} + +TEST_F_WITH_DATASET(PseeRawFileDecoder_Gtest, decode_evt3_monitoring_events) { + // GIVEN a RAW file in EVT3 format with a known content + std::string dataset_file_path = + (std::filesystem::path(GtestsParameters::instance().dataset_dir) / "openeb" / + "lifo_evt3.raw").string(); + + size_t received_cd_event_count = 0; + size_t received_monitoring_event_count = 0; + RawFileConfig cfg; + cfg.do_time_shifting_ = false; + std::unique_ptr device(DeviceDiscovery::open_raw_file(dataset_file_path, cfg)); + + ASSERT_TRUE(device) << "Failed to open raw file"; + + // AND a PSEE decoder of CD & monitoring events + auto decoder = device->get_facility(); + auto cd_decoder = device->get_facility>(); + auto monitoring_decoder = device->get_facility>(); + auto es = device->get_facility(); + + ASSERT_NE(nullptr, decoder); + ASSERT_NE(nullptr, cd_decoder); + ASSERT_NE(nullptr, es); + + cd_decoder->add_event_buffer_callback( + [&](auto ev_begin, auto ev_end) { received_cd_event_count += std::distance(ev_begin, ev_end); }); + + monitoring_decoder->add_event_buffer_callback( + [&](auto ev_begin, auto ev_end) { + for (auto it = ev_begin; it < ev_end; ++it) { + // 0x42 = MASTER_ANA_LIFO_ON + ASSERT_EQ(0x42, it->type_id); + } + received_monitoring_event_count += std::distance(ev_begin, ev_end); }); + + + es->start(); + + // WHEN we stream and decode the events in the file + while (es->wait_next_buffer() >= 0) { + auto raw_buffer = es->get_latest_raw_data(); + decoder->decode(raw_buffer); + } + + // THEN We decode the same data CD & triggers that are encoded in the RAW file + ASSERT_EQ(8314158, received_cd_event_count); + ASSERT_EQ(493, received_monitoring_event_count); +} diff --git a/sdk/cmake/MetavisionSDKModulesHelper.cmake b/sdk/cmake/MetavisionSDKModulesHelper.cmake index 2a807a78c..a677c64e7 100644 --- a/sdk/cmake/MetavisionSDKModulesHelper.cmake +++ b/sdk/cmake/MetavisionSDKModulesHelper.cmake @@ -238,7 +238,7 @@ endfunction(cmake_parse_arguments_only) # include(CMakeParseArguments) function(MetavisionSDK_add_module module_name) - set(multiValueArgs SOURCES EXTRA_REQUIRED_PACKAGE REQUIRED_METAVISION_SDK_MODULES VARIABLE_TO_SET) + set(multiValueArgs SOURCES EXTRA_REQUIRED_PACKAGE REQUIRED_METAVISION_SDK_MODULES VARIABLE_TO_SET VARIABLE_TO_SET_WIN32) cmake_parse_arguments(PARSED_ARGS "INTERFACE_LIBRARY" "" "${multiValueArgs}" ${ARGN}) # Check validity of input args @@ -368,6 +368,14 @@ function(MetavisionSDK_add_module module_name) set(config_file_text "${config_file_text}set(${variable_to_set})\n") endforeach(variable_to_set) + if(PARSED_ARGS_VARIABLE_TO_SET_WIN32) + string(APPEND config_file_text "if(WIN32)\n") + foreach(win32_variable_to_set ${PARSED_ARGS_VARIABLE_TO_SET_WIN32}) + string(APPEND config_file_text " set(${win32_variable_to_set})\n") + endforeach(win32_variable_to_set) + string(APPEND config_file_text "endif(WIN32)\n\n") + endif(PARSED_ARGS_VARIABLE_TO_SET_WIN32) + foreach(extra_package ${PARSED_ARGS_EXTRA_REQUIRED_PACKAGE}) set(config_file_text "${config_file_text}find_package(${extra_package} REQUIRED QUIET)\n") endforeach(extra_package) diff --git a/sdk/modules/base/cpp/include/metavision/sdk/base/events/event_monitoring.h b/sdk/modules/base/cpp/include/metavision/sdk/base/events/event_monitoring.h new file mode 100644 index 000000000..1c17ad7f4 --- /dev/null +++ b/sdk/modules/base/cpp/include/metavision/sdk/base/events/event_monitoring.h @@ -0,0 +1,53 @@ +/********************************************************************************************************************** + * Copyright (c) Prophesee S.A. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); * + * you may not use this file except in compliance with the License. * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and limitations under the License. * + **********************************************************************************************************************/ + +#ifndef METAVISION_SDK_BASE_EVENT_MONITORING_H +#define METAVISION_SDK_BASE_EVENT_MONITORING_H + +#include +#include +#include +#include "metavision/sdk/base/utils/timestamp.h" + +namespace Metavision { + +/// @brief Class representing monitoring event notifications +class EventMonitoring { +public: + /// @brief Timestamp at which the event happened (in us) + timestamp t; + /// @brief ID of the monitoring event type + uint32_t type_id; + /// @brief Data associated to the event + uint32_t payload; + + /// @brief Default constructor + EventMonitoring() = default; + + /// @brief Constructor + /// @param t Timestamp of the event (in us) + /// @param type_id ID of the monitoring event type + /// @param payload Data associated to the event + inline EventMonitoring(timestamp t, uint32_t type_id, uint32_t payload) : + t(t), type_id(type_id), payload(payload) {} + + bool operator==(const EventMonitoring &e) const { + return e.t == t && e.type_id == type_id && e.payload == payload; + } + + friend std::ostream &operator<<(std::ostream &out, const EventMonitoring &e) { + out << "EventMonitoring: (" << e.t << ", 0x" << std::hex << e.type_id << ", 0x" << e.payload << std::dec << ")"; + return out; + } +}; +} // namespace Metavision + +#endif // METAVISION_SDK_BASE_EVENT_MONITORING_H diff --git a/sdk/modules/core/cpp/samples/metavision_csv_viewer/metavision_csv_viewer.cpp b/sdk/modules/core/cpp/samples/metavision_csv_viewer/metavision_csv_viewer.cpp index 5c38c6cd8..87e47093f 100644 --- a/sdk/modules/core/cpp/samples/metavision_csv_viewer/metavision_csv_viewer.cpp +++ b/sdk/modules/core/cpp/samples/metavision_csv_viewer/metavision_csv_viewer.cpp @@ -19,8 +19,8 @@ #include #include #include -#include "metavision/sdk/base/events/event_cd.h" -#include "metavision/sdk/base/utils/object_pool.h" +#include +#include #include #include #include diff --git a/sdk/modules/core/cpp/samples/metavision_filtering/metavision_filtering.cpp b/sdk/modules/core/cpp/samples/metavision_filtering/metavision_filtering.cpp index 0611b1427..a7d38ccf4 100644 --- a/sdk/modules/core/cpp/samples/metavision_filtering/metavision_filtering.cpp +++ b/sdk/modules/core/cpp/samples/metavision_filtering/metavision_filtering.cpp @@ -22,8 +22,8 @@ #include #include #include -#include "metavision/sdk/ui/utils/event_loop.h" -#include "metavision/sdk/ui/utils/window.h" +#include +#include namespace po = boost::program_options; diff --git a/sdk/modules/core/python/samples/CMakeLists.txt b/sdk/modules/core/python/samples/CMakeLists.txt index b88cfe85e..c6cfc1b73 100644 --- a/sdk/modules/core/python/samples/CMakeLists.txt +++ b/sdk/modules/core/python/samples/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(metavision_events_integration) add_subdirectory(metavision_file_to_csv) add_subdirectory(metavision_filtering) add_subdirectory(metavision_interop) -add_subdirectory(metavision_sdk_get_started) add_subdirectory(metavision_simple_recorder) add_subdirectory(metavision_simple_viewer) add_subdirectory(metavision_sync) diff --git a/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started.py b/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started.py deleted file mode 100644 index f6703d24d..000000000 --- a/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) Prophesee S.A. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed -# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and limitations under the License. - -""" -Metavision SDK Get Started. -""" - - -from metavision_core.event_io import EventsIterator -from metavision_sdk_core import PeriodicFrameGenerationAlgorithm -from metavision_sdk_ui import EventLoop, BaseWindow, Window, UIAction, UIKeyEvent - -accumulation_time_us = 10000 - - -def parse_args(): - import argparse - """Parse command line arguments.""" - parser = argparse.ArgumentParser(description='Metavision SDK Get Started sample.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument( - '-i', '--input-event-file', dest='event_file_path', default="", - help="Path to input event file (RAW or HDF5). If not specified, the camera live stream is used. " - "If it's a camera serial number, it will try to open that camera instead.") - args = parser.parse_args() - return args - - -def main(): - """ Main """ - args = parse_args() - - # Events iterator on Camera or event file - mv_iterator = EventsIterator(input_path=args.event_file_path, delta_t=1000) - height, width = mv_iterator.get_size() # Camera Geometry - - # Window - Graphical User Interface - with Window(title="Metavision SDK Get Started", width=width, height=height, mode=BaseWindow.RenderMode.BGR) as window: - def keyboard_cb(key, scancode, action, mods): - if action != UIAction.RELEASE: - return - if key == UIKeyEvent.KEY_ESCAPE or key == UIKeyEvent.KEY_Q: - window.set_close_flag() - - window.set_keyboard_callback(keyboard_cb) - - # Event Frame Generator - event_frame_gen = PeriodicFrameGenerationAlgorithm(sensor_width=width, sensor_height=height, - accumulation_time_us=accumulation_time_us) - - def on_cd_frame_cb(ts, cd_frame): - window.show(cd_frame) - - event_frame_gen.set_output_callback(on_cd_frame_cb) - - global_counter = 0 # This will track how many events we processed - global_max_t = 0 # This will track the highest timestamp we processed - - # Process events - for evs in mv_iterator: - # Dispatch system events to the window - EventLoop.poll_and_dispatch() - - event_frame_gen.process_events(evs) - - print("----- New event buffer! -----") - if evs.size == 0: - print("The current event buffer is empty.") - else: - min_t = evs['t'][0] # Get the timestamp of the first event of this callback - max_t = evs['t'][-1] # Get the timestamp of the last event of this callback - global_max_t = max_t # Events are ordered by timestamp, so the current last event has the highest timestamp - - counter = evs.size # Local counter - global_counter += counter # Increase global counter - - print(f"There were {counter} events in this event buffer.") - print(f"There were {global_counter} total events up to now.") - print(f"The current event buffer included events from {min_t} to {max_t} microseconds.") - print("----- End of the event buffer! -----") - - if window.should_close(): - break - - # Print the global statistics - duration_seconds = global_max_t / 1.0e6 - print(f"There were {global_counter} events in total.") - print(f"The total duration was {duration_seconds:.2f} seconds.") - if duration_seconds >= 1: # No need to print this statistics if the total duration was too short - print(f"There were {global_counter / duration_seconds :.2f} events per second on average.") - - -if __name__ == "__main__": - main() diff --git a/sdk/modules/core_ml/python/pypkg/metavision_core_ml/event_to_video/gpu_esim.py b/sdk/modules/core_ml/python/pypkg/metavision_core_ml/event_to_video/gpu_esim.py index 87e662038..37e4460b1 100644 --- a/sdk/modules/core_ml/python/pypkg/metavision_core_ml/event_to_video/gpu_esim.py +++ b/sdk/modules/core_ml/python/pypkg/metavision_core_ml/event_to_video/gpu_esim.py @@ -56,7 +56,7 @@ class GPUEBSIM(object): Simulated Events on GPU Args: - dataloader: video-clips datalodaer + dataloader: video-clips dataloader simulator: gpu-simulator batch_times: number of rounds per batch event_volume_depth: number of timesteps per round diff --git a/sdk/modules/core_ml/python/samples/demo_event_to_video/demo_event_to_video.py b/sdk/modules/core_ml/python/samples/demo_event_to_video/demo_event_to_video.py index e5cd7f5b1..80a5d4ea0 100644 --- a/sdk/modules/core_ml/python/samples/demo_event_to_video/demo_event_to_video.py +++ b/sdk/modules/core_ml/python/samples/demo_event_to_video/demo_event_to_video.py @@ -8,7 +8,7 @@ # See the License for the specific language governing permissions and limitations under the License. """ -E2V Demo Script +Event to Video Demo Script """ import numpy as np diff --git a/sdk/modules/core_ml/python/samples/train_event_to_video/train_event_to_video.py b/sdk/modules/core_ml/python/samples/train_event_to_video/train_event_to_video.py index 137328de1..741818fba 100644 --- a/sdk/modules/core_ml/python/samples/train_event_to_video/train_event_to_video.py +++ b/sdk/modules/core_ml/python/samples/train_event_to_video/train_event_to_video.py @@ -8,7 +8,7 @@ # See the License for the specific language governing permissions and limitations under the License. """ -E2V Training Script +Event to Video Training Script """ import torch diff --git a/sdk/modules/core_ml/python/samples/viz_data_event_to_video/viz_data_event_to_video.py b/sdk/modules/core_ml/python/samples/viz_data_event_to_video/viz_data_event_to_video.py index ca404abfd..9ea70ee8f 100644 --- a/sdk/modules/core_ml/python/samples/viz_data_event_to_video/viz_data_event_to_video.py +++ b/sdk/modules/core_ml/python/samples/viz_data_event_to_video/viz_data_event_to_video.py @@ -61,7 +61,7 @@ def main(folder, num_workers=2, batch_size=4, batch_times=4, event_volume_depth= Args: folder (string): folder containing the mp4 videos (and optional _ts.npy timestamps files)/ num_workers (int): number of processes used. - batch_size (int): number of videos loaded simultaenously + batch_size (int): number of videos loaded simultaneously batch_times (int): number of time bins. event_volume_depth (int): number of channels in the event cube. height (int): height of each video in pixels. @@ -74,7 +74,7 @@ def main(folder, num_workers=2, batch_size=4, batch_times=4, event_volume_depth= batch_min_delta_t (int): min duration per batch batch_max_delta_t (int): max duration per batch device (string): either cuda or cpu (must be a valid descriptor for a torch.device) - verbose (boolean): wether to print batch loading times + verbose (boolean): whether to print batch loading times randomize_noises (boolean): add noises """ dataloader = GPUEBSIM.from_params( diff --git a/sdk/modules/stream/cpp/include/metavision/sdk/stream/camera.h b/sdk/modules/stream/cpp/include/metavision/sdk/stream/camera.h index 21cf02307..6e0640992 100644 --- a/sdk/modules/stream/cpp/include/metavision/sdk/stream/camera.h +++ b/sdk/modules/stream/cpp/include/metavision/sdk/stream/camera.h @@ -52,6 +52,9 @@ // Metavision SDK Stream FrameHisto handler class #include "metavision/sdk/stream/frame_histo.h" +// Metavision SDK Stream Monitoring handler class +#include "metavision/sdk/stream/monitoring.h" + // Metavision SDK Stream RAW data handler class #include "metavision/sdk/stream/raw_data.h" @@ -289,6 +292,10 @@ class Camera { /// @throw CameraException if the camera has not been initialized. FrameDiff &frame_diff(); + /// @brief Gets class to handle Monitoring + /// @throw CameraException if the camera has not been initialized. + Monitoring &monitoring(); + /// @brief Registers a callback that will be called when a runtime error occurs /// /// When a camera runtime error occurs, the camera thread is left and events are no longer sent. diff --git a/sdk/modules/stream/cpp/include/metavision/sdk/stream/event_file_reader.h b/sdk/modules/stream/cpp/include/metavision/sdk/stream/event_file_reader.h index be62a2003..04c8fff21 100644 --- a/sdk/modules/stream/cpp/include/metavision/sdk/stream/event_file_reader.h +++ b/sdk/modules/stream/cpp/include/metavision/sdk/stream/event_file_reader.h @@ -19,6 +19,7 @@ #include "metavision/sdk/base/events/event_cd.h" #include "metavision/sdk/base/events/event_erc_counter.h" #include "metavision/sdk/base/events/event_ext_trigger.h" +#include "metavision/sdk/base/events/event_monitoring.h" #include "metavision/sdk/base/events/event_pointcloud.h" #include "metavision/sdk/base/events/raw_event_frame_diff.h" #include "metavision/sdk/base/events/raw_event_frame_histo.h" @@ -69,6 +70,10 @@ class EventFileReader { /// @overload size_t add_read_callback(const EventsBufferReadCallback &cb); + /// @brief Adds a "reading callback" called when a buffer of events has been read + /// @overload + size_t add_read_callback(const EventsBufferReadCallback &cb); + /// @brief Adds a "reading callback" called when a histogram has been read /// @overload size_t add_read_callback(const EventFrameReadCallback &cb); @@ -141,6 +146,7 @@ class EventFileReader { void notify_events_buffer(const EventCD *, const EventCD *); void notify_events_buffer(const EventExtTrigger *, const EventExtTrigger *); void notify_events_buffer(const EventERCCounter *, const EventERCCounter *); + void notify_events_buffer(const EventMonitoring *, const EventMonitoring *); void notify_event_frame(const RawEventFrameHisto &); void notify_event_frame(const RawEventFrameDiff &); void notify_event_frame(const PointCloud &); diff --git a/sdk/modules/stream/cpp/include/metavision/sdk/stream/monitoring.h b/sdk/modules/stream/cpp/include/metavision/sdk/stream/monitoring.h new file mode 100644 index 000000000..99173465b --- /dev/null +++ b/sdk/modules/stream/cpp/include/metavision/sdk/stream/monitoring.h @@ -0,0 +1,64 @@ +/********************************************************************************************************************** + * Copyright (c) Prophesee S.A. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); * + * you may not use this file except in compliance with the License. * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and limitations under the License. * + **********************************************************************************************************************/ + +#ifndef METAVISION_SDK_STREAM_MONITORING_H +#define METAVISION_SDK_STREAM_MONITORING_H + +#include +#include + +// Metavision SDK Base monitoring event +#include "metavision/sdk/base/events/event_monitoring.h" + +// Definition of CallbackId +#include "metavision/sdk/base/utils/callback_id.h" + +namespace Metavision { + +/// @brief Type alias for a callback on a buffer of @ref EventMonitoring +using EventsMonitoringCallback = std::function; + +/// @brief Facility class to handle monitoring events +class Monitoring { +public: + /// @brief Destructor + /// + /// Deletes a Monitoring class instance. + virtual ~Monitoring(); + + /// @brief Subscribes to monitoring events + /// + /// Registers a callback that will be called each time a buffer of EventMonitoring has been decoded. + /// + /// @param cb Callback to call each time a buffer of EventMonitoring has been decoded + /// @sa @ref EventsMonitoringCallback + /// @return ID of the added callback + CallbackId add_callback(const EventsMonitoringCallback &cb); + + /// @brief Removes a previously registered callback + /// @param callback_id Callback ID + /// @return true if the callback has been unregistered correctly, false otherwise. + /// @sa @ref add_callback + bool remove_callback(CallbackId callback_id); + + /// @brief For internal use + class Private; + /// @brief For internal use + Private &get_pimpl(); + +private: + Monitoring(Private *); + std::unique_ptr pimpl_; +}; + +} // namespace Metavision + +#endif // METAVISION_SDK_STREAM_MONITORING_H diff --git a/sdk/modules/stream/cpp/samples/metavision_file_info/metavision_file_info.cpp b/sdk/modules/stream/cpp/samples/metavision_file_info/metavision_file_info.cpp index 052d37af3..1865d8372 100644 --- a/sdk/modules/stream/cpp/samples/metavision_file_info/metavision_file_info.cpp +++ b/sdk/modules/stream/cpp/samples/metavision_file_info/metavision_file_info.cpp @@ -66,6 +66,7 @@ std::string human_readable_time(Metavision::timestamp t) { int main(int argc, char *argv[]) { std::string in_file_path; + bool disable_ts_shifting = false; const std::string program_desc("Application to get information about an event file\n"); @@ -74,6 +75,7 @@ int main(int argc, char *argv[]) { options_desc.add_options() ("help,h", "Produce help message.") ("input-event-file,i", po::value(&in_file_path)->required(), "Path to input event file (RAW, DAT or HDF5).") + ("disable-timestamp-shifting,d", po::bool_switch(&disable_ts_shifting), "Disable shifting all event timestamps in a RAW file to be relative to the timestamp of the first event, preserving their original absolute values") ; // clang-format on @@ -103,6 +105,7 @@ int main(int argc, char *argv[]) { Metavision::Camera camera; try { auto hints = Metavision::FileConfigHints().real_time_playback(false); + hints.set("time_shift", !disable_ts_shifting); camera = Metavision::Camera::from_file(in_file_path, hints); } catch (Metavision::CameraException &e) { MV_LOG_ERROR() << e.what(); diff --git a/sdk/modules/stream/cpp/samples/metavision_file_to_csv/metavision_file_to_csv.cpp b/sdk/modules/stream/cpp/samples/metavision_file_to_csv/metavision_file_to_csv.cpp index 850c5da05..f96a5035e 100644 --- a/sdk/modules/stream/cpp/samples/metavision_file_to_csv/metavision_file_to_csv.cpp +++ b/sdk/modules/stream/cpp/samples/metavision_file_to_csv/metavision_file_to_csv.cpp @@ -10,7 +10,7 @@ **********************************************************************************************************************/ // This code sample demonstrates how to use Metavision SDK Stream to convert an event file -// to a CSV formatted event file. +// to separate CSV files for events and triggers #include #include @@ -22,43 +22,66 @@ class CSVWriter { public: - CSVWriter(std::string &filename) : ofs_(filename) { - if (!ofs_.is_open()) { - MV_LOG_ERROR() << "Unable to write in" << filename; - } - }; - // this function will be associated to the camera callback - void write(const Metavision::EventCD *begin, const Metavision::EventCD *end) { + CSVWriter(const std::string &filename) : filename_(filename) {} + // these functions will be associated to the camera callback + void write_cd(const Metavision::EventCD *begin, const Metavision::EventCD *end) { + ensure_file_opened(); for (const Metavision::EventCD *ev = begin; ev != end; ++ev) { ofs_ << ev->x << "," << ev->y << "," << ev->p << "," << ev->t << "\n"; } } + void write_trigger(const Metavision::EventExtTrigger *begin, const Metavision::EventExtTrigger *end) { + ensure_file_opened(); + for (const Metavision::EventExtTrigger *ev = begin; ev != end; ++ev) { + ofs_ << ev->p << "," << ev->id << "," << ev->t << "\n"; + } + } + + bool is_open() const { + return ofs_.is_open(); + } + private: + void ensure_file_opened() { + if (!ofs_.is_open()) { + ofs_.open(filename_); + if (!ofs_.is_open()) { + MV_LOG_ERROR() << "Unable to write in" << filename_; + } + } + } + std::ofstream ofs_; + std::string filename_; }; namespace po = boost::program_options; int main(int argc, char *argv[]) { std::string event_file_path; - std::string out_file_path; + std::string cd_file_path; + std::string trigger_file_path; + bool disable_ts_shifting = false; const std::string program_desc( - "Code sample demonstrating how to use Metavision SDK Stream to convert a file to a CSV formatted" - " file.\n"); + "Code sample demonstrating how to use Metavision SDK Stream to convert an event file " + "to CSV files for events and triggers.\n"); po::options_description options_desc("Options"); // clang-format off options_desc.add_options() ("help,h", "Produce help message.") ("input-event-file,i", po::value(&event_file_path)->required(), "Path to the input event file.") - ("output-file,o", po::value(&out_file_path)->default_value(""), "Path to the output CSV file.") + ("output-file,o", po::value(&cd_file_path)->default_value(""), + "Path to the output CSV file for CD events. If trigger events are found, this path will be used as the base name for the output trigger CSV file.") + ("disable-timestamp-shifting,d", po::bool_switch(&disable_ts_shifting), "Disable shifting all event timestamps in a RAW file to be relative to the timestamp of the first event, preserving their original absolute values") ; // clang-format on po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(options_desc).run(), vm); + if (vm.count("help")) { MV_LOG_INFO() << program_desc; MV_LOG_INFO() << options_desc; @@ -74,16 +97,18 @@ int main(int argc, char *argv[]) { return 1; } - // get the base of the input filename and the path - if (out_file_path.empty()) { - const std::string output_base = std::regex_replace(event_file_path, std::regex("\\.[^.]*$"), ""); - out_file_path = output_base + ".csv"; + // build the output files paths + if (cd_file_path.empty()) { + cd_file_path = std::filesystem::path(event_file_path).replace_extension(".csv").string(); } + trigger_file_path = std::filesystem::path(cd_file_path).replace_extension().string() + "_triggers.csv"; - // open the file that was passed + // open the input file Metavision::Camera cam; try { - cam = Metavision::Camera::from_file(event_file_path, Metavision::FileConfigHints().real_time_playback(false)); + auto hints = Metavision::FileConfigHints().real_time_playback(false); + hints.set("time_shift", !disable_ts_shifting); + cam = Metavision::Camera::from_file(event_file_path, hints); } catch (Metavision::CameraException &e) { MV_LOG_ERROR() << e.what(); return 1; @@ -92,7 +117,7 @@ int main(int argc, char *argv[]) { // setup feedback to be provided on processing progression using namespace std::chrono_literals; auto log = MV_LOG_INFO() << Metavision::Log::no_space << Metavision::Log::no_endline; - log << "Writing to " << out_file_path << "\n"; + log << "Writing to " << cd_file_path << "\n"; const std::string message("Writing CSV file..."); log << message << std::flush; int dots = 0; @@ -107,11 +132,20 @@ int main(int argc, char *argv[]) { } }; - // to write the events, we add a callback that will be called periodically to give access to the latest events - CSVWriter writer(out_file_path); + // setup writers + CSVWriter cd_writer(cd_file_path); + CSVWriter trigger_writer(trigger_file_path); + + // to write the CD events, we add a callback that will be called periodically to give access to the latest events cam.cd().add_callback([&](const Metavision::EventCD *ev_begin, const Metavision::EventCD *ev_end) { - writer.write(ev_begin, ev_end); progress_feedback_fct(); + cd_writer.write_cd(ev_begin, ev_end); + }); + + // callback for External Trigger events + cam.ext_trigger().add_callback( + [&](const Metavision::EventExtTrigger *ev_begin, const Metavision::EventExtTrigger *ev_end) { + trigger_writer.write_trigger(ev_begin, ev_end); }); cam.start(); @@ -120,7 +154,11 @@ int main(int argc, char *argv[]) { while (cam.is_running()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); }; + log << "\rDone! " << std::endl; + if (trigger_writer.is_open()) { + MV_LOG_INFO() << "Trigger events written to" << trigger_file_path; + }; return 0; } diff --git a/sdk/modules/stream/cpp/src/CMakeLists.txt b/sdk/modules/stream/cpp/src/CMakeLists.txt index 430f10d22..a10d7747a 100644 --- a/sdk/modules/stream/cpp/src/CMakeLists.txt +++ b/sdk/modules/stream/cpp/src/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(metavision_sdk_stream PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/frame_histo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hdf5_event_file_reader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hdf5_event_file_writer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/monitoring.cpp ${CMAKE_CURRENT_SOURCE_DIR}/offline_streaming_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/raw_data.cpp ${CMAKE_CURRENT_SOURCE_DIR}/raw_event_file_logger.cpp diff --git a/sdk/modules/stream/cpp/src/camera.cpp b/sdk/modules/stream/cpp/src/camera.cpp index c7e267824..c12e18916 100644 --- a/sdk/modules/stream/cpp/src/camera.cpp +++ b/sdk/modules/stream/cpp/src/camera.cpp @@ -134,7 +134,7 @@ bool Camera::Private::stop() { try { stop_impl(); } catch (const HalConnectionException &) { - // The implementation (probably in a plugin) reported an error. It is unknown wether the run thread will + // The implementation (probably in a plugin) reported an error. It is unknown whether the run thread will // terminate properly. If we join on it, we may wait forever, but if we don't, the thread remains joinable // and a future call to stop() may wait for the thread to be running while it is already stopped. // Detaching the thread makes it non-joinable, preserving Metavision execution, while preserving the @@ -268,6 +268,14 @@ FrameDiff &Camera::Private::frame_diff() { return *frame_diff_; } +Monitoring &Camera::Private::monitoring() { + check_initialization(); + if (!monitoring_) { + throw CameraException(UnsupportedFeatureErrors::MonitoringUnavailable); + } + return *monitoring_; +} + OfflineStreamingControl &Camera::Private::offline_streaming_control() { throw CameraException(CameraErrorCode::CameraNotInitialized); } @@ -353,6 +361,9 @@ bool Camera::Private::stop_recording_impl(const std::filesystem::path &file_path if (erc_counter_) { erc_counter_->remove_callback(it->second); } + if (monitoring_) { + monitoring_->remove_callback(it->second); + } } return true; } @@ -611,6 +622,10 @@ FrameDiff &Camera::frame_diff() { return pimpl_->frame_diff(); } +Monitoring &Camera::monitoring() { + return pimpl_->monitoring(); +} + CallbackId Camera::add_runtime_error_callback(RuntimeErrorCallback error_callback) { return pimpl_->add_runtime_error_callback(error_callback); } diff --git a/sdk/modules/stream/cpp/src/camera_live.cpp b/sdk/modules/stream/cpp/src/camera_live.cpp index f5e10eadc..75a3745a3 100644 --- a/sdk/modules/stream/cpp/src/camera_live.cpp +++ b/sdk/modules/stream/cpp/src/camera_live.cpp @@ -28,6 +28,7 @@ #include "metavision/sdk/stream/internal/erc_counter_internal.h" #include "metavision/sdk/stream/internal/frame_diff_internal.h" #include "metavision/sdk/stream/internal/frame_histo_internal.h" +#include "metavision/sdk/stream/internal/monitoring_internal.h" #include "metavision/sdk/stream/internal/raw_data_internal.h" namespace Metavision { @@ -265,6 +266,18 @@ void LivePrivate::init() { }); } + I_EventDecoder *i_monitoring_events_decoder = + device_->get_facility>(); + if (i_monitoring_events_decoder) { + monitoring_.reset(Monitoring::Private::build(index_manager_)); + i_monitoring_events_decoder->add_event_buffer_callback( + [this](const EventMonitoring *begin, const EventMonitoring *end) { + for (auto &&cb : monitoring_->get_pimpl().get_cbs()) { + cb(begin, end); + } + }); + } + if (!i_decoder_) { throw CameraException(InternalInitializationErrors::IDecoderNotFound); } diff --git a/sdk/modules/stream/cpp/src/camera_offline_raw.cpp b/sdk/modules/stream/cpp/src/camera_offline_raw.cpp index 7124a01ec..3118f8d0e 100644 --- a/sdk/modules/stream/cpp/src/camera_offline_raw.cpp +++ b/sdk/modules/stream/cpp/src/camera_offline_raw.cpp @@ -28,6 +28,7 @@ #include "metavision/sdk/stream/internal/frame_diff_internal.h" #include "metavision/sdk/stream/internal/frame_histo_internal.h" #include "metavision/sdk/stream/internal/offline_streaming_control_internal.h" +#include "metavision/sdk/stream/internal/monitoring_internal.h" #include "metavision/sdk/stream/internal/raw_data_internal.h" #include "metavision/sdk/stream/raw_event_file_reader.h" @@ -246,6 +247,18 @@ void OfflineRawPrivate::init() { i_decoder_ = i_pointcloud_decoder; } + I_EventDecoder *i_monitoring_events_decoder = + device_->get_facility>(); + if (i_monitoring_events_decoder) { + monitoring_.reset(Monitoring::Private::build(index_manager_)); + i_monitoring_events_decoder->add_event_buffer_callback( + [this](const EventMonitoring *begin, const EventMonitoring *end) { + for (auto &&cb : monitoring_->get_pimpl().get_cbs()) { + cb(begin, end); + } + }); + } + if (!i_decoder_) { throw CameraException(InternalInitializationErrors::IDecoderNotFound); } diff --git a/sdk/modules/stream/cpp/src/event_file_reader.cpp b/sdk/modules/stream/cpp/src/event_file_reader.cpp index acc8c0f6b..43d1ddbbd 100644 --- a/sdk/modules/stream/cpp/src/event_file_reader.cpp +++ b/sdk/modules/stream/cpp/src/event_file_reader.cpp @@ -20,6 +20,7 @@ EventFileReader::Private::Private(EventFileReader &reader, const std::filesystem cd_buffer_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), ext_trigger_buffer_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), erc_counter_buffer_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), + monitoring_buffer_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), histogram_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), diff_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), pointcloud_cb_mgr_(cb_id_mgr_, CallbackTagIds::READ_CALLBACK_TAG_ID), @@ -82,6 +83,13 @@ void EventFileReader::Private::notify_events_buffer(const EventERCCounter *begin } } +void EventFileReader::Private::notify_events_buffer(const EventMonitoring *begin, const EventMonitoring *end) { + auto cbs = monitoring_buffer_cb_mgr_.get_cbs(); + for (auto &cb : cbs) { + cb(begin, end); + } +} + void EventFileReader::Private::notify_event_frame(const RawEventFrameHisto &h) { auto cbs = histogram_cb_mgr_.get_cbs(); for (auto &cb : cbs) { @@ -238,6 +246,10 @@ void EventFileReader::notify_events_buffer(const EventERCCounter *begin, const E return pimpl_->notify_events_buffer(begin, end); } +void EventFileReader::notify_events_buffer(const EventMonitoring *begin, const EventMonitoring *end) { + return pimpl_->notify_events_buffer(begin, end); +} + void EventFileReader::notify_event_frame(const RawEventFrameHisto &h) { return pimpl_->notify_event_frame(h); } diff --git a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_error_code_internal.h b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_error_code_internal.h index f147a10f8..5c2a3cd04 100644 --- a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_error_code_internal.h +++ b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_error_code_internal.h @@ -44,6 +44,7 @@ enum : CameraErrorCodeType { FrameHistoUnavailable = CameraErrorCode::UnsupportedFeature | 0x17, FrameDiffUnavailable = CameraErrorCode::UnsupportedFeature | 0x18, SerializationUnsupported = CameraErrorCode::UnsupportedFeature | 0x19, + MonitoringUnavailable = CameraErrorCode::UnsupportedFeature | 0x20, }; } diff --git a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_internal.h b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_internal.h index 8ac5234c9..1dbcf60e0 100644 --- a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_internal.h +++ b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/camera_internal.h @@ -59,6 +59,7 @@ class Camera::Private { ERCCounter &erc_counter(); FrameHisto &frame_histo(); FrameDiff &frame_diff(); + Monitoring &monitoring(); const CameraGeneration &generation() const; @@ -106,6 +107,7 @@ class Camera::Private { std::unique_ptr erc_counter_; std::unique_ptr frame_histo_; std::unique_ptr frame_diff_; + std::unique_ptr monitoring_; std::unique_ptr raw_data_; std::unique_ptr generation_; diff --git a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/event_file_reader_internal.h b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/event_file_reader_internal.h index 8f451a835..47cc03403 100644 --- a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/event_file_reader_internal.h +++ b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/event_file_reader_internal.h @@ -33,6 +33,7 @@ class EventFileReader::Private { size_t add_read_callback(const EventsBufferReadCallback &cb); size_t add_read_callback(const EventsBufferReadCallback &cb); size_t add_read_callback(const EventsBufferReadCallback &cb); + size_t add_read_callback(const EventsBufferReadCallback &cb); size_t add_read_callback(const EventFrameReadCallback &cb); size_t add_read_callback(const EventFrameReadCallback &cb); size_t add_read_callback(const EventFrameReadCallback &cb); @@ -46,6 +47,7 @@ class EventFileReader::Private { void notify_events_buffer(const EventCD *begin, const EventCD *end); void notify_events_buffer(const EventExtTrigger *begin, const EventExtTrigger *end); void notify_events_buffer(const EventERCCounter *begin, const EventERCCounter *end); + void notify_events_buffer(const EventMonitoring *begin, const EventMonitoring *end); void notify_event_frame(const RawEventFrameHisto &h); void notify_event_frame(const RawEventFrameDiff &d); void notify_event_frame(const PointCloud &pc); @@ -66,6 +68,7 @@ class EventFileReader::Private { CallbackManager, size_t> cd_buffer_cb_mgr_; CallbackManager, size_t> ext_trigger_buffer_cb_mgr_; CallbackManager, size_t> erc_counter_buffer_cb_mgr_; + CallbackManager, size_t> monitoring_buffer_cb_mgr_; CallbackManager, size_t> histogram_cb_mgr_; CallbackManager, size_t> diff_cb_mgr_; CallbackManager, size_t> pointcloud_cb_mgr_; diff --git a/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/monitoring_internal.h b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/monitoring_internal.h new file mode 100644 index 000000000..a70913e55 --- /dev/null +++ b/sdk/modules/stream/cpp/src/include/metavision/sdk/stream/internal/monitoring_internal.h @@ -0,0 +1,36 @@ +/********************************************************************************************************************** + * Copyright (c) Prophesee S.A. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); * + * you may not use this file except in compliance with the License. * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and limitations under the License. * + **********************************************************************************************************************/ + +#ifndef METAVISION_SDK_STREAM_MONITORING_INTERNAL_H +#define METAVISION_SDK_STREAM_MONITORING_INTERNAL_H + +#include +#include +#include + +#include "metavision/sdk/core/utils/callback_manager.h" + +namespace Metavision { + +class IndexGenerator; + +class Monitoring::Private : public CallbackManager { +public: + Private(IndexManager &index_manager); + + virtual ~Private(); + + static Monitoring *build(IndexManager &index_manager); +}; + +} // namespace Metavision + +#endif // METAVISION_SDK_STREAM_MONITORING_INTERNAL_H diff --git a/sdk/modules/stream/cpp/src/monitoring.cpp b/sdk/modules/stream/cpp/src/monitoring.cpp new file mode 100644 index 000000000..6f7f43950 --- /dev/null +++ b/sdk/modules/stream/cpp/src/monitoring.cpp @@ -0,0 +1,45 @@ +/********************************************************************************************************************** + * Copyright (c) Prophesee S.A. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); * + * you may not use this file except in compliance with the License. * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and limitations under the License. * + **********************************************************************************************************************/ + +#include "metavision/sdk/stream/monitoring.h" + +#include "metavision/sdk/stream/internal/monitoring_internal.h" +#include "metavision/sdk/core/utils/index_manager.h" +#include "metavision/sdk/stream/internal/callback_tag_ids.h" + +namespace Metavision { + +Monitoring *Monitoring::Private::build(IndexManager &index_manager) { + return new Monitoring(new Private(index_manager)); +} + +Monitoring::Private::Private(IndexManager &index_manager) : + CallbackManager(index_manager, CallbackTagIds::DECODE_CALLBACK_TAG_ID) {} + +Monitoring::Private::~Private() {} + +Monitoring::~Monitoring() {} + +CallbackId Monitoring::add_callback(const EventsMonitoringCallback &cb) { + return pimpl_->add_callback(cb); +} + +bool Monitoring::remove_callback(CallbackId callback_id) { + return pimpl_->remove_callback(callback_id); +} + +Monitoring::Private &Monitoring::get_pimpl() { + return *pimpl_; +} + +Monitoring::Monitoring(Private *pimpl) : pimpl_(pimpl) {} + +} // namespace Metavision diff --git a/sdk/modules/stream/cpp/src/raw_event_file_reader.cpp b/sdk/modules/stream/cpp/src/raw_event_file_reader.cpp index 7e3eb925c..0679a7ae6 100644 --- a/sdk/modules/stream/cpp/src/raw_event_file_reader.cpp +++ b/sdk/modules/stream/cpp/src/raw_event_file_reader.cpp @@ -52,6 +52,15 @@ class RAWEventFileReader::Private { }); } + I_EventDecoder *i_monitoring_events_decoder = + device.get_facility>(); + if (i_monitoring_events_decoder) { + i_monitoring_events_decoder->add_event_buffer_callback( + [this](const EventMonitoring *begin, const EventMonitoring *end) { + reader_.notify_events_buffer(begin, end); + }); + } + auto i_histogram_decoder = device.get_facility>(); if (i_histogram_decoder) { i_histogram_decoder->add_event_frame_callback( diff --git a/sdk/modules/stream/python/samples/CMakeLists.txt b/sdk/modules/stream/python/samples/CMakeLists.txt index f14eb36e1..73eec523e 100644 --- a/sdk/modules/stream/python/samples/CMakeLists.txt +++ b/sdk/modules/stream/python/samples/CMakeLists.txt @@ -9,4 +9,5 @@ add_subdirectory(metavision_camera_stream_slicer) add_subdirectory(metavision_raw_evt_encoder) +add_subdirectory(metavision_sdk_get_started) add_subdirectory(metavision_synced_camera_streams_slicer) diff --git a/sdk/modules/core/python/samples/metavision_sdk_get_started/CMakeLists.txt b/sdk/modules/stream/python/samples/metavision_sdk_get_started/CMakeLists.txt similarity index 100% rename from sdk/modules/core/python/samples/metavision_sdk_get_started/CMakeLists.txt rename to sdk/modules/stream/python/samples/metavision_sdk_get_started/CMakeLists.txt diff --git a/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started.py b/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started.py new file mode 100644 index 000000000..7b66fc554 --- /dev/null +++ b/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started.py @@ -0,0 +1,91 @@ +# Copyright (c) Prophesee S.A. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. + +""" +Metavision SDK Get Started. +""" + + +import numpy as np + +from metavision_sdk_stream import Camera, CameraStreamSlicer +from metavision_sdk_core import BaseFrameGenerationAlgorithm +from metavision_sdk_ui import MTWindow, BaseWindow, EventLoop, UIAction, UIKeyEvent + + +def parse_args(): + import argparse + """Parse command line arguments.""" + parser = argparse.ArgumentParser(description='Metavision SDK Get Started sample.', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + '-i', '--input-event-file', + help="Path to input event file (RAW or HDF5). If not specified, the camera live stream is used.") + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + + if args.input_event_file: + camera = Camera.from_file(args.input_event_file) + else: + camera = Camera.from_first_available() + + global_counter = 0 # This will track how many events we processed + global_max_t = 0 # This will track the highest timestamp we processed + + slicer = CameraStreamSlicer(camera.move()) + width = slicer.camera().width() + height = slicer.camera().height() + frame = np.zeros((height, width, 3), np.uint8) + + with MTWindow(title="Metavision SDK Get Started", width=width, height=height, + mode=BaseWindow.RenderMode.BGR) as window: + def keyboard_cb(key, scancode, action, mods): + if key == UIKeyEvent.KEY_ESCAPE or key == UIKeyEvent.KEY_Q: + window.set_close_flag() + + window.set_keyboard_callback(keyboard_cb) + + for slice in slicer: + + print("----- New event slice! -----") + if slice.events.size == 0: + print("The current event slice is empty.") + else: + min_t = slice.events['t'][0] # Get the timestamp of the first event of this slice + max_t = slice.events['t'][-1] # Get the timestamp of the last event of this callback + global_max_t = max_t # Events are ordered by timestamp, so the current last event has the highest timestamp + + counter = slice.events.size # Local counter + global_counter += counter # Increase global counter + + print(f"There were {counter} events in this event slice.") + print(f"There were {global_counter} total events up to now.") + print(f"The current event slice included events from {min_t} to {max_t} microseconds.") + print("----- End of the event slice! -----") + + EventLoop.poll_and_dispatch() + BaseFrameGenerationAlgorithm.generate_frame(slice.events, frame) + window.show_async(frame) + + if window.should_close(): + break + + # Print the global statistics + duration_seconds = global_max_t / 1.0e6 + print(f"There were {global_counter} events in total.") + print(f"The total duration was {duration_seconds:.2f} seconds.") + if duration_seconds >= 1: # No need to print this statistics if the total duration was too short + print(f"There were {global_counter / duration_seconds :.2f} events per second on average.") + +if __name__ == "__main__": + main() diff --git a/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v1.py b/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v1.py similarity index 72% rename from sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v1.py rename to sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v1.py index 7a7fcaaa7..10b4ee886 100644 --- a/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v1.py +++ b/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v1.py @@ -12,7 +12,7 @@ """ -from metavision_core.event_io import EventsIterator +from metavision_sdk_stream import Camera, CameraStreamSlicer def parse_args(): @@ -21,23 +21,23 @@ def parse_args(): parser = argparse.ArgumentParser(description='Metavision SDK Get Started sample.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( - '-i', '--input-event-file', dest='event_file_path', default="", - help="Path to input event file (RAW or HDF5). If not specified, the camera live stream is used. " - "If it's a camera serial number, it will try to open that camera instead.") + '-i', '--input-event-file', + help="Path to input event file (RAW or HDF5). If not specified, the camera live stream is used.") args = parser.parse_args() return args def main(): - """ Main """ args = parse_args() - # Events iterator on Camera or event file - mv_iterator = EventsIterator(input_path=args.event_file_path, delta_t=1000) + if args.input_event_file: + camera = Camera.from_file(args.input_event_file) + else: + camera = Camera.from_first_available() - for evs in mv_iterator: + slicer = CameraStreamSlicer(camera.move()) + for _ in slicer: print("Events are available!") - if __name__ == "__main__": main() diff --git a/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v2.py b/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v2.py similarity index 64% rename from sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v2.py rename to sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v2.py index 1850fdcd8..36047cfaa 100644 --- a/sdk/modules/core/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v2.py +++ b/sdk/modules/stream/python/samples/metavision_sdk_get_started/metavision_sdk_get_started_v2.py @@ -12,7 +12,7 @@ """ -from metavision_core.event_io import EventsIterator +from metavision_sdk_stream import Camera, CameraStreamSlicer def parse_args(): @@ -21,40 +21,41 @@ def parse_args(): parser = argparse.ArgumentParser(description='Metavision SDK Get Started sample.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( - '-i', '--input-event-file', dest='event_file_path', default="", - help="Path to input event file (RAW or HDF5). If not specified, the camera live stream is used. " - "If it's a camera serial number, it will try to open that camera instead.") + '-i', '--input-event-file', + help="Path to input event file (RAW or HDF5). If not specified, the camera live stream is used.") args = parser.parse_args() return args def main(): - """ Main """ args = parse_args() - # Events iterator on Camera or event file - mv_iterator = EventsIterator(input_path=args.event_file_path, delta_t=1000) + if args.input_event_file: + camera = Camera.from_file(args.input_event_file) + else: + camera = Camera.from_first_available() global_counter = 0 # This will track how many events we processed global_max_t = 0 # This will track the highest timestamp we processed - # Process events - for evs in mv_iterator: - print("----- New event buffer! -----") - if evs.size == 0: - print("The current event buffer is empty.") + slicer = CameraStreamSlicer(camera.move()) + for slice in slicer: + print("----- New event slice! -----") + if slice.events.size == 0: + print("The current event slice is empty.") else: - min_t = evs['t'][0] # Get the timestamp of the first event of this callback - max_t = evs['t'][-1] # Get the timestamp of the last event of this callback + min_t = slice.events['t'][0] # Get the timestamp of the first event of this slice + max_t = slice.events['t'][-1] # Get the timestamp of the last event of this callback global_max_t = max_t # Events are ordered by timestamp, so the current last event has the highest timestamp - counter = evs.size # Local counter + counter = slice.events.size # Local counter global_counter += counter # Increase global counter - print(f"There were {counter} events in this event buffer.") + print(f"There were {counter} events in this event slice.") print(f"There were {global_counter} total events up to now.") - print(f"The current event buffer included events from {min_t} to {max_t} microseconds.") - print("----- End of the event buffer! -----") + print(f"The current event slice included events from {min_t} to {max_t} microseconds.") + print("----- End of the event slice! -----") + # Print the global statistics duration_seconds = global_max_t / 1.0e6 @@ -63,6 +64,5 @@ def main(): if duration_seconds >= 1: # No need to print this statistics if the total duration was too short print(f"There were {global_counter / duration_seconds :.2f} events per second on average.") - if __name__ == "__main__": main()