From b5b5ec1a5403cf30411825f46f64ca1f930ad8ac Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 24 Jun 2025 21:16:57 +0200 Subject: [PATCH 01/38] WIP: not compiling yet because of dependency --- CMakeLists.txt | 64 +++++++++++++------ .../yolo_onnx_ros}/yolo_inference.h | 0 package.xml | 29 +++++++++ src/main.cpp | 4 +- src/yolo_inference.cpp | 4 +- 5 files changed, 77 insertions(+), 24 deletions(-) rename {inc => include/yolo_onnx_ros}/yolo_inference.h (100%) create mode 100644 package.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 575e2e9..c3e5b81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,37 +1,61 @@ cmake_minimum_required(VERSION 3.5) +project(yolo_onnx_ros) -set(PROJECT_NAME Yolov8OnnxRuntimeCPPInference) -project(${PROJECT_NAME} VERSION 0.0.1 LANGUAGES CXX) +add_compile_options(-Wall -Werror=all) +add_compile_options(-Wextra -Werror=extra) # -------------- Support C++17 for using filesystem ------------------# set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) +#set(CMAKE_INCLUDE_CURRENT_DIR ON) # -------------- OpenCV ------------------# find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) +find_package(catkin REQUIRED + COMPONENTS + onnxruntime_ros +) + + +# ------------------------------------------------------------------------------------------------ +# CATKIN EXPORT +# ------------------------------------------------------------------------------------------------ + +catkin_package( + INCLUDE_DIRS include + LIBRARIES ${PROJECT_NAME} + CATKIN_DEPENDS + DEPENDS OpenCV +) + +# ------------------------------------------------------------------------------------------------ +# BUILD +# ------------------------------------------------------------------------------------------------ + +include_directories( + include + SYSTEM + ${OpenCV_INCLUDE_DIRS} + ${catkin_INCLUDE_DIRS} +) + # -------------- ONNXRuntime ------------------# -set(ONNXRUNTIME_VERSION 1.21.0) -set(ONNXRUNTIME_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../onnxruntime-linux-x64-gpu-1.21.1") -include_directories(${ONNXRUNTIME_ROOT}/include) # -------------- Cuda ------------------# add_definitions(-DUSE_CUDA=1) -include_directories(/usr/local/cuda/include) -set(PROJECT_SOURCES - src/main.cpp - src/yolo_inference.cpp +add_library(${PROJECT_NAME} + src/yolo_inference.cpp ) +target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES} ${catkin_LIBRARIES}) -add_executable(${PROJECT_NAME} ${PROJECT_SOURCES}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) - -# Link OpenCV libraries along with ONNX Runtime -target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so) +add_executable(test_${PROJECT_NAME} + src/main.cpp +) +target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME} ${OpenCV_LIBRARIES} ${catkin_LIBRARIES}) # For Windows system, copy onnxruntime.dll to the same folder of the executable file if (WIN32) @@ -46,9 +70,9 @@ endif () configure_file(data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) # Copy yolov8n.onnx file to the same folder of the executable file -configure_file(model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) +# configure_file(model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) -# Create folder name images in the same folder of the executable file -add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/images -) +# # Create folder name images in the same folder of the executable file +# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/images +# ) diff --git a/inc/yolo_inference.h b/include/yolo_onnx_ros/yolo_inference.h similarity index 100% rename from inc/yolo_inference.h rename to include/yolo_onnx_ros/yolo_inference.h diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..8106bc0 --- /dev/null +++ b/package.xml @@ -0,0 +1,29 @@ + + + + yolo_onnx_ros + 0.0.0 + Yolo inference + + Iason Theodorou + + ToDo + + catkin + + libopencv-dev + libopencv-dev + onnxruntime_ros + onnxruntime_ros + + catkin_lint_cmake + + doxygen + + + + + + diff --git a/src/main.cpp b/src/main.cpp index 091b185..b19c9d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #include #include -#include "yolo_inference.h" +#include "yolo_onnx_ros/yolo_inference.h" #include #include #include @@ -192,4 +192,4 @@ int main() { DetectTest(); //ClsTest(); -} \ No newline at end of file +} diff --git a/src/yolo_inference.cpp b/src/yolo_inference.cpp index 9f2f6bc..deecd2c 100644 --- a/src/yolo_inference.cpp +++ b/src/yolo_inference.cpp @@ -1,4 +1,4 @@ -#include "yolo_inference.h" +#include "yolo_onnx_ros/yolo_inference.h" #include #define benchmark @@ -383,4 +383,4 @@ char* YOLO_V8::WarmUpSession() { #endif } return RET_OK; -} \ No newline at end of file +} From e8a2678d1627178fec98a942b4c064eaddda042b Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 24 Jun 2025 21:21:08 +0200 Subject: [PATCH 02/38] (actions) add CI --- .github/workflows/main.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..4f3af87 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,13 @@ +name: CI + +on: [push, pull_request] + +jobs: + tue-ci: + name: TUe CI - ${{ github.event_name }} + runs-on: ubuntu-latest + steps: + - name: TUe CI + uses: tue-robotics/tue-env/ci/main@master + with: + package: ${{ github.event.repository.name }} From a1e06ed26944c35d4b1111157e2a335469eeae78 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 24 Jun 2025 22:17:03 +0200 Subject: [PATCH 03/38] Include with <> for onnx header --- include/yolo_onnx_ros/yolo_inference.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/yolo_onnx_ros/yolo_inference.h b/include/yolo_onnx_ros/yolo_inference.h index c35aeb6..cc92b2c 100644 --- a/include/yolo_onnx_ros/yolo_inference.h +++ b/include/yolo_onnx_ros/yolo_inference.h @@ -12,7 +12,7 @@ #include #include #include -#include "onnxruntime_cxx_api.h" +#include #ifdef USE_CUDA #include @@ -92,4 +92,4 @@ class YOLO_V8 float rectConfidenceThreshold; float iouThreshold; float resizeScales;//letterbox scale -}; \ No newline at end of file +}; From 42e61251c944d289c2d9740757501109e2335d74 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 25 Jun 2025 15:29:09 +0200 Subject: [PATCH 04/38] Updates gtests on the CMakeFile and made Preprocess public method --- CMakeLists.txt | 50 +++++++++++++++++++++++++++++++++----------- inc/yolo_inference.h | 9 ++------ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 575e2e9..6d061dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.14) # FetchContent requires 3.14+ set(PROJECT_NAME Yolov8OnnxRuntimeCPPInference) project(${PROJECT_NAME} VERSION 0.0.1 LANGUAGES CXX) @@ -9,13 +9,27 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) +# to show header files in Qt Creator +file(GLOB_RECURSE HEADER_FILES include/*.h) + +# -------------- Google Test ------------------# +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +FetchContent_MakeAvailable(googletest) + +enable_testing() + # -------------- OpenCV ------------------# find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) # -------------- ONNXRuntime ------------------# set(ONNXRUNTIME_VERSION 1.21.0) -set(ONNXRUNTIME_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../onnxruntime-linux-x64-gpu-1.21.1") +set(ONNXRUNTIME_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../hero_sam/onnxruntime-linux-x64-gpu-1.21.1") include_directories(${ONNXRUNTIME_ROOT}/include) # -------------- Cuda ------------------# @@ -27,26 +41,38 @@ set(PROJECT_SOURCES src/yolo_inference.cpp ) +# Main executable (without tests) add_executable(${PROJECT_NAME} ${PROJECT_SOURCES}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) -# Link OpenCV libraries along with ONNX Runtime +# Link libraries for main executable target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so) -# For Windows system, copy onnxruntime.dll to the same folder of the executable file -if (WIN32) - add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${ONNXRUNTIME_ROOT}/lib/onnxruntime.dll" - $) -endif () +# Test executable +add_executable(${PROJECT_NAME}_test + test/tst_yolo_test.cpp + src/yolo_inference.cpp # Include only the source files needed for testing (not main.cpp) +) + +target_include_directories(${PROJECT_NAME}_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc) + +# Link libraries for test executable +target_link_libraries(${PROJECT_NAME}_test + gtest_main + gmock_main + ${OpenCV_LIBS} + ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so +) + +# Add test to CTest +add_test(NAME yolo_tests COMMAND ${PROJECT_NAME}_test) # Download https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/cfg/datasets/coco.yaml # and put it in the same folder of the executable file -configure_file(data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) +configure_file(../hero_sam/yolo_inference/data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) # Copy yolov8n.onnx file to the same folder of the executable file -configure_file(model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) +configure_file(../hero_sam/yolo_inference/model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) # Create folder name images in the same folder of the executable file add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD diff --git a/inc/yolo_inference.h b/inc/yolo_inference.h index c35aeb6..944a5fe 100644 --- a/inc/yolo_inference.h +++ b/inc/yolo_inference.h @@ -2,12 +2,6 @@ #define RET_OK nullptr -#ifdef _WIN32 -#include -#include -#include -#endif - #include #include #include @@ -68,6 +62,8 @@ class YOLO_V8 const char* RunSession(const cv::Mat& iImg, std::vector& oResult); + char* PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Mat& oImg); + std::vector classes{}; private: @@ -78,7 +74,6 @@ class YOLO_V8 char* TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, std::vector& inputNodeDims, std::vector& oResult); - char* PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Mat& oImg); Ort::Env env; std::unique_ptr session; From 9d605449d50c12effa921cd5a65fa8da93b12b44 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 25 Jun 2025 15:30:01 +0200 Subject: [PATCH 05/38] Created initial tests and gitignore file --- .gitignore | 14 ++++++++++++++ test/tst_yolo_test.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 .gitignore create mode 100644 test/tst_yolo_test.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddd4b43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +build/ +images/* +onnxruntime*/ +onnxruntime/* +docker/* +CMakefile +CMakeCache.txt +CMakeFiles/* +cmake_install.cmake +Makefile +SPEED-SAM-C-TENSORRT/ +sam_inference/model/FastSAM-x.onnx +mask* +segmentation_results* diff --git a/test/tst_yolo_test.cpp b/test/tst_yolo_test.cpp new file mode 100644 index 0000000..a1bc32d --- /dev/null +++ b/test/tst_yolo_test.cpp @@ -0,0 +1,25 @@ +#include "yolo_inference.h" +#include +#include + +using namespace testing; + +// Add a simpler test to check YOLO object creation +TEST(YoloInferenceTest, ObjectCreationTest) { + // Test if we can create a YOLO_V8 object without crashing + EXPECT_NO_THROW({ + YOLO_V8 yolo; + }); +} +// Import Yolo Inference header +TEST (YoloInferenceTest, PreProcessTest) { + YOLO_V8 yolo; + cv::Mat img = cv::Mat::ones(640, 640, CV_8UC3) * 255; // Create a white image + std::vector imgSize = { 640, 640 }; + cv::Mat processedImg; + + char* result = yolo.PreProcess(img, imgSize, processedImg); + + EXPECT_EQ(result, nullptr) << "PreProcess should return nullptr (RET_OK) on success"; + EXPECT_EQ(processedImg.size(), cv::Size(640, 640)); +} From 3914fc69d62ecde4fe0547c2280019886dd7caf9 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 25 Jun 2025 15:44:49 +0200 Subject: [PATCH 06/38] Created ONNX Yolo run tests --- src/main.cpp | 1 - test/tst_yolo_test.cpp | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 091b185..e53c91b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,7 +89,6 @@ void Classifier(std::unique_ptr& p) cv::imshow("TEST_CLS", img); cv::waitKey(0); cv::destroyAllWindows(); - //cv::imwrite("E:\\output\\" + std::to_string(k) + ".png", img); } } diff --git a/test/tst_yolo_test.cpp b/test/tst_yolo_test.cpp index a1bc32d..3d356e3 100644 --- a/test/tst_yolo_test.cpp +++ b/test/tst_yolo_test.cpp @@ -21,5 +21,38 @@ TEST (YoloInferenceTest, PreProcessTest) { char* result = yolo.PreProcess(img, imgSize, processedImg); EXPECT_EQ(result, nullptr) << "PreProcess should return nullptr (RET_OK) on success"; - EXPECT_EQ(processedImg.size(), cv::Size(640, 640)); + EXPECT_EQ(processedImg.size(), cv::Size(640, 640)) << "Processed image size should match input size"; +} +TEST (YoloInferenceTest, CreateSessionTest) { + std::unique_ptr yolo = std::make_unique(); + DL_INIT_PARAM params; + params.modelPath = "yolo11m.onnx"; + params.modelType = YOLO_DETECT_V8; + params.imgSize = { 640, 640 }; + params.rectConfidenceThreshold = 0.6; + params.iouThreshold = 0.5; + params.cudaEnable = false; + + const char* result = yolo->CreateSession(params); + + EXPECT_EQ(result, nullptr) << "CreateSession should return nullptr (RET_OK) on success"; +} +TEST (YoloInferenceTest, RunSessionTest) { + std::unique_ptr yolo = std::make_unique(); + DL_INIT_PARAM params; + params.modelPath = "yolo11m.onnx"; // Use a dummy model path + params.modelType = YOLO_DETECT_V8; + params.imgSize = { 640, 640 }; + params.rectConfidenceThreshold = 0.6; + params.iouThreshold = 0.5; + params.cudaEnable = false; + + const char* createResult = yolo->CreateSession(params); + EXPECT_EQ(createResult, nullptr) << "CreateSession should return nullptr (RET_OK) on success"; + + cv::Mat img = cv::Mat::ones(640, 640, CV_8UC3) * 255; // Create a white image + std::vector results; + + const char* runResult = yolo->RunSession(img, results); + EXPECT_EQ(runResult, nullptr) << "RunSession should return nullptr (RET_OK) on success"; } From 0280491426f107514cc7f6da5c9185f224f6ebbd Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 25 Jun 2025 15:49:02 +0200 Subject: [PATCH 07/38] Renamed tests --- test/{tst_yolo_test.cpp => yolo_test.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{tst_yolo_test.cpp => yolo_test.cpp} (100%) diff --git a/test/tst_yolo_test.cpp b/test/yolo_test.cpp similarity index 100% rename from test/tst_yolo_test.cpp rename to test/yolo_test.cpp From 2e9fb553f1b38f47d0e268e9b504e90b8ea91c1c Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 25 Jun 2025 15:50:35 +0200 Subject: [PATCH 08/38] Small test update --- CMakeLists.txt | 2 +- test/yolo_test.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d061dd..79dfbb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_ROOT}/lib/lib # Test executable add_executable(${PROJECT_NAME}_test - test/tst_yolo_test.cpp + test/yolo_test.cpp src/yolo_inference.cpp # Include only the source files needed for testing (not main.cpp) ) diff --git a/test/yolo_test.cpp b/test/yolo_test.cpp index 3d356e3..46f6183 100644 --- a/test/yolo_test.cpp +++ b/test/yolo_test.cpp @@ -11,7 +11,8 @@ TEST(YoloInferenceTest, ObjectCreationTest) { YOLO_V8 yolo; }); } -// Import Yolo Inference header + +// Add a test to check if the PreProcess function works correctly TEST (YoloInferenceTest, PreProcessTest) { YOLO_V8 yolo; cv::Mat img = cv::Mat::ones(640, 640, CV_8UC3) * 255; // Create a white image @@ -23,6 +24,8 @@ TEST (YoloInferenceTest, PreProcessTest) { EXPECT_EQ(result, nullptr) << "PreProcess should return nullptr (RET_OK) on success"; EXPECT_EQ(processedImg.size(), cv::Size(640, 640)) << "Processed image size should match input size"; } + +// Add a test to check if the CreateSession function works correctly TEST (YoloInferenceTest, CreateSessionTest) { std::unique_ptr yolo = std::make_unique(); DL_INIT_PARAM params; @@ -37,6 +40,7 @@ TEST (YoloInferenceTest, CreateSessionTest) { EXPECT_EQ(result, nullptr) << "CreateSession should return nullptr (RET_OK) on success"; } +// Add a test to check if the RunSession function works correctly TEST (YoloInferenceTest, RunSessionTest) { std::unique_ptr yolo = std::make_unique(); DL_INIT_PARAM params; @@ -50,7 +54,7 @@ TEST (YoloInferenceTest, RunSessionTest) { const char* createResult = yolo->CreateSession(params); EXPECT_EQ(createResult, nullptr) << "CreateSession should return nullptr (RET_OK) on success"; - cv::Mat img = cv::Mat::ones(640, 640, CV_8UC3) * 255; // Create a white image + cv::Mat img = cv::Mat::ones(800, 800, CV_8UC3) * 255; // Create a white image std::vector results; const char* runResult = yolo->RunSession(img, results); From 38ad69551b40f42b8334be61c5eaf961acb3863b Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 25 Jun 2025 17:28:46 +0200 Subject: [PATCH 09/38] Use test Fixtures --- test/yolo_test.cpp | 124 +++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 39 deletions(-) diff --git a/test/yolo_test.cpp b/test/yolo_test.cpp index 46f6183..2368892 100644 --- a/test/yolo_test.cpp +++ b/test/yolo_test.cpp @@ -1,62 +1,108 @@ #include "yolo_inference.h" -#include #include +#include +#include using namespace testing; -// Add a simpler test to check YOLO object creation -TEST(YoloInferenceTest, ObjectCreationTest) { - // Test if we can create a YOLO_V8 object without crashing +class YoloInferenceTest : public testing::Test +{ +protected: + void SetUp() override + { + // Create test images with different characteristics + testImage_640x640 = cv::Mat::ones(640, 640, CV_8UC3) * 255; + testImage_800x600 = cv::Mat::ones(600, 800, CV_8UC3) * 128; + + // Create a more realistic test image with some patterns + testImage_realistic = cv::Mat(640, 640, CV_8UC3); + cv::randu(testImage_realistic, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255)); + + // Setup common parameters + params.modelPath = "yolo11m.onnx"; + params.modelType = YOLO_DETECT_V8; + params.imgSize = { 640, 640 }; + params.rectConfidenceThreshold = 0.6; + params.iouThreshold = 0.5; + params.cudaEnable = false; + + yolo = std::make_unique(); + NonSquareImgSize = { testImage_800x600.cols, testImage_800x600.rows }; + } + + void TearDown() override + { + // Clean up if needed + yolo.reset(); + } + + // Test data + cv::Mat testImage_640x640; + cv::Mat testImage_800x600; + cv::Mat testImage_realistic; + DL_INIT_PARAM params; + std::unique_ptr yolo; + std::vector NonSquareImgSize; +}; + +TEST_F(YoloInferenceTest, ObjectCreation) +{ EXPECT_NO_THROW({ - YOLO_V8 yolo; + YOLO_V8 localYolo; }); } -// Add a test to check if the PreProcess function works correctly -TEST (YoloInferenceTest, PreProcessTest) { - YOLO_V8 yolo; - cv::Mat img = cv::Mat::ones(640, 640, CV_8UC3) * 255; // Create a white image - std::vector imgSize = { 640, 640 }; +TEST_F(YoloInferenceTest, PreProcessSquareImage) +{ cv::Mat processedImg; + char* result = yolo->PreProcess(testImage_640x640, params.imgSize, processedImg); - char* result = yolo.PreProcess(img, imgSize, processedImg); - - EXPECT_EQ(result, nullptr) << "PreProcess should return nullptr (RET_OK) on success"; - EXPECT_EQ(processedImg.size(), cv::Size(640, 640)) << "Processed image size should match input size"; + EXPECT_EQ(result, nullptr) << "PreProcess should succeed"; + EXPECT_EQ(processedImg.size(), cv::Size(640, 640)) << "Output should be 640x640"; + EXPECT_FALSE(processedImg.empty()) << "Processed image should not be empty"; } -// Add a test to check if the CreateSession function works correctly -TEST (YoloInferenceTest, CreateSessionTest) { - std::unique_ptr yolo = std::make_unique(); - DL_INIT_PARAM params; - params.modelPath = "yolo11m.onnx"; - params.modelType = YOLO_DETECT_V8; - params.imgSize = { 640, 640 }; - params.rectConfidenceThreshold = 0.6; - params.iouThreshold = 0.5; - params.cudaEnable = false; +TEST_F(YoloInferenceTest, PreProcessRectangularImage) +{ + cv::Mat processedImg; + char* result = yolo->PreProcess(testImage_800x600, NonSquareImgSize, processedImg); + + EXPECT_EQ(result, nullptr) << "PreProcess should succeed"; + EXPECT_EQ(processedImg.size(), cv::Size(800, 600)) << "Output should be letterboxed to 800x600"; + EXPECT_FALSE(processedImg.empty()) << "Processed image should not be empty"; +} +TEST_F(YoloInferenceTest, CreateSessionWithValidModel) +{ const char* result = yolo->CreateSession(params); + EXPECT_EQ(result, nullptr) << "CreateSession should succeed with valid parameters"; +} - EXPECT_EQ(result, nullptr) << "CreateSession should return nullptr (RET_OK) on success"; +TEST_F(YoloInferenceTest, CreateSessionWithInvalidModel) +{ + params.modelPath = "nonexistent_model.onnx"; + const char* result = yolo->CreateSession(params); + EXPECT_NE(result, nullptr) << "CreateSession should fail with invalid model path"; } -// Add a test to check if the RunSession function works correctly -TEST (YoloInferenceTest, RunSessionTest) { - std::unique_ptr yolo = std::make_unique(); - DL_INIT_PARAM params; - params.modelPath = "yolo11m.onnx"; // Use a dummy model path - params.modelType = YOLO_DETECT_V8; - params.imgSize = { 640, 640 }; - params.rectConfidenceThreshold = 0.6; - params.iouThreshold = 0.5; - params.cudaEnable = false; +TEST_F(YoloInferenceTest, FullInferencePipeline) +{ + // First create session const char* createResult = yolo->CreateSession(params); - EXPECT_EQ(createResult, nullptr) << "CreateSession should return nullptr (RET_OK) on success"; + ASSERT_EQ(createResult, nullptr) << "Session creation must succeed for inference test"; - cv::Mat img = cv::Mat::ones(800, 800, CV_8UC3) * 255; // Create a white image + // Then run inference std::vector results; + const char* runResult = yolo->RunSession(testImage_realistic, results); + + EXPECT_EQ(runResult, nullptr) << "RunSession should succeed"; + // Note: results might be empty for random test image, that's okay + EXPECT_TRUE(results.size() >= 0) << "Results should be a valid vector"; +} - const char* runResult = yolo->RunSession(img, results); - EXPECT_EQ(runResult, nullptr) << "RunSession should return nullptr (RET_OK) on success"; +// Run all tests +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } From 723a133343cc44adb31f64012ae900fdf82c2ae8 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Fri, 27 Jun 2025 14:40:23 +0200 Subject: [PATCH 10/38] Updated readme file --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ed9d936..f5b9e48 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ C++ Onnx-runtime -This example demonstrates how to perform inference using YOLOv8 in C++ with ONNX Runtime and OpenCV's API. +https://github.com/ultralytics/ultralytics/tree/main/examples/YOLOv8-ONNXRuntime-CPP + +This algorithm is inspired by Ultralitics implementation (see link above) to perform inference using YOLOv8 in C++ with ONNX Runtime and OpenCV's API. ## Benefits ✨ @@ -57,12 +59,12 @@ In order to run example, you also need to download coco.yaml. You can download t | OpenCV | >=4.0.0 | | C++ Standard | >=17 | | Cmake | >=3.5 | -| Cuda (Optional) | >=11.4 \<12.0 | -| cuDNN (Cuda required) | =8 | +| Cuda (Optional) | =12.8 | +| cuDNN (Cuda required) | =9 | Note: The dependency on C++17 is due to the usage of the C++17 filesystem feature. -Note (2): Due to ONNX Runtime, we need to use CUDA 11 and cuDNN 8. Keep in mind that this requirement might change in the future. +Note (2): Due to ONNX Runtime, we need to use CUDA 12.8 and cuDNN 9. Keep in mind that this requirement might change in the future. ## Build 🛠️ @@ -87,12 +89,8 @@ Note (2): Due to ONNX Runtime, we need to use CUDA 11 and cuDNN 8. Keep in mind If you encounter an error indicating that the `ONNXRUNTIME_ROOT` variable is not set correctly, you can resolve this by building the project using the appropriate command tailored to your system. ```console - # compiled in a win32 system - cmake -D WIN32=TRUE .. # compiled in a linux system cmake -D LINUX=TRUE .. - # compiled in an apple system - cmake -D APPLE=TRUE .. ``` 5. Build the project: From 686ea7f501ad8065db70d50e3907d7a67577096d Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Fri, 27 Jun 2025 14:49:51 +0200 Subject: [PATCH 11/38] Commented out the classification parts --- src/main.cpp | 89 +++++++++++++++++++++--------------------- src/yolo_inference.cpp | 66 +++++++++++++++---------------- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e53c91b..521a1dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,41 +58,41 @@ void Detector(std::unique_ptr& p) { } -void Classifier(std::unique_ptr& p) -{ - std::filesystem::path current_path = std::filesystem::current_path(); - std::filesystem::path imgs_path = current_path;// / "images" - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(0, 255); - for (auto& i : std::filesystem::directory_iterator(imgs_path)) - { - if (i.path().extension() == ".jpg" || i.path().extension() == ".png") - { - std::string img_path = i.path().string(); - //std::cout << img_path << std::endl; - cv::Mat img = cv::imread(img_path); - std::vector res; - const char* ret = p->RunSession(img, res); - - float positionY = 50; - for (int i = 0; i < res.size(); i++) - { - int r = dis(gen); - int g = dis(gen); - int b = dis(gen); - cv::putText(img, std::to_string(i) + ":", cv::Point(10, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); - cv::putText(img, std::to_string(res.at(i).confidence), cv::Point(70, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); - positionY += 50; - } - - cv::imshow("TEST_CLS", img); - cv::waitKey(0); - cv::destroyAllWindows(); - } - - } -} +// void Classifier(std::unique_ptr& p) +// { +// std::filesystem::path current_path = std::filesystem::current_path(); +// std::filesystem::path imgs_path = current_path;// / "images" +// std::random_device rd; +// std::mt19937 gen(rd()); +// std::uniform_int_distribution dis(0, 255); +// for (auto& i : std::filesystem::directory_iterator(imgs_path)) +// { +// if (i.path().extension() == ".jpg" || i.path().extension() == ".png") +// { +// std::string img_path = i.path().string(); +// //std::cout << img_path << std::endl; +// cv::Mat img = cv::imread(img_path); +// std::vector res; +// const char* ret = p->RunSession(img, res); + +// float positionY = 50; +// for (int i = 0; i < res.size(); i++) +// { +// int r = dis(gen); +// int g = dis(gen); +// int b = dis(gen); +// cv::putText(img, std::to_string(i) + ":", cv::Point(10, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); +// cv::putText(img, std::to_string(res.at(i).confidence), cv::Point(70, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); +// positionY += 50; +// } + +// cv::imshow("TEST_CLS", img); +// cv::waitKey(0); +// cv::destroyAllWindows(); +// } + +// } +// } @@ -147,7 +147,6 @@ int ReadCocoYaml(std::unique_ptr& p) { void DetectTest() { - //YOLO_V8* yoloDetector = new YOLO_V8; std::unique_ptr yoloDetector = std::make_unique(); ReadCocoYaml(yoloDetector); @@ -176,15 +175,15 @@ void DetectTest() } -void ClsTest() -{ - std::unique_ptr yoloDetector = std::make_unique(); - std::string model_path = "cls.onnx"; - ReadCocoYaml(yoloDetector); - DL_INIT_PARAM params{ model_path, YOLO_CLS, {224, 224} }; - yoloDetector->CreateSession(params); - Classifier(yoloDetector); -} +// void ClsTest() +// { +// std::unique_ptr yoloDetector = std::make_unique(); +// std::string model_path = "cls.onnx"; +// ReadCocoYaml(yoloDetector); +// DL_INIT_PARAM params{ model_path, YOLO_CLS, {224, 224} }; +// yoloDetector->CreateSession(params); +// Classifier(yoloDetector); +// } int main() diff --git a/src/yolo_inference.cpp b/src/yolo_inference.cpp index 9f2f6bc..6ce0888 100644 --- a/src/yolo_inference.cpp +++ b/src/yolo_inference.cpp @@ -83,16 +83,16 @@ char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Ma oImg = tempImg; break; } - case YOLO_CLS: // CenterCrop - { - int h = iImg.rows; - int w = iImg.cols; - int m = min(h, w); - int top = (h - m) / 2; - int left = (w - m) / 2; - cv::resize(oImg(cv::Rect(left, top, m, m)), oImg, cv::Size(iImgSize.at(0), iImgSize.at(1))); - break; - } + // case YOLO_CLS: // CenterCrop + // { + // int h = iImg.rows; + // int w = iImg.cols; + // int m = min(h, w); + // int top = (h - m) / 2; + // int left = (w - m) / 2; + // cv::resize(oImg(cv::Rect(left, top, m, m)), oImg, cv::Size(iImgSize.at(0), iImgSize.at(1))); + // break; + // } } return RET_OK; } @@ -311,29 +311,29 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, break; } - case YOLO_CLS: - case YOLO_CLS_HALF: - { - cv::Mat rawData; - if (modelType == YOLO_CLS) { - // FP32 - rawData = cv::Mat(1, this->classes.size(), CV_32F, output); - } else { - // FP16 - rawData = cv::Mat(1, this->classes.size(), CV_16F, output); - rawData.convertTo(rawData, CV_32F); - } - float *data = (float *) rawData.data; - - DL_RESULT result; - for (int i = 0; i < this->classes.size(); i++) - { - result.classId = i; - result.confidence = data[i]; - oResult.push_back(result); - } - break; - } + // case YOLO_CLS: + // case YOLO_CLS_HALF: + // { + // cv::Mat rawData; + // if (modelType == YOLO_CLS) { + // // FP32 + // rawData = cv::Mat(1, this->classes.size(), CV_32F, output); + // } else { + // // FP16 + // rawData = cv::Mat(1, this->classes.size(), CV_16F, output); + // rawData.convertTo(rawData, CV_32F); + // } + // float *data = (float *) rawData.data; + + // DL_RESULT result; + // for (int i = 0; i < this->classes.size(); i++) + // { + // result.classId = i; + // result.confidence = data[i]; + // oResult.push_back(result); + // } + // break; + // } default: std::cout << "[YOLO_V8]: " << "Not support model type." << std::endl; } From 2cac602d0a8f249d192214cd606ebafd7d09ecf0 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Tue, 1 Jul 2025 20:23:51 +0200 Subject: [PATCH 12/38] Add inference engine calling functionality --- src/inference.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/inference.cpp diff --git a/src/inference.cpp b/src/inference.cpp new file mode 100644 index 0000000..5fcfc7d --- /dev/null +++ b/src/inference.cpp @@ -0,0 +1,185 @@ +#include +#include +#include "yolo_inference.h" +#include +#include +#include + +void Detector(std::unique_ptr& p, const cv::Mat& img) { + + std::vector res; + p->RunSession(img, res); + + for (auto& re : res) + { + cv::RNG rng(cv::getTickCount()); + cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256)); + + cv::rectangle(img, re.box, color, 3); + + float confidence = floor(100 * re.confidence) / 100; + std::cout << std::fixed << std::setprecision(2); + std::string label = p->classes[re.classId] + " " + + std::to_string(confidence).substr(0, std::to_string(confidence).size() - 4); + + cv::rectangle( + img, + cv::Point(re.box.x, re.box.y - 25), + cv::Point(re.box.x + label.length() * 15, re.box.y), + color, + cv::FILLED + ); + + cv::putText( + img, + label, + cv::Point(re.box.x, re.box.y - 5), + cv::FONT_HERSHEY_SIMPLEX, + 0.75, + cv::Scalar(0, 0, 0), + 2 + ); + + + } + // std::cout << "Press any key to exit" << std::endl; + // cv::imshow("Result of Detection", img); + // cv::waitKey(0); + // cv::destroyAllWindows(); + } + + + +// void Classifier(std::unique_ptr& p) +// { +// std::filesystem::path current_path = std::filesystem::current_path(); +// std::filesystem::path imgs_path = current_path;// / "images" +// std::random_device rd; +// std::mt19937 gen(rd()); +// std::uniform_int_distribution dis(0, 255); +// for (auto& i : std::filesystem::directory_iterator(imgs_path)) +// { +// if (i.path().extension() == ".jpg" || i.path().extension() == ".png") +// { +// std::string img_path = i.path().string(); +// //std::cout << img_path << std::endl; +// cv::Mat img = cv::imread(img_path); +// std::vector res; +// const char* ret = p->RunSession(img, res); + +// float positionY = 50; +// for (int i = 0; i < res.size(); i++) +// { +// int r = dis(gen); +// int g = dis(gen); +// int b = dis(gen); +// cv::putText(img, std::to_string(i) + ":", cv::Point(10, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); +// cv::putText(img, std::to_string(res.at(i).confidence), cv::Point(70, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); +// positionY += 50; +// } + +// cv::imshow("TEST_CLS", img); +// cv::waitKey(0); +// cv::destroyAllWindows(); +// } + +// } +// } + + + +int ReadCocoYaml(std::unique_ptr& p) { + // Open the YAML file + std::ifstream file("coco.yaml"); + if (!file.is_open()) + { + std::cerr << "Failed to open file" << std::endl; + return 1; + } + + // Read the file line by line + std::string line; + std::vector lines; + while (std::getline(file, line)) + { + lines.push_back(line); + } + + // Find the start and end of the names section + std::size_t start = 0; + std::size_t end = 0; + for (std::size_t i = 0; i < lines.size(); i++) + { + if (lines[i].find("names:") != std::string::npos) + { + start = i + 1; + } + else if (start > 0 && lines[i].find(':') == std::string::npos) + { + end = i; + break; + } + } + + // Extract the names + std::vector names; + for (std::size_t i = start; i < end; i++) + { + std::stringstream ss(lines[i]); + std::string name; + std::getline(ss, name, ':'); // Extract the number before the delimiter + std::getline(ss, name); // Extract the string after the delimiter + names.push_back(name); + } + + p->classes = names; + return 0; +} + + +std::vector Detect(const cv::Mat& img) +{ + std::unique_ptr yoloDetector = std::make_unique(); + + ReadCocoYaml(yoloDetector); + DL_INIT_PARAM params; + params.rectConfidenceThreshold = 0.1; + params.iouThreshold = 0.5; + params.modelPath = "yolo11m.onnx"; + params.imgSize = { 640, 640 }; +#ifdef USE_CUDA + params.cudaEnable = true; + + // GPU FP32 inference + params.modelType = YOLO_DETECT_V8; + // GPU FP16 inference + //Note: change fp16 onnx model + //params.modelType = YOLO_DETECT_V8_HALF; + +#else + // CPU inference + params.modelType = YOLO_DETECT_V8; + params.cudaEnable = false; + +#endif + yoloDetector->CreateSession(params); + std::vector results = Detector(yoloDetector, img); + return results; +} + + +// void ClsTest() +// { +// std::unique_ptr yoloDetector = std::make_unique(); +// std::string model_path = "cls.onnx"; +// ReadCocoYaml(yoloDetector); +// DL_INIT_PARAM params{ model_path, YOLO_CLS, {224, 224} }; +// yoloDetector->CreateSession(params); +// Classifier(yoloDetector); +// } + + +int main() +{ + Detect(); +} \ No newline at end of file From a4038fc58af706498d8bc8c59bcbfcf89b4057d7 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 2 Jul 2025 21:02:10 +0200 Subject: [PATCH 13/38] Use inference to call the function from a single point --- CMakeLists.txt | 2 +- inc/inference.h | 5 ++ src/inference.cpp | 22 +++--- src/main.cpp | 178 ++-------------------------------------------- 4 files changed, 20 insertions(+), 187 deletions(-) create mode 100644 inc/inference.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 79dfbb8..2c27a04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ include_directories(/usr/local/cuda/include) set(PROJECT_SOURCES src/main.cpp src/yolo_inference.cpp -) + src/inference.cpp) # Main executable (without tests) add_executable(${PROJECT_NAME} ${PROJECT_SOURCES}) diff --git a/inc/inference.h b/inc/inference.h new file mode 100644 index 0000000..9c1e452 --- /dev/null +++ b/inc/inference.h @@ -0,0 +1,5 @@ +#include "yolo_inference.h" + +std::vector Detect(const cv::Mat& img); +std::vector DetectObjects(std::unique_ptr& p, const cv::Mat& img); +int ReadCocoYaml(std::unique_ptr& p); \ No newline at end of file diff --git a/src/inference.cpp b/src/inference.cpp index 5fcfc7d..05b83d8 100644 --- a/src/inference.cpp +++ b/src/inference.cpp @@ -1,11 +1,11 @@ #include #include -#include "yolo_inference.h" +#include "inference.h" #include #include #include -void Detector(std::unique_ptr& p, const cv::Mat& img) { +std::vector DetectObjects(std::unique_ptr& p, const cv::Mat& img) { std::vector res; p->RunSession(img, res); @@ -42,10 +42,11 @@ void Detector(std::unique_ptr& p, const cv::Mat& img) { } - // std::cout << "Press any key to exit" << std::endl; - // cv::imshow("Result of Detection", img); - // cv::waitKey(0); - // cv::destroyAllWindows(); + std::cout << "Press any key to exit" << std::endl; + cv::imshow("Result of Detection", img); + cv::waitKey(0); + cv::destroyAllWindows(); + return res; } @@ -162,8 +163,9 @@ std::vector Detect(const cv::Mat& img) params.cudaEnable = false; #endif + // TODO: THIS IS UNOPTIMAL IF YOU PASS MULTIPLE IMAGES. yoloDetector->CreateSession(params); - std::vector results = Detector(yoloDetector, img); + std::vector results = DetectObjects(yoloDetector, img); return results; } @@ -177,9 +179,3 @@ std::vector Detect(const cv::Mat& img) // yoloDetector->CreateSession(params); // Classifier(yoloDetector); // } - - -int main() -{ - Detect(); -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 521a1dc..87a58d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,12 @@ #include #include -#include "yolo_inference.h" +#include "inference.h" #include #include #include -void Detector(std::unique_ptr& p) { +int main() +{ std::filesystem::path current_path = std::filesystem::current_path(); std::filesystem::path imgs_path = current_path / "images"; for (auto& i : std::filesystem::directory_iterator(imgs_path)) @@ -14,180 +15,11 @@ void Detector(std::unique_ptr& p) { { std::string img_path = i.path().string(); cv::Mat img = cv::imread(img_path); - std::vector res; - p->RunSession(img, res); - - for (auto& re : res) - { - cv::RNG rng(cv::getTickCount()); - cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256)); - - cv::rectangle(img, re.box, color, 3); - - float confidence = floor(100 * re.confidence) / 100; - std::cout << std::fixed << std::setprecision(2); - std::string label = p->classes[re.classId] + " " + - std::to_string(confidence).substr(0, std::to_string(confidence).size() - 4); - - cv::rectangle( - img, - cv::Point(re.box.x, re.box.y - 25), - cv::Point(re.box.x + label.length() * 15, re.box.y), - color, - cv::FILLED - ); - - cv::putText( - img, - label, - cv::Point(re.box.x, re.box.y - 5), - cv::FONT_HERSHEY_SIMPLEX, - 0.75, - cv::Scalar(0, 0, 0), - 2 - ); - - - } - std::cout << "Press any key to exit" << std::endl; - cv::imshow("Result of Detection", img); - cv::waitKey(0); - cv::destroyAllWindows(); - } - } + std::vector results; + results = Detect(img); } - - -// void Classifier(std::unique_ptr& p) -// { -// std::filesystem::path current_path = std::filesystem::current_path(); -// std::filesystem::path imgs_path = current_path;// / "images" -// std::random_device rd; -// std::mt19937 gen(rd()); -// std::uniform_int_distribution dis(0, 255); -// for (auto& i : std::filesystem::directory_iterator(imgs_path)) -// { -// if (i.path().extension() == ".jpg" || i.path().extension() == ".png") -// { -// std::string img_path = i.path().string(); -// //std::cout << img_path << std::endl; -// cv::Mat img = cv::imread(img_path); -// std::vector res; -// const char* ret = p->RunSession(img, res); - -// float positionY = 50; -// for (int i = 0; i < res.size(); i++) -// { -// int r = dis(gen); -// int g = dis(gen); -// int b = dis(gen); -// cv::putText(img, std::to_string(i) + ":", cv::Point(10, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); -// cv::putText(img, std::to_string(res.at(i).confidence), cv::Point(70, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2); -// positionY += 50; -// } - -// cv::imshow("TEST_CLS", img); -// cv::waitKey(0); -// cv::destroyAllWindows(); -// } - -// } -// } - - - -int ReadCocoYaml(std::unique_ptr& p) { - // Open the YAML file - std::ifstream file("coco.yaml"); - if (!file.is_open()) - { - std::cerr << "Failed to open file" << std::endl; - return 1; - } - - // Read the file line by line - std::string line; - std::vector lines; - while (std::getline(file, line)) - { - lines.push_back(line); } - // Find the start and end of the names section - std::size_t start = 0; - std::size_t end = 0; - for (std::size_t i = 0; i < lines.size(); i++) - { - if (lines[i].find("names:") != std::string::npos) - { - start = i + 1; - } - else if (start > 0 && lines[i].find(':') == std::string::npos) - { - end = i; - break; - } - } - // Extract the names - std::vector names; - for (std::size_t i = start; i < end; i++) - { - std::stringstream ss(lines[i]); - std::string name; - std::getline(ss, name, ':'); // Extract the number before the delimiter - std::getline(ss, name); // Extract the string after the delimiter - names.push_back(name); - } - - p->classes = names; return 0; -} - - -void DetectTest() -{ - std::unique_ptr yoloDetector = std::make_unique(); - - ReadCocoYaml(yoloDetector); - DL_INIT_PARAM params; - params.rectConfidenceThreshold = 0.1; - params.iouThreshold = 0.5; - params.modelPath = "yolo11m.onnx"; - params.imgSize = { 640, 640 }; -#ifdef USE_CUDA - params.cudaEnable = true; - - // GPU FP32 inference - params.modelType = YOLO_DETECT_V8; - // GPU FP16 inference - //Note: change fp16 onnx model - //params.modelType = YOLO_DETECT_V8_HALF; - -#else - // CPU inference - params.modelType = YOLO_DETECT_V8; - params.cudaEnable = false; - -#endif - yoloDetector->CreateSession(params); - Detector(yoloDetector); -} - - -// void ClsTest() -// { -// std::unique_ptr yoloDetector = std::make_unique(); -// std::string model_path = "cls.onnx"; -// ReadCocoYaml(yoloDetector); -// DL_INIT_PARAM params{ model_path, YOLO_CLS, {224, 224} }; -// yoloDetector->CreateSession(params); -// Classifier(yoloDetector); -// } - - -int main() -{ - DetectTest(); - //ClsTest(); } \ No newline at end of file From deb522751ec08dea7d5e8c663b9ee46900646a5c Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Thu, 3 Jul 2025 10:05:08 +0200 Subject: [PATCH 14/38] Used Initilialize function to create a session outside the running session in case of multiple inputs (to avoid necessary initializations). --- inc/inference.h | 2 +- src/inference.cpp | 49 ++++++++++++++++++++++------------------------- src/main.cpp | 4 +++- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/inc/inference.h b/inc/inference.h index 9c1e452..7f9ebc6 100644 --- a/inc/inference.h +++ b/inc/inference.h @@ -1,5 +1,5 @@ #include "yolo_inference.h" -std::vector Detect(const cv::Mat& img); +std::unique_ptr Initialize(); std::vector DetectObjects(std::unique_ptr& p, const cv::Mat& img); int ReadCocoYaml(std::unique_ptr& p); \ No newline at end of file diff --git a/src/inference.cpp b/src/inference.cpp index 05b83d8..791a2fa 100644 --- a/src/inference.cpp +++ b/src/inference.cpp @@ -137,36 +137,33 @@ int ReadCocoYaml(std::unique_ptr& p) { return 0; } - -std::vector Detect(const cv::Mat& img) +std::unique_ptr Initialize() { std::unique_ptr yoloDetector = std::make_unique(); ReadCocoYaml(yoloDetector); - DL_INIT_PARAM params; - params.rectConfidenceThreshold = 0.1; - params.iouThreshold = 0.5; - params.modelPath = "yolo11m.onnx"; - params.imgSize = { 640, 640 }; -#ifdef USE_CUDA - params.cudaEnable = true; - - // GPU FP32 inference - params.modelType = YOLO_DETECT_V8; - // GPU FP16 inference - //Note: change fp16 onnx model - //params.modelType = YOLO_DETECT_V8_HALF; - -#else - // CPU inference - params.modelType = YOLO_DETECT_V8; - params.cudaEnable = false; - -#endif - // TODO: THIS IS UNOPTIMAL IF YOU PASS MULTIPLE IMAGES. - yoloDetector->CreateSession(params); - std::vector results = DetectObjects(yoloDetector, img); - return results; + DL_INIT_PARAM params; + params.rectConfidenceThreshold = 0.1; + params.iouThreshold = 0.5; + params.modelPath = "yolo11m.onnx"; + params.imgSize = { 640, 640 }; + #ifdef USE_CUDA + params.cudaEnable = true; + + // GPU FP32 inference + params.modelType = YOLO_DETECT_V8; + // GPU FP16 inference + //Note: change fp16 onnx model + //params.modelType = YOLO_DETECT_V8_HALF; + + #else + // CPU inference + params.modelType = YOLO_DETECT_V8; + params.cudaEnable = false; + + #endif + yoloDetector->CreateSession(params); + return yoloDetector; } diff --git a/src/main.cpp b/src/main.cpp index 87a58d5..839ca9a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,8 @@ int main() { + // An example of how to use the YOLO_V8 class for object detection + std::unique_ptr yoloDetector = Initialize(); std::filesystem::path current_path = std::filesystem::current_path(); std::filesystem::path imgs_path = current_path / "images"; for (auto& i : std::filesystem::directory_iterator(imgs_path)) @@ -16,7 +18,7 @@ int main() std::string img_path = i.path().string(); cv::Mat img = cv::imread(img_path); std::vector results; - results = Detect(img); + results = DetectObjects(yoloDetector, img); } } From d5bcc125a284428be85db049928ee7a3f1159d6a Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Thu, 3 Jul 2025 10:30:31 +0200 Subject: [PATCH 15/38] Updated ReadmeFile --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f5b9e48..37f7eea 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ C++ Onnx-runtime -https://github.com/ultralytics/ultralytics/tree/main/examples/YOLOv8-ONNXRuntime-CPP -This algorithm is inspired by Ultralitics implementation (see link above) to perform inference using YOLOv8 in C++ with ONNX Runtime and OpenCV's API. + +This algorithm is inspired by [Ultralitics](https://github.com/ultralytics/ultralytics/tree/main/examples/YOLOv8-ONNXRuntime-CPP) implementation to perform inference using YOLOv8 (we also supports v11) in C++ with ONNX Runtime and OpenCV's API. ## Benefits ✨ @@ -102,9 +102,15 @@ Note (2): Due to ONNX Runtime, we need to use CUDA 12.8 and cuDNN 9. Keep in min 6. The built executable should now be located in the `build` directory. ## Usage 🚀 - +To run from main just run the executable. +To run the detector on you C++ application: ```c++ -//change your param as you like +//To run the detector add on you C++ application: +std::vector results; +std::unique_ptr yoloDetector = Initialize(); +results = DetectObjects(yoloDetector, img); + +//You can change your param as you like (inside the Initialize() function) //Pay attention to your device and the onnx model type(fp32 or fp16) DL_INIT_PARAM params; params.rectConfidenceThreshold = 0.1; From 22da61de286f5d30de6865fec327ba656c8cfe72 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 2 Sep 2025 20:38:22 +0200 Subject: [PATCH 16/38] Working switch between cuda and non cuda; code not working --- CMakeLists.txt | 52 ++++++++- include/yolo_onnx_ros/config.hpp.in | 7 ++ include/yolo_onnx_ros/yolo_inference.h | 30 ++--- src/main.cpp | 5 +- src/yolo_inference.cpp | 146 +++++++++++++------------ 5 files changed, 147 insertions(+), 93 deletions(-) create mode 100644 include/yolo_onnx_ros/config.hpp.in diff --git a/CMakeLists.txt b/CMakeLists.txt index c3e5b81..495abfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,37 +20,48 @@ find_package(catkin REQUIRED ) +set(${PROJECT_NAME}_CUDA_ENABLED ${onnxruntime_ros_CUDA_ENABLED}) +if(onnxruntime_ros_CUDA_ENABLED) + find_package(CUDAToolkit REQUIRED) +endif() + +configure_file(include/${PROJECT_NAME}/config.hpp.in ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}/${PROJECT_NAME}/config.hpp) +# add_custom_target(generate_config_hpp +# DEPENDS ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}/${PROJECT_NAME}/config.hpp +# ) + # ------------------------------------------------------------------------------------------------ # CATKIN EXPORT # ------------------------------------------------------------------------------------------------ catkin_package( - INCLUDE_DIRS include + INCLUDE_DIRS include ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION} LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS - DEPENDS OpenCV + DEPENDS CUDAToolkit OpenCV ) + # ------------------------------------------------------------------------------------------------ # BUILD # ------------------------------------------------------------------------------------------------ include_directories( include + ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION} SYSTEM + ${CUDAToolkit_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS} ) # -------------- ONNXRuntime ------------------# -# -------------- Cuda ------------------# -add_definitions(-DUSE_CUDA=1) - add_library(${PROJECT_NAME} src/yolo_inference.cpp ) -target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES} ${catkin_LIBRARIES}) +# add_dependencies(${PROJECT_NAME} generate_config_hpp) +target_link_libraries(${PROJECT_NAME} CUDA::toolkit ${OpenCV_LIBRARIES} ${catkin_LIBRARIES}) add_executable(test_${PROJECT_NAME} src/main.cpp @@ -65,6 +76,35 @@ if (WIN32) $) endif () + +# ------------------------------------------------------------------------------------------------ +# INSTALL +# ------------------------------------------------------------------------------------------------ + +install(FILES + ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_INCLUDE_DESTINATION}/config.hpp + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +) + +install( + DIRECTORY include/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +) + +install( + TARGETS + ${PROJECT_NAME} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +) + +install( + TARGETS + ${PROJECT_NAME} + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + # Download https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/cfg/datasets/coco.yaml # and put it in the same folder of the executable file configure_file(data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) diff --git a/include/yolo_onnx_ros/config.hpp.in b/include/yolo_onnx_ros/config.hpp.in new file mode 100644 index 0000000..8ea1605 --- /dev/null +++ b/include/yolo_onnx_ros/config.hpp.in @@ -0,0 +1,7 @@ +#ifndef YOLO_ONNX_ROS_CONFIG_HPP_ +#define YOLO_ONNX_ROS_CONFIG_HPP_ + +//Set which version of the Tree Interface to use +#define YOLO_ONNX_ROS_CUDA_ENABLED @onnx_yolo_ros_CUDA_ENABLED@ + +#endif //#define YOLO_ONNX_ROS_CONFIG_HPP_ diff --git a/include/yolo_onnx_ros/yolo_inference.h b/include/yolo_onnx_ros/yolo_inference.h index cc92b2c..bcd3184 100644 --- a/include/yolo_onnx_ros/yolo_inference.h +++ b/include/yolo_onnx_ros/yolo_inference.h @@ -14,7 +14,9 @@ #include #include -#ifdef USE_CUDA +#include + +#ifdef YOLO_ONNX_ROS_CUDA_ENABLED #include #endif @@ -75,21 +77,21 @@ class YOLO_V8 // Note: The logic is on the .cpp file since its a private method. template - char* TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, std::vector& inputNodeDims, + char* TensorProcess(clock_t& starttime_1, N& blob, std::vector& inputNodeDims, std::vector& oResult); char* PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Mat& oImg); - Ort::Env env; - std::unique_ptr session; - bool cudaEnable; - Ort::RunOptions options; - std::vector inputNodeNames; - std::vector outputNodeNames; - - MODEL_TYPE modelType; - std::vector imgSize; - float rectConfidenceThreshold; - float iouThreshold; - float resizeScales;//letterbox scale + Ort::Env env_; + std::unique_ptr session_; + bool cudaEnable_; + Ort::RunOptions options_; + std::vector inputNodeNames_; + std::vector outputNodeNames_; + + MODEL_TYPE modelType_; + std::vector imgSize_; + float rectConfidenceThreshold_; + float iouThreshold_; + float resizeScales_; //letterbox scale }; diff --git a/src/main.cpp b/src/main.cpp index b19c9d7..83579d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include #include #include "yolo_onnx_ros/yolo_inference.h" +#include #include #include #include @@ -76,7 +77,7 @@ void Classifier(std::unique_ptr& p) const char* ret = p->RunSession(img, res); float positionY = 50; - for (int i = 0; i < res.size(); i++) + for (uint i = 0; i < res.size(); i++) { int r = dis(gen); int g = dis(gen); @@ -157,7 +158,7 @@ void DetectTest() params.iouThreshold = 0.5; params.modelPath = "yolo11m.onnx"; params.imgSize = { 640, 640 }; -#ifdef USE_CUDA +#ifdef YOLO_ONNX_ROS_CUDA_ENABLED params.cudaEnable = true; // GPU FP32 inference diff --git a/src/yolo_inference.cpp b/src/yolo_inference.cpp index deecd2c..2337145 100644 --- a/src/yolo_inference.cpp +++ b/src/yolo_inference.cpp @@ -12,7 +12,7 @@ YOLO_V8::~YOLO_V8() { } -#ifdef USE_CUDA +#ifdef ONNX_YOLO_ROS_CUDA_ENABLED namespace Ort { template<> @@ -49,7 +49,7 @@ char* BlobFromImage(const cv::Mat& iImg, T& iBlob) { } -char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Mat& oImg) +char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iimgSize, cv::Mat& oImg) { if (iImg.channels() == 3) { @@ -61,7 +61,7 @@ char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Ma cv::cvtColor(iImg, oImg, cv::COLOR_GRAY2RGB); } - switch (modelType) + switch (modelType_) { case YOLO_DETECT_V8: case YOLO_POSE: @@ -70,27 +70,28 @@ char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Ma { if (iImg.cols >= iImg.rows) { - resizeScales = iImg.cols / (float)iImgSize.at(0); - cv::resize(oImg, oImg, cv::Size(iImgSize.at(0), int(iImg.rows / resizeScales))); + resizeScales_ = iImg.cols / (float)iimgSize.at(0); + cv::resize(oImg, oImg, cv::Size(iimgSize.at(0), int(iImg.rows / resizeScales_))); } else { - resizeScales = iImg.rows / (float)iImgSize.at(0); - cv::resize(oImg, oImg, cv::Size(int(iImg.cols / resizeScales), iImgSize.at(1))); + resizeScales_ = iImg.rows / (float)iimgSize.at(0); + cv::resize(oImg, oImg, cv::Size(int(iImg.cols / resizeScales_), iimgSize.at(1))); } - cv::Mat tempImg = cv::Mat::zeros(iImgSize.at(0), iImgSize.at(1), CV_8UC3); + cv::Mat tempImg = cv::Mat::zeros(iimgSize.at(0), iimgSize.at(1), CV_8UC3); oImg.copyTo(tempImg(cv::Rect(0, 0, oImg.cols, oImg.rows))); oImg = tempImg; break; } case YOLO_CLS: // CenterCrop + case YOLO_CLS_HALF: { int h = iImg.rows; int w = iImg.cols; int m = min(h, w); int top = (h - m) / 2; int left = (w - m) / 2; - cv::resize(oImg(cv::Rect(left, top, m, m)), oImg, cv::Size(iImgSize.at(0), iImgSize.at(1))); + cv::resize(oImg(cv::Rect(left, top, m, m)), oImg, cv::Size(iimgSize.at(0), iimgSize.at(1))); break; } } @@ -100,18 +101,20 @@ char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Ma const char* YOLO_V8::CreateSession(DL_INIT_PARAM& iParams) { const char* Ret = RET_OK; - if (session) + if (session_) { // Clear node names from previous declaration - for (auto& name : inputNodeNames) { + for (auto& name : inputNodeNames_) + { delete[] name; } - inputNodeNames.clear(); + inputNodeNames_.clear(); - for (auto& name : outputNodeNames) { + for (auto& name : outputNodeNames_) + { delete[] name; } - outputNodeNames.clear(); + outputNodeNames_.clear(); } std::regex pattern("[\u4e00-\u9fa5]"); bool result = std::regex_search(iParams.modelPath, pattern); @@ -123,43 +126,43 @@ const char* YOLO_V8::CreateSession(DL_INIT_PARAM& iParams) { } try { - rectConfidenceThreshold = iParams.rectConfidenceThreshold; - iouThreshold = iParams.iouThreshold; - imgSize = iParams.imgSize; - modelType = iParams.modelType; - cudaEnable = iParams.cudaEnable; - env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "Yolo"); - Ort::SessionOptions sessionOption; + rectConfidenceThreshold_ = iParams.rectConfidenceThreshold; + iouThreshold_ = iParams.iouThreshold; + imgSize_ = iParams.imgSize; + modelType_ = iParams.modelType; + cudaEnable_ = iParams.cudaEnable; + env_ = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "Yolo"); + Ort::SessionOptions session_Option; if (iParams.cudaEnable) { OrtCUDAProviderOptions cudaOption; cudaOption.device_id = 0; - sessionOption.AppendExecutionProvider_CUDA(cudaOption); + session_Option.AppendExecutionProvider_CUDA(cudaOption); } - sessionOption.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); - sessionOption.SetIntraOpNumThreads(iParams.intraOpNumThreads); - sessionOption.SetLogSeverityLevel(iParams.logSeverityLevel); + session_Option.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); + session_Option.SetIntraOpNumThreads(iParams.intraOpNumThreads); + session_Option.SetLogSeverityLevel(iParams.logSeverityLevel); const char *modelPath = iParams.modelPath.c_str(); - session = std::make_unique(env, modelPath, sessionOption); + session_ = std::make_unique(env_, modelPath, session_Option); Ort::AllocatorWithDefaultOptions allocator; - size_t inputNodesNum = session->GetInputCount(); + size_t inputNodesNum = session_->GetInputCount(); for (size_t i = 0; i < inputNodesNum; i++) { - Ort::AllocatedStringPtr input_node_name = session->GetInputNameAllocated(i, allocator); + Ort::AllocatedStringPtr input_node_name = session_->GetInputNameAllocated(i, allocator); char* temp_buf = new char[50]; strcpy(temp_buf, input_node_name.get()); - inputNodeNames.push_back(temp_buf); + inputNodeNames_.push_back(temp_buf); } - size_t OutputNodesNum = session->GetOutputCount(); + size_t OutputNodesNum = session_->GetOutputCount(); for (size_t i = 0; i < OutputNodesNum; i++) { - Ort::AllocatedStringPtr output_node_name = session->GetOutputNameAllocated(i, allocator); + Ort::AllocatedStringPtr output_node_name = session_->GetOutputNameAllocated(i, allocator); char* temp_buf = new char[10]; strcpy(temp_buf, output_node_name.get()); - outputNodeNames.push_back(temp_buf); + outputNodeNames_.push_back(temp_buf); } - options = Ort::RunOptions{ nullptr }; + options_ = Ort::RunOptions{ nullptr }; WarmUpSession(); return RET_OK; } @@ -172,34 +175,35 @@ const char* YOLO_V8::CreateSession(DL_INIT_PARAM& iParams) { std::strcpy(merged, result.c_str()); std::cout << merged << std::endl; delete[] merged; - return "[YOLO_V8]:Create session failed."; + return "[YOLO_V8]:Create session_ failed."; } } -const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oResult) { +const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oResult) +{ #ifdef benchmark clock_t starttime_1 = clock(); #endif // benchmark const char* Ret = RET_OK; cv::Mat processedImg; - PreProcess(iImg, imgSize, processedImg); - if (modelType < 4) + PreProcess(iImg, imgSize_, processedImg); + if (modelType_ < 4) { float* blob = new float[processedImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector inputNodeDims = { 1, 3, imgSize.at(0), imgSize.at(1) }; - TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult); + std::vector inputNodeDims = { 1, 3, imgSize_.at(0), imgSize_.at(1) }; + TensorProcess(starttime_1, blob, inputNodeDims, oResult); } else { -#ifdef USE_CUDA +#ifdef YOLO_ONNX_ROS_CUDA_ENABLED half* blob = new half[processedImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector inputNodeDims = { 1,3,imgSize.at(0),imgSize.at(1) }; - TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult); + std::vector inputNodeDims = { 1,3,imgSize_.at(0),imgSize_.at(1) }; + TensorProcess(starttime_1, blob, inputNodeDims, oResult); #endif } @@ -208,16 +212,16 @@ const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oRe template -char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, std::vector& inputNodeDims, +char* YOLO_V8::TensorProcess(clock_t& starttime_1, N& blob, std::vector& inputNodeDims, std::vector& oResult) { Ort::Value inputTensor = Ort::Value::CreateTensor::type>( - Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), + Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize_.at(0) * imgSize_.at(1), inputNodeDims.data(), inputNodeDims.size()); #ifdef benchmark clock_t starttime_2 = clock(); #endif // benchmark - auto outputTensor = session->Run(options, inputNodeNames.data(), &inputTensor, 1, outputNodeNames.data(), - outputNodeNames.size()); + auto outputTensor = session_->Run(options_, inputNodeNames_.data(), &inputTensor, 1, outputNodeNames_.data(), + outputNodeNames_.size()); #ifdef benchmark clock_t starttime_3 = clock(); #endif // benchmark @@ -227,7 +231,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, std::vector outputNodeDims = tensor_info.GetShape(); auto output = outputTensor.front().GetTensorMutableData::type>(); delete[] blob; - switch (modelType) + switch (modelType_) { case YOLO_DETECT_V8: case YOLO_DETECT_V8_HALF: @@ -238,7 +242,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, std::vector confidences; std::vector boxes; cv::Mat rawData; - if (modelType == YOLO_DETECT_V8) + if (modelType_ == YOLO_DETECT_V8) { // FP32 rawData = cv::Mat(signalResultNum, strideNum, CV_32F, output); @@ -263,7 +267,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, cv::Point class_id; double maxClassScore; cv::minMaxLoc(scores, 0, &maxClassScore, 0, &class_id); - if (maxClassScore > rectConfidenceThreshold) + if (maxClassScore > rectConfidenceThreshold_) { confidences.push_back(maxClassScore); class_ids.push_back(class_id.x); @@ -272,19 +276,19 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, float w = data[2]; float h = data[3]; - int left = int((x - 0.5 * w) * resizeScales); - int top = int((y - 0.5 * h) * resizeScales); + int left = int((x - 0.5 * w) * resizeScales_); + int top = int((y - 0.5 * h) * resizeScales_); - int width = int(w * resizeScales); - int height = int(h * resizeScales); + int width = int(w * resizeScales_); + int height = int(h * resizeScales_); boxes.push_back(cv::Rect(left, top, width, height)); } data += signalResultNum; } std::vector nmsResult; - cv::dnn::NMSBoxes(boxes, confidences, rectConfidenceThreshold, iouThreshold, nmsResult); - for (int i = 0; i < nmsResult.size(); ++i) + cv::dnn::NMSBoxes(boxes, confidences, rectConfidenceThreshold_, iouThreshold_, nmsResult); + for (uint i = 0; i < nmsResult.size(); ++i) { int idx = nmsResult[i]; DL_RESULT result; @@ -299,7 +303,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, double pre_process_time = (double)(starttime_2 - starttime_1) / CLOCKS_PER_SEC * 1000; double process_time = (double)(starttime_3 - starttime_2) / CLOCKS_PER_SEC * 1000; double post_process_time = (double)(starttime_4 - starttime_3) / CLOCKS_PER_SEC * 1000; - if (cudaEnable) + if (cudaEnable_) { std::cout << "[YOLO_V8(CUDA)]: " << pre_process_time << "ms pre-process, " << process_time << "ms inference, " << post_process_time << "ms post-process." << std::endl; } @@ -315,7 +319,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, case YOLO_CLS_HALF: { cv::Mat rawData; - if (modelType == YOLO_CLS) { + if (modelType_ == YOLO_CLS) { // FP32 rawData = cv::Mat(1, this->classes.size(), CV_32F, output); } else { @@ -326,7 +330,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, float *data = (float *) rawData.data; DL_RESULT result; - for (int i = 0; i < this->classes.size(); i++) + for (uint i = 0; i < this->classes.size(); i++) { result.classId = i; result.confidence = data[i]; @@ -344,39 +348,39 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, char* YOLO_V8::WarmUpSession() { clock_t starttime_1 = clock(); - cv::Mat iImg = cv::Mat(cv::Size(imgSize.at(0), imgSize.at(1)), CV_8UC3); + cv::Mat iImg = cv::Mat(cv::Size(imgSize_.at(0), imgSize_.at(1)), CV_8UC3); cv::Mat processedImg; - PreProcess(iImg, imgSize, processedImg); - if (modelType < 4) + PreProcess(iImg, imgSize_, processedImg); + if (modelType_ < 4) { float* blob = new float[iImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector YOLO_input_node_dims = { 1, 3, imgSize.at(0), imgSize.at(1) }; + std::vector YOLO_input_node_dims = { 1, 3, imgSize_.at(0), imgSize_.at(1) }; Ort::Value input_tensor = Ort::Value::CreateTensor( - Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), + Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize_.at(0) * imgSize_.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); - auto output_tensors = session->Run(options, inputNodeNames.data(), &input_tensor, 1, outputNodeNames.data(), - outputNodeNames.size()); + auto output_tensors = session_->Run(options_, inputNodeNames_.data(), &input_tensor, 1, outputNodeNames_.data(), + outputNodeNames_.size()); delete[] blob; clock_t starttime_4 = clock(); double post_process_time = (double)(starttime_4 - starttime_1) / CLOCKS_PER_SEC * 1000; - if (cudaEnable) + if (cudaEnable_) { std::cout << "[YOLO_V8(CUDA)]: " << "Cuda warm-up cost " << post_process_time << " ms. " << std::endl; } } else { -#ifdef USE_CUDA +#ifdef YOLO_ONNX_ROS_CUDA_ENABLED half* blob = new half[iImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector YOLO_input_node_dims = { 1,3,imgSize.at(0),imgSize.at(1) }; - Ort::Value input_tensor = Ort::Value::CreateTensor(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); - auto output_tensors = session->Run(options, inputNodeNames.data(), &input_tensor, 1, outputNodeNames.data(), outputNodeNames.size()); + std::vector YOLO_input_node_dims = { 1,3,imgSize_.at(0),imgSize_.at(1) }; + Ort::Value input_tensor = Ort::Value::CreateTensor(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize_.at(0) * imgSize_.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); + auto output_tensors = session_->Run(options_, inputNodeNames_.data(), &input_tensor, 1, outputNodeNames_.data(), outputNodeNames_.size()); delete[] blob; clock_t starttime_4 = clock(); double post_process_time = (double)(starttime_4 - starttime_1) / CLOCKS_PER_SEC * 1000; - if (cudaEnable) + if (cudaEnable_) { std::cout << "[YOLO_V8(CUDA)]: " << "Cuda warm-up cost " << post_process_time << " ms. " << std::endl; } From 63e4f11723cb93702fe09c50fae0935d2f93bd58 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 10 Sep 2025 17:02:43 +0200 Subject: [PATCH 17/38] Made the yolo a catkin package --- .github/workflows/main.yml | 13 +++++++++++++ CMakeLists.txt | 10 +++++----- {inc => include}/inference.h | 0 {inc => include}/yolo_inference.h | 0 package.xml | 29 +++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/main.yml rename {inc => include}/inference.h (100%) rename {inc => include}/yolo_inference.h (100%) create mode 100644 package.xml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..4f3af87 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,13 @@ +name: CI + +on: [push, pull_request] + +jobs: + tue-ci: + name: TUe CI - ${{ github.event_name }} + runs-on: ubuntu-latest + steps: + - name: TUe CI + uses: tue-robotics/tue-env/ci/main@master + with: + package: ${{ github.event.repository.name }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c27a04..31556de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ include_directories(${OpenCV_INCLUDE_DIRS}) # -------------- ONNXRuntime ------------------# set(ONNXRUNTIME_VERSION 1.21.0) -set(ONNXRUNTIME_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../hero_sam/onnxruntime-linux-x64-gpu-1.21.1") +set(ONNXRUNTIME_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../hero_sam.bak/onnxruntime-linux-x64-gpu-1.21.1") include_directories(${ONNXRUNTIME_ROOT}/include) # -------------- Cuda ------------------# @@ -43,7 +43,7 @@ set(PROJECT_SOURCES # Main executable (without tests) add_executable(${PROJECT_NAME} ${PROJECT_SOURCES}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # Link libraries for main executable target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so) @@ -54,7 +54,7 @@ add_executable(${PROJECT_NAME}_test src/yolo_inference.cpp # Include only the source files needed for testing (not main.cpp) ) -target_include_directories(${PROJECT_NAME}_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc) +target_include_directories(${PROJECT_NAME}_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) # Link libraries for test executable target_link_libraries(${PROJECT_NAME}_test @@ -69,10 +69,10 @@ add_test(NAME yolo_tests COMMAND ${PROJECT_NAME}_test) # Download https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/cfg/datasets/coco.yaml # and put it in the same folder of the executable file -configure_file(../hero_sam/yolo_inference/data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) +configure_file(/home/amigo/Documents/repos/hero_sam.bak/yolo_inference/data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) # Copy yolov8n.onnx file to the same folder of the executable file -configure_file(../hero_sam/yolo_inference/model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) +configure_file(/home/amigo/Documents/repos/hero_sam.bak/yolo_inference/model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) # Create folder name images in the same folder of the executable file add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD diff --git a/inc/inference.h b/include/inference.h similarity index 100% rename from inc/inference.h rename to include/inference.h diff --git a/inc/yolo_inference.h b/include/yolo_inference.h similarity index 100% rename from inc/yolo_inference.h rename to include/yolo_inference.h diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..8106bc0 --- /dev/null +++ b/package.xml @@ -0,0 +1,29 @@ + + + + yolo_onnx_ros + 0.0.0 + Yolo inference + + Iason Theodorou + + ToDo + + catkin + + libopencv-dev + libopencv-dev + onnxruntime_ros + onnxruntime_ros + + catkin_lint_cmake + + doxygen + + + + + + From 17421561268fa2b9a2f728976746e0eb25adbbc0 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 10 Sep 2025 17:05:40 +0200 Subject: [PATCH 18/38] Renamed inference files to detection --- CMakeLists.txt | 2 +- include/{inference.h => detection.h} | 0 src/{inference.cpp => detection.cpp} | 2 +- src/main.cpp | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename include/{inference.h => detection.h} (100%) rename src/{inference.cpp => detection.cpp} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31556de..9d86cf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ include_directories(/usr/local/cuda/include) set(PROJECT_SOURCES src/main.cpp src/yolo_inference.cpp - src/inference.cpp) + src/detection.cpp) # Main executable (without tests) add_executable(${PROJECT_NAME} ${PROJECT_SOURCES}) diff --git a/include/inference.h b/include/detection.h similarity index 100% rename from include/inference.h rename to include/detection.h diff --git a/src/inference.cpp b/src/detection.cpp similarity index 99% rename from src/inference.cpp rename to src/detection.cpp index 791a2fa..a52660b 100644 --- a/src/inference.cpp +++ b/src/detection.cpp @@ -1,6 +1,6 @@ #include #include -#include "inference.h" +#include "detection.h" #include #include #include diff --git a/src/main.cpp b/src/main.cpp index 839ca9a..7733f41 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #include #include -#include "inference.h" +#include "detection.h" #include #include #include From ef1f775c8b5b7d3d72db4fff1480a3105f09d76f Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Wed, 10 Sep 2025 20:19:21 +0200 Subject: [PATCH 19/38] Create single point of contact for Initialization and Detection (inference) --- src/detection.cpp | 23 ++++++++++++----------- src/main.cpp | 8 +++++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/detection.cpp b/src/detection.cpp index a52660b..b8303fc 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -5,9 +5,9 @@ #include #include -std::vector DetectObjects(std::unique_ptr& p, const cv::Mat& img) { +void Detector(std::unique_ptr& p, std::vector& res, const cv::Mat& img) { + - std::vector res; p->RunSession(img, res); for (auto& re : res) @@ -42,12 +42,12 @@ std::vector DetectObjects(std::unique_ptr& p, const cv::Mat& } - std::cout << "Press any key to exit" << std::endl; - cv::imshow("Result of Detection", img); - cv::waitKey(0); - cv::destroyAllWindows(); - return res; - } + //std::cout << "Press any key to exit" << std::endl; + //cv::imshow("Result of Detection", img); + //cv::waitKey(0); + //cv::destroyAllWindows(); + +} @@ -137,14 +137,15 @@ int ReadCocoYaml(std::unique_ptr& p) { return 0; } -std::unique_ptr Initialize() +std::tuple, std::vector> Initialize() { std::unique_ptr yoloDetector = std::make_unique(); - + std::vecroet res; ReadCocoYaml(yoloDetector); DL_INIT_PARAM params; params.rectConfidenceThreshold = 0.1; params.iouThreshold = 0.5; + // Mayve change the model from V11 to V8 params.modelPath = "yolo11m.onnx"; params.imgSize = { 640, 640 }; #ifdef USE_CUDA @@ -163,7 +164,7 @@ std::unique_ptr Initialize() #endif yoloDetector->CreateSession(params); - return yoloDetector; + return std::make_tuple(std::move(yoloDetector), std::move(res)); } diff --git a/src/main.cpp b/src/main.cpp index 7733f41..d7e9714 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,10 @@ int main() { // An example of how to use the YOLO_V8 class for object detection - std::unique_ptr yoloDetector = Initialize(); + std::unique_ptr yoloDetector; + std::vector results; + std::tie(yoloDetector, results) = Initialize(); + std::filesystem::path current_path = std::filesystem::current_path(); std::filesystem::path imgs_path = current_path / "images"; for (auto& i : std::filesystem::directory_iterator(imgs_path)) @@ -17,8 +20,7 @@ int main() { std::string img_path = i.path().string(); cv::Mat img = cv::imread(img_path); - std::vector results; - results = DetectObjects(yoloDetector, img); + DetectObjects(yoloDetector, img, results); } } From 8a9cfc6f0b8babbd04fdb8807ecd6c5b1bfefe19 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Fri, 12 Sep 2025 11:22:26 +0200 Subject: [PATCH 20/38] Refactored test according to detection.h way of inference --- CMakeLists.txt | 1 + test/yolo_test.cpp | 17 ++++++----------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d86cf3..4da80a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_ROOT}/lib/lib add_executable(${PROJECT_NAME}_test test/yolo_test.cpp src/yolo_inference.cpp # Include only the source files needed for testing (not main.cpp) + src/detection.cpp ) target_include_directories(${PROJECT_NAME}_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/test/yolo_test.cpp b/test/yolo_test.cpp index 2368892..ccdddc7 100644 --- a/test/yolo_test.cpp +++ b/test/yolo_test.cpp @@ -1,4 +1,5 @@ #include "yolo_inference.h" +#include "detection.h" #include #include #include @@ -19,14 +20,9 @@ class YoloInferenceTest : public testing::Test cv::randu(testImage_realistic, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255)); // Setup common parameters - params.modelPath = "yolo11m.onnx"; - params.modelType = YOLO_DETECT_V8; - params.imgSize = { 640, 640 }; - params.rectConfidenceThreshold = 0.6; - params.iouThreshold = 0.5; - params.cudaEnable = false; - - yolo = std::make_unique(); + std::tie(yolo, params) = Initialize(); + + NonSquareImgSize = { testImage_800x600.cols, testImage_800x600.rows }; } @@ -41,8 +37,9 @@ class YoloInferenceTest : public testing::Test cv::Mat testImage_800x600; cv::Mat testImage_realistic; DL_INIT_PARAM params; - std::unique_ptr yolo; std::vector NonSquareImgSize; + std::unique_ptr yolo; + std::vector results; }; TEST_F(YoloInferenceTest, ObjectCreation) @@ -91,8 +88,6 @@ TEST_F(YoloInferenceTest, FullInferencePipeline) const char* createResult = yolo->CreateSession(params); ASSERT_EQ(createResult, nullptr) << "Session creation must succeed for inference test"; - // Then run inference - std::vector results; const char* runResult = yolo->RunSession(testImage_realistic, results); EXPECT_EQ(runResult, nullptr) << "RunSession should succeed"; From 34a82dff91bafde4fd01f50b06de2e2ab0304c34 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Fri, 12 Sep 2025 11:23:53 +0200 Subject: [PATCH 21/38] Aligned Preprocessing and ONNX inference height width dimensions --- include/yolo_inference.h | 4 ++-- src/yolo_inference.cpp | 32 ++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/include/yolo_inference.h b/include/yolo_inference.h index 944a5fe..13dffea 100644 --- a/include/yolo_inference.h +++ b/include/yolo_inference.h @@ -61,8 +61,8 @@ class YOLO_V8 const char* CreateSession(DL_INIT_PARAM& iParams); const char* RunSession(const cv::Mat& iImg, std::vector& oResult); - - char* PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Mat& oImg); + // imgSize is [width, height] + char* PreProcess(const cv::Mat& iImg, const std::vector& iImgSize, cv::Mat& oImg); std::vector classes{}; diff --git a/src/yolo_inference.cpp b/src/yolo_inference.cpp index 6ce0888..00f3e86 100644 --- a/src/yolo_inference.cpp +++ b/src/yolo_inference.cpp @@ -49,8 +49,13 @@ char* BlobFromImage(const cv::Mat& iImg, T& iBlob) { } -char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Mat& oImg) +char* YOLO_V8::PreProcess(const cv::Mat& iImg, const std::vector& iImgSize, cv::Mat& oImg) { + // Basic validation + if (iImg.empty()) return (char*)"[YOLO_V8]: Empty input image."; + if (iImgSize.size() != 2 || iImgSize[0] <= 0 || iImgSize[1] <= 0) + return (char*)"[YOLO_V8]: Invalid target image size."; + if (iImg.channels() == 3) { oImg = iImg.clone(); @@ -70,15 +75,18 @@ char* YOLO_V8::PreProcess(const cv::Mat& iImg, std::vector iImgSize, cv::Ma { if (iImg.cols >= iImg.rows) { + // scale by target width resizeScales = iImg.cols / (float)iImgSize.at(0); - cv::resize(oImg, oImg, cv::Size(iImgSize.at(0), int(iImg.rows / resizeScales))); + cv::resize(oImg, oImg, cv::Size(iImgSize.at(0), int(std::round(iImg.rows / resizeScales)))); } else { - resizeScales = iImg.rows / (float)iImgSize.at(0); - cv::resize(oImg, oImg, cv::Size(int(iImg.cols / resizeScales), iImgSize.at(1))); + // scale by target height + resizeScales = iImg.rows / (float)iImgSize.at(1); + cv::resize(oImg, oImg, cv::Size(int(std::round(iImg.cols / resizeScales)), iImgSize.at(1))); } - cv::Mat tempImg = cv::Mat::zeros(iImgSize.at(0), iImgSize.at(1), CV_8UC3); + // Note: cv::Mat takes (rows, cols) = (height, width) + cv::Mat tempImg = cv::Mat::zeros(iImgSize.at(1), iImgSize.at(0), CV_8UC3); oImg.copyTo(tempImg(cv::Rect(0, 0, oImg.cols, oImg.rows))); oImg = tempImg; break; @@ -181,8 +189,7 @@ const char* YOLO_V8::CreateSession(DL_INIT_PARAM& iParams) { const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oResult) { #ifdef benchmark clock_t starttime_1 = clock(); -#endif // benchmark - +#endif const char* Ret = RET_OK; cv::Mat processedImg; PreProcess(iImg, imgSize, processedImg); @@ -190,7 +197,8 @@ const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oRe { float* blob = new float[processedImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector inputNodeDims = { 1, 3, imgSize.at(0), imgSize.at(1) }; + // ONNX expects {N, C, H, W} = {1, 3, height, width} + std::vector inputNodeDims = { 1, 3, imgSize.at(1), imgSize.at(0) }; TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult); } else @@ -198,11 +206,10 @@ const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oRe #ifdef USE_CUDA half* blob = new half[processedImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector inputNodeDims = { 1,3,imgSize.at(0),imgSize.at(1) }; + std::vector inputNodeDims = { 1, 3, imgSize.at(1), imgSize.at(0) }; TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult); #endif } - return Ret; } @@ -344,6 +351,7 @@ char* YOLO_V8::TensorProcess(clock_t& starttime_1, const cv::Mat& iImg, N& blob, char* YOLO_V8::WarmUpSession() { clock_t starttime_1 = clock(); + // cv::Size takes (width, height) cv::Mat iImg = cv::Mat(cv::Size(imgSize.at(0), imgSize.at(1)), CV_8UC3); cv::Mat processedImg; PreProcess(iImg, imgSize, processedImg); @@ -351,7 +359,7 @@ char* YOLO_V8::WarmUpSession() { { float* blob = new float[iImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector YOLO_input_node_dims = { 1, 3, imgSize.at(0), imgSize.at(1) }; + std::vector YOLO_input_node_dims = { 1, 3, imgSize.at(1), imgSize.at(0) }; Ort::Value input_tensor = Ort::Value::CreateTensor( Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); @@ -370,7 +378,7 @@ char* YOLO_V8::WarmUpSession() { #ifdef USE_CUDA half* blob = new half[iImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector YOLO_input_node_dims = { 1,3,imgSize.at(0),imgSize.at(1) }; + std::vector YOLO_input_node_dims = { 1, 3, imgSize.at(1), imgSize.at(0) }; Ort::Value input_tensor = Ort::Value::CreateTensor(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); auto output_tensors = session->Run(options, inputNodeNames.data(), &input_tensor, 1, outputNodeNames.data(), outputNodeNames.size()); delete[] blob; From 2318110066bc857b56146b0e37e78be54b2dcb2a Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Fri, 12 Sep 2025 11:26:54 +0200 Subject: [PATCH 22/38] Fixed the results vector in order not too keep boxes from previous images --- include/detection.h | 4 ++-- src/detection.cpp | 20 ++++++++++---------- src/main.cpp | 13 +++++++------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/detection.h b/include/detection.h index 7f9ebc6..0c113bf 100644 --- a/include/detection.h +++ b/include/detection.h @@ -1,5 +1,5 @@ #include "yolo_inference.h" -std::unique_ptr Initialize(); -std::vector DetectObjects(std::unique_ptr& p, const cv::Mat& img); +std::tuple, DL_INIT_PARAM> Initialize(); +std::vector Detector(std::unique_ptr& p, const cv::Mat& img); int ReadCocoYaml(std::unique_ptr& p); \ No newline at end of file diff --git a/src/detection.cpp b/src/detection.cpp index b8303fc..9ca1049 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -4,10 +4,10 @@ #include #include #include +#include "yolo_inference.h" +std::vector Detector(std::unique_ptr& p, const cv::Mat& img) { -void Detector(std::unique_ptr& p, std::vector& res, const cv::Mat& img) { - - + std::vector res; p->RunSession(img, res); for (auto& re : res) @@ -42,10 +42,11 @@ void Detector(std::unique_ptr& p, std::vector& res, const cv } - //std::cout << "Press any key to exit" << std::endl; - //cv::imshow("Result of Detection", img); - //cv::waitKey(0); - //cv::destroyAllWindows(); + std::cout << "Press any key to exit" << std::endl; + cv::imshow("Result of Detection", img); + cv::waitKey(0); + cv::destroyAllWindows(); + return std::move(res); } @@ -137,10 +138,9 @@ int ReadCocoYaml(std::unique_ptr& p) { return 0; } -std::tuple, std::vector> Initialize() +std::tuple, DL_INIT_PARAM> Initialize() { std::unique_ptr yoloDetector = std::make_unique(); - std::vecroet res; ReadCocoYaml(yoloDetector); DL_INIT_PARAM params; params.rectConfidenceThreshold = 0.1; @@ -164,7 +164,7 @@ std::tuple, std::vector> Initialize() #endif yoloDetector->CreateSession(params); - return std::make_tuple(std::move(yoloDetector), std::move(res)); + return std::make_tuple(std::move(yoloDetector), std::move(params)); } diff --git a/src/main.cpp b/src/main.cpp index d7e9714..b87da42 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,21 +7,22 @@ int main() { - // An example of how to use the YOLO_V8 class for object detection std::unique_ptr yoloDetector; - std::vector results; - std::tie(yoloDetector, results) = Initialize(); + DL_INIT_PARAM params; + + std::tie(yoloDetector, params) = Initialize(); std::filesystem::path current_path = std::filesystem::current_path(); - std::filesystem::path imgs_path = current_path / "images"; + std::filesystem::path imgs_path = "/home/amigo/Documents/repos/hero_sam.bak/sam_inference/build/images"; for (auto& i : std::filesystem::directory_iterator(imgs_path)) { if (i.path().extension() == ".jpg" || i.path().extension() == ".png" || i.path().extension() == ".jpeg") { std::string img_path = i.path().string(); cv::Mat img = cv::imread(img_path); - DetectObjects(yoloDetector, img, results); -} + std::vector results; + results = Detector(yoloDetector, img); + } } From afb89729e0d86b2fc8e609ee44205a890938e2b4 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Fri, 12 Sep 2025 14:09:38 +0200 Subject: [PATCH 23/38] Change CMake to be catkin package and small overall changes to run on ed_sensor_integration --- CMakeLists.txt | 98 ++++++++++++++++++++--------------------------- package.xml | 1 + src/detection.cpp | 12 +++--- 3 files changed, 48 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4da80a0..7fc64bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,81 +1,65 @@ -cmake_minimum_required(VERSION 3.14) # FetchContent requires 3.14+ +cmake_minimum_required(VERSION 3.14) -set(PROJECT_NAME Yolov8OnnxRuntimeCPPInference) +set(PROJECT_NAME yolo_onnx_ros) project(${PROJECT_NAME} VERSION 0.0.1 LANGUAGES CXX) -# -------------- Support C++17 for using filesystem ------------------# set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) -# to show header files in Qt Creator -file(GLOB_RECURSE HEADER_FILES include/*.h) +find_package(catkin REQUIRED COMPONENTS + roscpp -# -------------- Google Test ------------------# -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip ) - -FetchContent_MakeAvailable(googletest) - -enable_testing() - -# -------------- OpenCV ------------------# find_package(OpenCV REQUIRED) -include_directories(${OpenCV_INCLUDE_DIRS}) -# -------------- ONNXRuntime ------------------# -set(ONNXRUNTIME_VERSION 1.21.0) +# ONNX Runtime (adjust to your local path) set(ONNXRUNTIME_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../hero_sam.bak/onnxruntime-linux-x64-gpu-1.21.1") include_directories(${ONNXRUNTIME_ROOT}/include) -# -------------- Cuda ------------------# +# CUDA (optional) add_definitions(-DUSE_CUDA=1) include_directories(/usr/local/cuda/include) -set(PROJECT_SOURCES - src/main.cpp - src/yolo_inference.cpp - src/detection.cpp) - -# Main executable (without tests) -add_executable(${PROJECT_NAME} ${PROJECT_SOURCES}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) - -# Link libraries for main executable -target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so) +catkin_package( + INCLUDE_DIRS include + LIBRARIES ${PROJECT_NAME}_core + CATKIN_DEPENDS roscpp + DEPENDS OpenCV +) -# Test executable -add_executable(${PROJECT_NAME}_test - test/yolo_test.cpp - src/yolo_inference.cpp # Include only the source files needed for testing (not main.cpp) - src/detection.cpp +include_directories( + include + ${catkin_INCLUDE_DIRS} + ${OpenCV_INCLUDE_DIRS} ) -target_include_directories(${PROJECT_NAME}_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +# Core library (to be linked by other packages) +add_library(${PROJECT_NAME}_core + src/yolo_inference.cpp + src/detection.cpp +) +target_link_libraries(${PROJECT_NAME}_core + ${catkin_LIBRARIES} + ${OpenCV_LIBS} + ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so +) -# Link libraries for test executable -target_link_libraries(${PROJECT_NAME}_test - gtest_main - gmock_main - ${OpenCV_LIBS} - ${ONNXRUNTIME_ROOT}/lib/libonnxruntime.so +# Node executable +add_executable(${PROJECT_NAME} + src/main.cpp +) +target_link_libraries(${PROJECT_NAME} + ${PROJECT_NAME}_core ) -# Add test to CTest -add_test(NAME yolo_tests COMMAND ${PROJECT_NAME}_test) +# Install headers, library, and node so other packages can depend/link +install(TARGETS ${PROJECT_NAME}_core ${PROJECT_NAME} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) +install(DIRECTORY include/ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}) -# Download https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/cfg/datasets/coco.yaml -# and put it in the same folder of the executable file +# Runtime assets (# Download https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/cfg/datasets/coco.yaml) configure_file(/home/amigo/Documents/repos/hero_sam.bak/yolo_inference/data/coco.yaml ${CMAKE_CURRENT_BINARY_DIR}/coco.yaml COPYONLY) - -# Copy yolov8n.onnx file to the same folder of the executable file -configure_file(/home/amigo/Documents/repos/hero_sam.bak/yolo_inference/model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) - -# Create folder name images in the same folder of the executable file -add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/images -) +configure_file(/home/amigo/Documents/repos/hero_sam.bak/yolo_inference/model/yolo11m.onnx ${CMAKE_CURRENT_BINARY_DIR}/yolo11m.onnx COPYONLY) \ No newline at end of file diff --git a/package.xml b/package.xml index 8106bc0..12d03ff 100644 --- a/package.xml +++ b/package.xml @@ -10,6 +10,7 @@ Iason Theodorou ToDo + roscpp catkin diff --git a/src/detection.cpp b/src/detection.cpp index 9ca1049..3086d77 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -5,11 +5,12 @@ #include #include #include "yolo_inference.h" +//#define LOGGING std::vector Detector(std::unique_ptr& p, const cv::Mat& img) { std::vector res; p->RunSession(img, res); - + #ifdef LOGGING for (auto& re : res) { cv::RNG rng(cv::getTickCount()); @@ -39,13 +40,12 @@ std::vector Detector(std::unique_ptr& p, const cv::Mat& img) cv::Scalar(0, 0, 0), 2 ); - - - } + } std::cout << "Press any key to exit" << std::endl; cv::imshow("Result of Detection", img); cv::waitKey(0); cv::destroyAllWindows(); + #endif return std::move(res); } @@ -92,7 +92,7 @@ std::vector Detector(std::unique_ptr& p, const cv::Mat& img) int ReadCocoYaml(std::unique_ptr& p) { // Open the YAML file - std::ifstream file("coco.yaml"); + std::ifstream file("/home/amigo/Documents/repos/hero_sam.bak/yolo_inference/data/coco.yaml"); if (!file.is_open()) { std::cerr << "Failed to open file" << std::endl; @@ -146,7 +146,7 @@ std::tuple, DL_INIT_PARAM> Initialize() params.rectConfidenceThreshold = 0.1; params.iouThreshold = 0.5; // Mayve change the model from V11 to V8 - params.modelPath = "yolo11m.onnx"; + params.modelPath = "/home/amigo/Documents/repos/yolo_onnx_ros/build/yolo11m.onnx"; params.imgSize = { 640, 640 }; #ifdef USE_CUDA params.cudaEnable = true; From ec2c4c75002fdd8aa18712a6ff9e621ea13b4c21 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 30 Sep 2025 21:08:58 +0200 Subject: [PATCH 24/38] fix main.cpp --- src/main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 651dcc4..a2278c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,7 @@ int main() std::tie(yoloDetector, params) = Initialize(); std::filesystem::path current_path = std::filesystem::current_path(); - std::filesystem::path imgs_path = "/home/amigo/Documents/repos/hero_sam.bak/sam_inference/build/images"; + std::filesystem::path imgs_path = current_path / "images"; for (auto& i : std::filesystem::directory_iterator(imgs_path)) { if (i.path().extension() == ".jpg" || i.path().extension() == ".png" || i.path().extension() == ".jpeg") @@ -22,6 +22,12 @@ int main() cv::Mat img = cv::imread(img_path); std::vector results; results = Detector(yoloDetector, img); + for (const auto& result : results) + { + std::cout << "Image path: " << img_path << "\n" + << "class id: " << result.classId << "\n" + << "confidence: " << result.confidence << "\n"; + } } } From 266ebda1bd542eb9c62708f7bcdb9c17cee544ee Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 30 Sep 2025 21:09:27 +0200 Subject: [PATCH 25/38] Correct logic for cuda; Not compiling --- include/yolo_onnx_ros/yolo_inference.hpp | 2 ++ src/detection.cpp | 2 ++ src/yolo_inference.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/yolo_onnx_ros/yolo_inference.hpp b/include/yolo_onnx_ros/yolo_inference.hpp index 2f54282..bf25bd3 100644 --- a/include/yolo_onnx_ros/yolo_inference.hpp +++ b/include/yolo_onnx_ros/yolo_inference.hpp @@ -8,6 +8,8 @@ #include #include "onnxruntime_cxx_api.h" +#include + #ifdef YOLO_ONNX_ROS_CUDA_ENABLED #include #endif diff --git a/src/detection.cpp b/src/detection.cpp index 2d4452c..de7d373 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -1,4 +1,6 @@ #include "yolo_onnx_ros/detection.hpp" +#include + #include #include #include diff --git a/src/yolo_inference.cpp b/src/yolo_inference.cpp index c911c24..616791d 100644 --- a/src/yolo_inference.cpp +++ b/src/yolo_inference.cpp @@ -199,7 +199,7 @@ const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oRe #ifdef YOLO_ONNX_ROS_CUDA_ENABLED half* blob = new half[processedImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector inputNodeDims = { 1, 3, imgSize.at(1), imgSize.at(0) }; + std::vector inputNodeDims = { 1, 3, imgSize_.at(1), imgSize_.at(0) }; TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult); #endif } @@ -372,13 +372,13 @@ char* YOLO_V8::WarmUpSession() { #ifdef YOLO_ONNX_ROS_CUDA_ENABLED half* blob = new half[iImg.total() * 3]; BlobFromImage(processedImg, blob); - std::vector YOLO_input_node_dims = { 1, 3, imgSize.at(1), imgSize.at(0) }; - Ort::Value input_tensor = Ort::Value::CreateTensor(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); - auto output_tensors = session->Run(options, inputNodeNames.data(), &input_tensor, 1, outputNodeNames.data(), outputNodeNames.size()); + std::vector YOLO_input_node_dims = { 1, 3, imgSize_.at(1), imgSize_.at(0) }; + Ort::Value input_tensor = Ort::Value::CreateTensor(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize_.at(0) * imgSize_.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size()); + auto output_tensors = session_->Run(options, inputNodeNames_.data(), &input_tensor, 1, outputNodeNames_.data(), outputNodeNames_.size()); delete[] blob; clock_t starttime_4 = clock(); double post_process_time = (double)(starttime_4 - starttime_1) / CLOCKS_PER_SEC * 1000; - if (cudaEnable) + if (cudaEnable_) { std::cout << "[YOLO_V8(CUDA)]: " << "Cuda warm-up cost " << post_process_time << " ms. " << std::endl; } From 5c01ab4caf398207e87a022cefbfd4da07847d89 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 30 Sep 2025 21:10:28 +0200 Subject: [PATCH 26/38] Ignore onnx models --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ddd4b43..eb55d1a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ SPEED-SAM-C-TENSORRT/ sam_inference/model/FastSAM-x.onnx mask* segmentation_results* + +# Models +*.onnx From acd9b51c4483fde53c247efbaa8a90b20a660d50 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 30 Sep 2025 21:15:33 +0200 Subject: [PATCH 27/38] Make linking conditional based on CUDA --- CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a22893c..c337afc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,11 @@ find_package(catkin REQUIRED set(${PROJECT_NAME}_CUDA_ENABLED ${onnxruntime_ros_CUDA_ENABLED}) -if(onnxruntime_ros_CUDA_ENABLED) +if(${PROJECT_NAME}_CUDA_ENABLED) find_package(CUDAToolkit REQUIRED) + set(${PROJECT_NAME}_CUDA_CATKIN_DEPENDS "CUDAToolkit") + set(${PROJECT_NAME}_CUDA_INCLUDE_DIRS "${CUDAToolkit_INCLUDE_DIRS}") + set(${PROJECT_NAME}_CUDA_TARGET_LINK_LIBRARIES "CUDAToolkit") endif() configure_file(include/${PROJECT_NAME}/config.hpp.in ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}/${PROJECT_NAME}/config.hpp) @@ -35,7 +38,7 @@ catkin_package( INCLUDE_DIRS include ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION} LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS - DEPENDS CUDAToolkit OpenCV + DEPENDS ${${PROJECT_NAME}_CUDA_CATKIN_DEPENDS} OpenCV ) # ------------------------------------------------------------------------------------------------ @@ -46,7 +49,7 @@ include_directories( include ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION} SYSTEM - ${CUDAToolkit_INCLUDE_DIRS} + ${${PROJECT_NAME}_CUDA_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS} ) @@ -55,7 +58,7 @@ add_library(${PROJECT_NAME} src/detection.cpp src/yolo_inference.cpp ) -target_link_libraries(${PROJECT_NAME} CUDA::toolkit ${OpenCV_LIBRARIES} ${catkin_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} ${${PROJECT_NAME}_CUDA_TARGET_LINK_LIBRARIES} ${OpenCV_LIBRARIES} ${catkin_LIBRARIES}) # add_dependencies(${PROJECT_NAME} generate_config_hpp) add_executable(test_${PROJECT_NAME} From 38032f7dcd1aa6cd512855caf55609f779217256 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 14 Oct 2025 19:49:43 +0200 Subject: [PATCH 28/38] Fix conditional cuda --- CMakeLists.txt | 2 +- include/yolo_onnx_ros/config.hpp.in | 5 +++-- include/yolo_onnx_ros/yolo_inference.hpp | 2 +- src/detection.cpp | 2 +- src/yolo_inference.cpp | 6 +++--- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c337afc..ffd9371 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ if(${PROJECT_NAME}_CUDA_ENABLED) find_package(CUDAToolkit REQUIRED) set(${PROJECT_NAME}_CUDA_CATKIN_DEPENDS "CUDAToolkit") set(${PROJECT_NAME}_CUDA_INCLUDE_DIRS "${CUDAToolkit_INCLUDE_DIRS}") - set(${PROJECT_NAME}_CUDA_TARGET_LINK_LIBRARIES "CUDAToolkit") + set(${PROJECT_NAME}_CUDA_TARGET_LINK_LIBRARIES "CUDA::cudart") endif() configure_file(include/${PROJECT_NAME}/config.hpp.in ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}/${PROJECT_NAME}/config.hpp) diff --git a/include/yolo_onnx_ros/config.hpp.in b/include/yolo_onnx_ros/config.hpp.in index 8ea1605..7c7f2ff 100644 --- a/include/yolo_onnx_ros/config.hpp.in +++ b/include/yolo_onnx_ros/config.hpp.in @@ -1,7 +1,8 @@ #ifndef YOLO_ONNX_ROS_CONFIG_HPP_ #define YOLO_ONNX_ROS_CONFIG_HPP_ -//Set which version of the Tree Interface to use -#define YOLO_ONNX_ROS_CUDA_ENABLED @onnx_yolo_ros_CUDA_ENABLED@ +#define YOLO_ONNX_FALSE 0 +#define YOLO_ONNX_TRUE 1 +#define YOLO_ONNX_ROS_CUDA_ENABLED YOLO_ONNX_@yolo_onnx_ros_CUDA_ENABLED@ #endif //#define YOLO_ONNX_ROS_CONFIG_HPP_ diff --git a/include/yolo_onnx_ros/yolo_inference.hpp b/include/yolo_onnx_ros/yolo_inference.hpp index bf25bd3..4ef6b5e 100644 --- a/include/yolo_onnx_ros/yolo_inference.hpp +++ b/include/yolo_onnx_ros/yolo_inference.hpp @@ -10,7 +10,7 @@ #include -#ifdef YOLO_ONNX_ROS_CUDA_ENABLED +#if defined(YOLO_ONNX_ROS_CUDA_ENABLED) && YOLO_ONNX_ROS_CUDA_ENABLED #include #endif diff --git a/src/detection.cpp b/src/detection.cpp index de7d373..ed023f4 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -148,7 +148,7 @@ std::tuple, DL_INIT_PARAM> Initialize() // Mayve change the model from V11 to V8 params.modelPath = "yolo11m.onnx"; params.imgSize = { 640, 640 }; - #ifdef YOLO_ONNX_ROS_CUDA_ENABLED + #if defined(YOLO_ONNX_ROS_CUDA_ENABLED) && YOLO_ONNX_ROS_CUDA_ENABLED params.cudaEnable = true; // GPU FP32 inference diff --git a/src/yolo_inference.cpp b/src/yolo_inference.cpp index 616791d..ebda07b 100644 --- a/src/yolo_inference.cpp +++ b/src/yolo_inference.cpp @@ -4,7 +4,7 @@ #define benchmark #define min(a, b) (((a) < (b)) ? (a) : (b)) -#ifdef ONNX_YOLO_ROS_CUDA_ENABLED +#if defined(YOLO_ONNX_ROS_CUDA_ENABLED) && YOLO_ONNX_ROS_CUDA_ENABLED namespace Ort { template<> @@ -196,7 +196,7 @@ const char* YOLO_V8::RunSession(const cv::Mat& iImg, std::vector& oRe } else { -#ifdef YOLO_ONNX_ROS_CUDA_ENABLED +#if defined(YOLO_ONNX_ROS_CUDA_ENABLED) && YOLO_ONNX_ROS_CUDA_ENABLED half* blob = new half[processedImg.total() * 3]; BlobFromImage(processedImg, blob); std::vector inputNodeDims = { 1, 3, imgSize_.at(1), imgSize_.at(0) }; @@ -369,7 +369,7 @@ char* YOLO_V8::WarmUpSession() { } else { -#ifdef YOLO_ONNX_ROS_CUDA_ENABLED +#if defined(YOLO_ONNX_ROS_CUDA_ENABLED) && YOLO_ONNX_ROS_CUDA_ENABLED half* blob = new half[iImg.total() * 3]; BlobFromImage(processedImg, blob); std::vector YOLO_input_node_dims = { 1, 3, imgSize_.at(1), imgSize_.at(0) }; From 8e69019ac1a173a24ebe4388bc8290c03832cb64 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 14 Oct 2025 22:01:34 +0200 Subject: [PATCH 29/38] (actions) allow manual trigger --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4f3af87..5dcb6b6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,6 @@ name: CI -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: tue-ci: From d29d018347f4f8a488ff785515196f5d0fa486d0 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Tue, 21 Oct 2025 18:46:31 +0200 Subject: [PATCH 30/38] included .vscode file configs --- .vscode/c_cpp_properties_json | 19 +++++++ .vscode/launch.json | 45 +++++++++++++++++ .vscode/settings.json | 77 +++++++++++++++++++++++++++++ .vscode/tasks.json | 93 +++++++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 .vscode/c_cpp_properties_json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/c_cpp_properties_json b/.vscode/c_cpp_properties_json new file mode 100644 index 0000000..07812f5 --- /dev/null +++ b/.vscode/c_cpp_properties_json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/usr/include/opencv4", + "${workspaceFolder}/sam_inference/inc", + "${workspaceFolder}/sam_inference/build" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..eb2f055 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Yolo Model", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/devel/lib/yolo_onnx_ros/yolo_onnx_ros", // Path to the executable + "args": [], // Add any command-line arguments for your program here + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build", // Set the working directory + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "build-yolo-project" // Ensure the project is built before debugging + }, + { + "name": "Debug Yolo Test", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/Yolov8OnnxRuntimeCPPInference_test", // Path to the executable + "args": [], // Add any command-line arguments for your program here + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build", // Set the working directory + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "build-yolo-project" // Ensure the project is built before debugging + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..57bd363 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,77 @@ +{ + "files.associations": { + "iostream": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "shared_mutex": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "compare": "cpp", + "concepts": "cpp", + "numbers": "cpp", + "semaphore": "cpp", + "stop_token": "cpp", + "*.txx": "cpp", + "filesystem": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..5e878e7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,93 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build-sam-project", + "dependsOrder": "sequence", + "dependsOn": ["configure-sam", "build-sam-binary"], + "problemMatcher": ["$gcc"], + "group": "build" + }, + { + "label": "build-pipeline-project", + "dependsOrder": "sequence", + "dependsOn": ["configure-pipeline", "build-pipeline-binary"], + "problemMatcher": ["$gcc"], + "group": "build" + }, + { + "label": "build-yolo-project", + "dependsOrder": "sequence", + "dependsOn": ["configure-yolo", "build-yolo-binary"], + "problemMatcher": ["$gcc"], + "group": "build" + }, + { + "label": "configure-sam", + "type": "shell", + "command": "cmake", + "args": [ + "-DCMAKE_BUILD_TYPE=Debug", + "-S", "${workspaceFolder}/sam_inference", + "-B", "${workspaceFolder}/sam_inference/build" + ], + "problemMatcher": ["$gcc"] + }, + { + "label": "configure-pipeline", + "type": "shell", + "command": "cmake", + "args": [ + "-DCMAKE_BUILD_TYPE=Debug", + "-S", "${workspaceFolder}/pipeline", + "-B", "${workspaceFolder}/pipeline/build" + ], + "problemMatcher": ["$gcc"] + }, + { + "label": "configure-yolo", + "type": "shell", + "command": "cmake", + "args": [ + "-DCMAKE_BUILD_TYPE=Debug", + "-S", "${workspaceFolder}/", + "-B", "${workspaceFolder}/build" + ], + "problemMatcher": ["$gcc"] + }, + { + "label": "build-sam-binary", + "type": "shell", + "command": "cmake", + "args": [ + "--build", + "${workspaceFolder}/sam_inference/build", + "--config", "Debug" + ], + "problemMatcher": ["$gcc"] + }, + { + "label": "build-pipeline-binary", + "type": "shell", + "command": "cmake", + "args": [ + "--build", + "${workspaceFolder}/pipeline/build", + "--config", "Debug" + ], + "problemMatcher": ["$gcc"] + }, + { + "label": "build-yolo-binary", + "type": "shell", + "command": "cmake", + "args": [ + "--build", + "${workspaceFolder}/build", + "--config", "Debug" + ], + "problemMatcher": ["$gcc"] + } + + ] +} \ No newline at end of file From 297798010453de3ba859e2c38a8d9a769ebe5014 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Tue, 21 Oct 2025 19:49:42 +0200 Subject: [PATCH 31/38] updated tests on cmake lists --- CMakeLists.txt | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffd9371..d59157d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.5) project(yolo_onnx_ros) @@ -93,3 +93,25 @@ install( ${PROJECT_NAME} DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) + +# ------------------------------------------------------------------------------------------------ +# Testing +# ------------------------------------------------------------------------------------------------ +if (CATKIN_ENABLE_TESTING) + #find_package(catkin_lint_cmake REQUIRED) + #catkin_add_catkin_lint_test("-W2 --ignore HEADER_OUTSIDE_PACKAGE_INCLUDE_PATH") + + # Utils unit tests (no models needed) + catkin_add_gtest(yolo_test test/yolo_test.cpp) + if(TARGET yolo_test) + target_link_libraries( + yolo_test + ${PROJECT_NAME}_lib + ${catkin_LIBRARIES} + GTest::gtest + GTest::gtest_main + ) + #target_include_directories(yolo_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + endif() + +endif() From daa5337ecd500149a1d818517eccbc86fdfcb015 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Tue, 21 Oct 2025 19:58:43 +0200 Subject: [PATCH 32/38] updated .vscode files to build with new CMake --- .vscode/launch.json | 2 +- .vscode/tasks.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index eb2f055..35f7355 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Debug Yolo Model", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/devel/lib/yolo_onnx_ros/yolo_onnx_ros", // Path to the executable + "program": "${workspaceFolder}/build/devel/lib/yolo_onnx_ros/test_yolo_onnx_ros", // Path to the executable "args": [], // Add any command-line arguments for your program here "stopAtEntry": false, "cwd": "${workspaceFolder}/build", // Set the working directory diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5e878e7..5b58f2b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -50,6 +50,7 @@ "command": "cmake", "args": [ "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_POLICY_VERSION_MINIMUM=3.5", "-S", "${workspaceFolder}/", "-B", "${workspaceFolder}/build" ], @@ -90,4 +91,4 @@ } ] -} \ No newline at end of file +} From f87e8ee782415a8ac4cedeed2b4a7708d754db0f Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 21 Oct 2025 21:19:04 +0200 Subject: [PATCH 33/38] Working args --- include/yolo_onnx_ros/detection.hpp | 8 ++++++-- src/detection.cpp | 12 ++++++------ src/main.cpp | 12 ++++++++++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/yolo_onnx_ros/detection.hpp b/include/yolo_onnx_ros/detection.hpp index 3c62370..beed603 100644 --- a/include/yolo_onnx_ros/detection.hpp +++ b/include/yolo_onnx_ros/detection.hpp @@ -1,5 +1,9 @@ #include "yolo_onnx_ros/yolo_inference.hpp" -std::tuple, DL_INIT_PARAM> Initialize(); +#include + +std::tuple, DL_INIT_PARAM> Initialize(const std::filesystem::path& model_filename); + std::vector Detector(std::unique_ptr& p, const cv::Mat& img); -int ReadCocoYaml(std::unique_ptr& p); + +int ReadCocoYaml(const std::filesystem::path& filename, std::unique_ptr& p); diff --git a/src/detection.cpp b/src/detection.cpp index ed023f4..2814591 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -90,9 +90,10 @@ std::vector Detector(std::unique_ptr& p, const cv::Mat& img) -int ReadCocoYaml(std::unique_ptr& p) { +int ReadCocoYaml(const std::filesystem::path& filename, std::unique_ptr& p) +{ // Open the YAML file - std::ifstream file("data/coco.yaml"); + std::ifstream file(filename); if (!file.is_open()) { std::cerr << "Failed to open file" << std::endl; @@ -138,15 +139,14 @@ int ReadCocoYaml(std::unique_ptr& p) { return 0; } -std::tuple, DL_INIT_PARAM> Initialize() +std::tuple, DL_INIT_PARAM> Initialize(const std::filesystem::path& model_filename) { std::unique_ptr yoloDetector = std::make_unique(); - ReadCocoYaml(yoloDetector); + ReadCocoYaml(model_filename.parent_path() / "coco.yaml", yoloDetector); DL_INIT_PARAM params; params.rectConfidenceThreshold = 0.1; params.iouThreshold = 0.5; - // Mayve change the model from V11 to V8 - params.modelPath = "yolo11m.onnx"; + params.modelPath = model_filename; params.imgSize = { 640, 640 }; #if defined(YOLO_ONNX_ROS_CUDA_ENABLED) && YOLO_ONNX_ROS_CUDA_ENABLED params.cudaEnable = true; diff --git a/src/main.cpp b/src/main.cpp index a2278c6..c9ea6d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,12 +5,20 @@ #include #include -int main() +int main(int argc, char *argv[]) { std::unique_ptr yoloDetector; DL_INIT_PARAM params; - std::tie(yoloDetector, params) = Initialize(); + if (argc < 2) + { + std::cerr << "Not enough args provided" << std::endl; + return 1; + } + + const std::filesystem::path model_name = argv[1]; + + std::tie(yoloDetector, params) = Initialize(model_name); std::filesystem::path current_path = std::filesystem::current_path(); std::filesystem::path imgs_path = current_path / "images"; From 7957dbf24b138db8880adb014f5b4f4aecf90a2a Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Thu, 23 Oct 2025 13:33:55 +0200 Subject: [PATCH 34/38] Fix header extension --- test/yolo_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/yolo_test.cpp b/test/yolo_test.cpp index ccdddc7..e2a462f 100644 --- a/test/yolo_test.cpp +++ b/test/yolo_test.cpp @@ -1,5 +1,5 @@ #include "yolo_inference.h" -#include "detection.h" +#include "detection.hpp" #include #include #include From 70ca2ea236bb78e21642d77ff24391df31c9cac8 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 28 Oct 2025 11:15:08 +0100 Subject: [PATCH 35/38] fix(CMake): enable catkin_lint again --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d59157d..09520c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,8 +98,8 @@ install( # Testing # ------------------------------------------------------------------------------------------------ if (CATKIN_ENABLE_TESTING) - #find_package(catkin_lint_cmake REQUIRED) - #catkin_add_catkin_lint_test("-W2 --ignore HEADER_OUTSIDE_PACKAGE_INCLUDE_PATH") + find_package(catkin_lint_cmake REQUIRED) + catkin_add_catkin_lint_test("-W2 --ignore HEADER_OUTSIDE_PACKAGE_INCLUDE_PATH") # Utils unit tests (no models needed) catkin_add_gtest(yolo_test test/yolo_test.cpp) From 677becebb72fb7e686cc45b600b7ba86bcf141df Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 28 Oct 2025 11:19:22 +0100 Subject: [PATCH 36/38] Fix header extension --- test/yolo_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/yolo_test.cpp b/test/yolo_test.cpp index e2a462f..76e325e 100644 --- a/test/yolo_test.cpp +++ b/test/yolo_test.cpp @@ -1,4 +1,4 @@ -#include "yolo_inference.h" +#include "yolo_inference.hpp" #include "detection.hpp" #include #include From ad9cf19fd397da30c7516e7409e72d3cea1cbb35 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Tue, 28 Oct 2025 11:28:03 +0100 Subject: [PATCH 37/38] Fix header locations --- test/yolo_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/yolo_test.cpp b/test/yolo_test.cpp index 76e325e..5e2a4f5 100644 --- a/test/yolo_test.cpp +++ b/test/yolo_test.cpp @@ -1,5 +1,5 @@ -#include "yolo_inference.hpp" -#include "detection.hpp" +#include "yolo_onnx_ros/yolo_inference.hpp" +#include "yolo_onnx_ros/detection.hpp" #include #include #include From 90afade56b9af6164bb38df65e9df7eabfe00c83 Mon Sep 17 00:00:00 2001 From: IasonTheodorou Date: Tue, 28 Oct 2025 18:02:20 +0100 Subject: [PATCH 38/38] Added optional argument for images (you need to provide it only for the executable) --- .vscode/launch.json | 13 ++++++++----- include/yolo_onnx_ros/detection.hpp | 1 + src/detection.cpp | 1 - src/main.cpp | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 35f7355..b36e8ac 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,8 +5,11 @@ "name": "Debug Yolo Model", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/devel/lib/yolo_onnx_ros/test_yolo_onnx_ros", // Path to the executable - "args": [], // Add any command-line arguments for your program here + "program": "/home/amigo/ros/noetic/system/devel/lib/yolo_onnx_ros/test_yolo_onnx_ros", // Path to the executable + "args": [ + "/home/amigo/ros/noetic/repos/github.com/tue-robotics/yolo_onnx_ros/data/yolo11m.onnx", + "/home/amigo/Documents/repos/hero_sam.bak/pipeline/build/images" + ], // Add any command-line arguments for your program here "stopAtEntry": false, "cwd": "${workspaceFolder}/build", // Set the working directory "environment": [], @@ -19,13 +22,13 @@ "ignoreFailures": true } ], - "preLaunchTask": "build-yolo-project" // Ensure the project is built before debugging + //"preLaunchTask": "build-yolo-project" // Ensure the project is built before debugging }, { "name": "Debug Yolo Test", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/Yolov8OnnxRuntimeCPPInference_test", // Path to the executable + "program": "/home/amigo/ros/noetic/system/devel/lib/yolo_onnx_ros/yolo_test", // Path to the executable "args": [], // Add any command-line arguments for your program here "stopAtEntry": false, "cwd": "${workspaceFolder}/build", // Set the working directory @@ -39,7 +42,7 @@ "ignoreFailures": true } ], - "preLaunchTask": "build-yolo-project" // Ensure the project is built before debugging + //"preLaunchTask": "build-yolo-project" // Ensure the project is built before debugging } ] } diff --git a/include/yolo_onnx_ros/detection.hpp b/include/yolo_onnx_ros/detection.hpp index beed603..b0d4cbc 100644 --- a/include/yolo_onnx_ros/detection.hpp +++ b/include/yolo_onnx_ros/detection.hpp @@ -2,6 +2,7 @@ #include +// #define LOGGING std::tuple, DL_INIT_PARAM> Initialize(const std::filesystem::path& model_filename); std::vector Detector(std::unique_ptr& p, const cv::Mat& img); diff --git a/src/detection.cpp b/src/detection.cpp index 2814591..8200467 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -5,7 +5,6 @@ #include #include -// #define LOGGING std::vector Detector(std::unique_ptr& p, const cv::Mat& img) { std::vector res; diff --git a/src/main.cpp b/src/main.cpp index c9ea6d4..a637b05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,8 +20,7 @@ int main(int argc, char *argv[]) std::tie(yoloDetector, params) = Initialize(model_name); - std::filesystem::path current_path = std::filesystem::current_path(); - std::filesystem::path imgs_path = current_path / "images"; + std::filesystem::path imgs_path = argv[2]; for (auto& i : std::filesystem::directory_iterator(imgs_path)) { if (i.path().extension() == ".jpg" || i.path().extension() == ".png" || i.path().extension() == ".jpeg") @@ -30,12 +29,14 @@ int main(int argc, char *argv[]) cv::Mat img = cv::imread(img_path); std::vector results; results = Detector(yoloDetector, img); + #ifdef LOGGING for (const auto& result : results) { std::cout << "Image path: " << img_path << "\n" << "class id: " << result.classId << "\n" << "confidence: " << result.confidence << "\n"; } + #endif } }