Files
ANSCORE/modules/ANSODEngine/ANSSAM.cpp

734 lines
24 KiB
C++
Raw Normal View History

2026-03-28 16:54:11 +11:00
#include "ANSSAM.h"
#include <algorithm>
#include <filesystem>
#include <algorithm>
namespace ANSCENTER {
// public:
bool ANSSAM::OptimizeModel(bool fp16, std::string& optimizedModelFolder) {
std::lock_guard<std::recursive_mutex> 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("ANSSAM::OptimizeModel", "This model is optimized. No need other optimization.", __FILE__, __LINE__);
optimizedModelFolder = modelFolder;
return true;
}
else {
this->_logger.LogFatal("ANSSAM::OptimizeModel", "This model can not be optimized.", __FILE__, __LINE__);
optimizedModelFolder = modelFolder;
return false;
}
}
else {
this->_logger.LogFatal("ANSSAM::OptimizeModel", "This model is not exist. Please check the model path again.", __FILE__, __LINE__);
optimizedModelFolder = "";
return false;
}
}
bool ANSSAM::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
bool result = ANSODBase::LoadModel(modelZipFilePath, modelZipPassword);
if (!result) return false;
std::string xmlfile = CreateFilePath(_modelFolder, "anssam.xml");
std::string binaryfile = CreateFilePath(_modelFolder, "anssam.bin");
if (std::filesystem::exists(xmlfile)) {
_modelFilePath = xmlfile;
this->_logger.LogDebug("ANSSAM::Initialize. Loading OpenVINO weight", _modelFilePath, __FILE__, __LINE__);
if (FileExist(binaryfile)) {
this->_logger.LogDebug("ANSSAM::Initialize binary weight", binaryfile, __FILE__, __LINE__);
}
else {
this->_logger.LogError("ANSSAM::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;
}
if (_modelConfig.modelConfThreshold <= 0)_modelConfig.modelConfThreshold = 0.4;
if (_modelConfig.modelMNSThreshold <= 0)_modelConfig.modelMNSThreshold = 0.4;
_isInitialized = Init(_modelFilePath, _modelConfig.modelConfThreshold, _modelConfig.modelMNSThreshold, true);
return _isInitialized;
}
catch (std::exception& e) {
this->_logger.LogFatal("ANSPOSE::LoadModel", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSSAM::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);
try {
bool result = ANSODBase::LoadModelFromFolder(licenseKey, modelConfig, modelName, className, modelFolder, labelMap);
if (!result) return false;
std::string _modelName = modelName;
if (_modelName.empty()) {
_modelName = "anssam";
}
std::string xmlFileName = _modelName + ".xml";
std::string binFileName = _modelName + ".bin";
std::string xmlfile = CreateFilePath(_modelFolder, xmlFileName);
std::string binaryfile = CreateFilePath(_modelFolder, binFileName);
if (std::filesystem::exists(xmlfile)) {
_modelFilePath = xmlfile;
this->_logger.LogDebug("ANSSAM::Initialize. Loading OpenVINO weight", _modelFilePath, __FILE__, __LINE__);
if (FileExist(binaryfile)) {
this->_logger.LogDebug("ANSSAM::Initialize binary weight", binaryfile, __FILE__, __LINE__);
}
else {
this->_logger.LogError("ANSSAM::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;
}
if (modelConfig.modelConfThreshold <= 0)modelConfig.modelConfThreshold = 0.4;
if (modelConfig.modelMNSThreshold <= 0)modelConfig.modelMNSThreshold = 0.4;
labelMap = "SAM";
_isInitialized = Init(_modelFilePath, modelConfig.modelConfThreshold, modelConfig.modelMNSThreshold, true);
return _isInitialized;
}
catch (std::exception& e) {
this->_logger.LogFatal("ANSPOSE::LoadModel", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSSAM::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap)
{
try {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_modelConfig = modelConfig;
bool result = ANSODBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap);
if (!result) return false;
std::string xmlfile = CreateFilePath(_modelFolder, "anssam.xml");
std::string binaryfile = CreateFilePath(_modelFolder, "anssam.bin");
if (std::filesystem::exists(xmlfile)) {
_modelFilePath = xmlfile;
this->_logger.LogDebug("ANSSAM::Initialize. Loading OpenVINO weight", _modelFilePath, __FILE__, __LINE__);
if (FileExist(binaryfile)) {
this->_logger.LogDebug("ANSSAM::Initialize binary weight", binaryfile, __FILE__, __LINE__);
}
else {
this->_logger.LogError("ANSSAM::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;
}
if (modelConfig.modelConfThreshold <= 0)modelConfig.modelConfThreshold = 0.4;
if (modelConfig.modelMNSThreshold <= 0)modelConfig.modelMNSThreshold = 0.4;
labelMap = "SAM";
_isInitialized = Init(_modelFilePath, modelConfig.modelConfThreshold, modelConfig.modelMNSThreshold, true);
return _isInitialized;
}
catch (std::exception& e) {
this->_logger.LogFatal("ANSPOSE::Initialize", e.what(), __FILE__, __LINE__);
return false;
}
}
std::vector<Object> ANSSAM::RunInference(const cv::Mat& input) {
return RunInference(input, "CustomCam");
}
std::vector<Object> ANSSAM::RunInference(const cv::Mat& input,const std::string& camera_id)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (!_licenseValid || !_isInitialized || input.empty() ||
input.cols < 10 || input.rows < 10) {
return {};
}
// Convert to BGR
cv::Mat processedImage = (input.channels() == 1)
? [&] { cv::Mat tmp; cv::cvtColor(input, tmp, cv::COLOR_GRAY2BGR); return tmp; }()
: input;
// Run inference
ov::Tensor input_tensor = Preprocess(processedImage);
if (input_tensor.get_size() == 0) return {};
m_request.set_input_tensor(input_tensor);
m_request.infer();
std::vector<cv::Mat> masks = Postprocess(processedImage);
if (masks.empty()) return {};
// Build output
std::vector<Object> output;
output.reserve(masks.size());
const cv::Rect imageBounds(0, 0, input.cols, input.rows);
for (auto& mask : masks) {
Object obj;
obj.extraInfo = MaskToPolygons(mask, obj.box, obj.polygon);
obj.box &= imageBounds;
if (obj.box.area() == 0) continue;
obj.confidence = 1.0f;
obj.classId = 0;
obj.className = "sam";
obj.cameraId = camera_id;
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("ANSSAM::RunInference", e.what(), __FILE__, __LINE__);
return {};
}
}
ANSSAM::~ANSSAM() {
Destroy();
}
bool ANSSAM::Destroy()
{
try {
if (FolderExist(_modelFolder)) {
DeleteFolder(_modelFolder);
}
return true;
}
catch (std::exception& e) {
this->_logger.LogFatal("ANSSAM::Destroy", e.what(), __FILE__, __LINE__);
return false;
}
}
//private:
bool ANSSAM::Init(const std::string& xml_path, float conf, float iou, bool useGpu)
{
m_conf = conf;
m_iou = iou;
if (!std::filesystem::exists(xml_path))
return false;
m_model = m_core.read_model(xml_path);
if (!ParseArgs())
return false;
if (!BuildProcessor())
return false;
m_compiled_model = m_core.compile_model(m_model, useGpu && IsGpuAvaliable(m_core) ? "GPU" : "CPU");
m_request = m_compiled_model.create_infer_request();
return true;
}
void ANSSAM::Infer(const std::string& image_path)
{
try
{
cv::Mat image = cv::imread(image_path);
cv::Mat rendered = Infer(image);
std::string savedir = std::filesystem::current_path().string() + "/results";
if (!std::filesystem::exists(savedir))
std::filesystem::create_directory(savedir);
std::string savepath = savedir + "/" + std::filesystem::path(image_path).filename().string();
cv::imwrite(savepath, rendered);
//slog::info << "result saved in :" << savepath << "\n";
}
catch (const std::exception& e)
{
//slog::info << "Failed to Infer! ec: " << e.what() << '\n';
}
}
cv::Mat ANSSAM::Infer(const cv::Mat& image)
{
cv::Mat processedImg = image.clone();
ov::Tensor input_tensor = Preprocess(processedImg);
assert(input_tensor.get_size() != 0);
m_request.set_input_tensor(input_tensor);
m_request.infer();
std::vector<cv::Mat> result = Postprocess(image);
return Render(image, result);
}
bool ANSSAM::ParseArgs()
{
try
{
model_input_shape = m_model->input().get_shape();
model_output0_shape = m_model->output(0).get_shape();
model_output1_shape = m_model->output(1).get_shape();
//slog::info << "xml input shape:" << model_input_shape << "\n";
//slog::info << "xml output shape 0:" << model_output0_shape << "\n";
//slog::info << "xml output shape 1:" << model_output1_shape << "\n";
// [1, 3, 640, 640]
input_channel = model_input_shape[1];
input_height = model_input_shape[2];
input_width = model_input_shape[3];
this->input_data.resize(input_channel * input_height * input_height);
//slog::info << "model input height:" << input_height << " input width:" << input_width << "\n";
// output0 = [1,37,8400]
// output1 = [1,32,160,160]
mh = model_output1_shape[2];
mw = model_output1_shape[3];
//slog::info << "model output mh:" << mh << " output mw:" << mw << "\n";
}
catch (const std::exception& e)
{
//slog::info << "Failed to Parse Args. " << e.what() << '\n';
return false;
}
return true;
}
void ANSSAM::ScaleBoxes(cv::Mat& box, const cv::Size& oriSize)
{
float oriWidth = static_cast<float>(oriSize.width);
float oriHeight = static_cast<float>(oriSize.height);
float* pxvec = box.ptr<float>(0);
for (int i = 0; i < box.rows; i++) {
pxvec = box.ptr<float>(i);
pxvec[0] -= this->dw;
pxvec[0] = std::clamp(pxvec[0] * this->ratio, 0.f, oriWidth);
pxvec[1] -= this->dh;
pxvec[1] = std::clamp(pxvec[1] * this->ratio, 0.f, oriHeight);
pxvec[2] -= this->dw;
pxvec[2] = std::clamp(pxvec[2] * this->ratio, 0.f, oriWidth);
pxvec[3] -= this->dh;
pxvec[3] = std::clamp(pxvec[3] * this->ratio, 0.f, oriHeight);
}
}
std::vector<cv::Mat> ANSSAM::NMS(cv::Mat& prediction, int max_det)
{
std::vector<cv::Mat> vreMat;
cv::Mat temData = cv::Mat();
prediction = prediction.t(); // [37, 8400] --> [rows:8400, cols:37]
float* pxvec = prediction.ptr<float>(0);
for (int i = 0; i < prediction.rows; i++) {
pxvec = prediction.ptr<float>(i);
if (pxvec[4] > m_conf) {
temData.push_back(prediction.rowRange(i, i + 1).clone());
}
}
if (temData.rows == 0) {
return vreMat;
}
cv::Mat box = temData.colRange(0, 4).clone(); //
cv::Mat cls = temData.colRange(4, 5).clone(); //
cv::Mat mask = temData.colRange(5, temData.cols).clone(); //
cv::Mat j = cv::Mat::zeros(cls.size(), CV_32F);
cv::Mat dst;
cv::hconcat(box, cls, dst); // concat
cv::hconcat(dst, j, dst);
cv::hconcat(dst, mask, dst); // dst = [box class j mask] concat
std::vector<float> scores;
std::vector<cv::Rect> boxes;
pxvec = dst.ptr<float>(0);
for (int i = 0; i < dst.rows; i++) {
pxvec = dst.ptr<float>(i);
boxes.push_back(cv::Rect(pxvec[0], pxvec[1], pxvec[2], pxvec[3]));
scores.push_back(pxvec[4]);
}
std::vector<int> indices;
cv::dnn::NMSBoxes(boxes, scores, m_conf, m_iou, indices);
cv::Mat reMat;
for (int i = 0; i < indices.size() && i < max_det; i++) {
int index = indices[i];
reMat.push_back(dst.rowRange(index, index + 1).clone());
}
box = reMat.colRange(0, 6).clone();
xywh2xyxy(box);
mask = reMat.colRange(6, reMat.cols).clone();
vreMat.push_back(box);
vreMat.push_back(mask);
return vreMat;
}
void ANSSAM::xywh2xyxy(cv::Mat& box)
{
float* pxvec = box.ptr<float>(0);
for (int i = 0; i < box.rows; i++) {
pxvec = box.ptr<float>(i);
float w = pxvec[2];
float h = pxvec[3];
float cx = pxvec[0];
float cy = pxvec[1];
pxvec[0] = cx - w / 2;
pxvec[1] = cy - h / 2;
pxvec[2] = cx + w / 2;
pxvec[3] = cy + h / 2;
}
}
cv::Mat ANSSAM::ConvertToBinary(cv::Mat src) {
cv::Mat gray, binary;
// Check if the image is already in grayscale
if (src.channels() == 3) {
// Convert from BGR to Grayscale
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
}
else if (src.channels() == 1) {
gray = src.clone(); // Use the grayscale image as is
}
else {
std::cerr << "Unsupported number of channels: " << src.channels() << std::endl;
return cv::Mat(); // Return an empty matrix on failure
}
// Convert grayscale to binary
cv::threshold(gray, binary, 127, 255, cv::THRESH_BINARY); // Adjust the threshold as needed
cv::Mat binaryMask;
cv::threshold(binary, binaryMask, 0.5, 255, cv::THRESH_BINARY);
binaryMask.convertTo(binaryMask, CV_8UC1);
return binaryMask;
}
std::string ANSSAM::MaskToPolygons(const cv::Mat& image, cv::Rect& boundingBox, std::vector<cv::Point2f>& polygon) {
try {
// image is boxMask: CV_32FC1 with 0.0 / 1.0 → directly convert
cv::Mat mask8u;
image.convertTo(mask8u, CV_8UC1, 255.0); // 1.0 → 255, 0.0 → 0
if (mask8u.empty() || mask8u.type() != CV_8UC1) {
return "";
}
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(mask8u, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if (contours.empty()) {
return "";
}
// Select the largest contour
size_t largestContourIdx = 0;
double maxArea = 0.0;
for (size_t i = 0; i < contours.size(); ++i) {
double area = cv::contourArea(contours[i]);
if (area > maxArea) {
maxArea = area;
largestContourIdx = i;
}
}
// Approximate polygon
std::vector<cv::Point> approxPolygon;
cv::approxPolyDP(contours[largestContourIdx], approxPolygon, 3, true);
// Convert to Point2f
polygon.clear();
for (const auto& pt : approxPolygon) {
polygon.push_back(cv::Point2f(pt.x, pt.y));
}
// Calculate bounding box
boundingBox = cv::boundingRect(approxPolygon);
// Convert polygon to string
std::stringstream xCoords, yCoords;
for (size_t i = 0; i < polygon.size(); ++i) {
if (i > 0) {
xCoords << "; ";
yCoords << "; ";
}
xCoords << polygon[i].x;
yCoords << polygon[i].y;
}
std::string formattedString = xCoords.str() + " | " + yCoords.str();
return formattedString;
}
catch (const std::exception& e) {
//slog::info << "Failed to convert mask to polygons: " << e.what() << '\n';
return "";
}
}
cv::Mat ANSSAM::Render(const cv::Mat& image, const std::vector<cv::Mat>& vremat)
{
cv::Mat rendered = image.clone();
for (const auto& mask : vremat) {
auto color = RandomColor();
for (int y = 0; y < mask.rows; y++) {
const float* mp = mask.ptr<float>(y);
uchar* p = rendered.ptr<uchar>(y);
for (int x = 0; x < mask.cols; x++) {
if (mp[x] == 1.0) { // ??
p[0] = cv::saturate_cast<uchar>(p[0] * 0.5 + color[0] * 0.5);
p[1] = cv::saturate_cast<uchar>(p[1] * 0.5 + color[1] * 0.5);
p[2] = cv::saturate_cast<uchar>(p[2] * 0.5 + color[2] * 0.5);
}
p += 3;
}
}
}
return rendered;
}
ov::Tensor ANSSAM::Preprocess(cv::Mat& image)
{
if (!ConvertSize(image)) {
//slog::info << "failed to Convert Size!\n";
return ov::Tensor();
}
if (!ConvertLayout(image)) {
//slog::info << "Failed to Convert Layout!\n";
return ov::Tensor();
}
return BuildTensor();
}
cv::Mat ANSSAM::BuildOutput0()
{
auto* ptr = m_request.get_output_tensor(0).data();
return cv::Mat(model_output0_shape[1], model_output0_shape[2], CV_32F, ptr);
}
cv::Mat ANSSAM::BuildOutput1()
{
auto* ptr = m_request.get_output_tensor(1).data();
return cv::Mat(model_output1_shape[1], model_output1_shape[2] * model_output1_shape[3], CV_32F, ptr);
}
std::vector<cv::Mat> ANSSAM::ProcessMaskNative(const cv::Mat& image, cv::Mat& protos, cv::Mat& masks_in, cv::Mat& bboxes, cv::Size shape)
{
std::vector<cv::Mat> result;
cv::Mat matmulRes = (masks_in * protos).t(); //
cv::Mat maskMat = matmulRes.reshape(bboxes.rows, { mh, mw });
std::vector<cv::Mat> maskChannels;
cv::split(maskMat, maskChannels);
int scale_dw = this->dw / input_width * mw;
int scale_dh = this->dh / input_height * mh;
cv::Rect roi(scale_dw, scale_dh, mw - 2 * scale_dw, mh - 2 * scale_dh);
float* pxvec = bboxes.ptr<float>(0);
for (int i = 0; i < bboxes.rows; i++) {
pxvec = bboxes.ptr<float>(i);
cv::Mat dest, mask;
cv::exp(-maskChannels[i], dest);
dest = 1.0 / (1.0 + dest);
dest = dest(roi);
cv::resize(dest, mask, image.size(), cv::INTER_LINEAR);
cv::Rect roi(pxvec[0], pxvec[1], pxvec[2] - pxvec[0], pxvec[3] - pxvec[1]);
cv::Mat temmask = mask(roi);
cv::Mat boxMask = cv::Mat(image.size(), mask.type(), cv::Scalar(0.0));
float rx = std::max(pxvec[0], 0.0f);
float ry = std::max(pxvec[1], 0.0f);
for (int y = ry, my = 0; my < temmask.rows; y++, my++) {
float* ptemmask = temmask.ptr<float>(my);
float* pboxmask = boxMask.ptr<float>(y);
for (int x = rx, mx = 0; mx < temmask.cols; x++, mx++) {
pboxmask[x] = ptemmask[mx] > 0.5 ? 1.0 : 0.0;
}
}
result.push_back(boxMask);
}
return result;
}
std::vector<cv::Mat> ANSSAM::Postprocess(const cv::Mat& oriImage)
{
cv::Mat prediction = BuildOutput0();
cv::Mat proto = BuildOutput1();
std::vector<cv::Mat> remat = NMS(prediction, 100);
if (remat.size() < 2) {
return std::vector<cv::Mat>();
}
cv::Mat box = remat[0];
cv::Mat mask = remat[1];
ScaleBoxes(box, oriImage.size());
return ProcessMaskNative(oriImage, proto, mask, box, oriImage.size());
}
bool ANSSAM::ConvertSize(cv::Mat& image)
{
float height = static_cast<float>(image.rows);
float width = static_cast<float>(image.cols);
float r = std::min(input_height / height, input_width / width);
int padw = static_cast<int>(std::round(width * r)); //
int padh = static_cast<int>(std::round(height * r));
if ((int)width != padw || (int)height != padh)
cv::resize(image, image, cv::Size(padw, padh));
float _dw = (input_width - padw) / 2.f;
float _dh = (input_height - padh) / 2.f;
int top = static_cast<int>(std::round(_dh - 0.1f));
int bottom = static_cast<int>(std::round(_dh + 0.1f));
int left = static_cast<int>(std::round(_dw - 0.1f));
int right = static_cast<int>(std::round(_dw + 0.1f));
cv::copyMakeBorder(image, image, top, bottom, left, right, cv::BORDER_CONSTANT,
cv::Scalar(114, 114, 114));
this->ratio = 1 / r;
this->dw = _dw;
this->dh = _dh;
return true;
}
bool ANSSAM::ConvertLayout(cv::Mat& image)
{
int row = image.rows;
int col = image.cols;
int channels = image.channels();
if (channels != 3)
return false;
cv::cvtColor(image, image, cv::COLOR_BGR2RGB);
for (int c = 0; c < channels; c++) {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
float pix = image.at<cv::Vec3b>(i, j)[c];
input_data[c * row * col + i * col + j] = pix / 255.0;
}
}
}
return true;
}
ov::Tensor ANSSAM::BuildTensor()
{
ov::Shape shape = { 1, static_cast<unsigned long>(input_channel), static_cast<unsigned long>(input_height), static_cast<unsigned long>(input_width) };
return ov::Tensor(ov::element::f32, shape, input_data.data());;
}
bool ANSSAM::BuildProcessor()
{
try
{
m_ppp = std::make_shared<ov::preprocess::PrePostProcessor>(m_model);
m_ppp->input().tensor()
.set_shape({ 1, input_channel, input_height, input_width })
.set_element_type(ov::element::f32)
.set_layout("NCHW")
.set_color_format(ov::preprocess::ColorFormat::RGB);
m_model = m_ppp->build();
}
catch (const std::exception& e)
{
std::cerr << "Failed to build the model processor!\n" << e.what() << '\n';
return false;
}
return true;
}
bool ANSSAM::IsGpuAvaliable(const ov::Core& core)
{
std::vector<std::string> avaliableDevice = core.get_available_devices();
auto iter = std::find(avaliableDevice.begin(), avaliableDevice.end(), "GPU");
return iter != avaliableDevice.end();
}
cv::Scalar ANSSAM::RandomColor()
{
int b = rand() % 256;
int g = rand() % 256;
int r = rand() % 256;
return cv::Scalar(b, g, r);
}
}
// std::vector<Object> ANSSAM::RunInference(const cv::Mat& input, const std::string& camera_id) {
// std::lock_guard<std::recursive_mutex> lock(_mutex);
// std::vector<Object> detectionObjects;
// try {
// if (!_licenseValid) {
// this->_logger.LogError("ANSSAM::RunInference", "Invalid License", __FILE__, __LINE__);
// return detectionObjects;
// }
// if (!_isInitialized) {
// this->_logger.LogError("ANSSAM::RunInference", "Model is not initialized", __FILE__, __LINE__);
// return detectionObjects;
// }
// if (input.empty()) return detectionObjects;
// if ((input.cols < 10) || (input.rows < 10)) return detectionObjects;
// // 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;
// }
// ov::Tensor input_tensor = Preprocess(processedImage);
// assert(input_tensor.get_size() != 0);
// m_request.set_input_tensor(input_tensor);
// m_request.infer();
// std::vector<cv::Mat> result = Postprocess(input);
// for (int i = 0; i < result.size(); i++) {
// Object detectedObject;
// cv::Rect rect;
// std::vector<cv::Point2f> polygon;
// std::string extraInfo;
// extraInfo = MaskToPolygons(result.at(i), rect, polygon);
// detectedObject.box = rect;
// detectedObject.box.x = std::max(detectedObject.box.x, 0);
// detectedObject.box.y = std::max(detectedObject.box.y, 0);
// detectedObject.box.width = std::min(detectedObject.box.width, input.cols - detectedObject.box.x);
// detectedObject.box.height = std::min(detectedObject.box.height, input.rows - detectedObject.box.y);
// detectedObject.polygon = polygon;
// detectedObject.extraInfo = extraInfo;
// detectedObject.confidence = 1.0;
// detectedObject.classId = 0;
// detectedObject.className = "sam";
// detectedObject.cameraId = camera_id;
// detectionObjects.push_back(detectedObject);
// }
////EnqueueDetection(detectionObjects,camera_id);
// return detectionObjects;
// }
// catch (std::exception& e) {
// detectionObjects.clear();
// this->_logger.LogFatal("ANSSAM::RunInference", e.what(), __FILE__, __LINE__);
// return detectionObjects;
// }
// }