446 lines
14 KiB
C++
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;
|
|
// }
|
|
//}
|