From 0297c81759efdfa857d8c6698753d7c903119d44 Mon Sep 17 00:00:00 2001 From: Momoko Kono Date: Mon, 17 Mar 2025 14:41:58 -0700 Subject: [PATCH 1/3] added cuda tutorial for v24.05 --- cuda/README.md | 16 ++++ cuda/cuda-ion-setup.sh | 135 +++++++++++++++++++++++++++++ cuda/src/load_and_process.cpp | 155 ++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 cuda/README.md create mode 100644 cuda/cuda-ion-setup.sh create mode 100644 cuda/src/load_and_process.cpp diff --git a/cuda/README.md b/cuda/README.md new file mode 100644 index 0000000..35d5ad8 --- /dev/null +++ b/cuda/README.md @@ -0,0 +1,16 @@ +# CUDA tutorial + +## Setup + +The Sensing-Dev SDK install script introduced in [Sensing-Dev](https://sensing-dev.github.io/doc/) has ion-kit but target-CUDA feature is not available. + +**After installing either Sensing-Dev v24.05 or v25.01**, please run the `cuda-ion-setup.sh` which build and install ion-kit with the option of CUDA. + +```bash +sudo bash cuda-ion-setup.sh +``` +If you are using Sensing-Dev v24.05, please add the option of `--version v1.8.10`. + +Note that this install script is designed for Linux x86_64. + +After setting up, you can remove the directory called `cuda-setup`. diff --git a/cuda/cuda-ion-setup.sh b/cuda/cuda-ion-setup.sh new file mode 100644 index 0000000..d44c86f --- /dev/null +++ b/cuda/cuda-ion-setup.sh @@ -0,0 +1,135 @@ +#!/bin/bash +set -e + +: ' +SYNOPSIS + build_install_lib.sh [OPTIONS] + +DESCRIPTION + This script installs VCPKG, fetches a library from GitHub, builds it, and installs it. + +OPTIONS + --vcpkg-dir DIR Set the installation directory for VCPKG (default: $HOME/vcpkg) + --lib-dir DIR Set the directory for library installation (default: $HOME/libs) + --tag TAG Specify the branch or tag to checkout (default: latest release) + --install-path DIR Set the installation directory for Sensing-Dev (ion-kit) +' +# DEFAULT ###################################################################### +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WORKING_DIR="$SCRIPT_DIR/cuda-setup" +VCPKG_DIR="$WORKING_DIR/vcpkg" +GITHUB_REPO="fixstars/ion-kit" +BRANCH_OR_TAG="latest" +SDK_DIR="/opt/sensing-dev" + + +# VCPKG ######################################################################## +while [[ "$#" -gt 0 ]]; do + case "$1" in + --vcpkg-dir) + VCPKG_DIR="$2" + shift 2 + ;; + --lib-dir) + LIBRARY_DIR="$2" + shift 2 + ;; + --version) + BRANCH_OR_TAG="$2" + shift 2 + ;; + --install-path) + SDK_DIR="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +if [[ "$BRANCH_OR_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || [[ "$BRANCH_OR_TAG" == "LATEST" ]]; then + echo "Valid --version: $BRANCH_OR_TAG" +else + echo "Error: --version must be in the format 'vX.Y.Z' (e.g., v1.8.10)" + exit 1 +fi + +# Get git ###################################################################### +sudo apt install git-all -y + +# Set working directory ######################################################## +mkdir -p "$WORKING_DIR" + +# VCPKG ######################################################################## +if [ ! -d "$VCPKG_DIR" ]; then + echo "Cloning VCPKG..." + git clone https://github.com/microsoft/vcpkg.git "$VCPKG_DIR" + cd "$VCPKG_DIR" || exit + ./bootstrap-vcpkg.sh +else + echo "VCPKG already installed in $VCPKG_DIR" +fi +export PATH=$VCPKG_DIR:$PATH + +# Get Halide ################################################################### +cd "$WORKING_DIR" +echo $BRANCH_OR_TAG +if [[ "$BRANCH_OR_TAG" =~ ^v1\.8\.[0-9]+$ ]]; then + # v1.8.xx の場合 + curl -L https://github.com/halide/Halide/releases/download/v16.0.0/Halide-16.0.0-x86-64-linux-1e963ff817ef0968cc25d811a25a7350c8953ee6.tar.gz --output halide.tar.gz + tar -xvzf halide.tar.gz + cd Halide-16.0.0-x86-64-linux + export HALIDE_PATH="$WORKING_DIR/Halide-16.0.0-x86-64-linux" +else + # それ以外の場合(デフォルト) + curl -L https://github.com/halide/Halide/releases/download/v17.0.1/Halide-17.0.1-x86-64-linux-52541176253e74467dabc42eeee63d9a62c199f6.tar.gz --output halide.tar.gz + tar -xvzf halide.tar.gz + cd Halide-17.0.1-x86-64-linux + export HALIDE_PATH="$WORKING_DIR/Halide-17.0.1-x86-64-linux" +fi + +# Get ion-kit ################################################################## +cd "$WORKING_DIR" || exit +echo "Fetching library from GitHub..." +if [ "$BRANCH_OR_TAG" = "latest" ]; then + LATEST_TAG=$(curl -s "https://api.github.com/repos/$GITHUB_REPO/releases/latest" | grep 'tag_name' | cut -d '"' -f 4) + BRANCH_OR_TAG="$LATEST_TAG" +fi +echo "ion-kit $BRANCH_OR_TAG will be installed..." +if [ -d "$WORKING_DIR/ion-kit" ]; then + rm -r "$WORKING_DIR/ion-kit" +fi + +git clone --branch "$BRANCH_OR_TAG" --depth 1 "https://github.com/$GITHUB_REPO.git" + + +# Build and Install ############################################################ +cd "$WORKING_DIR/ion-kit" +# Set minimum CMake 3.22 +CMAKE_FILE="$WORKING_DIR/ion-kit/CMakeLists.txt" +if [ -f "$CMAKE_FILE" ]; then + sed -i 's/cmake_minimum_required(VERSION 3\.25)/cmake_minimum_required(VERSION 3.22)/' "$CMAKE_FILE" + echo "Updated cmake_minimum_required version in CMakeLists.txt" +fi +# Set up dependencies +vcpkg install +# Build +mkdir -p build && cd build +cmake -D CMAKE_TOOLCHAIN_FILE=${VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake \ +-D Halide_DIR=${HALIDE_PATH}/lib/cmake/Halide \ +-D HalideHelpers_DIR=${HALIDE_PATH}/lib/cmake/HalideHelpers \ +-DCMAKE_BUILD_TYPE=Release -D ION_BUILD_TEST=OFF -D BUILD_DOC=OFF -D ION_BUILD_EXAMPLE=OFF \ +-D CMAKE_INSTALL_PREFIX=${SDK_DIR} .. +# Install +cmake --build . --target install + +echo "Library installation completed." + +VERSION_INFO_FILE="$SDK_DIR/version_info.json" +if [ -f "$VERSION_INFO_FILE" ]; then + sed -i "s/\"ion-kit\": \"v[0-9]*\\.[0-9]*\\.[0-9]*\"/\"ion-kit\": \"$BRANCH_OR_TAG(CUDA)\"/" "$VERSION_INFO_FILE" + sed -i "s/\"ion-kit\": \"[0-9]*\\.[0-9]*\\.[0-9]*\"/\"ion-kit\": \"$BRANCH_OR_TAG(CUDA)\"/" "$VERSION_INFO_FILE" + echo "Updated $SDK_DIR/version_info.json" +fi diff --git a/cuda/src/load_and_process.cpp b/cuda/src/load_and_process.cpp new file mode 100644 index 0000000..9d9616d --- /dev/null +++ b/cuda/src/load_and_process.cpp @@ -0,0 +1,155 @@ +/* + +g++ src/load_and_process.cpp -o load_and_process \ +-I /opt/sensing-dev/include -I /opt/sensing-dev/include/aravis-0.8 \ +-I /opt/sensing-dev/include/opencv4 \ +-L /opt/sensing-dev/lib \ +-L /opt/sensing-dev/lib/x86_64-linux-gnu \ +-lHalide -lion-core -ldl -lpthread -lopencv_core \ +-lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc \ +-laravis-0.8 -lgobject-2.0 \ +`pkg-config --cflags --libs glib-2.0` + +*/ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace ion; +std::map bit_width_map{ + {"Mono8", 8}, {"Mono10", 16}, {"Mono12", 16}, + {"BayerBG8", 8}, {"BayerBG10", 16}, {"BayerBG12", 16}}; +std::map num_bit_shift_map{ + {"Mono8", 0}, {"Mono10", 6}, {"Mono12", 4}, + {"BayerBG8", 0}, {"BayerBG10", 6}, {"BayerBG12", 4}}; +std::map bb_name{ + {"BayerBG8", "image_io_binaryloader_u8x2"}, + {"BayerBG10", "image_io_binaryloader_u16x2"}, + {"BayerBG12", "image_io_binaryloader_u16x2"}, + {"Mono8", "image_io_binaryloader_u8x2"}, + {"Mono10", "image_io_binaryloader_u16x2"}, + {"Mono12", "image_io_binaryloader_u16x2"}}; + + +void pipeline_acquisition_and_process(bool use_cuda, bool display_image, std::string output_directory, std::string prefix, int width, int height, std::string pixelformat, int num_frames){ + std::vector< int > buf_size = std::vector < int >{3, width, height}; + + std::vector> outputs; + outputs.push_back(Halide::Buffer(buf_size)); + + Buffer finished(1); + + Builder b; + if (use_cuda){ + b.set_target(get_host_target().with_feature(Target::CUDA).with_feature(Target::Profile)); + }else{ + b.set_target(get_host_target().with_feature(Target::Profile)); + } + b.with_bb_module("ion-bb"); + + // add binary loader BB to pipeline + Node n = b.add(bb_name[pixelformat])(&width, &height) + .set_param( + Param("output_directory", output_directory), + Param("prefix", prefix) + ); + n["finished"].bind(finished); + + if (bit_width_map[pixelformat] == 8){ + n = b.add("base_cast_2d_uint8_to_uint16")(n["output"]); + } + + n = b.add("image_processing_normalize_raw_image")(n["output"]) + .set_param( + Param("bit_width", bit_width_map[pixelformat]), + Param("bit_shift", num_bit_shift_map[pixelformat]) + ); + + n = b.add("image_processing_bayer_demosaic_linear")(n["output"]) + .set_param( + Param("bayer_pattern", "BGGR"), + Param("width", width), + Param("height", height) + ); // output(x, y, c) + + n = b.add("base_denormalize_3d_uint8") (n["output"]); + n = b.add("base_reorder_buffer_3d_uint8")(n["output"]) + .set_param( + Param("dim0", "2"), + Param("dim1", "0"), + Param("dim2", "1") + ); // output(c, x, y) + n["output"].bind(outputs[0]); + + int count_run = 1; + while (true) { + b.run(); + bool is_finished = finished(0); + + cv::Mat img(height, width, CV_8UC3); + std::memcpy(img.ptr(), outputs[0].data(), outputs[0].size_in_bytes()); + if (display_image){ + cv::imshow("image" + std::to_string(0), img); + } + + if (count_run == num_frames || is_finished) { + break; + } + count_run += 1; + } + std::cout << "Total number of frames to process: " << count_run << std::endl; +} + +int main(int argc, char *argv[]) +{ + try{ + // if prefix is imageX if the name of the config is imageX-config.json + std::string prefix = "image0-"; + // check imageX-config.json + const int32_t width = 1920; + const int32_t height = 1080; + std::string pixelformat = "BayerBG8"; + + bool use_cuda = false; + bool display_image = false; + std::string output_directory = "."; + int num_frames = 0; + + if (argc > 1){ + for (int i = 1; i < argc; i++){ + if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--target-cuda") == 0){ + use_cuda = true; + }else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--display") == 0){ + display_image = true; + }else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--input") == 0){ + output_directory = argv[++i]; + }else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--prefix") == 0){ + prefix = argv[++i]; + }else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--num-frames") == 0){ + num_frames = strtol(argv[++i], NULL, 10); + }else{ + std::cerr << "wrong format of command option." << std::endl; + } + } + } + + pipeline_acquisition_and_process(use_cuda, display_image, output_directory, prefix, width, height, pixelformat, num_frames); + + } catch(std::exception& e){ + std::cerr << e.what() << std::endl; + return 1; + } catch (const ion::Error& e) { + std::cerr << e.what() << std::endl; + return 1; + } + return 0; +} \ No newline at end of file From f1456c9a499c078a09e5d07d4f913720b539e6c8 Mon Sep 17 00:00:00 2001 From: Momoko Kono Date: Mon, 17 Mar 2025 14:44:22 -0700 Subject: [PATCH 2/3] fixed the case --- cuda/cuda-ion-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cuda/cuda-ion-setup.sh b/cuda/cuda-ion-setup.sh index d44c86f..6080672 100644 --- a/cuda/cuda-ion-setup.sh +++ b/cuda/cuda-ion-setup.sh @@ -49,7 +49,7 @@ while [[ "$#" -gt 0 ]]; do esac done -if [[ "$BRANCH_OR_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || [[ "$BRANCH_OR_TAG" == "LATEST" ]]; then +if [[ "$BRANCH_OR_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || [[ "$BRANCH_OR_TAG" == "latest" ]]; then echo "Valid --version: $BRANCH_OR_TAG" else echo "Error: --version must be in the format 'vX.Y.Z' (e.g., v1.8.10)" From 49a3ebc1b4858fae3ed739e9811e666c224bbc6d Mon Sep 17 00:00:00 2001 From: fixstars_xinyu <143661893+xinyuli1204@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:41:57 -0700 Subject: [PATCH 3/3] fix --- cuda/src/load_and_process.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/cuda/src/load_and_process.cpp b/cuda/src/load_and_process.cpp index 9d9616d..cb0efa1 100644 --- a/cuda/src/load_and_process.cpp +++ b/cuda/src/load_and_process.cpp @@ -26,18 +26,13 @@ g++ src/load_and_process.cpp -o load_and_process \ using namespace ion; std::map bit_width_map{ - {"Mono8", 8}, {"Mono10", 16}, {"Mono12", 16}, {"BayerBG8", 8}, {"BayerBG10", 16}, {"BayerBG12", 16}}; std::map num_bit_shift_map{ - {"Mono8", 0}, {"Mono10", 6}, {"Mono12", 4}, {"BayerBG8", 0}, {"BayerBG10", 6}, {"BayerBG12", 4}}; std::map bb_name{ {"BayerBG8", "image_io_binaryloader_u8x2"}, {"BayerBG10", "image_io_binaryloader_u16x2"}, - {"BayerBG12", "image_io_binaryloader_u16x2"}, - {"Mono8", "image_io_binaryloader_u8x2"}, - {"Mono10", "image_io_binaryloader_u16x2"}, - {"Mono12", "image_io_binaryloader_u16x2"}}; + {"BayerBG12", "image_io_binaryloader_u16x2"}}; void pipeline_acquisition_and_process(bool use_cuda, bool display_image, std::string output_directory, std::string prefix, int width, int height, std::string pixelformat, int num_frames){ @@ -47,7 +42,7 @@ void pipeline_acquisition_and_process(bool use_cuda, bool display_image, std::st outputs.push_back(Halide::Buffer(buf_size)); Buffer finished(1); - + Builder b; if (use_cuda){ b.set_target(get_host_target().with_feature(Target::CUDA).with_feature(Target::Profile)); @@ -67,7 +62,7 @@ void pipeline_acquisition_and_process(bool use_cuda, bool display_image, std::st if (bit_width_map[pixelformat] == 8){ n = b.add("base_cast_2d_uint8_to_uint16")(n["output"]); } - + n = b.add("image_processing_normalize_raw_image")(n["output"]) .set_param( Param("bit_width", bit_width_map[pixelformat]), @@ -99,6 +94,7 @@ void pipeline_acquisition_and_process(bool use_cuda, bool display_image, std::st std::memcpy(img.ptr(), outputs[0].data(), outputs[0].size_in_bytes()); if (display_image){ cv::imshow("image" + std::to_string(0), img); + cv::waitKey(1); } if (count_run == num_frames || is_finished) { @@ -123,7 +119,7 @@ int main(int argc, char *argv[]) bool display_image = false; std::string output_directory = "."; int num_frames = 0; - + if (argc > 1){ for (int i = 1; i < argc; i++){ if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--target-cuda") == 0){ @@ -152,4 +148,4 @@ int main(int argc, char *argv[]) return 1; } return 0; -} \ No newline at end of file +}