Files
eUi/include/eui_tools/handleAiModelGuard.h
RCiRoot e3f7733316 V20260829-2.6.1
完成框架目录和模块重构;新增核心、单例、工具、加密及框架 SDK;统一任务、相机和 RPC 接口,并增加离线检测、相机标定、备份恢复、版本管理、崩溃守护和心跳监控功能。
2026-09-20 16:01:09 +08:00

359 lines
12 KiB
C++

#pragma once
#if defined(EUI_HANDLE_AI_2256)
#include <handleA2256I.h>
#else
#include <handleAI.h>
#endif
#if defined(HD_NO_NAMESPACE)
#define EUI_HANDLE_AI_MODEL_NAMESPACE
#else
#define EUI_HANDLE_AI_MODEL_NAMESPACE handdleAI::
#endif
#include <opencv.hpp>
#include <QDebug>
#include <QElapsedTimer>
#include <QMutex>
#include <QMutexLocker>
#include <QString>
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
template <typename handleAiModelPtr>
class handleAiModelInfo {
public:
using TimeCostCallback = std::function<void(const QString&, const QString&, const QString&, const QString&)>;
explicit handleAiModelInfo(TimeCostCallback timeCostCallbackIn = {})
: timeCostCallback(std::move(timeCostCallbackIn)) {}
~handleAiModelInfo() = default;
struct modelSlot {
handleAiModelPtr* modelPtr = nullptr;
int gpuId = -1;
QMutex mutex;
};
struct getModelPtrResult {
handleAiModelPtr* modelPtr = nullptr;
int gpuId = -1;
std::shared_ptr<modelSlot> slot;
};
int getModelCount() {
QMutexLocker locker(&vectorMutex);
return static_cast<int>(modelSlots.size());
}
//获取最新的SEG模型
getModelPtrResult getModelPtr(const int& id) {
auto slot = getModelSlot(id);
if (!slot) {
return{};
}
QMutexLocker locker(&slot->mutex);
return{ slot->modelPtr, slot->gpuId, slot };
}
std::shared_ptr<modelSlot> getModelSlot(const int& id) {
QMutexLocker locker(&vectorMutex);
if (id < 0 || id >= static_cast<int>(modelSlots.size())) {
qCritical() << QString::fromStdString(path) << "模型ID越界:" << id;
return {};
}
return modelSlots[id];
}
int addModelPtr(handleAiModelPtr* ptr,const int& gpuId,QString modelDiscribeIn) {
QMutexLocker locker(&vectorMutex);
modelDiscribe = modelDiscribeIn;
auto slot = std::make_shared<modelSlot>();
slot->modelPtr = ptr;
slot->gpuId = gpuId;
modelSlots.push_back(std::move(slot));
return static_cast<int>(modelSlots.size()) - 1; // 返回新添加模型的ID
}
void updateModelPtr(int id, handleAiModelPtr* newPtr) {
replaceModelPtr(id, newPtr);
}
handleAiModelPtr* replaceModelPtr(int id, handleAiModelPtr* newPtr) {
auto slot = getModelSlot(id);
if (!slot) {
return nullptr;
}
QMutexLocker locker(&slot->mutex);
handleAiModelPtr* oldPtr = slot->modelPtr;
slot->modelPtr = newPtr;
return oldPtr;
}
QString getModelDiscribe() const {
return modelDiscribe;
}
void submitTime(double time) {
TimeCostCallback callback;
QString description;
QString avgTimeText;
QString maxTimeText;
QString minTimeText;
{
QMutexLocker locker(&timeMutex);
totalTime += time;
callCount++;
maxCostTime = std::max(maxCostTime, time);
minCostTime = std::min(minCostTime, time);
//每十次发送一次平均耗时到界面 每千次输出一次日志并重置数据
if (callCount % 10 == 0) {
const double avgTime = callCount > 0 ? totalTime / callCount : 0.0;
callback = timeCostCallback;
description = modelDiscribe;
avgTimeText = QString::number(avgTime, 'f', 2) + "ms";
maxTimeText = QString::number(maxCostTime, 'f', 2) + "ms";
minTimeText = QString::number(minCostTime, 'f', 2) + "ms";
if (callCount == 1000) {
qInfo() << QString::fromStdString(path) + "近千次平均耗时" << avgTime << "ms,最高" << maxCostTime << "ms,最低" << minCostTime << "ms";
callCount = 0;
totalTime = 0;
maxCostTime = 0;
minCostTime = 99999.0;
}
}
}
if (callback) {
callback(description, avgTimeText, maxTimeText, minTimeText);
}
}
double avgTime() {
QMutexLocker locker(&timeMutex);
return callCount > 0 ? totalTime / callCount : 0.0;
}// 平均耗时(毫秒)
double maxTime() {
QMutexLocker locker(&timeMutex);
return maxCostTime;
}// 最大耗时(毫秒)
double minTime() {
QMutexLocker locker(&timeMutex);
return minCostTime;
}// 最小耗时(毫秒)
std::string path;
int batchSize = 1;
private:
QString modelDiscribe;//模型描述
TimeCostCallback timeCostCallback;
QMutex vectorMutex; // 保护modelSlots的互斥锁
int index = 0;
std::vector<std::shared_ptr<modelSlot>> modelSlots;
QMutex timeMutex;
double totalTime = 0.0, maxCostTime = 0.0, minCostTime = 99999.0;
int callCount = 0;// 提交耗时的次数
};
class segModelWithGuard {
public:
using ModelInfo = handleAiModelInfo<EUI_HANDLE_AI_MODEL_NAMESPACE pSegmentation>;
using ModelSlot = typename ModelInfo::modelSlot;
segModelWithGuard() = default;
segModelWithGuard(int idIn, std::shared_ptr<ModelInfo> segPtrIn)
: segInfoPtr(std::move(segPtrIn)) {
if (segInfoPtr) {
modelSlot = segInfoPtr->getModelSlot(idIn);
}
}
~segModelWithGuard() = default;
bool empty() const {
return !segInfoPtr || !modelSlot;
}
explicit operator bool() const {
return !empty();
}
cv::Mat Evaluate(const cv::Mat& input) const {
if (empty()) {
qCritical() << QString::fromStdString(segInfoPtr ? segInfoPtr->path : std::string()) << "模型未初始化";
return cv::Mat();
}
QMutexLocker locker(&modelSlot->mutex);
auto segPtr = modelSlot->modelPtr;
if (!segPtr) {
qCritical() << QString::fromStdString(segInfoPtr->path) << "模型指针为空";
return cv::Mat();
}
QElapsedTimer timer;
timer.start();
cv::Mat result = segPtr->Evaluate(input);
segInfoPtr->submitTime(timer.elapsed());
return result;
}
std::vector<cv::Mat> bunchEvaluate(const std::vector<cv::Mat>& input) const {
std::vector<cv::Mat> result;
if (empty()) {
qCritical() << QString::fromStdString(segInfoPtr ? segInfoPtr->path : std::string()) << "模型未初始化";
return result;
}
result.reserve(input.size());
QMutexLocker locker(&modelSlot->mutex);
auto segPtr = modelSlot->modelPtr;
if (!segPtr) {
qCritical() << QString::fromStdString(segInfoPtr->path) << "模型指针为空";
return result;
}
QElapsedTimer timer;
timer.start();
for (const auto& img : input) {
result.push_back(segPtr->Evaluate(img));
}
segInfoPtr->submitTime(timer.elapsed());
return result;
}
private:
std::shared_ptr<ModelInfo> segInfoPtr;
std::shared_ptr<ModelSlot> modelSlot;
};
class clsModelWithGuard {
public:
using ModelInfo = handleAiModelInfo<EUI_HANDLE_AI_MODEL_NAMESPACE pClassification>;
using ModelSlot = typename ModelInfo::modelSlot;
clsModelWithGuard() = default;
clsModelWithGuard(int idIn, std::shared_ptr<ModelInfo> ptrIn)
: clsInfoPtr(std::move(ptrIn)) {
if (clsInfoPtr) {
modelSlot = clsInfoPtr->getModelSlot(idIn);
}
}
~clsModelWithGuard() = default;
struct clsResult {
int classes = -1;
double prob = 0.0;
};
bool empty() const {
return !clsInfoPtr || !modelSlot;
}
explicit operator bool() const {
return !empty();
}
clsResult Evaluate(const cv::Mat& input) const {
if (empty()) {
qCritical() << QString::fromStdString(clsInfoPtr ? clsInfoPtr->path : std::string()) << "模型未初始化";
return { -1,0.0 };
}
QMutexLocker locker(&modelSlot->mutex);
auto clsPtr = modelSlot->modelPtr;
if (!clsPtr) {
qCritical() << QString::fromStdString(clsInfoPtr->path) << "模型指针为空";
return { -1,0.0 };
}
QElapsedTimer timer;
timer.start();
clsResult result{ clsPtr->Evaluate(input),clsPtr->getProbability() };
clsInfoPtr->submitTime(timer.elapsed());
return result;
}
std::vector<clsResult> bunchEvaluate(const std::vector<cv::Mat>& input) const {
std::vector<clsResult> result;
if (empty()) {
qCritical() << QString::fromStdString(clsInfoPtr ? clsInfoPtr->path : std::string()) << "模型未初始化";
return result;
}
result.reserve(input.size());
QMutexLocker locker(&modelSlot->mutex);
auto clsPtr = modelSlot->modelPtr;
if (!clsPtr) {
qCritical() << QString::fromStdString(clsInfoPtr->path) << "模型指针为空";
return result;
}
QElapsedTimer timer;
timer.start();
for (const auto& img : input) {
result.push_back({ clsPtr->Evaluate(img),clsPtr->getProbability() });
}
clsInfoPtr->submitTime(timer.elapsed());
return result;
}
private:
std::shared_ptr<ModelInfo> clsInfoPtr;
std::shared_ptr<ModelSlot> modelSlot;
};
class detModelWithGuard {
public:
using ModelInfo = handleAiModelInfo<EUI_HANDLE_AI_MODEL_NAMESPACE pDetection>;
using ModelSlot = typename ModelInfo::modelSlot;
detModelWithGuard() = default;
detModelWithGuard(int idIn, std::shared_ptr<ModelInfo> ptrIn)
: detInfoPtr(std::move(ptrIn)) {
if (detInfoPtr) {
modelSlot = detInfoPtr->getModelSlot(idIn);
}
}
~detModelWithGuard() = default;
bool empty() const {
return !detInfoPtr || !modelSlot;
}
explicit operator bool() const {
return !empty();
}
// 单张推理
std::vector<EUI_HANDLE_AI_MODEL_NAMESPACE Bbox> Evaluate(const cv::Mat& input) const {
if (empty()) {
qCritical() << QString::fromStdString(detInfoPtr ? detInfoPtr->path : std::string()) << "模型未初始化";
return std::vector<EUI_HANDLE_AI_MODEL_NAMESPACE Bbox>();
}
QMutexLocker locker(&modelSlot->mutex);
auto detPtr = modelSlot->modelPtr;
if (!detPtr) {
qCritical() << QString::fromStdString(detInfoPtr->path) << "模型指针为空";
return std::vector<EUI_HANDLE_AI_MODEL_NAMESPACE Bbox>();
}
QElapsedTimer timer;
timer.start();
auto result = detPtr->Evaluate(input);
detInfoPtr->submitTime(timer.elapsed());
return result;
}
// 批量推理
std::vector<std::vector<EUI_HANDLE_AI_MODEL_NAMESPACE Bbox>>bunchEvaluate(const std::vector<cv::Mat>& input) const {
std::vector<std::vector<EUI_HANDLE_AI_MODEL_NAMESPACE Bbox>> result;
if (empty()) {
qCritical() << QString::fromStdString(detInfoPtr ? detInfoPtr->path : std::string()) << "模型未初始化";
return result;
}
QMutexLocker locker(&modelSlot->mutex);
result.reserve(input.size());
auto detPtr = modelSlot->modelPtr;
if (!detPtr) {
qCritical() << QString::fromStdString(detInfoPtr->path) << "模型指针为空";
return result;
}
QElapsedTimer timer;
timer.start();
for (const auto& img : input) {
result.push_back(detPtr->Evaluate(img));
}
detInfoPtr->submitTime(timer.elapsed());
return result;
}
private:
std::shared_ptr<ModelInfo> detInfoPtr;
std::shared_ptr<ModelSlot> modelSlot;
};
#undef EUI_HANDLE_AI_MODEL_NAMESPACE