diff --git a/.gitattributes b/.gitattributes
index f53b7af..cb44273 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,6 @@
+# Ignore Python files in linguist
+*.py linguist-detectable=false
+
# Images
*.gif filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
@@ -19,6 +22,7 @@
# ROS Bags
**/resources/**/*.db3 filter=lfs diff=lfs merge=lfs -text
**/resources/**/*.yaml filter=lfs diff=lfs merge=lfs -text
+**/resources/**/*.yaml filter=lfs diff=lfs merge=lfs -text
# DNN Model files
-*.onnx filter=lfs diff=lfs merge=lfs -text
\ No newline at end of file
+*.onnx filter=lfs diff=lfs merge=lfs -text
diff --git a/README.md b/README.md
index 9baad94..43844d8 100644
--- a/README.md
+++ b/README.md
@@ -5,36 +5,41 @@ DNN Stereo Disparity includes packages for predicting disparity of stereo input.

---
+
## Webinar Available
-Learn how to use this package by watching our on-demand webinar: [Using ML Models in ROS2 to Robustly Estimate Distance to Obstacles](https://gateway.on24.com/wcc/experience/elitenvidiabrill/1407606/3998202/isaac-ros-webinar-series)
+
+Learn how to use this package by watching our on-demand webinar: [Using ML Models in ROS 2 to Robustly Estimate Distance to Obstacles](https://gateway.on24.com/wcc/experience/elitenvidiabrill/1407606/3998202/isaac-ros-webinar-series)
---
## Overview
-This repository provides an NVIDIA hardware-accelerated package for DNN-based stereo disparity. Stereo disparity (with additional processing) can produce a depth image or point cloud of a scene for robot navigation. The `isaac_ros_ess` package uses the [ESS](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/isaac/models/dnn_stereo_disparity) DNN to perform stereo depth estimation via continuous disparity prediction. Given a pair of stereo input images, the package generates a disparity map of the left input image.
+Isaac ROS DNN Disparity provides a GPU-accelerated package for DNN-based stereo disparity. Stereo disparity is calculated from a time-synchronized image pair sourced from a stereo camera and is used to produce a depth image or a point cloud of a scene. The `isaac_ros_ess` package uses the [ESS DNN model](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/isaac/models/dnn_stereo_disparity) to perform stereo depth estimation via continuous disparity prediction. Given a pair of stereo input images, the package generates a disparity map of the left input image.
+
+
-> Check your requirements against package [input limitations](#input-restrictions).
+ESS is used in a graph of nodes to provide a disparity prediction from an input left and right stereo image pair. Images to ESS need to be rectified and resized to the appropriate input resolution. The aspect ratio of the image needs to be maintained, so the image may need to be cropped and resized to maintain the input aspect ratio. The graph for DNN encode, to DNN inference, to DNN decode is part of the ESS node. Inference is performed using TensorRT, as the ESS DNN model is designed to use optimizations supported by TensorRT.
### ESS DNN
-[ESS](https://arxiv.org/pdf/1803.09719.pdf) stands for Enhanced Semi-Supervised stereo disparity DNN, which was developed by NVIDIA. The ESS DNN is used to predict the disparity for each pixel from stereo camera image pairs. This network has improvements over classic CV approaches that use epi-polar geometry to compute disparity, as the DNN can learn to predict disparity in cases where epi-polar geometry feature matching fails. The semi-supervised learning and stereo disparity matching makes the DNN robust to environment that is unseen in the training datasets and occluded objects. This DNN is optimized for and evaluated with RGB global shutter stereo camera images, and accuracy may vary with monochrome images.
+[ESS](https://arxiv.org/pdf/1803.09719.pdf) stands for Enhanced Semi-Supervised stereo disparity, developed by NVIDIA. The ESS DNN is used to predict the disparity for each pixel from stereo camera image pairs. This network has improvements over classic CV approaches that use epipolar geometry to compute disparity, as the DNN can learn to predict disparity in cases where epipolar geometry feature matching fails. The semi-supervised learning and stereo disparity matching makes the ESS DNN robust in environments unseen in the training datasets and with occluded objects. This DNN is optimized for and evaluated with color (RGB) global shutter stereo camera images, and accuracy may vary with monochrome stereo images used in analytic computer vision approaches to stereo disparity.
The predicted [disparity](https://en.wikipedia.org/wiki/Binocular_disparity) values represent the distance a point moves from one image to the other in a stereo image pair (a.k.a. the binocular image pair). The disparity is inversely proportional to the depth (i.e. `disparity = focalLength x baseline / depth`). Given the [focal length](https://en.wikipedia.org/wiki/Focal_length) and [baseline](https://en.wikipedia.org/wiki/Stereo_camera) of the camera that generates a stereo image pair, the predicted disparity map from the `isaac_ros_ess` package can be used to compute depth and generate a [point cloud](https://en.wikipedia.org/wiki/Point_cloud).
+> **Note**: Compare the requirements of your use case against the package [input limitations](#input-restrictions).
+
### Isaac ROS NITROS Acceleration
This package is powered by [NVIDIA Isaac Transport for ROS (NITROS)](https://developer.nvidia.com/blog/improve-perception-performance-for-ros-2-applications-with-nvidia-isaac-transport-for-ros/), which leverages type adaptation and negotiation to optimize message formats and dramatically accelerate communication between participating nodes.
## Performance
-The following are the benchmark performance results of the prepared pipelines in this package, by supported platform:
-
-| Pipeline | AGX Orin | Orin Nano | x86_64 w/ RTX 3060 Ti |
-| -------------------------- | ------------------ | ---------------- | --------------------- |
-| ESS Disparity Node (1080p) | 51 fps
17.3ms | 16 fps
60ms | 98 fps
7.6ms |
+The following table summarizes the per-platform performance statistics of sample graphs that use this package, with links included to the full benchmark output. These benchmark configurations are taken from the [Isaac ROS Benchmark](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark#list-of-isaac-ros-benchmarks) collection, based on the [`ros2_benchmark`](https://github.com/NVIDIA-ISAAC-ROS/ros2_benchmark) framework.
-These data have been collected per the methodology described [here](https://github.com/NVIDIA-ISAAC-ROS/.github/blob/main/profile/performance-summary.md#methodology).
+| Sample Graph | Input Size | AGX Orin | Orin NX | x86_64 w/ RTX 3060 Ti |
+| --------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [DNN Stereo Disparity Node](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/scripts//isaac_ros_ess_node.py) | 1080p | [63.6 fps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/results/isaac_ros_ess_node-agx_orin.json)
2.6 ms | [24.5 fps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/results/isaac_ros_ess_node-orin_nx.json)
3.0 ms | [131 fps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/results/isaac_ros_ess_node-x86_64_rtx_3060Ti.json)
0.73 ms |
+| [DNN Stereo Disparity Graph](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/scripts//isaac_ros_ess_graph.py) | 1080p | [52.7 fps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/results/isaac_ros_ess_graph-agx_orin.json)
20 ms | [20.8 fps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/results/isaac_ros_ess_graph-orin_nx.json)
50 ms | [116 fps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_benchmark/blob/main/results/isaac_ros_ess_graph-x86_64_rtx_3060Ti.json)
8.7 ms |
## Table of Contents
@@ -76,24 +81,24 @@ These data have been collected per the methodology described [here](https://gith
## Latest Update
-Update 2022-10-19: Updated OSS licensing
+Update 2023-04-05: Source available GXF extensions
## Supported Platforms
-This package is designed and tested to be compatible with ROS2 Humble running on [Jetson](https://developer.nvidia.com/embedded-computing) or an x86_64 system with an NVIDIA GPU.
+This package is designed and tested to be compatible with ROS 2 Humble running on [Jetson](https://developer.nvidia.com/embedded-computing) or an x86_64 system with an NVIDIA GPU.
-> **Note**: Versions of ROS2 earlier than Humble are **not** supported. This package depends on specific ROS2 implementation features that were only introduced beginning with the Humble release.
+> **Note**: Versions of ROS 2 earlier than Humble are **not** supported. This package depends on specific ROS 2 implementation features that were only introduced beginning with the Humble release.
-| Platform | Hardware | Software | Notes |
-| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| Jetson | [AGX Orin](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/)
[Orin Nano](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-agx-xavier/) | [JetPack 5.0.2](https://developer.nvidia.com/embedded/jetpack) | For best performance, ensure that [power settings](https://docs.nvidia.com/jetson/archives/r34.1/DeveloperGuide/text/SD/PlatformPowerAndPerformance.html) are configured appropriately. |
-| x86_64 | NVIDIA GPU | [Ubuntu 20.04+](https://releases.ubuntu.com/20.04/)
[CUDA 11.6.1+](https://developer.nvidia.com/cuda-downloads) |
+| Platform | Hardware | Software | Notes |
+| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Jetson | [AGX Orin](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/)
[Orin Nano](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-agx-xavier/) | [JetPack 5.1.1](https://developer.nvidia.com/embedded/jetpack) | For best performance, ensure that [power settings](https://docs.nvidia.com/jetson/archives/r34.1/DeveloperGuide/text/SD/PlatformPowerAndPerformance.html) are configured appropriately. |
+| x86_64 | NVIDIA GPU | [Ubuntu 20.04+](https://releases.ubuntu.com/20.04/)
[CUDA 11.8+](https://developer.nvidia.com/cuda-downloads) |
### Docker
To simplify development, we strongly recommend leveraging the Isaac ROS Dev Docker images by following [these steps](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_common/blob/main/docs/dev-env-setup.md). This will streamline your development environment setup with the correct versions of dependencies on both Jetson and x86_64 platforms.
-> **Note:** All Isaac ROS quick start guides, tutorials, and examples have been designed with the Isaac ROS Docker images as a prerequisite.
+> **Note**: All Isaac ROS quick start guides, tutorials, and examples have been designed with the Isaac ROS Docker images as a prerequisite.
## Quickstart
@@ -297,6 +302,7 @@ Make sure that the ROS bag has a reasonable size and publish rate.
| Date | Changes |
| ---------- | ------------------------------------------ |
+| 2023-04-05 | Source available GXF extensions |
| 2022-10-19 | Updated OSS licensing |
| 2022-08-31 | Update to be compatible with JetPack 5.0.2 |
| 2022-06-30 | Initial release |
diff --git a/docs/tutorial-ess-realsense.md b/docs/tutorial-ess-realsense.md
index 9cff5e3..cf6afbf 100644
--- a/docs/tutorial-ess-realsense.md
+++ b/docs/tutorial-ess-realsense.md
@@ -6,7 +6,7 @@
This tutorial demonstrates how to perform stereo-camera-based reconstruction using a [RealSense](https://www.intel.com/content/www/us/en/architecture-and-technology/realsense-overview.html) camera and [isaac_ros_ess](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_dnn_stereo_disparity).
-> Note: This tutorial has been tested with a RealSense D455/D435 camera connected to a Jetson Xavier AGX, as well as an x86 PC with an NVIDIA graphics card.
+> **Note**: This tutorial requires a compatible RealSense camera from the list available [here](https://github.com/NVIDIA-ISAAC-ROS/.github/blob/main/profile/realsense-setup.md#camera-compatibility).
## Tutorial Walkthrough
diff --git a/docs/tutorial-isaac-sim.md b/docs/tutorial-isaac-sim.md
index 791b716..675bc76 100644
--- a/docs/tutorial-isaac-sim.md
+++ b/docs/tutorial-isaac-sim.md
@@ -4,22 +4,24 @@
## Overview
-This tutorial walks you through a pipeline to [estimate depth](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_dnn_stereo_disparity) with stereo images from Isaac Sim.
+This tutorial walks you through a graph to [estimate depth](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_dnn_stereo_disparity) with stereo images from Isaac Sim.
+
+Last validated with [Isaac Sim 2022.2.1](https://docs.omniverse.nvidia.com/app_isaacsim/app_isaacsim/release_notes.html#id1)
## Tutorial Walkthrough
1. Complete steps 1-7 listed in the [Quickstart section](../README.md#quickstart) of the main README.
2. Install and launch Isaac Sim following the steps in the [Isaac ROS Isaac Sim Setup Guide](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_common/blob/main/docs/isaac-sim-sil-setup.md)
-3. Open the Isaac ROS Common USD scene (using the **Content** window) located at:
+3. Open the Isaac ROS Common USD scene (using the *Content* tab) located at:
- `omniverse://localhost/NVIDIA/Assets/Isaac/2022.1/Isaac/Samples/ROS2/Scenario/carter_warehouse_apriltags_worker.usd`.
+ ```text
+ http://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/2022.2.1/Isaac/Samples/ROS2/Scenario/carter_warehouse_apriltags_worker.usd
+ ```
Wait for the scene to load completely.
- > **Note:** To use a different server, replace `localhost` with ``
-4. Go to the **Stage** tab and select `/World/Carter_ROS/ROS_Cameras/ros2_create_camera_right_info`. In the **Property** tab, locate the **Compute Node -> Inputs -> stereoOffset -> X** value and change it from `0` to `-175.92`.
+4. Go to the *Stage* tab and select `/World/Carter_ROS/ROS_Cameras/ros2_create_camera_right_info`, then in *Property* tab *-> OmniGraph Node -> Inputs -> stereoOffset X* change `0` to `-175.92`.

-
-5. Enable the right camera for a stereo image pair. Go to the **Stage** tab and select `/World/Carter_ROS/ROS_Cameras/enable_camera_right`, then tick the **Condition** checkbox.
+5. Enable the right camera for a stereo image pair. Go to the *Stage* tab and select `/World/Carter_ROS/ROS_Cameras/enable_camera_right`, then tick the *Condition* checkbox.

6. Press **Play** to start publishing data from the Isaac Sim application.

diff --git a/isaac_ros_ess/CMakeLists.txt b/isaac_ros_ess/CMakeLists.txt
index c12cfbb..1ab88da 100644
--- a/isaac_ros_ess/CMakeLists.txt
+++ b/isaac_ros_ess/CMakeLists.txt
@@ -1,5 +1,5 @@
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
-# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,54 +15,31 @@
#
# SPDX-License-Identifier: Apache-2.0
-cmake_minimum_required(VERSION 3.8)
+cmake_minimum_required(VERSION 3.23.2)
project(isaac_ros_ess LANGUAGES C CXX)
-
-# Default to C++17
-if(NOT CMAKE_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD 17)
-endif()
-
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
-# Default to Release build
-if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
- set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
-endif()
-message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
-
-execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
-message(STATUS "Architecture: ${ARCHITECTURE}")
-
find_package(ament_cmake_auto REQUIRED)
ament_auto_find_build_dependencies()
-
# isaac_ros_ess_node
ament_auto_add_library(isaac_ros_ess_node SHARED src/ess_disparity_node.cpp)
-target_compile_definitions(isaac_ros_ess_node
- PRIVATE "COMPOSITION_BUILDING_DLL"
-)
target_link_libraries(isaac_ros_ess_node)
rclcpp_components_register_nodes(isaac_ros_ess_node "nvidia::isaac_ros::dnn_stereo_disparity::ESSDisparityNode")
set(node_plugins "${node_plugins}nvidia::isaac_ros::dnn_stereo_disparity::ESSDisparityNode;$\n")
-# Install visualizer python scripts
+### Install ESS extension built from source
-install(PROGRAMS
- scripts/isaac_ros_ess_visualizer.py
- DESTINATION lib/${PROJECT_NAME}
-)
+add_subdirectory(gxf/ess)
+install(TARGETS gxf_cvcore_ess DESTINATION share/${PROJECT_NAME}/gxf/lib/ess)
-# Install package executable
-install(TARGETS isaac_ros_ess_node
- ARCHIVE DESTINATION lib
- LIBRARY DESTINATION lib
- RUNTIME DESTINATION bin
-)
+### End extensions
+
+# Install visualizer python scripts
+install(PROGRAMS scripts/isaac_ros_ess_visualizer.py DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
diff --git a/isaac_ros_ess/config/isaac_ros_ess_hawk.rviz b/isaac_ros_ess/config/isaac_ros_ess_hawk.rviz
new file mode 100644
index 0000000..d074741
--- /dev/null
+++ b/isaac_ros_ess/config/isaac_ros_ess_hawk.rviz
@@ -0,0 +1,212 @@
+Panels:
+ - Class: rviz_common/Displays
+ Help Height: 78
+ Name: Displays
+ Property Tree Widget:
+ Expanded:
+ - /Global Options1
+ - /Status1
+ - /PointCloud21
+ Splitter Ratio: 0.5
+ Tree Height: 220
+ - Class: rviz_common/Selection
+ Name: Selection
+ - Class: rviz_common/Tool Properties
+ Expanded:
+ - /2D Goal Pose1
+ - /Publish Point1
+ Name: Tool Properties
+ Splitter Ratio: 0.5886790156364441
+ - Class: rviz_common/Views
+ Expanded:
+ - /Current View1
+ Name: Views
+ Splitter Ratio: 0.5
+ - Class: rviz_common/Time
+ Experimental: false
+ Name: Time
+ SyncMode: 0
+ SyncSource: PointCloud2
+Visualization Manager:
+ Class: ""
+ Displays:
+ - Alpha: 0.5
+ Cell Size: 1
+ Class: rviz_default_plugins/Grid
+ Color: 160; 160; 164
+ Enabled: true
+ Line Style:
+ Line Width: 0.029999999329447746
+ Value: Lines
+ Name: Grid
+ Normal Cell Count: 0
+ Offset:
+ X: 0
+ Y: 0
+ Z: 0
+ Plane: XY
+ Plane Cell Count: 10
+ Reference Frame:
+ Value: true
+ - Class: rviz_default_plugins/Image
+ Enabled: false
+ Max Value: 1
+ Median window: 5
+ Min Value: 0
+ Name: Image
+ Normalize Range: true
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /left/image_raw
+ Value: false
+ - Class: rviz_default_plugins/Image
+ Enabled: true
+ Max Value: 1
+ Median window: 5
+ Min Value: 0
+ Name: Image
+ Normalize Range: true
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /left/image_rect
+ Value: true
+ - Class: rviz_default_plugins/Image
+ Enabled: true
+ Max Value: 1
+ Median window: 5
+ Min Value: 0
+ Name: Image
+ Normalize Range: true
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /right/image_rect
+ Value: true
+ - Alpha: 1
+ Autocompute Intensity Bounds: true
+ Autocompute Value Bounds:
+ Max Value: 10
+ Min Value: -10
+ Value: true
+ Axis: Z
+ Channel Name: intensity
+ Class: rviz_default_plugins/PointCloud2
+ Color: 255; 255; 255
+ Color Transformer: Intensity
+ Decay Time: 0
+ Enabled: true
+ Invert Rainbow: false
+ Max Color: 255; 255; 255
+ Max Intensity: 4096
+ Min Color: 0; 0; 0
+ Min Intensity: 0
+ Name: PointCloud2
+ Position Transformer: XYZ
+ Selectable: true
+ Size (Pixels): 3
+ Size (m): 0.0010000000474974513
+ Style: Flat Squares
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ Filter size: 10
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /points2
+ Use Fixed Frame: true
+ Use rainbow: true
+ Value: true
+ Enabled: true
+ Global Options:
+ Background Color: 48; 48; 48
+ Fixed Frame: left/image_rect
+ Frame Rate: 30
+ Name: root
+ Tools:
+ - Class: rviz_default_plugins/Interact
+ Hide Inactive Objects: true
+ - Class: rviz_default_plugins/MoveCamera
+ - Class: rviz_default_plugins/Select
+ - Class: rviz_default_plugins/FocusCamera
+ - Class: rviz_default_plugins/Measure
+ Line color: 128; 128; 0
+ - Class: rviz_default_plugins/SetInitialPose
+ Covariance x: 0.25
+ Covariance y: 0.25
+ Covariance yaw: 0.06853891909122467
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /initialpose
+ - Class: rviz_default_plugins/SetGoal
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /goal_pose
+ - Class: rviz_default_plugins/PublishPoint
+ Single click: true
+ Topic:
+ Depth: 5
+ Durability Policy: Volatile
+ History Policy: Keep Last
+ Reliability Policy: Reliable
+ Value: /clicked_point
+ Transformation:
+ Current:
+ Class: rviz_default_plugins/TF
+ Value: true
+ Views:
+ Current:
+ Class: rviz_default_plugins/Orbit
+ Distance: 10
+ Enable Stereo Rendering:
+ Stereo Eye Separation: 0.05999999865889549
+ Stereo Focal Distance: 1
+ Swap Stereo Eyes: false
+ Value: false
+ Focal Point:
+ X: 0
+ Y: 0
+ Z: 0
+ Focal Shape Fixed Size: true
+ Focal Shape Size: 0.05000000074505806
+ Invert Z Axis: false
+ Name: Current View
+ Near Clip Distance: 0.009999999776482582
+ Pitch: -0.6146020889282227
+ Target Frame:
+ Value: Orbit (rviz)
+ Yaw: 3.9685781002044678
+ Saved: ~
+Window Geometry:
+ Displays:
+ collapsed: false
+ Height: 1136
+ Hide Left Dock: false
+ Hide Right Dock: false
+ Image:
+ collapsed: false
+ QMainWindow State: 000000ff00000000fd000000040000000000000156000003d6fc020000000bfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073000000003b00000165000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d0061006700650000000233000000bc0000002800fffffffb0000000a0049006d006100670065010000003b000001980000002800fffffffb0000000a0049006d00610067006501000001d9000002380000002800ffffff000000010000010f000002b4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003b000002b4000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007380000003efc0100000002fb0000000800540069006d00650100000000000007380000024400fffffffb0000000800540069006d00650100000000000004500000000000000000000005dc000003d600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
+ Selection:
+ collapsed: false
+ Time:
+ collapsed: false
+ Tool Properties:
+ collapsed: false
+ Views:
+ collapsed: false
+ Width: 1848
+ X: 72
+ Y: 27
diff --git a/isaac_ros_ess/gxf/AMENT_IGNORE b/isaac_ros_ess/gxf/AMENT_IGNORE
new file mode 100644
index 0000000..e69de29
diff --git a/isaac_ros_ess/gxf/ess/3dv/include/cv/ess/ESS.h b/isaac_ros_ess/gxf/ess/3dv/include/cv/ess/ESS.h
new file mode 100644
index 0000000..277165d
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/3dv/include/cv/ess/ESS.h
@@ -0,0 +1,203 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef NV_ESS_H_
+#define NV_ESS_H_
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace cvcore { namespace ess {
+
+/**
+ * Describes the algorithm supported for ESS Preprocessing
+ */
+enum class PreProcessType : uint8_t
+{
+ RESIZE = 0, // Resize to network dimensions without maintaining aspect ratio
+ CENTER_CROP // Crop to network dimensions from center of image
+};
+
+/**
+ * Describes the parameters for ESS Preprocessing
+ */
+struct ESSPreProcessorParams
+{
+ /* Preprocessing steps for ESS */
+ PreProcessType preProcessType;
+};
+
+/**
+ * Default parameters for the preprocessing pipeline.
+ */
+CVCORE_API extern const ImagePreProcessingParams defaultPreProcessorParams;
+
+/**
+ * Default parameters to describe the input expected for the model.
+ */
+CVCORE_API extern const ModelInputParams defaultModelInputParams;
+
+/**
+ * Default parameters to describe the model inference parameters.
+ */
+CVCORE_API extern const ModelInferenceParams defaultInferenceParams;
+
+/**
+ * Default parameters for the ESS Preprocessing
+ */
+CVCORE_API extern const ESSPreProcessorParams defaultESSPreProcessorParams;
+
+/*
+ * Interface for running pre-processing on ESS model.
+ */
+class CVCORE_API ESSPreProcessor
+{
+public:
+ /**
+ * Default constructor is deleted
+ */
+ ESSPreProcessor() = delete;
+
+ /**
+ * Constructor of ESSPreProcessor.
+ * @param preProcessorParams image pre-processing parameters.
+ * @param modelInputParams model paramters for network.
+ * @param essPreProcessorParams paramaters specific for ess preprocessing.
+ */
+ ESSPreProcessor(const ImagePreProcessingParams &preProcessorParams, const ModelInputParams &modelInputParams,
+ const ESSPreProcessorParams &essPreProcessorParams);
+
+ /**
+ * Destructor of ESSPreProcessor.
+ */
+ ~ESSPreProcessor();
+
+ /**
+ * Main interface to run pre-processing.
+ * @param stream cuda stream.
+ */
+
+ void execute(Tensor &leftOutput, Tensor &rightOutput,
+ const Tensor &leftInput, const Tensor &rightInput,
+ cudaStream_t stream = 0);
+
+private:
+ /**
+ * Implementation of ESSPreProcessor.
+ */
+ struct ESSPreProcessorImpl;
+ std::unique_ptr m_pImpl;
+};
+
+/**
+ * ESS parameters and implementation
+ */
+class CVCORE_API ESS
+{
+public:
+ /**
+ * Constructor for ESS.
+ * @param imgparams image pre-processing parameters.
+ * @param modelInputParams model parameters for network.
+ * @param modelInferParams model input inference parameters.
+ * @param essPreProcessorParams paramaters specific for ess preprocessing.
+ */
+ ESS(const ImagePreProcessingParams &imgparams, const ModelInputParams &modelParams,
+ const ModelInferenceParams &modelInferParams, const ESSPreProcessorParams &essPreProcessorParams);
+
+ /**
+ * Default constructor not supported.
+ */
+ ESS() = delete;
+
+ /**
+ * Destructor for ESS.
+ */
+ ~ESS();
+
+ /**
+ * Inference function for a given BGR image
+ * @param disparityMap Disparity map (CPU/GPU tensor supported)
+ * @param leftInput RGB/BGR Interleaved Left image (Only GPU Input Tensor
+ * supported)
+ * @param rightInput RGB/BGR Interleaved Right image (Only GPU Input Tensor
+ * supported)
+ * @param stream Cuda stream
+ */
+ void execute(Tensor &disparityMap, const Tensor &leftInput,
+ const Tensor &rightInput, cudaStream_t stream = 0);
+
+ /**
+ * Inference function for a given Preprocessed image
+ * @param disparityMap Disparity map (CPU/GPU tensor supported)
+ * @param leftInput RGB Planar Left image resized to network input dimensions (Only GPU Input Tensor
+ * supported)
+ * @param rightInput RGB Planar Right image resized to network input dimensions (Only GPU Input Tensor
+ * supported)
+ * @param stream Cuda stream
+ */
+ void execute(Tensor &disparityMap, const Tensor &leftInput,
+ const Tensor &rightInput, cudaStream_t stream = 0);
+
+private:
+ struct ESSImpl;
+ std::unique_ptr m_pImpl;
+};
+
+/**
+ * ESS parameters and implementation
+ */
+class CVCORE_API ESSPostProcessor
+{
+public:
+ /**
+ * Constructor for ESS.
+ * @param modelInputParams model parameters for network.
+ */
+ ESSPostProcessor(const ModelInputParams &modelParams);
+ /**
+ * Default constructor not supported.
+ */
+ ESSPostProcessor() = delete;
+
+ /**
+ * Destructor for ESS.
+ */
+ ~ESSPostProcessor();
+
+ /**
+ * Inference function for a given BGR image
+ * @param outputdisparityMap Disparity map rescaled to orginal resolution (CPU/GPU tensor)
+ * @param inputDisparityMap input Disparity map (GPU tensor)
+ * @param stream Cuda stream
+ */
+ void execute(Tensor &outputdisparityMap, const Tensor &inputdisparityMap,
+ cudaStream_t stream = 0);
+
+private:
+ struct ESSPostProcessorImpl;
+ std::unique_ptr m_pImpl;
+};
+
+}} // namespace cvcore::ess
+#endif
diff --git a/isaac_ros_ess/gxf/ess/3dv/src/ESS.cpp b/isaac_ros_ess/gxf/ess/3dv/src/ESS.cpp
new file mode 100644
index 0000000..151545c
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/3dv/src/ESS.cpp
@@ -0,0 +1,230 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include
+
+#include
+
+#ifdef NVBENCH_ENABLE
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+namespace cvcore { namespace ess {
+
+/* Default parameters used for the model provided*/
+const ImagePreProcessingParams defaultPreProcessorParams = {
+ BGR_U8, /**< Input type of image.*/
+ {-128, -128, -128}, /**< Mean value */
+ {1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0}, /**< Normalization factor */
+ {0.5, 0.5, 0.5}}; /**< Standard deviation */
+
+const ModelInputParams defaultModelInputParams = {1, /**< Max batch size supported */
+ 960, /**< Input layer width of the network */
+ 576, /**< Input layer height of the network */
+ RGB_U8}; /**< Input image type the network is trained with */
+
+const ModelInferenceParams defaultInferenceParams = {
+ "models/ess.engine", /**< Engine file path */
+ {"input_left", "input_right"}, /**< Input layer name of the model */
+ {"output_left"}}; /**< Output layer name of the network */
+
+const ESSPreProcessorParams defaultESSPreProcessorParams = {
+ PreProcessType::RESIZE}; // Resize the input image to the network input dimensions
+
+struct ESS::ESSImpl
+{
+ inferencer::TensorRTInferenceParams tensorrtParams;
+ inferencer::InferenceBackendClient client;
+
+ // Model includes 2 input layers and 1 output layer
+ Tensor m_outputDevice;
+ Tensor m_inputLeftPlanar;
+ Tensor m_inputRightPlanar;
+
+ // Preprocess and PostProcess Objects
+ std::unique_ptr m_preprocess;
+ std::unique_ptr m_postprocess;
+
+ // Max batch Size supported
+ size_t m_maxBatchSize;
+
+ std::string m_leftInputLayerName, m_rightInputLayerName;
+
+ size_t m_networkInputWidth, m_networkInputHeight;
+
+ ESSImpl(const ImagePreProcessingParams &imgParams, const ModelInputParams &modelParams,
+ const ModelInferenceParams &modelInferParams, const ESSPreProcessorParams &essParams)
+ : m_maxBatchSize(modelParams.maxBatchSize)
+ {
+ if (modelInferParams.inputLayers.size() != 2 || modelInferParams.outputLayers.size() != 1 ||
+ modelParams.maxBatchSize <= 0)
+ {
+ throw ErrorCode::INVALID_ARGUMENT;
+ }
+
+ // Initialize Preprocessor and postprocessor
+ m_preprocess.reset(new ESSPreProcessor(imgParams, modelParams, essParams));
+ m_postprocess.reset(new ESSPostProcessor(modelParams));
+
+ // Initialize TRT backend
+ tensorrtParams = {inferencer::TRTInferenceType::TRT_ENGINE,
+ nullptr,
+ modelInferParams.engineFilePath,
+ modelParams.maxBatchSize,
+ modelInferParams.inputLayers,
+ modelInferParams.outputLayers};
+
+ std::error_code err =
+ inferencer::InferenceBackendFactory::CreateTensorRTInferenceBackendClient(client, tensorrtParams);
+
+ if (err != cvcore::make_error_code(cvcore::ErrorCode::SUCCESS))
+ {
+ throw err;
+ }
+
+ inferencer::ModelMetaData modelInfo = client->getModelMetaData();
+
+ m_networkInputHeight = modelParams.inputLayerHeight;
+ m_networkInputWidth = modelParams.inputLayerWidth;
+ m_inputLeftPlanar = {m_networkInputWidth, m_networkInputHeight, modelParams.maxBatchSize, false};
+ m_inputRightPlanar = {m_networkInputWidth, m_networkInputHeight, modelParams.maxBatchSize, false};
+ size_t outputWidth = modelInfo.outputLayers[modelInferParams.outputLayers[0]].shape[2];
+ size_t outputHeight = modelInfo.outputLayers[modelInferParams.outputLayers[0]].shape[1];
+ m_outputDevice = {outputWidth, outputHeight, modelParams.maxBatchSize, false};
+ m_leftInputLayerName = modelInferParams.inputLayers[0];
+ m_rightInputLayerName = modelInferParams.inputLayers[1];
+ CHECK_ERROR_CODE(client->setInput(m_inputLeftPlanar, modelInferParams.inputLayers[0]));
+ CHECK_ERROR_CODE(client->setInput(m_inputRightPlanar, modelInferParams.inputLayers[1]));
+ CHECK_ERROR_CODE(client->setOutput(m_outputDevice, modelInferParams.outputLayers[0]));
+ }
+
+ ~ESSImpl()
+ {
+ CHECK_ERROR_CODE(client->unregister());
+ inferencer::InferenceBackendFactory::DestroyTensorRTInferenceBackendClient(client);
+ }
+
+ void execute(Tensor &output, const Tensor &inputLeft,
+ const Tensor &inputRight, cudaStream_t stream)
+ {
+ size_t batchSize = inputLeft.getDepth();
+ if (inputLeft.isCPU() || inputRight.isCPU())
+ {
+ throw std::invalid_argument("ESS : Input type should be GPU buffer");
+ }
+
+ if (inputLeft.getDepth() > m_maxBatchSize || inputRight.getDepth() > m_maxBatchSize)
+ {
+ throw std::invalid_argument("ESS : Input batch size cannot exceed max batch size\n");
+ }
+
+ if (inputLeft.getDepth() != inputRight.getDepth() || output.getDepth() != inputLeft.getDepth())
+ {
+ throw std::invalid_argument("ESS : Batch size of input and output images don't match!\n");
+ }
+ m_preprocess->execute(m_inputLeftPlanar, m_inputRightPlanar, inputLeft, inputRight, stream);
+
+#ifdef NVBENCH_ENABLE
+ size_t inputWidth = inputLeft.getWidth();
+ size_t inputHeight = inputLeft.getHeight();
+ const std::string testName = "ESSInference_batch" + std::to_string(batchSize) + "_" +
+ std::to_string(inputWidth) + "x" + std::to_string(inputHeight) + "x" +
+ std::to_string(inputLeft.getChannelCount()) + "_GPU";
+ nv::bench::Timer timerFunc = nv::bench::GPU(testName.c_str(), nv::bench::Flag::DEFAULT, stream);
+#endif
+
+ CHECK_ERROR_CODE(client->setCudaStream(stream));
+ CHECK_ERROR_CODE(client->infer(batchSize));
+ // PostProcess
+ m_postprocess->execute(output, m_outputDevice, stream);
+ }
+
+ void execute(Tensor &output, const Tensor &inputLeft,
+ const Tensor &inputRight, cudaStream_t stream)
+ {
+ size_t batchSize = inputLeft.getDepth();
+ if (inputLeft.isCPU() || inputRight.isCPU())
+ {
+ throw std::invalid_argument("ESS : Input type should be GPU buffer");
+ }
+
+ if (inputLeft.getDepth() > m_maxBatchSize || inputRight.getDepth() > m_maxBatchSize)
+ {
+ throw std::invalid_argument("ESS : Input batch size cannot exceed max batch size\n");
+ }
+
+ if (inputLeft.getDepth() != inputRight.getDepth() || output.getDepth() != inputLeft.getDepth())
+ {
+ throw std::invalid_argument("ESS : Batch size of input and output images don't match!\n");
+ }
+
+ if (inputLeft.getWidth() != m_networkInputWidth || inputLeft.getHeight() != m_networkInputHeight)
+ {
+ throw std::invalid_argument("ESS : Left preprocessed input does not match network input dimensions!\n");
+ }
+
+ if (inputRight.getWidth() != m_networkInputWidth || inputRight.getHeight() != m_networkInputHeight)
+ {
+ throw std::invalid_argument("ESS : Right preprocessed input does not match network input dimensions!\n");
+ }
+#ifdef NVBENCH_ENABLE
+ size_t inputWidth = inputLeft.getWidth();
+ size_t inputHeight = inputLeft.getHeight();
+ const std::string testName = "ESSInference_batch" + std::to_string(batchSize) + "_" +
+ std::to_string(inputWidth) + "x" + std::to_string(inputHeight) + "x" +
+ std::to_string(inputLeft.getChannelCount()) + "_GPU";
+ nv::bench::Timer timerFunc = nv::bench::GPU(testName.c_str(), nv::bench::Flag::DEFAULT, stream);
+#endif
+ // inference
+ CHECK_ERROR_CODE(client->setInput(inputLeft, m_leftInputLayerName));
+ CHECK_ERROR_CODE(client->setInput(inputRight, m_rightInputLayerName));
+
+ CHECK_ERROR_CODE(client->setCudaStream(stream));
+ CHECK_ERROR_CODE(client->infer(batchSize));
+ // PostProcess
+ m_postprocess->execute(output, m_outputDevice, stream);
+ }
+};
+
+ESS::ESS(const ImagePreProcessingParams &imgParams, const ModelInputParams &modelParams,
+ const ModelInferenceParams &modelInferParams, const ESSPreProcessorParams &essParams)
+ : m_pImpl(new ESSImpl(imgParams, modelParams, modelInferParams, essParams))
+{
+}
+
+ESS::~ESS() {}
+
+void ESS::execute(Tensor &output, const Tensor &inputLeft,
+ const Tensor &inputRight, cudaStream_t stream)
+{
+ m_pImpl->execute(output, inputLeft, inputRight, stream);
+}
+
+void ESS::execute(Tensor &output, const Tensor &inputLeft,
+ const Tensor &inputRight, cudaStream_t stream)
+{
+ m_pImpl->execute(output, inputLeft, inputRight, stream);
+}
+}} // namespace cvcore::ess
diff --git a/isaac_ros_ess/gxf/ess/3dv/src/ESSPostProcess.cpp b/isaac_ros_ess/gxf/ess/3dv/src/ESSPostProcess.cpp
new file mode 100644
index 0000000..ed823a0
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/3dv/src/ESSPostProcess.cpp
@@ -0,0 +1,129 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include
+
+#include
+
+#ifdef NVBENCH_ENABLE
+#include
+#endif
+
+#include
+#include
+#include
+#include
+
+namespace cvcore { namespace ess {
+
+struct ESSPostProcessor::ESSPostProcessorImpl
+{
+ ESSPostProcessorImpl(const ModelInputParams &modelParams)
+ : m_maxBatchSize(modelParams.maxBatchSize)
+ , m_networkWidth(modelParams.inputLayerWidth)
+ , m_networkHeight(modelParams.inputLayerHeight)
+ {
+ m_scaledDisparityDevice = {m_networkWidth, m_networkHeight, m_maxBatchSize, false};
+ m_outputDisparityDevice = {m_networkWidth, m_networkHeight, m_maxBatchSize, false};
+ }
+
+ void resizeBuffers(std::size_t width, std::size_t height)
+ {
+ if (m_outputDisparityDevice.getWidth() == width && m_outputDisparityDevice.getHeight() == height)
+ {
+ return;
+ }
+ m_outputDisparityDevice = {width, height, m_maxBatchSize, false};
+ }
+
+ void process(Tensor &outputDisparity, const Tensor &inputDisparity,
+ cudaStream_t stream)
+ {
+ if (inputDisparity.isCPU())
+ {
+ throw std::invalid_argument("ESSPostProcessor : Input Tensor must be GPU Tensor.");
+ }
+
+ if (inputDisparity.getWidth() != m_networkWidth || inputDisparity.getHeight() != m_networkHeight)
+ {
+ throw std::invalid_argument(
+ "ESSPostProcessor : Input Tensor dimension "
+ "does not match network input "
+ "requirement");
+ }
+
+ if (inputDisparity.getDepth() != outputDisparity.getDepth())
+ {
+ throw std::invalid_argument("ESSPostProcessor : Input/Output Tensor batchsize mismatch.");
+ }
+
+ const size_t batchSize = inputDisparity.getDepth();
+ if (batchSize > m_maxBatchSize)
+ {
+ throw std::invalid_argument("ESSPostProcessor : Input batchsize exceeds Max Batch size.");
+ }
+ const size_t outputWidth = outputDisparity.getWidth();
+ const size_t outputHeight = outputDisparity.getHeight();
+
+ // Disparity map values are scaled based on the outputWidth/networkInputWidth ratio
+ const float scale = static_cast(outputWidth) / m_networkWidth;
+ Tensor scaledDisparity(m_scaledDisparityDevice.getWidth(), m_scaledDisparityDevice.getHeight(),
+ batchSize, m_scaledDisparityDevice.getData(), false);
+
+ tensor_ops::Normalize(scaledDisparity, inputDisparity, scale, 0, stream);
+ if (!outputDisparity.isCPU())
+ {
+ tensor_ops::Resize(outputDisparity, m_scaledDisparityDevice, stream);
+ }
+ else
+ {
+ resizeBuffers(outputWidth, outputHeight);
+ Tensor outputDisparityDevice(m_outputDisparityDevice.getWidth(),
+ m_outputDisparityDevice.getHeight(), batchSize,
+ m_outputDisparityDevice.getData(), false);
+ tensor_ops::Resize(outputDisparityDevice, m_scaledDisparityDevice, stream);
+ cvcore::Copy(outputDisparity, outputDisparityDevice, stream);
+ CHECK_ERROR(cudaStreamSynchronize(stream));
+ }
+ }
+
+ size_t m_maxBatchSize;
+ size_t m_networkWidth, m_networkHeight;
+ Tensor m_scaledDisparityDevice;
+ Tensor m_outputDisparityDevice;
+};
+
+void ESSPostProcessor::execute(Tensor &outputDisparity, const Tensor &inputDisparity,
+ cudaStream_t stream)
+{
+#ifdef NVBENCH_ENABLE
+ const std::string testName = "ESSPostProcessor_batch" + std::to_string(outputDisparity.getDepth()) + "_" +
+ std::to_string(outputDisparity.getWidth()) + "x" +
+ std::to_string(outputDisparity.getHeight()) + "_GPU";
+ nv::bench::Timer timerFunc = nv::bench::GPU(testName.c_str(), nv::bench::Flag::DEFAULT, stream);
+#endif
+ m_pImpl->process(outputDisparity, inputDisparity, stream);
+}
+
+ESSPostProcessor::ESSPostProcessor(const ModelInputParams &modelInputParams)
+ : m_pImpl(new ESSPostProcessor::ESSPostProcessorImpl(modelInputParams))
+{
+}
+
+ESSPostProcessor::~ESSPostProcessor() {}
+
+}} // namespace cvcore::ess
diff --git a/isaac_ros_ess/gxf/ess/3dv/src/ESSPreProcess.cpp b/isaac_ros_ess/gxf/ess/3dv/src/ESSPreProcess.cpp
new file mode 100644
index 0000000..001c528
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/3dv/src/ESSPreProcess.cpp
@@ -0,0 +1,190 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include
+
+#include
+
+#ifdef NVBENCH_ENABLE
+#include
+#endif
+
+#include
+#include
+#include
+#include
+
+namespace cvcore { namespace ess {
+
+struct ESSPreProcessor::ESSPreProcessorImpl
+{
+ size_t m_maxBatchSize;
+ size_t m_outputWidth;
+ size_t m_outputHeight;
+ PreProcessType m_processType;
+ ImagePreProcessingParams m_preProcessorParams;
+ Tensor m_resizedDeviceLeftInput;
+ Tensor m_resizedDeviceRightInput;
+ Tensor m_normalizedDeviceLeftInput;
+ Tensor m_normalizedDeviceRightInput;
+ bool m_swapRB;
+
+ ESSPreProcessorImpl(const ImagePreProcessingParams &imgParams, const ModelInputParams &modelParams,
+ const ESSPreProcessorParams &essParams)
+ : m_maxBatchSize(modelParams.maxBatchSize)
+ , m_outputHeight(modelParams.inputLayerHeight)
+ , m_outputWidth(modelParams.inputLayerWidth)
+ , m_processType(essParams.preProcessType)
+ , m_preProcessorParams(imgParams)
+ {
+ if (imgParams.imgType != BGR_U8 && imgParams.imgType != RGB_U8)
+ {
+ throw std::invalid_argument("ESSPreProcessor : Only image types RGB_U8/BGR_U8 are supported\n");
+ }
+ m_resizedDeviceLeftInput = {modelParams.inputLayerWidth, modelParams.inputLayerHeight, modelParams.maxBatchSize,
+ false};
+ m_resizedDeviceRightInput = {modelParams.inputLayerWidth, modelParams.inputLayerHeight,
+ modelParams.maxBatchSize, false};
+ m_normalizedDeviceLeftInput = {modelParams.inputLayerWidth, modelParams.inputLayerHeight,
+ modelParams.maxBatchSize, false};
+ m_normalizedDeviceRightInput = {modelParams.inputLayerWidth, modelParams.inputLayerHeight,
+ modelParams.maxBatchSize, false};
+ m_swapRB = imgParams.imgType != modelParams.modelInputType;
+ }
+
+ void process(Tensor &outputLeft, Tensor &outputRight,
+ const Tensor &inputLeft, const Tensor &inputRight, cudaStream_t stream)
+ {
+ if (inputLeft.isCPU() || inputRight.isCPU() || outputLeft.isCPU() || outputRight.isCPU())
+ {
+ throw std::invalid_argument("ESSPreProcessor : Input/Output Tensor must be GPU Tensor.");
+ }
+
+ if (outputLeft.getWidth() != m_outputWidth || outputLeft.getHeight() != m_outputHeight ||
+ outputRight.getWidth() != m_outputWidth || outputRight.getHeight() != m_outputHeight)
+ {
+ throw std::invalid_argument(
+ "ESSPreProcessor : Output Tensor dimension does not match network input requirement");
+ }
+
+ if (inputLeft.getWidth() != inputRight.getWidth() || inputLeft.getHeight() != inputRight.getHeight())
+ {
+ throw std::invalid_argument("ESSPreProcessor : Input tensor dimensions don't match");
+ }
+
+ if (outputLeft.getDepth() != inputLeft.getDepth() || outputRight.getDepth() != inputRight.getDepth() ||
+ inputLeft.getDepth() != inputRight.getDepth())
+ {
+ throw std::invalid_argument("ESSPreProcessor : Input/Output Tensor batchsize mismatch.");
+ }
+
+ if (outputLeft.getDepth() > m_maxBatchSize)
+ {
+ throw std::invalid_argument("ESSPreProcessor : Input/Output batchsize exceeds max batch size.");
+ }
+
+ const size_t batchSize = inputLeft.getDepth();
+ const size_t inputWidth = inputLeft.getWidth();
+ const size_t inputHeight = inputLeft.getHeight();
+
+ if (m_processType == PreProcessType::RESIZE)
+ {
+ tensor_ops::Resize(m_resizedDeviceLeftInput, inputLeft, stream);
+ tensor_ops::Resize(m_resizedDeviceRightInput, inputRight, stream);
+ }
+ else
+ {
+ const float centerX = inputWidth / 2;
+ const float centerY = inputHeight / 2;
+ const float offsetX = m_outputWidth / 2;
+ const float offsetY = m_outputHeight / 2;
+ BBox srcCrop, dstCrop;
+ dstCrop = {0, 0, static_cast(m_outputWidth - 1), static_cast(m_outputHeight - 1)};
+ srcCrop.xmin = std::max(0, static_cast(centerX - offsetX));
+ srcCrop.ymin = std::max(0, static_cast(centerY - offsetY));
+ srcCrop.xmax = std::min(static_cast(m_outputWidth - 1), static_cast(centerX + offsetX));
+ srcCrop.ymax = std::min(static_cast(m_outputHeight - 1), static_cast(centerY + offsetY));
+ for (size_t i = 0; i < batchSize; i++)
+ {
+ Tensor inputLeftCrop(
+ inputWidth, inputHeight,
+ const_cast(inputLeft.getData()) + i * inputLeft.getStride(TensorDimension::DEPTH),
+ false);
+ Tensor outputLeftCrop(
+ m_outputWidth, m_outputHeight,
+ m_resizedDeviceLeftInput.getData() + i * m_resizedDeviceLeftInput.getStride(TensorDimension::DEPTH),
+ false);
+ Tensor inputRightCrop(
+ inputWidth, inputHeight,
+ const_cast(inputRight.getData()) + i * inputRight.getStride(TensorDimension::DEPTH),
+ false);
+ Tensor outputRightCrop(m_outputWidth, m_outputHeight,
+ m_resizedDeviceRightInput.getData() +
+ i * m_resizedDeviceRightInput.getStride(TensorDimension::DEPTH),
+ false);
+ tensor_ops::CropAndResize(outputLeftCrop, inputLeftCrop, dstCrop, srcCrop,
+ tensor_ops::InterpolationType::INTERP_LINEAR, stream);
+ tensor_ops::CropAndResize(outputRightCrop, inputRightCrop, dstCrop, srcCrop,
+ tensor_ops::InterpolationType::INTERP_LINEAR, stream);
+ }
+ }
+
+ if (m_swapRB)
+ {
+ tensor_ops::ConvertColorFormat(m_resizedDeviceLeftInput, m_resizedDeviceLeftInput, tensor_ops::BGR2RGB,
+ stream);
+ tensor_ops::ConvertColorFormat(m_resizedDeviceRightInput, m_resizedDeviceRightInput, tensor_ops::BGR2RGB,
+ stream);
+ }
+
+ float scale[3];
+ for (size_t i = 0; i < 3; i++)
+ {
+ scale[i] = m_preProcessorParams.normalization[i] / m_preProcessorParams.stdDev[i];
+ }
+
+ tensor_ops::Normalize(m_normalizedDeviceLeftInput, m_resizedDeviceLeftInput, scale,
+ m_preProcessorParams.pixelMean, stream);
+ tensor_ops::Normalize(m_normalizedDeviceRightInput, m_resizedDeviceRightInput, scale,
+ m_preProcessorParams.pixelMean, stream);
+ tensor_ops::InterleavedToPlanar(outputLeft, m_normalizedDeviceLeftInput, stream);
+ tensor_ops::InterleavedToPlanar(outputRight, m_normalizedDeviceRightInput, stream);
+ }
+};
+
+void ESSPreProcessor::execute(Tensor &outputLeft, Tensor &outputRight,
+ const Tensor &inputLeft, const Tensor &inputRight,
+ cudaStream_t stream)
+{
+#ifdef NVBENCH_ENABLE
+ const std::string testName = "ESSPreProcessor_batch" + std::to_string(inputLeft.getDepth()) + "_" +
+ std::to_string(inputLeft.getWidth()) + "x" + std::to_string(inputLeft.getHeight()) +
+ "_GPU";
+ nv::bench::Timer timerFunc = nv::bench::GPU(testName.c_str(), nv::bench::Flag::DEFAULT, stream);
+#endif
+ m_pImpl->process(outputLeft, outputRight, inputLeft, inputRight, stream);
+}
+
+ESSPreProcessor::ESSPreProcessor(const ImagePreProcessingParams &preProcessorParams,
+ const ModelInputParams &modelInputParams, const ESSPreProcessorParams &essParams)
+ : m_pImpl(new ESSPreProcessor::ESSPreProcessorImpl(preProcessorParams, modelInputParams, essParams))
+{
+}
+
+ESSPreProcessor::~ESSPreProcessor() {}
+
+}} // namespace cvcore::ess
diff --git a/isaac_ros_ess/gxf/ess/CMakeLists.txt b/isaac_ros_ess/gxf/ess/CMakeLists.txt
new file mode 100644
index 0000000..da68934
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/CMakeLists.txt
@@ -0,0 +1,129 @@
+# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+# Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+project(gxf_cvcore_ess LANGUAGES C CXX)
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ add_compile_options(-fPIC -w)
+endif()
+
+# Dependencies
+find_package(CUDAToolkit)
+include(YamlCpp)
+find_package(GXF ${ISAAC_ROS_GXF_VERSION} MODULE REQUIRED
+ COMPONENTS
+ core
+ cuda
+ multimedia
+ serialization
+)
+find_package(TENSORRT)
+
+# Create extension
+add_library(gxf_cvcore_ess SHARED
+ ESS.cpp
+ extensions/ess/ESS.hpp
+ ESSRegistry.cpp
+
+ extensions/tensor_ops/ImageAdapter.cpp
+ extensions/tensor_ops/ImageAdapter.hpp
+ extensions/tensor_ops/ImageUtils.cpp
+ extensions/tensor_ops/ImageUtils.hpp
+
+ extensions/tensor_ops/detail/ImageAdapterTensorImpl.cpp
+ extensions/tensor_ops/detail/ImageAdapterTensorImpl.hpp
+ extensions/tensor_ops/detail/ImageAdapterVideoBufferImpl.cpp
+ extensions/tensor_ops/detail/ImageAdapterVideoBufferImpl.hpp
+)
+
+set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
+target_include_directories(gxf_cvcore_ess PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/cvcore/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/3dv/include)
+
+add_library(cvcore_ess STATIC
+ # Tensorops
+ cvcore/src/tensor_ops/ArithmeticOperations.cpp
+ cvcore/src/tensor_ops/BBoxUtils.cpp
+ cvcore/src/tensor_ops/ColorConversions.cpp
+ cvcore/src/tensor_ops/DBScan.cpp
+ cvcore/src/tensor_ops/Errors.cpp
+ cvcore/src/tensor_ops/Filters.cpp
+ cvcore/src/tensor_ops/Filters.h
+ cvcore/src/tensor_ops/FusedOperations.cpp
+ cvcore/src/tensor_ops/GeometryTransforms.cpp
+ cvcore/src/tensor_ops/IImageWarp.cpp
+ cvcore/src/tensor_ops/NppUtils.cpp
+ cvcore/src/tensor_ops/NppUtils.h
+ cvcore/src/tensor_ops/OneEuroFilter.cpp
+ cvcore/src/tensor_ops/TensorOperators.cpp
+
+ # Core
+ cvcore/src/core/cvcore/Array.cpp
+ cvcore/src/core/cvcore/Dummy.cu
+ cvcore/src/core/cvcore/MathTypes.cpp
+ cvcore/src/core/cvcore/Tensor.cpp
+ cvcore/src/core/utility/CVError.cpp
+ cvcore/src/core/utility/Instrumentation.cpp
+ cvcore/src/core/utility/Memory.cpp
+ cvcore/src/core/utility/ProfileUtils.cpp
+
+ # Inferencer (ESS only)
+ cvcore/src/inferencer/tensorrt/TensorRTInferencer.cpp
+ cvcore/src/inferencer/Inferencer.cpp
+ cvcore/src/inferencer/Errors.cpp
+ cvcore/src/inferencer/tensorrt/TensorRTUtils.h
+ cvcore/src/inferencer/tensorrt/TensorRTUtils.cpp
+ cvcore/src/inferencer/tensorrt/TensorRTInferencer.h
+
+ # TRTBackend
+ cvcore/src/trtbackend/TRTBackend.cpp
+)
+
+target_include_directories(cvcore_ess PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cvcore/include)
+target_compile_options(cvcore_ess PUBLIC -fPIC)
+target_link_libraries(cvcore_ess PUBLIC
+ CUDA::cudart
+ CUDA::nppc
+ CUDA::nppial
+ CUDA::nppicc
+ CUDA::nppidei
+ CUDA::nppif
+ CUDA::nppig
+ CUDA::nppisu
+ TENSORRT::nvinfer
+)
+
+add_library(ess_3dv STATIC
+ 3dv/src/ESS.cpp
+ 3dv/src/ESSPostProcess.cpp
+ 3dv/src/ESSPreProcess.cpp
+)
+target_include_directories(ess_3dv PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/3dv/include)
+target_compile_options(ess_3dv PUBLIC -fPIC)
+target_link_libraries(ess_3dv PUBLIC
+ cvcore_ess
+)
+target_link_libraries(gxf_cvcore_ess
+ PUBLIC
+ GXF::cuda
+ GXF::multimedia
+ yaml-cpp
+ PRIVATE
+ cvcore_ess
+ ess_3dv
+)
diff --git a/isaac_ros_ess/gxf/ess/ESS.cpp b/isaac_ros_ess/gxf/ess/ESS.cpp
new file mode 100644
index 0000000..593e34c
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/ESS.cpp
@@ -0,0 +1,325 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include "extensions/ess/ESS.hpp"
+
+#include
+#include "gxf/cuda/cuda_stream_id.hpp"
+#include "gxf/cuda/cuda_stream_pool.hpp"
+#include "gxf/multimedia/video.hpp"
+#include "gxf/std/tensor.hpp"
+#include "gxf/std/timestamp.hpp"
+
+namespace nvidia {
+namespace cvcore {
+
+namespace detail {
+
+// Function to bind a cuda stream with cid into downstream message
+gxf_result_t BindCudaStream(gxf::Entity& message, gxf_uid_t cid) {
+ if (cid == kNullUid) {
+ GXF_LOG_ERROR("stream_cid is null");
+ return GXF_FAILURE;
+ }
+ auto output_stream_id = message.add("stream");
+ if (!output_stream_id) {
+ GXF_LOG_ERROR("failed to add cudastreamid.");
+ return GXF_FAILURE;
+ }
+ output_stream_id.value()->stream_cid = cid;
+ return GXF_SUCCESS;
+}
+
+// Function to record a new cuda event
+gxf_result_t RecordCudaEvent(gxf::Entity& message, gxf::Handle& stream) {
+ // Create a new event
+ cudaEvent_t cuda_event;
+ cudaEventCreateWithFlags(&cuda_event, 0);
+ gxf::CudaEvent event;
+ auto ret = event.initWithEvent(cuda_event, stream->dev_id(), [](auto) {});
+ if (!ret) {
+ GXF_LOG_ERROR("failed to init cuda event");
+ return GXF_FAILURE;
+ }
+ // Record the event
+ // Can define []() { GXF_LOG_DEBUG("tensorops event synced"); } as callback func for debug purpose
+ ret = stream->record(event.event().value(),
+ [event = cuda_event, entity = message.clone().value()](auto) { cudaEventDestroy(event); });
+ if (!ret) {
+ GXF_LOG_ERROR("record event failed");
+ return ret.error();
+ }
+ return GXF_SUCCESS;
+}
+
+} // namespace detail
+
+gxf_result_t ESS::registerInterface(gxf::Registrar* registrar) {
+ gxf::Expected result;
+
+ result &= registrar->parameter(left_image_name_, "left_image_name", "The name of the left image to be received", "",
+ gxf::Registrar::NoDefaultParameter(), GXF_PARAMETER_FLAGS_OPTIONAL);
+ result &= registrar->parameter(right_image_name_, "right_image_name", "The name of the right image to be received",
+ "", gxf::Registrar::NoDefaultParameter(), GXF_PARAMETER_FLAGS_OPTIONAL);
+ result &= registrar->parameter(output_name_, "output_name", "The name of the tensor to be passed to next node", "");
+ result &= registrar->parameter(stream_pool_, "stream_pool", "The Cuda Stream pool for allocate cuda stream", "",
+ gxf::Registrar::NoDefaultParameter(), GXF_PARAMETER_FLAGS_OPTIONAL);
+ result &= registrar->parameter(pool_, "pool", "Memory pool for allocating output data", "");
+ result &= registrar->parameter(left_image_receiver_, "left_image_receiver", "Receiver to get the left image", "");
+ result &= registrar->parameter(right_image_receiver_, "right_image_receiver", "Receiver to get the right image", "");
+ result &= registrar->parameter(output_transmitter_, "output_transmitter", "Transmitter to send the data", "");
+ result &= registrar->parameter(output_adapter_, "output_adapter", "Adapter to send output data", "");
+
+ result &= registrar->parameter(image_type_, "image_type", "Type of input image: BGR_U8 or RGB_U8", "");
+ result &= registrar->parameter(pixel_mean_, "pixel_mean", "The mean for each channel", "");
+ result &= registrar->parameter(normalization_, "normalization", "The normalization for each channel", "");
+ result &=
+ registrar->parameter(standard_deviation_, "standard_deviation", "The standard deviation for each channel", "");
+
+ result &= registrar->parameter(max_batch_size_, "max_batch_size", "The max batch size to run inference on", "");
+ result &= registrar->parameter(input_layer_width_, "input_layer_width", "The model input layer width", "");
+ result &= registrar->parameter(input_layer_height_, "input_layer_height", "The model input layer height", "");
+ result &= registrar->parameter(model_input_type_, "model_input_type", "The model input image: BGR_U8 or RGB_U8", "");
+
+ result &= registrar->parameter(engine_file_path_, "engine_file_path", "The path to the serialized TRT engine", "");
+ result &= registrar->parameter(input_layers_name_, "input_layers_name", "The names of the input layers", "");
+ result &= registrar->parameter(output_layers_name_, "output_layers_name", "The names of the output layers", "");
+
+ result &= registrar->parameter(preprocess_type_, "preprocess_type",
+ "The type of ESS preprocessing: RESIZE / CENTER_CROP", "");
+ result &= registrar->parameter(output_width_, "output_width", "The width of output result", "",
+ gxf::Registrar::NoDefaultParameter(), GXF_PARAMETER_FLAGS_OPTIONAL);
+ result &= registrar->parameter(output_height_, "output_height", "The height of output result", "",
+ gxf::Registrar::NoDefaultParameter(), GXF_PARAMETER_FLAGS_OPTIONAL);
+ result &= registrar->parameter(timestamp_policy_, "timestamp_policy",
+ "Input channel to get timestamp 0(left)/1(right)", "", 0);
+
+ return gxf::ToResultCode(result);
+}
+
+gxf_result_t ESS::start() {
+ // Allocate cuda stream using stream pool if necessary
+ if (stream_pool_.try_get()) {
+ auto stream = stream_pool_.try_get().value()->allocateStream();
+ if (!stream) {
+ GXF_LOG_ERROR("allocating stream failed.");
+ return GXF_FAILURE;
+ }
+ cuda_stream_ = std::move(stream.value());
+ if (!cuda_stream_->stream()) {
+ GXF_LOG_ERROR("allocated stream is not initialized.");
+ return GXF_FAILURE;
+ }
+ }
+ // Setting image pre-processing params for ESS
+ const auto& pixel_mean_vec = pixel_mean_.get();
+ const auto& normalization_vec = normalization_.get();
+ const auto& standard_deviation_vec = standard_deviation_.get();
+ if (pixel_mean_vec.size() != 3 || normalization_vec.size() != 3 || standard_deviation_vec.size() != 3) {
+ GXF_LOG_ERROR("Invalid preprocessing params.");
+ return GXF_FAILURE;
+ }
+
+ if (image_type_.get() == "BGR_U8") {
+ preProcessorParams.imgType = ::cvcore::BGR_U8;
+ } else if (image_type_.get() == "RGB_U8") {
+ preProcessorParams.imgType = ::cvcore::RGB_U8;
+ } else {
+ GXF_LOG_INFO("Wrong input image type. BGR_U8 and RGB_U8 are only supported.");
+ return GXF_FAILURE;
+ }
+ std::copy(pixel_mean_vec.begin(), pixel_mean_vec.end(), preProcessorParams.pixelMean);
+ std::copy(normalization_vec.begin(), normalization_vec.end(), preProcessorParams.normalization);
+ std::copy(standard_deviation_vec.begin(), standard_deviation_vec.end(), preProcessorParams.stdDev);
+
+ // Setting model input params for ESS
+ modelInputParams.maxBatchSize = max_batch_size_.get();
+ modelInputParams.inputLayerWidth = input_layer_width_.get();
+ modelInputParams.inputLayerHeight = input_layer_height_.get();
+ if (model_input_type_.get() == "BGR_U8") {
+ modelInputParams.modelInputType = ::cvcore::BGR_U8;
+ } else if (model_input_type_.get() == "RGB_U8") {
+ modelInputParams.modelInputType = ::cvcore::RGB_U8;
+ } else {
+ GXF_LOG_INFO("Wrong model input type. BGR_U8 and RGB_U8 are only supported.");
+ return GXF_FAILURE;
+ }
+
+ // Setting inference params for ESS
+ inferenceParams = {engine_file_path_.get(), input_layers_name_.get(), output_layers_name_.get()};
+
+ // Setting extra params for ESS
+ if (preprocess_type_.get() == "RESIZE") {
+ extraParams = {::cvcore::ess::PreProcessType::RESIZE};
+ } else if (preprocess_type_.get() == "CENTER_CROP") {
+ extraParams = {::cvcore::ess::PreProcessType::CENTER_CROP};
+ } else {
+ GXF_LOG_ERROR("Invalid preprocessing type.");
+ return GXF_FAILURE;
+ }
+
+ // Setting ESS object with the provided params
+ objESS.reset(new ::cvcore::ess::ESS(preProcessorParams, modelInputParams, inferenceParams, extraParams));
+
+ return GXF_SUCCESS;
+}
+
+gxf_result_t ESS::tick() {
+ // Get a CUDA stream for execution
+ cudaStream_t cuda_stream = 0;
+ if (!cuda_stream_.is_null()) {
+ cuda_stream = cuda_stream_->stream().value();
+ }
+ // Receiving the data
+ auto inputLeftMessage = left_image_receiver_->receive();
+ if (!inputLeftMessage) {
+ return GXF_FAILURE;
+ }
+ if (cuda_stream != 0) {
+ detail::RecordCudaEvent(inputLeftMessage.value(), cuda_stream_);
+ auto inputLeftStreamId = inputLeftMessage.value().get("stream");
+ if (inputLeftStreamId) {
+ auto inputLeftStream = gxf::Handle::Create(inputLeftStreamId.value().context(),
+ inputLeftStreamId.value()->stream_cid);
+ // NOTE: This is an expensive call. It will halt the current CPU thread until all events
+ // previously associated with the stream are cleared
+ if (!inputLeftStream.value()->syncStream()) {
+ GXF_LOG_ERROR("sync left stream failed.");
+ return GXF_FAILURE;
+ }
+ }
+ }
+
+ auto inputRightMessage = right_image_receiver_->receive();
+ if (!inputRightMessage) {
+ return GXF_FAILURE;
+ }
+ if (cuda_stream != 0) {
+ detail::RecordCudaEvent(inputRightMessage.value(), cuda_stream_);
+ auto inputRightStreamId = inputRightMessage.value().get("stream");
+ if (inputRightStreamId) {
+ auto inputRightStream = gxf::Handle::Create(inputRightStreamId.value().context(),
+ inputRightStreamId.value()->stream_cid);
+ // NOTE: This is an expensive call. It will halt the current CPU thread until all events
+ // previously associated with the stream are cleared
+ if (!inputRightStream.value()->syncStream()) {
+ GXF_LOG_ERROR("sync right stream failed.");
+ return GXF_FAILURE;
+ }
+ }
+ }
+
+ auto maybeLeftName = left_image_name_.try_get();
+ auto leftInputBuffer = inputLeftMessage.value().get(maybeLeftName ? maybeLeftName.value().c_str() : nullptr);
+ if (!leftInputBuffer) {
+ return GXF_FAILURE;
+ }
+ auto maybeRightName = right_image_name_.try_get();
+ auto rightInputBuffer = inputRightMessage.value().get(maybeRightName ? maybeRightName.value().c_str() : nullptr);
+ if (!rightInputBuffer) {
+ return GXF_FAILURE;
+ }
+ if (leftInputBuffer.value()->storage_type() != gxf::MemoryStorageType::kDevice ||
+ rightInputBuffer.value()->storage_type() != gxf::MemoryStorageType::kDevice) {
+ GXF_LOG_ERROR("input images must be on GPU.");
+ return GXF_FAILURE;
+ }
+
+ const auto& leftBufferInfo = leftInputBuffer.value()->video_frame_info();
+ const auto& rightBufferInfo = rightInputBuffer.value()->video_frame_info();
+ if (leftBufferInfo.width != rightBufferInfo.width || leftBufferInfo.height != rightBufferInfo.height ||
+ leftBufferInfo.color_format != rightBufferInfo.color_format) {
+ GXF_LOG_ERROR("left/right images mismatch.");
+ return GXF_FAILURE;
+ }
+ const size_t outputWidth = output_width_.try_get() ? output_width_.try_get().value() : leftBufferInfo.width;
+ const size_t outputHeight = output_height_.try_get() ? output_height_.try_get().value() : leftBufferInfo.height;
+
+ // Creating GXF Tensor or VideoBuffer to hold the data to be transmitted
+ gxf::Expected outputMessage = gxf::Entity::New(context());
+ if (!outputMessage) {
+ return outputMessage.error();
+ }
+ auto error = output_adapter_.get()->AddImageToMessage<::cvcore::ImageType::Y_F32>(
+ outputMessage.value(), outputWidth, outputHeight, pool_.get(), false, output_name_.get().c_str());
+ if (error != GXF_SUCCESS) {
+ return GXF_FAILURE;
+ }
+ auto outputImage = output_adapter_.get()->WrapImageFromMessage<::cvcore::ImageType::Y_F32>(
+ outputMessage.value(), output_name_.get().c_str());
+ if (!outputImage) {
+ return GXF_FAILURE;
+ }
+
+ // Creating CVCore Tensors to hold the input and output data
+ ::cvcore::Tensor<::cvcore::NHWC, ::cvcore::C1, ::cvcore::F32> outputImageDevice(outputWidth, outputHeight, 1,
+ outputImage.value().getData(), false);
+
+ // Running the inference
+ auto inputColorFormat = leftBufferInfo.color_format;
+ if (inputColorFormat == gxf::VideoFormat::GXF_VIDEO_FORMAT_RGB ||
+ inputColorFormat == gxf::VideoFormat::GXF_VIDEO_FORMAT_BGR) {
+ ::cvcore::Tensor<::cvcore::NHWC, ::cvcore::C3, ::cvcore::U8> leftImageDevice(
+ leftBufferInfo.width, leftBufferInfo.height, 1, reinterpret_cast(leftInputBuffer.value()->pointer()),
+ false);
+ ::cvcore::Tensor<::cvcore::NHWC, ::cvcore::C3, ::cvcore::U8> rightImageDevice(
+ leftBufferInfo.width, leftBufferInfo.height, 1, reinterpret_cast(rightInputBuffer.value()->pointer()),
+ false);
+ objESS->execute(outputImageDevice, leftImageDevice, rightImageDevice, cuda_stream);
+ } else if (inputColorFormat == gxf::VideoFormat::GXF_VIDEO_FORMAT_R32_G32_B32 ||
+ inputColorFormat == gxf::VideoFormat::GXF_VIDEO_FORMAT_B32_G32_R32) {
+ ::cvcore::Tensor<::cvcore::NCHW, ::cvcore::C3, ::cvcore::F32> leftImageDevice(
+ leftBufferInfo.width, leftBufferInfo.height, 1, reinterpret_cast(leftInputBuffer.value()->pointer()),
+ false);
+ ::cvcore::Tensor<::cvcore::NCHW, ::cvcore::C3, ::cvcore::F32> rightImageDevice(
+ leftBufferInfo.width, leftBufferInfo.height, 1, reinterpret_cast(rightInputBuffer.value()->pointer()),
+ false);
+ objESS->execute(outputImageDevice, leftImageDevice, rightImageDevice, cuda_stream);
+ } else {
+ GXF_LOG_ERROR("invalid input image type.");
+ return GXF_FAILURE;
+ }
+
+ // Allocate a cuda event that can be used to record on each tick
+ if (!cuda_stream_.is_null()) {
+ detail::BindCudaStream(outputMessage.value(), cuda_stream_.cid());
+ detail::RecordCudaEvent(outputMessage.value(), cuda_stream_);
+ }
+
+ // Pass down timestamp if necessary
+ auto maybeDaqTimestamp = timestamp_policy_.get() == 0 ? inputLeftMessage.value().get()
+ : inputRightMessage.value().get();
+ if (maybeDaqTimestamp) {
+ auto outputTimestamp = outputMessage.value().add(maybeDaqTimestamp.value().name());
+ if (!outputTimestamp) {
+ return outputTimestamp.error();
+ }
+ *outputTimestamp.value() = *maybeDaqTimestamp.value();
+ }
+
+ // Send the data
+ output_transmitter_->publish(outputMessage.value());
+ return GXF_SUCCESS;
+}
+
+gxf_result_t ESS::stop() {
+ objESS.reset(nullptr);
+ return GXF_SUCCESS;
+}
+
+} // namespace cvcore
+} // namespace nvidia
diff --git a/isaac_ros_ess/gxf/ess/ESSRegistry.cpp b/isaac_ros_ess/gxf/ess/ESSRegistry.cpp
new file mode 100644
index 0000000..d99b5b4
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/ESSRegistry.cpp
@@ -0,0 +1,27 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#include "extensions/ess/ESS.hpp"
+#include "gxf/std/extension_factory_helper.hpp"
+
+GXF_EXT_FACTORY_BEGIN()
+GXF_EXT_FACTORY_SET_INFO(0xfa198e2ff99642fc, 0x8fda0d23c0251610, "NvCvESSExtension", "CVCORE ESS module", "Nvidia_Gxf",
+ "1.0.1", "LICENSE");
+
+GXF_EXT_FACTORY_ADD(0x1aa1eea914344afe, 0x97fddaaedb594120, nvidia::cvcore::ESS, nvidia::gxf::Codelet,
+ "ESS GXF Extension");
+GXF_EXT_FACTORY_END()
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Array.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Array.h
new file mode 100644
index 0000000..c9f23d8
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Array.h
@@ -0,0 +1,386 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CVCORE_ARRAY_H
+#define CVCORE_ARRAY_H
+
+#include
+#include
+#include
+
+namespace cvcore {
+
+/**
+ * Base implementation of Array.
+ */
+class ArrayBase
+{
+public:
+ /**
+ * Constructor of a non-owning arrays.
+ * @param capacity capacity of the array.
+ * @param elemSize byte size of each element.
+ * @param dataPtr data pointer to the raw source array.
+ * @param isCPU whether to allocate the array on CPU or GPU.
+ */
+ ArrayBase(std::size_t capacity, std::size_t elemSize, void *dataPtr, bool isCPU);
+
+ /**
+ * Constructor of a memory-owning arrays
+ * @param capacity capacity of the array.
+ * @param elemSize byte size of each element.
+ * @param isCPU whether to allocate the array on CPU or GPU.
+ */
+ ArrayBase(std::size_t capacity, std::size_t elemSize, bool isCPU);
+
+ /**
+ * Destructor of ArrayBase.
+ */
+ ~ArrayBase();
+
+ /**
+ * ArrayBase is non-copyable.
+ */
+ ArrayBase(const ArrayBase &) = delete;
+
+ /**
+ * ArrayBase is non-copyable.
+ */
+ ArrayBase &operator=(const ArrayBase &) = delete;
+
+ /**
+ * Move constructor of ArrayBase.
+ */
+ ArrayBase(ArrayBase &&);
+
+ /**
+ * Move assignment operator of ArrayBase.
+ */
+ ArrayBase &operator=(ArrayBase &&);
+
+ /**
+ * Get the pointer to specified index.
+ * @param idx element index.
+ * @return pointer to the specified element.
+ */
+ void *getElement(int idx) const;
+
+ /**
+ * Get the size of the array.
+ * @return size of the array.
+ */
+ std::size_t getSize() const;
+
+ /**
+ * Get the capacity of the array.
+ * @return size of the array.
+ */
+ std::size_t getCapacity() const;
+
+ /**
+ * Get the size of each element.
+ * @return size of each element.
+ */
+ std::size_t getElementSize() const;
+
+ /**
+ * Set the size of the array.
+ * @param size size of the array.
+ */
+ void setSize(std::size_t size);
+
+ /**
+ * Get the flag whether the array is CPU or GPU array.
+ * @return whether the array is CPU array.
+ */
+ bool isCPU() const;
+
+ /**
+ * Get the flag whether the array is owning memory space.
+ * @return whether the array owns memory.
+ */
+ bool isOwning() const;
+
+ /**
+ * Get the raw pointer to the array data.
+ * @return void pointer to the first element of the array.
+ */
+ void *getData() const;
+
+private:
+ ArrayBase();
+
+ void *m_data;
+ std::size_t m_size;
+ std::size_t m_capacity;
+ std::size_t m_elemSize;
+ bool m_isOwning;
+ bool m_isCPU;
+};
+
+/**
+ * Implementation of Array class.
+ * @tparam T type of element in array.
+ */
+template
+class Array : public ArrayBase
+{
+public:
+ /**
+ * Default constructor of an array.
+ */
+ Array()
+ : ArrayBase{0, sizeof(T), nullptr, true}
+ {
+ }
+
+ /**
+ * Constructor of a non-owning array.
+ * @param size size of the array.
+ * @param capacity capacity of the array.
+ * @param dataPtr data pointer to the raw source array.
+ * @param isCPU whether to allocate array on CPU or GPU.
+ */
+ Array(std::size_t size, std::size_t capacity, void *dataPtr, bool isCPU = true)
+ : ArrayBase{capacity, sizeof(T), dataPtr, isCPU}
+ {
+ ArrayBase::setSize(size);
+ }
+
+ /**
+ * Constructor of a memory-owning array.
+ * @param capacity capacity of the array.
+ * @param isCPU whether to allocate array on CPU or GPU.
+ */
+ Array(std::size_t capacity, bool isCPU = true)
+ : ArrayBase{capacity, sizeof(T), isCPU}
+ {
+ }
+
+ /**
+ * Destructor of the Array.
+ */
+ ~Array()
+ {
+ // call resize here such that CPU-based destructor
+ // will call destructors of the objects stored
+ // in the array before deallocating the storage
+ setSize(0);
+ }
+
+ /**
+ * Array is non-copyable.
+ */
+ Array(const Array &) = delete;
+
+ /**
+ * Array is non-copyable.
+ */
+ Array &operator=(const Array &) = delete;
+
+ /**
+ * Move constructor of Array.
+ */
+ Array(Array &&t)
+ : Array()
+ {
+ *this = std::move(t);
+ }
+
+ /**
+ * Move assignment operator of Array.
+ */
+ Array &operator=(Array &&t)
+ {
+ static_cast(*this) = std::move(t);
+ return *this;
+ }
+
+ /**
+ * Set size of the Array.
+ * @param size size of the Array.
+ */
+ void setSize(std::size_t size)
+ {
+ const std::size_t oldSize = getSize();
+ ArrayBase::setSize(size);
+ if (isCPU())
+ {
+ // shrinking case
+ for (std::size_t i = size; i < oldSize; ++i)
+ {
+ reinterpret_cast(getElement(i))->~T();
+ }
+ // expanding case
+ for (std::size_t i = oldSize; i < size; ++i)
+ {
+ new (getElement(i)) T;
+ }
+ }
+ }
+
+ /**
+ * Const array index operator.
+ * @param idx index of element.
+ * @return const reference to the specified element.
+ */
+ const T &operator[](int idx) const
+ {
+ assert(idx >= 0 && idx < getSize());
+ return *reinterpret_cast(getElement(idx));
+ }
+
+ /**
+ * Array index operator.
+ * @param idx index of element.
+ * @return reference to the specified element.
+ */
+ T &operator[](int idx)
+ {
+ assert(idx >= 0 && idx < getSize());
+ return *reinterpret_cast(getElement(idx));
+ }
+};
+
+/**
+ * Implementation of ArrayN class.
+ * @tparam T type of element in array.
+ * @tparam N capacity of array.
+ */
+template
+class ArrayN : public ArrayBase
+{
+public:
+ /**
+ * Default constructor of ArrayN (create an owning Tensor with capacity N).
+ */
+ ArrayN()
+ : ArrayBase{N, sizeof(T), true}
+ {
+ setSize(N);
+ }
+
+ /**
+ * Constructor of a non-owning ArrayN.
+ * @param size size of the array.
+ * @param dataPtr data pointer to the raw source array.
+ * @param isCPU whether to allocate array on CPU or GPU.
+ */
+ ArrayN(std::size_t size, void *dataPtr, bool isCPU = true)
+ : ArrayBase{N, sizeof(T), dataPtr, isCPU}
+ {
+ ArrayBase::setSize(size);
+ }
+
+ /**
+ * Constructor of a memory-owning ArrayN.
+ * @param isCPU whether to allocate array on CPU or GPU.
+ */
+ ArrayN(bool isCPU)
+ : ArrayBase{N, sizeof(T), isCPU}
+ {
+ setSize(N);
+ }
+
+ /**
+ * Destructor of the ArrayN.
+ */
+ ~ArrayN()
+ {
+ // call resize here such that CPU-based destructor
+ // will call destructors of the objects stored
+ // in the array before deallocating the storage
+ setSize(0);
+ }
+
+ /**
+ * ArrayN is non-copyable.
+ */
+ ArrayN(const ArrayN &) = delete;
+
+ /**
+ * ArrayN is non-copyable.
+ */
+ ArrayN &operator=(const ArrayN &) = delete;
+
+ /**
+ * Move constructor of ArrayN.
+ */
+ ArrayN(ArrayN &&t)
+ : ArrayN()
+ {
+ *this = std::move(t);
+ }
+
+ /**
+ * Move assignment operator of ArrayN.
+ */
+ ArrayN &operator=(ArrayN &&t)
+ {
+ static_cast(*this) = std::move(t);
+ return *this;
+ }
+
+ /**
+ * Set size of the ArrayN.
+ * @param size size of the ArrayN.
+ */
+ void setSize(std::size_t size)
+ {
+ const std::size_t oldSize = getSize();
+ ArrayBase::setSize(size);
+ if (isCPU())
+ {
+ // shrinking case
+ for (std::size_t i = size; i < oldSize; ++i)
+ {
+ reinterpret_cast(getElement(i))->~T();
+ }
+ // expanding case
+ for (std::size_t i = oldSize; i < size; ++i)
+ {
+ new (getElement(i)) T;
+ }
+ }
+ }
+
+ /**
+ * Const ArrayN index operator.
+ * @param idx index of element.
+ * @return const reference to the specified element.
+ */
+ const T &operator[](int idx) const
+ {
+ assert(idx >= 0 && idx < getSize());
+ return *reinterpret_cast(getElement(idx));
+ }
+
+ /**
+ * ArrayN index operator.
+ * @param idx index of element.
+ * @return reference to the specified element.
+ */
+ T &operator[](int idx)
+ {
+ assert(idx >= 0 && idx < getSize());
+ return *reinterpret_cast(getElement(idx));
+ }
+};
+
+} // namespace cvcore
+
+#endif // CVCORE_ARRAY_H
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/BBox.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/BBox.h
new file mode 100644
index 0000000..93100d3
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/BBox.h
@@ -0,0 +1,142 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CVCORE_BBOX_H
+#define CVCORE_BBOX_H
+
+#include
+#include
+#include
+
+namespace cvcore {
+
+/**
+ * A struct.
+ * Structure used to store bounding box.
+ */
+struct BBox
+{
+ int xmin{0}; /**< minimum x coordinate. */
+ int ymin{0}; /**< minimum y coordinate. */
+ int xmax{0}; /**< maximum x coordinate. */
+ int ymax{0}; /**< maximum y coordinate. */
+
+ /**
+ * Clamp a bounding box based on a restricting clamp box
+ * @param Clamping bounding box (xmin, ymin, xmax, ymax)
+ * @return Clamped bounding box
+ */
+ BBox clamp(const BBox &clampBox) const
+ {
+ BBox outbox;
+ outbox.xmin = std::max(clampBox.xmin, xmin);
+ outbox.xmax = std::min(clampBox.xmax, xmax);
+ outbox.ymin = std::max(clampBox.ymin, ymin);
+ outbox.ymax = std::min(clampBox.ymax, ymax);
+ return outbox;
+ }
+
+ /**
+ * @return Width of the bounding box
+ */
+ size_t getWidth() const
+ {
+ return xmax - xmin;
+ }
+
+ /**
+ * @return Height of the bounding box
+ */
+ size_t getHeight() const
+ {
+ return ymax - ymin;
+ }
+
+ /**
+ * Checks if the bounding box is valid.
+ */
+ bool isValid() const
+ {
+ return (xmin < xmax) && (ymin < ymax) && (getWidth() > 0) && (getHeight() > 0);
+ }
+
+ /**
+ * Returns the center of the bounding box
+ * @return X,Y coordinate tuple
+ */
+ std::pair getCenter() const
+ {
+ int centerX = xmin + getWidth() / 2;
+ int centerY = ymin + getHeight() / 2;
+ return std::pair(centerX, centerY);
+ }
+
+ /**
+ * Scales bounding box based along the width and height retaining the same center.
+ * @param Scale in X direction along the width
+ * @param Scale in Y direction along the height
+ * @return Scaled bounding box
+ */
+ BBox scale(float scaleW, float scaleH) const
+ {
+ auto center = getCenter();
+ float newW = getWidth() * scaleW;
+ float newH = getHeight() * scaleH;
+ BBox outbox;
+ outbox.xmin = center.first - newW / 2;
+ outbox.xmax = center.first + newW / 2;
+ outbox.ymin = center.second - newH / 2;
+ outbox.ymax = center.second + newH / 2;
+
+ return outbox;
+ }
+
+ /**
+ * Resizes bounding box to a square bounding box based on
+ * the longest edge and clamps the bounding box based on the limits provided.
+ * @param Clamping bounding box (xmin, ymin, xmax, ymax)
+ * @return Sqaure bounding box
+ */
+ BBox squarify(const BBox &clampBox) const
+ {
+ size_t w = getWidth();
+ size_t h = getHeight();
+
+ BBox clampedBox1 = clamp(clampBox);
+ if (!clampedBox1.isValid())
+ {
+ throw std::range_error("Invalid bounding box generated\n");
+ }
+ float scaleW = static_cast(std::max(w, h)) / w;
+ float scaleH = static_cast(std::max(w, h)) / h;
+ BBox scaledBBox = clampedBox1.scale(scaleW, scaleH);
+ BBox clampedBox2 = scaledBBox.clamp(clampBox);
+ if (!clampedBox2.isValid())
+ {
+ throw std::range_error("Invalid bounding box generated\n");
+ }
+ size_t newW = clampedBox2.getWidth();
+ size_t newH = clampedBox2.getHeight();
+ size_t minW = std::min(newH, newW);
+ clampedBox2.ymax = clampedBox2.ymin + minW;
+ clampedBox2.xmax = clampedBox2.xmin + minW;
+ return clampedBox2;
+ }
+};
+
+} // namespace cvcore
+#endif // CVCORE_BBOX_H
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/CVError.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/CVError.h
new file mode 100644
index 0000000..82c16c1
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/CVError.h
@@ -0,0 +1,116 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CVCORE_CVERROR_H
+#define CVCORE_CVERROR_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+namespace cvcore {
+
+// CVCORE ERROR CODES
+// -----------------------------------------------------------------------------
+// Defining the CVCORE Error Codes on std::error_condition
+// std::error_condition creates a set of sub-system independent codes which may
+// be used to describe ANY downstream error in a broad sense. An std::error_code
+// is defined within the sub-system context (i.e. tensor_ops, trtbackend, ...)
+// which is mapped to the cvcore::ErrorCode.
+// As an example, cvcore::ErrorCode -1 may not ABSOLUTELY mean the same as
+// tensor_ops::FaultCode -1, but does mean the same as tensor_ops:FaultCode 4.
+// Thus, tensor_ops::FaultCode 4 needs to be mapped to cvcore::ErrorCode -1.
+enum class ErrorCode : std::int32_t
+{
+ SUCCESS = 0,
+ NOT_READY,
+ NOT_IMPLEMENTED,
+ INVALID_ARGUMENT,
+ INVALID_IMAGE_FORMAT,
+ INVALID_STORAGE_TYPE,
+ INVALID_ENGINE_TYPE,
+ INVALID_OPERATION,
+ DETECTED_NAN_IN_RESULT,
+ OUT_OF_MEMORY,
+ DEVICE_ERROR,
+ SYSTEM_ERROR,
+};
+
+} // namespace cvcore
+
+// WARNING: Extending base C++ namespace to cover cvcore error codes
+namespace std {
+
+template<>
+struct is_error_condition_enum : true_type
+{
+};
+
+template<>
+struct is_error_code_enum : true_type
+{
+};
+
+} // namespace std
+
+namespace cvcore {
+
+std::error_condition make_error_condition(ErrorCode) noexcept;
+
+std::error_code make_error_code(ErrorCode) noexcept;
+
+// -----------------------------------------------------------------------------
+
+inline void CheckCudaError(cudaError_t code, const char *file, const int line)
+{
+ if (code != cudaSuccess)
+ {
+ const char *errorMessage = cudaGetErrorString(code);
+ const std::string message = "CUDA error returned at " + std::string(file) + ":" + std::to_string(line) +
+ ", Error code: " + std::to_string(code) + " (" + std::string(errorMessage) + ")";
+ throw std::runtime_error(message);
+ }
+}
+
+inline void CheckErrorCode(std::error_code err, const char *file, const int line)
+{
+ const std::string message = "Error returned at " + std::string(file) + ":" + std::to_string(line) +
+ ", Error code: " + std::string(err.message());
+
+ if (err != cvcore::make_error_code(cvcore::ErrorCode::SUCCESS))
+ {
+ throw std::runtime_error(message);
+ }
+}
+
+} // namespace cvcore
+
+#define CHECK_ERROR(val) \
+ { \
+ cvcore::CheckCudaError((val), __FILE__, __LINE__); \
+ }
+
+#define CHECK_ERROR_CODE(val) \
+ { \
+ cvcore::CheckErrorCode((val), __FILE__, __LINE__); \
+ }
+
+#endif // CVCORE_CVERROR_H
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/CameraModel.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/CameraModel.h
new file mode 100644
index 0000000..157acf4
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/CameraModel.h
@@ -0,0 +1,292 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CVCORE_CAMERAMODEL_H
+#define CVCORE_CAMERAMODEL_H
+
+#include
+
+#include "cv/core/Array.h"
+#include "cv/core/MathTypes.h"
+
+namespace cvcore {
+
+/**
+ * An enum.
+ * Enum type for Camera Distortion type.
+ */
+enum class CameraDistortionType : uint8_t
+{
+ UNKNOWN, /**< Unknown arbitrary distortion model. */
+ NONE, /**< No distortion applied. */
+ Polynomial, /**< Polynomial distortion model. */
+ FisheyeEquidistant, /**< Equidistant Fisheye distortion model. */
+ FisheyeEquisolid, /**< Equisolid Fisheye distortion model. */
+ FisheyeOrthoGraphic, /**< Orthographic Fisheye distortion model. */
+ FisheyeStereographic /**< Stereographic Fisheye distortion model. */
+};
+
+/**
+ * Struct type used to store Camera Distortion model type and coefficients.
+ */
+struct CameraDistortionModel
+{
+ CameraDistortionType type; /**< Camera distortion model type. */
+ union /**< Camera distortion model coefficients. */
+ {
+ float coefficients[8];
+ struct
+ {
+ float k1, k2, k3, k4, k5, k6;
+ float p1, p2;
+ };
+ };
+
+ CameraDistortionModel()
+ : type(CameraDistortionType::UNKNOWN),
+ k1(0.0), k2(0.0), k3(0.0), k4(0.0), k5(0.0), k6(0.0),
+ p1(0.0), p2(0.0) {}
+
+ /**
+ * Camera Distortion Model creation using array of coefficients.
+ * @param distortionType Camera distortion model type
+ * @param distortionCoefficients An array of camera distortion model coefficients
+ * @return Camera Distortion Model
+ */
+ CameraDistortionModel(CameraDistortionType distortionType, std::array & distortionCoefficients)
+ : type(distortionType)
+ {
+ std::copy(distortionCoefficients.begin(), distortionCoefficients.end(), std::begin(coefficients));
+ }
+
+ /**
+ * Camera Distortion Model creation using individual coefficients.
+ * @param distortionType Camera distortion model type
+ * @param k1 Camera distortion model coefficient - k1
+ * @param k2 Camera distortion model coefficient - k2
+ * @param k3 Camera distortion model coefficient - k3
+ * @param k4 Camera distortion model coefficient - k4
+ * @param k5 Camera distortion model coefficient - k5
+ * @param k6 Camera distortion model coefficient - k6
+ * @param p1 Camera distortion model coefficient - p1
+ * @param p2 Camera distortion model coefficient - p2
+ * @return Camera Distortion Model
+ */
+ CameraDistortionModel(CameraDistortionType distortionType, float k1, float k2, float k3, \
+ float k4, float k5, float k6, float p1, float p2)
+ : type(distortionType)
+ , k1(k1)
+ , k2(k2)
+ , k3(k3)
+ , k4(k4)
+ , k5(k5)
+ , k6(k6)
+ , p1(p1)
+ , p2(p2)
+ {
+
+ }
+
+ /**
+ * Get camera distortion model type.
+ * @return Camera distortion model type
+ */
+ CameraDistortionType getDistortionType() const
+ {
+ return type;
+ }
+
+ /**
+ * Get camera distortion model coefficients.
+ * @return Camera distortion model coefficients array
+ */
+ const float * getCoefficients() const
+ {
+ return &coefficients[0];
+ }
+
+ inline bool operator==(const CameraDistortionModel & other) const noexcept
+ {
+ return this->k1 == other.k1 &&
+ this->k2 == other.k2 &&
+ this->k3 == other.k3 &&
+ this->k4 == other.k4 &&
+ this->k5 == other.k5 &&
+ this->k6 == other.k6 &&
+ this->p1 == other.p1 &&
+ this->p2 == other.p2;
+ }
+
+ inline bool operator!=(const CameraDistortionModel & other) const noexcept
+ {
+ return !(*this == other);
+ }
+};
+
+/**
+ * Struct type used to store Camera Intrinsics.
+ */
+struct CameraIntrinsics
+{
+ CameraIntrinsics() = default;
+
+ /**
+ * Camera Instrinsics creation with given intrinsics values
+ * @param fx Camera axis x focal length in pixels
+ * @param fy Camera axis y focal length in pixels
+ * @param cx Camera axis x principal point in pixels
+ * @param cy Camera axis y principal point in pixels
+ * @param s Camera slanted pixel
+ * @return Camera Intrinsics
+ */
+ CameraIntrinsics(float fx, float fy, float cx, float cy, float s = 0.0)
+ {
+ m_intrinsics[0][0] = fx;
+ m_intrinsics[0][1] = s;
+ m_intrinsics[0][2] = cx;
+ m_intrinsics[1][0] = 0.0;
+ m_intrinsics[1][1] = fy;
+ m_intrinsics[1][2] = cy;
+ }
+
+ /**
+ * Get camera intrinsics x focal length.
+ * @return Camera x focal length
+ */
+ float fx() const
+ {
+ return m_intrinsics[0][0];
+ }
+
+ /**
+ * Get camera intrinsics y focal length.
+ * @return Camera y focal length
+ */
+ float fy() const
+ {
+ return m_intrinsics[1][1];
+ }
+
+ /**
+ * Get camera intrinsics x principal point.
+ * @return Camera x principal point
+ */
+ float cx() const
+ {
+ return m_intrinsics[0][2];
+ }
+
+ /**
+ * Get camera intrinsics y principal point.
+ * @return Camera y principal point
+ */
+ float cy() const
+ {
+ return m_intrinsics[1][2];
+ }
+
+ /**
+ * Get camera intrinsics slanted pixels.
+ * @return Camera slanted pixels
+ */
+ float skew() const
+ {
+ return m_intrinsics[0][1];
+ }
+
+ /**
+ * Get camera intrinsics 2D array.
+ * @return Camera intrisics array
+ */
+ const float * getMatrix23() const
+ {
+ return &m_intrinsics[0][0];
+ }
+
+ inline bool operator==(const CameraIntrinsics & other) const noexcept
+ {
+ return m_intrinsics[0][0] == other.m_intrinsics[0][0] &&
+ m_intrinsics[0][1] == other.m_intrinsics[0][1] &&
+ m_intrinsics[0][2] == other.m_intrinsics[0][2] &&
+ m_intrinsics[1][0] == other.m_intrinsics[1][0] &&
+ m_intrinsics[1][1] == other.m_intrinsics[1][1] &&
+ m_intrinsics[1][2] == other.m_intrinsics[1][2];
+ }
+
+ inline bool operator!=(const CameraIntrinsics & other) const noexcept
+ {
+ return !(*this == other);
+ }
+
+ float m_intrinsics[2][3] {{1.0, 0.0, 0.0},{0.0, 1.0, 0.0}}; /**< Camera intrinsics 2D arrat. */
+};
+
+/**
+ * Struct type used to store Camera Extrinsics.
+ */
+struct CameraExtrinsics
+{
+ using RawMatrixType = float[3][4];
+
+ CameraExtrinsics() = default;
+
+ /**
+ * Camera Extrinsics creation with given extrinsics as raw 2D [3 x 4] array
+ * @param extrinsics Camera extrinsics as raw 2D array
+ * @return Camera Extrinsics
+ */
+ explicit CameraExtrinsics(const RawMatrixType & extrinsics)
+ {
+ std::copy(&extrinsics[0][0], &extrinsics[0][0] + 3 * 4, &m_extrinsics[0][0]);
+ }
+
+ inline bool operator==(const CameraExtrinsics & other) const noexcept
+ {
+ return m_extrinsics[0][0] == other.m_extrinsics[0][0] &&
+ m_extrinsics[0][1] == other.m_extrinsics[0][1] &&
+ m_extrinsics[0][2] == other.m_extrinsics[0][2] &&
+ m_extrinsics[0][3] == other.m_extrinsics[0][3] &&
+ m_extrinsics[1][0] == other.m_extrinsics[1][0] &&
+ m_extrinsics[1][1] == other.m_extrinsics[1][1] &&
+ m_extrinsics[1][2] == other.m_extrinsics[1][2] &&
+ m_extrinsics[1][3] == other.m_extrinsics[1][3] &&
+ m_extrinsics[2][0] == other.m_extrinsics[2][0] &&
+ m_extrinsics[2][1] == other.m_extrinsics[2][1] &&
+ m_extrinsics[2][2] == other.m_extrinsics[2][2] &&
+ m_extrinsics[2][3] == other.m_extrinsics[2][3];
+ }
+
+ inline bool operator!=(const CameraExtrinsics & other) const noexcept
+ {
+ return !(*this == other);
+ }
+
+ RawMatrixType m_extrinsics {{1.0, 0.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0, 0.0},
+ {0.0, 0.0, 1.0, 0.0}};
+};
+
+struct CameraModel
+{
+ CameraIntrinsics intrinsic;
+ CameraExtrinsics extrinsic;
+ CameraDistortionModel distortion;
+};
+
+} // namespace cvcore
+
+#endif // CVCORE_CAMERAMODEL_H
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/ComputeEngine.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/ComputeEngine.h
new file mode 100644
index 0000000..65fe7ca
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/ComputeEngine.h
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CVCORE_COMPUTEENGINE_H
+#define CVCORE_COMPUTEENGINE_H
+
+#include
+
+namespace cvcore {
+
+enum class ComputeEngine : unsigned int
+{
+ UNKNOWN = 0x00, // 0000_0000
+
+ CPU = 0x01, // 0000_0001
+ PVA = 0x02, // 0000_0010
+ VIC = 0x04, // 0000_0100
+ NVENC = 0x08, // 0000_1000
+ GPU = 0x10, // 0001_0000
+ DLA = 0x20, // 0010_0000
+ DLA_CORE_0 = 0x40, // 0100_0000
+ DLA_CORE_1 = 0x80, // 1000_0000
+
+ COMPUTE_FAULT = 0xFF // 1111_1111
+};
+
+} // namespace cvcore
+
+#endif // CVCORE_COMPUTEENGINE_H
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Core.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Core.h
new file mode 100644
index 0000000..42732d9
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Core.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CORE_H
+#define CORE_H
+
+namespace cvcore {
+
+// Enable dll imports/exports in case of windows support
+#ifdef _WIN32
+#ifdef CVCORE_EXPORT_SYMBOLS // Needs to be enabled in case of compiling dll
+#define CVCORE_API __declspec(dllexport) // Exports symbols when compiling the library.
+#else
+#define CVCORE_API __declspec(dllimport) // Imports the symbols when linked with library.
+#endif
+#else
+#define CVCORE_API
+#endif
+
+} // namespace cvcore
+#endif // CORE_H
diff --git a/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Image.h b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Image.h
new file mode 100644
index 0000000..263a699
--- /dev/null
+++ b/isaac_ros_ess/gxf/ess/cvcore/include/cv/core/Image.h
@@ -0,0 +1,893 @@
+// SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
+// Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef CVCORE_IMAGE_H
+#define CVCORE_IMAGE_H
+
+#include
+#include
+#include
+#include
+
+#include "Memory.h"
+#include "Tensor.h"
+
+namespace cvcore {
+
+/**
+ * An enum.
+ * Enum type for image type.
+ */
+enum ImageType
+{
+ Y_U8, /**< 8-bit unsigned gray. */
+ Y_U16, /**< 16-bit unsigned gray. */
+ Y_S8, /**< 8-bit signed gray. */
+ Y_S16, /**< 16-bit signed gray. */
+ Y_F16, /**< half normalized gray. */
+ Y_F32, /**< float normalized gray. */
+ RGB_U8, /**< 8-bit RGB. */
+ RGB_U16, /**< 16-bit RGB. */
+ RGB_F16, /**< half RGB. */
+ RGB_F32, /**< float RGB. */
+ BGR_U8, /**< 8-bit BGR. */
+ BGR_U16, /**< 16-bit BGR. */
+ BGR_F16, /**< half BGR. */
+ BGR_F32, /**< float BGR. */
+ RGBA_U8, /**< 8-bit RGBA. */
+ RGBA_U16, /**< 16-bit RGBA. */
+ RGBA_F16, /**< half RGBA. */
+ RGBA_F32, /**< float RGBA. */
+ PLANAR_RGB_U8, /**< 8-bit planar RGB. */
+ PLANAR_RGB_U16, /**< 16-bit planar RGB. */
+ PLANAR_RGB_F16, /**< half planar RGB. */
+ PLANAR_RGB_F32, /**< float planar RGB. */
+ PLANAR_BGR_U8, /**< 8-bit planar BGR. */
+ PLANAR_BGR_U16, /**< 16-bit planar BGR. */
+ PLANAR_BGR_F16, /**< half planar BGR. */
+ PLANAR_BGR_F32, /**< float planar BGR. */
+ PLANAR_RGBA_U8, /**< 8-bit planar RGBA. */
+ PLANAR_RGBA_U16, /**< 16-bit planar RGBA. */
+ PLANAR_RGBA_F16, /**< half planar RGBA. */
+ PLANAR_RGBA_F32, /**< float planar RGBA. */
+ NV12, /**< 8-bit planar Y + interleaved and subsampled (1/4 Y samples) UV. */
+ NV24, /**< 8-bit planar Y + interleaved UV. */
+};
+
+/**
+ * Struct type for image preprocessing params
+ */
+struct ImagePreProcessingParams
+{
+ ImageType imgType; /**< Input Image Type. */
+ float pixelMean[3]; /**< Image Mean value offset for R,G,B channels. Default is 0.0f */
+ float normalization[3]; /**< Scale or normalization values for R,G,B channels. Default is 1.0/255.0f */
+ float stdDev[3]; /**< Standard deviation values for R,G,B channels. Default is 1.0f */
+};
+
+template
+struct IsCompositeImage : std::integral_constant
+{
+};
+
+template
+struct IsPlanarImage
+ : std::integral_constant
+{
+};
+
+template
+struct IsInterleavedImage : std::integral_constant::value && !IsPlanarImage::value>
+{
+};
+
+/**
+ * Image traits that map ImageType to TensorLayout, ChannelCount and ChannelType.
+ */
+template
+struct ImageTraits;
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::S8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::S8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::S16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::S16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C1;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::HWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NHWC;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::CHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NCHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::CHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NCHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::CHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NCHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::CHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NCHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U8;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::CHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NCHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::U16;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::CHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+template<>
+struct ImageTraits
+{
+ static constexpr TensorLayout TL = TensorLayout::NCHW;
+ static constexpr ChannelCount CC = ChannelCount::C3;
+ static constexpr ChannelType CT = ChannelType::F32;
+};
+
+/**
+ * Get the bytes of each element for a specific ImageType.
+ */
+inline size_t GetImageElementSize(const ImageType type)
+{
+ size_t imageElementSize;
+
+ switch (type)
+ {
+ case ImageType::Y_U8:
+ case ImageType::Y_S8:
+ case ImageType::RGB_U8:
+ case ImageType::BGR_U8:
+ case ImageType::RGBA_U8:
+ case ImageType::PLANAR_RGB_U8:
+ case ImageType::PLANAR_BGR_U8:
+ case ImageType::PLANAR_RGBA_U8:
+ {
+ imageElementSize = 1;
+ break;
+ }
+ case ImageType::Y_U16:
+ case ImageType::Y_S16:
+ case ImageType::RGB_U16:
+ case ImageType::BGR_U16:
+ case ImageType::RGBA_U16:
+ case ImageType::PLANAR_RGB_U16:
+ case ImageType::PLANAR_BGR_U16:
+ case ImageType::PLANAR_RGBA_U16:
+ case ImageType::Y_F16:
+ case ImageType::RGB_F16:
+ case ImageType::BGR_F16:
+ case ImageType::RGBA_F16:
+ case ImageType::PLANAR_RGB_F16:
+ case ImageType::PLANAR_BGR_F16:
+ case ImageType::PLANAR_RGBA_F16:
+ {
+ imageElementSize = 2;
+ break;
+ }
+ case ImageType::Y_F32:
+ case ImageType::RGB_F32:
+ case ImageType::BGR_F32:
+ case ImageType::RGBA_F32:
+ case ImageType::PLANAR_RGB_F32:
+ case ImageType::PLANAR_BGR_F32:
+ case ImageType::PLANAR_RGBA_F32:
+ {
+ imageElementSize = 4;
+ break;
+ }
+ default:
+ {
+ imageElementSize = 0;
+ }
+ }
+
+ return imageElementSize;
+}
+
+/**
+ * Get the number of channels for a specific ImageType.
+ */
+inline size_t GetImageChannelCount(const ImageType type)
+{
+ size_t imageChannelCount;
+
+ switch (type)
+ {
+ case ImageType::Y_U8:
+ case ImageType::Y_U16:
+ case ImageType::Y_S8:
+ case ImageType::Y_S16:
+ case ImageType::Y_F16:
+ case ImageType::Y_F32:
+ {
+ imageChannelCount = 1;
+ break;
+ }
+ case ImageType::RGB_U8:
+ case ImageType::RGB_U16:
+ case ImageType::RGB_F16:
+ case ImageType::RGB_F32:
+ case ImageType::BGR_U8:
+ case ImageType::BGR_U16:
+ case ImageType::BGR_F16:
+ case ImageType::BGR_F32:
+ case ImageType::PLANAR_RGB_U8:
+ case ImageType::PLANAR_RGB_U16:
+ case ImageType::PLANAR_RGB_F16:
+ case ImageType::PLANAR_RGB_F32:
+ case ImageType::PLANAR_BGR_U8:
+ case ImageType::PLANAR_BGR_U16:
+ case ImageType::PLANAR_BGR_F16:
+ case ImageType::PLANAR_BGR_F32:
+ {
+ imageChannelCount = 3;
+ break;
+ }
+ case ImageType::RGBA_U8:
+ case ImageType::RGBA_U16:
+ case ImageType::RGBA_F16:
+ case ImageType::RGBA_F32:
+ case ImageType::PLANAR_RGBA_U8:
+ case ImageType::PLANAR_RGBA_U16:
+ case ImageType::PLANAR_RGBA_F16:
+ case ImageType::PLANAR_RGBA_F32:
+ {
+ imageChannelCount = 4;
+ break;
+ }
+ default:
+ {
+ imageChannelCount = 0;
+ }
+ }
+
+ return imageChannelCount;
+};
+
+template
+class Image
+{
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image : public Tensor
+{
+ using Tensor::Tensor;
+};
+
+template<>
+class Image