From 2392b6785bb952487bf74fb7347a644094463778 Mon Sep 17 00:00:00 2001 From: Tuan Nghia Nguyen Date: Sun, 29 Mar 2026 08:45:38 +1100 Subject: [PATCH] Add unit tests --- tests/ANSCV-UnitTest/ANSCV-UnitTest.cpp | 1471 +++++++++ tests/ANSCV-UnitTest/CMakeLists.txt | 41 + tests/ANSCV-UnitTest/OpenCVTest.cpp | 469 +++ tests/ANSFR-UnitTest/ANSFR-UnitTest.cpp | 1346 ++++++++ tests/ANSFR-UnitTest/CMakeLists.txt | 65 + tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp | 2780 +++++++++++++++++ tests/ANSLPR-UnitTest/CMakeLists.txt | 52 + tests/ANSOCR-UnitTest/ANSOCR-UnitTest.cpp | 404 +++ tests/ANSOCR-UnitTest/CMakeLists.txt | 23 + .../ANSODEngine-UnitTest.cpp | 1912 ++++++++++++ tests/ANSODEngine-UnitTest/ANSODTest.cpp | 2744 ++++++++++++++++ tests/ANSODEngine-UnitTest/ANSODTest.h | 119 + .../ANSODEngine-UnitTest/ANSSAM3-UnitTest.cpp | 154 + tests/ANSODEngine-UnitTest/CMakeLists.txt | 49 + .../CustomModel-StressTest.cpp | 551 ++++ tests/ANSODEngine-UnitTest/Yolov10OV.h | 189 ++ tests/ANSODEngine-UnitTest/Yolov10RT.h | 229 ++ tests/ANSODEngine-UnitTest/yolov10.h | 187 ++ tests/CMakeLists.txt | 6 +- 19 files changed, 12790 insertions(+), 1 deletion(-) create mode 100644 tests/ANSCV-UnitTest/ANSCV-UnitTest.cpp create mode 100644 tests/ANSCV-UnitTest/CMakeLists.txt create mode 100644 tests/ANSCV-UnitTest/OpenCVTest.cpp create mode 100644 tests/ANSFR-UnitTest/ANSFR-UnitTest.cpp create mode 100644 tests/ANSFR-UnitTest/CMakeLists.txt create mode 100644 tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp create mode 100644 tests/ANSLPR-UnitTest/CMakeLists.txt create mode 100644 tests/ANSOCR-UnitTest/ANSOCR-UnitTest.cpp create mode 100644 tests/ANSOCR-UnitTest/CMakeLists.txt create mode 100644 tests/ANSODEngine-UnitTest/ANSODEngine-UnitTest.cpp create mode 100644 tests/ANSODEngine-UnitTest/ANSODTest.cpp create mode 100644 tests/ANSODEngine-UnitTest/ANSODTest.h create mode 100644 tests/ANSODEngine-UnitTest/ANSSAM3-UnitTest.cpp create mode 100644 tests/ANSODEngine-UnitTest/CMakeLists.txt create mode 100644 tests/ANSODEngine-UnitTest/CustomModel-StressTest.cpp create mode 100644 tests/ANSODEngine-UnitTest/Yolov10OV.h create mode 100644 tests/ANSODEngine-UnitTest/Yolov10RT.h create mode 100644 tests/ANSODEngine-UnitTest/yolov10.h diff --git a/tests/ANSCV-UnitTest/ANSCV-UnitTest.cpp b/tests/ANSCV-UnitTest/ANSCV-UnitTest.cpp new file mode 100644 index 0000000..353da79 --- /dev/null +++ b/tests/ANSCV-UnitTest/ANSCV-UnitTest.cpp @@ -0,0 +1,1471 @@ +#define _CRTDBG_MAP_ALLOC +#include +#include "ANSRTSP.h" +#include "ANSFilePlayer.h" +#include "ANSVideoPlayer.h" +#include "ANSWEBCAM.h" +#include "ReadBarcode.h" +#include // Include this header for boundingRect +#include "ANSOpenCV.h" +#include +#include +#include +#include +#include +#include + +using namespace ANSCENTER; +using namespace cv; +using namespace std; +cv::Mat JpegStringToMat(const std::string& jpegStr) { + if (jpegStr.length() > 10) { + try { + // Convert the string to a vector of bytes + std::vector jpegData(jpegStr.begin(), jpegStr.end()); + // Decode the JPEG data into a cv::Mat + cv::Mat image = cv::imdecode(jpegData, cv::IMREAD_COLOR); + return image; + } + catch (std::exception& e) + { + cv::Mat emptyImage; + std::cout << "ANSGStreamerReader::JpegStringToMat. Error:" << e.what(); + return emptyImage; + } + catch (...) { + // Catch any other exceptions that were not caught by previous catch blocks + cv::Mat emptyImage; + std::cout << "ANSGStreamerReader::JpegStringToMat. Unknown error"; + return emptyImage; + } + } + else { + cv::Mat emptyImage; + return emptyImage; + } +} +int VideoTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSVIDEOPLAYER* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\SimFire.mp4"; + CreateANSVideoPlayerHandle(&filePlayerClient, "", testVideoFile.c_str()); + + StartVideoPlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + std::string jpegImage; + int index = 0; + while (true) { + index++; + GetVideoPlayerStrImage(&filePlayerClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + sleep(1); + continue; // Skip the rest of the loop if image is empty + } + cv::Mat image = JpegStringToMat(jpegImage); + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + StopVideoPlayer(&filePlayerClient); + ReleaseANSVideoPlayerHandle(&filePlayerClient); + return 0; + +} + +int FilePlayerTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\ANSFireFull.mp4"; + CreateANSFilePlayerHandle(&filePlayerClient, "", testVideoFile.c_str()); + + StartFilePlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + SetFilePlayerImageRotation(&filePlayerClient, 0);// Rotate 90 + std::string jpegImage; + int index = 0; + while (true) { + index++; + std::cout << "Index=" << index << std::endl; + if ((index == 20) || (index == 80) || (index == 120)) StopFilePlayer(&filePlayerClient); + if ((index == 40) || (index == 100) || (index == 150)) StartFilePlayer(&filePlayerClient); + // if (index > 200) break; + GetFilePlayerStrImage(&filePlayerClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + sleep(1); + continue; // Skip the rest of the loop if image is empty + } + cv::Mat image = JpegStringToMat(jpegImage); + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + //std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + StopFilePlayer(&filePlayerClient); + ReleaseANSFilePlayerHandle(&filePlayerClient); + return 0; + +} +int FilePlayerDoubleStartTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\Silversea\\PeopleCountCam.mp4"; + + // "C:\\Programs\\Documentation\\Video\\BM\\OriginalRes.mp4";// "C:\\Programs\\LPRVideo\\test_1.mp4"; + CreateANSFilePlayerHandle(&filePlayerClient, "", testVideoFile.c_str()); + StartFilePlayer(&filePlayerClient); + StopFilePlayer(&filePlayerClient); + StartFilePlayer(&filePlayerClient); + StopFilePlayer(&filePlayerClient); + ReleaseANSFilePlayerHandle(&filePlayerClient); + return 0; +} +int WebcamPlayerTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + std::vector cameraNames; + ANSWEBCAMPlayer* filePlayerClient; + std::string cameraName; + ScanStrANSWebcamPlayer(cameraNames); + if ((!cameraNames.empty()) && (cameraNames.size() > 0)) { + for (int i = 0; i < cameraNames.size(); i++) { + std::cout << "Camera name:" << cameraNames.at(i) << std::endl; + } + } + cameraName = "Integrated Camera";// "AIRHUG 02";"Intel Virtual Camera";// + + CreateANSWebcamPlayerHandle(&filePlayerClient, "", cameraName.c_str()); + SetWebcamImageRotation(&filePlayerClient, 0); + StartWebcamPlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + std::string jpegImage; + int index = 0; + while (true) { + std::cout << "Index=" << index << std::endl; + index++; + if ((index == 10) || (index == 80) || (index == 120)) StopWebcamPlayer(&filePlayerClient); //SetCropFlagFilePlayer(&filePlayerClient, 0);// + if ((index == 20) || (index == 100) || (index == 150)) StartWebcamPlayer(&filePlayerClient);//SetCropFlagFilePlayer(&filePlayerClient, 1); + if (index > 200) break; + GetWebcamStrImage(&filePlayerClient, width, height, pts, jpegImage); + cv::Mat image = JpegStringToMat(jpegImage); + if (jpegImage.empty()) { + continue; // Skip the rest of the loop if image is empty + } + /* + auto start = std::chrono::system_clock::now(); + StartWebcamPlayer(&filePlayerClient); + auto end1 = std::chrono::system_clock::now(); + + GetWebcamStrImage(&filePlayerClient, width, height, pts, jpegImage); + cv::Mat image = JpegStringToMat(jpegImage); + auto end2 = std::chrono::system_clock::now(); + + StopWebcamPlayer(&filePlayerClient); + auto end3 = std::chrono::system_clock::now(); + + auto elapsed1 = std::chrono::duration_cast(end1 - start); + std::cout << "Time to start camera:" << elapsed1.count() << "ms" << std::endl; + auto elapsed2 = std::chrono::duration_cast(end2 - end1); + std::cout << "Time to get image:" << elapsed2.count() << "ms" << std::endl; + auto elapsed3 = std::chrono::duration_cast(end3 - end2); + std::cout << "Time to stop camera:" << elapsed3.count() << "ms" << std::endl;*/ + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + // std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + StopWebcamPlayer(&filePlayerClient); + ReleaseANSWebcamPlayerHandle(&filePlayerClient); + return 0; + +} +int WebcamPlayerDoubleTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + std::vector cameraNames; + ANSWEBCAMPlayer* filePlayerClient; + std::string cameraName; + ScanStrANSWebcamPlayer(cameraNames); + if ((!cameraNames.empty()) && (cameraNames.size() > 0)) { + for (int i = 0; i < cameraNames.size(); i++) { + std::cout << "Camera name:" << cameraNames.at(i) << std::endl; + } + cameraName = cameraNames.at(0); + } + CreateANSWebcamPlayerHandle(&filePlayerClient, "", cameraName.c_str()); + StartWebcamPlayer(&filePlayerClient); + StopWebcamPlayer(&filePlayerClient); + StartWebcamPlayer(&filePlayerClient); + StopWebcamPlayer(&filePlayerClient); + StartWebcamPlayer(&filePlayerClient); + StartWebcamPlayer(&filePlayerClient); + StopWebcamPlayer(&filePlayerClient); + StopWebcamPlayer(&filePlayerClient); + + StartWebcamPlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + std::string jpegImage; + int index = 0; + while (true) { + index++; + if((index ==200)||(index==800)||(index==1200)) StopWebcamPlayer(&filePlayerClient); + if((index == 400)||(index==1000)||(index==1500)) StartWebcamPlayer(&filePlayerClient); + if (index > 2000) break; + GetWebcamStrImage(&filePlayerClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + continue; // Skip the rest of the loop if image is empty + } + cv::Mat image = JpegStringToMat(jpegImage); + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + + StopWebcamPlayer(&filePlayerClient); + ReleaseANSWebcamPlayerHandle(&filePlayerClient); + return 0; + +} +void PrintCapabilities(IAMStreamConfig* pConfig) +{ + int iCount = 0, iSize = 0; + HRESULT hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); + + if (SUCCEEDED(hr) && iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) + { + for (int iFormat = 0; iFormat < iCount; iFormat++) + { + VIDEO_STREAM_CONFIG_CAPS scc; + AM_MEDIA_TYPE* pmtConfig; + hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc); + + if (SUCCEEDED(hr)) + { + if (pmtConfig->formattype == FORMAT_VideoInfo) + { + VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat; + std::cout << "Resolution: " << pVih->bmiHeader.biWidth << " x " << pVih->bmiHeader.biHeight << std::endl; + } + //DeleteMediaType(pmtConfig); + } + } + } +} +void EnumerateDevices() +{ + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum)); + + if (SUCCEEDED(hr)) + { + hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0); + if (hr == S_OK) + { + IMoniker* pMoniker = NULL; + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) + { + IPropertyBag* pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag)); + if (FAILED(hr)) + { + pMoniker->Release(); + continue; + } + + VARIANT var; + VariantInit(&var); + + hr = pPropBag->Read(L"FriendlyName", &var, 0); + if (SUCCEEDED(hr)) + { + std::wcout << var.bstrVal << std::endl; + + IBaseFilter* pCap = NULL; + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); + if (SUCCEEDED(hr)) + { + IAMStreamConfig* pConfig = NULL; + hr = pCap->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig); + if (SUCCEEDED(hr)) + { + PrintCapabilities(pConfig); + pConfig->Release(); + } + pCap->Release(); + } + } + + VariantClear(&var); + pPropBag->Release(); + pMoniker->Release(); + } + pEnum->Release(); + } + pDevEnum->Release(); + } +} +int WebcamResolutionClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + std::vector cameraNames; + std::string supportedResolution; + ANSWEBCAMPlayer* filePlayerClient; + std::string cameraName; + ScanStrANSWebcamPlayer(cameraNames); + if ((!cameraNames.empty()) && (cameraNames.size() > 0)) { + for (int i = 0; i < cameraNames.size(); i++) { + std::cout << "Camera name:" << cameraNames.at(i) << std::endl; + } + cameraName = cameraNames.at(1); + } + cameraName = cameraNames.at(1); + ScanSupportedResolutions(cameraName, cameraNames, supportedResolution); + std::cout << "Supported resolution:" << supportedResolution << std::endl; + ReleaseANSWebcamPlayerHandle(&filePlayerClient); + return 0; +} +int RTSPStressTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSRTSPClient* rtspClient; + for (int i = 0; i < 2; i++) { + std::cout << "Running the " << i << " time" << std::endl; + CreateANSRTSPHandle(&rtspClient, "", "", "", "rtsp://admin:admin123@192.168.1.13:554"); + StartRTSP(&rtspClient); + SetRTSPImageRotation(&rtspClient, 0); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + std::string jpegImage; + int index = 0; + while (true) { + index++; + if ((index == 100) || (index == 300) || (index == 500)) StopRTSP(&rtspClient); + if ((index == 200) || (index == 400) || (index == 600)) StartRTSP(&rtspClient); + if (index > 10) break; + GetRTSPStrImage(&rtspClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + sleep(1); + std::cout << "Empty image" << std::endl; + continue; // Skip the rest of the loop if image is empty + } + std::cout << "Index=" << index << ". Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + + cv::Mat image = JpegStringToMat(jpegImage); + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + if (cv::waitKey(30) == 27) { + break; + } + + } + //cv::destroyAllWindows(); // Destroy all OpenCV windows + StopRTSP(&rtspClient); + ReleaseANSRTSPHandle(&rtspClient); + } + + + return 0; + +} + +// TurboJPEG Encoder +std::vector encodeJpeg(const cv::Mat& img, int quality = 80) { + tjhandle jpegCompressor = tjInitCompress(); + unsigned char* jpegBuf = nullptr; // Will hold the compressed image data + unsigned long jpegSize = 0; // Will hold the size of the compressed data + + int width = img.cols; + int height = img.rows; + int pixelFormat = TJPF_BGR; // OpenCV uses BGR format + + // Compress the image to JPEG format + int result = tjCompress2( + jpegCompressor, img.data, width, 0, height, pixelFormat, + &jpegBuf, &jpegSize, TJSAMP_420, quality, TJFLAG_FASTDCT // TJSAMP_420 for faster compression + ); + + // Check for compression errors + if (result < 0) { + std::cerr << "TurboJPEG compression error: " << tjGetErrorStr() << std::endl; + tjFree(jpegBuf); + tjDestroy(jpegCompressor); + return {}; // Return empty vector on failure + } + + // Copy the compressed data into a vector + std::vector encodedImage(jpegBuf, jpegBuf + jpegSize); + + // Free the TurboJPEG-allocated buffer and destroy the compressor + tjFree(jpegBuf); + tjDestroy(jpegCompressor); + + return encodedImage; // Return the JPEG-encoded image data +} + +// TurboJPEG Decoder +cv::Mat decodeJpeg(const std::vector& jpegBuf) { + tjhandle jpegDecompressor = tjInitDecompress(); + + int width, height, jpegSubsamp, jpegColorspace; + tjDecompressHeader3(jpegDecompressor, jpegBuf.data(), jpegBuf.size(), &width, &height, &jpegSubsamp, &jpegColorspace); + + cv::Mat img(height, width, CV_8UC3); // Assuming output is 3 channels (BGR) + + int pixelFormat = TJPF_BGR; // OpenCV uses BGR format + + int result = tjDecompress2(jpegDecompressor, jpegBuf.data(), jpegBuf.size(), + img.data, width, 0, height, pixelFormat, TJFLAG_FASTDCT); + + if (result < 0) { + std::cerr << "TurboJPEG decompression error: " << tjGetErrorStr() << std::endl; + } + + tjDestroy(jpegDecompressor); + + return img; +} + + +int FilePlayerOpenCVTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + //std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\SecureAgility\\TFNSW-AT-TCS2811-01_small.mp4"; + + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + int index = 0; + cv::VideoCapture capture(testVideoFile); + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + + auto start = std::chrono::system_clock::now(); + std::vector imageData; + bool success = cv::imencode(".jpg", frame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + break; + } + std::string jpegImage(imageData.begin(), imageData.end()); + cv::Mat image = JpegStringToMat(jpegImage); + + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + std::cout << "Time to decode the image:" << elapsed.count() << "ms" << std::endl; + + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(frame.cols, frame.rows)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + //std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + return 0; + +} +int FilePlayerTurboJpegTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\SecureAgility\\TFNSW-AT-TCS2811-01_small.mp4"; + + //std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + int index = 0; + cv::VideoCapture capture(testVideoFile); + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + std::vector imageData; + imageData=encodeJpeg(frame, 80); // Quality set to 80 + std::string jpegImage(imageData.begin(), imageData.end()); + std::vector jpegData(jpegImage.begin(), jpegImage.end()); + cv::Mat image = decodeJpeg(jpegData); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + std::cout << "Time to decode the image:" << elapsed.count() << "ms" << std::endl; + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(frame.cols, frame.rows)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + //std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + return 0; + +} +int FilePlayerDriverTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + //std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + + CreateANSFilePlayerHandle(&filePlayerClient, "", testVideoFile.c_str()); + StartFilePlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + SetFilePlayerImageRotation(&filePlayerClient, 0);// Rotate 90 + SetBBoxFilePlayer(&filePlayerClient, 0, 0, 1920, 1080); + SetCropFlagFilePlayer(&filePlayerClient, 1); + std::string jpegImage; + int index = 0; + while (true) { + index++; + if ((index == 200) || (index == 800) || (index == 1200)) StopFilePlayer(&filePlayerClient); //SetCropFlagFilePlayer(&filePlayerClient, 0);// + if ((index == 400) || (index == 1000) || (index == 1500)) StartFilePlayer(&filePlayerClient);//SetCropFlagFilePlayer(&filePlayerClient, 1); + if (index > 2000) break; + auto start = std::chrono::system_clock::now(); + GetFilePlayerStrImage(&filePlayerClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + sleep(1); + continue; // Skip the rest of the loop if image is empty + } + cv::Mat image = JpegStringToMat(jpegImage); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + std::cout << "Time to decode the image:" << elapsed.count() << "ms" << std::endl; + // std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + + + /* auto start = std::chrono::system_clock::now(); + StartFilePlayer(&filePlayerClient); + auto end1 = std::chrono::system_clock::now(); + + GetFilePlayerStrImage(&filePlayerClient, width, height, pts, jpegImage); + cv::Mat image = JpegStringToMat(jpegImage); + auto end2 = std::chrono::system_clock::now(); + + StopFilePlayer(&filePlayerClient); + auto end3 = std::chrono::system_clock::now(); + + auto elapsed1 = std::chrono::duration_cast(end1 - start); + std::cout << "Time to start camera:" << elapsed1.count() << "ms" << std::endl; + auto elapsed2 = std::chrono::duration_cast(end2 - end1); + std::cout << "Time to get image:" << elapsed2.count() << "ms" << std::endl; + auto elapsed3 = std::chrono::duration_cast(end3 - end2); + std::cout << "Time to stop camera:" << elapsed3.count() << "ms" << std::endl;*/ + + + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + StopFilePlayer(&filePlayerClient); + ReleaseANSFilePlayerHandle(&filePlayerClient); + return 0; + +} +int FilePlayerDriverBigFileTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\SecureAgility\\TFNSW-AT-TCS2811-01.mp4"; + CreateANSFilePlayerHandle(&filePlayerClient, "", testVideoFile.c_str()); + SetBBoxFilePlayer(&filePlayerClient, 0, 0, 300, 300); + + StartFilePlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + //cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + SetFilePlayerImageRotation(&filePlayerClient, 0);// Rotate 90 + std::string jpegImage; + int index = 0; + while (true) { + index++; + //if ((index == 200) || (index == 800) || (index == 1200)) StopFilePlayer(&filePlayerClient); //SetCropFlagFilePlayer(&filePlayerClient, 0);// + //if ((index == 400) || (index == 1000) || (index == 1500)) StartFilePlayer(&filePlayerClient);//SetCropFlagFilePlayer(&filePlayerClient, 1); + //if (index > 2000) break; + auto start = std::chrono::system_clock::now(); + GetFilePlayerStrImage(&filePlayerClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + sleep(1); + continue; // Skip the rest of the loop if image is empty + } + cv::Mat image = JpegStringToMat(jpegImage); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + //std::cout << "Time to decode the image:" << elapsed.count() << "ms" << std::endl; + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + StopFilePlayer(&filePlayerClient); + ReleaseANSFilePlayerHandle(&filePlayerClient); + return 0; + +} +int FilePlayerDriverStressClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* filePlayerClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + //std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + + CreateANSFilePlayerHandle(&filePlayerClient, "", testVideoFile.c_str()); + StartFilePlayer(&filePlayerClient); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1920, 1080); // Set initial size of the window. + SetFilePlayerImageRotation(&filePlayerClient, 0);// Rotate 90 + + std::string jpegImage; + int index = 0; + while (true) { + index++; + if (index > 10) break; + auto start = std::chrono::system_clock::now(); + GetFilePlayerStrImage(&filePlayerClient, width, height, pts, jpegImage); + if (jpegImage.empty()) { + sleep(1); + continue; // Skip the rest of the loop if image is empty + } + cv::Mat image = JpegStringToMat(jpegImage); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + //std::cout << "Time to decode the image:" << elapsed.count() << "ms" << std::endl; + std::cout << "Size: " << width << "x" << height << ". Timestamp: " << pts << std::endl; + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + if (cv::waitKey(30) == 27) { + break; + } + } + cv::destroyAllWindows(); // Destroy all OpenCV windows + StopFilePlayer(&filePlayerClient); + ReleaseANSFilePlayerHandle(&filePlayerClient); + return 0; + +} +int RSTPTestClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSRTSPClient* rtspClient; + //rtspClient.Init("","rtsp://root:abcd1234@118.70.125.152:5656/cam/realmonitor?channel=1&subtype=0"); + //rtspClient.Init("", "rtsp://anscamuser:SonTay2020@anssontay.tplinkdns.com:554/Streaming/Channels/301"); + //rtspClient.Init("","root", "abcd1234", "rtsp://118.70.125.152:5656/cam/realmonitor?channel=1&subtype=0"); + //rtspClient.Init("", "anscamuser", "SonTay2020", "rtsp://anssontay.tplinkdns.com:554/Streaming/Channels/101"); + // CreateANSRTSPHandle(&rtspClient, "", "", "", "rtsp://root:abcd1234@118.70.125.152:5656/cam/realmonitor?channel=1&subtype=0"); + //int createdObject=CreateANSRTSPHandle(&rtspClient, "", "admin", "Minhanhvu@14695", "rtsp://192.168.0.230:554/Streaming/Channels/101"); + //int createdObject = CreateANSRTSPHandle(&rtspClient, "", "", "", "rtsp://103.147.186.175:8554/9L02DA3PAJF8FF7"); + // int createdObject= CreateANSRTSPHandle(&rtspClient, "", "anscamuser", "SonTay2020", "rtsp://anssontay.tplinkdns.com:554/Streaming/Channels/101"); + // std::cout << "Created object:" << createdObject << std::endl; + //rtsp://camduongphotrauhoi.ddns.net:559/rtsp/streaming?channel=01&subtype=0 + //rtsp://ad1:admin123@camduongphotrauhoi.ddns.net:555/1/1 + //rtsp://ad1:admin123@cam3thang2.ddns.net:554/1/1 + //rtsp://admin:JA!uV_mx@42.1.117.99:8081/1/1 + //rtsp://admin:JA!uV_mx@42.1.117.99:8085/1/1 + //rtsp://admin:admin123@42.1.117.243:8001/1/1 + //std::string rtspUrl = "rtsp://anscamuser:SonTay2020@anssontay.tplinkdns.com:554/Streaming/Channels/401";// "rtsp://alex:admin123@192.168.1.11:554"; + // std::string rtspUrl = "rtsp://admin:admin123@192.168.1.17:554";//"rtsp://alex:admin123@192.168.1.11:554";// + std::string rtspUrl = "rtsp://admin:AnsHome16%&@192.168.1.104:554";//"rtsp://alex:admin123@192.168.1.11:554";//112 + // std::string rtspUrl = "rtsp://admin:admin123@192.168.1.87:554";//"rtsp://alex:admin123@192.168.1.11:554";// + // std::string rtspUrl = "rtsp://admin:12345678@192.168.0.251:554/profile1";//"rtsp://alex:admin123@192.168.1.11:554";// + + //std::string rtspUrl = "rtsp://admin:Minhanhvu@14695@192.168.0.230:554/Streaming/Channels/101";//"rtsp://alex:admin123@192.168.1.11:554";// + //std::cout << "RTSP URL:" << rtspUrl << std::endl; + + //std::string rtspUrl = "rtsp://admin:admin123@42.1.117.243:8001/1/1";// "rtsp://admin:admin123@42.1.117.245:8004/1/1";// "rtsp://admin:JA!uV_mx@42.1.117.99:8085/1/1";// "rtsp://admin:JA!uV_mx@42.1.117.99:8081/1/1"; + + // Testing + //std::string rtspUrl = "rtsp://camduongphotrauhoi.ddns.net:559/rtsp/streaming?channel=01&subtype=0";//"rtsp://alex:admin123@192.168.1.11:554";// + //std::string rtspUrl = "rtsp://ad1:admin123@camduongphotrauhoi.ddns.net:555/1/1";//"rtsp://alex:admin123@192.168.1.11:554";// + //std::string rtspUrl = "rtsp://ad1:admin123@cam3thang2.ddns.net:554/1/1"; + //std::string rtspUrl = "rtsp://admin:JA!uV_mx@42.1.117.99:8085/1/1"; + // std::string rtspUrl = "rtsp://khachtest:lamson2025@anninhlasuco.dssddns.net:5525/cam/realmonitor?channel=23&subtype=0"; + + //std::string rtspUrl = "rtsp://anscamuser:SonTay2020@anssontay.tplinkdns.com:554/Streaming/Channels/401"; + //std::string rtspUrl = "rtsp://root:A@bcd1234@172.28.5.3/axis-media/media.amp?videocodec=h264&camera=1";// "rtsp://admin:JA!uV_mx@42.1.117.99:8081/1/1"; + //std::string rtspUrl = "rtsp://172.28.5.3/axis-media/media.amp?videocodec=h264&camera=1";// "rtsp://admin:JA!uV_mx@42.1.117.99:8081/1/1"; + + //std::string rtspUrl = "rtsp://115.79.54.30:1024/Streaming/Channels/302";// "rtsp://admin:JA!uV_mx@42.1.117.99:8081/1/1" + //CreateANSRTSPHandle(&rtspClient, "", "admin", "Ttgs113pmh", rtspUrl.c_str()); + + //std::string rtspUrl = "rtsp://anscamuser:SonTay2020@anssontay.tplinkdns.com:554/Streaming/Channels/401"; + CreateANSRTSPHandle(&rtspClient, "", "", "", rtspUrl.c_str()); + + //SetBBoxRTSP(&rtspClient, 0, 0, 1920, 1080); + //SetCropFlagRTSP(&rtspClient, 1); + StartRTSP(&rtspClient); + //SetRTSPImageRotation(&rtspClient,0); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1080, 1920); // Set initial size of the window. + std::string jpegImage; + int index = 0; + while (true) { + index++; + std::cout << "Index=" << index << std::endl; + if ((index == 200) || (index == 800) || (index == 1200)) { StopRTSP(&rtspClient); } + if ((index == 400) || (index == 1000) || (index == 1500)) { StartRTSP(&rtspClient); } + //if (index > 2000) break; + + //if ((index == 100)) { StopRTSP(&rtspClient); } + //if ((index == 150) ) { StartRTSP(&rtspClient); } + ////if (index > 2000) break; + + //if (index > 300) StopRTSP(&rtspClient); + auto start = std::chrono::system_clock::now(); + GetRTSPStrImage(&rtspClient, width, height, pts, jpegImage); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start); + if(elapsed1.count()>0)std::cout << "Time to get image:" << elapsed1.count() << "ms" << std::endl; + + if (jpegImage.empty()) { + sleep(1); + continue; // Skip the rest of the loop if image is empty + } + + // auto start = std::chrono::system_clock::now(); + // StartRTSP(&rtspClient); + // auto end1 = std::chrono::system_clock::now(); + // GetRTSPStrImage(&rtspClient, width, height, pts, jpegImage); + // if (jpegImage.empty()) { + // sleep(1); + // std::cout << "Empty image" << std::endl; + // continue; // Skip the rest of the loop if image is empty + // } + //auto end2 = std::chrono::system_clock::now(); + // StopRTSP(&rtspClient); + //auto end3 = std::chrono::system_clock::now(); + // auto elapsed1 = std::chrono::duration_cast(end1-start); + // auto elapsed2 = std::chrono::duration_cast(end2 - end1); + // auto elapsed3 = std::chrono::duration_cast(end3 - end2); + // + // std::cout << "Time to start camera:" << elapsed1.count() << "ms" << std::endl; + // std::cout << "Time to get image:" << elapsed2.count() << "ms" << std::endl; + // std::cout << "Time to get stop:" << elapsed3.count() << "ms" << std::endl; + // sleep(1); + + cv::Mat image = JpegStringToMat(jpegImage); + cv::Mat resizedImage; + cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", resizedImage); // Show the resized image inside the window. + //std::cout << "Index="<empty()) { + ANSCV_ReleaseImage_S(&image); + std::this_thread::sleep_for(std::chrono::seconds(1)); + continue; // Skip processing if the image is empty + } + + // High-quality downscale for display: INTER_LANCZOS4 preserves sharpness and edges + cv::Mat displayImage; + if (image->cols > 1920) { + double scale = 1920.0 / image->cols; + cv::resize(*image, displayImage, cv::Size(), scale, scale, cv::INTER_LANCZOS4); + } + else { + displayImage = *image; + } + cv::imshow("Image", displayImage); + + ANSCV_ReleaseImage_S(&image); + //std::cout << "Index="< cameraNames; + ANSWEBCAMPlayer* filePlayerClient = nullptr; + std::string cameraName; + ScanStrANSWebcamPlayer(cameraNames); + if (cameraNames.empty()) { + std::cerr << "No webcam devices found!" << std::endl; + return -1; + } + for (size_t i = 0; i < cameraNames.size(); i++) { + std::cout << "Camera [" << i << "]: " << cameraNames.at(i) << std::endl; + } + // Use the first available camera + cameraName = cameraNames.at(0); + std::cout << ">>> Using camera: " << cameraName << std::endl; + + int createResult = CreateANSWebcamPlayerWithMaxResoHandle(&filePlayerClient, "", cameraName.c_str()); + std::cout << ">>> CreateANSWebcamPlayerHandle result=" << createResult << ", handle=" << (void*)filePlayerClient << std::endl; + if (createResult != 1 || !filePlayerClient) { + std::cerr << "Failed to create webcam handle! Result=" << createResult << std::endl; + return -1; + } + + SetWebcamImageRotation(&filePlayerClient, 0); + int startResult = StartWebcamPlayer(&filePlayerClient); + std::cout << ">>> StartWebcamPlayer result=" << startResult << std::endl; + + cv::namedWindow("Image", cv::WINDOW_NORMAL); + cv::resizeWindow("Image", 1920, 1080); + int index = 0; + while (true) { + index++; + + // Stop/Start cycle test: + // Stop at index 100, 300, 500, 700, 900 + // Start at index 200, 400, 600, 800, 1000 + if (index == 100 || index == 300 || index == 500 || index == 700 || index == 900) { + std::cout << ">>> [Index=" << index << "] STOPPING webcam" << std::endl; + int stopRes = StopWebcamPlayer(&filePlayerClient); + std::cout << ">>> StopWebcamPlayer result=" << stopRes << std::endl; + } + if (index == 200 || index == 400 || index == 600 || index == 800 || index == 1000) { + std::cout << ">>> [Index=" << index << "] STARTING webcam" << std::endl; + int startRes = StartWebcamPlayer(&filePlayerClient); + std::cout << ">>> StartWebcamPlayer result=" << startRes << std::endl; + } + if (index > 1100) { + std::cout << ">>> [Index=" << index << "] Test complete, exiting loop" << std::endl; + break; + } + + auto start = std::chrono::system_clock::now(); + cv::Mat* image = nullptr; + + int imgResult = GetWebcamCVImage(&filePlayerClient, width, height, pts, &image); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start); + + // Print log around stop/start boundaries and every 50 frames + bool printLog = (index % 50 == 0) || (index <= 5) + || (index >= 98 && index <= 103) || (index >= 198 && index <= 203) + || (index >= 298 && index <= 303) || (index >= 398 && index <= 403) + || (index >= 498 && index <= 503); + if (printLog) { + std::cout << "Index=" << index << ". ImgResult=" << imgResult + << ". W=" << width << " H=" << height << " PTS=" << pts + << " Time=" << elapsed1.count() << "ms" << std::endl; + } + + if (!image || image->empty()) { + if (printLog) { + std::cout << "Index=" << index << ". No image (stopped or not ready)" << std::endl; + } + ANSCV_ReleaseImage_S(&image); + std::this_thread::sleep_for(std::chrono::milliseconds(33)); + continue; + } + + cv::imshow("Image", *image); + ANSCV_ReleaseImage_S(&image); + + if (cv::waitKey(30) == 27) { + std::cout << "Break (ESC pressed)" << std::endl; + break; + } + } + cv::destroyAllWindows(); + StopWebcamPlayer(&filePlayerClient); + ReleaseANSWebcamPlayerHandle(&filePlayerClient); + return 0; +} +int FPTestCVClient() { + int width = 0; + int height = 0; + int64_t pts = 0; + ANSFILEPLAYER_CV* rtspClient; + std::string testVideoFile = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + + + CreateANSFilePlayerHandle(&rtspClient, "", testVideoFile.c_str()); + + StartFilePlayer(&rtspClient); + //SetRTSPImageRotation(&rtspClient,0); + cv::namedWindow("Image", cv::WINDOW_NORMAL); // Create a resizable window. + cv::resizeWindow("Image", 1080, 1920); // Set initial size of the window. + std::string jpegImage; + int index = 0; + while (true) { + index++; + //std::cout << "Index=" << index << std::endl; + // if ((index == 200) || (index == 800) || (index == 1200)) { StopRTSP(&rtspClient); SetCropFlagRTSP(&rtspClient, 1); } + // if ((index == 400) || (index == 1000) || (index == 1500)) { StartRTSP(&rtspClient); SetCropFlagRTSP(&rtspClient, 0); } + // if (index > 2000) break; + auto start = std::chrono::system_clock::now(); + cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image + GetFilePlayerCVImage(&rtspClient, width, height, pts, &image); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start); + if (elapsed1.count() > 0)std::cout << "Time to get image:" << elapsed1.count() << "ms" << std::endl; + + // ✅ Check if the image is valid BEFORE accessing it + if (!image || image->empty()) { + ANSCV_ReleaseImage_S(&image); + std::this_thread::sleep_for(std::chrono::seconds(1)); + continue; // Skip processing if the image is empty + } + + //cv::Mat resizedImage; + //cv::resize(image, resizedImage, cv::Size(width, height)); + cv::imshow("Image", *image); // Show the resized image inside the window. + + ANSCV_ReleaseImage_S(&image); + //std::cout << "Index="< threads; + + for (int i = 0; i < 100; ++i) { + threads.emplace_back(ImageManagementRefTest); // Start thread + } + + for (auto& t : threads) { + if (t.joinable()) t.join(); // Wait for all threads to finish + } +} +int TestCreateImageFromFile() { + std::string testImageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + cv::Mat* sharedImage = nullptr; + for (int i = 0; i < 5; i++) { + ANSCV_CreateImageFromFile_S(testImageFile.c_str(), &sharedImage); + int width = 0, height = 0; + ANSCV_GetImageInfo_S(&sharedImage, width, height); + std::cout << "Width:" << width << " Height:" << height << std::endl; + ANSCV_ReleaseImage_S(&sharedImage); + } + return 0; +} +bool readFileToString(const std::string& filePath, std::string& outBuffer) { + std::ifstream file(filePath, std::ios::binary | std::ios::ate); + if (!file) { + std::cerr << "Error opening file: " << filePath << std::endl; + return false; + } + + std::streamsize size = file.tellg(); + if (size <= 0) { + std::cerr << "File is empty or error getting file size: " << filePath << std::endl; + return false; + } + + outBuffer.resize(static_cast(size)); + file.seekg(0, std::ios::beg); + + if (!file.read(&outBuffer[0], size)) { + std::cerr << "Error reading file contents: " << filePath << std::endl; + return false; + } + + return true; +} +int TestCreateImageFromJpegStringFile() { + std::string testImageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + + // Correctly open the file + std::ifstream file(testImageFile, std::ios::binary); + if (!file) { + std::cerr << "Error opening file: " << testImageFile << std::endl; + return -1; + } + + // Read entire file into a string + std::string jpegImage((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + + // Close the file (optional, handled automatically by destructor) + file.close(); + unsigned char* inputImage; + // Convert string to unsigned char* + inputImage = reinterpret_cast(const_cast(jpegImage.data())); + unsigned int bufferLength = jpegImage.size(); + // Create image from jpeg string + cv::Mat* sharedImage = nullptr; + for (int i = 0; i < 500; i++) { + ANSCV_CreateImageFromJpegString_S(inputImage, bufferLength, &sharedImage); + // draw sharedImage image + //cv::imshow("Image", *sharedImage); + //cv::waitKey(0); + // Release the image + int width = 0, height = 0; + ANSCV_GetImageInfo_S(&sharedImage, width, height); + std::cout << "Width:" << width << " Height:" << height << std::endl; + ANSCV_ReleaseImage_S(&sharedImage); + } + + return 0; +} + +// Function to URL encode special characters +std::string urlEncode(const std::string& str) { + std::ostringstream encoded; + encoded.fill('0'); + encoded << std::hex; + for (char c : str) { + // Keep alphanumeric and some safe characters + if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + encoded << c; + } + else { + // Encode special characters + encoded << '%' << std::setw(2) << int(static_cast(c)); + } + } + + return encoded.str(); +} +int PureOpenCV() +{ + // RTSP connection parameters - configure these for your camera + std::string username = "root"; // Username can contain @ symbol + std::string password = "A@bcd1234"; + // Build RTSP URL without credentials first + std::string base_url = "172.28.5.3/axis-media/media.amp?videocodec=h264&camera=1"; + + std::string rtspUrl = "rtsp://" + base_url; // Use the base URL directly + std::cout << "Connecting to RTSP stream: " << base_url << std::endl; + + // Create VideoCapture object + cv::VideoCapture cap; + + // Method 1: Try using OpenCV's built-in credential handling + // Set username and password separately using VideoCapture properties + cap.open(rtspUrl); + + // If the above doesn't work, try Method 2: Manual URL encoding + if (!cap.isOpened()) { + std::cout << "Trying with embedded credentials..." << std::endl; + + // URL encode username and password to handle special characters + std::string encoded_username = urlEncode(username); + std::string encoded_password = urlEncode(password); + + // Build complete RTSP URL with encoded credentials + std::string rtsp_url = "rtsp://" + encoded_username + ":" + encoded_password + + "@" + base_url; + + cap.open(rtsp_url); + } + + // Method 3: Try alternative authentication method using CAP_PROP_* (OpenCV 4.x) + if (!cap.isOpened()) { + std::cout << "Trying alternative authentication method..." << std::endl; + cap.open(rtspUrl); + } + + // Check if camera opened successfully + if (!cap.isOpened()) { + std::cerr << "Error: Could not open RTSP stream!" << std::endl; + std::cerr << "Please check:" << std::endl; + std::cerr << "1. RTSP URL is correct" << std::endl; + std::cerr << "2. Camera is accessible from your network" << std::endl; + std::cerr << "3. Username/password are correct (if required)" << std::endl; + return -1; + } + + // Set buffer size to reduce latency (optional) + cap.set(cv::CAP_PROP_BUFFERSIZE, 1); + + // Get video properties + int frame_width = static_cast(cap.get(cv::CAP_PROP_FRAME_WIDTH)); + int frame_height = static_cast(cap.get(cv::CAP_PROP_FRAME_HEIGHT)); + double fps = cap.get(cv::CAP_PROP_FPS); + + std::cout << "Stream connected successfully!" << std::endl; + std::cout << "Resolution: " << frame_width << "x" << frame_height << std::endl; + std::cout << "FPS: " << fps << std::endl; + std::cout << "Press ESC to exit..." << std::endl; + + cv::Mat frame; + + while (true) { + // Capture frame-by-frame + bool ret = cap.read(frame); + + if (!ret) { + std::cerr << "Error: Failed to grab frame from stream!" << std::endl; + std::cerr << "Stream may have ended or connection lost." << std::endl; + break; + } + + // Display the frame + cv::imshow("RTSP H264 Stream", frame); + + // Check for ESC key press (ASCII code 27) + int key = cv::waitKey(1) & 0xFF; + if (key == 27) { // ESC key + std::cout << "ESC pressed. Exiting..." << std::endl; + break; + } + } + + // Release everything + cap.release(); + cv::destroyAllWindows(); + + std::cout << "Application closed successfully." << std::endl; + return 0; +} +int TestGetImage() { + std::string testImageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + cv::Mat*imageIn; + // Create image from file + + int createImage= ANSCV_CreateImageFromFile_S(testImageFile.c_str(), &imageIn); + if( createImage != 1) { + std::cerr << "Error: Could not create cv::Mat from file!" << std::endl; + return -1; + } + + std::string outputImage; + int width = 1080; + int quality = 80; // Set desired quality (0-100) + int newWidth = 0, newHeight = 0; + for (int i = 0; i < 20; i++) { + auto start1 = std::chrono::system_clock::now(); + int result = ANSCV_GetImage_CPP(&imageIn, width, quality, newWidth, newHeight, outputImage); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + std::cout << "Time to get image: " << elapsed1.count() << " ms" << std::endl; + if (result != 1) { + std::cerr << "Error: Could not convert cv::Mat to ANSCV image format!" << std::endl; + return -1; + } + + } + std::cout << "Image converted successfully!" << std::endl; + std::cout << "New Width: " << newWidth << ", New Height: " << newHeight << std::endl; + //std::cout << "Jpeg string:" << outputImage << std::endl; + // Draw the image imageIn + //cv::imshow("Image", *imageIn); + //cv::waitKey(0); // Wait for a key press to close the window + ANSCV_ReleaseImage_S(&imageIn); + + +} +int GenerateVideo() { + std::string imageFolder = "E:\\Programs\\DemoAssets\\ImageSeries\\TestImages"; + std::string outputVideoPath = "E:\\Programs\\DemoAssets\\ImageSeries\\output.mp4"; + bool conversionResult = ANSCV_ImagesToMP4_S(imageFolder.c_str(), outputVideoPath.c_str(), 3.5); + if (!conversionResult) { + std::cerr << "Failed to convert images to MP4." << std::endl; + return -1; + } + return 0; +} + +int OpenCVFunctionTest() { + ANSCENTER::ANSOPENCV* cvHandle = new ANSCENTER::ANSOPENCV(); + const char* licenseKey = ""; + cvHandle->Init(licenseKey); + cv::Mat inputFrame = cv::imread("E:\\Programs\\DemoAssets\\Images\\bus.jpg"); + cv::Rect roi(0, 0, 300, 100); + cv::Mat outputFrame = cvHandle->ShiftImage(inputFrame, 200,200); + + //cv::Mat outputFrame = cvHandle->ToGray(inputFrame); + + std::string jpegData = cvHandle->MatToBinaryData(outputFrame); + + // Check if encoding was successful + if (jpegData.empty()) { + std::cerr << "Error: Failed to encode image to JPEG" << std::endl; + } + else { + std::cout << "JPEG data size: " << jpegData.size() << " bytes" << std::endl; + + // Save jpegData to file + std::ofstream outFile("E:\\Programs\\DemoAssets\\Images\\output_gray.jpg", std::ios::binary); + if (outFile.is_open()) { + outFile.write(jpegData.data(), jpegData.size()); // <-- THIS WAS MISSING! + outFile.close(); + std::cout << "File saved successfully" << std::endl; + } + else { + std::cerr << "Error: Could not open output file" << std::endl; + } + } + + cv::imshow("Cropped Image", outputFrame); + cv::waitKey(0); + + delete cvHandle; + +} + + +int main() +{ + ANSCENTER::ANSOPENCV::InitCameraNetwork(); + //OpenCVFunctionTest(); + //GenerateVideo(); + //VideoTestClient(); + // TestGetImage(); + //PureOpenCV(); + // RSTPTestClient(); + RSTPTestCVClient(); + //TestCreateImageFromJpegStringFile(); + //TestCreateImageFromFile(); + //for (int i = 0; i < 100; i++) { + // ImageManagementRefTest(); + //} + //runParallelTest(); + //FPTestCVClient(); + //WebcamVCPlayerTestClient(); + //WebcamPlayerTestClient(); + //FilePlayerOpenCVTestClient(); + //FilePlayerTurboJpegTestClient(); + //FilePlayerOpenCVTestClient(); + //FilePlayerDriverBigFileTestClient(); + //FilePlayerDriverTestClient(); + //FilePlayerOpenCVTestClient(); + // FilePlayerTurboJpegTestClient(); + //WebcamResolutionClient(); + //for (int i = 0; i < 10; i++) { + // WebcamPlayerTestClient(); + //} + //WebcamPlayerDoubleTestClient(); + //WebcamPlayerTestClient(); + //for (int i = 0; i < 5000; i++) { + // FilePlayerTestClient(); + //} + //for (int i = 0; i < 30; i++) { + // //RTSPStressTestClient(); + // std::cout << "Running the " << i << " time" << std::endl; + // FilePlayerDriverStressClient(); + //} + //std::cout << "Complete the test " << std::endl; + ///BrightEnhancement(); + //AutoWhiteBalance(); + //PatternMatching(); + //GetColour(); + //DetectRedCar(); + //DominantColour(); + //TestZingQRcode(); + //TestQRCode(); + //return WebcamPlayerDoubleTestClient(); + //return RSTPTestClient(); + //return FilePlayerTestClient(); + ANSCENTER::ANSOPENCV::DeinitCameraNetwork(); +} \ No newline at end of file diff --git a/tests/ANSCV-UnitTest/CMakeLists.txt b/tests/ANSCV-UnitTest/CMakeLists.txt new file mode 100644 index 0000000..9153096 --- /dev/null +++ b/tests/ANSCV-UnitTest/CMakeLists.txt @@ -0,0 +1,41 @@ +# ANSCV Unit Test +add_executable(ANSCV-UnitTest + ANSCV-UnitTest.cpp + OpenCVTest.cpp +) + +target_include_directories(ANSCV-UnitTest PRIVATE + ${CMAKE_SOURCE_DIR}/modules/ANSCV + ${CMAKE_SOURCE_DIR}/MediaClient + ${CMAKE_SOURCE_DIR}/MediaClient/media + ${CMAKE_SOURCE_DIR}/MediaClient/rtsp + ${CMAKE_SOURCE_DIR}/MediaClient/rtp + ${CMAKE_SOURCE_DIR}/MediaClient/bm + ${CMAKE_SOURCE_DIR}/MediaClient/http + ${CMAKE_SOURCE_DIR}/MediaClient/directx + ${CMAKE_SOURCE_DIR}/MediaClient/rtmp + ${CMAKE_SOURCE_DIR}/MediaClient/librtmp + ${CMAKE_SOURCE_DIR}/MediaClient/srt + ${CMAKE_SOURCE_DIR}/MediaClient/ffmpeg/include + ${CMAKE_SOURCE_DIR}/MediaClient/openssl/include + ${CMAKE_SOURCE_DIR}/MediaClient/libsrt/include + ${SHARED_INCLUDE_DIR} + ${ANLS_ROOT}/TurboJpeg + ${RESEARCH_DIR}/QRCode +) + +target_link_libraries(ANSCV-UnitTest + PRIVATE ANSCV + PRIVATE ANSLicensingSystem + PRIVATE anslicensing + PRIVATE labview + PRIVATE opencv + PRIVATE turbojpeg + PRIVATE zxing +) + +if(WIN32) + target_link_libraries(ANSCV-UnitTest PRIVATE ${WIN_COMMON_LIBS}) +endif() + +target_compile_definitions(ANSCV-UnitTest PRIVATE UNICODE _UNICODE) diff --git a/tests/ANSCV-UnitTest/OpenCVTest.cpp b/tests/ANSCV-UnitTest/OpenCVTest.cpp new file mode 100644 index 0000000..d3e768d --- /dev/null +++ b/tests/ANSCV-UnitTest/OpenCVTest.cpp @@ -0,0 +1,469 @@ +// +//bool isRed(Vec3b color) { +// // Define the lower and upper bounds for red color +// Scalar lower_red = Scalar(0, 0, 100); // Adjust as needed +// Scalar upper_red = Scalar(80, 80, 255); // Adjust as needed +// +// // Convert the input color to a scalar for comparison +// Scalar target_color = Scalar(color[0], color[1], color[2]); +// +// // Check if the input color is within the specified range of red +// return (target_color.val[0] >= lower_red.val[0] && target_color.val[0] <= upper_red.val[0] && +// target_color.val[1] >= lower_red.val[1] && target_color.val[1] <= upper_red.val[1] && +// target_color.val[2] >= lower_red.val[2] && target_color.val[2] <= upper_red.val[2]); +//} +// +//int DominantColour() { +// // Read the input image +// //cv::Mat image = cv::imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ANSCVAImages\\redcar.jpg"); +// cv::Mat image = cv::imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ANSCVAImages\\Bluecar.jpeg"); +// +// if (image.empty()) { +// std::cout << "Could not open or find the image" << std::endl; +// return -1; +// } +// +// // Reshape the image into a 2D array of pixels +// Mat pixels = image.reshape(1, image.rows * image.cols); +// +// // Convert pixel values to floats +// pixels.convertTo(pixels, CV_32F); +// +// // Define the number of clusters (colors) to find +// int numClusters = 3; // Adjust as needed +// +// // Perform K-means clustering +// Mat labels, centers; +// kmeans(pixels, numClusters, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0), 3, KMEANS_PP_CENTERS, centers); +// +// // Find the dominant colors +// vector dominantColors; +// for (int i = 0; i < numClusters; ++i) { +// Vec3b color; +// color[0] = centers.at(i, 0); // Blue +// color[1] = centers.at(i, 1); // Green +// color[2] = centers.at(i, 2); // Red +// dominantColors.push_back(color); +// } +// +// // Print the dominant colors +// cout << "Dominant colors:" << endl; +// for (int i = 0; i < numClusters; ++i) { +// cout << "Color " << i + 1 << ": BGR(" << (int)dominantColors[i][0] << ", " << (int)dominantColors[i][1] << ", " << (int)dominantColors[i][2] << ")" << endl; +// } +// +// // Display the dominant colors +// Mat colorPalette(100, 100 * numClusters, CV_8UC3); +// for (int i = 0; i < numClusters; ++i) { +// rectangle(colorPalette, Point(i * 100, 0), Point((i + 1) * 100, 100), Scalar(dominantColors[i]), -1); // Filled rectangle +// } +// imshow("Dominant Colors", colorPalette); +// +// // Wait for key press to exit +// waitKey(0); +// +// return 0; +//} +//// Function to determine basic color from 8 basic colors based on BGR values +//string getBasicColor(Vec3b color) { +// // Define 8 basic colors and their BGR values +// map basicColors = { +// {"Red", {0, 0, 255}}, +// {"Green", {0, 255, 0}}, +// {"Blue", {255, 0, 0}}, +// {"Yellow", {0, 255, 255}}, +// {"Black", {0, 0, 0}}, +// {"White", {255, 255, 255}}, +// {"Brown", {42, 42, 165}}, +// {"Gray", {128, 128, 128}} +// }; +// +// string basicColor = "Other"; +// +// // Find the basic color closest to the given color +// int minDistance = INT_MAX; +// for (const auto& entry : basicColors) { +// int dist = norm(entry.second, color, NORM_L2SQR); +// if (dist < minDistance) { +// minDistance = dist; +// basicColor = entry.first; +// } +// } +// +// return basicColor; +//} +// +//int GetColour() { +// // Read the image +// Mat image = imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ANSCVAImages\\redcar.jpg"); +// if (image.empty()) { +// cerr << "Error: Unable to read image." << endl; +// return -1; +// } +// +// // Initialize variables to count occurrences of 8 basic colors +// map colorCounts; +// for (const auto& entry : { +// "Red", "Green", "Blue", "Yellow", "Black", "White", "Brown", "Gray" +// }) { +// colorCounts[entry] = 0; +// } +// +// // Iterate over image pixels to count occurrences of 8 basic colors +// for (int i = 0; i < image.rows; ++i) { +// for (int j = 0; j < image.cols; ++j) { +// Vec3b pixelColor = image.at(i, j); +// string basicColor = getBasicColor(pixelColor); +// colorCounts[basicColor]++; +// } +// } +// +// // Find the dominant basic color +// string dominantBasicColor = "Other"; +// int maxCount = 0; +// for (const auto& entry : colorCounts) { +// if (entry.second > maxCount) { +// maxCount = entry.second; +// dominantBasicColor = entry.first; +// } +// } +// +// // Get the BGR color code of the dominant basic color +// Vec3b dominantBGRColor; +// if (dominantBasicColor == "Red") +// dominantBGRColor = Vec3b(0, 0, 255); +// else if (dominantBasicColor == "Green") +// dominantBGRColor = Vec3b(0, 255, 0); +// else if (dominantBasicColor == "Blue") +// dominantBGRColor = Vec3b(255, 0, 0); +// else if (dominantBasicColor == "Yellow") +// dominantBGRColor = Vec3b(0, 255, 255); +// else if (dominantBasicColor == "Black") +// dominantBGRColor = Vec3b(0, 0, 0); +// else if (dominantBasicColor == "White") +// dominantBGRColor = Vec3b(255, 255, 255); +// else if (dominantBasicColor == "Brown") +// dominantBGRColor = Vec3b(42, 42, 165); +// else if (dominantBasicColor == "Gray") +// dominantBGRColor = Vec3b(128, 128, 128); +// +// // Create a new image with the dominant color filled +// Mat dominantColorImage(image.size(), CV_8UC3, dominantBGRColor); +// +// // Display the dominant color in a separate window +// namedWindow("Dominant Color", WINDOW_AUTOSIZE); +// imshow("Dominant Color", dominantColorImage); +// waitKey(0); +// +// return 0; +//} +// +//int DetectRedCar() { +// // Read the input image +// cv::Mat image = cv::imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ANSCVAImages\\Bluecar.jpeg"); +// +// if (image.empty()) { +// cout << "Could not open or find the image" << endl; +// return -1; +// } +// +// // Reshape the image into a 2D array of pixels +// Mat pixels = image.reshape(1, image.rows * image.cols); +// +// // Convert pixel values to floats +// pixels.convertTo(pixels, CV_32F); +// +// // Define the number of clusters (colors) to find +// int numClusters = 3; // Adjust as needed +// +// // Perform K-means clustering +// Mat labels, centers; +// kmeans(pixels, numClusters, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0), 3, KMEANS_PP_CENTERS, centers); +// +// // Find the dominant colors +// vector dominantColors; +// for (int i = 0; i < numClusters; ++i) { +// Vec3b color; +// color[0] = centers.at(i, 0); // Blue +// color[1] = centers.at(i, 1); // Green +// color[2] = centers.at(i, 2); // Red +// dominantColors.push_back(color); +// } +// +// // Check if any of the dominant colors are red +// bool redDetected = false; +// for (int i = 0; i < numClusters; ++i) { +// if (isRed(dominantColors[i])) { +// redDetected = true; +// break; +// } +// } +// +// // Print the result +// if (redDetected) { +// cout << "A red car is detected in the image." << endl; +// } +// else { +// cout << "No red car is detected in the image." << endl; +// } +// +// return 0; +//} +// +//double CalculateIoU(const cv::Rect& box1, const cv::Rect& box2) { +// int x1 = std::max(box1.x, box2.x); +// int y1 = std::max(box1.y, box2.y); +// int x2 = std::min(box1.x + box1.width, box2.x + box2.width); +// int y2 = std::min(box1.y + box1.height, box2.y + box2.height); +// +// int intersectionArea = std::max(0, x2 - x1) * std::max(0, y2 - y1); +// int box1Area = box1.width * box1.height; +// int box2Area = box2.width * box2.height; +// +// double iou = static_cast(intersectionArea) / (box1Area + box2Area - intersectionArea); +// return iou; +//} +//void NonMaximumSuppression(std::vector& detectedObjects, double iouThreshold) { +// std::sort(detectedObjects.begin(), detectedObjects.end(), +// [](const DetectionObject& a, const DetectionObject& b) { +// return a.confidence > b.confidence; +// }); +// +// std::vector finalDetections; +// while (!detectedObjects.empty()) { +// finalDetections.push_back(detectedObjects.front()); +// detectedObjects.erase(detectedObjects.begin()); +// +// for (auto it = detectedObjects.begin(); it != detectedObjects.end(); ) { +// if (CalculateIoU(finalDetections.back().box, it->box) > iouThreshold) { +// it = detectedObjects.erase(it); +// } +// else { +// ++it; +// } +// } +// } +// +// detectedObjects = std::move(finalDetections); +//} +//std::vector findMatches(cv::Mat& img, cv::Mat& templ, double threshold) { +// // Create the result matrix +// std::vector detectedObjects; +// int result_cols = img.cols - templ.cols + 1; +// int result_rows = img.rows - templ.rows + 1; +// cv::Mat result(result_rows, result_cols, CV_32FC1); +// +// // Perform match +// cv::matchTemplate(img, templ, result, cv::TM_CCOEFF_NORMED); +// cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); +// +// std::vector boundingBoxes; +// +// // Threshold and find non-zero locations +// for (int i = 0; i < result.rows; i++) { +// for (int j = 0; j < result.cols; j++) { +// if (result.at(i, j) > threshold) { +// cv::Rect rect(j, i, templ.cols, templ.rows); +// DetectionObject object; +// object.box = rect; +// boundingBoxes.push_back(rect); +// detectedObjects.push_back(object); +// // Optional: Draw rectangles on the image +// cv::rectangle(img, rect, cv::Scalar(0, 0, 255), 2); +// } +// } +// } +// NonMaximumSuppression(detectedObjects, 0.5); +// std::cout << "Bounding box size:" << boundingBoxes.size()< matches = findMatches(img, templ, 0.8); +// +// // Display the image with drawn rectangles +// cv::imshow("Matches", img); +// cv::waitKey(0); +// +// +// return 0; +//} + +//int TestZingQRcode() { +// +// // load your image data from somewhere. ImageFormat::Lum assumes grey scale image data +// +// cv::Mat inputImage = cv::imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\QR\\Code128.jpg"); +// cv::Mat grayMat; +// if (inputImage.channels() == 3) { +// cv::cvtColor(inputImage, grayMat, cv::COLOR_BGR2GRAY); +// } +// else if (inputImage.channels() == 4) { +// cv::cvtColor(inputImage, grayMat, cv::COLOR_BGRA2GRAY); +// } +// else { +// grayMat = inputImage; // Already grayscale +// } +// +// int width = grayMat.cols; +// int height= grayMat.rows; +// unsigned char* data = grayMat.data; +// auto image = ZXing::ImageView(data, width, height, ZXing::ImageFormat::Lum); +// auto options = ZXing::ReaderOptions().setFormats(ZXing::BarcodeFormat::Any); +// auto barcodes = ZXing::ReadBarcodes(image, options); +// if (barcodes.size() > 0) { +// for (const auto& b : barcodes) { +// std::cout << ZXing::ToString(b.format()) << ": " << b.text() << "\n"; +// ZXing::Position pos =b.position(); +// std::cout<<"Pos 1:("< channels(3); +// split(src_float, channels); +// +// Mat magnitude = Mat::zeros(src.size(), CV_32FC1); +// +// for (int i = 0; i < 3; i++) { +// Mat sobelx, sobely; +// Sobel(channels[i], sobelx, CV_32F, 1, 0); +// Sobel(channels[i], sobely, CV_32F, 0, 1); +// magnitude += sobelx.mul(sobelx) + sobely.mul(sobely); +// } +// +// sqrt(magnitude, magnitude); +// Mat flatMagnitude = magnitude.reshape(1, 1); +// cv::sort(flatMagnitude, flatMagnitude, SORT_EVERY_ROW + SORT_DESCENDING); +// int thresholdIdx = static_cast(percentile * flatMagnitude.total() / 100.0); +// double threshold = flatMagnitude.at(thresholdIdx); +// +// Mat mask = magnitude >= threshold; +// Scalar meanVal = mean(src_float, mask); +// +// cout << "Estimated illumination: " << meanVal << endl; +// return Vec3f(meanVal[0], meanVal[1], meanVal[2]); +//} +// +//void applyWhiteBalance(Mat& src, Mat& dst, Vec3f illumination) { +// vector channels(3); +// src.convertTo(src, CV_32FC3); +// split(src, channels); +// +// for (int i = 0; i < 3; i++) { +// channels[i] /= illumination[i]; +// } +// +// merge(channels, dst); +// dst.convertTo(dst, CV_8U); +//} +// +//void simpleWhiteBalance(Mat& src, Mat& dst) { +// // Convert image to floating point for precision +// src.convertTo(dst, CV_32F); +// +// // Split the image into separate color channels +// vector channels(3); +// split(dst, channels); +// +// // Calculate the average intensity for each channel +// double avgB = mean(channels[0])[0]; +// double avgG = mean(channels[1])[0]; +// double avgR = mean(channels[2])[0]; +// +// // Calculate the total average intensity +// double avgTotal = (avgB + avgG + avgR) / 3.0; +// +// // Scale each channel to adjust the white balance +// channels[0] *= avgTotal / avgB; +// channels[1] *= avgTotal / avgG; +// channels[2] *= avgTotal / avgR; +// +// // Merge the channels back into one image +// merge(channels, dst); +// +// // Convert back to 8-bit color +// dst.convertTo(dst, CV_8U); +//} +//int AutoWhiteBalance() { +// Mat src = imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ANSCVAImages\\cat.jpg"); +// if (src.empty()) { +// cout << "Could not open or find the image" << endl; +// return -1; +// } +// +// Mat dst; +// Vec3f illumination = estimateIllumination(src, 0.1); // Top 1% of gradients +// applyWhiteBalance(src, dst, illumination); +// +// //simpleWhiteBalance(src,dst); +// imshow("Original Image", src); +// imshow("White Balanced Image", dst); +// cv::waitKey(0); +// +// return 0; +//} +// +// +//int BrightEnhancement() { +// // Load the input image +// Mat inputImage = imread("C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ANSCVAImages\\dark.jpg", IMREAD_COLOR); +// +// // Check if the image was loaded successfully +// if (inputImage.empty()) { +// cout << "Error: Could not open or find the image" << endl; +// return -1; +// } +// +// // Separate the input image into B, G, and R channels +// vector channels; +// split(inputImage, channels); +// +// // Enhance brightness for each channel individually +// double brightnessScaleFactor = 1.5; // Scaling factor for brightness enhancement +// for (int i = 0; i < channels.size(); ++i) { +// channels[i] *= brightnessScaleFactor; +// } +// +// // Merge the channels back into a BGR image +// Mat enhancedImage; +// merge(channels, enhancedImage); +// +// // Display original and enhanced images +// namedWindow("Original Image", WINDOW_AUTOSIZE); +// imshow("Original Image", inputImage); +// +// namedWindow("Enhanced Image", WINDOW_AUTOSIZE); +// imshow("Enhanced Image", enhancedImage); +// +// // Wait for a keystroke in the window +// waitKey(0); +// +// // Close all OpenCV windows +// destroyAllWindows(); +// +// return 0; +//} \ No newline at end of file diff --git a/tests/ANSFR-UnitTest/ANSFR-UnitTest.cpp b/tests/ANSFR-UnitTest/ANSFR-UnitTest.cpp new file mode 100644 index 0000000..67e7645 --- /dev/null +++ b/tests/ANSFR-UnitTest/ANSFR-UnitTest.cpp @@ -0,0 +1,1346 @@ +#include +#include +#include +#include +#include "boost/property_tree/ptree.hpp" +#include "boost/property_tree/json_parser.hpp" +#include "boost/foreach.hpp" +#include "boost/optional.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ANSFR.h" +#include "fastdeploy/vision.h" +#include "ANSFilePlayer.h" +#include +#include + +using namespace cv; +using namespace dnn; +using namespace std; + +template +T GetOptionalValue(const boost::property_tree::ptree& pt, std::string attribute, T defaultValue) { + if (pt.count(attribute)) { + return pt.get(attribute); + } + return defaultValue; +} + +template +T GetData(const boost::property_tree::ptree& pt, const std::string& key) +{ + T ret; + if (boost::optional data = pt.get_optional(key)) + { + ret = data.get(); + } + return ret; +} + +typedef struct { + int width; + int height; + unsigned char* buffer; + unsigned long data_size; +} my_bitmap_type; + +std::vector EncodeToJpegData(const my_bitmap_type* image) +{ + nvjpegHandle_t nv_handle; + nvjpegEncoderState_t nv_enc_state; + nvjpegEncoderParams_t nv_enc_params; + cudaStream_t stream = NULL; + + nvjpegStatus_t er; + nvjpegCreateSimple(&nv_handle); + nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream); + nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream); + nvjpegEncoderParamsSetSamplingFactors(nv_enc_params, NVJPEG_CSS_444, stream); + + nvjpegImage_t nv_image; + nv_image.channel[0] = image->buffer; + nv_image.pitch[0] = 3 * image->width; + + er = nvjpegEncodeImage(nv_handle, nv_enc_state, nv_enc_params, &nv_image, + NVJPEG_INPUT_BGRI, image->width, image->height, stream); + + size_t length = 0; + nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, NULL, &length, stream); + + cudaStreamSynchronize(stream); + std::vector jpeg(length); + nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, jpeg.data(), &length, 0); + + nvjpegEncoderParamsDestroy(nv_enc_params); + nvjpegEncoderStateDestroy(nv_enc_state); + nvjpegDestroy(nv_handle); + + return jpeg; +} +int InsertUsers(std::string databaseFilePath,std::string recognizerFilePath, std::string detectorFilePath) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(),1); + + std::cout << "Insert users.\n"; + string userId = "0001"; + string userName = "Tien"; + + int userid= InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + userId = "0002"; + userName = "Tuan"; + + userid=InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + + + std::cout << "End of inserting users.\n"; + ReleaseANSRFHandle(&infHandle); + + return 0; +} +int InsertFaces(std::string databaseFilePath, std::string recognizerFilePath, std::string detectorFilePath,std::string imageFolder) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(),1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + + int userId = 1; + unsigned int bufferLength = 0; + //string imagePath = "C:\\Programs\\DemoAssets\\NV\\Ng Viet Xuan Nhi.png";// "C:\\Programs\\DemoAssets\\Images\\Hoang.jpg";;// imageFolder + "\\SuperImages\\Tom.jpg"; + //string imagePath = "C:\\Programs\\DemoAssets\\NV\\OtherIssues\\Tuan_Anh\\TA5.jpg";// "C:\\Programs\\DemoAssets\\Images\\Hoang.jpg";;// imageFolder + "\\SuperImages\\Tom.jpg"; + string imagePath = "C:\\Programs\\DemoAssets\\NV\\No\\canread.png";// "C:\\Programs\\DemoAssets\\Images\\Hoang.jpg";;// imageFolder + "\\SuperImages\\Tom.jpg"; + + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + InsertFaceBinary(& infHandle, userId, jpeg_string,width,height); + delete jpeg_string; + + /* + imagePath = imageFolder+"\\SuperImages\\Tom1.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + userId = 2; + imagePath = imageFolder+"\\SuperImages\\Jil.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + + imagePath = imageFolder+"\\SuperImages\\Jil1.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + imagePath = imageFolder+"\\SuperImages\\Jil2.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string;*/ + + std::cout << "End of inserting faces.\n"; + ReleaseANSRFHandle(&infHandle); + + return 0; +} +int RunInferenceTest(std::string databaseFilePath, std::string recognizerFilePath,std::string facedetectorPath, std::string imagePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorPath; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(),0.65,1,1,1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + unsigned int bufferLength = 0; + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + delete jpeg_string; + std::cout << "Result:"<< detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", class_name, class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Face detection", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of inserting faces.\n"; + } + std::cout << "End of inserting faces.\n"; + ReleaseANSRFHandle(&infHandle); + cudaDeviceReset(); + + //ReleaseLoggers(); + return 0; +} +int TestManagementAPI(std::string databaseFilePath, std::string recognizerFilePath) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(),1); + std::vector userIds; + Reload(&infHandle); + string userRecords; + GetUsersString(&infHandle, userRecords,userIds); + std::cout << "User records: " << userRecords << std::endl; + + string userRecord; + GetUserString(&infHandle, 1, userRecord); + std::cout << "User record: " << userRecord << std::endl; + + + string faceRecord; + GetFaceString(& infHandle, 1, faceRecord); + std::cout << "Face record: " << faceRecord << std::endl; + + string faceRecords; + GetFacesString(&infHandle, 1, faceRecords); + std::cout << "Face records: " << faceRecords << std::endl; + ReleaseANSRFHandle(&infHandle); + return 0; +} +int RunDetectTest(std::string databaseFilePath, std::string recognizerFilePath, std::string imagePath) { + + const char* configFilePath = ""; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(),1); + unsigned int bufferLength = 0; + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + string detectionResult = RunANSRFDetectorBinary(&infHandle, jpeg_string, width, height); + std::cout << "Result:" << detectionResult; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", class_name, class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + + } + } + cv::imshow("ANS Face detection", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of inserting faces.\n"; + } + delete jpeg_string; + ReleaseANSRFHandle(&infHandle); + return 0; +} +int DeleteFaces(std::string databaseFilePath, std::string recognizerFilePath) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(), 1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::vector userIds; + std::string userRecords; + GetUsersString(&infHandle, userRecords, userIds); + for (int i = 0; i < userIds.size(); i++) { + DeleteUser(&infHandle, userIds[i]); + } + std::cout << "End of deleting faces.\n"; + ReleaseANSRFHandle(&infHandle); + return 0; +} +int TestANSVISNoUserCase(std::string databaseFilePath, std::string recognizerFilePath, std::string detectorFilePath, std::string imagePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(), 1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + unsigned int bufferLength = 0; + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", class_name, class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + cv::imshow("ANS Face detection", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of inserting faces.\n"; + } + delete jpeg_string; + std::cout << "End of inserting faces.\n"; + ReleaseANSRFHandle(&infHandle); + return 0; +} +int TestCompleteFR() { + std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = currentPath.string() + "\\ANSFRDB\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip"; + //std::string imagePath = "C:\\Programs\\DemoAssets\\Images\\TestFaces\\SuperImages\\Tom.jpg"; + std::string imagePath = "C:\\Programs\\DemoAssets\\Images\\TestFaces\\SuperImages\\FaceRecordings\\1\\0001_138x138.jpg"; + std::string imageFolder = "C:\\Programs\\DemoAssets\\Images\\TestFaces"; + + //TestANSVISNoUserCase(databaseFilePath, recognizerFilePath, facedetectorFilePath, imagePath); + //InsertUsers(databaseFilePath, recognizerFilePath, facedetectorFilePath); + InsertFaces(databaseFilePath, recognizerFilePath, facedetectorFilePath,imageFolder); + //RunInferenceTest(databaseFilePath, recognizerFilePath, facedetectorFilePath,imagePath); + //DeleteFaces(databaseFilePath, recognizerFilePath); + std::cout << "End of program.\n"; +} + +int TestFaceRecognition() { + // Get the current working directory + //std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + //std::string databaseFilePath = currentPath.string() + "\\ANSFRDB\\ANSFR.db"; + //std::string recognizerFilePath = currentPath.string() + "\\ANSAIModels\\ANS_FaceRecognizer_v1.0.zip"; + //std::string facedetectorFilePath = currentPath.string() + "\\ANSAIModels\\ANS_GenericFD(GPU)_v1.0.zip"; + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip"; + std::string imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Jack.jpg"; + RunInferenceTest(databaseFilePath, recognizerFilePath, facedetectorFilePath, imagePath); + std::cout << "End of program.\n"; +} +int InsertAlex(std::string databaseFilePath, std::string recognizerFilePath, std::string detectorFilePath) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(), 1); + + std::cout << "Insert users.\n"; + + string userId = "0001"; + string userName = "Tom"; + int userid = InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + + userId = "0002"; + userName = "Jil"; + userid = InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + + + userId = "0003"; + userName = "Mark"; + userid = InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + + + userId = "0004"; + userName = "Jack"; + userid = InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + + + std::cout << "End of inserting users.\n"; + + ReleaseANSRFHandle(&infHandle); + + return 0; +} +int InsertAlexFaces(std::string databaseFilePath, std::string recognizerFilePath, std::string detectorFilePath, std::string imageFolder) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, databaseFilePath.c_str(), recognizerFilePath.c_str(), detectorFilePath.c_str(), 1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + + int userId = 1; + unsigned int bufferLength = 0; + string imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Tom.jpg"; + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + userId =2; + imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Jil.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + userId = 3; + imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Mark.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + userId = 4; + imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Jack.jpg"; + frame = cv::imread(imagePath, cv::IMREAD_COLOR); + jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + height = frame.rows; + width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + std::cout << "End of inserting faces.\n"; + ReleaseANSRFHandle(&infHandle); + + return 0; +} +int TestFromActualDB() { + std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = currentPath.string() + "\\ANSFRDB\\ANSFR.db"; + std::string recognizerFilePath = currentPath.string() + "\\ANSAIModels\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = currentPath.string() + "\\ANSAIModels\\ANS_GenericFD(GPU)_v1.0.zip"; + databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Jack.jpg"; + RunInferenceTest(databaseFilePath, recognizerFilePath, facedetectorFilePath, imagePath); + std::cout << "End of program.\n"; +} +int TestAlexRecognition() { + // Get the current working directory + std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = currentPath.string() + "\\ANSFRDB\\ANSFR.db"; + std::string recognizerFilePath = currentPath.string() + "\\ANSAIModels\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = currentPath.string() + "\\ANSAIModels\\ANS_GenericFD(GPU)_v1.0.zip"; + std::string imagePath = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages\\Jil.jpg"; + std::string imageFolder = "C:\\Programs\\DemoAssets\\TestImages\\SuperImages"; + InsertAlex(databaseFilePath, recognizerFilePath, facedetectorFilePath); + InsertAlexFaces(databaseFilePath, recognizerFilePath, facedetectorFilePath, imageFolder); + RunInferenceTest(databaseFilePath, recognizerFilePath, facedetectorFilePath, imagePath); + std::cout << "End of program.\n"; + return 0; +} +int FaceRecognitionBenchmark() { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + // Get the current working directory + std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip"; + std::string videoFilePath = currentPath.string() + "\\Videos\\BMIP.mp4"; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorFilePath; + int result = CreateANSRFHandle(& infHandle, + licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), + 1, + 0.25, 1, 1, 1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + const auto sim = GetData(result, "similarity"); + + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d-%f", class_name, class_id,sim), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + //printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Time:" << static_cast(elapsed.count()) << "; Result" << detectionResult << std::endl; + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSRFHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int RunInferenceTests(std::string databaseFilePath, std::string recognizerFilePath, std::string facedetectorPath, std::string folder) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorPath; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), 0.65, 1, 1, 1); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + unsigned int bufferLength = 0; + + for (const auto& entry : std::filesystem::directory_iterator(folder)) { + if (entry.is_regular_file()) { + std::string filePath = entry.path().string();//"C:\\Projects\\ANSVIS\\Documentation\\TestImages\\FacialRecognition\\Faces\\097.jpg";// + std::cout << "Image File:" << filePath << std::endl; + cv::Mat frame = cv::imread(filePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", class_name, class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + delete jpeg_string; + } + } + std::cout << "End of inserting faces.\n"; + ReleaseANSRFHandle(&infHandle); + return 0; +} +int StressTest() { + // Get the current working directory + std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = currentPath.string() + "\\ANSFRDB\\ANSFR.db"; + std::string recognizerFilePath = currentPath.string() + "\\ANSAIModels\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = currentPath.string() + "\\ANSAIModels\\ANS_GenericFD(GPU)_v1.0.zip"; + + std::string imageFolder = currentPath.string()+"\\TestImages\\FacialRecognition\\Faces"; + + for (int i = 0; i < 10; i++) { + RunInferenceTests(databaseFilePath, recognizerFilePath, facedetectorFilePath, imageFolder); + } + std::cout << "End of program.\n"; + return 0; +} +int ExampleOfSuperResolitionon() { + // Initialize the super-resolution model + cv::dnn_superres::DnnSuperResImpl sr; + + // Load the pre-trained model + std::string modelPath = "ESPCN_x4.pb"; // Replace with the path to your model file + try { + sr.readModel(modelPath); + } + catch (const cv::Exception& e) { + std::cerr << "Error loading model: " << e.what() << std::endl; + return -1; + } + + // Set the model and scaling factor + sr.setModel("espcn", 4); // "espcn" model with a 4x scaling factor + + // Load the input image + cv::Mat image = cv::imread("input_image.jpg"); // Replace with your image file path + if (image.empty()) { + std::cerr << "Could not open or find the image." << std::endl; + return -1; + } + + // Upscale the image + cv::Mat upscaledImage; + sr.upsample(image, upscaledImage); + + // Display the original and upscaled images + cv::imshow("Original Image", image); + cv::imshow("Upscaled Image", upscaledImage); + cv::waitKey(0); + + return 0; +} + +int ANSVISTest() { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + // Get the current working directory + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.1.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFDET\\ANS_GenericFD(GPU)_v1.0.zip"; + + + //std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_FaceRecognizer_v1.1.zip"; + //std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(CPU)_v1.0.zip"; + + //std::string videoFilePath = "E:\\Programs\\DemoAssets\\Videos\\ANSVIS_Issues\\face.mp4"; + //std::string videoFilePath = "E:\\Programs\\DemoAssets\\Videos\\TestFR\\Face31.mp4"; + //std::string videoFilePath = "E:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + std::string videoFilePath = "E:\\Programs\\DemoAssets\\Videos\\TestFR\\school1.mp4";// "C:\\ProgramData\\ANSCENTER\\Shared\\classroom.mp4"; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int enalbleHeadPose = 1; + int enableFaceLiveness = 1; + int enableAgeGender = 1; + int enableEmotion = 1; + int enableAntispoofing = 1; + int precision = 0; + std::string detectorFilePath = facedetectorFilePath; + int result = CreateANSRFHandle( & infHandle, + licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), + precision, + 0.25, enableAgeGender, enableEmotion, enalbleHeadPose, 30, 0.55, enableFaceLiveness, enableAntispoofing); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + int index = 0; + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + index++; + //if (index == 200)Reload(&infHandle); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + std::cout << "Time:" << static_cast(elapsed.count()) << "; Result" << detectionResult << std::endl; + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + index++; + std::cout << "Detected Index:" << index << std::endl; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + const auto sim = GetData(result, "similarity"); + + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d-%f", class_name, class_id, sim), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSRFHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} + +// ANSVISTestFilePlayer — Same as ANSVISTest but uses ANSFILEPLAYER (HW decode + NV12 registry) +// instead of cv::VideoCapture. This enables NV12 fast-path testing for the FR pipeline: +// - SCRFD face detection uses fused NV12→RGB center-letterbox kernel +// - Face alignment uses NV12 affine warp kernel (full 4K resolution) +int ANSVISTestFilePlayer() { + boost::property_tree::ptree pt; + + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.1.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFDET\\ANS_GenericFD(GPU)_v1.0.zip"; + // std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(CPU)_v1.0.zip"; + + std::string videoFilePath = "E:\\Programs\\DemoAssets\\Videos\\TestFR\\school1.mp4"; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int enableHeadPose = 1; + int enableFaceLiveness = 1; + int enableAgeGender = 1; + int enableEmotion = 1; + int enableAntispoofing = 1; + int precision = 0; + + int result = CreateANSRFHandle(&infHandle, + licenseKey.c_str(), configFilePath, + databaseFilePath.c_str(), recognizerFilePath.c_str(), + facedetectorFilePath.c_str(), precision, + 0.25, enableAgeGender, enableEmotion, enableHeadPose, + 30, 0.55, enableFaceLiveness, enableAntispoofing); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult << std::endl; + Reload(&infHandle); + + // Create ANSFILEPLAYER instead of cv::VideoCapture + // This uses FFmpeg HW decode → NV12 frames are registered in ANSGpuFrameRegistry + ANSCENTER::ANSFILEPLAYER* filePlayer = nullptr; + int fpResult = CreateANSFilePlayerHandle(&filePlayer, licenseKey.c_str(), videoFilePath.c_str()); + if (fpResult != 1 || !filePlayer) { + std::cout << "Failed to create file player. Result: " << fpResult << std::endl; + ReleaseANSRFHandle(&infHandle); + return -1; + } + + StartFilePlayer(&filePlayer); + std::cout << "File player started. Waiting for first frame..." << std::endl; + + // Wait for player to start producing frames + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + int index = 0; + while (true) { + int width = 0, height = 0; + int64_t timeStamp = 0; + cv::Mat* image = nullptr; + + int getResult = GetFilePlayerCVImage(&filePlayer, width, height, timeStamp, &image); + if (getResult != 1 || !image || image->empty()) { + // Check if player is still running (video may have ended) + if (!IsFilePlayerRunning(&filePlayer)) { + std::cout << "File player stopped. Reconnecting..." << std::endl; + ReconnectFilePlayer(&filePlayer); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + continue; + } + + index++; + cv::Mat frame = image->clone(); // Clone for display (image pointer may be reused) + + // Run FR inference directly with cv::Mat — the NV12 registry lookup + // happens inside SCRFD::Detect() using frame.datastart as the key + auto start = std::chrono::system_clock::now(); + std::vector outputs = infHandle->Inference(frame, "FRCAM"); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + + std::string detectionResult = infHandle->FaceObjectsToJsonString(outputs); + std::cout << "Frame:" << index << " Time:" << elapsed.count() + << "ms Faces:" << outputs.size() << std::endl; + + // Draw results + for (const auto& face : outputs) { + cv::rectangle(frame, face.box, cv::Scalar(0, 255, 0), 2); + cv::putText(frame, + cv::format("%s-%s-%.3f", face.userName.c_str(), face.userId.c_str(), face.similarity), + cv::Point(face.box.x, face.box.y - 5), 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + + cv::imshow("ANS FR FilePlayer (NV12)", frame); + if (cv::waitKey(30) == 27) break; + } + + StopFilePlayer(&filePlayer); + ReleaseANSFilePlayerHandle(&filePlayer); + cv::destroyAllWindows(); + ReleaseANSRFHandle(&infHandle); + std::cout << "End of ANSVISTestFilePlayer." << std::endl; + return 0; +} + +int RunInferenceLoopTest(std::string databaseFilePath, std::string recognizerFilePath, std::string facedetectorPath, std::string imagePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorPath; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), 0.65, 1, 1, 1); + + + for (int i = 0; i < 1000; i++) { + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + unsigned int bufferLength = 0; + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + delete jpeg_string; + + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", class_name, class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + } + + ReleaseANSRFHandle(&infHandle); + return 0; +} +int FRStressTest() { + // Get the current working directory + std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFDET\\ANS_GenericFD(GPU)_v1.0.zip"; + //std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(CPU)_v1.0.zip"; + + std::string imagePath = "C:\\Programs\\DemoAssets\\Images\\TestFaces\\Tien1.jpg"; + + for (int i = 0; i < 100; i++) { + RunInferenceTest(databaseFilePath, recognizerFilePath, facedetectorFilePath, imagePath); + } + //RunInferenceLoopTest(databaseFilePath, recognizerFilePath, facedetectorFilePath, imagePath); + std::cout << "End of program.\n"; + return 0; +} +int ANSVISRecordingTest() { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + // Get the current working directory + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip"; + + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\Weapon\\BMGWeapon.mp4";// "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorFilePath; + int result = CreateANSRFHandle(&infHandle, + licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), + 1, + 0.25, 1, 1, 1, 20); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + int index = 0; + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + //index++; + //if (index == 200)Reload(&infHandle); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + string detectionResult = RunANSRFFaceDetector(&infHandle, jpeg_string, width, height); + + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, "face", cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + //printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Time:" << static_cast(elapsed.count()) << "; Result" << detectionResult << std::endl; + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSRFHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} + + +// Test face detector +int FaceDetectorTest() { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + // Get the current working directory + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip"; + + /* std::filesystem::path currentPath = "C:\\Programs\\DemoAssets"; + std::string databaseFilePath = currentPath.string() + "\\ANSFRDB\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_FaceRecognizer_v1.0.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip";*/ + + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4";// "C:\\Programs\\DemoAssets\\Videos\\TestFR\\Face_Issue.mp4";// ;// + //"C:\\Programs\\DemoAssets\\Videos\\classroom.mp4";//classroom BMIP + //"C:\\Programs\\DemoAssets\\Videos\\TestFR\\BMGOffice.mp4";// + + // "C:\\Programs\\DemoAssets\\Videos\\BMIP.mp4";// + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorFilePath; + int result = CreateANSRFHandle(&infHandle, + licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), + 1, + 0.25, 1, 1, 1, 50); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + int index = 0; + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + index++; + if (index == 200)Reload(&infHandle); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + const auto sim = GetData(result, "similarity"); + + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d-%f", class_name, class_id, sim), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + //printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Time:" << static_cast(elapsed.count()) << "; Result" << detectionResult << std::endl; + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSRFHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int ANSVISImageTest() { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + // Get the current working directory + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.1.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFDET\\ServerOptimised\\ANS_GenericFD(GPU)_v1.0_NVIDIAGeForceRTX4070LaptopGPU.zip"; + + + std::string imageFilePath = "E:\\Programs\\DemoAssets\\Images\\Unknown\\4615.jpg"; + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + std::string detectorFilePath = facedetectorFilePath; + int result = CreateANSRFHandle(&infHandle, + licenseKey.c_str(), + configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), + 1, + 0.25, 1, 1, 1, 30); + int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + Reload(&infHandle); + + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + string detectionResult = RunANSRFInferenceBinary(&infHandle, jpeg_string, width, height); + + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "user_id"); + const auto class_name = GetData(result, "user_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + const auto sim = GetData(result, "similarity"); + + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d-%f", class_name, class_id, sim), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + //printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Time:" << static_cast(elapsed.count()) << "; Result" << detectionResult << std::endl; + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + cv::destroyAllWindows(); + ReleaseANSRFHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} + + + +int InsertUser(std::string databaseFilePath, std::string recognizerFilePath, std::string detectorFilePath, string userId, string userName) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), 1, 0.35, 0, 0, 0, 30); + + std::cout << "Insert users.\n"; + int userid = InsertUser(&infHandle, userId.c_str(), userName.c_str()); + std::cout << "user id:" << userid << " has been inserted" << std::endl; + + std::cout << "End of inserting users.\n"; + ReleaseANSRFHandle(&infHandle); + + return 0; +} +int InsertFace(std::string databaseFilePath, std::string recognizerFilePath, std::string detectorFilePath, std::string imagePath) { + + const char* configFilePath = ""; + ANSCENTER::ANSFacialRecognition* infHandle; + std::string licenseKey = ""; + int result = CreateANSRFHandle(&infHandle, licenseKey.c_str(), configFilePath, + databaseFilePath.c_str(), + recognizerFilePath.c_str(), + detectorFilePath.c_str(), 1, 0.35, 0, 0, 0, 30); int loadEngineResult = LoadANSRFEngine(&infHandle); + std::cout << "Load Engine Result:" << loadEngineResult; + + + UpdateParameters(&infHandle, 0.35, 0, 0, 0, 30, 0.3,1,1,1); + int userId = 1; + unsigned int bufferLength = 0; + + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned char* jpeg_string = ANSCENTER::ANSFRHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + InsertFaceBinary(&infHandle, userId, jpeg_string, width, height); + delete jpeg_string; + + std::cout << "End of inserting faces.\n"; + ReleaseANSRFHandle(&infHandle); + + return 0; +} + +int TestCompleteFR1() { + std::filesystem::path currentPath = "E:\\Programs\\DemoAssets"; + std::string databaseFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANSFR.db"; + std::string recognizerFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFR\\ANS_FaceRecognizer_v1.1.zip"; + std::string facedetectorFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSFDET\\ServerOptimised\\ANS_GenericFD(GPU)_v1.0_NVIDIAGeForceRTX4070LaptopGPU.zip"; + //std::string imageFile = "E:\\Programs\\DemoAssets\\Images\\Face\\Original.jpg"; + std::string imageFile = "E:\\Programs\\DemoAssets\\Images\\Face\\61.png"; + //InsertUser(databaseFilePath, recognizerFilePath, facedetectorFilePath,"0001","Tien"); + InsertFace(databaseFilePath, recognizerFilePath, facedetectorFilePath, imageFile); + + std::cout << "End of program.\n"; + return 1; +} +int main() +{ + + //FaceDetectorTest(); + //TestFaceRecognition(); + //TestCompleteFR1(); + + //ANSVISImageTest(); + ANSVISTest(); + //ANSVISTestFilePlayer(); + // ANSVISRecordingTest(); + //FRStressTest(); + //for (int i = 0; i < 20; i++) { + // ANSVISTest(); + //} + // StressTest(); + //TestFromActualDB(); + //TestAlexRecognition(); + //FaceRecognitionBenchmark(); + // TestCompleteFR(); + //TestFaceRecognition(); + //FaceRecognitionBenchmark(); + std::cin.get(); +} + diff --git a/tests/ANSFR-UnitTest/CMakeLists.txt b/tests/ANSFR-UnitTest/CMakeLists.txt new file mode 100644 index 0000000..bef9249 --- /dev/null +++ b/tests/ANSFR-UnitTest/CMakeLists.txt @@ -0,0 +1,65 @@ +# ANSFR Unit Test +# vcxproj also compiles ANSFRCommon.cpp and OpenVINO engine sources inline +add_executable(ANSFR-UnitTest + ANSFR-UnitTest.cpp + ${CMAKE_SOURCE_DIR}/modules/ANSFR/ANSFRCommon.cpp + ${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/src/faceapp/cnn.cpp + ${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/src/utils/args_helper.cpp + ${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/src/utils/common.cpp +) + +target_include_directories(ANSFR-UnitTest PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/modules/ANSFR + ${CMAKE_SOURCE_DIR}/modules/ANSODEngine + ${CMAKE_SOURCE_DIR}/modules/ANSODEngine/CUDA + ${CMAKE_SOURCE_DIR}/modules/ANSCV + ${CMAKE_SOURCE_DIR}/modules/ANSMOT + ${CMAKE_SOURCE_DIR}/engines/ONNXEngine + ${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/include + ${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/include/faceapp + ${CMAKE_SOURCE_DIR}/engines/TensorRTAPI/include + ${CMAKE_SOURCE_DIR}/MediaClient + ${CMAKE_SOURCE_DIR}/MediaClient/media + ${CMAKE_SOURCE_DIR}/MediaClient/rtsp + ${CMAKE_SOURCE_DIR}/MediaClient/rtp + ${CMAKE_SOURCE_DIR}/MediaClient/bm + ${CMAKE_SOURCE_DIR}/MediaClient/http + ${CMAKE_SOURCE_DIR}/MediaClient/directx + ${CMAKE_SOURCE_DIR}/MediaClient/rtmp + ${CMAKE_SOURCE_DIR}/MediaClient/librtmp + ${CMAKE_SOURCE_DIR}/MediaClient/srt + ${CMAKE_SOURCE_DIR}/MediaClient/ffmpeg/include + ${CMAKE_SOURCE_DIR}/MediaClient/openssl/include + ${CMAKE_SOURCE_DIR}/MediaClient/libsrt/include + ${SHARED_INCLUDE_DIR} + ${ANLS_ROOT}/TurboJpeg + ${ANSLIBS_DIR}/faiss + ${ANSLIBS_DIR}/TensorRT/include + ${RESEARCH_DIR}/boost_1_88_0 + C:/fastdeploy_gpu/include +) + +target_link_libraries(ANSFR-UnitTest + PRIVATE ANSFR + PRIVATE ANSODEngine + PRIVATE ANSCV + PRIVATE ANSLicensingSystem + PRIVATE anslicensing + PRIVATE ANSMOT + PRIVATE opencv + PRIVATE onnxruntime + PRIVATE openvino + PRIVATE boost + PRIVATE CUDA::cudart + PRIVATE CUDA::cudart_static + PRIVATE CUDA::cublas + PRIVATE CUDA::cublasLt + PRIVATE CUDA::nvjpeg +) + +if(WIN32) + target_link_libraries(ANSFR-UnitTest PRIVATE ${WIN_COMMON_LIBS}) +endif() + +target_compile_definitions(ANSFR-UnitTest PRIVATE UNICODE _UNICODE) diff --git a/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp b/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp new file mode 100644 index 0000000..e180c32 --- /dev/null +++ b/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp @@ -0,0 +1,2780 @@ +#include +#include +#include +#include +#include "boost/property_tree/ptree.hpp" +#include "boost/property_tree/json_parser.hpp" +#include "boost/foreach.hpp" +#include "boost/optional.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "ANSLPR.h" +#include "ANSLPR_CPU.h" +#include "ANSOpenCV.h" +#include "ANSRTSP.h" +#include "ANSVideoPlayer.h" +#include "ANSFilePlayer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +T GetOptionalValue(const boost::property_tree::ptree& pt, std::string attribute, T defaultValue) { + if (pt.count(attribute)) { + return pt.get(attribute); + } + return defaultValue; +} + +template +T GetData(const boost::property_tree::ptree& pt, const std::string& key) +{ + T ret; + if (boost::optional data = pt.get_optional(key)) + { + ret = data.get(); + } + + return ret; +} + +int ANSLPR_CPU_VideoTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle = new ANSCENTER::ANSALPR_CPU(); + std::string licenseKey = ""; + std::string modelZipFile = currentPath.string() + "\\ANS_GenericALPR_v1.0.zip"; + modelZipFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericALPR_v1.0.zip"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\ALPR1.mp4"; + std::string lpnResult; + bool result = infHandle->Initialize(licenseKey, modelZipFile, "",0.5, 0.5); + std::cout << "Loading ANSLRP:" << result << std::endl; + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + + infHandle->Inference(frame, lpnResult); + std::string detectionResult = lpnResult; + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + cv::imshow("ANSLPR", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of program faces.\n"; + } + } + capture.release(); + cv::destroyAllWindows(); +} + +int ANSLPR_BigSize_VideoTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle = new ANSCENTER::ANSALPR_CPU(); + std::string licenseKey = ""; + std::string modelZipFile = currentPath.string() + "\\ANS_GenericALPR_v1.0.zip"; + modelZipFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericALPR_v1.0.zip"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + std::string lpnResult; + bool result = infHandle->Initialize(licenseKey, modelZipFile, "",0.5,0.5); + std::cout << "Loading ANSLRP:" << result << std::endl; + infHandle->LoadEngine(); + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + + infHandle->Inference(frame, lpnResult,"MyCam"); + std::string detectionResult = lpnResult; + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 1.2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + cv::resize(frame, frame, cv::Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + + cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + cv::imshow("ANSLPR", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of program faces.\n"; + } + } + capture.release(); + cv::destroyAllWindows(); +} + +std::string readJsonFile(const std::string& filePath) { + boost::property_tree::ptree pt; + boost::property_tree::read_json(filePath, pt); + + std::ostringstream oss; + boost::property_tree::write_json(oss, pt, false); + + return oss.str(); +} +unsigned char* CVMatToBytes(cv::Mat image, unsigned int& bufferLengh) +{ + int size = int(image.total() * image.elemSize()); + std::cout << "size:" << size << std::endl; + unsigned char* bytes = new unsigned char[size]; // you will have to delete[] that later + std::memcpy(bytes, image.data, size * sizeof(unsigned char)); + bufferLengh = size * sizeof(unsigned char); + return bytes; +} +int ANSLPR_CPU_Inferences_FileTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle; + + std::string licenseKey = ""; + std::string modelZipFile = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ANS_GenericALPR_v1.0.zip"; + std::string imageFilePath = "C:\\Projects\\ANSVIS\\Documentation\\TestImages\\ALPR\\LP1.jpg"; + std::string StrBox = readJsonFile("C:\\Projects\\ANLS\\Documents\\bboxStr.json"); + + int result = CreateANSALPRHandle(& infHandle, "", modelZipFile.c_str(), "",0,0.5,0.5,0); + std::cout << "Init Result:" << result << std::endl; + unsigned int bufferLength = 0; + + cv::Mat input = cv::imread(imageFilePath, cv::IMREAD_COLOR); + cv::Mat frame = input; + unsigned char* jpeg_string = CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + std::string detectionResult = ANSALPR_RunInferenceBinaryInCroppedImages(&infHandle, jpeg_string, width, height, StrBox.c_str()); + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", class_name, class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + //cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + //cv::imshow("ANSLPR", frame); + //cv::waitKey(0); + //cv::destroyAllWindows(); + ReleaseANSALPRHandle(&infHandle); +} +int ANSLPR_CV_VideoTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle; + std::string licenseKey = ""; + std::string modelZipFile = currentPath.string() + "\\ANS_GenericALPR_v1.0.zip"; + modelZipFile = "C:\\Programs\\DemoAssets\\ModelsForANSVIS\\ANS_GenericALPR_v1.1.zip"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\3725.mp4"; + std::string lpnResult; + int result = CreateANSALPRHandle(& infHandle, licenseKey.c_str(), modelZipFile.c_str(), "",0,0.5,0.5,0); + std::cout << "Loading ANSLRP:" << result << std::endl; + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + std::string jpegImage; + + cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image + image = new cv::Mat(frame); // ✅ Allocate the image + ANSALPR_RunInferenceComplete_CPP(& infHandle, &image, "MyCam", 0, 0, lpnResult, jpegImage); + std::string detectionResult = lpnResult; + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 1.2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + cv::resize(frame, frame, cv::Size(1920,1080)); // to half size or even smaller + delete image; + cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + cv::imshow("ANSLPR", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of program faces.\n"; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSALPRHandle(&infHandle); + +} +int ANSLPR_OD_VideoTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle; + std::string licenseKey = ""; + std::string modelZipFile ="C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ANS_ALPR_v1.2.zip";// "C:\\Projects\\ANSVIS\\Models\\ANS_ALPR_v1.2.zip";// "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ServerOptimised\\ANS_ALPR_v1.1_NVIDIAGeForceRTX4070LaptopGPU.zip"; + + std::string videoFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\day.mp4";//"E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day.mp4";// + std::string lpnResult; + int engineType = 1; + double detectionThreshold = 0.5; + double ocrThreshold = 0.5; + double detectionColourThreshold = 0.5; + int result = CreateANSALPRHandle(&infHandle, licenseKey.c_str(), modelZipFile.c_str(), "", engineType, detectionThreshold, ocrThreshold, detectionColourThreshold); + std::cout << "Loading ANSLRP:" << result << std::endl; + + int loadEngine = LoadANSALPREngineHandle(&infHandle); + std::cout << "Loading ANSLRP:" << loadEngine << std::endl; + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + std::string jpegImage; + + cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image + image = new cv::Mat(frame); // ✅ Allocate the image + ANSALPR_RunInferenceComplete_CPP(&infHandle, &image, "MyCam", 0, 0, lpnResult, jpegImage); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + std::string detectionResult = lpnResult; + //std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 1.2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + + cv::resize(frame, frame, cv::Size(1920, 1080)); // to half size or even smaller + delete image; + cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + cv::imshow("ANSLPR", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of program faces.\n"; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSALPRHandle(&infHandle); + +} + +int ANSLPR_OD_Inferences_FileTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle; + std::string licenseKey = ""; + std::string modelZipFile = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ServerOptimised\\ANS_ALPR_v1.2_NVIDIAGeForceRTX4070LaptopGPU.zip"; + std::string imageFilePath = "E:\\Programs\\DemoAssets\\Images\\ALPRTest\\WrongOrder\\1109.jpg";//20250912_213850.717.jpg; 20250912_213850.511.jpg;//20250912_213850.411.jpg;//20250912_213850.261.jpg(65H115912:0.73) cororect (20250912_213850.071.jpg: 65H115833) + std::string lpnResult; + int engineType = 1; + double detectionThreshold = 0.3; + double ocrThreshold = 0.5; + double colourThreshold = 0.5; + int result = CreateANSALPRHandle(&infHandle, licenseKey.c_str(), modelZipFile.c_str(), "", engineType, detectionThreshold, ocrThreshold, colourThreshold); + std::cout << "Loading ANSLRP:" << result << std::endl; + + auto start = std::chrono::system_clock::now(); + + int loadEngine = LoadANSALPREngineHandle(&infHandle); + std::cout << "Init Result:" << result << std::endl; + auto end = std::chrono::system_clock::now(); + + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time to load engine = %lld ms\n", static_cast(elapsed.count())); + unsigned int bufferLength = 0; + std::string jpegImage; + + cv::Mat input = cv::imread(imageFilePath, cv::IMREAD_COLOR); + + cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image + image = new cv::Mat(input); // ✅ Allocate the image + ANSALPR_RunInferenceComplete_CPP(&infHandle, &image, "MyCam", 0, 0, lpnResult, jpegImage); + std::string detectionResult = lpnResult; + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(input, cv::Rect(x, y, width, height), 123, 2); + cv::putText(input, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 1.2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + delete image; + cv::resize(input, input, cv::Size(1920, 1080)); // to half size or even smaller + + cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + + cv::imshow("ANSLPR", input); + + cv::waitKey(0); + cv::destroyAllWindows(); + ReleaseANSALPRHandle(&infHandle); + return 0; +} + + +int ANSLPR_OD_INDOInferences_FileTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + ANSCENTER::ANSALPR* infHandle; + std::string licenseKey = ""; + std::string modelZipFile = "E:\\Programs\\DemoAssets\\ModelsForANSVIS\\ANS_ALPR_IND_v1.1.zip"; + std::string imageFilePath = "E:\\Programs\\TrainingWorkingStation\\IndoALPR\\Indonesian License Plate Dataset\\data\\train075.jpg";//20250912_213850.717.jpg; 20250912_213850.511.jpg;//20250912_213850.411.jpg;//20250912_213850.261.jpg(65H115912:0.73) cororect (20250912_213850.071.jpg: 65H115833) + std::string lpnResult; + int engineType = 1; + double detectionThreshold = 0.3; + double ocrThreshold = 0.5; + int result = CreateANSALPRHandle(&infHandle, licenseKey.c_str(), modelZipFile.c_str(), "", engineType, detectionThreshold, ocrThreshold, 0.5); + std::cout << "Loading ANSLRP:" << result << std::endl; + + int loadEngine = LoadANSALPREngineHandle(&infHandle); + std::cout << "Init Result:" << result << std::endl; + unsigned int bufferLength = 0; + std::string jpegImage; + + cv::Mat input = cv::imread(imageFilePath, cv::IMREAD_COLOR); + + cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image + image = new cv::Mat(input); // ✅ Allocate the image + ANSALPR_RunInferenceComplete_CPP(&infHandle, &image, "MyCam", 0, 0, lpnResult, jpegImage); + std::string detectionResult = lpnResult; + std::cout << "Result:" << detectionResult; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(input, cv::Rect(x, y, width, height), 123, 2); + cv::putText(input, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 1.2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + auto end = std::chrono::system_clock::now(); + delete image; + cv::resize(input, input, cv::Size(1920, 1080)); // to half size or even smaller + cv::namedWindow("ANSLPR", cv::WINDOW_AUTOSIZE); + cv::imshow("ANSLPR", input); + cv::waitKey(0); + cv::destroyAllWindows(); + ReleaseANSALPRHandle(&infHandle); + return 0; +} +// ============================================================================ +// Multi-GPU ALPR Stress Test — 4 parallel RTSP→ALPR tasks +// +// Purpose: Diagnose why dual RTX 5080 performs worse than single RTX 3050. +// Each task has its own RTSP reader + ALPR engine. Tasks 0-1 read stream A, +// tasks 2-3 read stream B. All 4 run in parallel threads. +// +// The display composites all 4 views into a single resizable window with a +// log panel at the bottom showing per-task stats and GPU diagnostics. +// ============================================================================ + +// Thread-safe logger: collects timestamped messages for on-screen log + file +static const char* LOG_FILE_PATH = "C:\\Temp\\ALPRdebug.txt"; + +class ThreadSafeLog { +public: + void init() { + std::lock_guard lk(m_mtx); + m_file.open(LOG_FILE_PATH, std::ios::out | std::ios::trunc); + if (m_file.is_open()) { + auto now = std::chrono::system_clock::now(); + auto t = std::chrono::system_clock::to_time_t(now); + char timeBuf[64]; + struct tm lt; + localtime_s(<, &t); + strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", <); + m_file << "================================================================\n"; + m_file << " ANSLPR Multi-GPU Stress Test Debug Log\n"; + m_file << " Started: " << timeBuf << "\n"; + m_file << " Log file: " << LOG_FILE_PATH << "\n"; + m_file << "================================================================\n\n"; + m_file.flush(); + } + } + void add(const std::string& msg) { + std::lock_guard lk(m_mtx); + // Full timestamp for file: HH:MM:SS.mmm + auto now = std::chrono::system_clock::now(); + auto t = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast( + now.time_since_epoch()).count() % 1000; + struct tm lt; + localtime_s(<, &t); + char ts[32]; + snprintf(ts, sizeof(ts), "[%02d:%02d:%02d.%03lld] ", + lt.tm_hour, lt.tm_min, lt.tm_sec, static_cast(ms)); + std::string line = std::string(ts) + msg; + m_lines.push_back(line); + if (m_lines.size() > 200) m_lines.pop_front(); + // Write to file immediately (flush so user can read mid-run) + if (m_file.is_open()) { + m_file << line << "\n"; + m_file.flush(); + } + } + std::deque getRecent(size_t n) { + std::lock_guard lk(m_mtx); + size_t start = (m_lines.size() > n) ? m_lines.size() - n : 0; + return std::deque(m_lines.begin() + start, m_lines.end()); + } + void close() { + std::lock_guard lk(m_mtx); + if (m_file.is_open()) m_file.close(); + } +private: + std::mutex m_mtx; + std::deque m_lines; + std::ofstream m_file; +}; + +// Per-task shared state (written by worker thread, read by display thread) +struct TaskState { + std::mutex mtx; + cv::Mat displayFrame; // latest frame with detections drawn + double fps = 0.0; + double inferenceMs = 0.0; + int frameCount = 0; + int detectionCount= 0; + std::string lastPlate; + bool engineLoaded = false; + bool streamOk = false; + std::string statusMsg = "Initializing..."; + // GPU resource tracking (set during engine load) + int gpuDeviceId = -1; // which GPU this task's engine landed on + size_t vramUsedBytes = 0; // VRAM consumed by this task's engine + // Grab/Inference timing (updated by worker thread) + double lastGrabMs = 0.0; + double lastInfMs = 0.0; +}; + +// Snapshot of GPU state for real-time monitoring +struct GpuSnapshot { + int deviceId = 0; + std::string name; + size_t totalMiB = 0; + size_t freeMiB = 0; + size_t usedMiB = 0; +}; + +// Query current GPU VRAM usage for all devices +static std::vector QueryGpuVram() { + std::vector snapshots; + int deviceCount = 0; + if (cudaGetDeviceCount(&deviceCount) != cudaSuccess) return snapshots; + for (int i = 0; i < deviceCount; i++) { + cudaDeviceProp prop; + cudaGetDeviceProperties(&prop, i); + int prevDevice; + cudaGetDevice(&prevDevice); + cudaSetDevice(i); + size_t freeMem = 0, totalMem = 0; + cudaMemGetInfo(&freeMem, &totalMem); + cudaSetDevice(prevDevice); + + GpuSnapshot s; + s.deviceId = i; + s.name = prop.name; + s.totalMiB = totalMem / (1024 * 1024); + s.freeMiB = freeMem / (1024 * 1024); + s.usedMiB = s.totalMiB - s.freeMiB; + snapshots.push_back(s); + } + return snapshots; +} + +// Measure per-GPU free VRAM (returns array indexed by device) +static std::vector GetPerGpuFreeMiB() { + std::vector result; + int deviceCount = 0; + if (cudaGetDeviceCount(&deviceCount) != cudaSuccess) return result; + int prevDevice; + cudaGetDevice(&prevDevice); + for (int i = 0; i < deviceCount; i++) { + cudaSetDevice(i); + size_t freeMem = 0, totalMem = 0; + cudaMemGetInfo(&freeMem, &totalMem); + result.push_back(freeMem / (1024 * 1024)); + } + cudaSetDevice(prevDevice); + return result; +} + +static std::atomic g_running{true}; +static ThreadSafeLog g_log; + +// Log GPU info using CUDA runtime +static void LogGpuInfo() { + int deviceCount = 0; + cudaError_t err = cudaGetDeviceCount(&deviceCount); + if (err != cudaSuccess) { + g_log.add("CUDA ERROR: cudaGetDeviceCount failed: " + std::string(cudaGetErrorString(err))); + printf("[GPU] CUDA ERROR: %s\n", cudaGetErrorString(err)); + return; + } + printf("============================================================\n"); + printf(" GPU DEVICE REPORT — %d device(s) detected\n", deviceCount); + printf("============================================================\n"); + g_log.add("GPU DEVICE REPORT: " + std::to_string(deviceCount) + " device(s)"); + + for (int i = 0; i < deviceCount; i++) { + cudaDeviceProp prop; + cudaGetDeviceProperties(&prop, i); + size_t freeMem = 0, totalMem = 0; + cudaSetDevice(i); + cudaMemGetInfo(&freeMem, &totalMem); + + char buf[512]; + snprintf(buf, sizeof(buf), + " GPU[%d] %s | SM %d.%d | VRAM: %.0f MiB total, %.0f MiB free", + i, prop.name, prop.major, prop.minor, + totalMem / 1048576.0, freeMem / 1048576.0); + printf("%s\n", buf); + g_log.add(buf); + + snprintf(buf, sizeof(buf), + " GPU[%d] PCIe Bus %d, Device %d | Async Engines: %d | Concurrent Kernels: %d", + i, prop.pciBusID, prop.pciDeviceID, + prop.asyncEngineCount, prop.concurrentKernels); + printf("%s\n", buf); + g_log.add(buf); + } + printf("============================================================\n"); +} + +// Worker thread: reads RTSP frames and runs ALPR inference +// RTSP client and ALPR engine are pre-created on the main thread to avoid +// race conditions in CreateANSRTSPHandle / CreateANSALPRHandle. +static void ALPRWorkerThread(int taskId, + ANSCENTER::ANSRTSPClient* rtspClient, + ANSCENTER::ANSALPR* alprHandle, + TaskState& state) { + char tag[32]; + snprintf(tag, sizeof(tag), "[Task%d]", taskId); + std::string prefix(tag); + + g_log.add(prefix + " Worker thread started"); + printf("%s Worker thread started\n", tag); + + // --- Main inference loop --- + int width = 0, height = 0; + int64_t pts = 0; + int emptyFrames = 0; + std::string cameraId = "Cam" + std::to_string(taskId); + + // FPS tracking with sliding window + std::deque fpsTimestamps; + + // Timing accumulators for periodic benchmarking + double totalGrabMs = 0, totalInfMs = 0; + int grabCount = 0, infCount = 0; + double maxGrabMs = 0, maxInfMs = 0; + auto benchStart = std::chrono::steady_clock::now(); + + bool hwDecodeLogged = false; + + while (g_running.load()) { + // Read frame from RTSP via ANSCV + auto grabStart = std::chrono::steady_clock::now(); + cv::Mat* framePtr = nullptr; + GetRTSPCVImage(&rtspClient, width, height, pts, &framePtr); + auto grabEnd = std::chrono::steady_clock::now(); + double grabMs = std::chrono::duration(grabEnd - grabStart).count(); + + if (framePtr == nullptr || framePtr->empty()) { + emptyFrames++; + if (emptyFrames % 100 == 1) { + g_log.add(prefix + " Empty frame (count=" + std::to_string(emptyFrames) + ")"); + } + if (emptyFrames > 300) { + g_log.add(prefix + " Too many empty frames, attempting reconnect..."); + ReconnectRTSP(&rtspClient); + emptyFrames = 0; + } + if (framePtr) delete framePtr; + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + emptyFrames = 0; + + // Log HW decode status once after first successful frame + if (!hwDecodeLogged) { + hwDecodeLogged = true; + int hwActive = rtspClient->IsHWDecodingActive() ? 1 : 0; + bool isCuda = rtspClient->IsCudaHWAccel(); + int hwGpu = rtspClient->GetHWDecodingGpuIndex(); + char hwBuf[256]; + const char* hwType = !hwActive ? "INACTIVE (software/CPU)" + : isCuda ? "ACTIVE (CUDA/NVDEC zero-copy)" + : "ACTIVE (D3D11VA/NVDEC cpu-nv12)"; + snprintf(hwBuf, sizeof(hwBuf), "%s HW Decode: %s (GPU index: %d)", + tag, hwType, hwGpu); + g_log.add(hwBuf); + printf("%s\n", hwBuf); + } + totalGrabMs += grabMs; + grabCount++; + if (grabMs > maxGrabMs) maxGrabMs = grabMs; + + // Run ALPR inference + auto infStart = std::chrono::steady_clock::now(); + std::string lpnResult, jpegImage; + // Pass framePtr directly — NOT a copy. ANSGpuFrameRegistry::lookup() + // matches by cv::Mat* pointer, so `new cv::Mat(*framePtr)` would create + // a different pointer the registry doesn't know, breaking NV12 zero-copy. + ANSALPR_RunInferenceComplete_CPP(&alprHandle, &framePtr, cameraId.c_str(), 0, 0, lpnResult, jpegImage); + auto infEnd = std::chrono::steady_clock::now(); + double infMs = std::chrono::duration(infEnd - infStart).count(); + totalInfMs += infMs; + infCount++; + if (infMs > maxInfMs) maxInfMs = infMs; + + // Parse detections and draw on frame + cv::Mat display = framePtr->clone(); + int detCount = 0; + std::string lastPlateText; + + if (!lpnResult.empty()) { + try { + boost::property_tree::ptree pt; + std::stringstream ss(lpnResult); + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type& child, pt.get_child("results")) { + const boost::property_tree::ptree& det = child.second; + const auto class_name = GetData(det, "class_name"); + const auto x = GetData(det, "x"); + const auto y = GetData(det, "y"); + const auto w = GetData(det, "width"); + const auto h = GetData(det, "height"); + cv::rectangle(display, cv::Rect((int)x, (int)y, (int)w, (int)h), + cv::Scalar(0, 255, 0), 2); + cv::putText(display, class_name, cv::Point((int)x, (int)y - 5), + cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2); + lastPlateText = class_name; + detCount++; + } + } + catch (...) {} + } + + // Update FPS (sliding window over last 2 seconds) + auto now = std::chrono::steady_clock::now(); + fpsTimestamps.push_back(now); + while (!fpsTimestamps.empty() && + std::chrono::duration(now - fpsTimestamps.front()).count() > 2.0) { + fpsTimestamps.pop_front(); + } + double fps = fpsTimestamps.size() / 2.0; + + // Draw OSD on frame + char osd[128]; + snprintf(osd, sizeof(osd), "Task%d | %.1f FPS | Inf: %.0f ms | #%d", + taskId, fps, infMs, state.frameCount + 1); + cv::putText(display, osd, cv::Point(10, 30), + cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 255), 2); + + // Update shared state + { + std::lock_guard lk(state.mtx); + state.displayFrame = display; + state.fps = fps; + state.inferenceMs = infMs; + state.lastGrabMs = grabMs; + state.lastInfMs = infMs; + state.frameCount++; + state.detectionCount += detCount; + if (!lastPlateText.empty()) state.lastPlate = lastPlateText; + } + + // Periodic logging (every 100 frames) + if ((state.frameCount % 100) == 0) { + double avgGrab = grabCount > 0 ? totalGrabMs / grabCount : 0; + double avgInf = infCount > 0 ? totalInfMs / infCount : 0; + double elapsed = std::chrono::duration( + std::chrono::steady_clock::now() - benchStart).count(); + + char buf[512]; + snprintf(buf, sizeof(buf), + "%s Frame %d | FPS=%.1f | Grab: avg=%.1fms max=%.0fms | Inf: avg=%.1fms max=%.0fms | " + "GrabPct=%.0f%% InfPct=%.0f%% | Det=%d", + tag, state.frameCount, fps, + avgGrab, maxGrabMs, + avgInf, maxInfMs, + (totalGrabMs / (elapsed * 1000.0)) * 100.0, + (totalInfMs / (elapsed * 1000.0)) * 100.0, + state.detectionCount); + g_log.add(buf); + printf("%s\n", buf); + + // Reset accumulators + totalGrabMs = totalInfMs = 0; + maxGrabMs = maxInfMs = 0; + grabCount = infCount = 0; + benchStart = std::chrono::steady_clock::now(); + } + + delete framePtr; + } + + g_log.add(prefix + " Worker loop exited"); +} + +int ANSLPR_MultiGPU_StressTest() { + ANSCENTER::ANSOPENCV::InitCameraNetwork(); + + // --- Initialize log file --- + g_log.init(); + + printf("\n"); + printf("============================================================\n"); + printf(" ANSLPR Multi-GPU Stress Test — 4 Parallel ALPR Tasks\n"); + printf(" Press ESC to stop\n"); + printf(" Log file: %s\n", LOG_FILE_PATH); + printf("============================================================\n\n"); + + g_log.add("============================================================"); + g_log.add(" ANSLPR Multi-GPU Stress Test — 4 Parallel ALPR Tasks"); + g_log.add("============================================================"); + + // --- Log GPU info for diagnostics --- + LogGpuInfo(); + + // --- RTSP URLs (4 independent streams, one per task) --- + const std::string rtspUrl0 = "rtsp://admin:admin123@103.156.0.133:8010/cam/realmonitor?channel=1&subtype=0"; + const std::string rtspUrl1 = "rtsp://cafe2471.ddns.net:600/rtsp/streaming?channel=01&subtype=0"; + const std::string rtspUrl2 = "rtsp://nhathuocngoclinh.zapto.org:600/rtsp/streaming?channel=01&subtype=0"; + const std::string rtspUrl3 = "rtsp://bnunitttd.ddns.net:554/rtsp/streaming?channel=01&subtype=0"; + + g_log.add("Stream 0: " + rtspUrl0); + g_log.add("Stream 1: " + rtspUrl1); + g_log.add("Stream 2: " + rtspUrl2); + g_log.add("Stream 3: " + rtspUrl3); + + // --- Task states --- + TaskState taskStates[4]; + + // ========================================================================= + // Create 4 INDEPENDENT RTSP readers — one per task, each with its own + // camera stream. Each task gets a dedicated RTSP connection. + // ========================================================================= + const int NUM_STREAMS = 4; + ANSCENTER::ANSRTSPClient* rtspClients[NUM_STREAMS] = {}; + const std::string streamUrls[NUM_STREAMS] = { rtspUrl0, rtspUrl1, rtspUrl2, rtspUrl3 }; + // Map: task index -> stream index (1:1 mapping) + const int taskStreamMap[4] = { 0, 1, 2, 3 }; + + for (int s = 0; s < NUM_STREAMS; s++) { + printf("[Stream%d] Creating RTSP handle for %s...\n", s, streamUrls[s].c_str()); + g_log.add("[Stream" + std::to_string(s) + "] Creating RTSP handle for " + streamUrls[s]); + int rtspResult = CreateANSRTSPHandle(&rtspClients[s], "", "", "", streamUrls[s].c_str()); + if (rtspResult != 1 || rtspClients[s] == nullptr) { + printf("[Stream%d] FAILED to create RTSP handle (result=%d)\n", s, rtspResult); + g_log.add("[Stream" + std::to_string(s) + "] RTSP create FAILED"); + rtspClients[s] = nullptr; + continue; + } + SetRTSPImageQuality(&rtspClients[s], 0); + SetRTSPHWDecoding(&rtspClients[s], 7); // HW_DECODING_CUDA: force CUDA/NVDEC zero-copy path + StartRTSP(&rtspClients[s]); + g_log.add("[Stream" + std::to_string(s) + "] RTSP started"); + } + + // ========================================================================= + // Create 4 ALPR engines sequentially + // ========================================================================= + ANSCENTER::ANSALPR* alprHandles[4] = {}; + std::string modelZipFile = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ANS_ALPR_v1.2.zip"; + int engineType = 1; // NVIDIA_GPU + double detThresh = 0.5, ocrThresh = 0.5, colThresh = 0.5; + + for (int i = 0; i < 4; i++) { + char tag[32]; + snprintf(tag, sizeof(tag), "[Task%d]", i); + + int streamIdx = taskStreamMap[i]; + if (rtspClients[streamIdx] == nullptr) { + printf("%s Skipped — Stream%d not available\n", tag, streamIdx); + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Stream not available"; + continue; + } + + { + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].streamOk = true; + taskStates[i].statusMsg = "Loading ALPR engine..."; + } + + printf("%s Creating ALPR handle (engineType=%d)...\n", tag, engineType); + g_log.add(std::string(tag) + " Creating ALPR handle..."); + auto engineStart = std::chrono::steady_clock::now(); + int createResult = CreateANSALPRHandle(&alprHandles[i], "", modelZipFile.c_str(), "", + engineType, detThresh, ocrThresh, colThresh); + if (createResult != 1 || alprHandles[i] == nullptr) { + printf("%s FAILED to create ALPR handle (result=%d)\n", tag, createResult); + g_log.add(std::string(tag) + " ALPR create FAILED"); + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "ALPR create failed"; + continue; + } + + printf("%s Loading ALPR engine (TensorRT)...\n", tag); + g_log.add(std::string(tag) + " Loading ALPR engine..."); + + // Snapshot VRAM before engine load to measure consumption + auto vramBefore = GetPerGpuFreeMiB(); + + int loadResult = LoadANSALPREngineHandle(&alprHandles[i]); + auto engineEnd = std::chrono::steady_clock::now(); + double loadMs = std::chrono::duration(engineEnd - engineStart).count(); + + if (loadResult != 1) { + printf("%s FAILED to load ALPR engine (result=%d)\n", tag, loadResult); + g_log.add(std::string(tag) + " Engine load FAILED"); + ReleaseANSALPRHandle(&alprHandles[i]); + alprHandles[i] = nullptr; + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Engine load failed"; + continue; + } + + // Snapshot VRAM after engine load — find which GPU lost the most VRAM + auto vramAfter = GetPerGpuFreeMiB(); + int bestGpu = 0; + size_t maxDelta = 0; + size_t gpuCount = vramBefore.size() < vramAfter.size() ? vramBefore.size() : vramAfter.size(); + for (size_t g = 0; g < gpuCount; g++) { + size_t delta = (vramBefore[g] > vramAfter[g]) ? (vramBefore[g] - vramAfter[g]) : 0; + if (delta > maxDelta) { + maxDelta = delta; + bestGpu = (int)g; + } + } + + char buf[512]; + snprintf(buf, sizeof(buf), + "%s Engine loaded in %.0f ms | GPU[%d] | VRAM used: %zu MiB (Stream%d)", + tag, loadMs, bestGpu, maxDelta, streamIdx); + printf("%s\n", buf); + g_log.add(buf); + + // Log per-GPU VRAM state after this engine load + for (size_t g = 0; g < vramAfter.size(); g++) { + size_t total = 0; + if (g < vramBefore.size()) { + // Compute total from free + used + auto gpus = QueryGpuVram(); + if (g < gpus.size()) total = gpus[g].totalMiB; + } + char vbuf[256]; + snprintf(vbuf, sizeof(vbuf), + " GPU[%zu] VRAM: %zu MiB free (of %zu MiB)", + g, vramAfter[g], total); + printf("%s\n", vbuf); + g_log.add(vbuf); + } + + { + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].engineLoaded = true; + taskStates[i].statusMsg = "Running"; + taskStates[i].gpuDeviceId = bestGpu; + taskStates[i].vramUsedBytes = maxDelta * 1024 * 1024; + } + } + + // --- Align NVDEC decode GPU with inference GPU for NV12 zero-copy --- + // Each stream should decode on the same GPU as its inference engine to enable + // direct NVDEC→TensorRT zero-copy (0.5ms vs 17ms preprocess per frame). + // + // Strategy: For each stream, count how many tasks run on each GPU (vote). + // Pick the GPU with the most tasks → maximises the number of NV12 zero-copy hits. + // If tied, prefer to keep the current decode GPU to avoid a reconnect. + // Additional tie-breaker: distribute streams across GPUs for decode load balance. + { + int streamPreferredGpu[NUM_STREAMS]; + for (int s = 0; s < NUM_STREAMS; s++) streamPreferredGpu[s] = -1; + + // Track how many streams have already been assigned to each GPU (for tie-breaking) + std::map gpuStreamCount; + + for (int s = 0; s < NUM_STREAMS; s++) { + if (!rtspClients[s]) continue; + + // Count votes: how many tasks on this stream use each GPU + std::map gpuVotes; + for (int i = 0; i < 4; i++) { + if (taskStreamMap[i] == s && alprHandles[i]) { + gpuVotes[taskStates[i].gpuDeviceId]++; + } + } + if (gpuVotes.empty()) continue; + + // Find the GPU with the most votes + int currentGpu = rtspClients[s]->GetHWDecodingGpuIndex(); + int bestGpu = -1; + int bestVotes = 0; + for (auto& [gpu, votes] : gpuVotes) { + if (votes > bestVotes) { + bestVotes = votes; + bestGpu = gpu; + } else if (votes == bestVotes) { + // Tie-break 1: prefer current decode GPU (avoids reconnect) + if (gpu == currentGpu && bestGpu != currentGpu) { + bestGpu = gpu; + } + // Tie-break 2: prefer GPU with fewer streams assigned (load balance) + else if (bestGpu != currentGpu && gpu != currentGpu) { + if (gpuStreamCount[gpu] < gpuStreamCount[bestGpu]) { + bestGpu = gpu; + } + } + } + } + + streamPreferredGpu[s] = bestGpu; + gpuStreamCount[bestGpu]++; + + char buf[512]; + std::string voteStr; + for (auto& [gpu, votes] : gpuVotes) { + if (!voteStr.empty()) voteStr += ", "; + voteStr += "GPU[" + std::to_string(gpu) + "]=" + std::to_string(votes); + } + snprintf(buf, sizeof(buf), + "[Stream%d] GPU vote: {%s} -> preferred GPU[%d] (current: GPU[%d])", + s, voteStr.c_str(), bestGpu, currentGpu); + g_log.add(buf); + printf("%s\n", buf); + } + + // Apply alignment: reconnect streams whose NVDEC is on the wrong GPU. + // IMPORTANT: If currentGpu == -1, the decoder hasn't initialized yet. + // Do NOT reconnect — it disrupts the initial RTSP handshake and causes + // 80+ seconds of empty frames. Just set preferredGpu; the decoder will + // use it when it naturally initializes. + for (int s = 0; s < NUM_STREAMS; s++) { + if (rtspClients[s] && streamPreferredGpu[s] >= 0) { + int currentGpu = rtspClients[s]->GetHWDecodingGpuIndex(); + if (currentGpu < 0) { + // Decoder not yet initialized — set preferred GPU without reconnect + SetRTSPHWDecoding(&rtspClients[s], 7, streamPreferredGpu[s]); + char buf[256]; + snprintf(buf, sizeof(buf), + "[Stream%d] NVDEC not yet initialized (GPU[-1]) -- set preferred GPU[%d] (no reconnect)", + s, streamPreferredGpu[s]); + g_log.add(buf); + printf("%s\n", buf); + } else if (currentGpu != streamPreferredGpu[s]) { + // Decoder is active on wrong GPU — reconnect to move it + SetRTSPHWDecoding(&rtspClients[s], 7, streamPreferredGpu[s]); + ReconnectRTSP(&rtspClients[s]); + char buf[256]; + snprintf(buf, sizeof(buf), + "[Stream%d] NVDEC GPU realigned: GPU[%d] -> GPU[%d] (reconnected for zero-copy)", + s, currentGpu, streamPreferredGpu[s]); + g_log.add(buf); + printf("%s\n", buf); + } else { + char buf[256]; + snprintf(buf, sizeof(buf), + "[Stream%d] NVDEC GPU already on GPU[%d] (zero-copy OK)", + s, currentGpu); + g_log.add(buf); + printf("%s\n", buf); + } + } + } + } + + // --- Enable deep pipeline benchmarking on all ALPR handles --- + for (int i = 0; i < 4; i++) { + if (alprHandles[i]) { + alprHandles[i]->ActivateDebugger(true); + } + } + g_log.add("Debug benchmarking ENABLED on all ALPR handles"); + + // --- Launch worker threads — tasks sharing a stream get the same RTSP client --- + g_log.add("Launching worker threads..."); + std::thread workers[4]; + for (int i = 0; i < 4; i++) { + int streamIdx = taskStreamMap[i]; + if (rtspClients[streamIdx] && alprHandles[i]) { + workers[i] = std::thread(ALPRWorkerThread, i, + rtspClients[streamIdx], alprHandles[i], + std::ref(taskStates[i])); + } + } + + // --- Display loop (main thread) --- + const int cellW = 640, cellH = 480; + const int logPanelH = 200; + cv::namedWindow("ANSLPR Multi-GPU Stress Test", cv::WINDOW_NORMAL); + cv::resizeWindow("ANSLPR Multi-GPU Stress Test", cellW * 2, cellH * 2 + logPanelH); + + auto testStart = std::chrono::steady_clock::now(); + auto lastGpuSnapshot = std::chrono::steady_clock::now(); + int snapshotCount = 0; + + while (g_running.load()) { + // --- Periodic GPU/perf snapshot every 10 seconds (written to log file) --- + auto now2 = std::chrono::steady_clock::now(); + if (std::chrono::duration(now2 - lastGpuSnapshot).count() >= 10.0) { + lastGpuSnapshot = now2; + snapshotCount++; + double elapsedSec = std::chrono::duration(now2 - testStart).count(); + g_log.add("---- PERIODIC SNAPSHOT #" + std::to_string(snapshotCount) + + " (elapsed " + std::to_string((int)elapsedSec) + "s) ----"); + // GPU VRAM + auto gpuSnap = QueryGpuVram(); + for (const auto& gs : gpuSnap) { + char buf[256]; + snprintf(buf, sizeof(buf), + " GPU[%d] %s | Used: %zu/%zu MiB (%.1f%%)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + gs.totalMiB > 0 ? 100.0 * gs.usedMiB / gs.totalMiB : 0.0); + g_log.add(buf); + } + // Per-task stats + double totalFpsSnap = 0; + for (int t = 0; t < 4; t++) { + std::lock_guard lk(taskStates[t].mtx); + char buf[256]; + snprintf(buf, sizeof(buf), + " T%d: GPU[%d] VRAM=%zuMiB FPS=%.1f GrabMs=%.0f InfMs=%.0f Frames=%d Det=%d", + t, taskStates[t].gpuDeviceId, + taskStates[t].vramUsedBytes / (1024 * 1024), + taskStates[t].fps, taskStates[t].lastGrabMs, taskStates[t].inferenceMs, + taskStates[t].frameCount, taskStates[t].detectionCount); + g_log.add(buf); + totalFpsSnap += taskStates[t].fps; + } + char buf[128]; + snprintf(buf, sizeof(buf), " Total throughput: %.1f FPS", totalFpsSnap); + g_log.add(buf); + // Multi-GPU check + std::set gpusUsed; + for (int t = 0; t < 4; t++) { + if (taskStates[t].gpuDeviceId >= 0) gpusUsed.insert(taskStates[t].gpuDeviceId); + } + if (gpusUsed.size() > 1) { + g_log.add(" MULTI-GPU: YES — tasks distributed across " + std::to_string(gpusUsed.size()) + " GPUs"); + } else if (!gpusUsed.empty()) { + g_log.add(" MULTI-GPU: NO — all tasks on GPU[" + std::to_string(*gpusUsed.begin()) + "]"); + } + g_log.add("---- END SNAPSHOT ----"); + } + // Build 2x2 grid + log panel + cv::Mat canvas(cellH * 2 + logPanelH, cellW * 2, CV_8UC3, cv::Scalar(30, 30, 30)); + + // Place each task's frame in its quadrant + for (int i = 0; i < 4; i++) { + int row = i / 2, col = i % 2; + 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; + size_t vramMiB = 0; + std::string statusMsg, lastPlate; + bool engineLoaded = false, streamOk = false; + { + std::lock_guard 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; + statusMsg = taskStates[i].statusMsg; + lastPlate = taskStates[i].lastPlate; + engineLoaded = taskStates[i].engineLoaded; + streamOk = taskStates[i].streamOk; + gpuId = taskStates[i].gpuDeviceId; + vramMiB = taskStates[i].vramUsedBytes / (1024 * 1024); + } + + 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); + } + + // Draw status bar at bottom of each cell (2 lines) + cv::rectangle(cell, cv::Rect(0, cellH - 50, cellW, 50), cv::Scalar(0, 0, 0), cv::FILLED); + char bar1[256], bar2[256]; + snprintf(bar1, sizeof(bar1), "T%d | %.1f FPS | %.0fms | Frames:%d | Det:%d | %s", + i, fps, infMs, fCount, dCount, + lastPlate.empty() ? "-" : lastPlate.c_str()); + if (gpuId >= 0) { + snprintf(bar2, sizeof(bar2), "GPU[%d] | VRAM: %zu MiB", gpuId, vramMiB); + } else { + snprintf(bar2, sizeof(bar2), "GPU: N/A"); + } + cv::Scalar barColor = engineLoaded ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 100, 255); + cv::putText(cell, bar1, cv::Point(5, cellH - 28), + cv::FONT_HERSHEY_SIMPLEX, 0.45, barColor, 1); + cv::putText(cell, bar2, cv::Point(5, cellH - 8), + cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(0, 200, 255), 1); + + cell.copyTo(canvas(roi)); + + // Draw grid lines + cv::line(canvas, cv::Point(cellW, 0), cv::Point(cellW, cellH * 2), + cv::Scalar(100, 100, 100), 1); + cv::line(canvas, cv::Point(0, cellH), cv::Point(cellW * 2, cellH), + cv::Scalar(100, 100, 100), 1); + } + + // --- Log panel at bottom --- + cv::Rect logRoi(0, cellH * 2, cellW * 2, logPanelH); + cv::Mat logPanel = canvas(logRoi); + logPanel.setTo(cv::Scalar(20, 20, 20)); + + // Elapsed time header + auto elapsed = std::chrono::duration(std::chrono::steady_clock::now() - testStart).count(); + char header[128]; + snprintf(header, sizeof(header), + "Elapsed: %.0fs | Press ESC to stop | Resize window freely", elapsed); + cv::putText(logPanel, header, cv::Point(10, 18), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(200, 200, 0), 1); + + // Aggregate stats + per-task GPU summary + double totalFps = 0; + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + totalFps += taskStates[i].fps; + } + char aggLine[256]; + snprintf(aggLine, sizeof(aggLine), "Total throughput: %.1f FPS | T0:GPU%d T1:GPU%d T2:GPU%d T3:GPU%d", + totalFps, + taskStates[0].gpuDeviceId, taskStates[1].gpuDeviceId, + taskStates[2].gpuDeviceId, taskStates[3].gpuDeviceId); + cv::putText(logPanel, aggLine, cv::Point(10, 38), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 255), 1); + + // Real-time GPU VRAM monitor (query every frame — cheap call) + auto gpuSnaps = QueryGpuVram(); + int gpuLineY = 58; + for (const auto& gs : gpuSnaps) { + // Count tasks on this GPU and their total VRAM + int tasksOnGpu = 0; + size_t taskVramMiB = 0; + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + if (taskStates[i].gpuDeviceId == gs.deviceId) { + tasksOnGpu++; + taskVramMiB += taskStates[i].vramUsedBytes / (1024 * 1024); + } + } + char gpuLine[256]; + snprintf(gpuLine, sizeof(gpuLine), + "GPU[%d] %s | Used: %zu/%zu MiB | Tasks: %d (engine VRAM: %zu MiB)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + tasksOnGpu, taskVramMiB); + cv::putText(logPanel, gpuLine, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(100, 255, 100), 1); + gpuLineY += 18; + } + + // Per-task resource line + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + char tLine[256]; + snprintf(tLine, sizeof(tLine), + "T%d: GPU[%d] VRAM=%zuMiB FPS=%.1f Inf=%.0fms Frames=%d Det=%d", + i, taskStates[i].gpuDeviceId, + taskStates[i].vramUsedBytes / (1024 * 1024), + taskStates[i].fps, taskStates[i].inferenceMs, + taskStates[i].frameCount, taskStates[i].detectionCount); + cv::putText(logPanel, tLine, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(200, 200, 200), 1); + gpuLineY += 16; + } + + // Recent log lines (remaining space) + auto recentLogs = g_log.getRecent(4); + for (const auto& line : recentLogs) { + if (gpuLineY > logPanelH - 5) break; + std::string display = (line.size() > 130) ? line.substr(0, 127) + "..." : line; + cv::putText(logPanel, display, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_PLAIN, 1.0, cv::Scalar(140, 140, 140), 1); + gpuLineY += 15; + } + + cv::imshow("ANSLPR Multi-GPU Stress Test", canvas); + int key = cv::waitKey(30); + if (key == 27) { // ESC + g_log.add("ESC pressed — stopping all tasks..."); + printf("\nESC pressed — stopping...\n"); + g_running.store(false); + } + } + + // --- Wait for all workers --- + printf("Waiting for worker threads to finish...\n"); + for (int i = 0; i < 4; i++) { + if (workers[i].joinable()) workers[i].join(); + } + + // --- Print final summary (console + log file) --- + double totalElapsed = std::chrono::duration( + std::chrono::steady_clock::now() - testStart).count(); + + g_log.add("================================================================"); + g_log.add(" FINAL PERFORMANCE SUMMARY"); + g_log.add(" Total runtime: " + std::to_string((int)totalElapsed) + " seconds"); + g_log.add("================================================================"); + + printf("\n============================================================\n"); + printf(" FINAL PERFORMANCE SUMMARY (runtime: %.0fs)\n", totalElapsed); + printf("============================================================\n"); + + double totalFpsFinal = 0; + for (int i = 0; i < 4; i++) { + char buf[512]; + snprintf(buf, sizeof(buf), + " Task %d: GPU[%d] | VRAM=%zuMiB | %d frames, %d detections, FPS=%.1f, InfMs=%.0f", + i, taskStates[i].gpuDeviceId, + taskStates[i].vramUsedBytes / (1024 * 1024), + taskStates[i].frameCount, taskStates[i].detectionCount, + taskStates[i].fps, taskStates[i].inferenceMs); + printf("%s\n", buf); + g_log.add(buf); + totalFpsFinal += taskStates[i].fps; + } + + auto finalGpu = QueryGpuVram(); + for (const auto& gs : finalGpu) { + char buf[256]; + snprintf(buf, sizeof(buf), " GPU[%d] %s: %zu/%zu MiB used (%.1f%%)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + gs.totalMiB > 0 ? 100.0 * gs.usedMiB / gs.totalMiB : 0.0); + printf("%s\n", buf); + g_log.add(buf); + } + + // Multi-GPU verdict + std::set finalGpusUsed; + for (int i = 0; i < 4; i++) { + if (taskStates[i].gpuDeviceId >= 0) finalGpusUsed.insert(taskStates[i].gpuDeviceId); + } + { + char buf[256]; + snprintf(buf, sizeof(buf), " Total throughput: %.1f FPS across 4 tasks", totalFpsFinal); + printf("%s\n", buf); + g_log.add(buf); + } + if (finalGpusUsed.size() > 1) { + char buf[128]; + snprintf(buf, sizeof(buf), " MULTI-GPU: YES — tasks on %zu different GPUs", finalGpusUsed.size()); + printf("%s\n", buf); + g_log.add(buf); + } else if (!finalGpusUsed.empty()) { + char buf[128]; + snprintf(buf, sizeof(buf), " MULTI-GPU: NO — all tasks on GPU[%d] only", *finalGpusUsed.begin()); + printf("%s\n", buf); + g_log.add(buf); + g_log.add(" DIAGNOSIS: Engine pool sees only 1 GPU. On dual-GPU systems, check:"); + g_log.add(" 1. Both GPUs visible to CUDA (nvidia-smi shows 2 devices)"); + g_log.add(" 2. TRT engine files are compatible with both GPU architectures"); + g_log.add(" 3. No CUDA_VISIBLE_DEVICES env var restricting GPU access"); + } + + printf("============================================================\n"); + g_log.add("================================================================"); + g_log.add(" Log saved to: " + std::string(LOG_FILE_PATH)); + g_log.add("================================================================"); + + // --- Release all handles (sequentially on main thread) --- + for (int i = 0; i < 4; i++) { + if (alprHandles[i]) { + ReleaseANSALPRHandle(&alprHandles[i]); + } + } + for (int s = 0; s < NUM_STREAMS; s++) { + if (rtspClients[s]) { + StopRTSP(&rtspClients[s]); + ReleaseANSRTSPHandle(&rtspClients[s]); + } + } + + g_log.close(); + cv::destroyAllWindows(); + ANSCENTER::ANSOPENCV::DeinitCameraNetwork(); + + return 0; +} + +// ============================================================================= +// VideoPlayer-based worker thread for SimulatedCam stress test +// Same structure as ALPRWorkerThread but uses ANSVideoPlayer instead of ANSRTSP +// ============================================================================= +static void ALPRWorkerThread_VideoPlayer(int taskId, + ANSCENTER::ANSVIDEOPLAYER* vpClient, + ANSCENTER::ANSALPR* alprHandle, + TaskState& state) { + char tag[32]; + snprintf(tag, sizeof(tag), "[Task%d]", taskId); + std::string prefix(tag); + + g_log.add(prefix + " Worker thread started"); + printf("%s Worker thread started\n", tag); + + int width = 0, height = 0; + int64_t pts = 0; + int emptyFrames = 0; + std::string cameraId = "Cam" + std::to_string(taskId); + + // FPS tracking with sliding window + std::deque fpsTimestamps; + + // Timing accumulators for periodic benchmarking + double totalGrabMs = 0, totalInfMs = 0; + int grabCount = 0, infCount = 0; + double maxGrabMs = 0, maxInfMs = 0; + auto benchStart = std::chrono::steady_clock::now(); + + while (g_running.load()) { + // Read frame from VideoPlayer + auto grabStart = std::chrono::steady_clock::now(); + cv::Mat* framePtr = nullptr; + GetVideoPlayerCVImage(&vpClient, width, height, pts, &framePtr); + auto grabEnd = std::chrono::steady_clock::now(); + double grabMs = std::chrono::duration(grabEnd - grabStart).count(); + + if (framePtr == nullptr || framePtr->empty()) { + emptyFrames++; + if (emptyFrames % 100 == 1) { + g_log.add(prefix + " Empty frame (count=" + std::to_string(emptyFrames) + ")"); + } + if (emptyFrames > 300) { + g_log.add(prefix + " Too many empty frames, attempting reconnect..."); + ReconnectVideoPlayer(&vpClient); + emptyFrames = 0; + } + if (framePtr) delete framePtr; + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + emptyFrames = 0; + + totalGrabMs += grabMs; + grabCount++; + if (grabMs > maxGrabMs) maxGrabMs = grabMs; + + // Run ALPR inference + auto infStart = std::chrono::steady_clock::now(); + std::string lpnResult, jpegImage; + // Pass framePtr directly — NOT a copy. ANSGpuFrameRegistry::lookup() + // matches by cv::Mat* pointer, so `new cv::Mat(*framePtr)` would create + // a different pointer the registry doesn't know, breaking NV12 zero-copy. + ANSALPR_RunInferenceComplete_CPP(&alprHandle, &framePtr, cameraId.c_str(), 0, 0, lpnResult, jpegImage); + auto infEnd = std::chrono::steady_clock::now(); + double infMs = std::chrono::duration(infEnd - infStart).count(); + totalInfMs += infMs; + infCount++; + if (infMs > maxInfMs) maxInfMs = infMs; + + // Parse detections and draw on frame + cv::Mat display = framePtr->clone(); + int detCount = 0; + std::string lastPlateText; + + if (!lpnResult.empty()) { + try { + boost::property_tree::ptree pt; + std::stringstream ss(lpnResult); + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type& child, pt.get_child("results")) { + const boost::property_tree::ptree& det = child.second; + const auto class_name = GetData(det, "class_name"); + const auto x = GetData(det, "x"); + const auto y = GetData(det, "y"); + const auto w = GetData(det, "width"); + const auto h = GetData(det, "height"); + cv::rectangle(display, cv::Rect((int)x, (int)y, (int)w, (int)h), + cv::Scalar(0, 255, 0), 2); + cv::putText(display, class_name, cv::Point((int)x, (int)y - 5), + cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2); + lastPlateText = class_name; + detCount++; + } + } + catch (...) {} + } + + // Update FPS (sliding window over last 2 seconds) + auto now = std::chrono::steady_clock::now(); + fpsTimestamps.push_back(now); + while (!fpsTimestamps.empty() && + std::chrono::duration(now - fpsTimestamps.front()).count() > 2.0) { + fpsTimestamps.pop_front(); + } + double fps = fpsTimestamps.size() / 2.0; + + // Draw OSD on frame + char osd[128]; + snprintf(osd, sizeof(osd), "Task%d | %.1f FPS | Inf: %.0f ms | #%d", + taskId, fps, infMs, state.frameCount + 1); + cv::putText(display, osd, cv::Point(10, 30), + cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 255), 2); + + // Update shared state + { + std::lock_guard lk(state.mtx); + state.displayFrame = display; + state.fps = fps; + state.inferenceMs = infMs; + state.lastGrabMs = grabMs; + state.lastInfMs = infMs; + state.frameCount++; + state.detectionCount += detCount; + if (!lastPlateText.empty()) state.lastPlate = lastPlateText; + } + + // Periodic logging (every 100 frames) + if ((state.frameCount % 100) == 0) { + double avgGrab = grabCount > 0 ? totalGrabMs / grabCount : 0; + double avgInf = infCount > 0 ? totalInfMs / infCount : 0; + double elapsed = std::chrono::duration( + std::chrono::steady_clock::now() - benchStart).count(); + + char buf[512]; + snprintf(buf, sizeof(buf), + "%s Frame %d | FPS=%.1f | Grab: avg=%.1fms max=%.0fms | Inf: avg=%.1fms max=%.0fms | " + "GrabPct=%.0f%% InfPct=%.0f%% | Det=%d", + tag, state.frameCount, fps, + avgGrab, maxGrabMs, + avgInf, maxInfMs, + (totalGrabMs / (elapsed * 1000.0)) * 100.0, + (totalInfMs / (elapsed * 1000.0)) * 100.0, + state.detectionCount); + g_log.add(buf); + printf("%s\n", buf); + + // Reset accumulators + totalGrabMs = totalInfMs = 0; + maxGrabMs = maxInfMs = 0; + grabCount = infCount = 0; + benchStart = std::chrono::steady_clock::now(); + } + + delete framePtr; + } + + g_log.add(prefix + " Worker loop exited"); +} + +// ============================================================================= +// ANSLPR_MultiGPU_StressTest_SimulatedCam +// Same structure as ANSLPR_MultiGPU_StressTest but uses local video files +// via ANSVideoPlayer instead of live RTSP streams. +// ============================================================================= +int ANSLPR_MultiGPU_StressTest_SimulatedCam() { + ANSCENTER::ANSOPENCV::InitCameraNetwork(); + + // --- Initialize log file --- + g_log.init(); + + printf("\n"); + printf("============================================================\n"); + printf(" ANSLPR Multi-GPU Stress Test (Simulated Cam)\n"); + printf(" Using local video files via ANSVideoPlayer\n"); + printf(" Press ESC to stop\n"); + printf(" Log file: %s\n", LOG_FILE_PATH); + printf("============================================================\n\n"); + + g_log.add("============================================================"); + g_log.add(" ANSLPR Multi-GPU Stress Test (Simulated Cam)"); + g_log.add(" Using ANSVideoPlayer with local video files"); + g_log.add("============================================================"); + + // --- Log GPU info for diagnostics --- + LogGpuInfo(); + + // --- Video file paths (4 files, one per task) --- + const std::string videoFile0 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day.mp4"; + const std::string videoFile1 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day_1.mp4"; + const std::string videoFile2 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day_2.mp4"; + const std::string videoFile3 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day_3.mp4"; + + g_log.add("Video 0: " + videoFile0); + g_log.add("Video 1: " + videoFile1); + g_log.add("Video 2: " + videoFile2); + g_log.add("Video 3: " + videoFile3); + + // --- Task states --- + TaskState taskStates[4]; + + // ========================================================================= + // Create 4 VideoPlayer readers — one per task + // ========================================================================= + const int NUM_STREAMS = 4; + ANSCENTER::ANSVIDEOPLAYER* vpClients[NUM_STREAMS] = {}; + const std::string videoFiles[NUM_STREAMS] = { videoFile0, videoFile1, videoFile2, videoFile3 }; + const int taskStreamMap[4] = { 0, 1, 2, 3 }; + + for (int s = 0; s < NUM_STREAMS; s++) { + printf("[Stream%d] Creating VideoPlayer for %s\n", s, videoFiles[s].c_str()); + g_log.add("[Stream" + std::to_string(s) + "] Creating VideoPlayer for " + videoFiles[s]); + int result = CreateANSVideoPlayerHandle(&vpClients[s], "", videoFiles[s].c_str()); + if (result != 1 || vpClients[s] == nullptr) { + printf("[Stream%d] FAILED to create VideoPlayer (result=%d)\n", s, result); + g_log.add("[Stream" + std::to_string(s) + "] VideoPlayer create FAILED"); + vpClients[s] = nullptr; + continue; + } + // Don't call StartVideoPlayer here — play() will be called just before worker threads + // launch, so the video doesn't play to completion during the ~16s engine loading phase. + SetVideoPlayerDisplayResolution(&vpClients[s], 1920, 1080); + g_log.add("[Stream" + std::to_string(s) + "] VideoPlayer created (display: 1920x1080)"); + } + + // ========================================================================= + // Create 4 ALPR engines sequentially + // ========================================================================= + ANSCENTER::ANSALPR* alprHandles[4] = {}; + std::string modelZipFile = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ANS_ALPR_v1.2.zip"; + int engineType = 1; // NVIDIA_GPU + double detThresh = 0.5, ocrThresh = 0.5, colThresh = 0.5; + + for (int i = 0; i < 4; i++) { + char tag[32]; + snprintf(tag, sizeof(tag), "[Task%d]", i); + + int streamIdx = taskStreamMap[i]; + if (vpClients[streamIdx] == nullptr) { + printf("%s Skipped — Stream%d not available\n", tag, streamIdx); + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Stream not available"; + continue; + } + + { + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].streamOk = true; + taskStates[i].statusMsg = "Loading ALPR engine..."; + } + + printf("%s Creating ALPR handle (engineType=%d)...\n", tag, engineType); + g_log.add(std::string(tag) + " Creating ALPR handle..."); + auto engineStart = std::chrono::steady_clock::now(); + int createResult = CreateANSALPRHandle(&alprHandles[i], "", modelZipFile.c_str(), "", + engineType, detThresh, ocrThresh, colThresh); + if (createResult != 1 || alprHandles[i] == nullptr) { + printf("%s FAILED to create ALPR handle (result=%d)\n", tag, createResult); + g_log.add(std::string(tag) + " ALPR create FAILED"); + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "ALPR create failed"; + continue; + } + + printf("%s Loading ALPR engine (TensorRT)...\n", tag); + g_log.add(std::string(tag) + " Loading ALPR engine..."); + + // Snapshot VRAM before engine load to measure consumption + auto vramBefore = GetPerGpuFreeMiB(); + + int loadResult = LoadANSALPREngineHandle(&alprHandles[i]); + auto engineEnd = std::chrono::steady_clock::now(); + double loadMs = std::chrono::duration(engineEnd - engineStart).count(); + + if (loadResult != 1) { + printf("%s FAILED to load ALPR engine (result=%d)\n", tag, loadResult); + g_log.add(std::string(tag) + " Engine load FAILED"); + ReleaseANSALPRHandle(&alprHandles[i]); + alprHandles[i] = nullptr; + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Engine load failed"; + continue; + } + + // Snapshot VRAM after engine load — find which GPU lost the most VRAM + auto vramAfter = GetPerGpuFreeMiB(); + int bestGpu = 0; + size_t maxDelta = 0; + size_t gpuCount = vramBefore.size() < vramAfter.size() ? vramBefore.size() : vramAfter.size(); + for (size_t g = 0; g < gpuCount; g++) { + size_t delta = (vramBefore[g] > vramAfter[g]) ? (vramBefore[g] - vramAfter[g]) : 0; + if (delta > maxDelta) { + maxDelta = delta; + bestGpu = (int)g; + } + } + + char buf[512]; + snprintf(buf, sizeof(buf), + "%s Engine loaded in %.0f ms | GPU[%d] | VRAM used: %zu MiB (Video%d)", + tag, loadMs, bestGpu, maxDelta, streamIdx); + printf("%s\n", buf); + g_log.add(buf); + + // Log per-GPU VRAM state after this engine load + for (size_t g = 0; g < vramAfter.size(); g++) { + size_t total = 0; + if (g < vramBefore.size()) { + auto gpus = QueryGpuVram(); + if (g < gpus.size()) total = gpus[g].totalMiB; + } + char vbuf[256]; + snprintf(vbuf, sizeof(vbuf), + " GPU[%zu] VRAM: %zu MiB free (of %zu MiB)", + g, vramAfter[g], total); + printf("%s\n", vbuf); + g_log.add(vbuf); + } + + { + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].engineLoaded = true; + taskStates[i].statusMsg = "Running"; + taskStates[i].gpuDeviceId = bestGpu; + taskStates[i].vramUsedBytes = maxDelta * 1024 * 1024; + } + } + + // --- No NVDEC realignment needed — ANSVideoPlayer uses cv::VideoCapture (CPU decode) --- + + // --- Enable deep pipeline benchmarking on all ALPR handles --- + for (int i = 0; i < 4; i++) { + if (alprHandles[i]) { + alprHandles[i]->ActivateDebugger(true); + } + } + g_log.add("Debug benchmarking ENABLED on all ALPR handles"); + + // --- Start video playback NOW (just before workers need frames) --- + // This avoids the video playing to completion during the ~16s engine loading phase. + for (int s = 0; s < NUM_STREAMS; s++) { + if (vpClients[s]) { + StartVideoPlayer(&vpClients[s]); + g_log.add("[Stream" + std::to_string(s) + "] VideoPlayer play() started"); + } + } + + // --- Launch worker threads --- + g_log.add("Launching worker threads..."); + std::thread workers[4]; + for (int i = 0; i < 4; i++) { + int streamIdx = taskStreamMap[i]; + if (vpClients[streamIdx] && alprHandles[i]) { + workers[i] = std::thread(ALPRWorkerThread_VideoPlayer, i, + vpClients[streamIdx], alprHandles[i], + std::ref(taskStates[i])); + } + } + + // --- Display loop (main thread) --- + const int cellW = 640, cellH = 480; + const int logPanelH = 200; + const char* windowName = "ANSLPR Multi-GPU Stress Test (Simulated Cam)"; + cv::namedWindow(windowName, cv::WINDOW_NORMAL); + cv::resizeWindow(windowName, cellW * 2, cellH * 2 + logPanelH); + + auto testStart = std::chrono::steady_clock::now(); + auto lastGpuSnapshot = std::chrono::steady_clock::now(); + int snapshotCount = 0; + + while (g_running.load()) { + // --- Periodic GPU/perf snapshot every 10 seconds --- + auto now2 = std::chrono::steady_clock::now(); + if (std::chrono::duration(now2 - lastGpuSnapshot).count() >= 10.0) { + lastGpuSnapshot = now2; + snapshotCount++; + double elapsedSec = std::chrono::duration(now2 - testStart).count(); + g_log.add("---- PERIODIC SNAPSHOT #" + std::to_string(snapshotCount) + + " (elapsed " + std::to_string((int)elapsedSec) + "s) ----"); + auto gpuSnap = QueryGpuVram(); + for (const auto& gs : gpuSnap) { + char buf[256]; + snprintf(buf, sizeof(buf), + " GPU[%d] %s | Used: %zu/%zu MiB (%.1f%%)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + gs.totalMiB > 0 ? 100.0 * gs.usedMiB / gs.totalMiB : 0.0); + g_log.add(buf); + } + double totalFpsSnap = 0; + for (int t = 0; t < 4; t++) { + std::lock_guard lk(taskStates[t].mtx); + char buf[256]; + snprintf(buf, sizeof(buf), + " T%d: GPU[%d] VRAM=%zuMiB FPS=%.1f GrabMs=%.0f InfMs=%.0f Frames=%d Det=%d", + t, taskStates[t].gpuDeviceId, + taskStates[t].vramUsedBytes / (1024 * 1024), + taskStates[t].fps, taskStates[t].lastGrabMs, taskStates[t].inferenceMs, + taskStates[t].frameCount, taskStates[t].detectionCount); + g_log.add(buf); + totalFpsSnap += taskStates[t].fps; + } + char buf[128]; + snprintf(buf, sizeof(buf), " Total throughput: %.1f FPS", totalFpsSnap); + g_log.add(buf); + std::set gpusUsed; + for (int t = 0; t < 4; t++) { + if (taskStates[t].gpuDeviceId >= 0) gpusUsed.insert(taskStates[t].gpuDeviceId); + } + if (gpusUsed.size() > 1) { + g_log.add(" MULTI-GPU: YES — tasks distributed across " + std::to_string(gpusUsed.size()) + " GPUs"); + } else if (!gpusUsed.empty()) { + g_log.add(" MULTI-GPU: NO — all tasks on GPU[" + std::to_string(*gpusUsed.begin()) + "]"); + } + g_log.add("---- END SNAPSHOT ----"); + } + + // Build 2x2 grid + log panel + cv::Mat canvas(cellH * 2 + logPanelH, cellW * 2, CV_8UC3, cv::Scalar(30, 30, 30)); + + for (int i = 0; i < 4; i++) { + int row = i / 2, col = i % 2; + 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; + size_t vramMiB = 0; + std::string statusMsg, lastPlate; + bool engineLoaded = false, streamOk = false; + { + std::lock_guard 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; + statusMsg = taskStates[i].statusMsg; + lastPlate = taskStates[i].lastPlate; + engineLoaded = taskStates[i].engineLoaded; + streamOk = taskStates[i].streamOk; + gpuId = taskStates[i].gpuDeviceId; + vramMiB = taskStates[i].vramUsedBytes / (1024 * 1024); + } + + 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); + } + + cv::rectangle(cell, cv::Rect(0, cellH - 50, cellW, 50), cv::Scalar(0, 0, 0), cv::FILLED); + char bar1[256], bar2[256]; + snprintf(bar1, sizeof(bar1), "T%d | %.1f FPS | %.0fms | Frames:%d | Det:%d | %s", + i, fps, infMs, fCount, dCount, + lastPlate.empty() ? "-" : lastPlate.c_str()); + if (gpuId >= 0) { + snprintf(bar2, sizeof(bar2), "GPU[%d] | VRAM: %zu MiB", gpuId, vramMiB); + } else { + snprintf(bar2, sizeof(bar2), "GPU: N/A"); + } + cv::Scalar barColor = engineLoaded ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 100, 255); + cv::putText(cell, bar1, cv::Point(5, cellH - 28), + cv::FONT_HERSHEY_SIMPLEX, 0.45, barColor, 1); + cv::putText(cell, bar2, cv::Point(5, cellH - 8), + cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(0, 200, 255), 1); + + cell.copyTo(canvas(roi)); + + cv::line(canvas, cv::Point(cellW, 0), cv::Point(cellW, cellH * 2), + cv::Scalar(100, 100, 100), 1); + cv::line(canvas, cv::Point(0, cellH), cv::Point(cellW * 2, cellH), + cv::Scalar(100, 100, 100), 1); + } + + // --- Log panel at bottom --- + cv::Rect logRoi(0, cellH * 2, cellW * 2, logPanelH); + cv::Mat logPanel = canvas(logRoi); + logPanel.setTo(cv::Scalar(20, 20, 20)); + + auto elapsed = std::chrono::duration(std::chrono::steady_clock::now() - testStart).count(); + char header[128]; + snprintf(header, sizeof(header), + "Elapsed: %.0fs | Simulated Cam (VideoPlayer) | Press ESC to stop", elapsed); + cv::putText(logPanel, header, cv::Point(10, 18), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(200, 200, 0), 1); + + double totalFps = 0; + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + totalFps += taskStates[i].fps; + } + char aggLine[256]; + snprintf(aggLine, sizeof(aggLine), "Total throughput: %.1f FPS | T0:GPU%d T1:GPU%d T2:GPU%d T3:GPU%d", + totalFps, + taskStates[0].gpuDeviceId, taskStates[1].gpuDeviceId, + taskStates[2].gpuDeviceId, taskStates[3].gpuDeviceId); + cv::putText(logPanel, aggLine, cv::Point(10, 38), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 255), 1); + + auto gpuSnaps = QueryGpuVram(); + int gpuLineY = 58; + for (const auto& gs : gpuSnaps) { + int tasksOnGpu = 0; + size_t taskVramMiB = 0; + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + if (taskStates[i].gpuDeviceId == gs.deviceId) { + tasksOnGpu++; + taskVramMiB += taskStates[i].vramUsedBytes / (1024 * 1024); + } + } + char gpuLine[256]; + snprintf(gpuLine, sizeof(gpuLine), + "GPU[%d] %s | Used: %zu/%zu MiB | Tasks: %d (engine VRAM: %zu MiB)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + tasksOnGpu, taskVramMiB); + cv::putText(logPanel, gpuLine, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(100, 255, 100), 1); + gpuLineY += 18; + } + + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + char tLine[256]; + snprintf(tLine, sizeof(tLine), + "T%d: GPU[%d] VRAM=%zuMiB FPS=%.1f Inf=%.0fms Frames=%d Det=%d", + i, taskStates[i].gpuDeviceId, + taskStates[i].vramUsedBytes / (1024 * 1024), + taskStates[i].fps, taskStates[i].inferenceMs, + taskStates[i].frameCount, taskStates[i].detectionCount); + cv::putText(logPanel, tLine, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(200, 200, 200), 1); + gpuLineY += 16; + } + + auto recentLogs = g_log.getRecent(4); + for (const auto& line : recentLogs) { + if (gpuLineY > logPanelH - 5) break; + std::string display = (line.size() > 130) ? line.substr(0, 127) + "..." : line; + cv::putText(logPanel, display, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_PLAIN, 1.0, cv::Scalar(140, 140, 140), 1); + gpuLineY += 15; + } + + cv::imshow(windowName, canvas); + int key = cv::waitKey(30); + if (key == 27) { // ESC + g_log.add("ESC pressed — stopping all tasks..."); + printf("\nESC pressed — stopping...\n"); + g_running.store(false); + } + } + + // --- Wait for all workers --- + printf("Waiting for worker threads to finish...\n"); + for (int i = 0; i < 4; i++) { + if (workers[i].joinable()) workers[i].join(); + } + + // --- Print final summary --- + double totalElapsed = std::chrono::duration( + std::chrono::steady_clock::now() - testStart).count(); + + g_log.add("================================================================"); + g_log.add(" FINAL PERFORMANCE SUMMARY (Simulated Cam)"); + g_log.add(" Total runtime: " + std::to_string((int)totalElapsed) + " seconds"); + g_log.add("================================================================"); + + printf("\n============================================================\n"); + printf(" FINAL PERFORMANCE SUMMARY — Simulated Cam (runtime: %.0fs)\n", totalElapsed); + printf("============================================================\n"); + + double totalFpsFinal = 0; + for (int i = 0; i < 4; i++) { + char buf[512]; + snprintf(buf, sizeof(buf), + " Task %d: GPU[%d] | VRAM=%zuMiB | %d frames, %d detections, FPS=%.1f, InfMs=%.0f", + i, taskStates[i].gpuDeviceId, + taskStates[i].vramUsedBytes / (1024 * 1024), + taskStates[i].frameCount, taskStates[i].detectionCount, + taskStates[i].fps, taskStates[i].inferenceMs); + printf("%s\n", buf); + g_log.add(buf); + totalFpsFinal += taskStates[i].fps; + } + + auto finalGpu = QueryGpuVram(); + for (const auto& gs : finalGpu) { + char buf[256]; + snprintf(buf, sizeof(buf), " GPU[%d] %s: %zu/%zu MiB used (%.1f%%)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + gs.totalMiB > 0 ? 100.0 * gs.usedMiB / gs.totalMiB : 0.0); + printf("%s\n", buf); + g_log.add(buf); + } + + std::set finalGpusUsed; + for (int i = 0; i < 4; i++) { + if (taskStates[i].gpuDeviceId >= 0) finalGpusUsed.insert(taskStates[i].gpuDeviceId); + } + { + char buf[256]; + snprintf(buf, sizeof(buf), " Total throughput: %.1f FPS across 4 tasks", totalFpsFinal); + printf("%s\n", buf); + g_log.add(buf); + } + if (finalGpusUsed.size() > 1) { + char buf[128]; + snprintf(buf, sizeof(buf), " MULTI-GPU: YES — tasks on %zu different GPUs", finalGpusUsed.size()); + printf("%s\n", buf); + g_log.add(buf); + } else if (!finalGpusUsed.empty()) { + char buf[128]; + snprintf(buf, sizeof(buf), " MULTI-GPU: NO — all tasks on GPU[%d] only", *finalGpusUsed.begin()); + printf("%s\n", buf); + g_log.add(buf); + } + + printf("============================================================\n"); + g_log.add("================================================================"); + g_log.add(" Log saved to: " + std::string(LOG_FILE_PATH)); + g_log.add("================================================================"); + + // --- Release all handles --- + for (int i = 0; i < 4; i++) { + if (alprHandles[i]) { + ReleaseANSALPRHandle(&alprHandles[i]); + } + } + for (int s = 0; s < NUM_STREAMS; s++) { + if (vpClients[s]) { + StopVideoPlayer(&vpClients[s]); + ReleaseANSVideoPlayerHandle(&vpClients[s]); + } + } + + g_log.close(); + cv::destroyAllWindows(); + ANSCENTER::ANSOPENCV::DeinitCameraNetwork(); + + return 0; +} + +// ============================================================================= +// Worker thread for FilePlayer-based stress test (uses ANSFILEPLAYER) +// Key difference from VideoPlayer worker: uses GetFilePlayerCVImage/ReconnectFilePlayer +// ============================================================================= +static void ALPRWorkerThread_FilePlayer(int taskId, + ANSCENTER::ANSFILEPLAYER* fpClient, + ANSCENTER::ANSALPR* alprHandle, + TaskState& state) { + char tag[32]; + snprintf(tag, sizeof(tag), "[Task%d]", taskId); + std::string prefix(tag); + + g_log.add(prefix + " Worker thread started"); + printf("%s Worker thread started\n", tag); + + int width = 0, height = 0; + int64_t pts = 0; + int emptyFrames = 0; + std::string cameraId = "Cam" + std::to_string(taskId); + + std::deque fpsTimestamps; + double totalGrabMs = 0, totalInfMs = 0; + int grabCount = 0, infCount = 0; + double maxGrabMs = 0, maxInfMs = 0; + auto benchStart = std::chrono::steady_clock::now(); + + while (g_running.load()) { + auto grabStart = std::chrono::steady_clock::now(); + cv::Mat* framePtr = nullptr; + GetFilePlayerCVImage(&fpClient, width, height, pts, &framePtr); + auto grabEnd = std::chrono::steady_clock::now(); + double grabMs = std::chrono::duration(grabEnd - grabStart).count(); + + if (framePtr == nullptr || framePtr->empty()) { + emptyFrames++; + if (emptyFrames % 100 == 1) { + g_log.add(prefix + " Empty frame (count=" + std::to_string(emptyFrames) + ")"); + } + if (emptyFrames > 300) { + g_log.add(prefix + " Too many empty frames, attempting reconnect..."); + ReconnectFilePlayer(&fpClient); + emptyFrames = 0; + } + if (framePtr) delete framePtr; + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + emptyFrames = 0; + + totalGrabMs += grabMs; + grabCount++; + if (grabMs > maxGrabMs) maxGrabMs = grabMs; + + auto infStart = std::chrono::steady_clock::now(); + std::string lpnResult, jpegImage; + // Pass framePtr directly — NOT a copy. ANSGpuFrameRegistry::lookup() + // matches by cv::Mat* pointer, so `new cv::Mat(*framePtr)` would create + // a different pointer the registry doesn't know, breaking NV12 zero-copy. + ANSALPR_RunInferenceComplete_CPP(&alprHandle, &framePtr, cameraId.c_str(), 0, 0, lpnResult, jpegImage); + auto infEnd = std::chrono::steady_clock::now(); + double infMs = std::chrono::duration(infEnd - infStart).count(); + totalInfMs += infMs; + infCount++; + if (infMs > maxInfMs) maxInfMs = infMs; + + cv::Mat display = framePtr->clone(); + int detCount = 0; + std::string lastPlateText; + + if (!lpnResult.empty()) { + try { + boost::property_tree::ptree pt; + std::stringstream ss(lpnResult); + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type& child, pt.get_child("results")) { + const boost::property_tree::ptree& det = child.second; + const auto class_name = GetData(det, "class_name"); + const auto x = GetData(det, "x"); + const auto y = GetData(det, "y"); + const auto w = GetData(det, "width"); + const auto h = GetData(det, "height"); + cv::rectangle(display, cv::Rect((int)x, (int)y, (int)w, (int)h), + cv::Scalar(0, 255, 0), 2); + cv::putText(display, class_name, cv::Point((int)x, (int)y - 5), + cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2); + lastPlateText = class_name; + detCount++; + } + } + catch (...) {} + } + + auto now = std::chrono::steady_clock::now(); + fpsTimestamps.push_back(now); + while (!fpsTimestamps.empty() && + std::chrono::duration(now - fpsTimestamps.front()).count() > 2.0) { + fpsTimestamps.pop_front(); + } + double fps = fpsTimestamps.size() / 2.0; + + char osd[128]; + snprintf(osd, sizeof(osd), "Task%d | %.1f FPS | Inf: %.0f ms | #%d", + taskId, fps, infMs, state.frameCount + 1); + cv::putText(display, osd, cv::Point(10, 30), + cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 255), 2); + + { + std::lock_guard lk(state.mtx); + state.displayFrame = display; + state.fps = fps; + state.inferenceMs = infMs; + state.lastGrabMs = grabMs; + state.lastInfMs = infMs; + state.frameCount++; + state.detectionCount += detCount; + if (!lastPlateText.empty()) state.lastPlate = lastPlateText; + } + + if ((state.frameCount % 100) == 0) { + double avgGrab = grabCount > 0 ? totalGrabMs / grabCount : 0; + double avgInf = infCount > 0 ? totalInfMs / infCount : 0; + double elapsed = std::chrono::duration( + std::chrono::steady_clock::now() - benchStart).count(); + + char buf[512]; + snprintf(buf, sizeof(buf), + "%s Frame %d | FPS=%.1f | Grab: avg=%.1fms max=%.0fms | Inf: avg=%.1fms max=%.0fms | " + "GrabPct=%.0f%% InfPct=%.0f%% | Det=%d", + tag, state.frameCount, fps, + avgGrab, maxGrabMs, + avgInf, maxInfMs, + (totalGrabMs / (elapsed * 1000.0)) * 100.0, + (totalInfMs / (elapsed * 1000.0)) * 100.0, + state.detectionCount); + g_log.add(buf); + printf("%s\n", buf); + + totalGrabMs = totalInfMs = 0; + maxGrabMs = maxInfMs = 0; + grabCount = infCount = 0; + benchStart = std::chrono::steady_clock::now(); + } + + delete framePtr; + } + + g_log.add(prefix + " Worker loop exited"); +} + +// ============================================================================= +// ANSLPR_MultiGPU_StressTest_FilePlayer +// Same as SimulatedCam but uses ANSFILEPLAYER (loops video continuously). +// ============================================================================= +int ANSLPR_MultiGPU_StressTest_FilePlayer() { + ANSCENTER::ANSOPENCV::InitCameraNetwork(); + g_log.init(); + + printf("\n"); + printf("============================================================\n"); + printf(" ANSLPR Multi-GPU Stress Test (FilePlayer — looping)\n"); + printf(" Using local video files via ANSFilePlayer (HW decode)\n"); + printf(" Press ESC to stop\n"); + printf(" Log file: %s\n", LOG_FILE_PATH); + printf("============================================================\n\n"); + + g_log.add("============================================================"); + g_log.add(" ANSLPR Multi-GPU Stress Test (FilePlayer — looping)"); + g_log.add(" Using ANSFilePlayer with HW decode + NV12 zero-copy"); + g_log.add("============================================================"); + + LogGpuInfo(); + + const std::string videoFile0 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day.mp4"; + const std::string videoFile1 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day_1.mp4"; + const std::string videoFile2 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day_2.mp4"; + const std::string videoFile3 = "E:\\Programs\\DemoAssets\\Videos\\ALRP\\PMH\\Day\\day_3.mp4"; + + g_log.add("Video 0: " + videoFile0); + g_log.add("Video 1: " + videoFile1); + g_log.add("Video 2: " + videoFile2); + g_log.add("Video 3: " + videoFile3); + + TaskState taskStates[4]; + + // ========================================================================= + // Create 4 FilePlayer readers + // ========================================================================= + const int NUM_STREAMS = 4; + ANSCENTER::ANSFILEPLAYER* fpClients[NUM_STREAMS] = {}; + const std::string videoFiles[NUM_STREAMS] = { videoFile0, videoFile1, videoFile2, videoFile3 }; + const int taskStreamMap[4] = { 0, 1, 2, 3 }; + + for (int s = 0; s < NUM_STREAMS; s++) { + printf("[Stream%d] Creating FilePlayer for %s\n", s, videoFiles[s].c_str()); + g_log.add("[Stream" + std::to_string(s) + "] Creating FilePlayer for " + videoFiles[s]); + int result = CreateANSFilePlayerHandle(&fpClients[s], "", videoFiles[s].c_str()); + if (result != 1 || fpClients[s] == nullptr) { + printf("[Stream%d] FAILED to create FilePlayer (result=%d)\n", s, result); + g_log.add("[Stream" + std::to_string(s) + "] FilePlayer create FAILED"); + fpClients[s] = nullptr; + continue; + } + // Don't start yet — start after engines are loaded + SetFilePlayerDisplayResolution(&fpClients[s], 1920, 1080); + g_log.add("[Stream" + std::to_string(s) + "] FilePlayer created (display: 1920x1080)"); + } + + // ========================================================================= + // Create 4 ALPR engines sequentially + // ========================================================================= + ANSCENTER::ANSALPR* alprHandles[4] = {}; + std::string modelZipFile = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\ANSALPR\\ANS_ALPR_v1.2.zip"; + int engineType = 1; + double detThresh = 0.5, ocrThresh = 0.5, colThresh = 0.5; + + for (int i = 0; i < 4; i++) { + char tag[32]; + snprintf(tag, sizeof(tag), "[Task%d]", i); + + int streamIdx = taskStreamMap[i]; + if (fpClients[streamIdx] == nullptr) { + printf("%s Skipped — Stream%d not available\n", tag, streamIdx); + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Stream not available"; + continue; + } + + { + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].streamOk = true; + taskStates[i].statusMsg = "Loading ALPR engine..."; + } + + printf("%s Creating ALPR handle (engineType=%d)...\n", tag, engineType); + g_log.add(std::string(tag) + " Creating ALPR handle..."); + auto engineStart = std::chrono::steady_clock::now(); + int createResult = CreateANSALPRHandle(&alprHandles[i], "", modelZipFile.c_str(), "", + engineType, detThresh, ocrThresh, colThresh); + if (createResult != 1 || alprHandles[i] == nullptr) { + printf("%s FAILED to create ALPR handle (result=%d)\n", tag, createResult); + g_log.add(std::string(tag) + " ALPR create FAILED"); + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "ALPR create failed"; + continue; + } + + printf("%s Loading ALPR engine (TensorRT)...\n", tag); + g_log.add(std::string(tag) + " Loading ALPR engine..."); + + auto vramBefore = GetPerGpuFreeMiB(); + int loadResult = LoadANSALPREngineHandle(&alprHandles[i]); + auto engineEnd = std::chrono::steady_clock::now(); + double loadMs = std::chrono::duration(engineEnd - engineStart).count(); + + if (loadResult != 1) { + printf("%s FAILED to load ALPR engine (result=%d)\n", tag, loadResult); + g_log.add(std::string(tag) + " Engine load FAILED"); + ReleaseANSALPRHandle(&alprHandles[i]); + alprHandles[i] = nullptr; + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Engine 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; } + } + + char ebuf[256]; + snprintf(ebuf, sizeof(ebuf), "%s Engine loaded in %d ms | GPU[%d] | VRAM used: %zu MiB (Video%d)", + tag, (int)loadMs, bestGpu, maxDelta, i); + printf("%s\n", ebuf); + g_log.add(ebuf); + + for (size_t g = 0; g < vramAfter.size(); g++) { + size_t total = 0; + cudaDeviceProp prop; + if (cudaGetDeviceProperties(&prop, (int)g) == cudaSuccess) { + total = prop.totalGlobalMem / (1024 * 1024); + } + char vbuf[128]; + snprintf(vbuf, sizeof(vbuf), " GPU[%zu] VRAM: %zu MiB free (of %zu MiB)", g, vramAfter[g], total); + printf("%s\n", vbuf); + g_log.add(vbuf); + } + + { + std::lock_guard lk(taskStates[i].mtx); + taskStates[i].engineLoaded = true; + taskStates[i].statusMsg = "Running"; + taskStates[i].gpuDeviceId = bestGpu; + taskStates[i].vramUsedBytes = maxDelta * 1024 * 1024; + } + } + + // --- Enable debug benchmarking --- + for (int i = 0; i < 4; i++) { + if (alprHandles[i]) { + alprHandles[i]->ActivateDebugger(true); + } + } + g_log.add("Debug benchmarking ENABLED on all ALPR handles"); + + // --- Start video playback NOW (just before workers need frames) --- + for (int s = 0; s < NUM_STREAMS; s++) { + if (fpClients[s]) { + StartFilePlayer(&fpClients[s]); + g_log.add("[Stream" + std::to_string(s) + "] FilePlayer play() started"); + } + } + + // --- Launch worker threads --- + g_log.add("Launching worker threads..."); + std::thread workers[4]; + for (int i = 0; i < 4; i++) { + int streamIdx = taskStreamMap[i]; + if (fpClients[streamIdx] && alprHandles[i]) { + workers[i] = std::thread(ALPRWorkerThread_FilePlayer, i, + fpClients[streamIdx], alprHandles[i], + std::ref(taskStates[i])); + } + } + + // --- Display loop (main thread) --- + const int cellW = 640, cellH = 480; + const int logPanelH = 200; + const char* windowName = "ANSLPR Stress Test (FilePlayer — looping)"; + cv::namedWindow(windowName, cv::WINDOW_NORMAL); + cv::resizeWindow(windowName, cellW * 2, cellH * 2 + logPanelH); + + auto testStart = std::chrono::steady_clock::now(); + auto lastGpuSnapshot = std::chrono::steady_clock::now(); + int snapshotCount = 0; + + while (g_running.load()) { + auto now2 = std::chrono::steady_clock::now(); + if (std::chrono::duration(now2 - lastGpuSnapshot).count() >= 10.0) { + lastGpuSnapshot = now2; + snapshotCount++; + double elapsedSec = std::chrono::duration(now2 - testStart).count(); + g_log.add("---- PERIODIC SNAPSHOT #" + std::to_string(snapshotCount) + + " (elapsed " + std::to_string((int)elapsedSec) + "s) ----"); + auto gpuSnap = QueryGpuVram(); + for (const auto& gs : gpuSnap) { + char buf[256]; + snprintf(buf, sizeof(buf), + " GPU[%d] %s | Used: %zu/%zu MiB (%.1f%%)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + gs.totalMiB > 0 ? 100.0 * gs.usedMiB / gs.totalMiB : 0.0); + g_log.add(buf); + } + double totalFpsSnap = 0; + for (int t = 0; t < 4; t++) { + std::lock_guard lk(taskStates[t].mtx); + char buf[256]; + snprintf(buf, sizeof(buf), + " T%d: GPU[%d] VRAM=%zuMiB FPS=%.1f GrabMs=%.0f InfMs=%.0f Frames=%d Det=%d", + t, taskStates[t].gpuDeviceId, + taskStates[t].vramUsedBytes / (1024 * 1024), + taskStates[t].fps, taskStates[t].lastGrabMs, taskStates[t].inferenceMs, + taskStates[t].frameCount, taskStates[t].detectionCount); + g_log.add(buf); + totalFpsSnap += taskStates[t].fps; + } + char buf[128]; + snprintf(buf, sizeof(buf), " Total throughput: %.1f FPS", totalFpsSnap); + g_log.add(buf); + std::set gpusUsed; + for (int t = 0; t < 4; t++) { + if (taskStates[t].gpuDeviceId >= 0) gpusUsed.insert(taskStates[t].gpuDeviceId); + } + if (gpusUsed.size() > 1) { + g_log.add(" MULTI-GPU: YES — tasks distributed across " + std::to_string(gpusUsed.size()) + " GPUs"); + } else if (!gpusUsed.empty()) { + g_log.add(" MULTI-GPU: NO — all tasks on GPU[" + std::to_string(*gpusUsed.begin()) + "]"); + } + g_log.add("---- END SNAPSHOT ----"); + } + + // Build 2x2 grid + log panel + cv::Mat canvas(cellH * 2 + logPanelH, cellW * 2, CV_8UC3, cv::Scalar(30, 30, 30)); + + for (int i = 0; i < 4; i++) { + int row = i / 2, col = i % 2; + 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; + size_t vramMiB = 0; + std::string statusMsg, lastPlate; + bool engineLoaded = false, streamOk = false; + { + std::lock_guard 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; + statusMsg = taskStates[i].statusMsg; + lastPlate = taskStates[i].lastPlate; + engineLoaded = taskStates[i].engineLoaded; + streamOk = taskStates[i].streamOk; + gpuId = taskStates[i].gpuDeviceId; + vramMiB = taskStates[i].vramUsedBytes / (1024 * 1024); + } + + 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); + } + + cv::rectangle(cell, cv::Rect(0, cellH - 50, cellW, 50), cv::Scalar(0, 0, 0), cv::FILLED); + char bar1[256], bar2[256]; + snprintf(bar1, sizeof(bar1), "T%d | %.1f FPS | %.0fms | Frames:%d | Det:%d | %s", + i, fps, infMs, fCount, dCount, + lastPlate.empty() ? "-" : lastPlate.c_str()); + if (gpuId >= 0) { + snprintf(bar2, sizeof(bar2), "GPU[%d] | VRAM: %zu MiB", gpuId, vramMiB); + } else { + snprintf(bar2, sizeof(bar2), "GPU: N/A"); + } + cv::Scalar barColor = engineLoaded ? cv::Scalar(0, 255, 0) : cv::Scalar(0, 100, 255); + cv::putText(cell, bar1, cv::Point(5, cellH - 28), + cv::FONT_HERSHEY_SIMPLEX, 0.45, barColor, 1); + cv::putText(cell, bar2, cv::Point(5, cellH - 8), + cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(0, 200, 255), 1); + + cell.copyTo(canvas(roi)); + + cv::line(canvas, cv::Point(cellW, 0), cv::Point(cellW, cellH * 2), + cv::Scalar(100, 100, 100), 1); + cv::line(canvas, cv::Point(0, cellH), cv::Point(cellW * 2, cellH), + cv::Scalar(100, 100, 100), 1); + } + + // Log panel + cv::Rect logRoi(0, cellH * 2, cellW * 2, logPanelH); + cv::Mat logPanel = canvas(logRoi); + logPanel.setTo(cv::Scalar(20, 20, 20)); + + auto elapsed = std::chrono::duration(std::chrono::steady_clock::now() - testStart).count(); + char header[128]; + snprintf(header, sizeof(header), + "Elapsed: %.0fs | FilePlayer (looping, HW decode) | Press ESC to stop", elapsed); + cv::putText(logPanel, header, cv::Point(10, 18), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(200, 200, 0), 1); + + double totalFps = 0; + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + totalFps += taskStates[i].fps; + } + char aggLine[256]; + snprintf(aggLine, sizeof(aggLine), "Total throughput: %.1f FPS | T0:GPU%d T1:GPU%d T2:GPU%d T3:GPU%d", + totalFps, + taskStates[0].gpuDeviceId, taskStates[1].gpuDeviceId, + taskStates[2].gpuDeviceId, taskStates[3].gpuDeviceId); + cv::putText(logPanel, aggLine, cv::Point(10, 38), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 255), 1); + + auto gpuSnaps = QueryGpuVram(); + int gpuLineY = 58; + for (const auto& gs : gpuSnaps) { + int tasksOnGpu = 0; + size_t taskVramMiB = 0; + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + if (taskStates[i].gpuDeviceId == gs.deviceId) { + tasksOnGpu++; + taskVramMiB += taskStates[i].vramUsedBytes / (1024 * 1024); + } + } + char gpuLine[256]; + snprintf(gpuLine, sizeof(gpuLine), + "GPU[%d] %s | Used: %zu/%zu MiB | Tasks: %d (engine VRAM: %zu MiB)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + tasksOnGpu, taskVramMiB); + cv::putText(logPanel, gpuLine, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_SIMPLEX, 0.45, cv::Scalar(100, 255, 100), 1); + gpuLineY += 18; + } + + for (int i = 0; i < 4; i++) { + std::lock_guard lk(taskStates[i].mtx); + char tLine[256]; + snprintf(tLine, sizeof(tLine), + "T%d: GPU[%d] VRAM=%zuMiB FPS=%.1f Inf=%.0fms Frames=%d Det=%d", + i, taskStates[i].gpuDeviceId, + taskStates[i].vramUsedBytes / (1024 * 1024), + taskStates[i].fps, taskStates[i].inferenceMs, + taskStates[i].frameCount, taskStates[i].detectionCount); + cv::putText(logPanel, tLine, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(200, 200, 200), 1); + gpuLineY += 16; + } + + auto recentLogs = g_log.getRecent(4); + for (const auto& line : recentLogs) { + if (gpuLineY > logPanelH - 5) break; + std::string display = (line.size() > 130) ? line.substr(0, 127) + "..." : line; + cv::putText(logPanel, display, cv::Point(10, gpuLineY), + cv::FONT_HERSHEY_PLAIN, 1.0, cv::Scalar(140, 140, 140), 1); + gpuLineY += 15; + } + + cv::imshow(windowName, canvas); + int key = cv::waitKey(30); + if (key == 27) { + g_log.add("ESC pressed — stopping all tasks..."); + printf("\nESC pressed — stopping...\n"); + g_running.store(false); + } + } + + // --- Wait for all workers --- + printf("Waiting for worker threads to finish...\n"); + for (int i = 0; i < 4; i++) { + if (workers[i].joinable()) workers[i].join(); + } + + // --- Final summary --- + double totalElapsed = std::chrono::duration( + std::chrono::steady_clock::now() - testStart).count(); + + g_log.add("================================================================"); + g_log.add(" FINAL PERFORMANCE SUMMARY (FilePlayer — looping)"); + g_log.add(" Total runtime: " + std::to_string((int)totalElapsed) + " seconds"); + g_log.add("================================================================"); + + printf("\n============================================================\n"); + printf(" FINAL PERFORMANCE SUMMARY — FilePlayer (runtime: %.0fs)\n", totalElapsed); + printf("============================================================\n"); + + double totalFpsFinal = 0; + for (int i = 0; i < 4; i++) { + char buf[512]; + snprintf(buf, sizeof(buf), + " Task %d: GPU[%d] | VRAM=%zuMiB | %d frames, %d detections, FPS=%.1f, InfMs=%.0f", + i, taskStates[i].gpuDeviceId, + taskStates[i].vramUsedBytes / (1024 * 1024), + taskStates[i].frameCount, taskStates[i].detectionCount, + taskStates[i].fps, taskStates[i].inferenceMs); + printf("%s\n", buf); + g_log.add(buf); + totalFpsFinal += taskStates[i].fps; + } + + auto finalGpu = QueryGpuVram(); + for (const auto& gs : finalGpu) { + char buf[256]; + snprintf(buf, sizeof(buf), " GPU[%d] %s: %zu/%zu MiB used (%.1f%%)", + gs.deviceId, gs.name.c_str(), gs.usedMiB, gs.totalMiB, + gs.totalMiB > 0 ? 100.0 * gs.usedMiB / gs.totalMiB : 0.0); + printf("%s\n", buf); + g_log.add(buf); + } + + { + char buf[256]; + snprintf(buf, sizeof(buf), " Total throughput: %.1f FPS across 4 tasks", totalFpsFinal); + printf("%s\n", buf); + g_log.add(buf); + } + + printf("============================================================\n"); + g_log.add("================================================================"); + + // --- Release all handles --- + for (int i = 0; i < 4; i++) { + if (alprHandles[i]) { + ReleaseANSALPRHandle(&alprHandles[i]); + } + } + for (int s = 0; s < NUM_STREAMS; s++) { + if (fpClients[s]) { + StopFilePlayer(&fpClients[s]); + ReleaseANSFilePlayerHandle(&fpClients[s]); + } + } + + g_log.close(); + cv::destroyAllWindows(); + ANSCENTER::ANSOPENCV::DeinitCameraNetwork(); + + return 0; +} + +int main() +{ + // ANSLPR_OD_INDOInferences_FileTest(); + //ANSLPR_OD_Inferences_FileTest(); + //ANSLPR_OD_VideoTest(); + //ANSLPR_BigSize_VideoTest(); + //ANSLPR_CPU_VideoTest(); + //for (int i = 0; i < 100; i++) { + // ANSLPR_CPU_Inferences_FileTest(); + //} + ANSLPR_MultiGPU_StressTest(); + //ANSLPR_MultiGPU_StressTest_SimulatedCam(); + //ANSLPR_MultiGPU_StressTest_FilePlayer(); + return 0; + +} + + diff --git a/tests/ANSLPR-UnitTest/CMakeLists.txt b/tests/ANSLPR-UnitTest/CMakeLists.txt new file mode 100644 index 0000000..27dd83a --- /dev/null +++ b/tests/ANSLPR-UnitTest/CMakeLists.txt @@ -0,0 +1,52 @@ +# ANSLPR Unit Test +add_executable(ANSLPR-UnitTest + ANSLPR-UnitTest.cpp +) + +target_include_directories(ANSLPR-UnitTest PRIVATE + ${CMAKE_SOURCE_DIR}/modules/ANSLPR + ${CMAKE_SOURCE_DIR}/modules/ANSLPR/include + ${CMAKE_SOURCE_DIR}/modules/ANSODEngine + ${CMAKE_SOURCE_DIR}/modules/ANSCV + ${CMAKE_SOURCE_DIR}/MediaClient + ${CMAKE_SOURCE_DIR}/MediaClient/media + ${CMAKE_SOURCE_DIR}/MediaClient/rtsp + ${CMAKE_SOURCE_DIR}/MediaClient/rtp + ${CMAKE_SOURCE_DIR}/MediaClient/bm + ${CMAKE_SOURCE_DIR}/MediaClient/http + ${CMAKE_SOURCE_DIR}/MediaClient/directx + ${CMAKE_SOURCE_DIR}/MediaClient/rtmp + ${CMAKE_SOURCE_DIR}/MediaClient/librtmp + ${CMAKE_SOURCE_DIR}/MediaClient/srt + ${CMAKE_SOURCE_DIR}/MediaClient/ffmpeg/include + ${CMAKE_SOURCE_DIR}/MediaClient/openssl/include + ${CMAKE_SOURCE_DIR}/MediaClient/libsrt/include + ${ANLS_ROOT}/TurboJpeg + ${CMAKE_SOURCE_DIR}/modules/ANSMOT + ${CMAKE_SOURCE_DIR}/modules/ANSOCR/ANSPaddleOCR + ${CMAKE_SOURCE_DIR}/modules/ANSOCR/ANSPaddleOCR/include + ${CMAKE_SOURCE_DIR}/engines/ONNXEngine + ${CMAKE_SOURCE_DIR}/engines/OpenVINOEngine/include + ${CMAKE_SOURCE_DIR}/engines/TensorRTAPI/include + ${SHARED_INCLUDE_DIR} +) + +target_link_libraries(ANSLPR-UnitTest + PRIVATE ANSLPR + PRIVATE ANSODEngine + PRIVATE ANSCV + PRIVATE ANSLicensingSystem + PRIVATE anslicensing + PRIVATE ANSMOT + PRIVATE opencv + PRIVATE onnxruntime + PRIVATE openvino + PRIVATE boost + PRIVATE CUDA::cudart +) + +if(WIN32) + target_link_libraries(ANSLPR-UnitTest PRIVATE ${WIN_COMMON_LIBS}) +endif() + +target_compile_definitions(ANSLPR-UnitTest PRIVATE UNICODE _UNICODE) diff --git a/tests/ANSOCR-UnitTest/ANSOCR-UnitTest.cpp b/tests/ANSOCR-UnitTest/ANSOCR-UnitTest.cpp new file mode 100644 index 0000000..f6ef0d5 --- /dev/null +++ b/tests/ANSOCR-UnitTest/ANSOCR-UnitTest.cpp @@ -0,0 +1,404 @@ +#include +#include +#include "boost/property_tree/ptree.hpp" +#include "boost/property_tree/json_parser.hpp" +#include "boost/foreach.hpp" +#include "boost/optional.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +using namespace cv; +template +T GetData(const boost::property_tree::ptree& pt, const std::string& key) +{ + T ret; + if (boost::optional data = pt.get_optional(key)) + { + ret = data.get(); + } + return ret; +} +unsigned char* CVMatToBytes(cv::Mat image, unsigned int& bufferLengh) +{ + int size = int(image.total() * image.elemSize()); + std::cout << "size:" << size << std::endl; + unsigned char* bytes = new unsigned char[size]; // you will have to delete[] that later + std::memcpy(bytes, image.data, size * sizeof(unsigned char)); + bufferLengh = size * sizeof(unsigned char); + return bytes; +} +int TestOCRImage() { + + ANSCENTER::ANSOCRBase* infHandle = nullptr; + + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::filesystem::path currentPath = std::filesystem::current_path(); + std::cout << "Current working directory: " << currentPath << std::endl; + std::string licenseKey = ""; + std::string modelFilePath = currentPath.string() + "\\ansocrmodels.zip"; + std::string imagePath = currentPath.string() + "\\ocrsample.png"; + std::string defaultDir = "C:\\Programs\\DemoAssets\\ANSAIModels"; + if (!std::filesystem::exists(modelFilePath)) modelFilePath = defaultDir + "\\ANS_GenericOCR_v1.0.zip"; + if (!std::filesystem::exists(imagePath)) imagePath = defaultDir + "\\ocrsample.png"; + imagePath = "C:\\Projects\\ANSVIS\\Documentation\\TestImages\\OCR\\ocrsample.png"; + + int language = 0; // CUSTOM + int engine = 0; + + int createResult = CreateANSOCRHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), "", language, engine); + std::cout << "ANSOCR Engine Creation:" << createResult << std::endl; + + cv::Mat input = cv::imread(imagePath, cv::IMREAD_COLOR); + cv::Mat frame = input.clone(); + int height = frame.rows; + int width = frame.cols; + unsigned int bufferLength = 0; + unsigned char* jpeg_string = CVMatToBytes(frame, bufferLength); + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + std::cout << "Result:" << detectionResult; + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 2.0, cv::Scalar(0, 0, 255), 3, cv::LINE_AA); + } + } + cv::resize(frame, frame, cv::Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + frame.release(); + + + ReleaseANSOCRHandle(&infHandle); + return 0; + +} + +int ANSOCR_VideoTest() { + // Get the current working directory + std::filesystem::path currentPath = std::filesystem::current_path(); + // Print the current working directory + std::cout << "Current working directory: " << currentPath << std::endl; + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + + ANSCENTER::ANSOCRBase* infHandle; + std::string licenseKey = ""; + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOCR_v1.0.zip"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\ALRP\\ALPR1.mp4"; + cv::VideoCapture capture(videoFilePath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + int language = 0;// CUSTOM + int engine = 0; + int createResult = CreateANSOCRHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), "", language, engine); + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s", class_name), cv::Point(x, y - 5), + 0, 2.0, cv::Scalar(0, 0, 255), 3, cv::LINE_AA); + } + } + + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + // cv::resize(frame, frame, cv::Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + cv::imshow("ANSOCR", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of inserting faces.\n"; + } + frame.release(); + delete jpeg_string; + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSOCRHandle(&infHandle); +} + +// Viewer state for zoom/pan +struct ImageViewerState { + cv::Mat image; // Full-resolution annotated image + double zoom = 1.0; // 1.0 = fit-to-screen + double panX = 0.0; // Top-left corner in original image coords + double panY = 0.0; + int dispW, dispH; // Display window size (pixels) + double fitScale; // Base scale to fit image into window + bool dragging = false; + int dragX0, dragY0; + double panX0, panY0; + bool dirty = true; +}; + +static void onViewerMouse(int event, int x, int y, int flags, void* userdata) { + ImageViewerState& s = *(ImageViewerState*)userdata; + if (event == cv::EVENT_MOUSEWHEEL) { + double factor = (cv::getMouseWheelDelta(flags) > 0) ? 1.25 : 0.8; + // Zoom centered on mouse cursor position + double sc = s.fitScale * s.zoom; + double imgX = s.panX + x / sc; + double imgY = s.panY + y / sc; + s.zoom = std::clamp(s.zoom * factor, 0.2, 50.0); + double newSc = s.fitScale * s.zoom; + s.panX = imgX - x / newSc; + s.panY = imgY - y / newSc; + s.dirty = true; + } + else if (event == cv::EVENT_LBUTTONDOWN) { + s.dragging = true; + s.dragX0 = x; s.dragY0 = y; + s.panX0 = s.panX; s.panY0 = s.panY; + } + else if (event == cv::EVENT_MOUSEMOVE && s.dragging) { + double sc = s.fitScale * s.zoom; + s.panX = s.panX0 - (x - s.dragX0) / sc; + s.panY = s.panY0 - (y - s.dragY0) / sc; + s.dirty = true; + } + else if (event == cv::EVENT_LBUTTONUP) { + s.dragging = false; + } +} + +int TestOCRv5mage() { + + ANSCENTER::ANSOCRBase* infHandle = nullptr; + + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::filesystem::path currentPath = std::filesystem::current_path(); + std::cout << "Current working directory: " << currentPath << std::endl; + std::string licenseKey = ""; + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_GenericOCR_v2.0.zip"; + std::string imagePath = "E:\\Programs\\DemoAssets\\Images\\OCR\\ref3_000.bmp"; + + int language = 0; // CUSTOM + int engine = 1;// GPU + + // For high-resolution images with PP-OCRv5 server models, use higher limitSideLen + // (default 960 downscales large images too aggressively, missing small text) + int gpuId = 0; + double detDBThresh = 0.3, detBoxThresh = 0.6, detUnclipRatio = 1.5; + double clsThresh = 0.9; + int useDilation = 0; + int limitSideLen = 2560; // 2560 Higher resolution for server-grade detection + + int createResult = CreateANSOCRHandleEx(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), "", + language, engine, gpuId, detDBThresh, detBoxThresh, detUnclipRatio, clsThresh, useDilation, limitSideLen); + std::cout << "ANSOCR Engine Creation:" << createResult << std::endl; + + cv::Mat input = cv::imread(imagePath, cv::IMREAD_COLOR); + if (input.empty()) { + std::cerr << "Failed to load image: " << imagePath << std::endl; + ReleaseANSOCRHandle(&infHandle); + return -1; + } + cv::Mat frame = input.clone(); + int height = frame.rows; + int width = frame.cols; + unsigned int bufferLength = 0; + unsigned char* jpeg_string = CVMatToBytes(frame, bufferLength); + + // --- Warmup run (first run includes GPU kernel compilation / cache warmup) --- + auto warmupStart = std::chrono::high_resolution_clock::now(); + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto warmupEnd = std::chrono::high_resolution_clock::now(); + double warmupMs = std::chrono::duration(warmupEnd - warmupStart).count(); + std::cout << "Warmup inference: " << warmupMs << " ms" << std::endl; + std::cout << "Result:" << detectionResult << std::endl; + + // --- Benchmark: run N iterations and report stats --- + const int benchmarkIterations = 10; + std::vector times; + times.reserve(benchmarkIterations); + for (int i = 0; i < benchmarkIterations; ++i) { + auto t0 = std::chrono::high_resolution_clock::now(); + std::string result = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto t1 = std::chrono::high_resolution_clock::now(); + double ms = std::chrono::duration(t1 - t0).count(); + times.push_back(ms); + std::cout << " Run " << (i + 1) << "/" << benchmarkIterations << ": " << ms << " ms" << std::endl; + } + std::sort(times.begin(), times.end()); + double sum = std::accumulate(times.begin(), times.end(), 0.0); + double avg = sum / benchmarkIterations; + double median = (benchmarkIterations % 2 == 0) + ? (times[benchmarkIterations / 2 - 1] + times[benchmarkIterations / 2]) / 2.0 + : times[benchmarkIterations / 2]; + std::cout << "\n=== Benchmark (" << benchmarkIterations << " runs) ===" << std::endl; + std::cout << " Avg: " << avg << " ms" << std::endl; + std::cout << " Median: " << median << " ms" << std::endl; + std::cout << " Min: " << times.front() << " ms" << std::endl; + std::cout << " Max: " << times.back() << " ms" << std::endl; + std::cout << " FPS: " << (1000.0 / avg) << std::endl; + + delete[] jpeg_string; + + // Draw OCR results on frame — 1.5x of original (was fontScale=1.5, thickness=3, offset=5) + double fontScale = 2.25; // 1.5 * 1.5 + int boxThickness = 3; + int fontThickness = 5; // ceil(3 * 1.5) + int textOffset = 8; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto class_name = GetData(result, "class_name"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto w = GetData(result, "width"); + const auto h = GetData(result, "height"); + cv::rectangle(frame, cv::Rect((int)x, (int)y, (int)w, (int)h), + cv::Scalar(0, 255, 0), boxThickness); + cv::putText(frame, class_name, cv::Point((int)x, (int)y - textOffset), + cv::FONT_HERSHEY_SIMPLEX, fontScale, cv::Scalar(0, 0, 255), fontThickness, cv::LINE_AA); + } + } + + // === Interactive Image Viewer (zoom/pan) === + ImageViewerState vs; + vs.image = frame; + + // Calculate scale to fit image into ~80% of a 1920x1080 screen + const int maxWinW = 1600, maxWinH = 900; + double scaleX = (double)maxWinW / frame.cols; + double scaleY = (double)maxWinH / frame.rows; + vs.fitScale = std::min(scaleX, scaleY); + if (vs.fitScale > 1.0) vs.fitScale = 1.0; // Don't upscale small images + vs.dispW = (int)(frame.cols * vs.fitScale); + vs.dispH = (int)(frame.rows * vs.fitScale); + + const std::string winName = "ANSOCR [Scroll=Zoom | Drag=Pan | R=Reset | ESC=Quit]"; + cv::namedWindow(winName, cv::WINDOW_AUTOSIZE); + cv::setMouseCallback(winName, onViewerMouse, &vs); + + while (true) { + if (vs.dirty) { + double sc = vs.fitScale * vs.zoom; + int srcW = std::min((int)(vs.dispW / sc), vs.image.cols); + int srcH = std::min((int)(vs.dispH / sc), vs.image.rows); + if (srcW <= 0) srcW = 1; + if (srcH <= 0) srcH = 1; + int sx = std::clamp((int)vs.panX, 0, std::max(0, vs.image.cols - srcW)); + int sy = std::clamp((int)vs.panY, 0, std::max(0, vs.image.rows - srcH)); + vs.panX = sx; + vs.panY = sy; + + cv::Mat roi = vs.image(cv::Rect(sx, sy, srcW, srcH)); + cv::Mat display; + cv::resize(roi, display, cv::Size(vs.dispW, vs.dispH), 0, 0, + (sc >= 1.0) ? cv::INTER_LINEAR : cv::INTER_AREA); + + // Overlay zoom info + cv::putText(display, cv::format("Zoom: %.1fx (%dx%d)", vs.zoom, vs.image.cols, vs.image.rows), + cv::Point(10, 25), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 255, 0), 2); + + cv::imshow(winName, display); + vs.dirty = false; + } + + int key = cv::waitKey(30) & 0xFF; + if (key == 27) break; // ESC to quit + if (key == 'r' || key == 'R') { + vs.zoom = 1.0; vs.panX = 0; vs.panY = 0; vs.dirty = true; // Reset view + } + if (key == '+' || key == '=') { + vs.zoom = std::min(vs.zoom * 1.25, 50.0); vs.dirty = true; // Keyboard zoom in + } + if (key == '-' || key == '_') { + vs.zoom = std::max(vs.zoom * 0.8, 0.2); vs.dirty = true; // Keyboard zoom out + } + + // Quit when user closes the window (clicks X button) + if (cv::getWindowProperty(winName, cv::WND_PROP_VISIBLE) < 1) break; + } + + cv::destroyAllWindows(); + frame.release(); + input.release(); + ReleaseANSOCRHandle(&infHandle); + return 0; +} + +int main() +{ + TestOCRv5mage(); + + //ANSOCR_VideoTest(); + // TestOCRImage(); + /* for (int i = 0; i < 20; i++) { + TestOCRImage(); + }*/ + return 0; +} diff --git a/tests/ANSOCR-UnitTest/CMakeLists.txt b/tests/ANSOCR-UnitTest/CMakeLists.txt new file mode 100644 index 0000000..389b103 --- /dev/null +++ b/tests/ANSOCR-UnitTest/CMakeLists.txt @@ -0,0 +1,23 @@ +# ANSOCR Unit Test +add_executable(ANSOCR-UnitTest + ANSOCR-UnitTest.cpp +) + +target_include_directories(ANSOCR-UnitTest PRIVATE + ${CMAKE_SOURCE_DIR}/modules/ANSOCR + ${SHARED_INCLUDE_DIR} +) + +target_link_libraries(ANSOCR-UnitTest + PRIVATE ANSOCR + PRIVATE ANSLicensingSystem + PRIVATE anslicensing + PRIVATE opencv + PRIVATE boost +) + +if(WIN32) + target_link_libraries(ANSOCR-UnitTest PRIVATE ${WIN_COMMON_LIBS}) +endif() + +target_compile_definitions(ANSOCR-UnitTest PRIVATE UNICODE _UNICODE) diff --git a/tests/ANSODEngine-UnitTest/ANSODEngine-UnitTest.cpp b/tests/ANSODEngine-UnitTest/ANSODEngine-UnitTest.cpp new file mode 100644 index 0000000..c041718 --- /dev/null +++ b/tests/ANSODEngine-UnitTest/ANSODEngine-UnitTest.cpp @@ -0,0 +1,1912 @@ +#include "ANSODTest.h" +#include "ANSCUSTOMPY.h" +#include "ANSMotionDetector.h" +#include "ANSONNXSAM3.h" +#include +#include +#include +#include +//#include "ANSSAM3.h" // TensorRT headers conflict with Windows SDK (ACCESS_MASK) + +// Defined in ANSSAM3-UnitTest.cpp (separate translation unit to avoid header conflict) +int SAM3TRT_UnitTest(); +int SAM3TRT_ImageTest(); + +std::string ReadJsonFileContent(std::string filePath) { + std::ifstream ifs(filePath); + return std::string((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); +} +//int ParseJSonFile() { +// std::string jsonFile = "C:\\Programs\\DemoAssets\\modelConfig1.json"; +// std::string jsonStringContent = ReadJsonFileContent(jsonFile); +// ANSCENTER::Params param= ANSCENTER::ANSUtilityHelper::ParseCustomParameters(jsonStringContent); +// +// string jsonConvertContent = ANSCENTER::ANSUtilityHelper::SerializeCustomParamters(param); +// std::cout << "JSON Content: " << jsonConvertContent << std::endl; +// +// return 0; +// +//} +int ANSCUSTOMPY_Test() { + ANSCENTER::ANSODBase* infHandle; + infHandle = new ANSCENTER::ANSCUSTOMPY(); + // Load model from folder + std::string modelFolder = "C:\\Programs\\PythonProjects\\YoloInference"; + ANSCENTER::ModelConfig modelConfig; + modelConfig.modelConfThreshold = 0.5f; + modelConfig.modelMNSThreshold = 0.4f; + modelConfig.detectionScoreThreshold = 0.4f; + modelConfig.detectionType = ANSCENTER::DetectionType::DETECTION; + + std::string labelMap; + infHandle->LoadModelFromFolder("", modelConfig, "", "", modelFolder, labelMap); + + // Load image + cv::Mat image = cv::imread("C:\\Programs\\PythonProjects\\YoloInference\\bus.jpg"); + std::vector results = infHandle->RunInference(image); + + // Draw results + for (const auto& obj : results) { + cv::rectangle(image, cv::Point(obj.box.x, obj.box.y), cv::Point(obj.box.x + obj.box.width, obj.box.y + obj.box.height), cv::Scalar(0, 255, 0), 2); + cv::putText(image, std::to_string(obj.classId), cv::Point(obj.box.x, obj.box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 1); + } + cv::imshow("Detection", image); + cv::waitKey(0); + // Release resources + cv::destroyAllWindows(); + // Release model + + + //Release + infHandle->Destroy(); + delete infHandle; +} +int CUSTOMPYEngine(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.48; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 18;//Custom python script model + int detectorType = 1; // Detection + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "Reading settings:" << std::endl; + int index = 0; + std::string paramString; + GetConfiguredParameters_CPP(&infHandle, paramString); + std::cout << "Configured Parameters: " << paramString << std::endl; + int setResult = SetODParameters(&infHandle, paramString.c_str()); + if (setResult == 0) { + std::cout << "SetODParameters failed" << std::endl; + } + else { + std::cout << "SetODParameters success" << std::endl; + } + std::cout << "Reading video..." << std::endl; + while (true) + { + index++; + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + if (index >= 10) break; + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int CUSTOMPYEngine1(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.48; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 18;//Custom python script model + int detectorType = 1; // Detection + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "Reading settings:" << std::endl; + int index = 0; + std::string paramString; + GetConfiguredParameters_CPP(&infHandle, paramString); + std::cout << "Configured Parameters: " << paramString << std::endl; + int setResult = SetODParameters(&infHandle, paramString.c_str()); + if (setResult == 0) { + std::cout << "SetODParameters failed" << std::endl; + } + else { + std::cout << "SetODParameters success" << std::endl; + } + std::cout << "Reading video..." << std::endl; + while (true) + { + index++; + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + if (index >= 10) break; + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int CustomPyTest() { + std::string cpumodelFilePath = "C:\\Programs\\PythonProjects\\CustomPyModel.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + CUSTOMPYEngine(cpumodelFilePath, videoFile);//yolov10 + return 0; +} +int CustomPyTest1() { + std::string cpumodelFilePath = "C:\\Programs\\PythonProjects\\CustomPyModel.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + CUSTOMPYEngine1(cpumodelFilePath, videoFile);//yolov10 + return 0; +} +int multithreadTest() { + /*CustomPyTest();*/ + std::thread t1(CustomPyTest); + std::thread t2(CustomPyTest1); + //std::thread t3(CustomPyTest); + //std::thread t4(CustomPyTest); + //std::thread t5(CustomPyTest); + //std::thread t6(CustomPyTest); + + t1.join(); + t2.join(); + //t3.join(); + //t4.join(); + //t5.join(); + //t6.join(); + return 0; +} +int CustomModelEngine(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.48; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 16; // OPENVINO + int detectorType = 1; // Detection + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + std::string optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, 1,1); + std::cout << "Optimized model folder: " << optmizedModelFolder << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size() << std::endl; + + while (true) { + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame(cv::Rect(0, 0, 1920, 1080)); + auto start1 = std::chrono::system_clock::now(); + + std::vector imageData; + bool success = cv::imencode(".jpg", croppedFrame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + break; + } + std::string jpegImage(imageData.begin(), imageData.end()); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + //printf("Conversion Time = %lld ms\n", static_cast(elapsed1.count())); + + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromCV(&infHandle, croppedFrame);//RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size());// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) { // Wait for 'esc' key press to exit + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; + } + } + } +} +int TrafficLightEngine(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.48; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 16; // CUSTOM + int detectorType = 1; // Detection + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + std::string optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Optimized model folder: " << optmizedModelFolder << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType,1); + if (labelMap.empty()) { + std::cout << "Failed to create ANSODHandle. Please check the model file path and parameters." << std::endl; + return -1; + } + std::stringstream ss(labelMap); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size() << std::endl; + + // Load model settings file and set parameters + std::string paramString; + std::string modelSettingsFile = "C:\\Programs\\DemoAssets\\TrafficLights\\TrafficLightSettings.json"; + if (!std::filesystem::exists(modelSettingsFile)) { + std::cout << "Model settings file does not exist: " << modelSettingsFile << std::endl; + return -1; + } + std::ifstream settingsFile(modelSettingsFile); + if (!settingsFile.is_open()) { + std::cout << "Failed to open model settings file: " << modelSettingsFile << std::endl; + return -1; + } + paramString.assign((std::istreambuf_iterator(settingsFile)), std::istreambuf_iterator()); + settingsFile.close(); + + int setparamValue= SetODParameters(&infHandle, paramString.c_str()); + if (setparamValue == 0) { + std::cout << "SetODParameters failed" << std::endl; + } + else { + std::cout << "SetODParameters success" << std::endl; + } + while (true) { + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame.clone();// (cv::Rect(0, 0, 1920, 1080)); + auto start1 = std::chrono::system_clock::now(); + + std::vector imageData; + bool success = cv::imencode(".jpg", croppedFrame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + break; + } + std::string jpegImage(imageData.begin(), imageData.end()); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + //printf("Conversion Time = %lld ms\n", static_cast(elapsed1.count())); + + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromCV(&infHandle, croppedFrame);//RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size());// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) { // Wait for 'esc' key press to exit + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; + } + } + } +} +int HelMetDetection() { + std::string cpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_Helmet(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_Helmet(GPU)_v1.0.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\Helmet\\HM2.mp4"; ; + CustomModelEngine(gpumodelFilePath, videoFile);//yolov8 + return 0; +} +int TrafficLight() { + std::string gpumodelFilePath = "C:\\Programs\\DemoAssets\\TrafficLights\\ANS_TrafficLightALPR_v1.0.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\TrafficLights\\trafficlight1.mp4"; ; + TrafficLightEngine(gpumodelFilePath, videoFile);//yolov8 + return 0; +} +int SAMS_UnitTest() { + std::string samFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_SAM_v1.0.zip"; + //std::string imageFile = "C:\\Programs\\TrainingToolTest\\SegmentationEngine\\SegmeTxtYolo\\data\\20241220_173948_695.jpg"; + //std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + ANSSAMTest(samFile, videoFile); + return 0; +} +int ANSMotionTest(std::string modelFilePath, std::string videoPath) { + ANSCENTER::ANSMOTIONDETECTOR infHandle; + std::string licenseKey = ""; + std::string labelmap = ""; + std::string modelZipFilePassword = ""; + ANSCENTER::ModelConfig modelConfig; + modelConfig.modelConfThreshold = 0.5f; + modelConfig.detectionScoreThreshold = 0.8f; + infHandle.Initialize(licenseKey, modelConfig, modelFilePath, modelZipFilePassword, labelmap); + + cv::VideoCapture capture(videoPath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + std::vector masks = infHandle.RunInference(frame); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + for (int i = 0; i < masks.size(); i++) { + cv::rectangle(frame, masks.at(i).box, 123, 2); + + //const cv::Point* pts = (const cv::Point*)cv::Mat(masks.at(i).polygon).data; + //int npts = cv::Mat(masks.at(i).polygon).rows; + //polylines(frame, &pts, &npts, 1, true, cv::Scalar(0, 255, 0), 1); // Green color, line thickness 3 + + } + // Resize to fit 1920x1080 window + + cv::resize(frame, frame, cv::Size(1920, 1080)); + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + infHandle.Destroy(); + std::cout << "End of program.\n"; + return 0; +} +int MotionDetectorEngine(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.5; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.5; + int modelType = 19; // OPENVINO + int detectorType = 1; // Detection + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + std::string optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Optimized model folder: " << optmizedModelFolder << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size() << std::endl; + + while (true) { + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + + unsigned int bufferLength = 0; + //cv::Mat croppedFrame = frame(cv::Rect(0, 0, 1920, 1080)); + auto start1 = std::chrono::system_clock::now(); + + std::vector imageData; + bool success = cv::imencode(".jpg", frame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + break; + } + std::string jpegImage(imageData.begin(), imageData.end()); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + printf("Conversion Time = %lld ms\n", static_cast(elapsed1.count())); + + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size(),"ID");// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) { // Wait for 'esc' key press to exit + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; + } + } + } +} +int ImageDetectionEngine(std::string modelFilePath, std::string imageFilePath, int engineType = 20, int modelDetectionType = 1) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.5; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.5; + int modelType = engineType; // ONNX CL + int detectorType = modelDetectionType; // Detection + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + std::string optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, modelDetectionType,1); + std::cout << "Optimized model folder: " << optmizedModelFolder << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size() << std::endl; + cv::Mat frame = cv::imread(imageFilePath); + unsigned int bufferLength = 0; + //cv::Mat croppedFrame = frame(cv::Rect(0, 0, 1920, 1080)); + auto start1 = std::chrono::system_clock::now(); + std::vector imageData; + bool success = cv::imencode(".jpg", frame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + return -1; + } + std::string jpegImage(imageData.begin(), imageData.end()); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + printf("Conversion Time = %lld ms\n", static_cast(elapsed1.count())); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size(), "ID");// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + // Collect all detections first, then draw in two passes + // (single overlay for all polygons to avoid cumulative blending artifacts) + struct DetInfo { + int class_id; float prob; + cv::Rect box; + std::vector polyPts; // empty if no polygon + }; + std::vector detections; + + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + DetInfo d; + d.class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + d.prob = GetData(result, "prob"); + const auto w = GetData(result, "width"); + const auto h = GetData(result, "height"); + d.box = cv::Rect(static_cast(x), static_cast(y), + static_cast(w), static_cast(h)); + + const auto polygon_str = GetData(result, "polygon"); + if (!polygon_str.empty()) { + std::vector coords; + std::stringstream pss(polygon_str); + std::string token; + while (std::getline(pss, token, ';')) { + if (!token.empty()) coords.push_back(std::stof(token)); + } + // Auto-detect: if all values in [0,1] treat as normalized, else absolute + bool isNormalized = !coords.empty(); + for (const auto& v : coords) { + if (v > 1.0f) { isNormalized = false; break; } + } + for (size_t p = 0; p + 1 < coords.size(); p += 2) { + int px = isNormalized ? static_cast(coords[p] * frame.cols) + : static_cast(coords[p]); + int py = isNormalized ? static_cast(coords[p + 1] * frame.rows) + : static_cast(coords[p + 1]); + d.polyPts.emplace_back(px, py); + } + if (d.polyPts.size() < 3) d.polyPts.clear(); + } + detections.push_back(std::move(d)); + } + + // Pass 1: Draw all filled polygons on a single overlay + cv::Mat overlay = frame.clone(); + bool anyPoly = false; + for (const auto& d : detections) { + if (!d.polyPts.empty()) { + anyPoly = true; + std::vector> polys = { d.polyPts }; + cv::Scalar polyColor((d.class_id * 67 + 50) % 256, + (d.class_id * 123 + 100) % 256, + (d.class_id * 37 + 150) % 256); + cv::fillPoly(overlay, polys, polyColor); + } + } + if (anyPoly) { + cv::addWeighted(overlay, 0.4, frame, 0.6, 0, frame); + } + + // Pass 2: Draw outlines, boxes, and labels + auto drawDashedRect = [&](const cv::Rect& box, cv::Scalar color) { + int dashLen = 8, gapLen = 6; + auto drawDashedLine = [&](cv::Point p1, cv::Point p2) { + double dx = p2.x - p1.x, dy = p2.y - p1.y; + double len = std::sqrt(dx * dx + dy * dy); + if (len < 1) return; + dx /= len; dy /= len; + double d = 0; + bool draw = true; + while (d < len) { + double seg = draw ? dashLen : gapLen; + double dEnd = std::min(d + seg, len); + if (draw) { + cv::line(frame, + cv::Point(static_cast(p1.x + d * dx), static_cast(p1.y + d * dy)), + cv::Point(static_cast(p1.x + dEnd * dx), static_cast(p1.y + dEnd * dy)), + color, 1, cv::LINE_AA); + } + d = dEnd; + draw = !draw; + } + }; + cv::Point tl(box.x, box.y), tr(box.x + box.width, box.y); + cv::Point br(box.x + box.width, box.y + box.height), bl(box.x, box.y + box.height); + drawDashedLine(tl, tr); drawDashedLine(tr, br); + drawDashedLine(br, bl); drawDashedLine(bl, tl); + }; + + for (const auto& d : detections) { + if (!d.polyPts.empty()) { + // Polygon outline + dashed box + std::vector> polys = { d.polyPts }; + cv::Scalar polyColor((d.class_id * 67 + 50) % 256, + (d.class_id * 123 + 100) % 256, + (d.class_id * 37 + 150) % 256); + cv::polylines(frame, polys, true, polyColor, 2, cv::LINE_AA); + drawDashedRect(d.box, cv::Scalar(0, 255, 0)); + } else { + // Solid box + cv::rectangle(frame, d.box, cv::Scalar(0, 255, 0), 2); + } + std::string label = (d.class_id >= 0 && d.class_id < static_cast(classes.size())) + ? classes[d.class_id] : "?"; + cv::putText(frame, cv::format("%s:%d:%.2f", label.c_str(), d.class_id, d.prob), + cv::Point(d.box.x, d.box.y - 5), 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + //resize to fit 1920x1080 window + cv::resize(frame, frame, cv::Size(1920, 1080)); + cv::imshow("ANS Object Tracking", frame); + + // Wait indefinitely for key press or window close + std::cout << "Press ESC to exit or close the window..." << std::endl; + while (true) { + int key = cv::waitKey(100); // Check every 100ms + if (key == 27) { // ESC key pressed + break; + } + // Check if window was closed + if (cv::getWindowProperty("ANS Object Tracking", cv::WND_PROP_VISIBLE) < 1) { + break; + } + } + + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int VideoDetectorEngine(std::string modelFilePath, std::string videoFilePath, int engineType = 20, int modelDetectionType=1) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.3; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.5; + int modelType = engineType; // OPENVINO + int detectorType = modelDetectionType; // Detection + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + std::string optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, modelDetectionType,1); + std::cout << "Optimized model folder: " << optmizedModelFolder << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType,1); + std::stringstream ss(labelMap); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size() << std::endl; + + // setup tracker + int trackerResult = SetTracker(&infHandle, 0, 1); // 0 for BYTETRACK + int frameNum = 0; + // Track per-trackId detection history for flickering analysis + std::unordered_map>> trackPresenceLog; // trackId -> [(frame, wasReal)] + while (true) { + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + frameNum = 0; + continue; + } + + unsigned int bufferLength = 0; + //cv::Mat croppedFrame = frame(cv::Rect(0, 0, 1920, 1080)); + auto start = std::chrono::system_clock::now(); + std::vector imageData; + bool success = cv::imencode(".jpg", frame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + break; + } + std::string jpegImage(imageData.begin(), imageData.end()); + /* auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + printf("Jpeg conversion Time = %lld ms\n", static_cast(elapsed1.count()));*/ + + int height = frame.rows; + int width = frame.cols; + //auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size(), "ID");// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + frameNum++; + printf("Inference Time = %lld ms\n", static_cast(elapsed.count())); + + if (!detectionResult.empty()) { + // COCO pose skeleton connections + const std::vector> POSE_SKELETON = { + {0,1}, {0,2}, {1,3}, {2,4}, // Face + {3,5}, {4,6}, // Head-to-shoulder + {5,7}, {7,9}, {6,8}, {8,10}, // Arms + {5,6}, {5,11}, {6,12}, {11,12}, // Body + {11,13}, {13,15}, {12,14}, {14,16} // Legs + }; + // Colors for different limb groups + const std::vector LIMB_COLORS = { + {255,0,0}, {255,0,0}, {255,0,0}, {255,0,0}, // Face - blue + {0,255,255}, {0,255,255}, // Head-shoulder - yellow + {0,255,0}, {0,255,0}, {0,165,255}, {0,165,255}, // Arms - green/orange + {255,255,0}, {255,0,255}, {255,0,255}, {255,255,0},// Body - cyan/magenta + {0,255,0}, {0,255,0}, {0,165,255}, {0,165,255} // Legs - green/orange + }; + + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + + // ── Stabilization debug counters ── + int realCount = 0, stabilizedCount = 0; + + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto track_id = GetData(result, "track_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + const auto kps_str = GetData(result, "kps"); + const auto extra_info = GetData(result, "extra_info"); + + const auto polygon_str = GetData(result, "polygon"); + bool hasPolygon = !polygon_str.empty(); + bool hasKeypoints = !kps_str.empty(); + + // ── Detect stabilized (ghost) vs real detection ── + bool isStabilized = (extra_info.find("stabilized") != std::string::npos); + if (isStabilized) stabilizedCount++; else realCount++; + + // Log per-track presence for flickering analysis + if (track_id > 0) { + trackPresenceLog[track_id].push_back({frameNum, !isStabilized}); + } + + // Draw bounding box: dashed if polygon or keypoints present, solid otherwise + cv::Rect bbox(static_cast(x), static_cast(y), + static_cast(width), static_cast(height)); + + // Color: GREEN = real detection, YELLOW = stabilized (ghost) + cv::Scalar boxColor = isStabilized ? cv::Scalar(0, 255, 255) : cv::Scalar(0, 255, 0); + int boxThickness = isStabilized ? 1 : 2; + + // Dashed helper lambda + auto drawDashedLine = [&](cv::Point p1, cv::Point p2, cv::Scalar color, int dashLen = 8, int gapLen = 6) { + float dx = static_cast(p2.x - p1.x); + float dy = static_cast(p2.y - p1.y); + float dist = std::sqrt(dx * dx + dy * dy); + if (dist < 1.f) return; + float ux = dx / dist, uy = dy / dist; + float drawn = 0.f; + bool dash = true; + while (drawn < dist) { + float seg = dash ? static_cast(dashLen) : static_cast(gapLen); + float end = std::min(drawn + seg, dist); + if (dash) { + cv::Point a(static_cast(p1.x + ux * drawn), static_cast(p1.y + uy * drawn)); + cv::Point b(static_cast(p1.x + ux * end), static_cast(p1.y + uy * end)); + cv::line(frame, a, b, color, 1, cv::LINE_AA); + } + drawn = end; + dash = !dash; + } + }; + + if (isStabilized || hasPolygon || hasKeypoints) { + // Dashed box for stabilized ghosts, polygons, and keypoints + cv::Point tl = bbox.tl(), br = bbox.br(); + cv::Point tr(br.x, tl.y), bl(tl.x, br.y); + drawDashedLine(tl, tr, boxColor); + drawDashedLine(tr, br, boxColor); + drawDashedLine(br, bl, boxColor); + drawDashedLine(bl, tl, boxColor); + } else { + cv::rectangle(frame, bbox, boxColor, boxThickness); + } + + // Label: class:classId:conf:trackId (append [S] if stabilized) + std::string label = cv::format("%s:%d:%.2f:%d", classes[class_id].c_str(), class_id, prob, track_id); + if (isStabilized) label += "[S]"; + cv::Scalar textColor = isStabilized ? cv::Scalar(0, 200, 200) : cv::Scalar(0, 0, 255); + cv::putText(frame, label, cv::Point(static_cast(x), static_cast(y) - 5), + 0, 0.6, textColor, 1, cv::LINE_AA); + + // Draw polygon if available (format: x1;y1;x2;y2;... normalized coords) + if (!polygon_str.empty()) { + // Parse semicolon-separated normalized coordinates + std::vector polyPts; + std::stringstream pss(polygon_str); + std::string token; + std::vector coords; + while (std::getline(pss, token, ';')) { + if (!token.empty()) + coords.push_back(std::stof(token)); + } + for (size_t p = 0; p + 1 < coords.size(); p += 2) { + int px = static_cast(coords[p] * frame.cols); + int py = static_cast(coords[p + 1] * frame.rows); + polyPts.emplace_back(px, py); + } + if (polyPts.size() >= 3) { + // Draw filled polygon with transparency + cv::Mat overlay = frame.clone(); + std::vector> polys = { polyPts }; + // Use class_id to generate a unique color per class + cv::Scalar polyColor( + (class_id * 67 + 50) % 256, + (class_id * 123 + 100) % 256, + (class_id * 37 + 150) % 256); + cv::fillPoly(overlay, polys, polyColor); + cv::addWeighted(overlay, 0.4, frame, 0.6, 0, frame); + // Draw polygon outline + cv::polylines(frame, polys, true, polyColor, 2, cv::LINE_AA); + } + } + + // Draw keypoints if available (format: x1;y1;score1;x2;y2;score2;... stride=3) + if (!kps_str.empty()) { + std::vector kps = ANSCENTER::ANSUtilityHelper::StringToKeypoints(kps_str); + int numKeypoints = (int)kps.size() / 3; // stride of 3: x, y, confidence + + // Collect keypoint positions and confidence + std::vector keypointPts(numKeypoints); + std::vector keypointConf(numKeypoints, 0.f); + for (int k = 0; k < numKeypoints; k++) { + keypointPts[k] = cv::Point2f(kps[k * 3], kps[k * 3 + 1]); + keypointConf[k] = kps[k * 3 + 2]; + } + + const float kpConfThreshold = 0.3f; + + // Draw skeleton lines + for (size_t s = 0; s < POSE_SKELETON.size(); s++) { + int idx1 = POSE_SKELETON[s].first; + int idx2 = POSE_SKELETON[s].second; + if (idx1 < numKeypoints && idx2 < numKeypoints && + keypointConf[idx1] > kpConfThreshold && keypointConf[idx2] > kpConfThreshold) { + cv::Scalar color = (s < LIMB_COLORS.size()) ? LIMB_COLORS[s] : cv::Scalar(200, 200, 200); + cv::line(frame, keypointPts[idx1], keypointPts[idx2], color, 2, cv::LINE_AA); + } + } + + // Draw keypoint circles on top of lines + for (int k = 0; k < numKeypoints; k++) { + if (keypointConf[k] > kpConfThreshold) { + cv::circle(frame, keypointPts[k], 4, cv::Scalar(0, 0, 255), -1, cv::LINE_AA); + cv::circle(frame, keypointPts[k], 4, cv::Scalar(255, 255, 255), 1, cv::LINE_AA); + } + } + } + } + + // ── Per-frame stabilization summary ── + printf(" Frame %d: %d real + %d stabilized = %d total detections\n", + frameNum, realCount, stabilizedCount, realCount + stabilizedCount); + + // Print flickering report every 100 frames + if (frameNum % 100 == 0 && frameNum > 0) { + printf("\n=== FLICKERING REPORT (frame %d) ===\n", frameNum); + for (const auto& kv : trackPresenceLog) { + int trackId = kv.first; + const auto& history = kv.second; + if (history.size() < 5) continue; // skip short-lived tracks + int realFrames = 0, ghostFrames = 0, transitions = 0; + bool prevReal = history[0].second; + for (size_t i = 0; i < history.size(); ++i) { + if (history[i].second) realFrames++; else ghostFrames++; + if (i > 0 && history[i].second != prevReal) transitions++; + prevReal = history[i].second; + } + float stabilityPct = (history.size() > 0) ? + 100.f * realFrames / static_cast(history.size()) : 0.f; + // Only report tracks that have flickering (transitions > 2) + if (transitions > 2) { + printf(" Track %3d: %d frames (%d real, %d ghost), %d transitions, %.1f%% real\n", + trackId, (int)history.size(), realFrames, ghostFrames, transitions, stabilityPct); + } + } + printf("=================================\n\n"); + } + } + + // Draw frame number on screen + cv::putText(frame, cv::format("Frame: %d", frameNum), cv::Point(10, 30), + cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(255, 255, 255), 2); + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) { // Wait for 'esc' key press to exit + // Print final flickering report + printf("\n=== FINAL FLICKERING REPORT (frame %d) ===\n", frameNum); + for (const auto& kv : trackPresenceLog) { + int trackId = kv.first; + const auto& history = kv.second; + if (history.size() < 3) continue; + int realFrames = 0, ghostFrames = 0, transitions = 0; + bool prevReal = history[0].second; + for (size_t i = 0; i < history.size(); ++i) { + if (history[i].second) realFrames++; else ghostFrames++; + if (i > 0 && history[i].second != prevReal) transitions++; + prevReal = history[i].second; + } + float stabilityPct = (history.size() > 0) ? + 100.f * realFrames / static_cast(history.size()) : 0.f; + printf(" Track %3d: %d frames (%d real, %d ghost), %d transitions, %.1f%% real\n", + trackId, (int)history.size(), realFrames, ghostFrames, transitions, stabilityPct); + } + printf("===========================================\n"); + + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; + } + } + } +} +int Motion_UnitTest() { + std::string motionFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_SAM_v1.0.zip"; + //std::string imageFile = "C:\\Programs\\TrainingToolTest\\SegmentationEngine\\SegmeTxtYolo\\data\\20241220_173948_695.jpg"; + //std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + //std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\ANSFireFull.mp4"; + //std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\Fail1\\Test2.mp4"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\ANSVIS_Issues\\FGFire2.mp4"; + + ANSMotionTest(motionFile, videoFile); + return 0; +} +int MotionEngine_UnitTest() { + std::string motionFile = ""; + //std::string imageFile = "C:\\Programs\\TrainingToolTest\\SegmentationEngine\\SegmeTxtYolo\\data\\20241220_173948_695.jpg"; + //std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\ANSFireFull.mp4"; + //std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\Fail1\\Test2.mp4"; + //std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\ANSVIS_Issues\\FGFire2.mp4"; + + MotionDetectorEngine(motionFile, videoFile); + return 0; +} +int ONNXCLE_Test() { + std::string onnxclmodelFilePath = "E:\\Programs\\DemoAssets\\ANSAIModels\\ClassifierModels\\ANSVehicleColour.zip"; + std::string imageFile = "E:\\Programs\\DemoAssets\\ANSAIModels\\ClassifierModels\\data\\IMG-20251014-WA0008.jpg"; + ImageDetectionEngine(onnxclmodelFilePath, imageFile,20);//yolov8 + return 0; +} +int ONNXPOSE_Test() { + std::string onnxclmodelFilePath = "E:\\Programs\\DemoAssets\\ANSAIModels\\PoseEstimationModels\\ANSPOSEN.zip"; + std::string imageFile = "E:\\Programs\\DemoAssets\\ANSAIModels\\PoseEstimationModels\\openpose.jpg"; + ImageDetectionEngine(onnxclmodelFilePath, imageFile,21);// + return 0; +} +int ONNXPOSE_VideoTest() { + std::string onnxclmodelFilePath = "E:\\Programs\\DemoAssets\\ANSAIModels\\PoseEstimationModels\\ANSPOSEN.zip"; + + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\train.mp4"; + + + VideoDetectorEngine(onnxclmodelFilePath, videoFile,21);// 22 is RT, 21 is onnx + return 0; +} +int Helmet_VideoTest() { + std::string helmetModel = "E:\\Programs\\DemoAssets\\TestInference\\ANS_helmet_1712(GPU)_1.zip"; + + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\Helmet\\HM1.mp4"; + + + VideoDetectorEngine(helmetModel, videoFile, 4,0); + return 0; +} +int BristleTest() { + + std::string modelFilePath = "C:\\Programs\\DemoAssets\\ODHUB\\Bristle_Loss.zip"; + std::string imageFile = "C:\\Programs\\DemoAssets\\ODHUB\\data\\20251028_120112.PNG"; + int modelType = 13; // ONNX POSE + ImageDetectionEngine(modelFilePath, imageFile, modelType);// + return 0; +} + +int Yolov11Test() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_FireNSmoke_v2.0.zip"; + std::string imageFile = "C:\\ProgramData\\ANSCENTER\\Shared\\20260107_011644_762.jpg"; + std::string videoFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANSFireFull.mp4"; + int modelType = 3; // ONNX POSE + //ImageDetectionEngine(modelFilePath, imageFile, modelType);// + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int Yolov12Test() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\GenericYolov12.zip"; + std::string imageFile = "C:\\ProgramData\\ANSCENTER\\Shared\\20260107_011644_762.jpg"; + std::string videoFile = "C:\\ProgramData\\ANSCENTER\\Shared\\test.mp4"; + int modelType = 17; // ONNX POSE + //ImageDetectionEngine(modelFilePath, imageFile, modelType);// + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int TensorRTTest() { + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_VehicleDetection(GPU)_v1.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\road.mp4"; + int modelType = 4; // ONNX POSE + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int OpenVINOTest() { + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_VehicleDetection(CPU)_v1.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\road.mp4"; + int modelType = 5; // OpenVINO + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int OpenVINOYolo10Test() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(CPU)_v1.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + int modelType = 15; // OpenVINO + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int FireNSmokeCustomDetection() { + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FireSmoke_v2.0.zip"; + std::string videoFilePath = "E:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\ANSFireFull.mp4";// passed + int modelType = 16; // Custom POSE + VideoDetectorEngine(modelFilePath, videoFilePath, modelType); + return 0; +} +int TensorRT10Test() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + std::string videoFile = "C:\\ProgramData\\ANSCENTER\\Shared\\classroom.mp4"; + int modelType = 14; // TensorRT v10 + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} + + +int SAM3ONNX_UnitTest() { + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_SAM_v3.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + //ANSSAMONNXTest(samFile, videoFile); + + // Use LoadModelFromFolder to avoid zip extraction issues with 3.3GB data file + std::string modelFolder = "C:\\Projects\\ANSVIS\\Models\\ANS_SAM_v3.0"; + ANSCENTER::ANSONNXSAM3 infHandle; + ANSCENTER::ModelConfig modelConfig; + modelConfig.modelConfThreshold = 0.5f; + std::string labelmap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + infHandle.Initialize(licenseKey, modelConfig, modelFilePath, modelZipFilePassword, labelmap); + infHandle.SetPrompt("person"); + + cv::VideoCapture capture(videoFile); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + std::vector masks = infHandle.RunInference(frame); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + for (int i = 0; i < masks.size(); i++) { + cv::rectangle(frame, masks.at(i).box, 123, 2); + } + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) break; + } + capture.release(); + cv::destroyAllWindows(); + infHandle.Destroy(); + return 0; +} +int SAM3ONNX_ImageTest() { + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_SAM_v3.0.zip"; + std::string imageFile = "C:\\Projects\\Research\\sam3onnx\\sam3-onnx\\images\\dog.jpg"; + + ANSCENTER::ANSONNXSAM3 infHandle; + ANSCENTER::ModelConfig modelConfig; + modelConfig.modelConfThreshold = 0.5f; + std::string labelmap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + infHandle.Initialize(licenseKey, modelConfig, modelFilePath, modelZipFilePassword, labelmap); + infHandle.SetPrompt("dog"); + + cv::Mat image = cv::imread(imageFile); + if (image.empty()) { + std::cerr << "SAM3ONNX_ImageTest: could not read image file: " << imageFile << "\n"; + return -1; + } + + auto start = std::chrono::system_clock::now(); + std::vector masks = infHandle.RunInference(image); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + for (size_t i = 0; i < masks.size(); i++) { + const auto& obj = masks[i]; + // 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 polyPts; + polyPts.reserve(obj.polygon.size()); + for (const auto& pt : obj.polygon) { + polyPts.emplace_back( + static_cast(pt.x * image.cols), + static_cast(pt.y * image.rows)); + } + // Semi-transparent filled polygon + cv::Mat overlay = image.clone(); + std::vector> 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); + } + // Draw mask overlay if available + 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)); + } + + printf(" [%zu] %s conf=%.3f box=(%d,%d,%d,%d) polygon=%zu pts\n", + i, obj.className.c_str(), obj.confidence, + obj.box.x, obj.box.y, obj.box.width, obj.box.height, + obj.polygon.size()); + } + cv::imshow("SAM3 ONNX Image Test", image); + cv::waitKey(0); + cv::destroyAllWindows(); + infHandle.Destroy(); + return 0; +} + +int YOLO26ODYolo12Test() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\GenericYolov12.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\road.mp4"; + int modelType = 3; // ONNX YOLO (30) RT YOLO (31) + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int YOLO26ODYolo11Test() { + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_VehicleDetection_v2.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\road.mp4"; + int modelType = 31; // ONNX YOLO (30) RT YOLO (31) + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +int YOLO26ODYolo10Test() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\road.mp4"; + int modelType = 31; // ONNX YOLO (30) RT YOLO (31) + VideoDetectorEngine(modelFilePath, videoFile, modelType); + return 0; +} +// Classification test with ONNX CL engine. Note that this model is not optimised for ONNX CL, so performance will be poor and may cause timeouts in some cases. It's recommended to use a smaller model for testing ONNX CL classification, or to optimise the model for ONNX CL using the OptimizeModelStr function before running this test. +int YOLO26CLYolo11Test() { + int modelType = 30; // ONNX YOLO (30) RT YOLO (31) + std::string onnxclmodelFilePath = "E:\\Programs\\DemoAssets\\ANSAIModels\\ClassifierModels\\ANSVehicleColour.zip"; + std::string imageFile = "E:\\Programs\\DemoAssets\\ANSAIModels\\ClassifierModels\\data\\IMG-20251014-WA0002.jpg"; + ImageDetectionEngine(onnxclmodelFilePath, imageFile, modelType);//yolov8 + return 0; +} +int YOLO26SEGYolo11Test() { + int modelType = 30; // ONNX YOLO (30) RT YOLO (31) + std::string onnxclmodelFilePath = "C:\\Projects\\Research\\YoloSeg\\ANS_GenericSEG_v1.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\road.mp4"; + VideoDetectorEngine(onnxclmodelFilePath, videoFile, modelType);// 22 is RT, 21 is onnx + return 0; +} +int YOLO26POSEYolo11Test() { + int modelType = 31; // ONNX YOLO (30) RT YOLO (31) + std::string onnxclmodelFilePath = "E:\\Programs\\DemoAssets\\ANSAIModels\\PoseEstimationModels\\ANSPOSEN.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\train.mp4"; + + VideoDetectorEngine(onnxclmodelFilePath, videoFile, modelType);// 22 is RT, 21 is onnx + return 0; +} + +int YOLO26OBBYolo11Test() { + std::string onnxclmodelFilePath = "C:\\Projects\\Research\\YoloOBB\\ANS_GenericOBB_v1.0.zip"; + std::string imageFile = "C:\\Projects\\Research\\YoloOBB\\boats.jpg"; + // Test with ONNX first + std::cout << "\n=== Testing OBB with ONNX (modelType=31) ===" << std::endl; + ImageDetectionEngine(onnxclmodelFilePath, imageFile, 31); + //// Test with TRT + //std::cout << "\n=== Testing OBB with TRT (modelType=31) ===" << std::endl; + //ImageDetectionEngine(onnxclmodelFilePath, imageFile, 31); + return 0; +} + +int HelmetDetectionTest() { + int modelType = 16; // Custom model type for helmet detection, adjust as needed based on how the model is set up in the engine + std::string onnxclmodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_Helmet_v2.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\Helmet\\HM1.mp4"; + + VideoDetectorEngine(onnxclmodelFilePath, videoFile, modelType);// 22 is RT, 21 is onnx + return 0; +} + + +// ============================================================================ +// ElasticGPUTest — Verify elastic pool, round-robin dispatch, multi-GPU, +// concurrent inference, and idle-slot cleanup. +// +// Test matrix: +// 1. Single-handle creation → probe slot exists (capacity == 1) +// 2. Sequential inference → works on probe slot +// 3. Concurrent inference from N threads → pool grows on-demand +// 4. After burst → verify pool grew (capacity > 1) +// 5. Wait for idle cleanup → verify slots released (capacity == 1) +// 6. Post-cleanup inference → still works (probe slot alive) +// 7. Multi-GPU detection → reports all GPUs found +// 8. Clean release → no crash, no hang +// ============================================================================ +int ElasticGPUTest() { + std::cout << "\n" + << "============================================================\n" + << " ElasticGPUTest — Elastic Pool + Round-Robin Verification\n" + << "============================================================\n" << std::endl; + + // --- Config --- + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + std::string videoFile = "C:\\ProgramData\\ANSCENTER\\Shared\\classroom.mp4"; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.3f; + float modelConfThreshold = 0.48f; + float modelNMSThreshold = 0.5f; + int modelType = 14; // TensorRT v10 + int detectorType = 1; // Detection + + const int NUM_CONCURRENT_THREADS = 4; + const int FRAMES_PER_THREAD = 20; + const int IDLE_WAIT_SECONDS = 75; // > 60s cleanup threshold + + int testsPassed = 0; + int testsFailed = 0; + + auto PASS = [&](const std::string& name) { + testsPassed++; + std::cout << " [PASS] " << name << std::endl; + }; + auto FAIL = [&](const std::string& name, const std::string& reason) { + testsFailed++; + std::cout << " [FAIL] " << name << " — " << reason << std::endl; + }; + + // ================================================================ + // TEST 1: Create handle (should create probe slot, elastic mode) + // ================================================================ + std::cout << "\n--- Test 1: Handle creation (elastic mode) ---\n" << std::endl; + + std::cout << "Optimizing model, please wait..." << std::endl; + std::string optimizedFolder = OptimizeModelStr( + modelFilePath.c_str(), modelZipFilePassword.c_str(), + modelType, detectorType, 1); + std::cout << "Optimized model folder: " << optimizedFolder << std::endl; + + ANSCENTER::ANSODBase* infHandle = nullptr; + std::string labelMap = CreateANSODHandle( + &infHandle, licenseKey.c_str(), modelFilePath.c_str(), + modelZipFilePassword.c_str(), detectionScoreThreshold, + modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType, 1); + + if (infHandle == nullptr) { + FAIL("Handle creation", "infHandle is nullptr"); + return -1; + } + PASS("Handle creation"); + + // Parse classes + std::vector classes; + { + std::stringstream ss(labelMap); + std::string substr; + while (std::getline(ss, substr, ',')) { + classes.push_back(substr); + } + } + std::cout << " Classes loaded: " << classes.size() << std::endl; + + // ================================================================ + // TEST 2: Load test frames from video + // ================================================================ + std::cout << "\n--- Test 2: Load test frames ---\n" << std::endl; + + cv::VideoCapture capture(videoFile); + if (!capture.isOpened()) { + FAIL("Video loading", "Cannot open " + videoFile); + ReleaseANSODHandle(&infHandle); + return -1; + } + + // Pre-load frames and encode as JPEG for thread safety + const int TOTAL_FRAMES_NEEDED = NUM_CONCURRENT_THREADS * FRAMES_PER_THREAD; + std::vector> jpegFrames; + jpegFrames.reserve(TOTAL_FRAMES_NEEDED); + + for (int i = 0; i < TOTAL_FRAMES_NEEDED; i++) { + cv::Mat frame; + if (!capture.read(frame)) { + capture.set(cv::CAP_PROP_POS_FRAMES, 0); + if (!capture.read(frame)) break; + } + std::vector buf; + cv::imencode(".jpg", frame, buf); + jpegFrames.push_back(std::move(buf)); + } + capture.release(); + + if (jpegFrames.empty()) { + FAIL("Frame loading", "No frames loaded"); + ReleaseANSODHandle(&infHandle); + return -1; + } + PASS("Frame loading (" + std::to_string(jpegFrames.size()) + " frames)"); + + // ================================================================ + // TEST 3: Sequential inference (single-threaded, probe slot only) + // ================================================================ + std::cout << "\n--- Test 3: Sequential inference (probe slot) ---\n" << std::endl; + + int seqSuccessCount = 0; + auto seqStart = std::chrono::steady_clock::now(); + for (int i = 0; i < 5; i++) { + const auto& jpeg = jpegFrames[i % jpegFrames.size()]; + std::string result = RunInferenceFromJpegString( + &infHandle, + reinterpret_cast(jpeg.data()), + static_cast(jpeg.size()), + "seq_test"); + if (!result.empty() && result.find("results") != std::string::npos) { + seqSuccessCount++; + } + } + auto seqEnd = std::chrono::steady_clock::now(); + double seqMs = std::chrono::duration(seqEnd - seqStart).count(); + + if (seqSuccessCount == 5) { + PASS("Sequential inference (5/5, " + std::to_string(static_cast(seqMs)) + " ms total)"); + } else { + FAIL("Sequential inference", std::to_string(seqSuccessCount) + "/5 succeeded"); + } + + // ================================================================ + // TEST 4: Concurrent inference (N threads → pool should grow) + // ================================================================ + std::cout << "\n--- Test 4: Concurrent inference (" << NUM_CONCURRENT_THREADS + << " threads x " << FRAMES_PER_THREAD << " frames) ---\n" << std::endl; + + std::atomic totalSuccess{0}; + std::atomic totalFailed{0}; + std::mutex printMutex; + + auto workerFn = [&](int threadId) { + int localSuccess = 0; + int localFailed = 0; + + for (int i = 0; i < FRAMES_PER_THREAD; i++) { + int frameIdx = (threadId * FRAMES_PER_THREAD + i) % static_cast(jpegFrames.size()); + const auto& jpeg = jpegFrames[frameIdx]; + + std::string cameraId = "cam_" + std::to_string(threadId); + std::string result = RunInferenceFromJpegString( + &infHandle, + reinterpret_cast(jpeg.data()), + static_cast(jpeg.size()), + cameraId.c_str()); + + if (!result.empty() && result.find("results") != std::string::npos) { + localSuccess++; + } else { + localFailed++; + } + } + + totalSuccess += localSuccess; + totalFailed += localFailed; + + std::lock_guard lk(printMutex); + std::cout << " Thread " << threadId << ": " + << localSuccess << "/" << FRAMES_PER_THREAD << " succeeded" << std::endl; + }; + + auto concStart = std::chrono::steady_clock::now(); + + std::vector threads; + for (int t = 0; t < NUM_CONCURRENT_THREADS; t++) { + threads.emplace_back(workerFn, t); + } + for (auto& th : threads) { + th.join(); + } + + auto concEnd = std::chrono::steady_clock::now(); + double concMs = std::chrono::duration(concEnd - concStart).count(); + int totalInferences = NUM_CONCURRENT_THREADS * FRAMES_PER_THREAD; + + std::cout << "\n Total: " << totalSuccess.load() << "/" << totalInferences + << " succeeded, " << totalFailed.load() << " failed" + << " (" << static_cast(concMs) << " ms, " + << static_cast(concMs / totalInferences) << " ms/inference avg)" << std::endl; + + if (totalSuccess.load() == totalInferences) { + PASS("Concurrent inference (" + std::to_string(totalInferences) + "/" + + std::to_string(totalInferences) + ")"); + } else if (totalSuccess.load() > 0) { + // Some rejections are OK if GPU is full — not a failure + PASS("Concurrent inference (partial: " + std::to_string(totalSuccess.load()) + + "/" + std::to_string(totalInferences) + ", some slots busy — expected)"); + } else { + FAIL("Concurrent inference", "All inferences failed"); + } + + // ================================================================ + // TEST 5: Verify pool grew during concurrent burst + // ================================================================ + std::cout << "\n--- Test 5: Pool growth verification ---\n" << std::endl; + + // Pool info is inside the Engine — we can't access it directly from ANSODBase. + // But the pool prints "Info [Pool]: On-demand slot created/recycled" to stdout + // during growth. We verify indirectly: if concurrent inference succeeded + // with N threads simultaneously, the pool must have grown (or the probe slot + // serialized all requests via the round-robin dispatch). + std::cout << " (Check stdout above for 'Info [Pool]: On-demand slot' messages)" << std::endl; + if (totalSuccess.load() > 0) { + PASS("Pool growth (concurrent inference succeeded — pool dispatched correctly)"); + } else { + FAIL("Pool growth", "No successful inferences during concurrent burst"); + } + + // ================================================================ + // TEST 6: Wait for idle cleanup (60s threshold + timer interval) + // ================================================================ + std::cout << "\n--- Test 6: Idle cleanup (waiting " << IDLE_WAIT_SECONDS + << "s for 60s cleanup timer) ---\n" << std::endl; + + std::cout << " Waiting..." << std::flush; + for (int i = 0; i < IDLE_WAIT_SECONDS; i++) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + if ((i + 1) % 10 == 0) { + std::cout << " " << (i + 1) << "s" << std::flush; + } + } + std::cout << " done." << std::endl; + + // The idle timer should have fired and released extra slots. + // Check stdout for "Info [Pool]: Released N idle slot(s)" messages. + std::cout << " (Check stdout above for 'Info [Pool]: Released' and 'Releasing idle slot' messages)" << std::endl; + PASS("Idle cleanup wait completed (verify pool messages above)"); + + // ================================================================ + // TEST 7: Post-cleanup inference (probe slot must still work) + // ================================================================ + std::cout << "\n--- Test 7: Post-cleanup inference ---\n" << std::endl; + + int postCleanupSuccess = 0; + for (int i = 0; i < 3; i++) { + const auto& jpeg = jpegFrames[i % jpegFrames.size()]; + std::string result = RunInferenceFromJpegString( + &infHandle, + reinterpret_cast(jpeg.data()), + static_cast(jpeg.size()), + "post_cleanup"); + if (!result.empty() && result.find("results") != std::string::npos) { + postCleanupSuccess++; + } + } + + if (postCleanupSuccess == 3) { + PASS("Post-cleanup inference (3/3 — probe slot alive)"); + } else { + FAIL("Post-cleanup inference", std::to_string(postCleanupSuccess) + "/3 succeeded"); + } + + // ================================================================ + // TEST 8: Multi-GPU detection (via nvidia-smi — no CUDA link needed) + // ================================================================ + std::cout << "\n--- Test 8: Multi-GPU detection ---\n" << std::endl; + + // Use nvidia-smi to query GPUs without linking cuda_runtime + int smiResult = system("nvidia-smi --query-gpu=index,name,memory.total,memory.free " + "--format=csv,noheader,nounits"); + if (smiResult == 0) { + PASS("GPU detection (see nvidia-smi output above)"); + } else { + FAIL("GPU detection", "nvidia-smi not found or failed"); + } + std::cout << " (Pool init messages above show which GPUs were used for slot creation)" << std::endl; + + // ================================================================ + // TEST 9: Clean release (no crash, no hang) + // ================================================================ + std::cout << "\n--- Test 9: Handle release ---\n" << std::endl; + + auto releaseStart = std::chrono::steady_clock::now(); + int releaseResult = ReleaseANSODHandle(&infHandle); + auto releaseEnd = std::chrono::steady_clock::now(); + double releaseMs = std::chrono::duration(releaseEnd - releaseStart).count(); + + if (releaseResult == 0 || infHandle == nullptr) { + PASS("Handle release (" + std::to_string(static_cast(releaseMs)) + " ms)"); + } else { + FAIL("Handle release", "ReleaseANSODHandle returned " + std::to_string(releaseResult)); + } + + // ================================================================ + // SUMMARY + // ================================================================ + std::cout << "\n" + << "============================================================\n" + << " ElasticGPUTest RESULTS: " << testsPassed << " passed, " + << testsFailed << " failed\n" + << "============================================================\n" << std::endl; + + return testsFailed; +} + + +int FireNSmokeTest() { + int modelType = 16; // Custom model type for helmet detection, adjust as needed based on how the model is set up in the engine + std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FireSmoke_v2.0.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\Helmet\\HM1.mp4"; + + + ANSCENTER::ANSODBase* infHandle; + + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + double detectionScoreThreshold = 0.3; + double modelConfThreshold = 0.48; + double modelNMSThreshold = 0.5; + int loadEngine = 0; + CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), + detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, 1, loadEngine); + + std::string stParam; + GetConfiguredParameters_CPP(&infHandle, stParam); + std::cout << "Configured parameters:\n" << stParam << std::endl; + + ReleaseANSODHandle(&infHandle); + + + return 0; +} +int main() +{ + //FireNSmokeTest(); + //ElasticGPUTest(); + + //YOLO26SEGYolo11Test(); + //YOLO26POSEYolo11Test(); + //YOLO26CLYolo11Test(); + //YOLO26ODYolo12Test(); + //YOLO26ODYolo11Test(); + //YOLO26ODYolo10Test(); + //YOLO26OBBYolo11Test(); + //SAM3ONNX_ImageTest(); // ORT reference — runs first, prints decoder input stats + //SAM3TRT_ImageTest(); // TRT under test — compare decoder input stats with above + CustomModel_StressTest_FilePlayer(); // Multi-task stress test (LabVIEW flow) + //SAM3TRT_UnitTest(); // TensorRT SAM3 test (in ANSSAM3-UnitTest.cpp) + //TensorRT10Test(); + //FireNSmokeCustomDetection(); + //OpenVINOTest(); + //OpenVINOYolo10Test(); + //TensorRTTest(); + //BristleTest();// + //Yolov12Test(); + //Yolov11Test();// + //ONNXPOSE_VideoTest(); + //ONNXCLE_Test(); + //ONNXPOSE_Test(); + //MotionEngine_UnitTest(); + //Motion_UnitTest(); + //GenericModelTest(); + //RVATest(); + //SAMS_UnitTest(); + //TrafficLight(); + //Helmet_VideoTest(); + // HelMetDetection(); + // ONNXPOSE_VideoTest(); + + //multithreadTest(); + //CustomPyTest(); + //for (int i = 0; i < 10; i++) { + // CustomPyTest(); + // CustomPyTest(); + //} + //ANSCUSTOMPY_Test(); + + //ParseJSonFile(); + //TestODHUB(); + //TestYOLOV12(); + // GenericModelTest(); + //Yolov10RT_Test(); + //PersonHead(); + //RectifierTest(); + //LocSetTest(); + //PPETest(); + //ShutdownPythonEngine_CPP(); + return 0; +} + diff --git a/tests/ANSODEngine-UnitTest/ANSODTest.cpp b/tests/ANSODEngine-UnitTest/ANSODTest.cpp new file mode 100644 index 0000000..ee1d3fa --- /dev/null +++ b/tests/ANSODEngine-UnitTest/ANSODTest.cpp @@ -0,0 +1,2744 @@ +#include "ANSODTest.h" + +int GPUYolov10EngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 14;//TENSORRT V10 + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, 1,1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int OpenVINOYolov10EngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.48; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 15;//OPENVINO + int detectorType = 1; // Detection + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int OpenVINOYolov10EngineUnitTestLoop(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.48; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 15; // OPENVINO + int detectorType = 1; // Detection + + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size() << std::endl; + + while (true) { + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame(cv::Rect(0, 0, 1920, 1080)); + auto start1 = std::chrono::system_clock::now(); + + std::vector imageData; + bool success = cv::imencode(".jpg", croppedFrame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + break; + } + std::string jpegImage(imageData.begin(), imageData.end()); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + //printf("Conversion Time = %lld ms\n", static_cast(elapsed1.count())); + + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromCV(&infHandle, croppedFrame);//RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size());// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) { // Wait for 'esc' key press to exit + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; + } + } + } +} +int OpenVINOEngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.2; + float modelConfThreshold = 0.2; + float modelNMSThreshold = 0.2; + int modelType = 5;//OPENVINO + int detectorType = 1; // Detection + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + cv::Mat croppedframe = frame(cv::Rect(0, 0, frame.cols, frame.rows)); + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(croppedframe, bufferLength); + int height = croppedframe.rows; + int width = croppedframe.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedframe, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedframe, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedframe); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int Yolov8EngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 3;//TENSORRT + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame.clone();// frame(cv::Rect(1440, 0, 320, 320)).clone();// frame.clone();//frame(cv::Rect(1250, 0, 640, 640)).clone();//frame.clone();// frame.clone();// + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(croppedFrame, bufferLength); + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + croppedFrame.release(); + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int Yolov5EngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.2; + float modelConfThreshold = 0.2; + float modelNMSThreshold = 0.2; + int modelType = 2;//Yolov5 + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame.clone();// frame(cv::Rect(1440, 0, 320, 320)).clone();// frame.clone();//frame(cv::Rect(1250, 0, 640, 640)).clone();//frame.clone();// frame.clone();// + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(croppedFrame, bufferLength); + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + croppedFrame.release(); + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int Yolov12EngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.25; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 17;//Yolov12 (4 RT) + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame.clone();// frame(cv::Rect(1440, 0, 320, 320)).clone();// frame.clone();//frame(cv::Rect(1250, 0, 640, 640)).clone();//frame.clone();// frame.clone();// + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(croppedFrame, bufferLength); + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + croppedFrame.release(); + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int GPUEngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.2; + float modelConfThreshold = 0.2; + float modelNMSThreshold = 0.2; + int modelType = 4;//TENSORRT + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame.clone();// frame(cv::Rect(1440, 0, 320, 320)).clone();// frame.clone();//frame(cv::Rect(1250, 0, 640, 640)).clone();//frame.clone();// frame.clone();// + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(croppedFrame, bufferLength); + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + croppedFrame.release(); + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int ONNXEngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 3;//ONNX + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 0); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int GPUEngineImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 4;//TENSORRT + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + //cv::imshow("ANS Object Tracking", frame); + //if (cv::waitKey(0) == 0) // Wait for 'esc' key press to exit + //{ + // std::cout << "End of facial detection.\n"; + //} + cv::destroyAllWindows(); + + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int GPU11EngineImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 4;//TENSORRTyolo11 same as yolov8 + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, 1,1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType,1); + std::stringstream ss(labelMap); + + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 0) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int GPU11EngineUnitTest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.2; + float modelConfThreshold = 0.2; + float modelNMSThreshold = 0.2; + int modelType = 4;//TENSORRTv11 same as Yolov8 + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + cv::Mat croppedFrame = frame.clone();// frame(cv::Rect(1440, 0, 320, 320)).clone();// frame.clone();//frame(cv::Rect(1250, 0, 640, 640)).clone();//frame.clone();// frame.clone();// + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(croppedFrame, bufferLength); + int height = croppedFrame.rows; + int width = croppedFrame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(croppedFrame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(croppedFrame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", croppedFrame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + croppedFrame.release(); + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int UnitTests() { + std::string defaultDir = "C:\\Programs"; + std::string abmodelFilePath = defaultDir + "\\DemoAssets\\ANSAIModels\\anomalibmodel.zip"; + std::string cpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(CPU)_v1.0.zip"; + std::string gpumodelFilePath = defaultDir + "\\DemoAssets\\ANSAIModels\\OptimisedModels\\ANS_GenericOD(GPU)_v1.0.zip"; + + std::string Yolov8OpenVINOModelPath = defaultDir + "\\DemoAssets\\Models\\ANS_GenericOD(CPU)YL8_v1.0.zip"; + std::string Yolov8OTensorRTModelPath = defaultDir + "\\DemoAssets\\ANSAIModels\\OptimisedModels\\PPEGPU.zip"; + + std::string odhubModelPath = defaultDir + "\\DemoAssets\\Models\\openflapmulticat_v1.zip"; + std::string openposeModelPath = defaultDir + "\\ANSAIModels\\ANS_PoseEstimation_v1.0.zip"; + std::string samModelPath = defaultDir + "\\ANSAIModels\\ANS_SAM_v1.0.zip"; + std::string customModelPath = defaultDir + "\\ANLS\\AIModels\\ANSCustomModel_v3.zip"; + + + std::string abImageFilePath = defaultDir + "\\TestImages\\brokenlarge.png"; + std::string customModelImage = defaultDir + "\\ANLS\\AIModels\\LP2.jpg"; + std::string imageDataPath = defaultDir + "\\DemoAssets\\TestImages\\ALPR\\101_EUS664.jpg"; + std::string videoDataPath = defaultDir + "\\DemoAssets\\Videos\\road.mp4"; + std::string videoPPEPath = defaultDir + "\\DemoAssets\\Videos\\Factory1.mp4"; + std::string odhubVideoPath = defaultDir + "\\DemoAssets\\Videos\\openflap.mp4"; + std::string openposeVideoPath = defaultDir + "\\DemoAssets\\Videos\\train.mp4";; + std::string openposeImagePath = defaultDir + "\\DemoAssets\\TestImages\\ANSCVAImages\\openpose.jpg"; + std::string classroom = defaultDir + "\\DemoAssets\\Videos\\classroom.mp4"; + std::string classroomGPUTest = "C:\\ProgramData\\ANSCENTER\\Shared\\classroom.mp4"; + std::string modelGPUTest = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + + // OpenVINOEngineUnitTest(Yolov8OpenVINOModelPath, videoDataPath); // Yolov8 + //GPUEngineUnitTest(Yolov8OTensorRTModelPath, videoPPEPath);// yolov8 + // OpenVINOYolov10EngineUnitTestLoop(cpumodelFilePath, classroom);//yolov10 + OpenVINOYolov10EngineUnitTest(cpumodelFilePath, classroom);//yolov10 + + // GPUYolov10EngineUnitTest(modelGPUTest, classroomGPUTest);// yolov10 + //ODHUBAPITest(odhubModelPath, odhubVideoPath); + + //AnomalibTest(abmodelFilePath, abImageFilePath); + //FacialDetectorTest(cpumodelFilePath, imageDataPath); + //HumanPoseTest(openposeModelPath, openposeVideoPath); + //HumanPoseImageTest(openposeModelPath, openposeImagePath); + //ANSSAMTest(samModelPath, openflapVideoPath); + //CustomCodeImageTest(customModelPath, customModelImage); + //ALPRPipeLineTest(gpumodelFilePath, videoFilePathPipeLine); + return 0; +} + +int FacialDetectorTest(std::string modelFilePath, std::string imagePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 6;//Facial + int detectorType = 1; // Detection + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int AnomalibTest(std::string abmodelFilePath, std::string abImageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 10;//Facial + int detectorType = 2; // Segmentation + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), abmodelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "label map:" << labelMap << std::endl; + std::string imagePath = abImageFilePath; + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of abnomalib detection.\n"; + } + cv::destroyAllWindows(); + + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int HumanPoseTest(std::string modelFilePath, std::string imagePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 11;//POSE + int detectorType = 7; // KEYPOINT + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + + cv::VideoCapture capture(imagePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int HumanPoseImageTest(std::string modelFilePath, std::string imagePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 11;//POSE + int detectorType = 7; // KEYPOINT + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + + cv::Mat frame = cv::imread(imagePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int ANSSAMTest(std::string modelFilePath, std::string videoPath) { + ANSCENTER::ANSSAM infHandle; + std::string licenseKey = ""; + std::string labelmap = ""; + std::string modelZipFilePassword = ""; + ANSCENTER::ModelConfig modelConfig; + modelConfig.modelConfThreshold = 0.5f; + infHandle.Initialize(licenseKey, modelConfig, modelFilePath, modelZipFilePassword, labelmap); + + cv::VideoCapture capture(videoPath); + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + auto start = std::chrono::system_clock::now(); + std::vector masks = infHandle.RunInference(frame); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + for (int i = 0; i < masks.size(); i++) { + cv::rectangle(frame, masks.at(i).box, 123, 2); + + //const cv::Point* pts = (const cv::Point*)cv::Mat(masks.at(i).polygon).data; + //int npts = cv::Mat(masks.at(i).polygon).rows; + //polylines(frame, &pts, &npts, 1, true, cv::Scalar(0, 255, 0), 1); // Green color, line thickness 3 + + } + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + infHandle.Destroy(); + std::cout << "End of program.\n"; + return 0; +} +int ODHUBAPITest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.7; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 13;//ODHUBAPI ;1 is yolov4 opencv + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int ODHUBOpenCVAPITest(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.7; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 13;//ODHUBAPI ;1 is yolov4 opencv + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} + +int ODHUBAPIImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.7; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 13;//ODHUBAPI ;1 is yolov4 opencv + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(255, 0, 0), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + resize(frame, frame, Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + namedWindow("Display frame", WINDOW_AUTOSIZE); + cv::imshow("Display frame", frame); + if (cv::waitKey(0) == 3) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int ODHUBCVAPIImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.7; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 1;//ODHUBAPI ;1 is yolov4 opencv + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, 1,1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(255, 0, 0), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + resize(frame, frame, Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + namedWindow("Display frame", WINDOW_AUTOSIZE); + cv::imshow("Display frame", frame); + if (cv::waitKey(0) == 3) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int CustomCodeImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.7; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 16;//Customized + int detectorType = 1; + std::string optmizedModelFolder; + + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", "Test", class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 27) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int FallDetection() { + + std::string cpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FallDetection(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FallDetection(GPU)_v1.0.zip"; + + std::string videoFile = "C:\\Programs\\TrainingWorkingStation\\Projects\\FallDetection\\video\\Fall.mp4"; + std::string MAFallVideo = "C:\\Programs\\DemoAssets\\Videos\\MAFall.mp4"; + + std::string cpumodelFilePathM = "C:\\Programs\\TrainingWorkingStation\\Projects\\FallDetection\\RawModelModified\\ANS_FallDetectionM(CPU)_v1.0.zip"; + std::string gpumodelFilePathM = "C:\\Programs\\TrainingWorkingStation\\Projects\\FallDetection\\RawModelModified\\ANS_FallDetectionM(GPU)_v1.0.zip"; + std::string odhubModelPath = "C:\\Programs\\DemoAssets\\Models\\Fall_ODHUB.zip"; + + //OpenVINOEngineUnitTest(cpumodelFilePathM, videoFile);//yolov8 + //GPUEngineUnitTest(gpumodelFilePath, videoFile);// yolov8 + + ODHUBOpenCVAPITest(odhubModelPath, MAFallVideo); + return 0; +} +int HeadDetection() { + + std::string cpumodelFilePath = "C:\\Programs\\DemoAssets\\ANSAIModels\\ANS_PeopleHead(CPU)_v1.zip"; + std::string gpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\ServerOptimised\\B-IN_ANS_PeopleHead(GPU)_v1.0_6111783b89cda8cf337ad2d60c8b2eea_NVIDIAGeForceRTX4070LaptopGPU.zip";// "C:\\Projects\\ANSVIS\\Models\\ANS_PeopleHead(GPU)_v1.0.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + // OpenVINOEngineUnitTest(gpumodelFilePath, videoFile);//yolov8 + //OpenVINOEngineUnitTest(FallModelCPU, FallVideoFile);//yolov8 + //OpenVINOEngineUnitTest(PPECPUMOdel, PPEVideoFile);//yolov8 + + GPUEngineUnitTest(gpumodelFilePath, videoFile);// yolov8 + //GPUEngineUnitTest(PPEGPUMOdel, PPEVideoFile);// yolov8 + + + return 0; +} +int FireNSmokeDetection() { + + std::string cpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FireSmoke(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\Programs\\ModelExports\\ANS_FireSmoke(GPU)_v1.0\\ANS_FireSmoke(GPU)_v1.0.zip"; + std::string gpumodel10FilePath = "C:\\Programs\\ModelExports\\HoangWork\\ANS_FireSmoke(GPU)_v2.0.zip"; + std::string optimisedModelPath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\ServerOptimised\\B-IN_ANS_GenericOD(GPU)_v1.0_d52ffdcc7241b541fdcf17f2eff78b89_NVIDIAGeForceRTX4070LaptopGPU.zip"; + std::string optimisedModelPath8 = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\ServerOptimised\\B-IN_ANS_PeopleHead(GPU)_v1.0_6111783b89cda8cf337ad2d60c8b2eea_NVIDIAGeForceRTX4070LaptopGPU.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\Fire1.mp4"; + + + //GPUYolov10EngineUnitTest(optimisedModelPath, videoFile);// yolov10 + GPUEngineUnitTest(optimisedModelPath8, videoFile);// yolov8 + + //OpenVINOEngineUnitTest(cpumodelFilePath, videoFile);//yolov8 + + //GPUEngineUnitTest(gpumodelFilePath, videoFile);// yolov8 + // ONNXEngineUnitTest(gpumodelFilePath, videoFile); + + return 0; +} +int VehicleDetection() { + + std::string cpumodelFilePath = "C:\\Programs\\DemoAssets\\ANSAIModels\\ANS_GenericVehicle8(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\Programs\\DemoAssets\\AIModels\\ODv8xGPUGeneric.zip"; + + std::string cpumodel10FilePath = "C:\\Programs\\DemoAssets\\ANSAIModels\\ANS_GenericVehicle(CPU)_v1.0.zip"; + std::string gpumodel10FilePath = "C:\\Programs\\AIModels\\ANS_GenericOD(GPU)_v1.0.zip"; + + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\road.mp4"; + std::string hotelvideoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + + std::string testModel = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\ServerOptimised\\B-IN_ANS_PeopleHead(GPU)_v1.0_6111783b89cda8cf337ad2d60c8b2eea_NVIDIAGeForceRTX4070LaptopGPU.zip"; + + // std::string testModel = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\ServerOptimised\\B-IN_ANS_PeopleHead(GPU)_v1.0_6111783b89cda8cf337ad2d60c8b2eea_NVIDIARTXA500EmbeddedGPU.zip"; + //GPUYolov10EngineUnitTest(gpumodel10FilePath, videoFile);// yolov10 + //OpenVINOYolov10EngineUnitTestLoop(cpumodel10FilePath, videoFile);//yolov10 + + //OpenVINOEngineUnitTest(testModel, hotelvideoFile);//yolov8 + GPUEngineUnitTest(testModel, hotelvideoFile);// yolov8 + + return 0; +} +void TestODHUB() { + + std::string odhubModelPath = "C:\\Programs\\DemoAssets\\ANSAIModels\\Models\\openflapmulticat_v1.zip"; + std::string odhubVideoPath = "C:\\Programs\\DemoAssets\\Videos\\openflap.mp4"; + ODHUBAPITest(odhubModelPath, odhubVideoPath); + //ODHUBOpenCVAPITest(odhubModelPath, odhubVideoPath); +} +void DissemTest() { + std::string odhubModelPath = "C:\\Workstation\\CustomerSupport\\Dissem\\EngineTest\\Test_Model Type\\20240705_Waper_1.zip"; + std::string odhubImagePath = "C:\\Workstation\\CustomerSupport\\Dissem\\EngineTest\\Test_Model Type\\0711_10_0051.jpg"; + //ODHUBAPIImageTest(odhubModelPath, odhubImagePath); + ODHUBCVAPIImageTest(odhubModelPath, odhubImagePath); +} +int DissemParallelTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.7; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 13;//ODHUBAPI ;1 is yolov4 opencv + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, 1,1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(255, 0, 0), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + resize(frame, frame, Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + namedWindow("Display frame", WINDOW_AUTOSIZE); + cv::imshow("Display frame", frame); + if (cv::waitKey(0) == 3) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int CustomTest() { + std::string customModelPath = "C:\\Programs\\DemoAssets\\AIModels\\ANSCustomFaceDetector.zip"; + std::string imageDataPath = "C:\\Projects\\ANSVISCustomFunction\\Examples\\FaceDetector\\test.jpg"; + CustomCodeImageTest(customModelPath, imageDataPath); + return 0; +} +int CocoTest() { + + std::string gpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_Coco_format(GPU)_1.zip"; + std::string imageFile = "C:\\ProgramData\\ANSCENTER\\Shared\\20240620_132740_256.jpg"; + GPUEngineImageTest(gpumodelFilePath, imageFile); + + return 0; +} +int FaceDetector(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 6;//Facial + int detectorType = 1; // Detection + // Optimise model + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) + { + cv::Mat frame; + if (!capture.read(frame)) // if not success, break loop + { + std::cout << "\n Cannot read the video file. please check your video.\n"; + break; + } + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) // Wait for 'esc' key press to exit + { + break; + } + } + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int TiledInferenceTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.55; + float modelConfThreshold = 5; + float modelNMSThreshold = 0.5; + int modelType = 14;// + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + + auto start1 = std::chrono::system_clock::now(); + + std::vector imageData; + bool success = cv::imencode(".jpg", frame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + return 0; + } + std::string jpegImage(imageData.begin(), imageData.end()); + + + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + std::string detectionResult = RunTiledInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size(), 640, 640, 0.2, "TestCam"); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + //cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + // 0, 0.6, cv::Scalar(255, 0, 0), 1, cv::LINE_AA); + // std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + //resize(frame, frame, Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + //namedWindow("Display frame", WINDOW_AUTOSIZE); + cv::imshow("Display frame", frame); + if (cv::waitKey(0) == 3) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int NormalInferenceTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.55; + float modelConfThreshold = 5; + float modelNMSThreshold = 0.5; + int modelType = 14;// + int detectorType = 1; + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, "", modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + + auto start1 = std::chrono::system_clock::now(); + + std::vector imageData; + bool success = cv::imencode(".jpg", frame, imageData); + if (!success) { + std::cout << "Failed to encode the image" << std::endl; + return 0; + } + std::string jpegImage(imageData.begin(), imageData.end()); + + + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + std::string detectionResult = RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size(), "TestCam"); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + /* cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(255, 0, 0), 1, cv::LINE_AA);*/ + // std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + //resize(frame, frame, Size(frame.cols / 2, frame.rows / 2)); // to half size or even smaller + namedWindow("Display frame", WINDOW_AUTOSIZE); + cv::imshow("Display frame", frame); + if (cv::waitKey(0) == 3) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int TiledInferenceTest() { + std::string modelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + std::string imageFilePath = "C:\\Programs\\DemoAssets\\Images\\SAHI\\smallobjects.jpeg"; + //TiledInferenceTest(modelFilePath, imageFilePath); + NormalInferenceTest(modelFilePath, imageFilePath); + return 0; +} +int MotionDetection(std::string modelFilePath, std::string videoFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float detectionScoreThreshold = 0.2; + float modelConfThreshold = 0.48; + float modelNMSThreshold = 0.48; + int modelType = 17; // ANSFIRESMOKE + int detectorType = 1; // Detection + + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), detectionScoreThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + std::cout << "classes:" << classes.size(); + std::cout << "classes:" << classes.size() << std::endl; + + while (true) { + std::cout << "begin read video" << std::endl; + cv::VideoCapture capture(videoFilePath); + + if (!capture.isOpened()) { + printf("could not read this video file...\n"); + return -1; + } + + std::cout << "end read video" << std::endl; + + while (true) { + cv::Mat frame; + if (!capture.read(frame)) { + std::cout << "\n Cannot read the video file. Restarting...\n"; + capture.set(cv::CAP_PROP_POS_FRAMES, 0); // Reset to the beginning of the video + continue; + } + + unsigned int bufferLength = 0; + //cv::Mat croppedFrame = frame(cv::Rect(0, 0, 1920, 1080)); + auto start1 = std::chrono::system_clock::now(); + + //std::vector imageData; + //bool success = cv::imencode(".jpg", frame, imageData); + //if (!success) { + // std::cout << "Failed to encode the image" << std::endl; + // break; + //} + //std::string jpegImage(imageData.begin(), imageData.end()); + auto end1 = std::chrono::system_clock::now(); + auto elapsed1 = std::chrono::duration_cast(end1 - start1); + //printf("Conversion Time = %lld ms\n", static_cast(elapsed1.count())); + + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceFromCV(&infHandle, frame);//RunInferenceFromJpegString(&infHandle, jpegImage.c_str(), imageData.size());// , 100, 100, 0.2); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto prob = GetData(result, "prob"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d:%.2f", classes[class_id], class_id, prob), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(30) == 27) { // Wait for 'esc' key press to exit + capture.release(); + cv::destroyAllWindows(); + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; + } + } + } +} +int MotionDetectionForFireNSmoke() { + std::string cpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FireSmoke(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_FireSmoke(GPU)_v1.0.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\BCA2.mp4"; + //std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\Fire25m.mp4"; + //std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\fire2.mp4"; + //std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\ANSFireFull.mp4"; + + // std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + // std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\road.mp4"; + + //GPUYolov10EngineUnitTest(gpumodel10FilePath, videoFile);// yolov10 + MotionDetection(gpumodelFilePath, videoFile);//yolov10 + + //OpenVINOEngineUnitTest(cpumodelFilePath, videoFile);//yolov8 + //GPUEngineUnitTest(gpumodelFilePath, videoFile);// yolov8 + + return 0; +} +int StressTest() { + std::string gpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_PeopleHead(GPU)_v1.0.zip"; + std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + for (int i = 0; i < 100; i++) { + std::cout << "Test:" << i << std::endl; + GPUEngineImageTest(gpumodelFilePath, imageFile); + } + +} +int OpenVINOCLEngineImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 5;//OpenVINO + int detectorType = 0;// Classification + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 0) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int TENSORRTCLEngineImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 4;//OpenVINO + int detectorType = 0;// Classification + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType,1, 1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + cv::imshow("ANS Object Tracking", frame); + if (cv::waitKey(0) == 0) // Wait for 'esc' key press to exit + { + std::cout << "End of facial detection.\n"; + } + cv::destroyAllWindows(); + + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int TestCL() { + std::string cpumodelFilePath = "C:\\Programs\\DemoAssets\\AIModels\\ANSFireNSmokeCL(CPU).zip"; + std::string gpumodelFilePath = "C:\\Programs\\DemoAssets\\AIModels\\ANSFireNSmokeCL(GPU).zip"; + + std::string imageFile = "C:\\Programs\\DemoAssets\\TestImages\\FireNSmoke\\smoke\\test1.jpg"; + //std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + TENSORRTCLEngineImageTest(gpumodelFilePath, imageFile); +} +int Engine_Test() { + std::string gpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + std::string imageFile = "C:\\ProgramData\\ANSCENTER\\Shared\\bus.jpg"; + GPUEngineImageTest(gpumodelFilePath, imageFile); +} +int SegEngineImageTest(std::string modelFilePath, std::string imageFilePath) { + boost::property_tree::ptree root; + boost::property_tree::ptree detectionObjects; + boost::property_tree::ptree pt; + std::vector classes; + std::filesystem::path currentPath = std::filesystem::current_path(); + ANSCENTER::ANSODBase* infHandle; + std::string labelMap; + std::string licenseKey = ""; + std::string modelZipFilePassword = ""; + float modelThreshold = 0.5; + float modelConfThreshold = 0.5; + float modelNMSThreshold = 0.5; + int modelType = 5;//OpenVINO + int detectorType = 2;// Segmentation + std::string optmizedModelFolder; + // Optimise model + std::cout << "Optimizing model, please wait...." << std::endl; + optmizedModelFolder = OptimizeModelStr(modelFilePath.c_str(), modelZipFilePassword.c_str(), modelType, 1,1); + std::cout << "Model is optmized, run inference...." << std::endl; + labelMap = CreateANSODHandle(&infHandle, licenseKey.c_str(), modelFilePath.c_str(), modelZipFilePassword.c_str(), modelThreshold, modelConfThreshold, modelNMSThreshold, 1, modelType, detectorType); + std::stringstream ss(labelMap); + + while (ss.good()) + { + std::string substr; + getline(ss, substr, ','); + classes.push_back(substr); + } + cv::Mat frame = cv::imread(imageFilePath, cv::IMREAD_COLOR); + unsigned int bufferLength = 0; + unsigned char* jpeg_string = ANSCENTER::ANSUtilityHelper::CVMatToBytes(frame, bufferLength); + int height = frame.rows; + int width = frame.cols; + auto start = std::chrono::system_clock::now(); + /* measured work */ + std::string detectionResult = RunInferenceBinary(&infHandle, jpeg_string, width, height); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(elapsed.count())); + std::cout << "Result:" << detectionResult << std::endl; + delete jpeg_string; + + if (!detectionResult.empty()) { + pt.clear(); + std::stringstream ss; + ss.clear(); + ss << detectionResult; + boost::property_tree::read_json(ss, pt); + BOOST_FOREACH(const boost::property_tree::ptree::value_type & child, pt.get_child("results")) + { + const boost::property_tree::ptree& result = child.second; + const auto class_id = GetData(result, "class_id"); + const auto x = GetData(result, "x"); + const auto y = GetData(result, "y"); + const auto width = GetData(result, "width"); + const auto height = GetData(result, "height"); + cv::rectangle(frame, cv::Rect(x, y, width, height), 123, 2); + cv::putText(frame, cv::format("%s:%d", classes[class_id], class_id), cv::Point(x, y - 5), + 0, 0.6, cv::Scalar(0, 0, 255), 1, cv::LINE_AA); + std::cout << "Keypoints =[" << GetData(result, "extra_info") << "]" << std::endl; + + } + } + + //cv::imshow("ANS Object Tracking", frame); + //if (cv::waitKey(0) == 0) // Wait for 'esc' key press to exit + //{ + // std::cout << "End of facial detection.\n"; + //} + cv::destroyAllWindows(); + + ReleaseANSODHandle(&infHandle); + std::cout << "End of program.\n"; + return 0; +} +int SegmentationTest() { + std::string segmodelFilePath = "C:\\Programs\\TrainingToolTest\\SegmentationEngine\\SegmeTxtYolo\\Models\\ANS_MySegmentation(CPU)_1.zip"; + // std::string segmodelFilePath = "C:\\Programs\\TrainingToolTest\\SegmentationEngine\\SegmeTxtYolo\\Models\\Yolov8\\ANS_MySegmentation(CPU)_1.zip"; + std::string imageFile = "C:\\Programs\\TrainingToolTest\\SegmentationEngine\\SegmeTxtYolo\\data\\20241220_173948_695.jpg"; + //std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + SegEngineImageTest(segmodelFilePath, imageFile); +} +int LocSetTest() { + std::string gpumodelFilePath = "C:\\Programs\\LocSet\\LocSetGPU_v1.0.zip"; + std::string cpumodelFilePath = "C:\\Programs\\LocSet\\LocSetCPU_v1.0.zip"; + std::string yolov8ModeFilePath = "C:\\Programs\\Yolov8\\Yolov8_General\\ANS_GenericODM.zip";//"C:\\Programs\\LocSet\\LocSet_v1.0.zip";// + std::string videoFilePath = "C:\\Programs\\LocSet\\loc_set 1.mp4"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + Yolov8EngineUnitTest(yolov8ModeFilePath, videoFile); + //GPUEngineUnitTest(gpumodelFilePath, videoFilePath); + //OpenVINOEngineUnitTest(cpumodelFilePath, videoFilePath); + //GPUYolov10EngineUnitTest(cpumodelFilePath, videoFilePath); +} +int PPETest() { + //std::string gpumodelFilePath = "C:\\Programs\\DemoAssets\\ANSAIModels\\Models\\PPEGPU.zip"; + std::string gpumodelFilePath = "C:\\Programs\\Yolov8\\ANS_PPE(GPU)_v3.0.zip"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\Factory1.mp4"; + Yolov8EngineUnitTest(gpumodelFilePath, videoFilePath); + return 1; + +} +int RectifierTest() { + + std::string Yolov5Model = "C:\\Programs\\Yolov5\\Rectifier_v1.zip"; + std::string videoFilePath = "C:\\Programs\\Yolov5\\rectifier.mp4"; + //std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + //GPUEngineUnitTest(yolov5ModeFilePaht, videoFile);// + Yolov5EngineUnitTest(Yolov5Model, videoFilePath); +} +int FaceTest() { + std::string facemodeFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(GPU)_v1.0.zip"; + std::string video = "C:\\Programs\\DemoAssets\\Videos\\BMIP.mp4"; + FaceDetector(facemodeFile, video); + return 0; +} +int FaceOVTest() { + std::string facemodeFile = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericFD(CPU)_v1.0.zip"; + std::string imagePath = "C:\\Programs\\DemoAssets\\TestImages\\Face\\Hoang2.jpg";// "C:\\Programs\\DemoAssets\\Images\\Tien\\80.jpg"; + FacialDetectorTest(facemodeFile, imagePath);// yolov8 + return 0; +} +int FaceYoloTest() { + std::string facecpumodeFile = "C:\\Projects\\ANSVIS\\Models\\ANS_Face(CPU)_v1.0.zip"; + std::string facegpumodeFile = "C:\\Projects\\ANSVIS\\Models\\ANS_Face(GPU)_v1.0.zip"; + std::string video = "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + OpenVINOEngineUnitTest(facecpumodeFile, video);//yolov8 + // GPUEngineUnitTest(facegpumodeFile, video);// yolov8 + return 0; +} +int Yolov11RT_Test() { + std::string gpumodelFilePath = "C:\\Users\\nghia\\Downloads\\Generic11GPU.zip";// "C:\\Programs\\DemoAssets\\AIModels\\ANS_PersonHead(GPU)_1.zip"; + std::string cpumodelFilePath = "C:\\Programs\\DemoAssets\\AIModels\\ODv11nCPUGeneric.zip"; + + std::string imageFile = "C:\\Programs\\DemoAssets\\Images\\bus.jpg"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + + // GPU11EngineImageTest(gpumodelFilePath, imageFile); + GPUEngineUnitTest(gpumodelFilePath, videoFile); + //OpenVINOEngineUnitTest(cpumodelFilePath, videoFile); +} +int Yolov10RT_Test() { + std::string gpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + std::string videoFilePath = "C:\\Programs\\DemoAssets\\Videos\\classroom.mp4"; + GPUYolov10EngineUnitTest(gpumodelFilePath, videoFilePath); + +} + +int TestYOLOV12() { + std::string modelPath = "C:\\Programs\\Yolov12\\GenericYolov12.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\FireNSmoke\\SimFire.mp4"; + Yolov12EngineUnitTest(modelPath, videoFile); +} +int GenericModelTest() { + //std::string cpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip";// "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\B-IN_ANS_PeopleHead(GPU)_v1.0_54a7944906d79395a9840945d3c24b9a.zip";// "C:\\ProgramData\\ANSCENTER\\Shared\\ANS_GenericOD(GPU)_v1.0.zip"; + //std::string gpumodelFilePath = "C:\\ProgramData\\ANSCENTER\\ANSVIS Server\\Models\\ServerOptimised\\B-IN_ANS_GenericOD(GPU)_v1.0_101944350_NVIDIAGeForceRTX4070LaptopGPU.zip"; + std::string videoFile = "E:\\Programs\\DemoAssets\\Videos\\TestFR\\school1.mp4"; + //OpenVINOYolov10EngineUnitTest(cpumodelFilePath, videoFile);//yolov10 + GPUYolov10EngineUnitTest(gpumodelFilePath, videoFile);//yolov10 + return 0; +} +int PersonHead() { + std::string cpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_PeopleHead(CPU)_v1.0.zip"; + std::string gpumodelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_PeopleHead(CPU)_v1.0.zip"; + std::string videoFile = "C:\\Programs\\DemoAssets\\Videos\\video_20.mp4"; + OpenVINOEngineUnitTest(cpumodelFilePath, videoFile);//yolov8 + return 0; +} +int RVATest() { + std::string rvamodelFilePath = "C:\\Programs\\Braemac\\BR_RVA\\Models\\ANS_BR_RVA(GPU)_1.zip"; + std::string rvaImageFile = "C:\\Programs\\Braemac\\TestData\\2025-07-29-122338.jpg"; + GPU11EngineImageTest(rvamodelFilePath, rvaImageFile); + return 0; +} diff --git a/tests/ANSODEngine-UnitTest/ANSODTest.h b/tests/ANSODEngine-UnitTest/ANSODTest.h new file mode 100644 index 0000000..1658baa --- /dev/null +++ b/tests/ANSODEngine-UnitTest/ANSODTest.h @@ -0,0 +1,119 @@ + +#include +#include +#include +#include +#include "boost/property_tree/ptree.hpp" +#include "boost/property_tree/json_parser.hpp" +#include "boost/foreach.hpp" +#include "boost/optional.hpp" +#include +#include +#include +#include "ANSODEngine.h" +#include "openvino/openvino.hpp" +#include +#include +#include +#include +#include "format_reader/include/format_reader_ptr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "inference_engine.hpp" +#include +#include "ANSPOSE.h" +#include "ANSSAM.h" +#include "ANSEngineCommon.h" +#include "ANSLPR.h" +#include "ANSLPR_CPU.h" +#include + +using namespace cv; +using namespace dnn; +template +T GetOptionalValue(const boost::property_tree::ptree& pt, std::string attribute, T defaultValue) { + if (pt.count(attribute)) { + return pt.get(attribute); + } + return defaultValue; +} +template +T GetData(const boost::property_tree::ptree& pt, const std::string& key) +{ + T ret; + if (boost::optional data = pt.get_optional(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(); \ No newline at end of file diff --git a/tests/ANSODEngine-UnitTest/ANSSAM3-UnitTest.cpp b/tests/ANSODEngine-UnitTest/ANSSAM3-UnitTest.cpp new file mode 100644 index 0000000..1d1199b --- /dev/null +++ b/tests/ANSODEngine-UnitTest/ANSSAM3-UnitTest.cpp @@ -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 +#include +#include + +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 masks = infHandle.RunInference(frame); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + printf("Time = %lld ms\n", static_cast(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 results = infHandle.RunInference(image); + auto end = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(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 polyPts; + polyPts.reserve(obj.polygon.size()); + for (const auto& pt : obj.polygon) { + polyPts.emplace_back( + static_cast(pt.x * image.cols), + static_cast(pt.y * image.rows)); + } + cv::Mat overlay = image.clone(); + std::vector> 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; +} diff --git a/tests/ANSODEngine-UnitTest/CMakeLists.txt b/tests/ANSODEngine-UnitTest/CMakeLists.txt new file mode 100644 index 0000000..451e846 --- /dev/null +++ b/tests/ANSODEngine-UnitTest/CMakeLists.txt @@ -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) diff --git a/tests/ANSODEngine-UnitTest/CustomModel-StressTest.cpp b/tests/ANSODEngine-UnitTest/CustomModel-StressTest.cpp new file mode 100644 index 0000000..b149553 --- /dev/null +++ b/tests/ANSODEngine-UnitTest/CustomModel-StressTest.cpp @@ -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 + +#include "ANSODTest.h" +#include +#include +#include +#include +#include +#include +// 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& 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 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 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 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 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(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 detections; + int infResult = RunInferenceComplete_CPP(&odHandle, &clonedImage, cameraId.c_str(), "", detections); + auto infEnd = std::chrono::steady_clock::now(); + double infMs = std::chrono::duration(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(now - fpsTimestamps.front()).count() > 2.0) { + fpsTimestamps.pop_front(); + } + double fps = fpsTimestamps.size() / 2.0; + + // --- Update state --- + { + std::lock_guard 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 lk(taskStates[i].mtx); + taskStates[i].statusMsg = "Stream not available"; + continue; + } + + { + std::lock_guard 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(loadEnd - loadStart).count(); + + if (!odHandles[i]) { + printf("%s FAILED to create OD handle\n", tag); + std::lock_guard 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 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 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( + 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( + 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; +} diff --git a/tests/ANSODEngine-UnitTest/Yolov10OV.h b/tests/ANSODEngine-UnitTest/Yolov10OV.h new file mode 100644 index 0000000..46abf18 --- /dev/null +++ b/tests/ANSODEngine-UnitTest/Yolov10OV.h @@ -0,0 +1,189 @@ +#pragma once + +#pragma once + +/// +/// 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 +/// + + +#include "opencv2/opencv.hpp" +#include +#include +#include +#include +#include + +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& 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 post_process(float* result, float factor, int outputLength) { + std::vector position_boxes; + std::vector class_ids; + std::vector 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 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& 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{1, 3, 640, 640}); + std::vector inputData(640 * 640 * 3); + std::chrono::time_point t_beg; + std::chrono::time_point 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(), inputData.data(), 640 * 640 * 3); + request.infer(); + float* output_data = request.get_output_tensor().data(); + std::vector 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(t_end - t_beg).count()) + + ", Time: " + std::to_string(std::chrono::duration(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::vectorrequests = { 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{1, 3, 640, 640}); + requests[1].get_input_tensor().set_shape(std::vector{1, 3, 640, 640}); + cv::Mat frame; + capture.read(frame); + std::vector inputData(640 * 640 * 3); + pre_process(&frame, 640, &factor, inputData); + memcpy(requests[0].get_input_tensor().data(), inputData.data(), 640 * 640 * 3); + requests[0].start_async(); + std::chrono::time_point t_beg; + std::chrono::time_point 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(), inputData.data(), 640 * 640 * 3); + requests[1].start_async(); + requests[0].wait(); + float* output_data = requests[0].get_output_tensor().data(); + std::vector 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(t_end - t_beg).count()) + + ", Time: " + std::to_string(std::chrono::duration(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; + } +} diff --git a/tests/ANSODEngine-UnitTest/Yolov10RT.h b/tests/ANSODEngine-UnitTest/Yolov10RT.h new file mode 100644 index 0000000..63f1751 --- /dev/null +++ b/tests/ANSODEngine-UnitTest/Yolov10RT.h @@ -0,0 +1,229 @@ +#pragma once + +/// +/// //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 +/// + + +#include "opencv2/opencv.hpp" +#include +#include +#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(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(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(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& 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 postProcess(float* result, float factor, int outputLength) { + std::vector positionBoxes; + std::vector classIds; + std::vector 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 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& 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 creatContext(std::string modelPath) { + std::ifstream filePtr(modelPath, std::ios::binary); + if (!filePtr.good()) { + std::cerr << "Errror" << std::endl; + return std::shared_ptr(); + } + 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(engine->createExecutionContext()); + } + + + void yolov10Infer() { + const char* videoPath = "E:\\Text_dataset\\car_test.mov"; + const char* enginePath = "E:\\Text_Model\\yolov10s.engine"; + + std::shared_ptr 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 output_data(300 * 6); + std::vector 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 result = postProcess(output_data.data(), factor, 300); + drawBbox(frame, result); + imshow("Frame", frame); + cv::waitKey(10); + } + cv::destroyAllWindows(); + } +} \ No newline at end of file diff --git a/tests/ANSODEngine-UnitTest/yolov10.h b/tests/ANSODEngine-UnitTest/yolov10.h new file mode 100644 index 0000000..7425d6e --- /dev/null +++ b/tests/ANSODEngine-UnitTest/yolov10.h @@ -0,0 +1,187 @@ +#pragma once +#include +#include +#include +#include +#include +#include +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 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 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& detections, const std::vector& class_names); + std::vector 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 model = core.read_model(model_path); + if (model->is_dynamic()) { + model->reshape({ 1, 3, static_cast(model_input_shape_.height), static_cast(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 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> 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> 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 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(frame.cols / model_input_shape_.width); + factor_.y = static_cast(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(); + 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(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& detections, const std::vector& class_names) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution 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 GetClassNameFromMetadata(const std::string& metadata_path) { + std::vector 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; + } + +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0075b41..b3610ca 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,2 +1,6 @@ # ANSCORE Unit Tests -# Add test executables here as needed +add_subdirectory(ANSCV-UnitTest) +add_subdirectory(ANSODEngine-UnitTest) +add_subdirectory(ANSFR-UnitTest) +add_subdirectory(ANSLPR-UnitTest) +add_subdirectory(ANSOCR-UnitTest)