lb 10 hodín pred
commit
85f1a671bc
28 zmenil súbory, kde vykonal 4227 pridanie a 0 odobranie
  1. 27 0
      CMakeLists.txt
  2. 342 0
      CMakeLists.txt.user
  3. 201 0
      LICENSE
  4. 68 0
      README.md
  5. 257 0
      main (copy).cpp
  6. 178 0
      main.cpp
  7. 253 0
      rtdetr_onnx.cpp
  8. 98 0
      rtdetr_onnx.h
  9. 108 0
      yolov8.cpp
  10. 32 0
      yolov8.h
  11. 111 0
      yolov8_obb.cpp
  12. 30 0
      yolov8_obb.h
  13. 264 0
      yolov8_obb_onnx.cpp
  14. 95 0
      yolov8_obb_onnx.h
  15. 261 0
      yolov8_onnx.cpp
  16. 91 0
      yolov8_onnx.h
  17. 38 0
      yolov8_onnx_test.pro
  18. 318 0
      yolov8_onnx_test.pro.user
  19. 121 0
      yolov8_pose.cpp
  20. 25 0
      yolov8_pose.h
  21. 275 0
      yolov8_pose_onnx.cpp
  22. 91 0
      yolov8_pose_onnx.h
  23. 135 0
      yolov8_seg.cpp
  24. 32 0
      yolov8_seg.h
  25. 316 0
      yolov8_seg_onnx.cpp
  26. 97 0
      yolov8_seg_onnx.h
  27. 278 0
      yolov8_utils.cpp
  28. 85 0
      yolov8_utils.h

+ 27 - 0
CMakeLists.txt

@@ -0,0 +1,27 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0)
+project(YOLOv8)
+
+
+SET (OpenCV_DIR path/to/opencv/build)  #opencv root
+SET (ONNXRUNTIME_DIR path/to/onnxruntime)
+
+FIND_PACKAGE(OpenCV REQUIRED)
+#include_directories("")
+ADD_EXECUTABLE(YOLOv8 yolov8.h yolov8_onnx.h yolov8_seg.h yolov8_seg_onnx.h yolov8_utils.h
+			 main.cpp yolov8.cpp yolov8_onnx.cpp yolov8_seg.cpp yolov8_seg_onnx.cpp yolov8_utils.cpp)
+
+SET(CMAKE_CXX_STANDARD 14)
+SET(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+TARGET_INCLUDE_DIRECTORIES(YOLOv8 PRIVATE "${ONNXRUNTIME_DIR}/include")
+
+TARGET_COMPILE_FEATURES(YOLOv8 PRIVATE cxx_std_14)
+TARGET_LINK_LIBRARIES(YOLOv8 ${OpenCV_LIBS})
+
+if (WIN32)
+    TARGET_LINK_LIBRARIES(YOLOv8 "${ONNXRUNTIME_DIR}/lib/onnxruntime.lib")
+endif(WIN32)
+
+if (UNIX)
+    TARGET_LINK_LIBRARIES(YOLOv8 "${ONNXRUNTIME_DIR}/lib/libonnxruntime.so")
+endif(UNIX)

+ 342 - 0
CMakeLists.txt.user

@@ -0,0 +1,342 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QtCreatorProject>
+<!-- Written by QtCreator 4.10.0, 2026-01-30T13:08:32. -->
+<qtcreator>
+ <data>
+  <variable>EnvironmentId</variable>
+  <value type="QByteArray">{3ce99616-2a23-4538-ac0d-5d33c5889fe4}</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
+   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
+   <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
+    <value type="QString" key="language">Cpp</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
+    </valuemap>
+   </valuemap>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
+    <value type="QString" key="language">QmlJS</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
+    </valuemap>
+   </valuemap>
+   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
+   <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
+   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
+   <value type="int" key="EditorConfiguration.IndentSize">4</value>
+   <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
+   <value type="int" key="EditorConfiguration.MarginColumn">80</value>
+   <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
+   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
+   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
+   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
+   <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
+   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
+   <value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
+   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
+   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
+   <value type="int" key="EditorConfiguration.TabSize">8</value>
+   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
+   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
+   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
+   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
+   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
+   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.PluginSettings</variable>
+  <valuemap type="QVariantMap">
+   <valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
+   <value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.12.5 GCC 64bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.12.5 GCC 64bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5125.gcc_64_kit</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
+    <valuelist type="QVariantList" key="CMake.Configuration">
+     <value type="QString">CMAKE_BUILD_TYPE:STRING=Debug</value>
+    </valuelist>
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/siemens/Projects/QtProjects/build-yolov8-opencv-onnx-Desktop_Qt_5_12_5_GCC_64bit-Debug</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">all</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">clean</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
+    <valuelist type="QVariantList" key="CMake.Configuration">
+     <value type="QString">CMAKE_BUILD_TYPE:STRING=Release</value>
+    </valuelist>
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/siemens/Projects/QtProjects/build-yolov8-opencv-onnx-Desktop_Qt_5_12_5_GCC_64bit-Release</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">all</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">clean</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
+    <valuelist type="QVariantList" key="CMake.Configuration">
+     <value type="QString">CMAKE_BUILD_TYPE:STRING=RelWithDebInfo</value>
+    </valuelist>
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/siemens/Projects/QtProjects/build-yolov8-opencv-onnx-Desktop_Qt_5_12_5_GCC_64bit-Release-with-Debug-Information</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">all</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">clean</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release with Debug Information</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
+    <valuelist type="QVariantList" key="CMake.Configuration">
+     <value type="QString">CMAKE_BUILD_TYPE:STRING=MinSizeRel</value>
+    </valuelist>
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/siemens/Projects/QtProjects/build-yolov8-opencv-onnx-Desktop_Qt_5_12_5_GCC_64bit-Minimum-Size-Release</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">all</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
+      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
+       <value type="QString">clean</value>
+      </valuelist>
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">CMake Build</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Minimum Size Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">4</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
+    <value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
+    <valuelist type="QVariantList" key="Analyzer.Perf.Events">
+     <value type="QString">cpu-cycles</value>
+    </valuelist>
+    <valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
+    <value type="int" key="Analyzer.Perf.Frequency">250</value>
+    <value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
+    <value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
+    <value type="int" key="Analyzer.Perf.StackSize">4096</value>
+    <value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
+    <value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
+    <value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
+    <value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
+    <value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
+    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">YOLOv8</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration./home/siemens/Projects/QtProjects/yolov8-opencv-onnx///::///YOLOv8</value>
+    <value type="QString" key="RunConfiguration.Arguments"></value>
+    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
+    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
+    <value type="QString" key="RunConfiguration.WorkingDirectory"></value>
+    <value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/siemens/Projects/QtProjects/build-yolov8-opencv-onnx-Desktop_Qt_5_12_5_GCC_64bit-Debug</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">1</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">22</value>
+ </data>
+ <data>
+  <variable>Version</variable>
+  <value type="int">22</value>
+ </data>
+</qtcreator>

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 68 - 0
README.md

@@ -0,0 +1,68 @@
+# yolov8-opencv-onnxruntime-cpp
+## 使用OpenCV-dnn和ONNXRuntime部署yolov8目标检测和实例分割模型<br>
+基于yolov8:https://github.com/ultralytics/ultralytics
+
+## requirements for opencv-dnn
+1. > OpenCV>=4.7.0<br>
+OpenCV>=4.7.0<br>
+OpenCV>=4.7.0<br>
+
+2. export for opencv-dnn:</br>
+```bash
+#Note: When exporting to opencv, it is best to set opset to 12
+
+yolo export model=path/to/model.pt format=onnx dynamic=False  opset=12
+```
+
+3. export RT-DETR:</br>
+```bash
+#Note: rtdetr need opset>=16,dynamic=False/True 
+
+yolo export model=path/to/rtdetr-l.pt format=onnx  opset=16
+
+```
+
+```python
+from ultralytics import YOLO
+model = YOLO('./pre_model/yolov8-rtdetr-l.pt')
+results = model.export(format='onnx',opset=16)
+```
+
+
+## requirements for onnxruntime (only yolo*_onnx.h/cpp)
+>opencv>=4.5.0 </br>
+ONNXRuntime>=1.9.0 </br>
+
+## 更新说明:
+#### 2024.04.15更新<br>
++ 新增yolov8-pose模型部署(https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp/issues/52)
++ 修复命名空间使用问题。
+
+#### 2024.01.22更新<br>
++ 新增yolov8-obb模型部署(https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp/issues/40)
++ 修改一些便利性使用的问题。
+#### 2023.12.05更新<br>
++ 新增yolov8-RTDETR部署。
++ 优化部分代码,例如输出shape之类从输出中获取,而非像之前需要设置正确参数。
+
+#### 2023.11.09更新<br>
++ 修复此pr中提到的一些问题[https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp/pull/30],此bug会导致mask与box大小可能会差几个像素从而导致出现一些问题(如果用的时候没有注意的话),本次更新之后会将其缩放到一致大小。
++ 新增视频流推理的demo,这是由于发现很多初学者调用视频的时候总是每一张图片都去读取一次模型,所以本次更新一起加上去。
+
+#### 2023.09.20更新<br>
++ 0.新增模型路径检查,部分issue查了半天,发现模型路径不对。
++ 1.计算mask部分bug修复,此前如果输入大小非640的话,需要同时设置头文件和结构体才能完成检测,但是大部分人只修改了一个地方,目前优化这部分内容,只需要修头文件中的定义即可。另外将segHeight和segWidth设置为从网络输出中读取,这样如果mask-ratio不是4倍的话,可以不需要修改这两个参数值。
++ 2.修复```GetMask2()```中可能导致越界的问题。<br>
+
+
+#### 2023.02.17更新<br>
++ 0.新增加onnxruntime旧版本API接口支持
++ 1.opencv不支持动态推理,请将dymanic设置为False导出onnx,同时opset需要设置为12。
++ 2.关于换行符,windows下面需要设置为CRLF,上传到github会自动切换成LF,windows下面切换一下即可<br>
+
+#### 2023.02.07 更新:</br>
++ yolov8使用opencv-dnn推理的话,目前只支持opencv4.7.0及其以上的版本,我暂时也没找到怎么修改适应opencv4.5.0的版本( ̄へ ̄),这个版本需求和onnxruntime无关,onnxruntime只需要4.5.0的版本,4.x的版本应该都可以用,只要能正确读取,有```cv::dnn::blobFromImages()```这个函数即可,如果真的没有这个函数,你自己将其源码抠出来用也是可以的,或者大佬们自己实现该函数功能。
++ 而目前opencv4.7.0的版本有问题(https://github.com/opencv/opencv/issues/23080) ,如果你的CPU不支持```AVX2```指令集,则需要在```net.forward()``` 前面加上```net.enableWinograd(false);```来关闭Winograd加速,如果支持这个指令集的话可以开启加速(蚊子腿)。
+
+依照惯例贴一张yolov8-seg.onnx在640x640下用onnxruntime运行结果图:
+![Alt text](images/bus_out.bmp)

+ 257 - 0
main (copy).cpp

@@ -0,0 +1,257 @@
+#include <iostream>
+#include<opencv2/opencv.hpp>
+
+#include<math.h>
+#include "yolov8.h"
+#include "yolov8_onnx.h"
+#include "yolov8_seg.h"
+#include "rtdetr_onnx.h"
+#include "yolov8_seg_onnx.h"
+#include "yolov8_obb.h"
+#include "yolov8_obb_onnx.h"
+#include "yolov8_pose.h"
+#include "yolov8_pose_onnx.h"
+#include<time.h>
+//#define  VIDEO_OPENCV //if define, use opencv for video.
+
+using namespace std;
+using namespace cv;
+using namespace dnn;
+
+template<typename _Tp>
+int yolov8(_Tp& task, cv::Mat& img, std::string& model_path)
+{
+
+
+	cv::dnn::Net net;
+	if (task.ReadModel(net, model_path, false)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+		return -1;
+	}
+	//生成随机颜色
+	std::vector<cv::Scalar> color;
+	srand(time(0));
+	for (int i = 0; i < 80; i++) {
+		int b = rand() % 256;
+		int g = rand() % 256;
+		int r = rand() % 256;
+		color.push_back(cv::Scalar(b, g, r));
+	}
+	std::vector<OutputParams> result;
+
+	bool isPose = false;
+	if (typeid(task) == typeid(Yolov8Pose)) {
+		isPose = true;
+	}
+	PoseParams poseParams;
+	if (task.Detect(img, net, result)) {
+
+		if (isPose)
+			DrawPredPose(img, result, poseParams);
+		else
+		DrawPred(img, result, task._className, color);
+		
+	}
+	else {
+		std::cout << "Detect Failed!" << std::endl;
+	}
+	system("pause");
+	return 0;
+}
+
+template<typename _Tp>
+int yolov8_onnx(_Tp& task, cv::Mat& img, std::string& model_path)
+{
+
+	if (task.ReadModel(model_path, false)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+		return -1;
+	}
+	//生成随机颜色
+	std::vector<cv::Scalar> color;
+	srand(time(0));
+	for (int i = 0; i < 80; i++) {
+		int b = rand() % 256;
+		int g = rand() % 256;
+		int r = rand() % 256;
+		color.push_back(cv::Scalar(b, g, r));
+	}
+	bool isPose = false;
+	if (typeid(task) == typeid(Yolov8PoseOnnx)) {
+		isPose = true;
+	}
+	PoseParams poseParams;
+
+	std::vector<OutputParams> result;
+	if (task.OnnxDetect(img, result)) {
+		if (isPose)
+			DrawPredPose(img, result, poseParams);
+		else
+			DrawPred(img, result, task._className, color);
+	}
+	else {
+		std::cout << "Detect Failed!" << std::endl;
+	}
+	system("pause");
+	return 0;
+}
+
+
+template<typename _Tp>
+int video_demo(_Tp& task, std::string& model_path)
+{
+	std::vector<cv::Scalar> color;
+	srand(time(0));
+	for (int i = 0; i < 80; i++) {
+		int b = rand() % 256;
+		int g = rand() % 256;
+		int r = rand() % 256;
+		color.push_back(cv::Scalar(b, g, r));
+	}
+	std::vector<OutputParams> result;
+	cv::VideoCapture cap(0);
+	if (!cap.isOpened())
+	{
+		std::cout << "open capture failured!" << std::endl;
+		return -1;
+	}
+	cv::Mat frame;
+	bool isPose = false;
+	PoseParams poseParams;
+#ifdef VIDEO_OPENCV
+	cv::dnn::Net net;
+	if (typeid(task) == typeid(Yolov8Pose)) {
+		isPose = true;
+	}
+	if (task.ReadModel(net, model_path, true)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+		std::cout << "read net failured!" << std::endl;
+		return -1;
+	}
+
+#else
+	if (typeid(task) == typeid(Yolov8PoseOnnx)) {
+		isPose = true;
+	}
+	if (task.ReadModel(model_path, true)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+		std::cout << "read net failured!" << std::endl;
+		return -1;
+	}
+
+#endif
+
+	while (true)
+	{
+
+		cap.read(frame);
+		if (frame.empty())
+		{
+			std::cout << "read to end" << std::endl;
+			break;
+		}
+		result.clear();
+#ifdef VIDEO_OPENCV
+
+		if (task.Detect(frame, net, result)) {
+
+			if (isPose)
+				DrawPredPose(frame, result, poseParams,true);
+			else
+				DrawPred(frame, result, task._className, color,true);
+	
+		}
+#else
+		if (task.OnnxDetect(frame, result)) {
+			if (isPose)
+				DrawPredPose(frame, result, poseParams, true);
+			else
+				DrawPred(frame, result, task._className, color, true);
+		}
+#endif
+		int k = waitKey(10);
+		if (k == 27) { //esc 
+			break;
+		}
+
+	}
+	cap.release();
+
+	system("pause");
+
+	return 0;
+}
+
+
+int main() {
+
+	std::string img_path = "./images/bus.jpg";
+
+	std::string model_path_detect = "./models/yolov8s-pose1.onnx";
+	std::string model_path_rtdetr = "./models/rtdetr-l.onnx";  //yolov8-redetr
+	std::string model_path_obb = "./models/yolov8s-obb.onnx";
+	std::string model_path_seg = "./models/yolov8s-seg.onnx";
+	std::string model_path_pose = "./models/yolov8s-pose.onnx";
+
+	cv::Mat src = imread(img_path);
+	cv::Mat img = src.clone();
+
+	Yolov8				task_detect_ocv;
+	Yolov8PoseOnnx			task_detect_ort;
+
+	Yolov8Seg			task_segment_ocv;
+	Yolov8SegOnnx		task_segment_ort;
+
+	Yolov8Obb			task_obb_ocv;
+	Yolov8ObbOnnx		task_obb_ort;
+
+	Yolov8Pose			task_pose_ocv;
+	Yolov8PoseOnnx		task_pose_ort;
+
+	RTDETROnnx			task_rtdetr_ort;
+
+	//yolov8(task_detect_ocv,img,model_path_detect);    //yolov8 opencv detect
+	//img = src.clone();
+	//yolov8_onnx(task_detect_ort,img,model_path_detect);  //yoolov8 onnxruntime detect
+	// 
+	//img = src.clone();
+	//yolov8_onnx(task_rtdetr_ort, img, model_path_rtdetr);  //yolov8-rtdetr onnxruntime detect
+
+	//img = src.clone();
+	//yolov8(task_segment_ocv,img,model_path_seg);   //yolov8 opencv segment
+	//img = src.clone();
+	//yolov8_onnx(task_segment_ort,img,model_path_seg); //yolov8 onnxruntime segment
+
+
+	//img = src.clone();
+	//yolov8(task_obb_ocv, img, model_path_obb); //yolov8 opencv obb
+	//img = src.clone();
+	//yolov8_onnx(task_obb_ort, img, model_path_obb); //yolov8 onnxruntime obb
+
+	//img = src.clone();
+	//yolov8(task_pose_ocv, img, model_path_pose); //yolov8 opencv pose
+	img = src.clone();
+	yolov8_onnx(task_pose_ort, img, model_path_pose); //yolov8 onnxruntime pose
+
+#ifdef VIDEO_OPENCV
+	video_demo(task_detect_ocv, model_path_detect);
+	//video_demo(task_segment_ocv, model_path_seg);
+	//video_demo(task_pose_ocv, model_path_pose);
+#else
+	//video_demo(task_detect_ort, model_path_detect);
+	//video_demo(task_rtdetr_ort, model_path_rtdetr);
+	//video_demo(task_segment_ort, model_path_seg);
+	//video_demo(task_pose_ort, model_path_pose);
+#endif
+	return 0;
+}
+
+

+ 178 - 0
main.cpp

@@ -0,0 +1,178 @@
+#include <iostream>
+#include<opencv2/opencv.hpp>
+
+#include<math.h>
+#include "yolov8_onnx.h"
+#include "yolov8_pose_onnx.h"
+#include<time.h>
+//#define  VIDEO_OPENCV //if define, use opencv for video.
+
+using namespace std;
+using namespace cv;
+using namespace dnn;
+
+
+template<typename _Tp>
+int yolov8_onnx(_Tp& task, cv::Mat& img, std::string& model_path)
+{
+
+    if (task.ReadModel(model_path, true)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+        std::cerr << "fail to read net!" << std::endl;
+		return -1;
+	}
+	//生成随机颜色
+	std::vector<cv::Scalar> color;
+	srand(time(0));
+	for (int i = 0; i < 80; i++) {
+		int b = rand() % 256;
+		int g = rand() % 256;
+		int r = rand() % 256;
+		color.push_back(cv::Scalar(b, g, r));
+	}
+	bool isPose = false;
+	if (typeid(task) == typeid(Yolov8PoseOnnx)) {
+		isPose = true;
+	}
+	PoseParams poseParams;
+
+	std::vector<OutputParams> result;
+	if (task.OnnxDetect(img, result)) {
+		if (isPose)
+			DrawPredPose(img, result, poseParams);
+		else
+			DrawPred(img, result, task._className, color);
+	}
+	else {
+		std::cout << "Detect Failed!" << std::endl;
+	}
+
+    cv::imshow("1", img);
+    cv::waitKey(0);
+    system("pause");
+	return 0;
+}
+
+
+template<typename _Tp>
+int video_demo(_Tp& task, std::string& model_path)
+{
+	std::vector<cv::Scalar> color;
+	srand(time(0));
+	for (int i = 0; i < 80; i++) {
+		int b = rand() % 256;
+		int g = rand() % 256;
+		int r = rand() % 256;
+		color.push_back(cv::Scalar(b, g, r));
+	}
+	std::vector<OutputParams> result;
+	cv::VideoCapture cap(0);
+	if (!cap.isOpened())
+	{
+		std::cout << "open capture failured!" << std::endl;
+		return -1;
+	}
+	cv::Mat frame;
+	bool isPose = false;
+	PoseParams poseParams;
+#ifdef VIDEO_OPENCV
+	cv::dnn::Net net;
+	if (typeid(task) == typeid(Yolov8Pose)) {
+		isPose = true;
+	}
+	if (task.ReadModel(net, model_path, true)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+		std::cout << "read net failured!" << std::endl;
+		return -1;
+	}
+
+#else
+	if (typeid(task) == typeid(Yolov8PoseOnnx)) {
+		isPose = true;
+	}
+	if (task.ReadModel(model_path, true)) {
+		std::cout << "read net ok!" << std::endl;
+	}
+	else {
+		std::cout << "read net failured!" << std::endl;
+		return -1;
+	}
+
+#endif
+
+	while (true)
+	{
+
+		cap.read(frame);
+		if (frame.empty())
+		{
+			std::cout << "read to end" << std::endl;
+			break;
+		}
+		result.clear();
+#ifdef VIDEO_OPENCV
+
+		if (task.Detect(frame, net, result)) {
+
+			if (isPose)
+				DrawPredPose(frame, result, poseParams,true);
+			else
+				DrawPred(frame, result, task._className, color,true);
+	
+		}
+#else
+		if (task.OnnxDetect(frame, result)) {
+			if (isPose)
+                DrawPredPose(frame, result, poseParams);
+			else
+                DrawPred(frame, result, task._className, color);
+		}
+#endif
+            cv::imshow("1", frame);
+		int k = waitKey(10);
+		if (k == 27) { //esc 
+			break;
+		}
+
+	}
+	cap.release();
+
+	system("pause");
+
+	return 0;
+}
+
+#define Pos_Flag
+
+int main() {
+
+#ifdef Pos_Flag
+     std::string img_path = "/home/sxyx2026/cdq_data/imgs/2/2_2026-01-22_21-48-33-291.jpg";
+    std::string model_path = "/home/sxyx2026/cdq_arrow.onnx";
+
+    cv::Mat src = imread(img_path);
+    cv::Mat img = src.clone();
+
+    Yolov8PoseOnnx		task_pose_ort;
+    yolov8_onnx(task_pose_ort, img, model_path); //yolov8 onnxruntime pose
+
+#else
+
+    std::string img_path = "/home/sxyx2026/cdq_data/imgs/0/0_2026-01-22_14-35-48-249.jpg";
+
+    std::string model_path = "/home/sxyx2026/cdq_grab.onnx";
+
+    cv::Mat src = imread(img_path);
+    cv::Mat img = src.clone();
+
+    Yolov8Onnx			task_detect_ort;
+    yolov8_onnx(task_detect_ort,img,model_path);  //yoolov8 onnxruntime detect
+#endif
+	return 0;
+}
+
+

+ 253 - 0
rtdetr_onnx.cpp

@@ -0,0 +1,253 @@
+#include "rtdetr_onnx.h"
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+using namespace Ort;
+
+
+
+
+bool RTDETROnnx::ReadModel(const std::string& modelPath, bool isCuda, int cudaID, bool warmUp) {
+	if (_batchSize < 1) _batchSize = 1;
+	try
+	{
+		if (!CheckModelPath(modelPath))
+			return false;
+		std::vector<std::string> available_providers = GetAvailableProviders();
+		auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");
+
+
+		if (isCuda && (cuda_available == available_providers.end()))
+		{
+			std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		else if (isCuda && (cuda_available != available_providers.end()))
+		{
+			std::cout << "************* Infer model on GPU! *************" << std::endl;
+#if ORT_API_VERSION < ORT_OLD_VISON
+			OrtCUDAProviderOptions cudaOption;
+			cudaOption.device_id = cudaID;
+			_OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
+#else
+			OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);
+#endif
+		}
+		else
+		{
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		//
+
+		_OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
+
+#ifdef _WIN32
+		std::wstring model_path(modelPath.begin(), modelPath.end());
+		_OrtSession = new Ort::Session(_OrtEnv, model_path.c_str(), _OrtSessionOptions);
+#else
+		_OrtSession = new Ort::Session(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
+#endif
+
+		Ort::AllocatorWithDefaultOptions allocator;
+		//init input
+		_inputNodesNum = _OrtSession->GetInputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_inputName = _OrtSession->GetInputName(0, allocator);
+		_inputNodeNames.push_back(_inputName);
+#else
+		_inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));
+		_inputNodeNames.push_back(_inputName.get());
+#endif
+		//std::cout << _inputNodeNames[0] << std::endl;
+		Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);
+		auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
+		_inputNodeDataType = input_tensor_info.GetElementType();
+		_inputTensorShape = input_tensor_info.GetShape();
+
+		if (_inputTensorShape[0] == -1)
+		{
+			_isDynamicShape = true;
+			_inputTensorShape[0] = _batchSize;
+
+		}
+		if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1) {
+			_isDynamicShape = true;
+			_inputTensorShape[2] = _netHeight;
+			_inputTensorShape[3] = _netWidth;
+		}
+		//init output
+		_outputNodesNum = _OrtSession->GetOutputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_output_name0 = _OrtSession->GetOutputName(0, allocator);
+		_outputNodeNames.push_back(_output_name0);
+#else
+		_output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));
+		_outputNodeNames.push_back(_output_name0.get());
+#endif
+		Ort::TypeInfo type_info_output0(nullptr);
+		type_info_output0 = _OrtSession->GetOutputTypeInfo(0);  //output0
+
+		auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
+		_outputNodeDataType = tensor_info_output0.GetElementType();
+		_outputTensorShape = tensor_info_output0.GetShape();
+
+		//_outputMaskNodeDataType = tensor_info_output1.GetElementType(); //the same as output0
+		//_outputMaskTensorShape = tensor_info_output1.GetShape();
+		//if (_outputTensorShape[0] == -1)
+		//{
+		//	_outputTensorShape[0] = _batchSize;
+		//	_outputMaskTensorShape[0] = _batchSize;
+		//}
+		//if (_outputMaskTensorShape[2] == -1) {
+		//	//size_t ouput_rows = 0;
+		//	//for (int i = 0; i < _strideSize; ++i) {
+		//	//	ouput_rows += 3 * (_netWidth / _netStride[i]) * _netHeight / _netStride[i];
+		//	//}
+		//	//_outputTensorShape[1] = ouput_rows;
+
+		//	_outputMaskTensorShape[2] = _segHeight;
+		//	_outputMaskTensorShape[3] = _segWidth;
+		//}
+
+		//warm up
+		if (isCuda && warmUp) {
+			//draw run
+			std::cout << "Start warming up" << std::endl;
+			size_t input_tensor_length = VectorProduct(_inputTensorShape);
+			float* temp = new float[input_tensor_length];
+			std::vector<Ort::Value> input_tensors;
+			std::vector<Ort::Value> output_tensors;
+			input_tensors.push_back(Ort::Value::CreateTensor<float>(
+				_OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),
+				_inputTensorShape.size()));
+			for (int i = 0; i < 3; ++i) {
+				output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+					_inputNodeNames.data(),
+					input_tensors.data(),
+					_inputNodeNames.size(),
+					_outputNodeNames.data(),
+					_outputNodeNames.size());
+			}
+
+			delete[]temp;
+		}
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+	return true;
+
+}
+
+int RTDETROnnx::PreProcessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params) {
+	outSrcImgs.clear();
+	cv::Size input_size = cv::Size(_netWidth, _netHeight);
+	for (int i = 0; i < srcImgs.size(); ++i) {
+		cv::Mat temp_img = srcImgs[i];
+		cv::Vec4d temp_param = { 1,1,0,0 };
+		if (temp_img.size() != input_size) {
+			cv::Mat borderImg;
+			LetterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
+			//std::cout << borderImg.size() << std::endl;
+			outSrcImgs.push_back(borderImg);
+			params.push_back(temp_param);
+		}
+		else {
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+
+	int lack_num = _batchSize - srcImgs.size();
+	if (lack_num > 0) {
+		for (int i = 0; i < lack_num; ++i) {
+			cv::Mat temp_img = cv::Mat::zeros(input_size, CV_8UC3);
+			cv::Vec4d temp_param = { 1,1,0,0 };
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+	return 0;
+
+}
+bool RTDETROnnx::OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output) {
+	std::vector<cv::Mat> input_data = { srcImg };
+	std::vector<std::vector<OutputParams>> tenp_output;
+	if (OnnxBatchDetect(input_data, tenp_output)) {
+		output = tenp_output[0];
+		return true;
+	}
+	else return false;
+}
+bool RTDETROnnx::OnnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<OutputParams>>& output) {
+	std::vector<cv::Vec4d> params;
+	std::vector<cv::Mat> input_images;
+	cv::Size input_size(_netWidth, _netHeight);
+	//preprocessing
+	PreProcessing(srcImgs, input_images, params);
+	cv::Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, cv::Scalar(0, 0, 0), true, false);
+
+	int64_t input_tensor_length = VectorProduct(_inputTensorShape);
+	std::vector<Ort::Value> input_tensors;
+	std::vector<Ort::Value> output_tensors;
+	input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float*)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));
+
+	output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+		_inputNodeNames.data(),
+		input_tensors.data(),
+		_inputNodeNames.size(),
+		_outputNodeNames.data(),
+		_outputNodeNames.size()
+	);
+	//post-process
+	float* all_data = output_tensors[0].GetTensorMutableData<float>();
+	_outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();
+	int net_width = _outputTensorShape[2];
+	int socre_array_length = net_width - 4;
+	int input_tensor_width = _inputTensorShape[2];
+	int input_tensor_height = _inputTensorShape[3];
+	int64_t one_output_length = VectorProduct(_outputTensorShape) / _outputTensorShape[0];
+	for (int img_index = 0; img_index < srcImgs.size(); ++img_index) {
+		cv::Mat output0 = cv::Mat(cv::Size((int)_outputTensorShape[2], (int)_outputTensorShape[1]), CV_32F, all_data);
+		all_data += one_output_length;
+		float* pdata = (float*)output0.data;
+		int rows = output0.rows;
+		cv::Rect holeImgRect(0, 0, srcImgs[img_index].cols, srcImgs[img_index].rows);
+		std::vector<OutputParams> temp_output;
+		for (int r = 0; r < rows; ++r) {    //stride
+			cv::Mat scores(1, socre_array_length, CV_32F, pdata + 4);
+			cv::Point classIdPoint;
+			double max_class_socre;
+			minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+			max_class_socre = (float)max_class_socre;
+			if (max_class_socre >= _classThreshold) {
+
+				//rect [x,y,w,h]
+				float x = (pdata[0] * input_tensor_width - params[img_index][2]) / params[img_index][0];  //x
+				float y = (pdata[1] * input_tensor_height - params[img_index][3]) / params[img_index][1];  //y
+				float w = pdata[2] / params[img_index][0] * input_tensor_width;  //w
+				float h = pdata[3] / params[img_index][1] * input_tensor_height;  //h
+				int left = MAX(int(x - 0.5 * w + 0.5), 0);
+				int top = MAX(int(y - 0.5 * h + 0.5), 0);
+
+				cv::Rect box = cv::Rect(left, top, int(w + 0.5), int(h + 0.5));
+
+				OutputParams result;
+				result.id = classIdPoint.x;
+				result.confidence = max_class_socre;
+				result.box = box & holeImgRect;
+				if (result.box.area() < 1)
+					continue;
+				temp_output.push_back(result);
+			}
+			pdata += net_width;//ÏÂÒ»ÐÐ
+		}
+		output.push_back(temp_output);
+	}
+
+	if (output.size())
+		return true;
+	else
+		return false;
+
+}

+ 98 - 0
rtdetr_onnx.h

@@ -0,0 +1,98 @@
+#pragma once
+#include <iostream>
+#include<memory>
+#include <opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+#include<onnxruntime_cxx_api.h>
+
+//#include <tensorrt_provider_factory.h>  //if use OrtTensorRTProviderOptionsV2
+//#include <onnxruntime_c_api.h>
+
+
+class RTDETROnnx {
+public:
+	RTDETROnnx() : _OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
+	~RTDETROnnx() {
+		if (_OrtSession != nullptr)
+			delete _OrtSession;
+	};// delete _OrtMemoryInfo;
+
+
+public:
+	/** \brief Read onnx-model
+	* \param[in] modelPath:onnx-model path
+	* \param[in] isCuda:if true,use Ort-GPU,else run it on cpu.
+	* \param[in] cudaID:if isCuda==true,run Ort-GPU on cudaID.
+	* \param[in] warmUp:if isCuda==true,warm up GPU-model.
+	*/
+	bool ReadModel(const std::string& modelPath, bool isCuda = false, int cudaID = 0, bool warmUp = true);
+
+	/** \brief  detect.
+	* \param[in] srcImg:a 3-channels image.
+	* \param[out] output:detection results of input image.
+	*/
+	bool OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output);
+	/** \brief  detect,batch size= _batchSize
+	* \param[in] srcImg:A batch of images.
+	* \param[out] output:detection results of input images.
+	*/
+	bool OnnxBatchDetect(std::vector<cv::Mat>& srcImg, std::vector<std::vector<OutputParams>>& output);
+
+private:
+
+	template <typename T>
+	T VectorProduct(const std::vector<T>& v)
+	{
+		return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
+	};
+	int PreProcessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params);
+	
+	const int _netWidth = 640;   //ONNX-net-input-width
+	const int _netHeight = 640;  //ONNX-net-input-height
+
+	int _batchSize = 1;  //if multi-batch,set this
+	bool _isDynamicShape = false;//onnx support dynamic shape
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+	float _maskThreshold = 0.5;
+
+
+	//ONNXRUNTIME	
+	Ort::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov8");
+	Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();
+	Ort::Session* _OrtSession = nullptr;
+	Ort::MemoryInfo _OrtMemoryInfo;
+#if ORT_API_VERSION < ORT_OLD_VISON
+	char* _inputName, * _output_name0;
+#else
+	std::shared_ptr<char> _inputName, _output_name0;
+#endif
+
+	std::vector<char*> _inputNodeNames; //输入节点名
+	std::vector<char*> _outputNodeNames;//输出节点名
+
+	size_t _inputNodesNum = 0;        //输入节点数
+	size_t _outputNodesNum = 0;       //输出节点数
+
+	ONNXTensorElementDataType _inputNodeDataType; //数据类型
+	ONNXTensorElementDataType _outputNodeDataType;
+	std::vector<int64_t> _inputTensorShape; //输入张量shape
+
+	std::vector<int64_t> _outputTensorShape;
+
+public:
+	std::vector<std::string> _className = {
+		"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
+		"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
+		"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
+		"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
+		"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
+		"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
+		"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
+		"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
+		"hair drier", "toothbrush"
+	};
+
+
+
+};

+ 108 - 0
yolov8.cpp

@@ -0,0 +1,108 @@
+#include"yolov8.h"
+
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+
+bool Yolov8::ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda = false) {
+	try {
+		if (!CheckModelPath(netPath))
+			return false;
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR<7
+		std::cout << "Yolov8 Need OpenCV Version >=4.7.0" << std::endl;
+		return false;
+#endif
+		net = cv::dnn::readNetFromONNX(netPath);
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR==7&&CV_VERSION_REVISION==0
+		net.enableWinograd(false);  //bug of opencv4.7.x in AVX only platform ,https://github.com/opencv/opencv/pull/23112 and https://github.com/opencv/opencv/issues/23080 
+		//net.enableWinograd(true);		//If your CPU supports AVX2, you can set it true to speed up
+#endif
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+
+	if (isCuda) {
+		//cuda
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); //or DNN_TARGET_CUDA_FP16
+	}
+	else {
+		//cpu
+		std::cout << "Inference device: CPU" << std::endl;
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
+	}
+	return true;
+}
+
+
+bool Yolov8::Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output) {
+	cv::Mat blob;
+	output.clear();
+	int col = srcImg.cols;
+	int row = srcImg.rows;
+	cv::Mat netInputImg;
+	cv::Vec4d params;
+	LetterBox(srcImg, netInputImg, params, cv::Size(_netWidth, _netHeight));
+	cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(0, 0, 0), true, false);
+	//**************************************************************************************************************************************************/
+	//如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
+	// If there is no problem with other settings, but results are a lot different from  Python-onnx , you can try to use the following two sentences
+	// 
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);
+	//****************************************************************************************************************************************************/
+	net.setInput(blob);
+	std::vector<cv::Mat> net_output_img;
+
+	net.forward(net_output_img, net.getUnconnectedOutLayersNames()); //get outputs
+	std::vector<int> class_ids;// res-class_id
+	std::vector<float> confidences;// res-conf 
+	std::vector<cv::Rect> boxes;// res-box
+	cv::Mat output0=cv::Mat( cv::Size(net_output_img[0].size[2], net_output_img[0].size[1]), CV_32F, (float*)net_output_img[0].data).t();  //[bs,116,8400]=>[bs,8400,116]
+	int net_width = output0.cols;
+	int rows = output0.rows;
+	int socre_array_length = net_width - 4;
+	float* pdata = (float*)output0.data;
+	for (int r = 0; r < rows; ++r) {
+			cv::Mat scores(1, socre_array_length, CV_32FC1, pdata + 4);
+			cv::Point classIdPoint;
+			double max_class_socre;
+			minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+			max_class_socre = (float)max_class_socre;
+			if (max_class_socre >= _classThreshold) {
+				//rect [x,y,w,h]
+				float x = (pdata[0] - params[2]) / params[0];  
+				float y = (pdata[1] - params[3]) / params[1];  
+				float w = pdata[2] / params[0];  
+				float h = pdata[3] / params[1];  
+				int left = MAX(int(x - 0.5 * w + 0.5), 0);
+				int top = MAX(int(y - 0.5 * h + 0.5), 0);
+				class_ids.push_back(classIdPoint.x);
+				confidences.push_back(max_class_socre);
+				boxes.push_back(cv::Rect(left, top, int(w + 0.5), int(h + 0.5)));
+			}
+			pdata += net_width;//next line
+	}
+	//NMS
+	std::vector<int> nms_result;
+	cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+	std::vector<std::vector<float>> temp_mask_proposals;
+	cv::Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);
+	for (int i = 0; i < nms_result.size(); ++i) {
+		int idx = nms_result[i];
+		OutputParams result;
+		result.id = class_ids[idx];
+		result.confidence = confidences[idx];
+		result.box = boxes[idx] & holeImgRect;
+		if (result.box.area() < 1)
+			continue;
+		output.push_back(result);
+	}
+	if (output.size())
+		return true;
+	else
+		return false;
+}
+

+ 32 - 0
yolov8.h

@@ -0,0 +1,32 @@
+#pragma once
+#include<iostream>
+#include<opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+
+class Yolov8 {
+public:
+	Yolov8() {
+	}
+	~Yolov8() {}
+
+	bool ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
+	bool Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output);
+
+	int _netWidth = 640;   //ONNX图片输入宽度
+	int _netHeight = 640;  //ONNX图片输入高度
+
+
+	//类别名,自己的模型需要修改此项
+	std::vector<std::string> _className = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
+		"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
+		"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
+		"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
+		"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
+		"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
+		"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
+		"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
+		"hair drier", "toothbrush" };
+private:
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+};

+ 111 - 0
yolov8_obb.cpp

@@ -0,0 +1,111 @@
+#include"yolov8_obb.h"
+
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+
+bool Yolov8Obb::ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda = false) {
+	try {
+		if (!CheckModelPath(netPath))
+			return false;
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR<7
+		std::cout << "OBB Need OpenCV Version >=4.7.0" << std::endl; 
+		return false;
+#endif
+		net = cv::dnn::readNetFromONNX(netPath);
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR==7&&CV_VERSION_REVISION==0
+		net.enableWinograd(false);  //bug of opencv4.7.x in AVX only platform ,https://github.com/opencv/opencv/pull/23112 and https://github.com/opencv/opencv/issues/23080 
+		//net.enableWinograd(true);		//If your CPU supports AVX2, you can set it true to speed up
+#endif
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+
+	if (isCuda) {
+		//cuda
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); //or DNN_TARGET_CUDA_FP16
+	}
+	else {
+		//cpu
+		std::cout << "Inference device: CPU" << std::endl;
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
+	}
+	return true;
+}
+
+
+bool Yolov8Obb::Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output) {
+	cv::Mat blob;
+	output.clear();
+	int col = srcImg.cols;
+	int row = srcImg.rows;
+	cv::Mat netInputImg;
+	cv::Vec4d params;
+	LetterBox(srcImg, netInputImg, params, cv::Size(_netWidth, _netHeight));
+	cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(0, 0, 0), true, false);
+	//**************************************************************************************************************************************************/
+	//如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
+	// If there is no problem with other settings, but results are a lot different from  Python-onnx , you can try to use the following two sentences
+	// 
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);
+	//****************************************************************************************************************************************************/
+	net.setInput(blob);
+	std::vector<cv::Mat> net_output_img;
+
+	net.forward(net_output_img, net.getUnconnectedOutLayersNames()); //get outputs
+	std::vector<int> class_ids;// res-class_id
+	std::vector<float> confidences;// res-conf 
+	std::vector<cv::RotatedRect> boxes;// res-box
+	cv::Mat output0 = cv::Mat(cv::Size(net_output_img[0].size[2], net_output_img[0].size[1]), CV_32F, (float*)net_output_img[0].data).t();  //[bs,20,21504]=>[bs,21504,20]
+	int net_width = output0.cols;
+	int rows = output0.rows;
+	int class_score_length = net_width - 5;
+	int angle_index = net_width - 1;
+	float* pdata = (float*)output0.data;
+	for (int r = 0; r < rows; ++r) {
+		cv::Mat scores(1, class_score_length, CV_32FC1, pdata + 4);
+		cv::Point classIdPoint;
+		double max_class_socre;
+		minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+		max_class_socre = (float)max_class_socre;
+		if (max_class_socre >= _classThreshold) {
+			//rect [x,y,w,h]
+			float x = (pdata[0] - params[2]) / params[0];
+			float y = (pdata[1] - params[3]) / params[1];
+			float w = pdata[2] / params[0];
+			float h = pdata[3] / params[1];
+			float angle = pdata[angle_index]  / CV_PI *180.0;
+			class_ids.push_back(classIdPoint.x);
+			confidences.push_back(max_class_socre);
+			//cv::RotatedRect temp_rotated;
+			//BBox2Obb(x, y, w, h, angle, temp_rotated);
+			//boxes.push_back(temp_rotated);
+			boxes.push_back(cv::RotatedRect(cv::Point2f(x, y), cv::Size(w, h), angle));
+		}
+		pdata += net_width;//next line
+	}
+	//NMS
+	std::vector<int> nms_result;
+	cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+	std::vector<std::vector<float>> temp_mask_proposals;
+	//cv::Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);
+	for (int i = 0; i < nms_result.size(); ++i) {
+		int idx = nms_result[i];
+		OutputParams result;
+		result.id = class_ids[idx];
+		result.confidence = confidences[idx];
+		result.rotatedBox = boxes[idx];
+		if (result.rotatedBox.size.width<1|| result.rotatedBox.size.height<1)
+			continue;
+		output.push_back(result);
+	}
+	if (output.size())
+		return true;
+	else
+		return false;
+}
+

+ 30 - 0
yolov8_obb.h

@@ -0,0 +1,30 @@
+#pragma once
+#include<iostream>
+#include<opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+
+class Yolov8Obb {
+public:
+	Yolov8Obb() {
+	}
+	~Yolov8Obb() {}
+
+	bool ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
+	bool Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output);
+
+	int _netWidth = 1024;   //ONNX图片输入宽度
+	int _netHeight = 1024;  //ONNX图片输入高度
+
+
+	//类别名,自己的模型需要修改此项
+	std::vector<std::string> _className = 
+	{  "plane",  "ship", "storage tank", 
+		"baseball diamond",  "tennis court",   "basketball court", 
+		"ground track field", "harbor",  "bridge",  
+		"large vehicle",  "small vehicle",  "helicopter",
+		"roundabout",  "soccer ball field",  "swimming pool"
+	};
+private:
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+};

+ 264 - 0
yolov8_obb_onnx.cpp

@@ -0,0 +1,264 @@
+#include "yolov8_obb_onnx.h"
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+using namespace Ort;
+
+
+
+
+bool Yolov8ObbOnnx::ReadModel(const std::string& modelPath, bool isCuda, int cudaID, bool warmUp) {
+	if (_batchSize < 1) _batchSize = 1;
+	try
+	{
+		if (!CheckModelPath(modelPath))
+			return false;
+		std::vector<std::string> available_providers = GetAvailableProviders();
+		auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");
+		
+
+		if (isCuda && (cuda_available == available_providers.end()))
+		{
+			std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		else if (isCuda && (cuda_available != available_providers.end()))
+		{
+			std::cout << "************* Infer model on GPU! *************" << std::endl;
+#if ORT_API_VERSION < ORT_OLD_VISON
+			OrtCUDAProviderOptions cudaOption;
+			cudaOption.device_id = cudaID;
+			_OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
+#else
+			OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);
+#endif
+		}
+		else
+		{
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		//
+
+		_OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
+
+#ifdef _WIN32
+		std::wstring model_path(modelPath.begin(), modelPath.end());
+		_OrtSession = new Ort::Session(_OrtEnv, model_path.c_str(), _OrtSessionOptions);
+#else
+		_OrtSession = new Ort::Session(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
+#endif
+
+		Ort::AllocatorWithDefaultOptions allocator;
+		//init input
+		_inputNodesNum = _OrtSession->GetInputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_inputName = _OrtSession->GetInputName(0, allocator);
+		_inputNodeNames.push_back(_inputName);
+#else
+		_inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));
+		_inputNodeNames.push_back(_inputName.get());
+#endif
+		//std::cout << _inputNodeNames[0] << std::endl;
+		Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);
+		auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
+		_inputNodeDataType = input_tensor_info.GetElementType();
+		_inputTensorShape = input_tensor_info.GetShape();
+
+		if (_inputTensorShape[0] == -1)
+		{
+			_isDynamicShape = true;
+			_inputTensorShape[0] = _batchSize;
+
+		}
+		if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1) {
+			_isDynamicShape = true;
+			_inputTensorShape[2] = _netHeight;
+			_inputTensorShape[3] = _netWidth;
+		}
+		//init output
+		_outputNodesNum = _OrtSession->GetOutputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_output_name0 = _OrtSession->GetOutputName(0, allocator);
+		_outputNodeNames.push_back(_output_name0);
+#else
+		_output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));
+		_outputNodeNames.push_back(_output_name0.get());
+#endif
+		Ort::TypeInfo type_info_output0(nullptr);
+		type_info_output0 = _OrtSession->GetOutputTypeInfo(0);  //output0
+
+		auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
+		_outputNodeDataType = tensor_info_output0.GetElementType();
+		_outputTensorShape = tensor_info_output0.GetShape();
+
+		//_outputMaskNodeDataType = tensor_info_output1.GetElementType(); //the same as output0
+		//_outputMaskTensorShape = tensor_info_output1.GetShape();
+		//if (_outputTensorShape[0] == -1)
+		//{
+		//	_outputTensorShape[0] = _batchSize;
+		//	_outputMaskTensorShape[0] = _batchSize;
+		//}
+		//if (_outputMaskTensorShape[2] == -1) {
+		//	//size_t ouput_rows = 0;
+		//	//for (int i = 0; i < _strideSize; ++i) {
+		//	//	ouput_rows += 3 * (_netWidth / _netStride[i]) * _netHeight / _netStride[i];
+		//	//}
+		//	//_outputTensorShape[1] = ouput_rows;
+
+		//	_outputMaskTensorShape[2] = _segHeight;
+		//	_outputMaskTensorShape[3] = _segWidth;
+		//}
+
+		//warm up
+		if (isCuda && warmUp) {
+			//draw run
+			std::cout << "Start warming up" << std::endl;
+			size_t input_tensor_length = VectorProduct(_inputTensorShape);
+			float* temp = new float[input_tensor_length];
+			std::vector<Ort::Value> input_tensors;
+			std::vector<Ort::Value> output_tensors;
+			input_tensors.push_back(Ort::Value::CreateTensor<float>(
+				_OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),
+				_inputTensorShape.size()));
+			for (int i = 0; i < 3; ++i) {
+				output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+					_inputNodeNames.data(),
+					input_tensors.data(),
+					_inputNodeNames.size(),
+					_outputNodeNames.data(),
+					_outputNodeNames.size());
+			}
+
+			delete[]temp;
+		}
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+	return true;
+
+}
+
+int Yolov8ObbOnnx::Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params) {
+	outSrcImgs.clear();
+	cv::Size input_size = cv::Size(_netWidth, _netHeight);
+	for (int i = 0; i < srcImgs.size(); ++i) {
+		cv::Mat temp_img = srcImgs[i];
+		cv::Vec4d temp_param = {1,1,0,0};
+		if (temp_img.size() != input_size) {
+			cv::Mat borderImg;
+			LetterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
+			//std::cout << borderImg.size() << std::endl;
+			outSrcImgs.push_back(borderImg);
+			params.push_back(temp_param);
+		}
+		else {
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+
+	int lack_num =  _batchSize- srcImgs.size();
+	if (lack_num > 0) {
+		for (int i = 0; i < lack_num; ++i) {
+			cv::Mat temp_img = cv::Mat::zeros(input_size, CV_8UC3);
+			cv::Vec4d temp_param = { 1,1,0,0 };
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+	return 0;
+
+}
+bool Yolov8ObbOnnx::OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output) {
+	std::vector<cv::Mat> input_data = { srcImg };
+	std::vector<std::vector<OutputParams>> tenp_output;
+	if (OnnxBatchDetect(input_data, tenp_output)) {
+		output = tenp_output[0];
+		return true;
+	}
+	else return false;
+}
+bool Yolov8ObbOnnx::OnnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<OutputParams>>& output) {
+	std::vector<cv::Vec4d> params;
+	std::vector<cv::Mat> input_images;
+	cv::Size input_size(_netWidth, _netHeight);
+	//preprocessing
+	Preprocessing(srcImgs, input_images, params);
+	cv::Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, cv::Scalar(0, 0, 0), true, false);
+
+	int64_t input_tensor_length = VectorProduct(_inputTensorShape);
+	std::vector<Ort::Value> input_tensors;
+	std::vector<Ort::Value> output_tensors;
+	input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float*)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));
+
+	output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+		_inputNodeNames.data(),
+		input_tensors.data(),
+		_inputNodeNames.size(),
+		_outputNodeNames.data(),
+		_outputNodeNames.size()
+	);
+	//post-process
+	float* all_data = output_tensors[0].GetTensorMutableData<float>();
+	_outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();
+	int net_width = _outputTensorShape[1];
+	int socre_array_length = net_width - 5;
+	int angle_index = net_width - 1;
+	int64_t one_output_length = VectorProduct(_outputTensorShape) / _outputTensorShape[0];
+	for (int img_index = 0; img_index < srcImgs.size(); ++img_index) {
+		cv::Mat output0 = cv::Mat(cv::Size((int)_outputTensorShape[2], (int)_outputTensorShape[1]), CV_32F, all_data).t();  //[bs,116,8400]=>[bs,8400,116]
+		all_data += one_output_length;
+		float* pdata = (float*)output0.data;
+		int rows = output0.rows;
+		std::vector<int> class_ids;//结果id数组
+		std::vector<float> confidences;//结果每个id对应置信度数组
+		std::vector<cv::RotatedRect> boxes;//每个id矩形框
+		for (int r = 0; r < rows; ++r) {    //stride
+			cv::Mat scores(1, socre_array_length, CV_32F, pdata + 4);
+			cv::Point classIdPoint;
+			double max_class_socre;
+			minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+			max_class_socre = (float)max_class_socre;
+			if (max_class_socre >= _classThreshold) {
+
+				//rect [x,y,w,h]
+				float x = (pdata[0] - params[img_index][2]) / params[img_index][0];  //x
+				float y = (pdata[1] - params[img_index][3]) / params[img_index][1];  //y
+				float w = pdata[2] / params[img_index][0];  //w
+				float h = pdata[3] / params[img_index][1];  //h
+				float angle = pdata[angle_index] / CV_PI * 180.0;
+				class_ids.push_back(classIdPoint.x);
+				confidences.push_back(max_class_socre);
+				//cv::RotatedRect temp_rotated;
+				//BBox2Obb(x, y, w, h, angle, temp_rotated);
+				//boxes.push_back(temp_rotated);
+				boxes.push_back(cv::RotatedRect(cv::Point2f(x, y), cv::Size(w, h), angle));
+
+			}
+			pdata += net_width;//下一行
+		}
+
+		std::vector<int> nms_result;
+		cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+		std::vector<std::vector<float>> temp_mask_proposals;
+		std::vector<OutputParams> temp_output;
+		for (int i = 0; i < nms_result.size(); ++i) {
+			int idx = nms_result[i];
+			OutputParams result;
+			result.id = class_ids[idx];
+			result.confidence = confidences[idx];
+			result.rotatedBox = boxes[idx];
+			if (result.rotatedBox.size.width < 1 || result.rotatedBox.size.height < 1)
+				continue;
+			temp_output.push_back(result);
+		}
+		output.push_back(temp_output);
+	}
+
+	if (output.size())
+		return true;
+	else
+		return false;
+
+}

+ 95 - 0
yolov8_obb_onnx.h

@@ -0,0 +1,95 @@
+#pragma once
+#include <iostream>
+#include<memory>
+#include <opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+#include<onnxruntime_cxx_api.h>
+
+//#include <tensorrt_provider_factory.h>  //if use OrtTensorRTProviderOptionsV2
+//#include <onnxruntime_c_api.h>
+
+
+class Yolov8ObbOnnx {
+public:
+	Yolov8ObbOnnx() :_OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
+	~Yolov8ObbOnnx() {
+		if (_OrtSession != nullptr)
+			delete _OrtSession;
+	
+	};// delete _OrtMemoryInfo;
+
+
+public:
+	/** \brief Read onnx-model
+	* \param[in] modelPath:onnx-model path
+	* \param[in] isCuda:if true,use Ort-GPU,else run it on cpu.
+	* \param[in] cudaID:if isCuda==true,run Ort-GPU on cudaID.
+	* \param[in] warmUp:if isCuda==true,warm up GPU-model.
+	*/
+	bool ReadModel(const std::string& modelPath, bool isCuda = false, int cudaID = 0, bool warmUp = true);
+
+	/** \brief  detect.
+	* \param[in] srcImg:a 3-channels image.
+	* \param[out] output:detection results of input image.
+	*/
+	bool OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output);
+	/** \brief  detect,batch size= _batchSize
+	* \param[in] srcImg:A batch of images.
+	* \param[out] output:detection results of input images.
+	*/
+	bool OnnxBatchDetect(std::vector<cv::Mat>& srcImg, std::vector<std::vector<OutputParams>>& output);
+
+private:
+
+	template <typename T>
+	T VectorProduct(const std::vector<T>& v)
+	{
+		return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
+	};
+	int Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params);
+
+	const int _netWidth = 1024;   //ONNX-net-input-width
+	const int _netHeight = 1024;  //ONNX-net-input-height
+
+	int _batchSize = 1;  //if multi-batch,set this
+	bool _isDynamicShape = false;//onnx support dynamic shape
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+	float _maskThreshold = 0.5;
+
+
+	//ONNXRUNTIME	
+	Ort::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov8");
+	Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();
+	Ort::Session* _OrtSession = nullptr;
+	Ort::MemoryInfo _OrtMemoryInfo;
+#if ORT_API_VERSION < ORT_OLD_VISON
+	char* _inputName, * _output_name0;
+#else
+	std::shared_ptr<char> _inputName, _output_name0;
+#endif
+
+	std::vector<char*> _inputNodeNames; //输入节点名
+	std::vector<char*> _outputNodeNames;//输出节点名
+
+	size_t _inputNodesNum = 0;        //输入节点数
+	size_t _outputNodesNum = 0;       //输出节点数
+
+	ONNXTensorElementDataType _inputNodeDataType; //数据类型
+	ONNXTensorElementDataType _outputNodeDataType;
+	std::vector<int64_t> _inputTensorShape; //输入张量shape
+
+	std::vector<int64_t> _outputTensorShape;
+
+public:
+	std::vector<std::string> _className = 
+	{  "plane",  "ship", "storage tank",
+		"baseball diamond",  "tennis court",   "basketball court",
+		"ground track field", "harbor",  "bridge",
+		"large vehicle",  "small vehicle",  "helicopter",
+		"roundabout",  "soccer ball field",  "swimming pool"
+	};
+
+
+
+};

+ 261 - 0
yolov8_onnx.cpp

@@ -0,0 +1,261 @@
+#include "yolov8_onnx.h"
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+using namespace Ort;
+
+
+
+
+bool Yolov8Onnx::ReadModel(const std::string& modelPath, bool isCuda, int cudaID, bool warmUp) {
+	if (_batchSize < 1) _batchSize = 1;
+	try
+	{
+		if (!CheckModelPath(modelPath))
+			return false;
+		std::vector<std::string> available_providers = GetAvailableProviders();
+		auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");
+		
+
+		if (isCuda && (cuda_available == available_providers.end()))
+		{
+			std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		else if (isCuda && (cuda_available != available_providers.end()))
+		{
+			std::cout << "************* Infer model on GPU! *************" << std::endl;
+#if ORT_API_VERSION < ORT_OLD_VISON
+			OrtCUDAProviderOptions cudaOption;
+			cudaOption.device_id = cudaID;
+			_OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
+#else
+			OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);
+#endif
+		}
+		else
+		{
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		//
+
+		_OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
+
+#ifdef _WIN32
+		std::wstring model_path(modelPath.begin(), modelPath.end());
+		_OrtSession = new Ort::Session(_OrtEnv, model_path.c_str(), _OrtSessionOptions);
+#else
+		_OrtSession = new Ort::Session(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
+#endif
+
+		Ort::AllocatorWithDefaultOptions allocator;
+		//init input
+		_inputNodesNum = _OrtSession->GetInputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_inputName = _OrtSession->GetInputName(0, allocator);
+		_inputNodeNames.push_back(_inputName);
+#else
+		_inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));
+		_inputNodeNames.push_back(_inputName.get());
+#endif
+		//std::cout << _inputNodeNames[0] << std::endl;
+		Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);
+		auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
+		_inputNodeDataType = input_tensor_info.GetElementType();
+		_inputTensorShape = input_tensor_info.GetShape();
+
+		if (_inputTensorShape[0] == -1)
+		{
+			_isDynamicShape = true;
+			_inputTensorShape[0] = _batchSize;
+
+		}
+		if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1) {
+			_isDynamicShape = true;
+			_inputTensorShape[2] = _netHeight;
+			_inputTensorShape[3] = _netWidth;
+		}
+		//init output
+		_outputNodesNum = _OrtSession->GetOutputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_output_name0 = _OrtSession->GetOutputName(0, allocator);
+		_outputNodeNames.push_back(_output_name0);
+#else
+		_output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));
+		_outputNodeNames.push_back(_output_name0.get());
+#endif
+		Ort::TypeInfo type_info_output0(nullptr);
+		type_info_output0 = _OrtSession->GetOutputTypeInfo(0);  //output0
+
+		auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
+		_outputNodeDataType = tensor_info_output0.GetElementType();
+		_outputTensorShape = tensor_info_output0.GetShape();
+
+		//_outputMaskNodeDataType = tensor_info_output1.GetElementType(); //the same as output0
+		//_outputMaskTensorShape = tensor_info_output1.GetShape();
+		//if (_outputTensorShape[0] == -1)
+		//{
+		//	_outputTensorShape[0] = _batchSize;
+		//	_outputMaskTensorShape[0] = _batchSize;
+		//}
+		//if (_outputMaskTensorShape[2] == -1) {
+		//	//size_t ouput_rows = 0;
+		//	//for (int i = 0; i < _strideSize; ++i) {
+		//	//	ouput_rows += 3 * (_netWidth / _netStride[i]) * _netHeight / _netStride[i];
+		//	//}
+		//	//_outputTensorShape[1] = ouput_rows;
+
+		//	_outputMaskTensorShape[2] = _segHeight;
+		//	_outputMaskTensorShape[3] = _segWidth;
+		//}
+
+		//warm up
+		if (isCuda && warmUp) {
+			//draw run
+			std::cout << "Start warming up" << std::endl;
+			size_t input_tensor_length = VectorProduct(_inputTensorShape);
+			float* temp = new float[input_tensor_length];
+			std::vector<Ort::Value> input_tensors;
+			std::vector<Ort::Value> output_tensors;
+			input_tensors.push_back(Ort::Value::CreateTensor<float>(
+				_OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),
+				_inputTensorShape.size()));
+			for (int i = 0; i < 3; ++i) {
+				output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+					_inputNodeNames.data(),
+					input_tensors.data(),
+					_inputNodeNames.size(),
+					_outputNodeNames.data(),
+					_outputNodeNames.size());
+			}
+
+			delete[]temp;
+		}
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+	return true;
+
+}
+
+int Yolov8Onnx::Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params) {
+	outSrcImgs.clear();
+	cv::Size input_size = cv::Size(_netWidth, _netHeight);
+	for (int i = 0; i < srcImgs.size(); ++i) {
+		cv::Mat temp_img = srcImgs[i];
+		cv::Vec4d temp_param = {1,1,0,0};
+		if (temp_img.size() != input_size) {
+			cv::Mat borderImg;
+			LetterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
+			//std::cout << borderImg.size() << std::endl;
+			outSrcImgs.push_back(borderImg);
+			params.push_back(temp_param);
+		}
+		else {
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+
+	int lack_num =  _batchSize- srcImgs.size();
+	if (lack_num > 0) {
+		for (int i = 0; i < lack_num; ++i) {
+			cv::Mat temp_img = cv::Mat::zeros(input_size, CV_8UC3);
+			cv::Vec4d temp_param = { 1,1,0,0 };
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+	return 0;
+
+}
+bool Yolov8Onnx::OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output) {
+	std::vector<cv::Mat> input_data = { srcImg };
+	std::vector<std::vector<OutputParams>> tenp_output;
+	if (OnnxBatchDetect(input_data, tenp_output)) {
+		output = tenp_output[0];
+		return true;
+	}
+	else return false;
+}
+bool Yolov8Onnx::OnnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<OutputParams>>& output) {
+	std::vector<cv::Vec4d> params;
+	std::vector<cv::Mat> input_images;
+	cv::Size input_size(_netWidth, _netHeight);
+	//preprocessing
+	Preprocessing(srcImgs, input_images, params);
+	cv::Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, cv::Scalar(0, 0, 0), true, false);
+
+	int64_t input_tensor_length = VectorProduct(_inputTensorShape);
+	std::vector<Ort::Value> input_tensors;
+	std::vector<Ort::Value> output_tensors;
+	input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float*)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));
+
+	output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+		_inputNodeNames.data(),
+		input_tensors.data(),
+		_inputNodeNames.size(),
+		_outputNodeNames.data(),
+		_outputNodeNames.size()
+	);
+	//post-process
+	float* all_data = output_tensors[0].GetTensorMutableData<float>();
+	_outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();
+	int net_width = _outputTensorShape[1];
+	int socre_array_length = net_width - 4;
+	int64_t one_output_length = VectorProduct(_outputTensorShape) / _outputTensorShape[0];
+	for (int img_index = 0; img_index < srcImgs.size(); ++img_index) {
+		cv::Mat output0 = cv::Mat(cv::Size((int)_outputTensorShape[2], (int)_outputTensorShape[1]), CV_32F, all_data).t();  //[bs,116,8400]=>[bs,8400,116]
+		all_data += one_output_length;
+		float* pdata = (float*)output0.data;
+		int rows = output0.rows;
+		std::vector<int> class_ids;//结果id数组
+		std::vector<float> confidences;//结果每个id对应置信度数组
+		std::vector<cv::Rect> boxes;//每个id矩形框
+		for (int r = 0; r < rows; ++r) {    //stride
+			cv::Mat scores(1, socre_array_length, CV_32F, pdata + 4);
+			cv::Point classIdPoint;
+			double max_class_socre;
+			minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+			max_class_socre = (float)max_class_socre;
+			if (max_class_socre >= _classThreshold) {
+
+				//rect [x,y,w,h]
+				float x = (pdata[0] - params[img_index][2]) / params[img_index][0];  //x
+				float y = (pdata[1] - params[img_index][3]) / params[img_index][1];  //y
+				float w = pdata[2] / params[img_index][0];  //w
+				float h = pdata[3] / params[img_index][1];  //h
+				int left = MAX(int(x - 0.5 * w + 0.5), 0);
+				int top = MAX(int(y - 0.5 * h + 0.5), 0);
+				class_ids.push_back(classIdPoint.x);
+				confidences.push_back(max_class_socre);
+				boxes.push_back(cv::Rect(left, top, int(w + 0.5), int(h + 0.5)));
+			}
+			pdata += net_width;//下一行
+		}
+
+		std::vector<int> nms_result;
+		cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+		std::vector<std::vector<float>> temp_mask_proposals;
+		cv::Rect holeImgRect(0, 0, srcImgs[img_index].cols, srcImgs[img_index].rows);
+		std::vector<OutputParams> temp_output;
+		for (int i = 0; i < nms_result.size(); ++i) {
+			int idx = nms_result[i];
+			OutputParams result;
+			result.id = class_ids[idx];
+			result.confidence = confidences[idx];
+			result.box = boxes[idx] & holeImgRect;
+			if (result.box.area() < 1)
+				continue;
+			temp_output.push_back(result);
+		}
+		output.push_back(temp_output);
+	}
+
+	if (output.size())
+		return true;
+	else
+		return false;
+
+}

+ 91 - 0
yolov8_onnx.h

@@ -0,0 +1,91 @@
+#pragma once
+#include <iostream>
+#include<memory>
+#include <opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+#include<onnxruntime_cxx_api.h>
+
+//#include <tensorrt_provider_factory.h>  //if use OrtTensorRTProviderOptionsV2
+//#include <onnxruntime_c_api.h>
+
+
+class Yolov8Onnx {
+public:
+	Yolov8Onnx() :_OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
+	~Yolov8Onnx() {
+		if (_OrtSession != nullptr)
+			delete _OrtSession;
+	
+	};// delete _OrtMemoryInfo;
+
+
+public:
+	/** \brief Read onnx-model
+	* \param[in] modelPath:onnx-model path
+	* \param[in] isCuda:if true,use Ort-GPU,else run it on cpu.
+	* \param[in] cudaID:if isCuda==true,run Ort-GPU on cudaID.
+	* \param[in] warmUp:if isCuda==true,warm up GPU-model.
+	*/
+	bool ReadModel(const std::string& modelPath, bool isCuda = false, int cudaID = 0, bool warmUp = true);
+
+	/** \brief  detect.
+	* \param[in] srcImg:a 3-channels image.
+	* \param[out] output:detection results of input image.
+	*/
+	bool OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output);
+	/** \brief  detect,batch size= _batchSize
+	* \param[in] srcImg:A batch of images.
+	* \param[out] output:detection results of input images.
+	*/
+	bool OnnxBatchDetect(std::vector<cv::Mat>& srcImg, std::vector<std::vector<OutputParams>>& output);
+
+private:
+
+	template <typename T>
+	T VectorProduct(const std::vector<T>& v)
+	{
+		return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
+	};
+	int Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params);
+
+	const int _netWidth = 640;   //ONNX-net-input-width
+	const int _netHeight = 640;  //ONNX-net-input-height
+
+	int _batchSize = 1;  //if multi-batch,set this
+	bool _isDynamicShape = false;//onnx support dynamic shape
+    float _classThreshold = 0.55;
+	float _nmsThreshold = 0.45;
+	float _maskThreshold = 0.5;
+
+
+	//ONNXRUNTIME	
+	Ort::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov8");
+	Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();
+	Ort::Session* _OrtSession = nullptr;
+	Ort::MemoryInfo _OrtMemoryInfo;
+#if ORT_API_VERSION < ORT_OLD_VISON
+	char* _inputName, * _output_name0;
+#else
+	std::shared_ptr<char> _inputName, _output_name0;
+#endif
+
+	std::vector<char*> _inputNodeNames; //输入节点名
+	std::vector<char*> _outputNodeNames;//输出节点名
+
+	size_t _inputNodesNum = 0;        //输入节点数
+	size_t _outputNodesNum = 0;       //输出节点数
+
+	ONNXTensorElementDataType _inputNodeDataType; //数据类型
+	ONNXTensorElementDataType _outputNodeDataType;
+	std::vector<int64_t> _inputTensorShape; //输入张量shape
+
+	std::vector<int64_t> _outputTensorShape;
+
+public:
+	std::vector<std::string> _className = {
+        "earAxis", "auxHook", "mainHook"
+	};
+
+
+
+};

+ 38 - 0
yolov8_onnx_test.pro

@@ -0,0 +1,38 @@
+QT -= gui
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+        main.cpp \
+        yolov8_onnx.cpp \
+        yolov8_pose_onnx.cpp \
+        yolov8_utils.cpp
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+INCLUDEPATH += /usr/local/include/opencv4
+LIBS += -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_video -lopencv_imgproc -lopencv_ml -lopencv_videoio -lopencv_imgcodecs -lopencv_dnn
+
+INCLUDEPATH += /home/sxyx2026/onnxruntime-linux-x64-gpu-1.14.1/include/
+LIBS += -L/home/sxyx2026/onnxruntime-linux-x64-gpu-1.14.1/lib -lonnxruntime
+
+HEADERS += \
+    yolov8_onnx.h \
+    yolov8_pose_onnx.h \
+    yolov8_utils.h
+

+ 318 - 0
yolov8_onnx_test.pro.user

@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QtCreatorProject>
+<!-- Written by QtCreator 4.11.1, 2026-02-07T15:10:26. -->
+<qtcreator>
+ <data>
+  <variable>EnvironmentId</variable>
+  <value type="QByteArray">{0a1afb34-cdaa-4eaa-94c9-1947243976cd}</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
+   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
+   <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
+    <value type="QString" key="language">Cpp</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
+    </valuemap>
+   </valuemap>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
+    <value type="QString" key="language">QmlJS</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
+    </valuemap>
+   </valuemap>
+   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
+   <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
+   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
+   <value type="int" key="EditorConfiguration.IndentSize">4</value>
+   <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
+   <value type="int" key="EditorConfiguration.MarginColumn">80</value>
+   <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
+   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
+   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
+   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
+   <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
+   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
+   <value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
+   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
+   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
+   <value type="int" key="EditorConfiguration.TabSize">8</value>
+   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
+   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
+   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
+   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
+   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
+   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.PluginSettings</variable>
+  <valuemap type="QVariantMap">
+   <valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
+   <value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.14.2 GCC 64bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.14.2 GCC 64bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5142.gcc_64_kit</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/sxyx2026/QtProjects/build-yolov8-onnx-Desktop_Qt_5_14_2_GCC_64bit-Debug</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/sxyx2026/Projects/build-yolov8_onnx_test-Desktop_Qt_5_14_2_GCC_64bit-Release</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/sxyx2026/Projects/build-yolov8_onnx_test-Desktop_Qt_5_14_2_GCC_64bit-Profile</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
+    <value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
+    <valuelist type="QVariantList" key="Analyzer.Perf.Events">
+     <value type="QString">cpu-cycles</value>
+    </valuelist>
+    <valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
+    <value type="int" key="Analyzer.Perf.Frequency">250</value>
+    <valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
+     <value type="QString">-e</value>
+     <value type="QString">cpu-cycles</value>
+     <value type="QString">--call-graph</value>
+     <value type="QString">dwarf,4096</value>
+     <value type="QString">-F</value>
+     <value type="QString">250</value>
+    </valuelist>
+    <value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
+    <value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
+    <value type="int" key="Analyzer.Perf.StackSize">4096</value>
+    <value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
+    <value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
+    <value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
+    <value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
+    <value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
+    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/sxyx2026/QtProjects/yolov8-opencv-onnx/yolov8_onnx_test.pro</value>
+    <value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/sxyx2026/QtProjects/yolov8-opencv-onnx/yolov8_onnx_test.pro</value>
+    <value type="QString" key="RunConfiguration.Arguments"></value>
+    <value type="bool" key="RunConfiguration.Arguments.multi">false</value>
+    <value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
+    <value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
+    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
+    <value type="bool" key="RunConfiguration.UseTerminal">false</value>
+    <value type="QString" key="RunConfiguration.WorkingDirectory"></value>
+    <value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/sxyx2026/QtProjects/build-yolov8-onnx-Desktop_Qt_5_14_2_GCC_64bit-Debug</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">1</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">22</value>
+ </data>
+ <data>
+  <variable>Version</variable>
+  <value type="int">22</value>
+ </data>
+</qtcreator>

+ 121 - 0
yolov8_pose.cpp

@@ -0,0 +1,121 @@
+#include"yolov8_pose.h"
+
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+
+bool Yolov8Pose::ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda = false) {
+	try {
+		if (!CheckModelPath(netPath))
+			return false;
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR<7
+		std::cout << "OBB Need OpenCV Version >=4.7.0" << std::endl; 
+		return false;
+#endif
+		net = cv::dnn::readNetFromONNX(netPath);
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR==7&&CV_VERSION_REVISION==0
+		net.enableWinograd(false);  //bug of opencv4.7.x in AVX only platform ,https://github.com/opencv/opencv/pull/23112 and https://github.com/opencv/opencv/issues/23080 
+		//net.enableWinograd(true);		//If your CPU supports AVX2, you can set it true to speed up
+#endif
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+
+	if (isCuda) {
+		//cuda
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); //or DNN_TARGET_CUDA_FP16
+	}
+	else {
+		//cpu
+		std::cout << "Inference device: CPU" << std::endl;
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
+	}
+	return true;
+}
+
+
+bool Yolov8Pose::Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output) {
+	cv::Mat blob;
+	output.clear();
+	int col = srcImg.cols;
+	int row = srcImg.rows;
+	cv::Mat netInputImg;
+	cv::Vec4d params;
+	LetterBox(srcImg, netInputImg, params, cv::Size(_netWidth, _netHeight));
+	cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(0, 0, 0), true, false);
+	//**************************************************************************************************************************************************/
+	//如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
+	// If there is no problem with other settings, but results are a lot different from  Python-onnx , you can try to use the following two sentences
+	// 
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);
+	//****************************************************************************************************************************************************/
+	net.setInput(blob);
+	std::vector<cv::Mat> net_output_img;
+	net.forward(net_output_img, net.getUnconnectedOutLayersNames()); //get outputs
+	std::vector<int> class_ids;// res-class_id
+	std::vector<float> confidences;// res-conf 
+	std::vector<cv::Rect> boxes;// res-box
+	std::vector<std::vector<PoseKeyPoint>> pose_key_points; //保存kpt
+	cv::Mat output0 = cv::Mat(cv::Size(net_output_img[0].size[2], net_output_img[0].size[1]), CV_32F, (float*)net_output_img[0].data).t();  //[bs,20,21504]=>[bs,21504,20]
+	int net_width = output0.cols;
+	int rows = output0.rows;
+	int key_point_length = net_width - 5;
+	int key_point_num = 17; //_bodyKeyPoints.size(), shape[x, y, confidence]
+	if (key_point_num * 3 != key_point_length) {
+		std::cout << "Pose should be shape [x, y, confidence] with 17-points" << std::endl;
+		return false;
+	}
+
+	float* pdata = (float*)output0.data;
+	for (int r = 0; r < rows; ++r) {
+		float max_class_socre=pdata[4];
+		if (max_class_socre >= _classThreshold) {
+			//rect [x,y,w,h]
+			float x = (pdata[0] - params[2]) / params[0];
+			float y = (pdata[1] - params[3]) / params[1];
+			float w = pdata[2] / params[0];
+			float h = pdata[3] / params[1];
+			class_ids.push_back(0);
+			confidences.push_back(max_class_socre);
+			int left = MAX(int(x - 0.5 * w + 0.5), 0);
+			int top = MAX(int(y - 0.5 * h + 0.5), 0);
+			boxes.push_back(cv::Rect(left, top, int(w + 0.5), int(h + 0.5)));
+			std::vector<PoseKeyPoint> temp_kpts;
+			for (int kpt = 0; kpt < key_point_length; kpt += 3) {
+				PoseKeyPoint temp_kp;
+				temp_kp.x = (pdata[5 + kpt] - params[2]) / params[0];
+				temp_kp.y = (pdata[6 + kpt] - params[3]) / params[1];
+				temp_kp.confidence = pdata[7 + kpt];
+				temp_kpts.push_back(temp_kp);
+			}
+			pose_key_points.push_back(temp_kpts);
+
+		}
+		pdata += net_width;//next line
+	}
+	//NMS
+	std::vector<int> nms_result;
+	cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+	std::vector<std::vector<float>> temp_mask_proposals;
+	cv::Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);
+	for (int i = 0; i < nms_result.size(); ++i) {
+		int idx = nms_result[i];
+		OutputParams result;
+		result.id = class_ids[idx];
+		result.confidence = confidences[idx];
+		result.box = boxes[idx]& holeImgRect;
+		result.keyPoints = pose_key_points[idx];
+		if (result.box.area() < 1)
+			continue;
+		output.push_back(result);
+	}
+	if (output.size())
+		return true;
+	else
+		return false;
+}
+

+ 25 - 0
yolov8_pose.h

@@ -0,0 +1,25 @@
+#pragma once
+#include<iostream>
+#include<opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+
+class Yolov8Pose {
+public:
+	Yolov8Pose() {}
+	~Yolov8Pose() {}
+
+	bool ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
+	bool Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output);
+
+	int _netWidth = 640;   //ONNX图片输入宽度
+	int _netHeight = 640;  //ONNX图片输入高度
+
+
+	//类别名,自己的模型需要修改此项
+	std::vector<std::string> _className ={ "person" };
+
+private:
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+	//float _keyPointThreshold = 0.5;
+};

+ 275 - 0
yolov8_pose_onnx.cpp

@@ -0,0 +1,275 @@
+#include "yolov8_pose_onnx.h"
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+using namespace Ort;
+
+
+
+
+bool Yolov8PoseOnnx::ReadModel(const std::string& modelPath, bool isCuda, int cudaID, bool warmUp) {
+	if (_batchSize < 1) _batchSize = 1;
+	try
+	{
+		if (!CheckModelPath(modelPath))
+			return false;
+		std::vector<std::string> available_providers = GetAvailableProviders();
+		auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");
+		
+
+		if (isCuda && (cuda_available == available_providers.end()))
+		{
+			std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		else if (isCuda && (cuda_available != available_providers.end()))
+		{
+			std::cout << "************* Infer model on GPU! *************" << std::endl;
+#if ORT_API_VERSION < ORT_OLD_VISON
+			OrtCUDAProviderOptions cudaOption;
+			cudaOption.device_id = cudaID;
+			_OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
+#else
+			OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);
+#endif
+		}
+		else
+		{
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		//
+
+		_OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
+
+#ifdef _WIN32
+		std::wstring model_path(modelPath.begin(), modelPath.end());
+		_OrtSession = new Ort::Session(_OrtEnv, model_path.c_str(), _OrtSessionOptions);
+#else
+		_OrtSession = new Ort::Session(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
+#endif
+
+		Ort::AllocatorWithDefaultOptions allocator;
+		//init input
+		_inputNodesNum = _OrtSession->GetInputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_inputName = _OrtSession->GetInputName(0, allocator);
+		_inputNodeNames.push_back(_inputName);
+#else
+		_inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));
+		_inputNodeNames.push_back(_inputName.get());
+#endif
+		//std::cout << _inputNodeNames[0] << std::endl;
+		Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);
+		auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
+		_inputNodeDataType = input_tensor_info.GetElementType();
+		_inputTensorShape = input_tensor_info.GetShape();
+
+		if (_inputTensorShape[0] == -1)
+		{
+			_isDynamicShape = true;
+			_inputTensorShape[0] = _batchSize;
+
+		}
+		if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1) {
+			_isDynamicShape = true;
+			_inputTensorShape[2] = _netHeight;
+			_inputTensorShape[3] = _netWidth;
+		}
+		//init output
+		_outputNodesNum = _OrtSession->GetOutputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_output_name0 = _OrtSession->GetOutputName(0, allocator);
+		_outputNodeNames.push_back(_output_name0);
+#else
+		_output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));
+		_outputNodeNames.push_back(_output_name0.get());
+#endif
+		Ort::TypeInfo type_info_output0(nullptr);
+		type_info_output0 = _OrtSession->GetOutputTypeInfo(0);  //output0
+
+		auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
+		_outputNodeDataType = tensor_info_output0.GetElementType();
+		_outputTensorShape = tensor_info_output0.GetShape();
+
+		//_outputMaskNodeDataType = tensor_info_output1.GetElementType(); //the same as output0
+		//_outputMaskTensorShape = tensor_info_output1.GetShape();
+		//if (_outputTensorShape[0] == -1)
+		//{
+		//	_outputTensorShape[0] = _batchSize;
+		//	_outputMaskTensorShape[0] = _batchSize;
+		//}
+		//if (_outputMaskTensorShape[2] == -1) {
+		//	//size_t ouput_rows = 0;
+		//	//for (int i = 0; i < _strideSize; ++i) {
+		//	//	ouput_rows += 3 * (_netWidth / _netStride[i]) * _netHeight / _netStride[i];
+		//	//}
+		//	//_outputTensorShape[1] = ouput_rows;
+
+		//	_outputMaskTensorShape[2] = _segHeight;
+		//	_outputMaskTensorShape[3] = _segWidth;
+		//}
+
+		//warm up
+		if (isCuda && warmUp) {
+			//draw run
+			std::cout << "Start warming up" << std::endl;
+			size_t input_tensor_length = VectorProduct(_inputTensorShape);
+			float* temp = new float[input_tensor_length];
+			std::vector<Ort::Value> input_tensors;
+			std::vector<Ort::Value> output_tensors;
+			input_tensors.push_back(Ort::Value::CreateTensor<float>(
+				_OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),
+				_inputTensorShape.size()));
+			for (int i = 0; i < 3; ++i) {
+				output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+					_inputNodeNames.data(),
+					input_tensors.data(),
+					_inputNodeNames.size(),
+					_outputNodeNames.data(),
+					_outputNodeNames.size());
+			}
+
+			delete[]temp;
+		}
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+	return true;
+
+}
+
+int Yolov8PoseOnnx::Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params) {
+	outSrcImgs.clear();
+	cv::Size input_size = cv::Size(_netWidth, _netHeight);
+	for (int i = 0; i < srcImgs.size(); ++i) {
+		cv::Mat temp_img = srcImgs[i];
+		cv::Vec4d temp_param = {1,1,0,0};
+		if (temp_img.size() != input_size) {
+			cv::Mat borderImg;
+			LetterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
+			//std::cout << borderImg.size() << std::endl;
+			outSrcImgs.push_back(borderImg);
+			params.push_back(temp_param);
+		}
+		else {
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+
+	int lack_num =  _batchSize- srcImgs.size();
+	if (lack_num > 0) {
+		for (int i = 0; i < lack_num; ++i) {
+			cv::Mat temp_img = cv::Mat::zeros(input_size, CV_8UC3);
+			cv::Vec4d temp_param = { 1,1,0,0 };
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+	return 0;
+
+}
+bool Yolov8PoseOnnx::OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output) {
+	std::vector<cv::Mat> input_data = { srcImg };
+	std::vector<std::vector<OutputParams>> tenp_output;
+	if (OnnxBatchDetect(input_data, tenp_output)) {
+		output = tenp_output[0];
+		return true;
+	}
+	else return false;
+}
+bool Yolov8PoseOnnx::OnnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<OutputParams>>& output) {
+	std::vector<cv::Vec4d> params;
+	std::vector<cv::Mat> input_images;
+	cv::Size input_size(_netWidth, _netHeight);
+	//preprocessing
+	Preprocessing(srcImgs, input_images, params);
+	cv::Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, cv::Scalar(0, 0, 0), true, false);
+
+	int64_t input_tensor_length = VectorProduct(_inputTensorShape);
+	std::vector<Ort::Value> input_tensors;
+	std::vector<Ort::Value> output_tensors;
+	input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float*)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));
+
+	output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+		_inputNodeNames.data(),
+		input_tensors.data(),
+		_inputNodeNames.size(),
+		_outputNodeNames.data(),
+		_outputNodeNames.size()
+	);
+	//post-process
+	float* all_data = output_tensors[0].GetTensorMutableData<float>();
+	_outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();
+	int net_width = _outputTensorShape[1];
+
+
+	int key_point_length = net_width - 5;
+    //int key_point_num = 17; //_bodyKeyPoints.size(), shape[x, y, confidence]
+    if (key_point_num * 2 != key_point_length) {
+		std::cout << "Pose should be shape [x, y, confidence] with 17-points" << std::endl;
+		return false;
+	}
+	int64_t one_output_length = VectorProduct(_outputTensorShape) / _outputTensorShape[0];
+	for (int img_index = 0; img_index < srcImgs.size(); ++img_index) {
+		cv::Mat output0 = cv::Mat(cv::Size((int)_outputTensorShape[2], (int)_outputTensorShape[1]), CV_32F, all_data).t();  //[bs,116,8400]=>[bs,8400,116]
+		all_data += one_output_length;
+		float* pdata = (float*)output0.data;
+		int rows = output0.rows;
+		std::vector<int> class_ids;//结果id数组
+		std::vector<float> confidences;//结果每个id对应置信度数组
+		std::vector<cv::Rect> boxes;//每个id矩形框
+		std::vector<std::vector<PoseKeyPoint>> pose_key_points; //保存kpt
+
+		for (int r = 0; r < rows; ++r) {    
+			float max_class_socre= pdata[4];
+			if (max_class_socre >= _classThreshold) {
+				//rect [x,y,w,h]
+				float x = (pdata[0] - params[img_index][2]) / params[img_index][0];  //x
+				float y = (pdata[1] - params[img_index][3]) / params[img_index][1];  //y
+				float w = pdata[2] / params[img_index][0];  //w
+				float h = pdata[3] / params[img_index][1];  //h
+				int left = MAX(int(x - 0.5 * w + 0.5), 0);
+				int top = MAX(int(y - 0.5 * h + 0.5), 0);
+				class_ids.push_back(0);
+				confidences.push_back(max_class_socre);
+				boxes.push_back(cv::Rect(left, top, int(w + 0.5), int(h + 0.5)));
+				std::vector<PoseKeyPoint> temp_kpts;
+				for (int kpt = 0; kpt < key_point_length; kpt += 3) {
+					PoseKeyPoint temp_kp;
+					temp_kp.x = (pdata[5 + kpt]- params[img_index][2]) / params[img_index][0];
+					temp_kp.y = (pdata[6 + kpt] - params[img_index][3]) / params[img_index][1];
+					temp_kp.confidence = pdata[7 + kpt];
+					temp_kpts.push_back(temp_kp);
+				}
+				pose_key_points.push_back(temp_kpts);
+			}
+			pdata += net_width;//下一行
+		}
+
+		std::vector<int> nms_result;
+		cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+		std::vector<std::vector<float>> temp_mask_proposals;
+		cv::Rect holeImgRect(0, 0, srcImgs[img_index].cols, srcImgs[img_index].rows);
+		std::vector<OutputParams> temp_output;
+		for (int i = 0; i < nms_result.size(); ++i) {
+			int idx = nms_result[i];
+			OutputParams result;
+			result.id = class_ids[idx];
+			result.confidence = confidences[idx];
+			result.box = boxes[idx] & holeImgRect;
+			result.keyPoints = pose_key_points[idx];
+			if (result.box.area() < 1)
+				continue;
+			temp_output.push_back(result);
+		}
+		output.push_back(temp_output);
+	}
+
+	if (output.size())
+		return true;
+	else
+		return false;
+
+}

+ 91 - 0
yolov8_pose_onnx.h

@@ -0,0 +1,91 @@
+#pragma once
+#include <iostream>
+#include<memory>
+#include <opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+#include<onnxruntime_cxx_api.h>
+
+//#include <tensorrt_provider_factory.h>  //if use OrtTensorRTProviderOptionsV2
+//#include <onnxruntime_c_api.h>
+
+class Yolov8PoseOnnx {
+public:
+	Yolov8PoseOnnx() :_OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
+	~Yolov8PoseOnnx() {
+		if (_OrtSession != nullptr)
+			delete _OrtSession;
+	
+	};// delete _OrtMemoryInfo;
+
+
+public:
+	/** \brief Read onnx-model
+	* \param[in] modelPath:onnx-model path
+	* \param[in] isCuda:if true,use Ort-GPU,else run it on cpu.
+	* \param[in] cudaID:if isCuda==true,run Ort-GPU on cudaID.
+	* \param[in] warmUp:if isCuda==true,warm up GPU-model.
+	*/
+	bool ReadModel(const std::string& modelPath, bool isCuda = false, int cudaID = 0, bool warmUp = true);
+
+	/** \brief  detect.
+	* \param[in] srcImg:a 3-channels image.
+	* \param[out] output:detection results of input image.
+	*/
+	bool OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output);
+	/** \brief  detect,batch size= _batchSize
+	* \param[in] srcImg:A batch of images.
+	* \param[out] output:detection results of input images.
+	*/
+	bool OnnxBatchDetect(std::vector<cv::Mat>& srcImg, std::vector<std::vector<OutputParams>>& output);
+
+private:
+
+	template <typename T>
+	T VectorProduct(const std::vector<T>& v)
+	{
+		return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
+	};
+	int Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params);
+
+	const int _netWidth = 640;   //ONNX-net-input-width
+	const int _netHeight = 640;  //ONNX-net-input-height
+
+	int _batchSize = 1;  //if multi-batch,set this
+	bool _isDynamicShape = false;//onnx support dynamic shape
+    float _classThreshold = 0.75;
+	float _nmsThreshold = 0.45;
+
+    int key_point_num = 1; //_bodyKeyPoints.size(), shape[x, y, confidence]
+    int key_point_shape = 2; // shape[x, y], shape[x, y, confidence]
+
+	//ONNXRUNTIME	
+	Ort::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov8");
+	Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();
+	Ort::Session* _OrtSession = nullptr;
+	Ort::MemoryInfo _OrtMemoryInfo;
+#if ORT_API_VERSION < ORT_OLD_VISON
+	char* _inputName, * _output_name0;
+#else
+	std::shared_ptr<char> _inputName, _output_name0;
+#endif
+
+	std::vector<char*> _inputNodeNames; //输入节点名
+	std::vector<char*> _outputNodeNames;//输出节点名
+
+	size_t _inputNodesNum = 0;        //输入节点数
+	size_t _outputNodesNum = 0;       //输出节点数
+
+	ONNXTensorElementDataType _inputNodeDataType; //数据类型
+	ONNXTensorElementDataType _outputNodeDataType;
+	std::vector<int64_t> _inputTensorShape; //输入张量shape
+
+	std::vector<int64_t> _outputTensorShape;
+
+public:
+	std::vector<std::string> _className = {
+        "arrow"
+	};
+
+
+
+};

+ 135 - 0
yolov8_seg.cpp

@@ -0,0 +1,135 @@
+#include"yolov8_seg.h"
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+
+bool Yolov8Seg::ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda = false) {
+	try {
+		if (!CheckModelPath(netPath))
+			return false;
+		net = cv::dnn::readNetFromONNX(netPath);
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR<7
+		std::cout << "Yolov8-seg Need OpenCV Version >=4.7.0" << std::endl;
+		return false;
+#endif
+#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR==7&&CV_VERSION_REVISION==0
+		net.enableWinograd(false);  //bug of opencv4.7.x in AVX only platform ,https://github.com/opencv/opencv/pull/23112 and https://github.com/opencv/opencv/issues/23080 
+		//net.enableWinograd(true);		//If your CPU supports AVX2, you can set it true to speed up
+#endif
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+
+	if (isCuda) {
+		//cuda
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); //or DNN_TARGET_CUDA_FP16
+	}
+	else {
+		//cpu
+		std::cout << "Inference device: CPU" << std::endl;
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
+	}
+	return true;
+}
+
+
+bool Yolov8Seg::Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output) {
+	cv::Mat blob;
+	output.clear();
+	int col = srcImg.cols;
+	int row = srcImg.rows;
+	cv::Mat netInputImg;
+	cv::Vec4d params;
+	LetterBox(srcImg, netInputImg, params, cv::Size(_netWidth, _netHeight));
+	cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(0, 0, 0), true, false);
+	//**************************************************************************************************************************************************/
+	//如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
+	// If there is no problem with other settings, but results are a lot different from  Python-onnx , you can try to use the following two sentences
+	// 
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);
+	//$ cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);
+	//****************************************************************************************************************************************************/
+	net.setInput(blob);
+	std::vector<cv::Mat> net_output_img;
+	std::vector<std::string> output_layer_names{ "output0","output1" };
+	net.forward(net_output_img, output_layer_names); //get outputs
+	std::vector<int> class_ids;// res-class_id
+	std::vector<float> confidences;// res-conf 
+	std::vector<cv::Rect> boxes;// res-box
+	std::vector<std::vector<float>> picked_proposals;  //output0[:,:, 4 + _className.size():net_width]===> for mask
+	cv::Mat output0 = cv::Mat(cv::Size(net_output_img[0].size[2], net_output_img[0].size[1]), CV_32F, (float*)net_output_img[0].data).t();  //[bs,116,8400]=>[bs,8400,116]
+	int rows = output0.rows;
+	int net_width = output0.cols;
+	int socre_array_length = net_width - 4 - net_output_img[1].size[1];
+	float* pdata = (float*)output0.data;
+
+	for (int r = 0; r < rows; ++r) {
+		cv::Mat scores(1, socre_array_length, CV_32FC1, pdata + 4);
+		cv::Point classIdPoint;
+		double max_class_socre;
+		minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+		max_class_socre = (float)max_class_socre;
+		if (max_class_socre >= _classThreshold) {
+			std::vector<float> temp_proto(pdata + 4 + socre_array_length, pdata + net_width);
+			picked_proposals.push_back(temp_proto);
+			//rect [x,y,w,h]
+			float x = (pdata[0] - params[2]) / params[0];
+			float y = (pdata[1] - params[3]) / params[1];
+			float w = pdata[2] / params[0];
+			float h = pdata[3] / params[1];
+			int left = MAX(int(x - 0.5 * w + 0.5), 0);
+			int top = MAX(int(y - 0.5 * h + 0.5), 0);
+			class_ids.push_back(classIdPoint.x);
+			confidences.push_back(max_class_socre);
+			boxes.push_back(cv::Rect(left, top, int(w + 0.5), int(h + 0.5)));
+		}
+		pdata += net_width;//next line
+	}
+	//NMS
+	std::vector<int> nms_result;
+	cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+	std::vector<std::vector<float>> temp_mask_proposals;
+	cv::Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);
+	for (int i = 0; i < nms_result.size(); ++i) {
+
+		int idx = nms_result[i];
+		OutputParams result;
+		result.id = class_ids[idx];
+		result.confidence = confidences[idx];
+		result.box = boxes[idx] & holeImgRect;
+		if (result.box.area() < 1)
+			continue;
+		temp_mask_proposals.push_back(picked_proposals[idx]);
+		output.push_back(result);
+	}
+	MaskParams mask_params;
+	mask_params.params = params;
+	mask_params.srcImgShape = srcImg.size();
+	mask_params.netHeight = _netHeight;
+	mask_params.netWidth = _netWidth;
+	mask_params.maskThreshold = _maskThreshold;
+	for (int i = 0; i < temp_mask_proposals.size(); ++i) {
+		GetMask2(cv::Mat(temp_mask_proposals[i]).t(), net_output_img[1], output[i], mask_params);
+	}
+
+
+	//******************** ****************
+	// 老版本的方案,如果上面在开启我注释的部分之后还一直报错,建议使用这个。
+	 //If the GetMask2() still reports errors , it is recommended to use GetMask().
+	//cv::Mat mask_proposals;
+	//for (int i = 0; i < temp_mask_proposals.size(); ++i) {
+	//	mask_proposals.push_back(cv::Mat(temp_mask_proposals[i]).t());
+	//}
+	//GetMask(mask_proposals, net_output_img[1], output, mask_params);
+	//*****************************************************/
+
+
+	if (output.size())
+		return true;
+	else
+		return false;
+}
+

+ 32 - 0
yolov8_seg.h

@@ -0,0 +1,32 @@
+#pragma once
+#include<iostream>
+#include<opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+
+class Yolov8Seg {
+public:
+	Yolov8Seg() {
+	}
+	~Yolov8Seg() {}
+
+	bool ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
+	bool Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputParams>& output);
+
+	//类别名,自己的模型需要修改此项
+	std::vector<std::string> _className = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
+		"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
+		"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
+		"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
+		"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
+		"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
+		"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
+		"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
+		"hair drier", "toothbrush" };
+	int _netWidth = 640;   //ONNX图片输入宽度
+	int _netHeight = 640;  //ONNX图片输入高度
+
+private:
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+	float _maskThreshold = 0.5;
+};

+ 316 - 0
yolov8_seg_onnx.cpp

@@ -0,0 +1,316 @@
+#include "yolov8_seg_onnx.h"
+//using namespace std;
+//using namespace cv;
+//using namespace cv::dnn;
+using namespace Ort;
+
+bool Yolov8SegOnnx::ReadModel(const std::string& modelPath, bool isCuda, int cudaID, bool warmUp) {
+	if (_batchSize < 1) _batchSize = 1;
+	try
+	{
+		if (!CheckModelPath(modelPath))
+			return false;
+		std::vector<std::string> available_providers = GetAvailableProviders();
+		auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");
+
+		if (isCuda && (cuda_available == available_providers.end()))
+		{
+			std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		else if (isCuda && (cuda_available != available_providers.end()))
+		{
+			std::cout << "************* Infer model on GPU! *************" << std::endl;
+#if ORT_API_VERSION < ORT_OLD_VISON
+			OrtCUDAProviderOptions cudaOption;
+			cudaOption.device_id = cudaID;
+			_OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
+#else
+			OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);
+#endif
+		}
+		else
+		{
+			std::cout << "************* Infer model on CPU! *************" << std::endl;
+		}
+		//
+		_OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
+
+#ifdef _WIN32
+		std::wstring model_path(modelPath.begin(), modelPath.end());
+		_OrtSession = new Ort::Session(_OrtEnv, model_path.c_str(), _OrtSessionOptions);
+#else
+		_OrtSession = new Ort::Session(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
+#endif
+
+		Ort::AllocatorWithDefaultOptions allocator;
+		//init input
+		_inputNodesNum = _OrtSession->GetInputCount();
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_inputName = _OrtSession->GetInputName(0, allocator);
+		_inputNodeNames.push_back(_inputName);
+#else
+		_inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));
+		_inputNodeNames.push_back(_inputName.get());
+#endif
+
+		Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);
+		auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
+		_inputNodeDataType = input_tensor_info.GetElementType();
+		_inputTensorShape = input_tensor_info.GetShape();
+
+		if (_inputTensorShape[0] == -1)
+		{
+			_isDynamicShape = true;
+			_inputTensorShape[0] = _batchSize;
+
+		}
+		if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1) {
+			_isDynamicShape = true;
+			_inputTensorShape[2] = _netHeight;
+			_inputTensorShape[3] = _netWidth;
+		}
+		//init output
+		_outputNodesNum = _OrtSession->GetOutputCount();
+		if (_outputNodesNum != 2) {
+			std::cout << "This model has " << _outputNodesNum << "output, which is not a segmentation model.Please check your model name or path!" << std::endl;
+			return false;
+		}
+#if ORT_API_VERSION < ORT_OLD_VISON
+		_output_name0 = _OrtSession->GetOutputName(0, allocator);
+		_output_name1 = _OrtSession->GetOutputName(1, allocator);
+#else
+		_output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));
+		_output_name1 = std::move(_OrtSession->GetOutputNameAllocated(1, allocator));
+#endif
+		Ort::TypeInfo type_info_output0(nullptr);
+		Ort::TypeInfo type_info_output1(nullptr);
+		bool flag = false;
+#if ORT_API_VERSION < ORT_OLD_VISON
+		flag = strcmp(_output_name0, _output_name1) < 0;
+#else
+		flag = strcmp(_output_name0.get(), _output_name1.get()) < 0;
+#endif
+		if (flag)  //make sure "output0" is in front of  "output1"
+		{
+			type_info_output0 = _OrtSession->GetOutputTypeInfo(0);  //output0
+			type_info_output1 = _OrtSession->GetOutputTypeInfo(1);  //output1
+#if ORT_API_VERSION < ORT_OLD_VISON
+			_outputNodeNames.push_back(_output_name0);
+			_outputNodeNames.push_back(_output_name1);
+#else
+			_outputNodeNames.push_back(_output_name0.get());
+			_outputNodeNames.push_back(_output_name1.get());
+#endif
+
+		}
+		else {
+			type_info_output0 = _OrtSession->GetOutputTypeInfo(1);  //output0
+			type_info_output1 = _OrtSession->GetOutputTypeInfo(0);  //output1
+#if ORT_API_VERSION < ORT_OLD_VISON
+			_outputNodeNames.push_back(_output_name1);
+			_outputNodeNames.push_back(_output_name0);
+#else
+			_outputNodeNames.push_back(_output_name1.get());
+			_outputNodeNames.push_back(_output_name0.get());
+#endif
+		}
+
+		auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
+		_outputNodeDataType = tensor_info_output0.GetElementType();
+		_outputTensorShape = tensor_info_output0.GetShape();
+		auto tensor_info_output1 = type_info_output1.GetTensorTypeAndShapeInfo();
+		//_outputMaskNodeDataType = tensor_info_output1.GetElementType(); //the same as output0
+		//_outputMaskTensorShape = tensor_info_output1.GetShape();
+		//if (_outputTensorShape[0] == -1)
+		//{
+		//	_outputTensorShape[0] = _batchSize;
+		//	_outputMaskTensorShape[0] = _batchSize;
+		//}
+		//if (_outputMaskTensorShape[2] == -1) {
+		//	//size_t ouput_rows = 0;
+		//	//for (int i = 0; i < _strideSize; ++i) {
+		//	//	ouput_rows += 3 * (_netWidth / _netStride[i]) * _netHeight / _netStride[i];
+		//	//}
+		//	//_outputTensorShape[1] = ouput_rows;
+
+		//	_outputMaskTensorShape[2] = _segHeight;
+		//	_outputMaskTensorShape[3] = _segWidth;
+		//}
+		//warm up
+		if (isCuda && warmUp) {
+			//draw run
+			std::cout << "Start warming up" << std::endl;
+			size_t input_tensor_length = VectorProduct(_inputTensorShape);
+			float* temp = new float[input_tensor_length];
+			std::vector<Ort::Value> input_tensors;
+			std::vector<Ort::Value> output_tensors;
+			input_tensors.push_back(Ort::Value::CreateTensor<float>(
+				_OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),
+				_inputTensorShape.size()));
+			for (int i = 0; i < 3; ++i) {
+				output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+					_inputNodeNames.data(),
+					input_tensors.data(),
+					_inputNodeNames.size(),
+					_outputNodeNames.data(),
+					_outputNodeNames.size());
+			}
+
+			delete[]temp;
+		}
+	}
+	catch (const std::exception&) {
+		return false;
+	}
+	return true;
+}
+
+int Yolov8SegOnnx::PreProcessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params) {
+	outSrcImgs.clear();
+	cv::Size input_size = cv::Size(_netWidth, _netHeight);
+	for (int i = 0; i < srcImgs.size(); ++i) {
+		cv::Mat temp_img = srcImgs[i];
+		cv::Vec4d temp_param = { 1,1,0,0 };
+		if (temp_img.size() != input_size) {
+			cv::Mat borderImg;
+			LetterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
+			//std::cout << borderImg.size() << std::endl;
+			outSrcImgs.push_back(borderImg);
+			params.push_back(temp_param);
+		}
+		else {
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+
+	int lack_num = srcImgs.size() % _batchSize;
+	if (lack_num != 0) {
+		for (int i = 0; i < lack_num; ++i) {
+			cv::Mat temp_img = cv::Mat::zeros(input_size, CV_8UC3);
+			cv::Vec4d temp_param = { 1,1,0,0 };
+			outSrcImgs.push_back(temp_img);
+			params.push_back(temp_param);
+		}
+	}
+	return 0;
+
+}
+bool Yolov8SegOnnx::OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output) {
+	std::vector<cv::Mat> input_data = { srcImg };
+	std::vector<std::vector<OutputParams>> tenp_output;
+	if (OnnxBatchDetect(input_data, tenp_output)) {
+		output = tenp_output[0];
+		return true;
+	}
+	else return false;
+}
+bool Yolov8SegOnnx::OnnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<OutputParams>>& output) {
+	std::vector<cv::Vec4d> params;
+	std::vector<cv::Mat> input_images;
+	cv::Size input_size(_netWidth, _netHeight);
+	//preprocessing
+	PreProcessing(srcImgs, input_images, params);
+	cv::Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, cv::Scalar(0, 0, 0), true, false);
+
+	int64_t input_tensor_length = VectorProduct(_inputTensorShape);
+	std::vector<Ort::Value> input_tensors;
+	std::vector<Ort::Value> output_tensors;
+	input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float*)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));
+
+	output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
+		_inputNodeNames.data(),
+		input_tensors.data(),
+		_inputNodeNames.size(),
+		_outputNodeNames.data(),
+		_outputNodeNames.size()
+	);
+
+	//post-process
+	float* all_data = output_tensors[0].GetTensorMutableData<float>();
+	_outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();
+	_outputMaskTensorShape = output_tensors[1].GetTensorTypeAndShapeInfo().GetShape();
+	std::vector<int> mask_protos_shape = { 1,(int)_outputMaskTensorShape[1],(int)_outputMaskTensorShape[2],(int)_outputMaskTensorShape[3] };
+	int mask_protos_length = VectorProduct(mask_protos_shape);
+	int64_t one_output_length = VectorProduct(_outputTensorShape) / _outputTensorShape[0];
+	int net_width = (int)_outputTensorShape[1];
+	int socre_array_length = net_width - 4 - _outputMaskTensorShape[1];
+	for (int img_index = 0; img_index < srcImgs.size(); ++img_index) {
+		cv::Mat output0 = cv::Mat(cv::Size((int)_outputTensorShape[2], (int)_outputTensorShape[1]), CV_32F, all_data).t();  //[bs,116,8400]=>[bs,8400,116]
+		all_data += one_output_length;
+		float* pdata = (float*)output0.data;
+		int rows = output0.rows;
+		std::vector<int> class_ids;//结果id数组
+		std::vector<float> confidences;//结果每个id对应置信度数组
+		std::vector<cv::Rect> boxes;//每个id矩形框
+		std::vector<std::vector<float>> picked_proposals;  //output0[:,:, 5 + _className.size():net_width]===> for mask
+		for (int r = 0; r < rows; ++r) {    //stride
+			cv::Mat scores(1, socre_array_length, CV_32F, pdata + 4);
+			cv::Point classIdPoint;
+			double max_class_socre;
+			minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+			max_class_socre = (float)max_class_socre;
+			if (max_class_socre >= _classThreshold) {
+				std::vector<float> temp_proto(pdata + 4 + socre_array_length, pdata + net_width);
+				picked_proposals.push_back(temp_proto);
+				//rect [x,y,w,h]
+				float x = (pdata[0] - params[img_index][2]) / params[img_index][0];  //x
+				float y = (pdata[1] - params[img_index][3]) / params[img_index][1];  //y
+				float w = pdata[2] / params[img_index][0];  //w
+				float h = pdata[3] / params[img_index][1];  //h
+				int left = MAX(int(x - 0.5 * w + 0.5), 0);
+				int top = MAX(int(y - 0.5 * h + 0.5), 0);
+				class_ids.push_back(classIdPoint.x);
+				confidences.push_back(max_class_socre);
+				boxes.push_back(cv::Rect(left, top, int(w + 0.5), int(h + 0.5)));
+			}
+			pdata += net_width;//下一行
+		}
+
+		std::vector<int> nms_result;
+		cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
+		std::vector<std::vector<float>> temp_mask_proposals;
+		cv::Rect holeImgRect(0, 0, srcImgs[img_index].cols, srcImgs[img_index].rows);
+		std::vector<OutputParams> temp_output;
+		for (int i = 0; i < nms_result.size(); ++i) {
+			int idx = nms_result[i];
+			OutputParams result;
+			result.id = class_ids[idx];
+			result.confidence = confidences[idx];
+			result.box = boxes[idx] & holeImgRect;
+			if (result.box.area() < 1)
+				continue;
+			temp_mask_proposals.push_back(picked_proposals[idx]);
+			temp_output.push_back(result);
+		}
+
+		MaskParams mask_params;
+		mask_params.params = params[img_index];
+		mask_params.srcImgShape = srcImgs[img_index].size();
+		mask_params.netHeight = _netHeight;
+		mask_params.netWidth = _netWidth;
+		mask_params.maskThreshold = _maskThreshold;
+		cv::Mat mask_protos = cv::Mat(mask_protos_shape, CV_32F, output_tensors[1].GetTensorMutableData<float>() + img_index * mask_protos_length);
+		for (int i = 0; i < temp_mask_proposals.size(); ++i) {
+			GetMask2(cv::Mat(temp_mask_proposals[i]).t(), mask_protos, temp_output[i], mask_params);
+		}
+
+		//******************** ****************
+		// 老版本的方案,如果上面在开启我注释的部分之后还一直报错,建议使用这个。
+		// If the GetMask2() still reports errors , it is recommended to use GetMask().
+		//cv::Mat mask_proposals;
+		//for (int i = 0; i < temp_mask_proposals.size(); ++i) {
+		//	mask_proposals.push_back(cv::Mat(temp_mask_proposals[i]).t());
+		//}
+		//GetMask(mask_proposals, mask_protos, temp_output, mask_params);
+		//*****************************************************/
+		output.push_back(temp_output);
+
+	}
+
+	if (output.size())
+		return true;
+	else
+		return false;
+}

+ 97 - 0
yolov8_seg_onnx.h

@@ -0,0 +1,97 @@
+#pragma once
+#include <iostream>
+#include<memory>
+#include <opencv2/opencv.hpp>
+#include "yolov8_utils.h"
+#include<onnxruntime_cxx_api.h>
+//#include <tensorrt_provider_factory.h>  //if use OrtTensorRTProviderOptionsV2
+//#include <onnxruntime_c_api.h>
+
+class Yolov8SegOnnx {
+public:
+	Yolov8SegOnnx() :_OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
+	~Yolov8SegOnnx() {
+		if (_OrtSession != nullptr)
+			delete _OrtSession;
+	};// delete _OrtMemoryInfo;
+
+
+public:
+	/** \brief Read onnx-model
+	* \param[in] modelPath:onnx-model path
+	* \param[in] isCuda:if true,use Ort-GPU,else run it on cpu.
+	* \param[in] cudaID:if isCuda==true,run Ort-GPU on cudaID.
+	* \param[in] warmUp:if isCuda==true,warm up GPU-model.
+	*/
+	bool ReadModel(const std::string& modelPath, bool isCuda = false, int cudaID = 0, bool warmUp = true);
+
+	/** \brief  detect.
+	* \param[in] srcImg:a 3-channels image.
+	* \param[out] output:detection results of input image.
+	*/
+	bool OnnxDetect(cv::Mat& srcImg, std::vector<OutputParams>& output);
+	/** \brief  detect,batch size= _batchSize
+	* \param[in] srcImg:A batch of images.
+	* \param[out] output:detection results of input images.
+	*/
+	bool OnnxBatchDetect(std::vector<cv::Mat>& srcImg, std::vector<std::vector<OutputParams>>& output);
+
+private:
+
+	template <typename T>
+	T VectorProduct(const std::vector<T>& v)
+	{
+		return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
+	};
+	int PreProcessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params);
+
+	const int _netWidth = 640;   //ONNX-net-input-width
+	const int _netHeight = 640;  //ONNX-net-input-height
+
+	int _batchSize = 1;  //if multi-batch,set this
+	bool _isDynamicShape = false;//onnx support dynamic shape
+	float _classThreshold = 0.25;
+	float _nmsThreshold = 0.45;
+	float _maskThreshold = 0.5;
+
+
+	//ONNXRUNTIME	
+	Ort::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov8");
+	Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();
+	Ort::Session* _OrtSession = nullptr;
+	Ort::MemoryInfo _OrtMemoryInfo;
+#if ORT_API_VERSION < ORT_OLD_VISON
+
+	char* _inputName, * _output_name0, * _output_name1;
+#else
+	std::shared_ptr<char> _inputName, _output_name0,_output_name1;
+#endif
+
+	std::vector<char*> _inputNodeNames; //输入节点名
+	std::vector<char*> _outputNodeNames;//输出节点名
+
+	size_t _inputNodesNum = 0;        //输入节点数
+	size_t _outputNodesNum = 0;       //输出节点数
+
+	ONNXTensorElementDataType _inputNodeDataType; //数据类型
+	ONNXTensorElementDataType _outputNodeDataType;
+	std::vector<int64_t> _inputTensorShape; //输入张量shape
+
+	std::vector<int64_t> _outputTensorShape;
+	std::vector<int64_t> _outputMaskTensorShape;
+public:
+	std::vector<std::string> _className = {
+		"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
+		"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
+		"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
+		"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
+		"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
+		"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
+		"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
+		"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
+		"hair drier", "toothbrush"
+	};
+
+
+
+};

+ 278 - 0
yolov8_utils.cpp

@@ -0,0 +1,278 @@
+#pragma once
+#include "yolov8_utils.h"
+//using namespace cv;
+//using namespace std;
+bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize) {
+	if (netHeight % netStride[strideSize - 1] != 0 || netWidth % netStride[strideSize - 1] != 0)
+	{
+		std::cout << "Error:_netHeight and _netWidth must be multiple of max stride " << netStride[strideSize - 1] << "!" << std::endl;
+		return false;
+	}
+	return true;
+}
+bool CheckModelPath(std::string modelPath) {
+
+#ifdef _WIN32
+
+    if (0 != _access(modelPath.c_str(), 0)) {
+        std::cout << "Model path does not exist,  please check " << modelPath << std::endl;
+        return false;
+    }
+    else
+        return true;
+
+#else
+
+    return (0 == access(modelPath.c_str(), F_OK));
+    if (0 != access(modelPath.c_str(), F_OK)) {
+        std::cout << "Model path does not exist,  please check " << modelPath << std::endl;
+        return false;
+    }
+    else
+        return true;
+#endif
+
+
+}
+void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,
+	bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
+{
+	if (false) {
+		int maxLen = MAX(image.rows, image.cols);
+		outImage = cv::Mat::zeros(cv::Size(maxLen, maxLen), CV_8UC3);
+		image.copyTo(outImage(cv::Rect(0, 0, image.cols, image.rows)));
+		params[0] = 1;
+		params[1] = 1;
+		params[3] = 0;
+		params[2] = 0;
+	}
+
+	cv::Size shape = image.size();
+	float r = std::min((float)newShape.height / (float)shape.height,
+		(float)newShape.width / (float)shape.width);
+	if (!scaleUp)
+		r = std::min(r, 1.0f);
+
+	float ratio[2]{ r, r };
+	int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };
+
+	auto dw = (float)(newShape.width - new_un_pad[0]);
+	auto dh = (float)(newShape.height - new_un_pad[1]);
+
+	if (autoShape)
+	{
+		dw = (float)((int)dw % stride);
+		dh = (float)((int)dh % stride);
+	}
+	else if (scaleFill)
+	{
+		dw = 0.0f;
+		dh = 0.0f;
+		new_un_pad[0] = newShape.width;
+		new_un_pad[1] = newShape.height;
+		ratio[0] = (float)newShape.width / (float)shape.width;
+		ratio[1] = (float)newShape.height / (float)shape.height;
+	}
+
+	dw /= 2.0f;
+	dh /= 2.0f;
+
+	if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1])
+	{
+		cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));
+	}
+	else {
+		outImage = image.clone();
+	}
+
+	int top = int(std::round(dh - 0.1f));
+	int bottom = int(std::round(dh + 0.1f));
+	int left = int(std::round(dw - 0.1f));
+	int right = int(std::round(dw + 0.1f));
+	params[0] = ratio[0];
+	params[1] = ratio[1];
+	params[2] = left;
+	params[3] = top;
+	cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
+}
+
+void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputParams>& output, const MaskParams& maskParams) {
+	//std::cout << maskProtos.size << std::endl;
+
+	int net_width = maskParams.netWidth;
+	int net_height = maskParams.netHeight;
+	int seg_channels = maskProtos.size[1];
+	int seg_height = maskProtos.size[2];
+	int seg_width = maskProtos.size[3];
+	float mask_threshold = maskParams.maskThreshold;
+	cv::Vec4f params = maskParams.params;
+	cv::Size src_img_shape = maskParams.srcImgShape;
+
+	cv::Mat protos = maskProtos.reshape(0, { seg_channels,seg_width * seg_height });
+
+	cv::Mat matmul_res = (maskProposals * protos).t();
+	cv::Mat masks = matmul_res.reshape(output.size(), { seg_width,seg_height });
+	std::vector<cv::Mat> maskChannels;
+	split(masks, maskChannels);
+	for (int i = 0; i < output.size(); ++i) {
+		cv::Mat dest, mask;
+		//sigmoid
+		cv::exp(-maskChannels[i], dest);
+		dest = 1.0 / (1.0 + dest);
+
+		cv::Rect roi(int(params[2] / net_width * seg_width), int(params[3] / net_height * seg_height), int(seg_width - params[2] / 2), int(seg_height - params[3] / 2));
+		dest = dest(roi);
+		resize(dest, mask, src_img_shape, cv::INTER_NEAREST);
+
+		//crop
+		cv::Rect temp_rect = output[i].box;
+		mask = mask(temp_rect) > mask_threshold;
+		output[i].boxMask = mask;
+	}
+}
+
+void GetMask2(const cv::Mat& maskProposals, const cv::Mat& maskProtos, OutputParams& output, const MaskParams& maskParams) {
+	int net_width = maskParams.netWidth;
+	int net_height = maskParams.netHeight;
+	int seg_channels = maskProtos.size[1];
+	int seg_height = maskProtos.size[2];
+	int seg_width = maskProtos.size[3];
+	float mask_threshold = maskParams.maskThreshold;
+	cv::Vec4f params = maskParams.params;
+	cv::Size src_img_shape = maskParams.srcImgShape;
+
+	cv::Rect temp_rect = output.box;
+	//crop from mask_protos
+	int rang_x = floor((temp_rect.x * params[0] + params[2]) / net_width * seg_width);
+	int rang_y = floor((temp_rect.y * params[1] + params[3]) / net_height * seg_height);
+	int rang_w = ceil(((temp_rect.x + temp_rect.width) * params[0] + params[2]) / net_width * seg_width) - rang_x;
+	int rang_h = ceil(((temp_rect.y + temp_rect.height) * params[1] + params[3]) / net_height * seg_height) - rang_y;
+
+	//如果下面的 mask_protos(roi_rangs).clone()位置报错,说明你的output.box数据不对,或者矩形框就1个像素的,开启下面的注释部分防止报错。
+	rang_w = MAX(rang_w, 1);
+	rang_h = MAX(rang_h, 1);
+	if (rang_x + rang_w > seg_width) {
+		if (seg_width - rang_x > 0)
+			rang_w = seg_width - rang_x;
+		else
+			rang_x -= 1;
+	}
+	if (rang_y + rang_h > seg_height) {
+		if (seg_height - rang_y > 0)
+			rang_h = seg_height - rang_y;
+		else
+			rang_y -= 1;
+	}
+
+	std::vector<cv::Range> roi_rangs;
+	roi_rangs.push_back(cv::Range(0, 1));
+	roi_rangs.push_back(cv::Range::all());
+	roi_rangs.push_back(cv::Range(rang_y, rang_h + rang_y));
+	roi_rangs.push_back(cv::Range(rang_x, rang_w + rang_x));
+
+	//crop
+	cv::Mat temp_mask_protos = maskProtos(roi_rangs).clone();
+	cv::Mat protos = temp_mask_protos.reshape(0, { seg_channels,rang_w * rang_h });
+	cv::Mat matmul_res = (maskProposals * protos).t();
+	cv::Mat masks_feature = matmul_res.reshape(1, { rang_h,rang_w });
+	cv::Mat dest, mask;
+
+	//sigmoid
+	cv::exp(-masks_feature, dest);
+	dest = 1.0 / (1.0 + dest);
+
+	int left = floor((net_width / seg_width * rang_x - params[2]) / params[0]);
+	int top = floor((net_height / seg_height * rang_y - params[3]) / params[1]);
+	int width = ceil(net_width / seg_width * rang_w / params[0]);
+	int height = ceil(net_height / seg_height * rang_h / params[1]);
+
+	resize(dest, mask, cv::Size(width, height), cv::INTER_NEAREST);
+	cv::Rect mask_rect = temp_rect - cv::Point(left, top);
+	mask_rect &= cv::Rect(0, 0, width, height);
+	mask = mask(mask_rect) > mask_threshold;
+	if (mask.rows != temp_rect.height || mask.cols != temp_rect.width) { //https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp/pull/30
+		resize(mask, mask, temp_rect.size(), cv::INTER_NEAREST);
+	}
+	output.boxMask = mask;
+
+}
+int BBox2Obb(float centerX, float centerY, float boxW, float boxH, float angle, cv::RotatedRect& rotatedRect) {
+	rotatedRect = cv::RotatedRect(cv::Point2f(centerX, centerY), cv::Size2f(boxW, boxH), angle);
+	return 0;
+}
+void DrawRotatedBox(cv::Mat& srcImg, cv::RotatedRect box, cv::Scalar color, int thinkness) {
+	cv::Point2f p[4];
+	box.points(p);
+	for (int l = 0; l < 4; ++l) {
+		line(srcImg, p[l], p[(l + 1) % 4], color, thinkness, 8);
+	}
+}
+
+void DrawPred(cv::Mat& img, std::vector<OutputParams> result, std::vector<std::string> classNames, std::vector<cv::Scalar> color) {
+	cv::Mat mask = img.clone();
+	for (int i = 0; i < result.size(); i++) {
+		int left = 0, top = 0;
+
+		int color_num = i;
+		if (result[i].box.area() > 0) {
+			rectangle(img, result[i].box, color[result[i].id], 2, 8);
+			left = result[i].box.x;
+			top = result[i].box.y;
+		}
+		if (result[i].rotatedBox.size.width * result[i].rotatedBox.size.height > 0) {
+			DrawRotatedBox(img, result[i].rotatedBox, color[result[i].id], 2);
+			left = result[i].rotatedBox.center.x;
+			top = result[i].rotatedBox.center.y;
+		}
+		if (result[i].boxMask.rows && result[i].boxMask.cols > 0)
+			mask(result[i].box).setTo(color[result[i].id], result[i].boxMask);
+		std::string label = classNames[result[i].id] + ":" + std::to_string(result[i].confidence);
+		int baseLine;
+		cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
+		top = MAX(top, labelSize.height);
+		//rectangle(frame, cv::Point(left, top - int(1.5 * labelSize.height)), cv::Point(left + int(1.5 * labelSize.width), top + baseLine), cv::Scalar(0, 255, 0), FILLED);
+		putText(img, label, cv::Point(left, top), cv::FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);
+	}
+	cv::addWeighted(img, 0.5, mask, 0.5, 0, img); //add mask to src
+}
+
+
+void DrawPredPose(cv::Mat& img, std::vector<OutputParams> result, PoseParams& poseParams) {
+	for (int i = 0; i < result.size(); i++) {
+		int left, top;
+		int color_num = i;
+		if (result[i].box.area() > 0) {
+            rectangle(img, result[i].box, poseParams.objColor, 2, 8);
+			left = result[i].box.x;
+			top = result[i].box.y;
+		}
+		else
+			continue;
+
+        std::string label = std::to_string(result[i].confidence);
+		int baseLine;
+		cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
+		top = MAX(top, labelSize.height);
+		//rectangle(frame, cv::Point(left, top - int(1.5 * labelSize.height)), cv::Point(left + int(1.5 * labelSize.width), top + baseLine), cv::Scalar(0, 255, 0), FILLED);
+        putText(img, label, cv::Point(left+20, top), cv::FONT_HERSHEY_SIMPLEX, 1, poseParams.objColor, 2);
+		if (result[i].keyPoints.size() != poseParams.kptBodyNames.size())
+			continue;
+		for (int j = 0; j < result[i].keyPoints.size(); ++j) {
+			PoseKeyPoint kpt = result[i].keyPoints[j];
+			if (kpt.confidence < poseParams.kptThreshold)
+				continue;
+			cv::Scalar kptColor = poseParams.posePalette[poseParams.kptColor[j]];
+			cv::circle(img, cv::Point(kpt.x, kpt.y), poseParams.kptRadius, kptColor, -1, 8);
+		}
+		if (poseParams.isDrawKptLine) {
+			for (int j = 0; j < poseParams.skeleton.size(); ++j) {
+				PoseKeyPoint kpt0 = result[i].keyPoints[poseParams.skeleton[j][0] - 1];
+				PoseKeyPoint kpt1 = result[i].keyPoints[poseParams.skeleton[j][1] - 1];
+				if (kpt0.confidence < poseParams.kptThreshold || kpt1.confidence < poseParams.kptThreshold)
+					continue;
+				cv::Scalar kptColor = poseParams.posePalette[poseParams.limbColor[j]];
+				cv::line(img, cv::Point(kpt0.x, kpt0.y), cv::Point(kpt1.x, kpt1.y), kptColor, 2, 8);
+			}
+		}
+	}
+}

+ 85 - 0
yolov8_utils.h

@@ -0,0 +1,85 @@
+#pragma once
+#include<iostream>
+#include <numeric>
+#include<opencv2/opencv.hpp>
+
+#ifdef _WIN32
+    #include <io.h>     // Windows: _access
+#else
+    #include <unistd.h> // Linux/macOS: access
+#endif
+
+#define ORT_OLD_VISON 13  //ort1.12.0 之前的版本为旧版本API
+
+struct PoseKeyPoint {
+	float x = 0;
+	float y = 0;
+	float confidence = 0;
+};
+
+struct OutputParams {
+	int id;             //结果类别id
+	float confidence;   //结果置信度
+	cv::Rect box;       //矩形框
+	cv::RotatedRect rotatedBox;  //obb结果矩形框
+	cv::Mat boxMask;       //矩形框内mask,节省内存空间和加快速度
+	std::vector<PoseKeyPoint> keyPoints; //pose key points
+
+};
+struct MaskParams {
+	//int segChannels = 32;
+	//int segWidth = 160;
+	//int segHeight = 160;
+	int netWidth = 640;
+	int netHeight = 640;
+	float maskThreshold = 0.5;
+	cv::Size srcImgShape;
+	cv::Vec4d params;
+};
+
+struct PoseParams {
+	float kptThreshold = 0.5;
+	int kptRadius = 5;
+    bool isDrawKptLine = false; //If True, the function will draw lines connecting keypoint for human pose.Default is True.
+    cv::Scalar objColor = cv::Scalar(0, 0, 255);
+    std::vector<std::vector<int>>skeleton = {
+        {16, 14} ,{14, 12},{17, 15},{15, 13},
+        {12, 13},{6, 12},{7, 13},{6, 7},{6, 8},{7, 9},
+        {8, 10},{9, 11},{2, 3},{1, 2},{1, 3},{2, 4},
+        {3, 5},{4, 6},{5, 7}
+    };
+	std::vector<cv::Scalar> posePalette =
+	{
+    cv::Scalar(255, 128, 0)
+	};
+    std::vector<int> limbColor = {0};
+    std::vector<int> kptColor = {0};
+	std::map<unsigned int, std::string> kptBodyNames{
+                    {0,"A"}
+	};
+};
+
+
+
+bool CheckModelPath(std::string modelPath);
+bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize);
+void DrawPred(cv::Mat& img,
+	std::vector<OutputParams> result,
+	std::vector<std::string> classNames,
+    std::vector<cv::Scalar> color
+);
+void DrawPredPose(cv::Mat& img, std::vector<OutputParams> result, PoseParams& poseParams);
+
+void DrawRotatedBox(cv::Mat& srcImg, cv::RotatedRect box, cv::Scalar color, int thinkness);
+void LetterBox(const cv::Mat& image, cv::Mat& outImage,
+	cv::Vec4d& params, //[ratio_x,ratio_y,dw,dh]
+	const cv::Size& newShape = cv::Size(640, 640),
+	bool autoShape = false,
+	bool scaleFill = false,
+	bool scaleUp = true,
+	int stride = 32,
+	const cv::Scalar& color = cv::Scalar(114, 114, 114));
+void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputParams>& output, const MaskParams& maskParams);
+void GetMask2(const cv::Mat& maskProposals, const cv::Mat& maskProtos, OutputParams& output, const MaskParams& maskParams);
+int BBox2Obb(float centerX, float centerY, float boxW, float boxH, float angle, cv::RotatedRect& rotatedRect);
+