#include "ANSCUSTOMDetector.h" #include "Utility.h" #include namespace ANSCENTER { std::string ANSCUSTOMDETECTOR::FindANSCustomLibraryName(const std::string& folderPath, const std::string& keyword) { ANS_DBG("ANSCUSTOM_FindLib", "ENTRY folder=%s keyword=%s", folderPath.c_str(), keyword.c_str()); std::string searchPath = folderPath + "\\*.dll"; WIN32_FIND_DATAA findFileData; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findFileData); if (hFind == INVALID_HANDLE_VALUE) { ANS_DBG("ANSCUSTOM_FindLib", "NO_MATCH (FindFirstFile invalid handle) folder=%s", folderPath.c_str()); return ""; // Return an empty string if no file is found } do { std::string fileName = findFileData.cFileName; if (fileName.find(keyword) != std::string::npos) { FindClose(hFind); // Close the handle before returning std::string fullPath = folderPath + "\\" + fileName; ANS_DBG("ANSCUSTOM_FindLib", "FOUND %s", fullPath.c_str()); return fullPath; // Return the full path } } while (FindNextFileA(hFind, &findFileData) != 0); FindClose(hFind); // Close the handle after finishing the loop ANS_DBG("ANSCUSTOM_FindLib", "NO_MATCH folder=%s keyword=%s", folderPath.c_str(), keyword.c_str()); return ""; // Return an empty string if no match is found } bool ANSCUSTOMDETECTOR::OptimizeModel(bool fp16, std::string& optimizedModelFolder) { ANS_DBG("ANSCUSTOM_Optimize", "ENTRY this=%p fp16=%d", (void*)this, (int)fp16); std::lock_guard lock(_mutex); if (!ANSODBase::OptimizeModel(fp16, optimizedModelFolder)) { ANS_DBG("ANSCUSTOM_Optimize", "ERROR base OptimizeModel failed this=%p", (void*)this); return false; } optimizedModelFolder = _modelFolder; if (!_customDetector) { ANS_DBG("ANSCUSTOM_Optimize", "ERROR _customDetector null this=%p", (void*)this); return false; } bool ok = _customDetector->OptimizeModel(fp16); ANS_DBG("ANSCUSTOM_Optimize", "%s this=%p folder=%s", ok ? "SUCCESS" : "FAILED", (void*)this, optimizedModelFolder.c_str()); return ok; } bool ANSCUSTOMDETECTOR::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) { ANS_DBG("ANSCUSTOM_LoadModel", "ENTRY this=%p zip=%s", (void*)this, modelZipFilePath.c_str()); std::lock_guard lock(_mutex); ModelLoadingGuard mlg(_modelLoading); try { bool result = ANSODBase::LoadModel(modelZipFilePath, modelZipPassword); if (!result) { ANS_DBG("ANSCUSTOM_LoadModel", "ERROR base LoadModel failed this=%p zip=%s", (void*)this, modelZipFilePath.c_str()); return false; } std::string labelMap; CreateCustomDetector(); if (!_customDetector) { ANS_DBG("ANSCUSTOM_LoadModel", "ERROR _customDetector null after Create this=%p", (void*)this); return false; } //_customDetector->SetLoadEngineOnCreate(this->_loadEngineOnCreation); bool ok = _customDetector->Initialize(_modelFolder,_modelConfig.detectionScoreThreshold, labelMap); ANS_DBG("ANSCUSTOM_LoadModel", "%s this=%p folder=%s thr=%.3f", ok ? "SUCCESS" : "FAILED", (void*)this, _modelFolder.c_str(), _modelConfig.detectionScoreThreshold); return ok; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_LoadModel", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMDETECTOR::LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap) { ANS_DBG("ANSCUSTOM_LoadFolder", "ENTRY this=%p model=%s class=%s folder=%s", (void*)this, modelName.c_str(), className.c_str(), modelFolder.c_str()); std::lock_guard lock(_mutex); ModelLoadingGuard mlg(_modelLoading); try { _modelFolder = modelFolder; std::string labelMap; _modelConfig = modelConfig; if (_modelConfig.modelMNSThreshold < 0.2) _modelConfig.modelMNSThreshold = 0.5; if (_modelConfig.modelConfThreshold < 0.2) _modelConfig.modelConfThreshold = 0.5; CreateCustomDetector(); if (!_customDetector) { ANS_DBG("ANSCUSTOM_LoadFolder", "ERROR _customDetector null after Create this=%p", (void*)this); _isInitialized = false; return false; } _customDetector->SetLoadEngineOnCreate(this->_loadEngineOnCreation); _isInitialized = _customDetector->Initialize(_modelFolder, _modelConfig.detectionScoreThreshold, labelMap); ANS_DBG("ANSCUSTOM_LoadFolder", "%s this=%p folder=%s thr=%.3f loadOnCreate=%d", _isInitialized ? "SUCCESS" : "FAILED", (void*)this, _modelFolder.c_str(), _modelConfig.detectionScoreThreshold, (int)this->_loadEngineOnCreation); return _isInitialized; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_LoadFolder", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMDETECTOR::ConfigureParameters(Params& param) { ANS_DBG("ANSCUSTOM_Configure", "ENTRY this=%p", (void*)this); std::lock_guard lock(_mutex); try { if (!_customDetector) { ANS_DBG("ANSCUSTOM_Configure", "ERROR _customDetector null this=%p", (void*)this); this->_logger.LogError("ANSCUSTOMDETECTOR::ConfigureParamaters", "Custom detector is not initialized", __FILE__, __LINE__); return false; } // Convert the vector of Params to a vector of CustomParams CustomParams customParams; _customDetector->ConfigureParameters(customParams); // loop throught this->_params and set the values param.ROI_Config.clear(); for (auto& cf : customParams.ROI_Config) { ROIConfig ROIConfig; ROIConfig.Rectangle = cf.Rectangle; ROIConfig.Polygon = cf.Polygon; ROIConfig.Line = cf.Line; ROIConfig.MinItems = cf.MinItems; ROIConfig.MaxItems = cf.MaxItems; ROIConfig.Name = cf.Name; ROIConfig.ROIMatch = cf.ROIMatch; param.ROI_Config.push_back(ROIConfig); } param.ROI_Options.clear(); for (auto& op : customParams.ROI_Options) { param.ROI_Options.push_back(op); } param.Parameters.clear(); for (auto& par : customParams.Parameters) { Parameter Param; Param.Name = par.Name; Param.DataType = par.DataType; Param.NoOfDecimals = par.NoOfDecimals; Param.MaxValue = par.MaxValue; Param.MinValue = par.MinValue; Param.StartValue = par.StartValue; Param.ListItems.clear(); for (auto& item : par.ListItems) { Param.ListItems.push_back(item); } Param.DefaultValue = par.DefaultValue; Param.Value = par.Value; param.Parameters.push_back(Param); } param.ROI_Values.clear(); for (auto& roi : customParams.ROI_Values) { ROIValue roiValue; roiValue.ROIMatch = roi.ROIMatch; roiValue.OriginalImageSize = roi.OriginalImageSize; roiValue.Name = roi.Name; roiValue.Option = roi.Option; roiValue.ROIPoints.clear(); for (auto& point : roi.ROIPoints) { Point customPoint; customPoint.x = point.x; customPoint.y = point.y; roiValue.ROIPoints.push_back(customPoint); } param.ROI_Values.push_back(roiValue); } ANS_DBG("ANSCUSTOM_Configure", "SUCCESS this=%p ROI_Config=%zu Options=%zu Params=%zu ROI_Values=%zu", (void*)this, param.ROI_Config.size(), param.ROI_Options.size(), param.Parameters.size(), param.ROI_Values.size()); return true; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_Configure", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::ConfigureParamaters", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMDETECTOR::SetParameters(const Params& param) { ANS_DBG("ANSCUSTOM_SetParams", "ENTRY this=%p ROI_Config=%zu Options=%zu Params=%zu ROI_Values=%zu", (void*)this, param.ROI_Config.size(), param.ROI_Options.size(), param.Parameters.size(), param.ROI_Values.size()); std::lock_guard lock(_mutex); try { if (!_customDetector) { ANS_DBG("ANSCUSTOM_SetParams", "ERROR _customDetector null this=%p", (void*)this); return false; } // Convert the vector of Params to a vector of CustomParams ANSODBase::SetParameters(param); CustomParams customParams; customParams.ROI_Config.clear(); for (auto& cf : param.ROI_Config) { CustomROIConfig customROIConfig; customROIConfig.Rectangle = cf.Rectangle; customROIConfig.Polygon = cf.Polygon; customROIConfig.Line = cf.Line; customROIConfig.MinItems = cf.MinItems; customROIConfig.MaxItems = cf.MaxItems; customROIConfig.Name = cf.Name; customROIConfig.ROIMatch = cf.ROIMatch; customParams.ROI_Config.push_back(customROIConfig); } customParams.ROI_Options.clear(); for (auto& op : param.ROI_Options) { customParams.ROI_Options.push_back(op); } customParams.Parameters.clear(); for (auto& par : param.Parameters) { CustomParameter customParam; customParam.Name = par.Name; customParam.DataType = par.DataType; customParam.NoOfDecimals = par.NoOfDecimals; customParam.MaxValue = par.MaxValue; customParam.MinValue = par.MinValue; customParam.StartValue = par.StartValue; customParam.ListItems.clear(); for (auto& item : par.ListItems) { customParam.ListItems.push_back(item); } customParam.DefaultValue = par.DefaultValue; customParam.Value = par.Value; customParams.Parameters.push_back(customParam); } customParams.ROI_Values.clear(); for (auto& roi : param.ROI_Values) { CustomROIValue roiValue; roiValue.ROIMatch = roi.ROIMatch; roiValue.OriginalImageSize = roi.OriginalImageSize; roiValue.Name = roi.Name; roiValue.Option = roi.Option; roiValue.ROIPoints.clear(); for (auto& point : roi.ROIPoints) { CustomPoint customPoint; customPoint.x = point.x; customPoint.y = point.y; roiValue.ROIPoints.push_back(customPoint); } customParams.ROI_Values.push_back(roiValue); } bool ok = _customDetector->SetParameters(customParams); ANS_DBG("ANSCUSTOM_SetParams", "%s this=%p", ok ? "SUCCESS" : "FAILED", (void*)this); return ok; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_SetParams", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::SetParamaters", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMDETECTOR::CreateCustomDetector() { ANS_DBG("ANSCUSTOM_CreateDet", "ENTRY this=%p folder=%s prevDet=%p prevHMod=%p", (void*)this, _modelFolder.c_str(), (void*)_customDetector.get(), (void*)hMod); std::lock_guard lock(_mutex); try { Destroy(); //1. Load dynamic library _modelFilePath = FindANSCustomLibraryName(_modelFolder, "ANSCustom");// if (!FileExist(_modelFilePath)) { _modelFilePath = CreateFilePath(_modelFolder, "ANSCustomCode.dll"); // This is the dynamic library } //2. Check if the file exists again if (!FileExist(_modelFilePath)) { ANS_DBG("ANSCUSTOM_CreateDet", "ERROR DLL not found path=%s", _modelFilePath.c_str()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", "Cannot find ANSCustomCode.dll", __FILE__, __LINE__); return false; } // 3. Load the library std::wstring dllPath = String2WString(_modelFilePath); hMod = LoadLibrary(dllPath.c_str()); if (!hMod) { DWORD err = GetLastError(); ANS_DBG("ANSCUSTOM_CreateDet", "ERROR LoadLibrary failed path=%s err=%lu", _modelFilePath.c_str(), (unsigned long)err); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", "Cannot open library", __FILE__, __LINE__); return false; } ANS_DBG("ANSCUSTOM_CreateDet", "LIB_LOADED hMod=%p path=%s", (void*)hMod, _modelFilePath.c_str()); CreatePluginFunc createPlugin = (CreatePluginFunc)GetProcAddress(hMod, "Create"); if (!createPlugin) { ANS_DBG("ANSCUSTOM_CreateDet", "ERROR GetProcAddress(Create) failed hMod=%p — FreeLibrary", (void*)hMod); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize.", "Cannot load Create", __FILE__, __LINE__); FreeLibrary(hMod); hMod = nullptr; return false; } _customDetector = std::unique_ptr(createPlugin()); if (!_customDetector) { ANS_DBG("ANSCUSTOM_CreateDet", "ERROR createPlugin returned null hMod=%p — FreeLibrary", (void*)hMod); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", "Cannot create custom detector", __FILE__, __LINE__); FreeLibrary(hMod); hMod = nullptr; return false; } ANS_DBG("ANSCUSTOM_CreateDet", "SUCCESS this=%p detector=%p hMod=%p", (void*)this, (void*)_customDetector.get(), (void*)hMod); return true; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_CreateDet", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", e.what(), __FILE__, __LINE__); return false; } } bool ANSCUSTOMDETECTOR::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) { ANS_DBG("ANSCUSTOM_Initialize", "ENTRY this=%p zip=%s", (void*)this, modelZipFilePath.c_str()); std::lock_guard lock(_mutex); ModelLoadingGuard mlg(_modelLoading); try { bool result = ANSODBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap); if (!result) { ANS_DBG("ANSCUSTOM_Initialize", "ERROR base Initialize failed this=%p zip=%s", (void*)this, modelZipFilePath.c_str()); return false; } _modelConfig = modelConfig; if (_modelConfig.modelMNSThreshold < 0.2) _modelConfig.modelMNSThreshold = 0.5; if (_modelConfig.modelConfThreshold < 0.2) _modelConfig.modelConfThreshold = 0.5; _modelConfig.detectionType = ANSCENTER::DetectionType::DETECTION; labelMap.clear(); //1. Create custom detector CreateCustomDetector(); if (!_customDetector) { ANS_DBG("ANSCUSTOM_Initialize", "ERROR _customDetector null after Create this=%p", (void*)this); _isInitialized = false; return false; } //2. Load initial model _customDetector->SetLoadEngineOnCreate(this->_loadEngineOnCreation); _isInitialized = _customDetector->Initialize(_modelFolder, _modelConfig.detectionScoreThreshold,labelMap); ANS_DBG("ANSCUSTOM_Initialize", "%s this=%p folder=%s thr=%.3f loadOnCreate=%d", _isInitialized ? "SUCCESS" : "FAILED", (void*)this, _modelFolder.c_str(), _modelConfig.detectionScoreThreshold, (int)this->_loadEngineOnCreation); return _isInitialized; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_Initialize", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", e.what(), __FILE__, __LINE__); return false; } } std::vector ANSCUSTOMDETECTOR::RunInference(const cv::Mat& input) { return RunInference(input, "CustomCam"); } std::vector ANSCUSTOMDETECTOR::RunInference(const cv::Mat& input,const std::string& camera_id) { ANS_DBG("ANSCUSTOM_Infer", "ENTRY this=%p cam=%s in=%dx%d type=%d", (void*)this, camera_id.c_str(), input.cols, input.rows, input.type()); if (!PreInferenceCheck("ANSCUSTOMDETECTOR::RunInference")) { ANS_DBG("ANSCUSTOM_Infer", "EARLY_OUT preInferenceCheck failed this=%p cam=%s", (void*)this, camera_id.c_str()); return {}; } std::vector result; try { // Early returns - good practice maintained if (!_licenseValid) { ANS_DBG("ANSCUSTOM_Infer", "ERROR invalid license this=%p cam=%s", (void*)this, camera_id.c_str()); this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference", "Invalid License", __FILE__, __LINE__); return result; } if (!_isInitialized) { ANS_DBG("ANSCUSTOM_Infer", "ERROR not initialized this=%p cam=%s", (void*)this, camera_id.c_str()); this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference", "Model is not initialized", __FILE__, __LINE__); return result; } if (input.empty() || input.cols < 10 || input.rows < 10) { ANS_DBG("ANSCUSTOM_Infer", "EARLY_OUT input too small this=%p cam=%s %dx%d", (void*)this, camera_id.c_str(), input.cols, input.rows); return result; } if (!_customDetector) { ANS_DBG("ANSCUSTOM_Infer", "ERROR _customDetector null this=%p cam=%s", (void*)this, camera_id.c_str()); return result; } // Run inference std::vector customResult = _customDetector->RunInference(input, camera_id); // Pre-allocate to avoid reallocations result.reserve(customResult.size()); //// Use emplace_back + move semantics for zero-copy construction for (auto& customObj : customResult) { Object obj; obj.classId = customObj.classId; obj.trackId = customObj.trackId; obj.className = std::move(customObj.className); obj.confidence = customObj.confidence; obj.mask = std::move(customObj.mask); obj.box = customObj.box; obj.extraInfo = std::move(customObj.extraInfo); obj.kps = std::move(customObj.kps); obj.polygon = std::move(customObj.polygon); obj.cameraId = std::move(customObj.cameraId); result.emplace_back(std::move(obj)); } if (_trackerEnabled) { result = ApplyTracking(result, camera_id); if (_stabilizationEnabled) result = StabilizeDetections(result, camera_id); } ANS_DBG("ANSCUSTOM_Infer", "DONE this=%p cam=%s det=%zu tracked=%d stab=%d", (void*)this, camera_id.c_str(), result.size(), (int)_trackerEnabled, (int)_stabilizationEnabled); return result; // RVO applies, no copy } catch (const std::exception& e) { // Catch by const reference ANS_DBG("ANSCUSTOM_Infer", "ERROR exception this=%p cam=%s: %s", (void*)this, camera_id.c_str(), e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::RunInference", e.what(), __FILE__, __LINE__); return {}; // Return empty vector } } ANSCUSTOMDETECTOR::~ANSCUSTOMDETECTOR() { ANS_DBG("ANSCUSTOM_Dtor", "ENTRY this=%p detector=%p hMod=%p", (void*)this, (void*)_customDetector.get(), (void*)hMod); try { // Auto-release plugin object before unloading its DLL. // Destroy() itself swallows exceptions, but wrap defensively // so the destructor never throws. Destroy(); } catch (const std::exception& e) { ANS_DBG("ANSCUSTOM_Dtor", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::~ANSCUSTOMDETECTOR()", e.what(), __FILE__, __LINE__); } catch (...) { ANS_DBG("ANSCUSTOM_Dtor", "ERROR unknown exception this=%p", (void*)this); } ANS_DBG("ANSCUSTOM_Dtor", "EXIT this=%p detector=%p hMod=%p", (void*)this, (void*)_customDetector.get(), (void*)hMod); } bool ANSCUSTOMDETECTOR::Destroy() { ANS_DBG("ANSCUSTOM_Destroy", "ENTRY this=%p detector=%p hMod=%p", (void*)this, (void*)_customDetector.get(), (void*)hMod); try { if (_customDetector) { ANS_DBG("ANSCUSTOM_Destroy", "DESTROY detector=%p", (void*)_customDetector.get()); _customDetector->Destroy(); _customDetector.reset(); } if (hMod) { ANS_DBG("ANSCUSTOM_Destroy", "FREE_LIBRARY hMod=%p", (void*)hMod); FreeLibrary(hMod); hMod = nullptr; } ANS_DBG("ANSCUSTOM_Destroy", "SUCCESS this=%p", (void*)this); return true; } catch (std::exception& e) { ANS_DBG("ANSCUSTOM_Destroy", "ERROR exception this=%p: %s", (void*)this, e.what()); this->_logger.LogFatal("ANSCUSTOMDETECTOR::Destroy", e.what(), __FILE__, __LINE__); return false; } } } //std::vector ANSCUSTOMDETECTOR::RunInference(const cv::Mat& input, const std::string& camera_id) { // std::lock_guard lock(_mutex); // std::vector result; // try { // if (!_licenseValid) { // this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference", "Invalid License", __FILE__, __LINE__); // return result; // } // if (!_isInitialized) { // this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference", "Model is not initialized", __FILE__, __LINE__); // return result; // } // // Run inference // if (input.empty()) return result; // if ((input.cols < 10) || (input.rows < 10)) return result; // std::vector customResult; // customResult = _customDetector->RunInference(input,camera_id); // for (int i = 0; i < customResult.size(); i++) { // Object obj; // obj.classId = customResult[i].classId; // obj.trackId = customResult[i].trackId; // obj.className = customResult[i].className; // obj.confidence = customResult[i].confidence; // obj.mask = customResult[i].mask; // obj.box = customResult[i].box; // obj.extraInfo = customResult[i].extraInfo; // obj.kps = customResult[i].kps; // obj.polygon = customResult[i].polygon; // obj.cameraId = customResult[i].cameraId; // //obj.attributes = customResult[i].attributes; // result.push_back(obj); // } // return result; // } // catch (std::exception& e) { // result.clear(); // this->_logger.LogFatal("ANSCUSTOMDETECTOR::RunInference", e.what(), __FILE__, __LINE__); // return result; // } //}