Files
ANSCORE/modules/ANSODEngine/ANSODHUB.cpp

446 lines
14 KiB
C++

#include "ANSODHUB.h"
#include "Utility.h"
namespace ANSCENTER
{
// ODHUBAPI
bool ODHUBAPI::OptimizeModel(bool fp16, std::string& optimizedModelFolder) {
std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<Object> ODHUBAPI::RunInference(const cv::Mat& input) {
return RunInference(input, "ODHUBCam");
}
std::vector<Object> ODHUBAPI::RunInference(const cv::Mat& input, const std::string& camera_id)
{
if (!PreInferenceCheck("ODHUBAPI::RunInference")) return {};
std::vector<Object> 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<bbox_t> 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<int>(_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<int>(box.x),
static_cast<int>(box.y),
static_cast<int>(box.w),
static_cast<int>(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<Object> ODHUBAPI::RunInference(const cv::Mat& input, const std::string& camera_id) {
// std::lock_guard<std::recursive_mutex> lock(_mutex);
// std::vector<Object> 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<bbox_t> 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<bbox_t> 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;
// }
//}