Add unit tests

This commit is contained in:
2026-03-29 08:45:38 +11:00
parent 8a2e721058
commit 2392b6785b
19 changed files with 12790 additions and 1 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/json_parser.hpp"
#include "boost/foreach.hpp"
#include "boost/optional.hpp"
#include <string>
#include <regex>
#include <filesystem>
#include "ANSODEngine.h"
#include "openvino/openvino.hpp"
#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "format_reader/include/format_reader_ptr.h"
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include <openvino/op/transpose.hpp>
#include <openvino/core/node.hpp>
#include <opencv2/dnn.hpp>
#include <fstream>
//#include "inference_engine.hpp"
#include <filesystem>
#include "ANSPOSE.h"
#include "ANSSAM.h"
#include "ANSEngineCommon.h"
#include "ANSLPR.h"
#include "ANSLPR_CPU.h"
#include <stdlib.h>
using namespace cv;
using namespace dnn;
template<typename T>
T GetOptionalValue(const boost::property_tree::ptree& pt, std::string attribute, T defaultValue) {
if (pt.count(attribute)) {
return pt.get<T>(attribute);
}
return defaultValue;
}
template <typename T>
T GetData(const boost::property_tree::ptree& pt, const std::string& key)
{
T ret;
if (boost::optional<T> data = pt.get_optional<T>(key))
{
ret = data.get();
}
else
{
throw std::runtime_error("Could not read the data from ptree: [key: " + key + "]");
}
return ret;
}
int GPUYolov10EngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int OpenVINOYolov10EngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int OpenVINOYolov10EngineUnitTestLoop(std::string modelFilePath, std::string videoFilePath);
int GPUEngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int ONNXEngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int GPUEngineImageTest(std::string modelFilePath, std::string imageFilePath);
int OpenVINOEngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int FacialDetectorTest(std::string modelFilePath, std::string imagePath);
int AnomalibTest(std::string abmodelFilePath, std::string abImageFilePath);
int HumanPoseTest(std::string modelFilePath, std::string imagePath);
int HumanPoseImageTest(std::string modelFilePath, std::string imagePath);
int ANSSAMTest(std::string modelFilePath, std::string imagePath);
int ODHUBAPITest(std::string modelFilePath, std::string videoFilePath);
int ODHUBOpenCVAPITest(std::string modelFilePath, std::string videoFilePath);
int ALPRPipeLineTest(std::string modelFilePath, std::string videoFilePath);
int ODHUBAPIImageTest(std::string modelFilePath, std::string imageFilePath);
int ODHUBCVAPIImageTest(std::string modelFilePath, std::string imageFilePath);
int CustomCodeImageTest(std::string modelFilePath, std::string imageFilePath);
int UnitTests();
int FallDetection();
int HeadDetection();
int FireNSmokeDetection();
int VehicleDetection();
void TestODHUB();
void DissemTest();
int DissemParallelTest(std::string modelFilePath, std::string imageFilePath);
int CustomTest();
int CocoTest();
int PersonHead();
int GenericModelTest();
int FaceDetector(std::string modelFilePath, std::string videoFilePath);
int TiledInferenceTest(std::string modelFilePath, std::string imageFilePath);
int NormalInferenceTest(std::string modelFilePath, std::string imageFilePath);
int TiledInferenceTest();
int MotionDetection(std::string modelFilePath, std::string videoFilePath);
int MotionDetectionForFireNSmoke();
int StressTest();
int GPU11EngineImageTest(std::string modelFilePath, std::string imageFilePath);
int GPU11EngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int Yolov11RT_Test();
int Yolov10RT_Test();
int OpenVINOCLEngineImageTest(std::string modelFilePath, std::string imageFilePath);
int TENSORRTCLEngineImageTest(std::string modelFilePath, std::string imageFilePath);
int TestCL();
int Engine_Test();
int SegEngineImageTest(std::string modelFilePath, std::string imageFilePath);
int SegmentationTest();
int Yolov8EngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int Yolov5EngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int Yolov12EngineUnitTest(std::string modelFilePath, std::string videoFilePath);
int LocSetTest();
int RectifierTest();
int FaceTest();
int FaceOVTest();
int FaceYoloTest();
int TestYOLOV12();
int PPETest();
int RVATest();
int CustomModel_StressTest_FilePlayer();

View File

@@ -0,0 +1,154 @@
// Separate translation unit for ANSSAM3 (TensorRT) tests.
// TensorRT/CUDA headers conflict with Windows SDK (ACCESS_MASK ambiguous symbol)
// when included in the same .cpp as ONNX Runtime headers, so we isolate them here.
#include "ANSSAM3.h"
#include <iostream>
#include <chrono>
#include <opencv2/opencv.hpp>
int SAM3TRT_UnitTest()
{
std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\video_20.mp4";
std::string modelFolder = "C:\\Projects\\ANSVIS\\Models\\ANS_SAM_v3.0";
ANSCENTER::ANSSAM3 infHandle;
ANSCENTER::ModelConfig modelConfig;
modelConfig.modelConfThreshold = 0.5f;
std::string labelmap;
if (!infHandle.LoadModelFromFolder("", modelConfig, "anssam3", "", modelFolder, labelmap)) {
std::cerr << "SAM3TRT_UnitTest: LoadModelFromFolder failed\n";
return -1;
}
infHandle.SetPrompt("person");
cv::VideoCapture capture(videoFile);
if (!capture.isOpened()) {
std::cerr << "SAM3TRT_UnitTest: could not open video file\n";
return -1;
}
while (true) {
cv::Mat frame;
if (!capture.read(frame)) {
std::cout << "\nEnd of video.\n";
break;
}
auto start = std::chrono::system_clock::now();
std::vector<ANSCENTER::Object> masks = infHandle.RunInference(frame);
auto end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
printf("Time = %lld ms\n", static_cast<long long int>(elapsed.count()));
for (size_t i = 0; i < masks.size(); i++) {
cv::rectangle(frame, masks[i].box, 123, 2);
}
cv::imshow("SAM3 TensorRT Test", frame);
if (cv::waitKey(30) == 27) break;
}
capture.release();
cv::destroyAllWindows();
infHandle.Destroy();
std::cout << "SAM3TRT_UnitTest: done.\n";
return 0;
}
int SAM3TRT_ImageTest()
{
std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_SAM_v3.0.zip";
std::string modelFolder = "C:\\Projects\\ANSVIS\\Models\\ANS_SAM_v3.0";
std::string imageFile = "C:\\Projects\\Research\\sam3onnx\\sam3-onnx\\images\\dog.jpg";
ANSCENTER::ANSSAM3 infHandle;
ANSCENTER::ModelConfig modelConfig;
modelConfig.modelConfThreshold = 0.5f;
std::string labelmap;
std::string licenseKey = "";
std::string modelZipFilePassword = "";
if (!infHandle.Initialize(licenseKey, modelConfig, modelFilePath, modelZipFilePassword, labelmap)) {
std::cerr << "SAM3TRT_ImageTest: LoadModelFromFolder failed\n";
return -1;
}
infHandle.SetPrompt("dog");
cv::Mat image = cv::imread(imageFile);
if (image.empty()) {
std::cerr << "SAM3TRT_ImageTest: could not read image: " << imageFile << "\n";
return -1;
}
const int NUM_RUNS = 5;
for (int run = 0; run < NUM_RUNS; run++) {
auto start = std::chrono::system_clock::now();
std::vector<ANSCENTER::Object> results = infHandle.RunInference(image);
auto end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "SAM3TRT_ImageTest run " << (run + 1) << "/" << NUM_RUNS
<< ": " << results.size() << " detections in "
<< elapsed.count() << " ms\n";
if (run == NUM_RUNS - 1) {
for (size_t i = 0; i < results.size(); i++) {
const auto& obj = results[i];
std::cout << " [" << i << "] box=" << obj.box
<< " conf=" << obj.confidence
<< " polygon=" << obj.polygon.size() << " pts\n";
// Draw bounding box
cv::Scalar boxColor(0, 255, 0);
cv::rectangle(image, obj.box, boxColor, 2);
// Draw label
std::string label = obj.className + " " + std::to_string(obj.confidence).substr(0, 4);
int baseline = 0;
cv::Size textSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseline);
cv::rectangle(image,
cv::Point(obj.box.x, obj.box.y - textSize.height - 4),
cv::Point(obj.box.x + textSize.width, obj.box.y),
boxColor, cv::FILLED);
cv::putText(image, label, cv::Point(obj.box.x, obj.box.y - 2),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0), 1, cv::LINE_AA);
// Draw polygon (normalized coordinates)
if (obj.polygon.size() >= 3) {
std::vector<cv::Point> polyPts;
polyPts.reserve(obj.polygon.size());
for (const auto& pt : obj.polygon) {
polyPts.emplace_back(
static_cast<int>(pt.x * image.cols),
static_cast<int>(pt.y * image.rows));
}
cv::Mat overlay = image.clone();
std::vector<std::vector<cv::Point>> polys = { polyPts };
cv::Scalar polyColor((i * 67 + 50) % 256, (i * 123 + 100) % 256, (i * 37 + 150) % 256);
cv::fillPoly(overlay, polys, polyColor);
cv::addWeighted(overlay, 0.4, image, 0.6, 0, image);
cv::polylines(image, polys, true, polyColor, 2, cv::LINE_AA);
}
// Mask overlay fallback
else if (!obj.mask.empty()) {
cv::Mat colorMask(obj.mask.size(), CV_8UC3,
cv::Scalar((i * 67 + 50) % 256, (i * 123 + 100) % 256, (i * 37 + 150) % 256));
cv::Mat roiImg = image(obj.box);
cv::Mat maskBool;
if (obj.mask.type() != CV_8UC1)
obj.mask.convertTo(maskBool, CV_8UC1, 255.0);
else
maskBool = obj.mask;
colorMask.copyTo(roiImg, maskBool);
cv::addWeighted(roiImg, 0.4, image(obj.box), 0.6, 0, image(obj.box));
}
}
}
}
cv::imshow("SAM3 TRT Image Test", image);
cv::waitKey(0);
cv::destroyAllWindows();
infHandle.Destroy();
std::cout << "SAM3TRT_ImageTest: done.\n";
return 0;
}

View File

@@ -0,0 +1,49 @@
# ANSODEngine Unit Test
add_executable(ANSODEngine-UnitTest
ANSODEngine-UnitTest.cpp
ANSODTest.cpp
ANSODTest.h
ANSSAM3-UnitTest.cpp
CustomModel-StressTest.cpp
yolov10.h
Yolov10OV.h
Yolov10RT.h
)
target_include_directories(ANSODEngine-UnitTest PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/modules/ANSODEngine
${CMAKE_SOURCE_DIR}/modules/ANSODEngine/CUDA
${CMAKE_SOURCE_DIR}/modules/ANSLPR
${CMAKE_SOURCE_DIR}/modules/ANSLPR/include
${CMAKE_SOURCE_DIR}/modules/ANSOCR/ANSPaddleOCR
${CMAKE_SOURCE_DIR}/modules/ANSOCR/ANSPaddleOCR/include
${CMAKE_SOURCE_DIR}/modules/ANSMOT
${CMAKE_SOURCE_DIR}/engines/ONNXEngine
${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/include
${CMAKE_SOURCE_DIR}/engines/TensorRTAPI/include
${ANSLIBS_DIR}/OpenVINO/samples/cpp/common
${SHARED_INCLUDE_DIR}
${ANSLIBS_DIR}/pybind11/include
${ANSLIBS_DIR}/Python311/include
)
target_link_libraries(ANSODEngine-UnitTest
PRIVATE ANSODEngine
PRIVATE ANSLicensingSystem
PRIVATE ANSLPR
PRIVATE ANSMOT
PRIVATE opencv
PRIVATE onnxruntime
PRIVATE openvino
PRIVATE tensorrt
PRIVATE boost
PRIVATE python311
PRIVATE CUDA::cudart
)
if(WIN32)
target_link_libraries(ANSODEngine-UnitTest PRIVATE ${WIN_COMMON_LIBS})
endif()
target_compile_definitions(ANSODEngine-UnitTest PRIVATE UNICODE _UNICODE)

View File

@@ -0,0 +1,551 @@
// =============================================================================
// CustomModel-StressTest.cpp
//
// Multi-task stress test using ANSODEngine's extern "C" API functions
// (same path as LabVIEW). Uses FilePlayer + CloneImage + RunInferenceComplete_CPP
// to reproduce the full LabVIEW production flow for custom model DLLs.
//
// This test loads ANSCV.dll at runtime via LoadLibrary/GetProcAddress
// so it does NOT require linking ANSCV.lib.
// =============================================================================
// windows.h MUST come before ANSODTest.h to avoid ACCESS_MASK conflict with TensorRT
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "ANSODTest.h"
#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
#include <deque>
#include <set>
// Note: NOT linking cudart.lib — use GetProcAddress for CUDA if needed
// --- Forward declarations of ANSODEngine extern "C" functions ---
// These are linked via ANSODEngine.lib
extern "C" __declspec(dllimport) std::string CreateANSODHandle(
ANSCENTER::ANSODBase** Handle,
const char* licenseKey, const char* modelFilePath,
const char* modelFileZipPassword,
float detectionScoreThreshold, float modelConfThreshold, float modelMNSThreshold,
int autoDetectEngine, int modelType, int detectionType, int loadEngineOnCreation);
extern "C" __declspec(dllimport) int RunInferenceComplete_CPP(
ANSCENTER::ANSODBase** Handle, cv::Mat** cvImage, const char* cameraId,
const char* activeROIMode, std::vector<ANSCENTER::Object>& detectionResult);
extern "C" __declspec(dllimport) int ReleaseANSODHandle(ANSCENTER::ANSODBase** Handle);
// --- ANSCV function pointer types (loaded at runtime) ---
typedef int (*FnCreateFilePlayer)(void** Handle, const char* licenseKey, const char* url);
typedef int (*FnStartFilePlayer)(void** Handle);
typedef int (*FnStopFilePlayer)(void** Handle);
typedef int (*FnGetFilePlayerCVImage)(void** Handle, int& w, int& h, int64_t& pts, cv::Mat** image);
typedef void(*FnSetFilePlayerDisplayRes)(void** Handle, int w, int h);
typedef int (*FnReleaseFilePlayer)(void** Handle);
typedef int (*FnCloneImage)(cv::Mat** imageIn, cv::Mat** imageOut);
typedef int (*FnReleaseImage)(cv::Mat** imageIn);
typedef void(*FnInitCameraNetwork)();
typedef void(*FnDeinitCameraNetwork)();
// --- ANSCV function pointers ---
static FnCreateFilePlayer pCreateFilePlayer = nullptr;
static FnStartFilePlayer pStartFilePlayer = nullptr;
static FnStopFilePlayer pStopFilePlayer = nullptr;
static FnGetFilePlayerCVImage pGetFilePlayerCVImage = nullptr;
static FnSetFilePlayerDisplayRes pSetFilePlayerDisplayRes = nullptr;
static FnReleaseFilePlayer pReleaseFilePlayer = nullptr;
static FnCloneImage pCloneImage = nullptr;
static FnReleaseImage pReleaseImage = nullptr;
static FnInitCameraNetwork pInitCameraNetwork = nullptr;
static FnDeinitCameraNetwork pDeinitCameraNetwork = nullptr;
static HMODULE g_hANSCV = nullptr;
static bool LoadANSCV() {
g_hANSCV = LoadLibraryA("ANSCV.dll");
if (!g_hANSCV) {
printf("ERROR: Failed to load ANSCV.dll (error %lu)\n", GetLastError());
return false;
}
pCreateFilePlayer = (FnCreateFilePlayer)GetProcAddress(g_hANSCV, "CreateANSFilePlayerHandle");
pStartFilePlayer = (FnStartFilePlayer)GetProcAddress(g_hANSCV, "StartFilePlayer");
pStopFilePlayer = (FnStopFilePlayer)GetProcAddress(g_hANSCV, "StopFilePlayer");
pGetFilePlayerCVImage = (FnGetFilePlayerCVImage)GetProcAddress(g_hANSCV, "GetFilePlayerCVImage");
pSetFilePlayerDisplayRes = (FnSetFilePlayerDisplayRes)GetProcAddress(g_hANSCV, "SetFilePlayerDisplayResolution");
pReleaseFilePlayer = (FnReleaseFilePlayer)GetProcAddress(g_hANSCV, "ReleaseANSFilePlayerHandle");
pCloneImage = (FnCloneImage)GetProcAddress(g_hANSCV, "ANSCV_CloneImage_S");
pReleaseImage = (FnReleaseImage)GetProcAddress(g_hANSCV, "ANSCV_ReleaseImage_S");
pInitCameraNetwork = (FnInitCameraNetwork)GetProcAddress(g_hANSCV, "InitCameraNetwork");
pDeinitCameraNetwork = (FnDeinitCameraNetwork)GetProcAddress(g_hANSCV, "DeinitCameraNetwork");
if (!pCreateFilePlayer || !pStartFilePlayer || !pStopFilePlayer ||
!pGetFilePlayerCVImage || !pReleaseFilePlayer ||
!pCloneImage || !pReleaseImage) {
printf("ERROR: Failed to resolve one or more ANSCV functions\n");
FreeLibrary(g_hANSCV);
g_hANSCV = nullptr;
return false;
}
printf("ANSCV.dll loaded successfully\n");
return true;
}
static void UnloadANSCV() {
if (g_hANSCV) {
FreeLibrary(g_hANSCV);
g_hANSCV = nullptr;
}
}
// --- Shared state ---
static std::atomic<bool> g_stressRunning{true};
struct StressTaskState {
std::mutex mtx;
cv::Mat displayFrame;
double fps = 0;
double inferenceMs = 0;
double grabMs = 0;
int frameCount = 0;
int detectionCount = 0;
int gpuDeviceId = -1;
size_t vramUsedMiB = 0;
std::string statusMsg = "Initializing";
std::string lastDetection;
bool engineLoaded = false;
};
// --- GPU VRAM helpers (via cudart.dll at runtime) ---
typedef int (*FnCudaGetDeviceCount)(int*);
typedef int (*FnCudaSetDevice)(int);
typedef int (*FnCudaMemGetInfo)(size_t*, size_t*);
static std::vector<size_t> GetPerGpuFreeMiB() {
static HMODULE hCudart = LoadLibraryA("cudart64_12.dll");
if (!hCudart) hCudart = LoadLibraryA("cudart64_110.dll");
if (!hCudart) return {};
auto fnGetCount = (FnCudaGetDeviceCount)GetProcAddress(hCudart, "cudaGetDeviceCount");
auto fnSetDev = (FnCudaSetDevice)GetProcAddress(hCudart, "cudaSetDevice");
auto fnMemInfo = (FnCudaMemGetInfo)GetProcAddress(hCudart, "cudaMemGetInfo");
if (!fnGetCount || !fnSetDev || !fnMemInfo) return {};
int count = 0;
fnGetCount(&count);
std::vector<size_t> result(count, 0);
for (int i = 0; i < count; i++) {
fnSetDev(i);
size_t freeMem = 0, totalMem = 0;
fnMemInfo(&freeMem, &totalMem);
result[i] = freeMem / (1024 * 1024);
}
return result;
}
// --- Worker thread ---
// Mimics LabVIEW flow: GetImage → CloneImage → RunInferenceComplete_CPP → ReleaseImage
static void ODWorkerThread(int taskId,
void* fpClient,
ANSCENTER::ANSODBase* odHandle,
StressTaskState& state) {
char tag[32];
snprintf(tag, sizeof(tag), "[Task%d]", taskId);
printf("%s Worker thread started\n", tag);
int width = 0, height = 0;
int64_t pts = 0;
int emptyFrames = 0;
std::string cameraId = "StressCam" + std::to_string(taskId);
std::deque<std::chrono::steady_clock::time_point> fpsTimestamps;
while (g_stressRunning.load()) {
// --- Step 1: Get image from FilePlayer (like camera process) ---
auto grabStart = std::chrono::steady_clock::now();
cv::Mat* framePtr = nullptr;
pGetFilePlayerCVImage(&fpClient, width, height, pts, &framePtr);
auto grabEnd = std::chrono::steady_clock::now();
double grabMs = std::chrono::duration<double, std::milli>(grabEnd - grabStart).count();
if (!framePtr || framePtr->empty()) {
emptyFrames++;
if (emptyFrames > 500) {
printf("%s Too many empty frames (%d), stopping\n", tag, emptyFrames);
break;
}
if (framePtr) { pReleaseImage(&framePtr); }
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
emptyFrames = 0;
// --- Step 2: Clone image (like LabVIEW consumer) ---
cv::Mat* clonedImage = nullptr;
int cloneResult = pCloneImage(&framePtr, &clonedImage);
if (cloneResult != 1 || !clonedImage) {
printf("%s CloneImage failed (result=%d)\n", tag, cloneResult);
pReleaseImage(&framePtr);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
// Release original frame (camera process would do this)
pReleaseImage(&framePtr);
// --- Step 3: Run inference on clone (like AI task) ---
auto infStart = std::chrono::steady_clock::now();
std::vector<ANSCENTER::Object> detections;
int infResult = RunInferenceComplete_CPP(&odHandle, &clonedImage, cameraId.c_str(), "", detections);
auto infEnd = std::chrono::steady_clock::now();
double infMs = std::chrono::duration<double, std::milli>(infEnd - infStart).count();
// --- Step 4: Draw results on clone for display ---
cv::Mat display;
if (clonedImage && !clonedImage->empty()) {
display = clonedImage->clone();
}
std::string lastDet;
int detCount = 0;
if (infResult > 0) {
for (const auto& obj : detections) {
if (!display.empty()) {
cv::rectangle(display, obj.box, cv::Scalar(0, 255, 0), 2);
std::string label = obj.className + " " +
std::to_string((int)(obj.confidence * 100)) + "%";
cv::putText(display, label,
cv::Point(obj.box.x, obj.box.y - 5),
cv::FONT_HERSHEY_SIMPLEX, 0.5,
cv::Scalar(0, 255, 0), 1);
}
lastDet = obj.className;
detCount++;
}
}
// --- Step 5: Release clone (like LabVIEW task cleanup) ---
pReleaseImage(&clonedImage);
// --- FPS calculation ---
auto now = std::chrono::steady_clock::now();
fpsTimestamps.push_back(now);
while (!fpsTimestamps.empty() &&
std::chrono::duration<double>(now - fpsTimestamps.front()).count() > 2.0) {
fpsTimestamps.pop_front();
}
double fps = fpsTimestamps.size() / 2.0;
// --- Update state ---
{
std::lock_guard<std::mutex> lk(state.mtx);
if (!display.empty()) state.displayFrame = display;
state.fps = fps;
state.inferenceMs = infMs;
state.grabMs = grabMs;
state.frameCount++;
state.detectionCount += detCount;
if (!lastDet.empty()) state.lastDetection = lastDet;
}
// Periodic log
if ((state.frameCount % 200) == 0) {
printf("%s %d frames | %.1f FPS | Inf: %.0f ms | Det: %d\n",
tag, state.frameCount, fps, infMs, state.detectionCount);
}
}
printf("%s Worker thread finished (%d frames)\n", tag, state.frameCount);
}
// =============================================================================
// Main test function
//
// Config (edit these):
// NUM_STREAMS — number of FilePlayer instances (cameras)
// NUM_TASKS — number of AI tasks
// videoFiles[] — paths to video files
// modelFolder — path to custom model folder
// modelType — engine type (31=RTYOLO, 30=ONNXYOLO, 10=CustomDetector, etc.)
// =============================================================================
int CustomModel_StressTest_FilePlayer() {
printf("\n");
printf("============================================================\n");
printf(" Custom Model Multi-Task Stress Test (FilePlayer)\n");
printf(" Uses RunInferenceComplete_CPP (same path as LabVIEW)\n");
printf(" Press ESC to stop\n");
printf("============================================================\n\n");
// --- Load ANSCV.dll at runtime ---
if (!LoadANSCV()) return -1;
if (pInitCameraNetwork) pInitCameraNetwork();
// =====================================================================
// CONFIGURATION — EDIT THESE FOR YOUR TEST
// =====================================================================
const int NUM_STREAMS = 2;
const int NUM_TASKS = 4; // 2 tasks per camera
// Video files (one per stream)
const std::string videoFiles[NUM_STREAMS] = {
"E:\\Programs\\DemoAssets\\Videos\\Helmet\\HM1.mp4",
"E:\\Programs\\DemoAssets\\Videos\\Helmet\\HM2.mp4",
};
// Which stream each task uses
const int taskStreamMap[NUM_TASKS] = { 0, 0, 1, 1 };
// Model config — EDIT for your custom model
const std::string modelFolder = "C:\\Projects\\ANSVIS\\Models\\ANS_Helmet_v2.0.zip";
//const char* modelName = "detector";
//const char* className = "detector.names";
const int modelType = 16; // 16 = CustomDetector, 31 = RTYOLO, 30 = ONNXYOLO
const float scoreThresh = 0.5f;
const float confThresh = 0.5f;
const float nmsThresh = 0.45f;
// =====================================================================
int detectorType = 1; // Detection
std::cout << "\n--- Test 1: Handle creation (elastic mode) ---\n" << std::endl;
std::cout << "Optimizing model, please wait..." << std::endl;
std::string optimizedFolder = OptimizeModelStr(
modelFolder.c_str(), "",
modelType, detectorType, 1);
std::cout << "Optimized model folder: " << optimizedFolder << std::endl;
StressTaskState taskStates[NUM_TASKS];
// --- Create FilePlayer instances ---
void* fpClients[NUM_STREAMS] = {};
for (int s = 0; s < NUM_STREAMS; s++) {
printf("[Stream%d] Creating FilePlayer: %s\n", s, videoFiles[s].c_str());
int result = pCreateFilePlayer(&fpClients[s], "", videoFiles[s].c_str());
if (result != 1 || !fpClients[s]) {
printf("[Stream%d] FAILED to create FilePlayer (result=%d)\n", s, result);
fpClients[s] = nullptr;
continue;
}
if (pSetFilePlayerDisplayRes) {
pSetFilePlayerDisplayRes(&fpClients[s], 1920, 1080);
}
printf("[Stream%d] FilePlayer created (display: 1920x1080)\n", s);
}
// --- Create OD engine handles sequentially ---
ANSCENTER::ANSODBase* odHandles[NUM_TASKS] = {};
for (int i = 0; i < NUM_TASKS; i++) {
char tag[32];
snprintf(tag, sizeof(tag), "[Task%d]", i);
int streamIdx = taskStreamMap[i];
if (!fpClients[streamIdx]) {
printf("%s Skipped — Stream%d not available\n", tag, streamIdx);
std::lock_guard<std::mutex> lk(taskStates[i].mtx);
taskStates[i].statusMsg = "Stream not available";
continue;
}
{
std::lock_guard<std::mutex> lk(taskStates[i].mtx);
taskStates[i].statusMsg = "Loading model...";
}
printf("%s Creating OD handle (modelType=%d)...\n", tag, modelType);
auto loadStart = std::chrono::steady_clock::now();
auto vramBefore = GetPerGpuFreeMiB();
// Use CreateANSODHandle — same API as VideoDetectorEngine and LabVIEW
std::string labelMap = CreateANSODHandle(
&odHandles[i],
"", // licenseKey
modelFolder.c_str(),// modelFilePath (zip or folder)
"", // modelZipFilePassword
scoreThresh, // detectionScoreThreshold
confThresh, // modelConfThreshold
nmsThresh, // modelMNSThreshold
1, // autoDetectEngine
modelType, // modelType (16=custom, 31=RTYOLO, etc.)
1, // detectionType (1=Detection)
1); // loadEngineOnCreation
auto loadEnd = std::chrono::steady_clock::now();
double loadMs = std::chrono::duration<double, std::milli>(loadEnd - loadStart).count();
if (!odHandles[i]) {
printf("%s FAILED to create OD handle\n", tag);
std::lock_guard<std::mutex> lk(taskStates[i].mtx);
taskStates[i].statusMsg = "Model load failed";
continue;
}
auto vramAfter = GetPerGpuFreeMiB();
int bestGpu = 0;
size_t maxDelta = 0;
for (size_t g = 0; g < vramBefore.size() && g < vramAfter.size(); g++) {
size_t delta = (vramBefore[g] > vramAfter[g]) ? vramBefore[g] - vramAfter[g] : 0;
if (delta > maxDelta) { maxDelta = delta; bestGpu = (int)g; }
}
printf("%s Model loaded in %.0f ms | GPU[%d] | VRAM: %zu MiB | Labels: %s\n",
tag, loadMs, bestGpu, maxDelta,
labelMap.empty() ? "(none)" : labelMap.substr(0, 80).c_str());
{
std::lock_guard<std::mutex> lk(taskStates[i].mtx);
taskStates[i].engineLoaded = true;
taskStates[i].statusMsg = "Running";
taskStates[i].gpuDeviceId = bestGpu;
taskStates[i].vramUsedMiB = maxDelta;
}
}
// --- Start video playback ---
for (int s = 0; s < NUM_STREAMS; s++) {
if (fpClients[s]) {
pStartFilePlayer(&fpClients[s]);
printf("[Stream%d] Playback started\n", s);
}
}
// Give FilePlayer time to decode first frames
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// --- Launch worker threads ---
std::thread workers[NUM_TASKS];
for (int i = 0; i < NUM_TASKS; i++) {
int streamIdx = taskStreamMap[i];
if (fpClients[streamIdx] && odHandles[i]) {
workers[i] = std::thread(ODWorkerThread, i,
fpClients[streamIdx], odHandles[i],
std::ref(taskStates[i]));
}
}
// --- Display loop ---
const int cols = (NUM_TASKS <= 2) ? NUM_TASKS : 2;
const int rows = (NUM_TASKS + cols - 1) / cols;
const int cellW = 640, cellH = 480;
const char* windowName = "Custom Model Stress Test";
cv::namedWindow(windowName, cv::WINDOW_NORMAL);
cv::resizeWindow(windowName, cellW * cols, cellH * rows + 40);
auto testStart = std::chrono::steady_clock::now();
while (g_stressRunning.load()) {
cv::Mat canvas(cellH * rows + 40, cellW * cols, CV_8UC3, cv::Scalar(30, 30, 30));
for (int i = 0; i < NUM_TASKS; i++) {
int row = i / cols, col = i % cols;
cv::Rect roi(col * cellW, row * cellH, cellW, cellH);
cv::Mat cell;
double fps = 0, infMs = 0;
int fCount = 0, dCount = 0;
int gpuId = -1;
std::string statusMsg, lastDet;
bool engineLoaded = false;
{
std::lock_guard<std::mutex> lk(taskStates[i].mtx);
if (!taskStates[i].displayFrame.empty()) {
cv::resize(taskStates[i].displayFrame, cell, cv::Size(cellW, cellH));
}
fps = taskStates[i].fps;
infMs = taskStates[i].inferenceMs;
fCount = taskStates[i].frameCount;
dCount = taskStates[i].detectionCount;
gpuId = taskStates[i].gpuDeviceId;
statusMsg = taskStates[i].statusMsg;
lastDet = taskStates[i].lastDetection;
engineLoaded = taskStates[i].engineLoaded;
}
if (cell.empty()) {
cell = cv::Mat(cellH, cellW, CV_8UC3, cv::Scalar(40, 40, 40));
cv::putText(cell, "Task " + std::to_string(i) + ": " + statusMsg,
cv::Point(20, cellH / 2),
cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(100, 100, 255), 2);
}
// Status bar
cv::rectangle(cell, cv::Rect(0, cellH - 45, cellW, 45), cv::Scalar(0, 0, 0), cv::FILLED);
char bar1[256], bar2[128];
snprintf(bar1, sizeof(bar1), "T%d | %.1f FPS | %.0fms | Frames:%d | Det:%d",
i, fps, infMs, fCount, dCount);
snprintf(bar2, sizeof(bar2), "GPU[%d] | %s",
gpuId, lastDet.empty() ? "-" : lastDet.c_str());
cv::Scalar barColor = engineLoaded ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 100, 255);
cv::putText(cell, bar1, cv::Point(5, cellH - 25),
cv::FONT_HERSHEY_SIMPLEX, 0.45, barColor, 1);
cv::putText(cell, bar2, cv::Point(5, cellH - 5),
cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(0, 200, 255), 1);
cell.copyTo(canvas(roi));
}
// Bottom status bar
double elapsed = std::chrono::duration<double>(
std::chrono::steady_clock::now() - testStart).count();
double totalFps = 0;
for (int i = 0; i < NUM_TASKS; i++) totalFps += taskStates[i].fps;
char bottomBar[256];
snprintf(bottomBar, sizeof(bottomBar),
"Elapsed: %.0fs | Total: %.1f FPS | %d streams, %d tasks | Press ESC to stop",
elapsed, totalFps, NUM_STREAMS, NUM_TASKS);
cv::putText(canvas, bottomBar, cv::Point(10, cellH * rows + 25),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(200, 200, 200), 1);
cv::imshow(windowName, canvas);
int key = cv::waitKey(30);
if (key == 27) {
printf("\nESC pressed — stopping...\n");
g_stressRunning.store(false);
}
}
// --- Wait for workers ---
printf("Waiting for worker threads...\n");
for (int i = 0; i < NUM_TASKS; i++) {
if (workers[i].joinable()) workers[i].join();
}
// --- Final summary ---
double totalElapsed = std::chrono::duration<double>(
std::chrono::steady_clock::now() - testStart).count();
printf("\n============================================================\n");
printf(" FINAL SUMMARY (runtime: %.0fs)\n", totalElapsed);
printf("============================================================\n");
double totalFps = 0;
for (int i = 0; i < NUM_TASKS; i++) {
printf(" Task %d: GPU[%d] | %d frames | %d detections | %.1f FPS | Inf: %.0fms\n",
i, taskStates[i].gpuDeviceId,
taskStates[i].frameCount, taskStates[i].detectionCount,
taskStates[i].fps, taskStates[i].inferenceMs);
totalFps += taskStates[i].fps;
}
printf(" Total throughput: %.1f FPS across %d tasks\n", totalFps, NUM_TASKS);
printf("============================================================\n");
// --- Release ---
for (int i = 0; i < NUM_TASKS; i++) {
if (odHandles[i]) ReleaseANSODHandle(&odHandles[i]);
}
for (int s = 0; s < NUM_STREAMS; s++) {
if (fpClients[s]) {
pStopFilePlayer(&fpClients[s]);
pReleaseFilePlayer(&fpClients[s]);
}
}
cv::destroyAllWindows();
if (pDeinitCameraNetwork) pDeinitCameraNetwork();
UnloadANSCV();
return 0;
}

View File

@@ -0,0 +1,189 @@
#pragma once
#pragma once
/// <summary>
/// https://www.cnblogs.com/guojin-blogs/p/18284497
/// wget https://github.com/jameslahm/yolov10/releases/download/v1.0/yolov10s.pt
// yolo export model = yolov10s.pt format = onnx opset = 13 simplify
/// </summary>
#include "opencv2/opencv.hpp"
#include <openvino/op/transpose.hpp>
#include <openvino/core/node.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <models/detection_model_ssd.h>
namespace Yolov10OV {
struct DetResult {
cv::Rect bbox;
float conf;
int lable;
DetResult(cv::Rect bbox, float conf, int lable) :bbox(bbox), conf(conf), lable(lable) {}
};
void pre_process(cv::Mat* img, int length, float* factor, std::vector<float>& data) {
cv::Mat mat;
int rh = img->rows;
int rw = img->cols;
int rc = img->channels();
cv::cvtColor(*img, mat, cv::COLOR_BGR2RGB);
int max_image_length = rw > rh ? rw : rh;
cv::Mat max_image = cv::Mat::zeros(max_image_length, max_image_length, CV_8UC3);
max_image = max_image * 255;
cv::Rect roi(0, 0, rw, rh);
mat.copyTo(cv::Mat(max_image, roi));
cv::Mat resize_img;
cv::resize(max_image, resize_img, cv::Size(length, length), 0.0f, 0.0f, cv::INTER_LINEAR);
*factor = (float)((float)max_image_length / (float)length);
resize_img.convertTo(resize_img, CV_32FC3, 1 / 255.0);
rh = resize_img.rows;
rw = resize_img.cols;
rc = resize_img.channels();
for (int i = 0; i < rc; ++i) {
cv::extractChannel(resize_img, cv::Mat(rh, rw, CV_32FC1, data.data() + i * rh * rw), i);
}
}
std::vector<DetResult> post_process(float* result, float factor, int outputLength) {
std::vector<cv::Rect> position_boxes;
std::vector <int> class_ids;
std::vector <float> confidences;
// Preprocessing output results
for (int i = 0; i < outputLength; i++)
{
int s = 6 * i;
if ((float)result[s + 4] > 0.2)
{
float cx = result[s + 0];
float cy = result[s + 1];
float dx = result[s + 2];
float dy = result[s + 3];
int x = (int)((cx)*factor);
int y = (int)((cy)*factor);
int width = (int)((dx - cx) * factor);
int height = (int)((dy - cy) * factor);
cv::Rect box(x, y, width, height);
position_boxes.push_back(box);
class_ids.push_back((int)result[s + 5]);
confidences.push_back((float)result[s + 4]);
}
}
std::vector<DetResult> re;
for (int i = 0; i < position_boxes.size(); i++)
{
DetResult det(position_boxes[i], confidences[i], class_ids[i]);
re.push_back(det);
}
return re;
}
void draw_bbox(cv::Mat& img, std::vector<DetResult>& res) {
for (size_t j = 0; j < res.size(); j++) {
cv::rectangle(img, res[j].bbox, cv::Scalar(255, 0, 255), 2);
cv::putText(img, std::to_string(res[j].lable) + "-" + std::to_string(res[j].conf),
cv::Point(res[j].bbox.x, res[j].bbox.y - 1), cv::FONT_HERSHEY_PLAIN,
1.2, cv::Scalar(0, 0, 255), 2);
}
}
void yolov10_infer_without_process() {
std::string videoPath = "E:\\Text_dataset\\car_test.mov";
std::string model_path = "E:\\Text_Model\\yolov10s_openvino_model\\yolov10s.xml";
ov::Core core;
auto model = core.read_model(model_path);
auto compiled_model = core.compile_model(model, "CPU");
ov::InferRequest request = compiled_model.create_infer_request();
cv::VideoCapture capture(videoPath);
if (!capture.isOpened()) {
std::cerr << "ERROR: " << std::endl;
return;
}
float factor = 0;
request.get_input_tensor().set_shape(std::vector<size_t>{1, 3, 640, 640});
std::vector<float> inputData(640 * 640 * 3);
std::chrono::time_point<std::chrono::steady_clock> t_beg;
std::chrono::time_point<std::chrono::steady_clock> t_end;
while (true)
{
cv::Mat frame;
if (!capture.read(frame)) {
break;
}
t_beg = std::chrono::high_resolution_clock::now();
pre_process(&frame, 640, &factor, inputData);
memcpy(request.get_input_tensor().data<float>(), inputData.data(), 640 * 640 * 3);
request.infer();
float* output_data = request.get_output_tensor().data<float>();
std::vector<DetResult> result = post_process(output_data, factor, 300);
t_end = std::chrono::high_resolution_clock::now();
cv::putText(frame, "FPS: " + std::to_string(1000.0 / std::chrono::duration<float, std::milli>(t_end - t_beg).count())
+ ", Time: " + std::to_string(std::chrono::duration<float, std::milli>(t_end - t_beg).count()) + "ms",
cv::Point(20, 40), 1, 2, cv::Scalar(255, 0, 255), 2);
draw_bbox(frame, result);
imshow("Frame", frame);
cv::waitKey(1); //30
}
cv::destroyAllWindows();
return;
}
void yolov10_infer_ansy_without_process() {
std::string videoPath = "E:\\Text_dataset\\car_test.mov";
std::string model_path = "E:\\Text_Model\\yolov10s_openvino_model\\yolov10s.xml";
ov::Core core;
auto model = core.read_model(model_path);
auto compiled_model = core.compile_model(model, "CPU");
std::vector<ov::InferRequest>requests = { compiled_model.create_infer_request(), compiled_model.create_infer_request() };
cv::VideoCapture capture(videoPath);
if (!capture.isOpened()) {
std::cerr << "ERROR:" << std::endl;
return;
}
float factor = 0;
requests[0].get_input_tensor().set_shape(std::vector<size_t>{1, 3, 640, 640});
requests[1].get_input_tensor().set_shape(std::vector<size_t>{1, 3, 640, 640});
cv::Mat frame;
capture.read(frame);
std::vector<float> inputData(640 * 640 * 3);
pre_process(&frame, 640, &factor, inputData);
memcpy(requests[0].get_input_tensor().data<float>(), inputData.data(), 640 * 640 * 3);
requests[0].start_async();
std::chrono::time_point<std::chrono::steady_clock> t_beg;
std::chrono::time_point<std::chrono::steady_clock> t_end;
while (true)
{
cv::Mat next_frame;
if (!capture.read(next_frame)) {
break;
}
t_beg = std::chrono::high_resolution_clock::now();
pre_process(&next_frame, 640, &factor, inputData);
memcpy(requests[1].get_input_tensor().data<float>(), inputData.data(), 640 * 640 * 3);
requests[1].start_async();
requests[0].wait();
float* output_data = requests[0].get_output_tensor().data<float>();
std::vector<DetResult> result = post_process(output_data, factor, 300);
t_end = std::chrono::high_resolution_clock::now();
draw_bbox(frame, result);
cv::putText(frame, "FPS: " + std::to_string(1000.0 / std::chrono::duration<float, std::milli>(t_end - t_beg).count())
+ ", Time: " + std::to_string(std::chrono::duration<float, std::milli>(t_end - t_beg).count()) + "ms",
cv::Point(20, 40), 1, 2, cv::Scalar(255, 0, 255), 2);
imshow("Frame", frame);
cv::waitKey(1); //30
frame = next_frame;
std::swap(requests[0], requests[1]);
}
cv::destroyAllWindows();
return;
}
}

View File

@@ -0,0 +1,229 @@
#pragma once
/// <summary>
/// //https://www.cnblogs.com/guojin-blogs/p/18258877
/// wget https://github.com/jameslahm/yolov10/releases/download/v1.0/yolov10s.pt
// yolo export model = yolov10s.pt format = onnx opset = 13 simplify
/// </summary>
#include "opencv2/opencv.hpp"
#include <fstream>
#include <iostream>
#include "cuda.h"
#include "NvInfer.h"
#include "NvOnnxParser.h"
namespace Yolov10RT {
class Logger : public nvinfer1::ILogger
{
void log(Severity severity, const char* msg) noexcept override
{
if (severity <= Severity::kWARNING)
std::cout << msg << std::endl;
}
} logger;
struct DetResult {
cv::Rect bbox;
float conf;
int lable;
DetResult(cv::Rect bbox, float conf, int lable) :bbox(bbox), conf(conf), lable(lable) {}
};
void onnxToEngine(const char* onnxFile, int memorySize) {
std::string path(onnxFile);
std::string::size_type iPos = (path.find_last_of('\\') + 1) == 0 ? path.find_last_of('/') + 1 : path.find_last_of('\\') + 1;
std::string modelPath = path.substr(0, iPos);//
std::string modelName = path.substr(iPos, path.length() - iPos);//
std::string modelName_ = modelName.substr(0, modelName.rfind("."));//
std::string engineFile = modelPath + modelName_ + ".engine";
nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(logger);
#if NV_TENSORRT_MAJOR >= 10
nvinfer1::INetworkDefinition* network = builder->createNetworkV2(0);
#else
const auto explicitBatch = 1U << static_cast<uint32_t>(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH);
nvinfer1::INetworkDefinition* network = builder->createNetworkV2(explicitBatch);
#endif
nvonnxparser::IParser* parser = nvonnxparser::createParser(*network, logger);
parser->parseFromFile(onnxFile, 2);
for (int i = 0; i < parser->getNbErrors(); ++i) {
std::cout << "load error: " << parser->getError(i)->desc() << std::endl;
}
printf("tensorRT load mask onnx model successfully!!!...\n");
nvinfer1::IBuilderConfig* config = builder->createBuilderConfig();
#if NV_TENSORRT_MAJOR < 10
config->setMaxWorkspaceSize(1024 * 1024 * memorySize);
#else
config->setMemoryPoolLimit(nvinfer1::MemoryPoolType::kWORKSPACE, 1024ULL * 1024 * memorySize);
#endif
config->setFlag(nvinfer1::BuilderFlag::kFP16);
#if NV_TENSORRT_MAJOR >= 10
nvinfer1::IHostMemory* plan = builder->buildSerializedNetwork(*network, *config);
std::cout << "try to save engine file now~~~" << std::endl;
std::ofstream filePtr(engineFile, std::ios::binary);
if (!filePtr) {
std::cerr << "could not open plan output file" << std::endl;
return;
}
filePtr.write(reinterpret_cast<const char*>(plan->data()), plan->size());
delete plan;
delete network;
delete parser;
#else
nvinfer1::ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);
std::cout << "try to save engine file now~~~" << std::endl;
std::ofstream filePtr(engineFile, std::ios::binary);
if (!filePtr) {
std::cerr << "could not open plan output file" << std::endl;
return;
}
nvinfer1::IHostMemory* modelStream = engine->serialize();
filePtr.write(reinterpret_cast<const char*>(modelStream->data()), modelStream->size());
modelStream->destroy();
engine->destroy();
network->destroy();
parser->destroy();
#endif
std::cout << "convert onnx model to TensorRT engine model successfully!" << std::endl;
}
void preProcess(cv::Mat* img, int length, float* factor, std::vector<float>& data) {
cv::Mat mat;
int rh = img->rows;
int rw = img->cols;
int rc = img->channels();
cv::cvtColor(*img, mat, cv::COLOR_BGR2RGB);
int maxImageLength = rw > rh ? rw : rh;
cv::Mat maxImage = cv::Mat::zeros(maxImageLength, maxImageLength, CV_8UC3);
maxImage = maxImage * 255;
cv::Rect roi(0, 0, rw, rh);
mat.copyTo(cv::Mat(maxImage, roi));
cv::Mat resizeImg;
cv::resize(maxImage, resizeImg, cv::Size(length, length), 0.0f, 0.0f, cv::INTER_LINEAR);
*factor = (float)((float)maxImageLength / (float)length);
resizeImg.convertTo(resizeImg, CV_32FC3, 1 / 255.0);
rh = resizeImg.rows;
rw = resizeImg.cols;
rc = resizeImg.channels();
for (int i = 0; i < rc; ++i) {
cv::extractChannel(resizeImg, cv::Mat(rh, rw, CV_32FC1, data.data() + i * rh * rw), i);
}
}
std::vector<DetResult> postProcess(float* result, float factor, int outputLength) {
std::vector<cv::Rect> positionBoxes;
std::vector <int> classIds;
std::vector <float> confidences;
// Preprocessing output results
for (int i = 0; i < outputLength; i++)
{
int s = 6 * i;
if ((float)result[s + 4] > 0.2)
{
float cx = result[s + 0];
float cy = result[s + 1];
float dx = result[s + 2];
float dy = result[s + 3];
int x = (int)((cx)*factor);
int y = (int)((cy)*factor);
int width = (int)((dx - cx) * factor);
int height = (int)((dy - cy) * factor);
cv::Rect box(x, y, width, height);
positionBoxes.push_back(box);
classIds.push_back((int)result[s + 5]);
confidences.push_back((float)result[s + 4]);
}
}
std::vector<DetResult> re;
for (int i = 0; i < positionBoxes.size(); i++)
{
DetResult det(positionBoxes[i], confidences[i], classIds[i]);
re.push_back(det);
}
return re;
}
void drawBbox(cv::Mat& img, std::vector<DetResult>& res) {
for (size_t j = 0; j < res.size(); j++) {
cv::rectangle(img, res[j].bbox, cv::Scalar(255, 0, 255), 2);
cv::putText(img, std::to_string(res[j].lable) + "-" + std::to_string(res[j].conf),
cv::Point(res[j].bbox.x, res[j].bbox.y - 1), cv::FONT_HERSHEY_PLAIN,
1.2, cv::Scalar(0, 0, 255), 2);
}
}
std::shared_ptr<nvinfer1::IExecutionContext> creatContext(std::string modelPath) {
std::ifstream filePtr(modelPath, std::ios::binary);
if (!filePtr.good()) {
std::cerr << "Errror" << std::endl;
return std::shared_ptr<nvinfer1::IExecutionContext>();
}
size_t size = 0;
filePtr.seekg(0, filePtr.end); //
size = filePtr.tellg(); //
filePtr.seekg(0, filePtr.beg); //
char* modelStream = new char[size];
filePtr.read(modelStream, size);
filePtr.close();
nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger);
nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(modelStream, size);
return std::shared_ptr<nvinfer1::IExecutionContext>(engine->createExecutionContext());
}
void yolov10Infer() {
const char* videoPath = "E:\\Text_dataset\\car_test.mov";
const char* enginePath = "E:\\Text_Model\\yolov10s.engine";
std::shared_ptr<nvinfer1::IExecutionContext> context = creatContext(enginePath);
cv::VideoCapture capture(videoPath);
if (!capture.isOpened()) {
std::cerr << "ERROR:" << std::endl;
return;
}
cudaStream_t stream;
cudaStreamCreate(&stream);
void* inputSrcDevice;
void* outputSrcDevice;
cudaMalloc(&inputSrcDevice, 3 * 640 * 640 * sizeof(float));
cudaMalloc(&outputSrcDevice, 1 * 300 * 6 * sizeof(float));
std::vector<float> output_data(300 * 6);
std::vector<float> inputData(640 * 640 * 3);
while (true)
{
cv::Mat frame;
if (!capture.read(frame)) {
break;
}
float factor = 0;
preProcess(&frame, 640, &factor, inputData);
cudaMemcpyAsync(inputSrcDevice, inputData.data(), 3 * 640 * 640 * sizeof(float),
cudaMemcpyHostToDevice, stream);
#if NV_TENSORRT_MAJOR >= 10
context->setTensorAddress("images", inputSrcDevice);
context->setTensorAddress("output0", outputSrcDevice);
context->enqueueV3(stream);
#else
void* bindings[] = { inputSrcDevice, outputSrcDevice };
context->enqueueV2((void**)bindings, stream, nullptr);
#endif
cudaMemcpyAsync(output_data.data(), outputSrcDevice, 300 * 6 * sizeof(float),
cudaMemcpyDeviceToHost, stream);
cudaStreamSynchronize(stream);
std::vector<DetResult> result = postProcess(output_data.data(), factor, 300);
drawBbox(frame, result);
imshow("Frame", frame);
cv::waitKey(10);
}
cv::destroyAllWindows();
}
}

View File

@@ -0,0 +1,187 @@
#pragma once
#include <openvino/op/transpose.hpp>
#include <openvino/core/node.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <models/detection_model_ssd.h>
#include <random>
namespace Yolov10 {
struct YoloDetection {
short class_id;
float confidence;
cv::Rect box;
};
class Inference {
public:
Inference() {}
Inference(const std::string& model_path, const float& model_confidence_threshold);
Inference(const std::string& model_path, const cv::Size model_input_shape, const float& model_confidence_threshold);
std::vector<YoloDetection> RunInference(const cv::Mat& frame);
private:
void InitialModel(const std::string& model_path);
void Preprocessing(const cv::Mat& frame);
void PostProcessing();
cv::Rect GetBoundingBox(const cv::Rect& src) const;
std::vector<YoloDetection> detections_;
float model_confidence_threshold_;
cv::Mat resized_frame_;
cv::Point2f factor_;
cv::Size2f model_input_shape_;
cv::Size model_output_shape_;
std::string _modelFilePath;
ov::Tensor input_tensor_;
ov::InferRequest inference_request_;
ov::CompiledModel compiled_model_;
};
void DrawDetectedObject(cv::Mat& frame, const std::vector<YoloDetection>& detections, const std::vector<std::string>& class_names);
std::vector<std::string> GetClassNameFromMetadata(const std::string& metadata_path);
Inference::Inference(const std::string& model_path, const float& model_confidence_threshold) {
model_input_shape_ = cv::Size(640, 640); // Set the default size for models with dynamic shapes to prevent errors.
model_confidence_threshold_ = model_confidence_threshold;
_modelFilePath = model_path;
InitialModel(model_path);
}
// If the model has dynamic shapes, we need to set the input shape.
Inference::Inference(const std::string& model_path, const cv::Size model_input_shape, const float& model_confidence_threshold) {
model_input_shape_ = model_input_shape;
model_confidence_threshold_ = model_confidence_threshold;
_modelFilePath = model_path;
InitialModel(model_path);
}
void Inference::InitialModel(const std::string& model_path) {
ov::Core core;
std::shared_ptr<ov::Model> model = core.read_model(model_path);
if (model->is_dynamic()) {
model->reshape({ 1, 3, static_cast<long int>(model_input_shape_.height), static_cast<long int>(model_input_shape_.width) });
}
ov::preprocess::PrePostProcessor ppp = ov::preprocess::PrePostProcessor(model);
ppp.input().tensor().set_element_type(ov::element::u8).set_layout("NHWC").set_color_format(ov::preprocess::ColorFormat::BGR);
ppp.input().preprocess().convert_element_type(ov::element::f32).convert_color(ov::preprocess::ColorFormat::RGB).scale({ 255, 255, 255 });
ppp.input().model().set_layout("NCHW");
ppp.output().tensor().set_element_type(ov::element::f32);
model = ppp.build();
//compiled_model_ = core.compile_model(model, "AUTO:GPU,CPU");
//core.set_property("AUTO", ov::device::priorities("GPU,CPU"));
compiled_model_ = core.compile_model(model, "C");
std::vector<std::string> available_devices = core.get_available_devices();
auto num_requests = compiled_model_.get_property(ov::optimal_number_of_infer_requests);
inference_request_ = compiled_model_.create_infer_request();
const std::vector<ov::Output<ov::Node>> inputs = model->inputs();
const ov::Shape input_shape = inputs[0].get_shape();
short height = input_shape[1];
short width = input_shape[2];
model_input_shape_ = cv::Size2f(width, height);
const std::vector<ov::Output<ov::Node>> outputs = model->outputs();
const ov::Shape output_shape = outputs[0].get_shape();
height = output_shape[1];
width = output_shape[2];
model_output_shape_ = cv::Size(width, height);
}
std::vector<YoloDetection> Inference::RunInference(const cv::Mat& frame) {
Preprocessing(frame);
inference_request_.infer();
PostProcessing();
return detections_;
}
void Inference::Preprocessing(const cv::Mat& frame) {
cv::resize(frame, resized_frame_, model_input_shape_, 0, 0, cv::INTER_AREA);
factor_.x = static_cast<float>(frame.cols / model_input_shape_.width);
factor_.y = static_cast<float>(frame.rows / model_input_shape_.height);
float* input_data = (float*)resized_frame_.data;
input_tensor_ = ov::Tensor(compiled_model_.input().get_element_type(), compiled_model_.input().get_shape(), input_data);
inference_request_.set_input_tensor(input_tensor_);
}
void Inference::PostProcessing() {
const float* detections = inference_request_.get_output_tensor().data<const float>();
detections_.clear();
/*
* 0 1 2 3 4 5
* x, y, w. h, confidence, class_id
*/
for (unsigned int i = 0; i < model_output_shape_.height; ++i) {
const unsigned int index = i * model_output_shape_.width;
const float& confidence = detections[index + 4];
if (confidence > model_confidence_threshold_) {
const float& x = detections[index + 0];
const float& y = detections[index + 1];
const float& w = detections[index + 2];
const float& h = detections[index + 3];
YoloDetection result;
result.class_id = static_cast<const short>(detections[index + 5]);
if (result.class_id > 9) result.class_id = 9;
result.confidence = confidence;
result.box = GetBoundingBox(cv::Rect(x, y, w, h));
detections_.push_back(result);
}
}
}
void DrawDetectedObject(cv::Mat& frame, const std::vector<YoloDetection>& detections, const std::vector<std::string>& class_names) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(120, 255);
for (const auto& detection : detections) {
const cv::Rect& box = detection.box;
const float& confidence = detection.confidence;
const int& class_id = detection.class_id;
const cv::Scalar color = cv::Scalar(dis(gen), dis(gen), dis(gen));
cv::rectangle(frame, box, color, 3);
std::string class_string;
if (class_names.empty())
class_string = "id[" + std::to_string(class_id) + "] " + std::to_string(confidence).substr(0, 4);
else
class_string = class_names[class_id] + " " + std::to_string(confidence).substr(0, 4);
const cv::Size text_size = cv::getTextSize(class_string, cv::FONT_HERSHEY_SIMPLEX, 0.6, 2, 0);
const cv::Rect text_box(box.x - 2, box.y - 27, text_size.width + 10, text_size.height + 15);
cv::rectangle(frame, text_box, color, cv::FILLED);
cv::putText(frame, class_string, cv::Point(box.x + 5, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 0), 2, 0);
}
}
std::vector<std::string> GetClassNameFromMetadata(const std::string& metadata_path) {
std::vector<std::string> class_names;
class_names.push_back("person");
class_names.push_back("bicycle");
class_names.push_back("car");
class_names.push_back("motorcycle");
class_names.push_back("airplane");
class_names.push_back("bus");
class_names.push_back("train");
class_names.push_back("truck");
class_names.push_back("boat");
class_names.push_back("traffic light");
class_names.push_back("fire hydrant");
return class_names;
}
}