Files
eUi/include/yhGlobal.h
T
RCiRoot 97462c8aab On main: V20260416-2.5.1
增加halconGuard类,用于防止halcon算法的输入输出和程序不一致而引起的报错,并且会检查算法文件是否存在,如不存在则会弹窗提示。
增加handleAiGpuThreadGuard类,用于防止因重复调用同一个模型而引起的报错,并且支持不停机更新模型,支持初始化时检测模型文件是否存在。
增加内存占用显示控件。
用户管理增加root权限,默认密码为dseuiroot,模型热更新时需要此权限。
支持缓存界面上的检测数据。
相机模块新增在回调后的指定时间没有取图时则清空容器的功能。
增加等待结果汇总功能,在启用时同一个SN的图片会等待总结果后再进行存图。
存图线程修改为多线程编码,单线程储存,提高IO效率。并且增加根据内存占用的百分比更新存图逻辑的功能,默认占用超过70%不储存OK原图,超过80%不储存原图,超过90%时不储存所有图片。
2026-04-26 12:25:13 +08:00

309 lines
16 KiB
C++

#pragma once
#include <missionBase.hpp>
#include <detCallbackChain.hpp>
#include <share.h>
#include <QObject>
#include <opencvPaintAlgo.hpp>
#include <halconGuard.h>
#include <paramSpecifications.h>
#pragma region 基础函数
#define CATCH_EXCEPTIONS \
catch (HDevEngineCpp::HDevEngineException& ex) { \
std::cout << "HDevEngineException: " << ex.Message() << std::endl; \
qCritical() << "HDevEngineException: " << ex.Message(); \
} \
catch (HalconCpp::HException& ex) { \
std::cout << "Halcon Exception Caught!" << std::endl; \
std::cout << "Error Code: " << ex.ErrorCode() << std::endl; \
std::cout << "Error Message: " << ex.ErrorMessage() << std::endl; \
qCritical() << "Halcon Exception Caught!"; \
qCritical() << "Error Code: " << ex.ErrorCode(); \
qCritical() << "Error Message: " << ex.ErrorMessage(); \
} \
catch (const std::exception& e) { \
std::cout << "Caught exception: " << e.what() << std::endl; \
qCritical() << "Caught exception: " << e.what(); \
}\
catch (...) {\
std::cout << "Caught exception: unexcepted"; \
qCritical() << "Caught exception: unexcepted"; \
}
struct yh_581_address {
int triggerAddr = -1;
int snAddr = -1;
QByteArray completeAddr = "-1";
QByteArray resultAddr = "-1";
int valueOffsetAddr = -1;
int index = -1;
};
static yh_581_address generateYh581Address(int startAddr, int offset) {//INPUT:开始地址/电芯地址偏移(0~3)
return yh_581_address{
startAddr + offset * 2,
startAddr + 10 + offset * 22 ,
QByteArray::number(startAddr + 98 + offset * 2),
QByteArray::number(startAddr + 106 + offset * 2),
startAddr + 114 + offset * 20,
offset
};
}
static std::map<int, yh_581_address> generateYh581AddressMap(int startAddr, int cnt) {//INPUT:开始地址/0~3) 数量
std::map<int, yh_581_address> result;
for (auto i = 0; i < cnt; i++) {
result[i] = generateYh581Address(startAddr, i);
}
return result;
}
class detParams {
public:
};
#pragma endregion
//算法回调函数需要包含完整的算法流程以及发送信号,发送ui图表,捕获异常,处理异常等操作
//并且注意 异常可能会导致运行不到发送信号的函数,请在处理异常时发送异常结果
void generalExceptionResume(std::shared_ptr<detData> data, yh_581_address address, QString why = "") {
qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode) << why;
cv::Mat Paint;
data->getOriImg(0).copyTo(Paint);
if (Paint.channels() == 1)
cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR);
TextRendererZH textPainter(Paint.cols, Paint.rows, 300);
textPainter.putText(Paint, why.toStdString(), cv::Point(500, 50), cv::Scalar(0, 255, 0));
cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5);
data->insertResultImg(Paint);
if (data->service->_paramSyncManager->get("通用设置", "强制OK", false).toBool())
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈
else
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//结果反馈
}
static bool generalAlgoTest(std::shared_ptr <detData> data, detParams* _detParams, yh_581_address address) {
try {
qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start";
std::vector < std::string> defects = {"测试"};
///////////////////取图//处理//////////////////
if (data->getOriImgSize() < 1)
{
qCritical() << "图片数量不满足要求:" << data->getOriImgSize();
return false;
}
if (data->getOriImg(0).rows == 100) {
cv::Mat Paint;
data->getOriImg(0).copyTo(Paint);
cv::putText(Paint, "time out", cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 2);
return false;
}
cv::Mat Paint;
QMutex paintMutex;
clock_t start, finish;
start = clock();
cv::Mat src1 = data->getOriImg(0);
if (src1.channels() != 3)
cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR);
else
src1.copyTo(Paint);
TextRendererZH textPainter(Paint.cols, Paint.rows, 300);
textPainter.putText(Paint, "OK", cv::Point(10,10), cv::Scalar(0, 255, 0));
data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.123");//发送数据1
data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2)+ "_0.456");//发送数据2
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果
data->service->_missionResultHandle->toBarChart(data->SNcode, defects);//发送图标操作
data->insertResultImg(Paint);
return true;
}
CATCH_EXCEPTIONS
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送异常结果
return false;
}
template <typename paramTemplte>
//此类适用于单相机多触发地址需要联合判断的情况的情况 比如顶盖焊,包膜,入壳机台
//例触发地址有4个,输入信号为 1 0 0 1 则触发1和4的地址拍照检测,2和3拍照取图并废弃
class _581_Union_triggerTemplate {
public:
paramTemplte* _detParams;
detCallbackChain<paramTemplte, yh_581_address>* generalDet;
std::string cameraName;
QString viewerName;
std::map<int, yh_581_address>address;
int oneTriggerCaptrueTimes = 1;
/// <summary>
/// 初始化
/// </summary>
/// <param name="cameraNameIn">相机名</param>
/// <param name="viewerNameIN">窗口名</param>
/// <param name="startAddr">开始地址</param>
/// <param name="triggerCount">触发信号数</param>
/// <param name="oneTriggerCaptrueTimes">单次触发调用几次相机模块</param>
/// <param name="detParamsIn">参数输入</param>
/// <param name="_serviceManagerIn">默认</param>
/// <param name="bridgeIn">默认</param>
/// <param name="_processAlgoCallback">算法函数</param>
/// <param name="resultHandlerIn"></param>
void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount,int oneTriggerCaptrueTimesIN,
paramTemplte* detParamsIn, ServiceManager* _serviceManagerIn, bSignalHub* bridgeIn,
typename detCallbackChain<paramTemplte, yh_581_address>::processAlgoCallback _processAlgoCallback,
QString saveObjectNameIN = "") {
viewerName = viewerNameIN;
cameraName = cameraNameIn;
_serviceManager = _serviceManagerIn;
_detParams = detParamsIn;
bridge = bridgeIn;
oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN;
saveObjectName = saveObjectNameIN;
generalDet = new detCallbackChain<paramTemplte, yh_581_address>(_serviceManager, _detParams, bridge);
generalDet->registerProcessAlgoCallback(_processAlgoCallback);
address = generateYh581AddressMap(startAddr, triggerCount);
//联合触发器条件
std::vector<std::pair<int, int>> conditions;
for (int i = 0; i < triggerCount; i++) {
conditions.push_back(std::make_pair(address[i].triggerAddr, 1));
//注册清除完成信号触发器 任意触发地址归零时触发一次
_serviceManager->_triggerManager->registerCallback(address[i].triggerAddr, 0, [this, i](int triggerPos, int triggerValue, QByteArray& byteArray)
{_serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_0"); }, "D" + address[0].completeAddr.toStdString() + "清零");
}
//注册联合触发器 任意触发地址置1时触发
_serviceManager->_triggerManager->registerUnionCallback(conditions, triggerManager::conditionMode::or ,[this](std::vector<std::pair<int, int>> vals, QByteArray& byteArray){
int cnt = 0;
for (auto& val : vals) {
if (val.second == 1)
evaluate(cnt, byteArray);
else
captrueAndDiscard(cnt, byteArray);
cnt++;
}
}, "");
for (int i = 0; i < address.size(); i++) {
_serviceManager->_triggerManager->registerPlcValueViewer(viewerNameIN + "_" + QString::number(i),
{ {QString::number(address[i].triggerAddr) + "触发",address[i].triggerAddr,finsShort },
{address[i].completeAddr + "反馈",address[i].completeAddr.toInt(),finsShort},
{address[i].resultAddr + "结果",address[i].resultAddr.toInt(),finsShort},
{QString::number(address[i].valueOffsetAddr) + "数值1",address[i].valueOffsetAddr,finsFloat},
{QString::number(address[i].valueOffsetAddr + 2) + "数值2",address[i].valueOffsetAddr + 2,finsFloat},
{QString::number(address[i].valueOffsetAddr + 4) + "数值3",address[i].valueOffsetAddr + 4,finsFloat} });
}
}
//获取图片并进行检测
void evaluate(int batteryOffset, QByteArray& byteArray) {
std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, -1);
auto camera = _serviceManager->_cameraManager->getCamera(cameraName);
camera->clearCache();
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(
QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
data->saveObjectName = saveObjectName;
camera->captureImage(data);//拍照
generalDet->asyncProcess(data, address[batteryOffset]);//处理算法
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
_serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_1");//完成信号 固定只发在第0位
qDebug() << data->uuid << "bind->" << QString::fromStdString(cameraName) << "|" << QString::fromStdString(sn) << "|" << address[batteryOffset].triggerAddr;
}
//获取图片然后废弃 一般为进站NG
void captrueAndDiscard(int batteryOffset, QByteArray& byteArray) {
std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, -1);
auto camera = _serviceManager->_cameraManager->getCamera(cameraName);
camera->clearCache();
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
camera->captureImage(data);//拍照
qDebug() <<"sn" << QString::fromStdString(sn) << "uuid" << data->uuid << "将取图并丢弃";
_serviceManager->_detDataManager->deleteDetDataLater(data->uuid);
_serviceManager->_triggerManager->writeShort("D" + address[0].completeAddr + "_1");//完成信号 固定只发在第0位
_serviceManager->_triggerManager->writeShort("D" + address[batteryOffset].resultAddr + "_2");//发个2防止报警
}
private:
QString saveObjectName = "";
bSignalHub* bridge;
ServiceManager* _serviceManager = nullptr;
};
template <typename paramTemplte2>
//此类适用于单相机多触发地址单次判断的情况,比如密封钉,三协机台
//例触发地址有4个,输入信号为 1 0 0 1 则按顺序触发1和4的地址拍照检测,2和3不做处理
class _581_Single_triggerTemplate {
public:
paramTemplte2* _detParams;
detCallbackChain<paramTemplte2, yh_581_address>* generalDet;
std::string cameraName;
QString viewerName;
std::map<int, yh_581_address>address;
int oneTriggerCaptrueTimes = 1;
/// <summary>
/// 初始化
/// </summary>
/// <param name="cameraNameIn">相机名</param>
/// <param name="viewerNameIN">窗口名</param>
/// <param name="startAddr">开始地址</param>
/// <param name="triggerCount">触发信号数</param>
/// <param name="oneTriggerCaptrueTimes">单次触发调用几次相机模块</param>
/// <param name="detParamsIn">参数输入</param>
/// <param name="_serviceManagerIn">默认</param>
/// <param name="bridgeIn">默认</param>
/// <param name="_processAlgoCallback">算法函数</param>
/// <param name="resultHandlerIn"></param>
void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount, int oneTriggerCaptrueTimesIN,
paramTemplte2* detParamsIn, ServiceManager* _serviceManagerIn, bSignalHub* bridgeIn,
typename detCallbackChain<paramTemplte2, yh_581_address>::processAlgoCallback _processAlgoCallback,
QString saveObjectNameIN = "") {
viewerName = viewerNameIN;
cameraName = cameraNameIn;
_serviceManager = _serviceManagerIn;
_detParams = detParamsIn;
bridge = bridgeIn;
oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN;
saveObjectName = saveObjectNameIN;
generalDet = new detCallbackChain<paramTemplte2, yh_581_address>(_serviceManager, _detParams, bridge);
generalDet->registerProcessAlgoCallback(_processAlgoCallback);
address = generateYh581AddressMap(startAddr, triggerCount);
//单次触发器条件
for (int i = 0; i < triggerCount; i++) {
//注册单触发器 触发地址置1时触发
_serviceManager->_triggerManager->registerCallback(address[i].triggerAddr, 1, [this, i](int triggerPos, int triggerValue, QByteArray& byteArray) {
evaluate(i, byteArray);}, "");
//注册清除完成信号触发器 任意触发地址归零时触发一次
_serviceManager->_triggerManager->registerCallback(address[i].triggerAddr, 0, [this, i](int triggerPos, int triggerValue, QByteArray& byteArray) {
_serviceManager->_triggerManager->writeShort("D" + address[i].completeAddr + "_0"); }, "D" + address[0].completeAddr.toStdString() + "清零");
}
for (int i = 0; i < address.size(); i++) {
_serviceManager->_triggerManager->registerPlcValueViewer(viewerNameIN + "_" + QString::number(i),
{ {QString::number(address[i].triggerAddr) + "触发",address[i].triggerAddr,finsShort },
{address[i].completeAddr + "反馈",address[i].completeAddr.toInt(),finsShort},
{address[i].resultAddr + "结果",address[i].resultAddr.toInt(),finsShort},
{QString::number(address[i].valueOffsetAddr) + "数值1",address[i].valueOffsetAddr,finsFloat},
{QString::number(address[i].valueOffsetAddr + 2) + "数值2",address[i].valueOffsetAddr + 2,finsFloat},
{QString::number(address[i].valueOffsetAddr + 4) + "数值3",address[i].valueOffsetAddr + 4,finsFloat} });
}
}
//获取图片并进行检测
void evaluate(int batteryOffset, QByteArray& byteArray) {
std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, -1);
auto camera = _serviceManager->_cameraManager->getCamera(cameraName);
camera->clearCache();
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(
QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
data->saveObjectName = saveObjectName;
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
camera->captureImage(data);//拍照
generalDet->asyncProcess(data, address[batteryOffset]);//处理算法
_serviceManager->_triggerManager->writeShort("D" + address[batteryOffset].completeAddr + "_1");//完成信号 根据偏移发送
qDebug() << data->uuid << "bind->" << QString::fromStdString(cameraName) << "|" << QString::fromStdString(sn) << "|" << address[batteryOffset].triggerAddr;
}
private:
QString saveObjectName = "";
bSignalHub* bridge;
ServiceManager* _serviceManager = nullptr;
};