#include "ANSPOSE.h" #include #include #include namespace ANSCENTER { bool ANSPOSE::OptimizeModel(bool fp16, std::string& optimizedModelFolder) { std::lock_guard lock(_mutex); if (!ANSODBase::OptimizeModel(fp16, optimizedModelFolder)) { return false; } if (FileExist(_modelFilePath)) { std::string modelName = GetFileNameWithoutExtension(_modelFilePath); std::string binaryModelName = modelName + ".bin"; std::string modelFolder = GetParentFolder(_modelFilePath); std::string optimizedModelPath = CreateFilePath(modelFolder, binaryModelName); if (FileExist(optimizedModelPath)) { this->_logger.LogDebug("ANSPOSE::OptimizeModel", "This model is optimized. No need other optimization.", __FILE__, __LINE__); optimizedModelFolder = modelFolder; return true; } else { this->_logger.LogFatal("ANSPOSE::OptimizeModel", "This model can not be optimized.", __FILE__, __LINE__); optimizedModelFolder = modelFolder; return false; } } else { this->_logger.LogFatal("ANSPOSE::OptimizeModel", "This model is not exist. Please check the model path again.", __FILE__, __LINE__); optimizedModelFolder = ""; return false; } } bool ANSPOSE::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) { std::lock_guard lock(_mutex); try { bool result = ANSODBase::LoadModel(modelZipFilePath, modelZipPassword); if (!result) return false; _device = GetOpenVINODevice(_core); // 0. Check if the configuration file exist if (FileExist(_modelConfigFile)) { ModelType modelType; std::vector inputShape; _classes = ANSUtilityHelper::GetConfigFileContent(_modelConfigFile, modelType, inputShape); if (inputShape.size() == 2) { if (inputShape[0] > 0)_modelConfig.inpHeight = inputShape[0]; if (inputShape[1] > 0)_modelConfig.inpWidth = inputShape[1]; } } else {// This is old version of model zip file std::string xmlfile = CreateFilePath(_modelFolder, "ansposesetimation.xml"); std::string binaryfile = CreateFilePath(_modelFolder, "ansposesetimation.bin"); if (std::filesystem::exists(xmlfile)) { _modelFilePath = xmlfile; this->_logger.LogDebug("ANSPOSE::Initialize. Loading OpenVINO weight", _modelFilePath, __FILE__, __LINE__); if (FileExist(binaryfile)) { this->_logger.LogDebug("ANSPOSE::Initialize binary weight", binaryfile, __FILE__, __LINE__); } else { this->_logger.LogError("ANSPOSE::Initialize. Model binary file does not exist", binaryfile, __FILE__, __LINE__); return false; } } else { this->_logger.LogError("ANSPOSE::Initialize. Model file does exist", _modelFilePath, __FILE__, __LINE__); return false; } } _isInitialized = true; return true; } catch (std::exception& e) { this->_logger.LogFatal("ANSPOSE::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSPOSE::LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap) { std::lock_guard lock(_mutex); try { bool result = ANSODBase::LoadModelFromFolder(licenseKey, modelConfig, modelName, className, modelFolder, labelMap); if (!result) return false; std::string _modelName = modelName; if (_modelName.empty()) { _modelName = "ansposesetimation"; } std::string xmlFileName = _modelName + ".xml"; std::string binFileName = _modelName + ".bin"; _modelConfig = modelConfig; _modelConfig.detectionType = ANSCENTER::DetectionType::KEYPOINT; _modelConfig.modelType = ModelType::POSE; _modelConfig.inpHeight = 640; _modelConfig.inpWidth = 640; if (_modelConfig.modelMNSThreshold < 0.2) _modelConfig.modelMNSThreshold = 0.5; if (_modelConfig.modelConfThreshold < 0.2) _modelConfig.modelConfThreshold = 0.5; _device = GetOpenVINODevice(_core); // 0. Check if the configuration file exist if (FileExist(_modelConfigFile)) { ModelType modelType; std::vector inputShape; _classes = ANSUtilityHelper::GetConfigFileContent(_modelConfigFile, modelType, inputShape); if (inputShape.size() == 2) { if (inputShape[0] > 0)_modelConfig.inpHeight = inputShape[0]; if (inputShape[1] > 0)_modelConfig.inpWidth = inputShape[1]; } } else {// This is old version of model zip file std::string xmlfile = CreateFilePath(_modelFolder, xmlFileName); std::string binaryfile = CreateFilePath(_modelFolder, binFileName); if (std::filesystem::exists(xmlfile)) { _modelFilePath = xmlfile; this->_logger.LogDebug("ANSPOSE::Initialize. Loading OpenVINO weight", _modelFilePath, __FILE__, __LINE__); if (FileExist(binaryfile)) { this->_logger.LogDebug("ANSPOSE::Initialize binary weight", binaryfile, __FILE__, __LINE__); } else { this->_logger.LogError("ANSPOSE::Initialize. Model binary file does not exist", binaryfile, __FILE__, __LINE__); return false; } } else { this->_logger.LogError("ANSPOSE::Initialize. Model file does exist", _modelFilePath, __FILE__, __LINE__); return false; } } labelMap = "Person"; _isInitialized = true; return true; } catch (std::exception& e) { this->_logger.LogFatal("ANSPOSE::LoadModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSPOSE::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) { std::lock_guard lock(_mutex); try { std::string openVINOVersion = ov::get_openvino_version().buildNumber; this->_logger.LogDebug("ANSPOSE::Initialize. OpenVINO version", openVINOVersion, __FILE__, __LINE__); bool result = ANSODBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap); if (!result) return false; // Parsing for ABNORMAL only here _modelConfig = modelConfig; _modelConfig.detectionType = ANSCENTER::DetectionType::KEYPOINT; _modelConfig.modelType = ModelType::POSE; _modelConfig.inpHeight = 640; _modelConfig.inpWidth = 640; if (_modelConfig.modelMNSThreshold < 0.2) _modelConfig.modelMNSThreshold = 0.5; if (_modelConfig.modelConfThreshold < 0.2) _modelConfig.modelConfThreshold = 0.5; _device = GetOpenVINODevice(_core); // 0. Check if the configuration file exist if (FileExist(_modelConfigFile)) { ModelType modelType; std::vector inputShape; _classes = ANSUtilityHelper::GetConfigFileContent(_modelConfigFile, modelType, inputShape); if (inputShape.size() == 2) { if (inputShape[0] > 0)_modelConfig.inpHeight = inputShape[0]; if (inputShape[1] > 0)_modelConfig.inpWidth = inputShape[1]; } } else {// This is old version of model zip file std::string xmlfile = CreateFilePath(_modelFolder, "ansposesetimation.xml"); std::string binaryfile = CreateFilePath(_modelFolder, "ansposesetimation.bin"); if (std::filesystem::exists(xmlfile)) { _modelFilePath = xmlfile; this->_logger.LogDebug("ANSPOSE::Initialize. Loading OpenVINO weight", _modelFilePath, __FILE__, __LINE__); if (FileExist(binaryfile)) { this->_logger.LogDebug("ANSPOSE::Initialize binary weight", binaryfile, __FILE__, __LINE__); } else { this->_logger.LogError("ANSPOSE::Initialize. Model binary file does not exist", binaryfile, __FILE__, __LINE__); return false; } } else { this->_logger.LogError("ANSPOSE::Initialize. Model file does exist", _modelFilePath, __FILE__, __LINE__); return false; } } labelMap = "Person"; _isInitialized = true; return true; } catch (std::exception& e) { this->_logger.LogFatal("ANSANOMALIB::Initialize", e.what(), __FILE__, __LINE__); labelMap = "Normal,Defect"; return false; } } std::vector ANSPOSE::RunInference(const cv::Mat& input) { return RunInference(input, "CustomCam"); } std::vector ANSPOSE::RunInference(const cv::Mat& input, const std::string& camera_id) { std::lock_guard lock(_mutex); try { // Validation if (!_licenseValid) { _logger.LogError("ANSPOSE::RunInference", "Invalid License", __FILE__, __LINE__); return {}; } if (!_isInitialized) { _logger.LogError("ANSPOSE::RunInference", "Model is not initialized", __FILE__, __LINE__); return {}; } if (input.empty() || input.cols < 10 || input.rows < 10) { return {}; } // Convert to BGR if needed cv::Mat processedImage; if (input.channels() == 1) { cv::cvtColor(input, processedImage, cv::COLOR_GRAY2BGR); } else { processedImage = input; // Shallow copy } const int width = processedImage.cols; const int height = processedImage.rows; // Initialize pipeline once if (!_poseEstimationPipeline) { double aspectRatio = width / static_cast(height); auto model = std::make_unique( _modelFilePath, aspectRatio, 0, 0.5f, "" ); try { _poseEstimationPipeline = new AsyncPipeline(std::move(model), ConfigFactory::getUserConfig(_device, 1, "", 4), _core); } catch (const std::exception& e) { // Fall back to CPU _logger.LogWarn("ANSPOSE::RunInference", "GPU init failed, using CPU: " + std::string(e.what()), __FILE__, __LINE__); model = std::make_unique( _modelFilePath, aspectRatio, 0, 0.5f, "" ); _poseEstimationPipeline = new AsyncPipeline(std::move(model), ConfigFactory::getUserConfig("CPU", 0, "", 0), _core); } } if (!_poseEstimationPipeline) { _logger.LogError("ANSPOSE::RunInference", "Pipeline initialization failed", __FILE__, __LINE__); return {}; } // Run inference auto startTime = std::chrono::steady_clock::now(); int64_t frameNum = _poseEstimationPipeline->submitData( ImageInputData(processedImage), std::make_shared(processedImage, startTime) ); _poseEstimationPipeline->waitForTotalCompletion(); std::unique_ptr result = _poseEstimationPipeline->getResult(); // Process results std::vector output; auto& poses = result->asRef().poses; output.reserve(poses.size()); const cv::Rect imageBounds(0, 0, width, height); for (const auto& pose : poses) { if (pose.keypoints.empty()) { continue; } // Calculate bounding box from keypoints int x_min = width, y_min = height; int x_max = 0, y_max = 0; for (const auto& kp : pose.keypoints) { if (kp.x > 0) { x_min = std::min(x_min, static_cast(kp.x)); x_max = std::max(x_max, static_cast(kp.x)); } if (kp.y > 0) { y_min = std::min(y_min, static_cast(kp.y)); y_max = std::max(y_max, static_cast(kp.y)); } } // Validate bounding box if (x_max <= x_min || y_max <= y_min) { continue; } Object obj; obj.classId = 0; obj.className = "Person"; obj.confidence = 1.0f; obj.cameraId = camera_id; // Set bounding box obj.box = cv::Rect(x_min, y_min, x_max - x_min, y_max - y_min); obj.box &= imageBounds; // Clamp to image bounds // Extract mask ROI (CRITICAL: Clone to avoid dangling reference!) cv::Rect maskRect = obj.box & imageBounds; if (maskRect.area() > 0) { obj.mask = processedImage(maskRect).clone(); // Must clone! } // Store keypoints efficiently obj.kps.reserve(pose.keypoints.size() * 2); obj.polygon.reserve(pose.keypoints.size()); for (const auto& kp : pose.keypoints) { obj.kps.push_back(kp.x); obj.kps.push_back(kp.y); obj.polygon.emplace_back(kp.x, kp.y); } // Build extraInfo string efficiently (if really needed) if (!pose.keypoints.empty()) { std::string keypointX, keypointY; keypointX.reserve(pose.keypoints.size() * 10); // Estimate keypointY.reserve(pose.keypoints.size() * 10); for (size_t i = 0; i < pose.keypoints.size(); i++) { keypointX += std::to_string(pose.keypoints[i].x); keypointY += std::to_string(pose.keypoints[i].y); if (i < pose.keypoints.size() - 1) { keypointX += ";"; keypointY += ";"; } } obj.extraInfo = keypointX + "|" + keypointY; } output.push_back(std::move(obj)); } if (_trackerEnabled) { output = ApplyTracking(output, camera_id); if (_stabilizationEnabled) output = StabilizeDetections(output, camera_id); } return output; } catch (const std::exception& e) { _logger.LogFatal("ANSPOSE::RunInference", e.what(), __FILE__, __LINE__); return {}; } } ANSPOSE::~ANSPOSE() { if (_poseEstimationPipeline) { delete _poseEstimationPipeline; _poseEstimationPipeline = nullptr; } if (FolderExist(_modelFolder)) { if (!DeleteFolder(_modelFolder)) { this->_logger.LogError("ANSPOSE::~ANSPOSE", "Failed to release ANSPOSE Models", __FILE__, __LINE__); } } } bool ANSPOSE::Destroy() { if (_poseEstimationPipeline) { delete _poseEstimationPipeline; _poseEstimationPipeline = nullptr; } if (FolderExist(_modelFolder)) { if (!DeleteFolder(_modelFolder)) { this->_logger.LogError("ANSPOSE::Destroy", "Failed to release ANSPOSE Models", __FILE__, __LINE__); } } return true; } } // std::vector ANSPOSE::RunInference(const cv::Mat& input, const std::string& camera_id) { // std::lock_guard lock(_mutex); // std::vector output; // output.clear(); // if (!_licenseValid) { // this->_logger.LogError("ANSPOSE::RunInference", "Invalid License", __FILE__, __LINE__); // return output; // } // if (!_isInitialized) { // this->_logger.LogError("ANSPOSE::RunInference", "Model is not initialized", __FILE__, __LINE__); // return output; // } // try { // if (input.empty()) return output; // if ((input.cols < 10) || (input.rows < 10)) return output; // // Convert grayscale to 3-channel BGR if needed // cv::Mat processedImage; // if (input.channels() == 1) { // cv::cvtColor(input, processedImage, cv::COLOR_GRAY2BGR); // } // else { // processedImage = input; // } // cv::Mat im = processedImage; // int width = im.cols; // int height = im.rows; // if (!_poseEstimationPipeline) { // // Load Model from Here // std::unique_ptr model; // double aspectRatio = width / static_cast(height); // model.reset(new HPEOpenPose(_modelFilePath, aspectRatio, 0, static_cast(0.5), "")); // //ov::Core core; // try { // _poseEstimationPipeline = new AsyncPipeline(std::move(model), ConfigFactory::getUserConfig(_device, 1, "", 4), _core); // } // catch (const std::exception& e) { // // Fall back to CPU // _poseEstimationPipeline = new AsyncPipeline(std::move(model), ConfigFactory::getUserConfig("CPU", 0, "", 0), _core); // } // } // if (_poseEstimationPipeline) { // auto startTime = std::chrono::steady_clock::now(); // int64_t frameNum = _poseEstimationPipeline->submitData(ImageInputData(im), std::make_shared(im, startTime)); // _poseEstimationPipeline->waitForTotalCompletion(); // std::unique_ptr result = _poseEstimationPipeline->getResult(); // /* static const std::pair keypointsOP[] = { // {1, 2}, // {1, 5}, // {2, 3}, // {3, 4}, // {5, 6}, // {6, 7}, // {1, 8}, // {8, 9}, // {9, 10}, // {1, 11}, // {11, 12}, // {12, 13}, // {1, 0}, // {0, 14}, // {14, 16}, // {0, 15}, // {15, 17} // };*/ // const cv::Point2f absentKeypoint(-1.0f, -1.0f); // for (auto& obj : result->asRef().poses) { // Object result; // float confidence = 1.0; // if (confidence > 0) // { // // Intepret keypoints // int x_min = 10000; // int y_min = 10000; // int x_max = 0; // int y_max = 0; // std::stringstream keypointXss; // std::stringstream keypointYss; // std::vector kps; // std::vector keypoints; // if (obj.keypoints.size() > 0) { // for (size_t keypointIdx = 0; keypointIdx < obj.keypoints.size(); keypointIdx++) { // if (obj.keypoints[keypointIdx].x > 0) { // if (x_min > obj.keypoints[keypointIdx].x) x_min = obj.keypoints[keypointIdx].x; // if (x_max < obj.keypoints[keypointIdx].x) x_max = obj.keypoints[keypointIdx].x; // } // if (obj.keypoints[keypointIdx].y > 0) { // if (y_min > obj.keypoints[keypointIdx].y) y_min = obj.keypoints[keypointIdx].y; // if (y_max < obj.keypoints[keypointIdx].y) y_max = obj.keypoints[keypointIdx].y; // } // keypointXss << obj.keypoints[keypointIdx].x; // Add semicolon after each x value // keypointYss << obj.keypoints[keypointIdx].y; // Add semicolon after each y value // // Add semicolon after each value except the last one // if (keypointIdx < obj.keypoints.size() - 1) // { // keypointXss << ";"; // keypointYss << ";"; // } // cv::Point2f kp; // kp.x = obj.keypoints[keypointIdx].x; // kp.y = obj.keypoints[keypointIdx].y; // kps.push_back(kp); // keypoints.push_back(kp.x); // keypoints.push_back(kp.y); // } // // Retrieve strings from string streams // std::string keypointXString = keypointXss.str(); // std::string keypointYString = keypointYss.str(); // std::string keypointString = keypointXString + "|" + keypointYString; // result.classId = 0; // human keypoint // result.className = "Person"; // result.confidence = confidence; // result.box.x = x_min; // result.box.y = y_min; // result.box.width = x_max - x_min; // result.box.height = y_max - y_min; // result.box.x = std::max(0, result.box.x); // result.box.y = std::max(0, result.box.y); // result.box.width = std::min(width - result.box.x, result.box.width); // result.box.height = std::min(height - result.box.y, result.box.height); // cv::Rect maskImage(cv::Point(x_min, y_min), cv::Point(x_max, y_max)); // result.mask = im(maskImage); // result.polygon = kps; // result.kps = keypoints; // result.extraInfo = keypointString;//Convert keypoint to st; // result.cameraId = camera_id; // output.push_back(result); // } // } // } // im.release(); // } ////EnqueueDetection(output,camera_id); // return output; // } // catch (std::exception& e) { // this->_logger.LogFatal("ANSPOSE::RunInference", e.what(), __FILE__, __LINE__); // return output; // } // }