#include "ANSODHUB.h" #include "Utility.h" namespace ANSCENTER { // ODHUBAPI bool ODHUBAPI::OptimizeModel(bool fp16, std::string& optimizedModelFolder) { std::lock_guard lock(_mutex); if (!ANSODBase::OptimizeModel(fp16, optimizedModelFolder)) { return false; } if (FileExist(_modelFilePath)) { optimizedModelFolder = GetParentFolder(_modelFilePath); this->_logger.LogDebug("ODHUBAPI::OptimizeModel", "This model is optimized. No need other optimization.", __FILE__, __LINE__); return true; } else { optimizedModelFolder = ""; this->_logger.LogFatal("ODHUBAPI::OptimizeModel", "This model is not exist. Please check the model path again.", __FILE__, __LINE__); return false; } } bool ODHUBAPI::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) { std::lock_guard lock(_mutex); ModelLoadingGuard mlg(_modelLoading); try { bool result = ANSODBase::LoadModel(modelZipFilePath, modelZipPassword); if (!result) return false; // 0. Check weigth file std::string weightfile = CreateFilePath(_modelFolder, "train_last.weights"); if (FileExist(weightfile)) { // This is the darknet Yolov4 _modelFilePath = weightfile; _classFilePath = CreateFilePath(_modelFolder, "classes.names"); _modelCfgPath = CreateFilePath(_modelFolder, "test.cfg"); if (std::filesystem::exists(_modelCfgPath)) { this->_logger.LogDebug("ODHUBAPI::LoadModel. Loading ODHUB weight", _modelCfgPath, __FILE__, __LINE__); } else { this->_logger.LogError("ODHUBAPI::LoadModel. Model config file is not exist", _modelCfgPath, __FILE__, __LINE__); return false; } } else { this->_logger.LogError("ODHUBAPI::LoadModel. Model file is not exist", _modelFilePath, __FILE__, __LINE__); return false; } std::ifstream isValidFileName(_classFilePath); if (!isValidFileName) { LoadClassesFromString(); } else { LoadClassesFromFile(); } //1. Load the model EngineType engineType = ANSLicenseHelper::CheckHardwareInformation(); if (engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA { _useGPU = true; _net = new Detector(); _net->Init(_modelCfgPath.c_str(), _modelFilePath.c_str(), 0, 1); } else { _useGPU = false; _netCPU = new CPUDetector(); _netCPU->Init(_modelCfgPath.c_str(), _modelFilePath.c_str(), -1, 1); } _isInitialized = true; return true; } catch (std::exception& e) { this->_logger.LogFatal("ODHUBAPI::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ODHUBAPI::LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap) { std::lock_guard lock(_mutex); ModelLoadingGuard mlg(_modelLoading); try { bool result = ANSODBase::LoadModelFromFolder(licenseKey, modelConfig, modelName, className, modelFolder, labelMap); if (!result) return false; std::string _modelName = modelName; if (_modelName.empty()) { _modelName = "train_last"; } std::string modelFullName = _modelName + ".weights"; _modelConfig = modelConfig; _modelConfig.detectionType = ANSCENTER::DetectionType::DETECTION; _modelConfig.inpHeight = 416; _modelConfig.inpWidth = 416; // 0. Check weigth file std::string weightfile = CreateFilePath(_modelFolder, modelFullName); if (FileExist(weightfile)) { // This is the darknet Yolov4 _modelFilePath = weightfile; _classFilePath = CreateFilePath(_modelFolder, className); _modelCfgPath = CreateFilePath(_modelFolder, "test.cfg"); if (std::filesystem::exists(_modelCfgPath)) { this->_logger.LogDebug("ODHUBAPI::LoadModel. Loading ODHUB weight", _modelCfgPath, __FILE__, __LINE__); } else { this->_logger.LogError("ODHUBAPI::LoadModel. Model config file is not exist", _modelCfgPath, __FILE__, __LINE__); return false; } } else { this->_logger.LogError("ODHUBAPI::LoadModel. Model file is not exist", _modelFilePath, __FILE__, __LINE__); return false; } std::ifstream isValidFileName(_classFilePath); if (!isValidFileName) { LoadClassesFromString(); } else { LoadClassesFromFile(); } // 1. Load labelMap and engine labelMap.clear(); if (!_classes.empty()) labelMap = VectorToCommaSeparatedString(_classes); //2. Load the model EngineType engineType = ANSLicenseHelper::CheckHardwareInformation(); if (engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA { _useGPU = true; _net = new Detector(); _net->Init(_modelCfgPath.c_str(), _modelFilePath.c_str(), 0, 1); } else { _useGPU = false; _netCPU = new CPUDetector(); _netCPU->Init(_modelCfgPath.c_str(), _modelFilePath.c_str(), -1, 1); } _isInitialized = true; return true; } catch (std::exception& e) { this->_logger.LogFatal("ODHUBAPI::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ODHUBAPI::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) { std::lock_guard lock(_mutex); ModelLoadingGuard mlg(_modelLoading); try { bool result = ANSODBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap); if (!result) return false; // Parsing for YOLO only here _modelConfig = modelConfig; _modelConfig.detectionType = ANSCENTER::DetectionType::DETECTION; _modelConfig.inpHeight = 416; _modelConfig.inpWidth = 416; // 0. Check weigth file std::string weightfile = CreateFilePath(_modelFolder, "train_last.weights"); if (FileExist(weightfile)) { // This is the darknet Yolov4 _modelFilePath = weightfile; _classFilePath = CreateFilePath(_modelFolder, "classes.names"); _modelCfgPath = CreateFilePath(_modelFolder, "test.cfg"); if (std::filesystem::exists(_modelCfgPath)) { this->_logger.LogDebug("ODHUBAPI::LoadModel. Loading ODHUB weight", _modelCfgPath, __FILE__, __LINE__); } else { this->_logger.LogError("ODHUBAPI::LoadModel. Model config file is not exist", _modelCfgPath, __FILE__, __LINE__); return false; } } else { this->_logger.LogError("ODHUBAPI::LoadModel. Model file is not exist", _modelFilePath, __FILE__, __LINE__); return false; } std::ifstream isValidFileName(_classFilePath); if (!isValidFileName) { LoadClassesFromString(); } else { LoadClassesFromFile(); } // 1. Load labelMap and engine labelMap.clear(); if (!_classes.empty()) labelMap = VectorToCommaSeparatedString(_classes); //2. Load the model EngineType engineType = ANSLicenseHelper::CheckHardwareInformation(); if (engineType == EngineType::NVIDIA_GPU) // NVIDIA CUDA { _useGPU = true; _net = new Detector(); _net->Init(_modelCfgPath.c_str(), _modelFilePath.c_str(), 0, 1); } else { _useGPU = false; _netCPU = new CPUDetector(); _netCPU->Init(_modelCfgPath.c_str(), _modelFilePath.c_str(), -1, 1); } _isInitialized = true; return true; } catch (std::exception& e) { this->_logger.LogFatal("ODHUBAPI::Initialize", e.what(), __FILE__, __LINE__); return false; } } std::vector ODHUBAPI::RunInference(const cv::Mat& input) { return RunInference(input, "ODHUBCam"); } std::vector ODHUBAPI::RunInference(const cv::Mat& input, const std::string& camera_id) { if (!PreInferenceCheck("ODHUBAPI::RunInference")) return {}; std::vector result; try { // Early validation if (!_licenseValid) { _logger.LogError("ODHUBAPI::RunInference", "Invalid License", __FILE__, __LINE__); return result; } if (!_isInitialized) { _logger.LogError("ODHUBAPI::RunInference", "Model is not initialized", __FILE__, __LINE__); return result; } if (input.empty() || input.cols < 10 || input.rows < 10) { return result; } // Prepare image for inference cv::Mat processedImage; if (input.channels() == 1) { cv::cvtColor(input, processedImage, cv::COLOR_GRAY2BGR); } else { // Shallow copy is safe if detect() doesn't modify input // If it does, use: processedImage = input.clone(); processedImage = input; } // Get detections (unified call) std::vector boxes = _useGPU ? _net->detect(processedImage, _modelConfig.detectionScoreThreshold, false) : _netCPU->detect(processedImage, _modelConfig.detectionScoreThreshold, false); // Pre-allocate result vector result.reserve(boxes.size()); // Pre-calculate image bounds const int maxWidth = input.cols; const int maxHeight = input.rows; const cv::Rect imageBounds(0, 0, maxWidth, maxHeight); const int classNameSize = static_cast(_classes.size()); // Convert detections to Objects for (const auto& box : boxes) { Object obj; // Set class info obj.classId = box.obj_id; if (!_classes.empty()) { obj.className = (box.obj_id < classNameSize) ? _classes[box.obj_id] : _classes[classNameSize - 1]; } else { obj.className = "Unknown"; } // Set detection info obj.confidence = box.prob; obj.cameraId = camera_id; // Clamp bounding box to image bounds obj.box = cv::Rect( static_cast(box.x), static_cast(box.y), static_cast(box.w), static_cast(box.h) ) & imageBounds; // Single intersection operation // Skip invalid boxes (completely outside image) if (obj.box.area() > 0) { result.push_back(std::move(obj)); } } if (_trackerEnabled) { result = ApplyTracking(result, camera_id); if (_stabilizationEnabled) result = StabilizeDetections(result, camera_id); } return result; } catch (const std::exception& e) { _logger.LogFatal("ODHUBAPI::RunInference", e.what(), __FILE__, __LINE__); return {}; // Return empty vector } } ODHUBAPI::~ODHUBAPI() { try { this->_logger.LogDebug("ODHUBAPI::~ODHUBAPI()", "Release ODHUBAPI ", __FILE__, __LINE__); } catch (std::exception& e) { this->_logger.LogFatal("ODHUBAPI::~ODHUBAPI()", e.what(), __FILE__, __LINE__); } } bool ODHUBAPI::Destroy() { try { this->_logger.LogDebug("ODHUBAPI::Destroy()", "Release ODHUBAPI ", __FILE__, __LINE__); if (_net != nullptr)delete _net; if (_netCPU != nullptr)delete _netCPU; _net = nullptr; _netCPU = nullptr; return true; } catch (std::exception& e) { this->_logger.LogFatal("ODHUBAPI::Destroy()", e.what(), __FILE__, __LINE__); return false; } } } //std::vector ODHUBAPI::RunInference(const cv::Mat& input, const std::string& camera_id) { // std::lock_guard lock(_mutex); // std::vector result; // try { // if (!_licenseValid) { // this->_logger.LogError("ODHUBAPI::RunInference", "Invalid License", __FILE__, __LINE__); // return result; // } // if (!_isInitialized) { // this->_logger.LogError("ODHUBAPI::RunInference", "Model is not initialized", __FILE__, __LINE__); // return result; // } // if (input.empty()) return result; // if ((input.cols < 10) || (input.rows < 10)) return result; // int maxWidth = input.cols; // int maxHeight = input.rows; // cv::Mat processedImage; // if (input.channels() == 1) { // cv::cvtColor(input, processedImage, cv::COLOR_GRAY2BGR); // } // else { // processedImage = input; // } // int classNameSize = _classes.size(); // // Run inference // if (_useGPU) // Use GPU // { // std::vector boxes = _net->detect(processedImage, _modelConfig.detectionScoreThreshold, false); // for (auto& box : boxes) { // Object obj; // // Check if the box is out of the image // if (box.x < 0) box.x = 0; // if (box.y < 0) box.y = 0; // if (box.x + box.w > maxWidth) box.w = maxWidth - box.x - 5; // if (box.y + box.h > maxHeight) box.h = maxHeight - box.y - 5; // obj.classId = box.obj_id; // // if (!_classes.empty()) { // if (box.obj_id < classNameSize) { // obj.className = _classes[box.obj_id]; // } // else { // obj.className = _classes[classNameSize - 1]; // Use last valid class name if out of range // } // } // else { // obj.className = "Unknown"; // Fallback if _classes is empty // } // obj.confidence = box.prob; // obj.box.x = box.x; // obj.box.y = box.y; // obj.box.width = box.w; // obj.box.height = box.h; // obj.box.x = std::max(0, obj.box.x); // obj.box.y = std::max(0, obj.box.y); // obj.box.width = std::min(maxWidth - obj.box.x, obj.box.width); // obj.box.height = std::min(maxHeight - obj.box.y, obj.box.height); // obj.cameraId = camera_id; // result.push_back(obj); // } // //EnqueueDetection(result, camera_id); // return result; // } // else // Use CPU // { // std::vector boxes = _netCPU->detect(processedImage, _modelConfig.detectionScoreThreshold, false); // for (auto& box : boxes) { // Object obj; // // Check if the box is out of the image // if (box.x < 0) box.x = 0; // if (box.y < 0) box.y = 0; // if (box.x + box.w > maxWidth) box.w = maxWidth - box.x - 5; // if (box.y + box.h > maxHeight) box.h = maxHeight - box.y - 5; // obj.classId = box.obj_id; // if (!_classes.empty()) { // if (box.obj_id < classNameSize) { // obj.className = _classes[box.obj_id]; // } // else { // obj.className = _classes[classNameSize - 1]; // Use last valid class name if out of range // } // } // else { // obj.className = "Unknown"; // Fallback if _classes is empty // } // obj.confidence = box.prob; // obj.box.x = box.x; // obj.box.y = box.y; // obj.box.width = box.w; // obj.box.height = box.h; // obj.box.x = std::max(0, obj.box.x); // obj.box.y = std::max(0, obj.box.y); // obj.box.width = std::min(maxWidth - obj.box.x, obj.box.width); // obj.box.height = std::min(maxHeight - obj.box.y, obj.box.height); // obj.cameraId = camera_id; // result.push_back(obj); // } // //EnqueueDetection(result, camera_id); // return result; // } // } // catch (std::exception& e) { // result.clear(); // this->_logger.LogFatal("ODHUBAPI::RunInference", e.what(), __FILE__, __LINE__); // return result; // } //}