完成框架目录和模块重构;新增核心、单例、工具、加密及框架 SDK;统一任务、相机和 RPC 接口,并增加离线检测、相机标定、备份恢复、版本管理、崩溃守护和心跳监控功能。
359 lines
12 KiB
C++
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
|