V20251106-2.1.7

修复oneTriggerCaptrueTimes不生效的问题。
修复logwidget可能导致的死锁问题。
优化日志显示。
优化mission错误处理。
修改重试功能。
优化histogramWidget显示。
This commit is contained in:
2025-11-09 07:24:25 +08:00
parent 90b24b869b
commit ba849b24aa
14 changed files with 213 additions and 180 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
#include <vector>
#include <functional>
#pragma execution_character_set("utf-8")
const std::string softwareVersion = "20251104-2.1.6";
const std::string softwareVersion = "20251106-2.1.7";
const std::string euiJsonVersion = "1.0.6";
#define globalDatabasePth "./sqlDatabase/eui_db.db" //全局数据库路径
#define saveImgEnable 1
+57
View File
@@ -1,6 +1,7 @@
#include <HalconCpp.h>
#include <opencv.hpp>
#include <ios>
#include <algorithm>
#include <handleAI.h>
#include <QString>
#include <QByteArray>
@@ -753,6 +754,62 @@ static cv::Mat tiledImages(std::vector<cv::Mat>& imgs)
return showMat;
};
/**
* 快速去噪函数
*
* 说明:
* - 优先使用均值滤波(box filter)实现快速平滑;
* - 对明显的椒盐噪声可开启中值滤波(按通道处理,适用于8U/16U);
* - 指定较大核或需要可控平滑强度时,使用高斯滤波作为兜底。
*
* 参数:
* - inputMat 输入图像(支持单通道/多通道);
* - outputMat 输出图像;
* - kernelSize 卷积核大小,必须为奇数且>=3(传偶数会自动+1);
* - sigma 高斯滤波标准差,<=0 表示走OpenCV自动推导;
* - useMedian 是否启用中值滤波(更抗椒盐噪声,速度较均值略慢)。
*/
static void denoiseImage(const cv::Mat& inputMat, cv::Mat& outputMat, int kernelSize = 3, double sigma = 0.0, bool useMedian = false)
{
if (inputMat.empty()) {
outputMat.release();
return;
}
int k = kernelSize;
if (k < 3) k = 3; // 最小有效核大小
if ((k & 1) == 0) {
++k; // 转换为奇数核
}
// 快速路径(椒盐噪声):启用中值滤波;多通道按通道分别处理
if (useMedian && (inputMat.depth() == CV_8U || inputMat.depth() == CV_16U)) {
if (inputMat.channels() == 1) {
cv::medianBlur(inputMat, outputMat, k);
return;
} else {
std::vector<cv::Mat> ch;
cv::split(inputMat, ch);
for (auto& c : ch) {
cv::medianBlur(c, c, k);
}
cv::merge(ch, outputMat);
return;
}
}
// 默认快速路径:小核且未指定sigma时使用均值滤波(分离实现,速度快)
if (k <= 5 && sigma <= 0.0) {
cv::blur(inputMat, outputMat, cv::Size(k, k), cv::Point(-1, -1), cv::BORDER_DEFAULT);
return;
}
// 兜底:使用可分离高斯滤波,适合较大核或需要指定平滑强度的场景
const double sigmaChecked = getMax(0.0, sigma);
cv::GaussianBlur(inputMat, outputMat, cv::Size(k, k), sigmaChecked, sigmaChecked, cv::BORDER_DEFAULT);
}
// 字符编码转换:GBK 编码的 std::string 转为 UTF-8 编码的 std::string(基于 Qt 5.14.x)
// 入参:gbkStr - GBK/GB2312/GB18030 字节序列(std::string 仅作为原始字节容器)
// 返回:UTF-8 编码的字节序列(std::string)
+80
View File
@@ -7,6 +7,8 @@
#include <devguid.h>
#include <shellapi.h>
#include <ShlObj.h>
#include <string>
#include <vector>
#include <QPixmap>
#include <QFileIconProvider>
#include <QFileInfo>
@@ -258,4 +260,82 @@ static QIcon getFileIcon(const QString& filePath, const QSize& size) {
QPixmap pixmap = icon.pixmap(size);
return QIcon(pixmap);
}
static bool restartProgram(bool asAdmin = false, bool exitCurrent = true, int delayMs = 0) {
wchar_t exePath[MAX_PATH];
if (GetModuleFileNameW(nullptr, exePath, MAX_PATH) == 0) {
return false;
}
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
std::wstring params;
if (argv && argc > 1) {
for (int i = 1; i < argc; ++i) {
const wchar_t* arg = argv[i];
bool needQuote = wcspbrk(arg, L" \t\"'") != nullptr;
if (i > 1) params.push_back(L' ');
if (needQuote) {
params.push_back(L'"');
for (const wchar_t* p = arg; *p; ++p) {
if (*p == L'"') params.push_back(L'\\'), params.push_back(L'"');
else params.push_back(*p);
}
params.push_back(L'"');
} else {
params.append(arg);
}
}
}
if (argv) LocalFree(argv);
if (delayMs <= 0) {
SHELLEXECUTEINFOW sei{};
sei.cbSize = sizeof(sei);
sei.lpVerb = asAdmin ? L"runas" : L"open";
sei.lpFile = exePath;
sei.lpParameters = params.empty() ? nullptr : params.c_str();
sei.nShow = SW_SHOWNORMAL;
if (!ShellExecuteExW(&sei)) return false;
if (exitCurrent) ExitProcess(0);
return true;
} else {
std::wstring exeEsc;
for (const wchar_t* p = exePath; *p; ++p) {
if (*p == L'\'') exeEsc.push_back(L'\''); // duplicate single quote for PS literal
exeEsc.push_back(*p);
}
std::wstring argsEsc;
if (!params.empty()) {
for (const wchar_t* p = params.c_str(); *p; ++p) {
if (*p == L'\'') argsEsc.push_back(L'\'');
argsEsc.push_back(*p);
}
}
std::wstring psParam = L"-NoProfile -WindowStyle Hidden -Command \"Wait-Process -Id ";
psParam += std::to_wstring(GetCurrentProcessId());
psParam += L"; Start-Sleep -Milliseconds ";
psParam += std::to_wstring(delayMs);
psParam += L"; Start-Process -FilePath '";
psParam += exeEsc;
psParam += L"'";
if (!argsEsc.empty()) {
psParam += L" -ArgumentList '";
psParam += argsEsc;
psParam += L"'";
}
psParam += L"\"";
SHELLEXECUTEINFOW sei{};
sei.cbSize = sizeof(sei);
sei.lpVerb = asAdmin ? L"runas" : L"open";
sei.lpFile = L"powershell.exe";
sei.lpParameters = psParam.c_str();
sei.nShow = SW_HIDE;
if (!ShellExecuteExW(&sei)) return false;
if (exitCurrent) ExitProcess(0);
return true;
}
}
#pragma once
+6 -3
View File
@@ -88,6 +88,7 @@ public:
std::string cameraName;
QString viewerName;
std::vector<sx_581_address>address;
int oneTriggerCaptrueTimes = 1;
/// <summary>
/// 初始化
/// </summary>
@@ -101,7 +102,7 @@ public:
/// <param name="bridgeIn">默认</param>
/// <param name="_processAlgoCallback">算法函数</param>
/// <param name="resultHandlerIn"></param>
void init(std::string cameraNameIn, QString viewerNameIN, std::vector<sx_581_address> addressIN, int oneTriggerCaptrueTimes,
void init(std::string cameraNameIn, QString viewerNameIN, std::vector<sx_581_address> addressIN, int oneTriggerCaptrueTimesIN,
paramTemplte* detParamsIn, ServiceManager* _serviceManagerIn, qtFuncBridge* bridgeIn,
typename detCallbackChain<paramTemplte, sx_581_address>::processAlgoCallback _processAlgoCallback,
QString saveObjectNameIN = "") {
@@ -112,6 +113,7 @@ public:
bridge = bridgeIn;
address = addressIN;
saveObjectName = saveObjectNameIN;
oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN;
generalDet = new detCallbackChain<paramTemplte, sx_581_address>(_serviceManager, _detParams, bridge);
generalDet->registerProcessAlgoCallback(_processAlgoCallback);
//单次触发器条件
@@ -145,10 +147,11 @@ public:
auto camera = _serviceManager->_cameraManager->getCamera(cameraName);//获取相机
camera->clearCache();//清除缓存
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(
QString::fromStdString(cameraName), sn, 1, camera->config.oriSaveFormat);//创建数据包
QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
QString saveObjectName = "";
data->saveObjectName = saveObjectName;
camera->captureImage(data);//拍照
for (int i = 0; i < oneTriggerCaptrueTimes; i++)
camera->captureImage(data);//拍照
generalDet->ansyncProcess(data, address[batteryOffset], ("D" + address[0].completeAddr + "_1"));//处理算法 并在取到图片后发送完成信号
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
}
+16 -6
View File
@@ -107,6 +107,7 @@ public:
std::string cameraName;
QString viewerName;
std::map<int, yh_581_address>address;
int oneTriggerCaptrueTimes = 1;
/// <summary>
/// 初始化
/// </summary>
@@ -120,7 +121,7 @@ public:
/// <param name="bridgeIn">默认</param>
/// <param name="_processAlgoCallback">算法函数</param>
/// <param name="resultHandlerIn"></param>
void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount,int oneTriggerCaptrueTimes,
void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount,int oneTriggerCaptrueTimesIN,
paramTemplte* detParamsIn, ServiceManager* _serviceManagerIn, qtFuncBridge* bridgeIn,
typename detCallbackChain<paramTemplte, yh_581_address>::processAlgoCallback _processAlgoCallback,
QString saveObjectNameIN = "") {
@@ -129,6 +130,7 @@ public:
_serviceManager = _serviceManagerIn;
_detParams = detParamsIn;
bridge = bridgeIn;
oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN;
saveObjectName = saveObjectNameIN;
generalDet = new detCallbackChain<paramTemplte, yh_581_address>(_serviceManager, _detParams, bridge);
@@ -170,9 +172,12 @@ public:
auto camera = _serviceManager->_cameraManager->getCamera(cameraName);
camera->clearCache();
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(
QString::fromStdString(cameraName), sn, 1, camera->config.oriSaveFormat);//创建数据包
QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
data->saveObjectName = saveObjectName;
camera->captureImage(data);//拍照
for(int i=0;i< oneTriggerCaptrueTimes;i++)
camera->captureImage(data);//拍照
generalDet->ansyncProcess(data, address[batteryOffset]);//处理算法
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
}
@@ -199,6 +204,7 @@ public:
std::string cameraName;
QString viewerName;
std::map<int, yh_581_address>address;
int oneTriggerCaptrueTimes = 1;
/// <summary>
/// 初始化
/// </summary>
@@ -212,7 +218,7 @@ public:
/// <param name="bridgeIn">默认</param>
/// <param name="_processAlgoCallback">算法函数</param>
/// <param name="resultHandlerIn"></param>
void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount, int oneTriggerCaptrueTimes,
void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount, int oneTriggerCaptrueTimesIN,
paramTemplte2* detParamsIn, ServiceManager* _serviceManagerIn, qtFuncBridge* bridgeIn,
typename detCallbackChain<paramTemplte2, yh_581_address>::processAlgoCallback _processAlgoCallback,
QString saveObjectNameIN = "") {
@@ -221,6 +227,7 @@ public:
_serviceManager = _serviceManagerIn;
_detParams = detParamsIn;
bridge = bridgeIn;
oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN;
saveObjectName = saveObjectNameIN;
generalDet = new detCallbackChain<paramTemplte2, yh_581_address>(_serviceManager, _detParams, bridge);
@@ -253,9 +260,12 @@ public:
auto camera = _serviceManager->_cameraManager->getCamera(cameraName);
camera->clearCache();
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(
QString::fromStdString(cameraName), sn, 1, camera->config.oriSaveFormat);//创建数据包
QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
data->saveObjectName = saveObjectName;
camera->captureImage(data);//拍照
for (int i = 0; i < oneTriggerCaptrueTimes; i++)
camera->captureImage(data);//拍照
generalDet->ansyncProcess(data, address[batteryOffset]);//处理算法
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
}
+3 -1
View File
@@ -26,7 +26,7 @@ void Backend::init(SQLiteDB* db, qtFuncBridge* bridgeIn, nlohmann::ordered_json&
_serviceManager._csvWriter = _csvWriter;
_serviceManager._paramSyncManager = _paramSyncManager;
//CLI 只在首次初始化创建
connect(bridge, &qtFuncBridge::restartInit, this, &Backend::restartInit);
//connect(bridge, &qtFuncBridge::restartInit, this, &Backend::restartInit);
_cliManager = new CLIManager(&_serviceManager, bridge);
initOnce = true;
}
@@ -58,6 +58,8 @@ void Backend::run() {
bool res = _missionLoader.loadMission(missionJson["missionDllPath"]);
if (res == false) {
emit bridge->loadingWindow_appendInitLog("初始化Mission失败!请检查路径是否正确.", "red");
emit bridge->initResult(InitFailure);
return;
}
_missionLoader.getmission(missionJson["missionDllPath"])->initBasic(
&_serviceManager,
+1 -1
View File
@@ -133,7 +133,7 @@ public:
}
private:
QString defaultPath = "{imgSaveRootDir}/{yyyy-MM-dd}/{saveObjectName}{imageType}/{HH}H/{processResult}/{SN}/";
QString defaultFileName = "{SN}_{cameraName}_{index}";
QString defaultFileName = "{SN}_{cameraName}_{index}_{HH-mm-ss}";
};
struct saveJob {
saveJob(std::string jobNameIn) :jobName(jobNameIn) {}
+2
View File
@@ -5,6 +5,8 @@ class MissionLoader {
MissionLoader() = default;
~MissionLoader() = default;
bool loadMission(const std::string& missionPath) {
if (QFile(QString::fromStdString("./" + missionPath + ".dll")).exists() == false)
return false;
hDlls[missionPath] = LoadLibrary(missionPath.c_str());
if (!hDlls[missionPath]) {
std::cerr << "Failed to load Misson DLL!" << std::endl;
@@ -215,11 +215,6 @@ public:
appendColoredMessagesBatch(state.textWidget, logCache[index]);
logCache[index].clear();
// 自动滚动到底部
if (state.autoScroll) {
scrollToBottom(state.textWidget);
}
}
private:
@@ -191,164 +191,14 @@ protected:
}
};
//class histogramWidget : public QWidget {
// Q_OBJECT
//public:
// histogramWidget(QString title, QWidget* parent = nullptr)
// : QWidget(parent), enableAnimation(true)
// {
// setStyleSheet("background-color: rgb(50, 55, 60); color: white;");
// initUI(title);
// initChart();
// }
//
// void setTitle(const QString& text) {
// titleLabel->setText(text);
// }
//
// void setStats(int total, int bad, int good, double goodRate) {
// labelLeft->setText(QString(u8"检测总数: %1\n不良数: %2").arg(total).arg(bad));
// labelRight->setText(QString(u8"良品数: %1\n良品率: %2%").arg(good).arg(goodRate, 0, 'f', 2));
// }
//
// void addBarCategory(const QString& category, double value) {
// categories << category;
// *barSet << value;
// updateChart();
// }
//
// void clearBarData() {
// categories.clear();
// barSet->remove(0, barSet->count());
// updateChart();
// }
//
// void setAnimationEnabled(bool enabled) {
// enableAnimation = enabled;
// chart->setAnimationOptions(enableAnimation ? QChart::SeriesAnimations : QChart::NoAnimation);
// }
//
//private:
// QLabel* titleLabel;
// QLabel* labelLeft;
// QLabel* labelRight;
// QChart* chart;
// QChartView* chartView;
// QBarSet* barSet;
// QStringList categories;
// bool enableAnimation;
//
// void initUI(QString title) {
// QVBoxLayout* mainLayout = new QVBoxLayout(this);
//
// titleLabel = new QLabel(title);
// titleLabel->setStyleSheet("font-size: 16px; font-weight: bold;");
// mainLayout->addWidget(titleLabel);
//
// QHBoxLayout* dataLayout = new QHBoxLayout();
// labelLeft = new QLabel(u8"检测总数\n不良数");
// labelRight = new QLabel(u8"良品数\n良品率");
// labelLeft->setAlignment(Qt::AlignLeft);
// labelRight->setAlignment(Qt::AlignLeft);
// dataLayout->addWidget(labelLeft);
// dataLayout->addStretch();
// dataLayout->addWidget(labelRight);
// mainLayout->addLayout(dataLayout);
//
// chartView = new QChartView();
// chartView->setRenderHint(QPainter::Antialiasing);
// mainLayout->addWidget(chartView);
//
// this->setStyleSheet(
// "QLineEdit { background-color: rgb(50, 55, 60); color: white; border-radius: 4px; padding: 2px; } "
// "QLabel { color: white; } "
// );
// }
//
// void initChart() {
// barSet = new QBarSet("数量");
// *barSet << 0; // 初始一个数据
//
// QBarSeries* series = new QBarSeries();
// series->append(barSet);
//
// chart = new QChart();
// chart->addSeries(series);
// chart->setBackgroundVisible(false);
// chart->legend()->hide();
// chart->setAnimationOptions(enableAnimation ? QChart::SeriesAnimations : QChart::NoAnimation);
//
// QBarCategoryAxis* axisX = new QBarCategoryAxis();
// axisX->append(categories);
// chart->addAxis(axisX, Qt::AlignBottom);
// series->attachAxis(axisX);
//
// QValueAxis* axisY = new QValueAxis();
// axisY->setLabelFormat("%.0f");
// axisY->setLabelsBrush(QBrush(QColor(255, 255, 255)));
// axisY->setRange(0, 100); // 初始范围,后面会动态调整
// chart->addAxis(axisY, Qt::AlignLeft);
// series->attachAxis(axisY);
//
// chartView->setChart(chart);
//
// chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// chartView->setContentsMargins(0, 0, 0, 0);
// chartView->setStyleSheet("background-color: rgb(50, 55, 60); border: none;");
// chart->setMargins(QMargins(0, 0, 0, 0)); // 去掉 QChart 的四周空白
// chart->setBackgroundBrush(QBrush(QColor(50, 55, 60)));
// }
//
// void updateChart() {
// QMutexLocker locker(&mutex);
// chart->removeAllSeries();
//
// QBarSeries* series = new QBarSeries();
// series->append(barSet);
// chart->addSeries(series);
//
// QBarCategoryAxis* axisX = new QBarCategoryAxis();
// axisX->append(categories);
// chart->addAxis(axisX, Qt::AlignBottom);
// series->attachAxis(axisX);
//
// QValueAxis* axisY = new QValueAxis();
// axisY->setLabelFormat("%.0f");
// // 添加每个柱子上方的数值标签
// for (int i = 0; i < barSet->count(); ++i) {
// QGraphicsSimpleTextItem* label = new QGraphicsSimpleTextItem(QString::number((*barSet)[i]));
// label->setBrush(QBrush(Qt::white));
// QPointF pos = chart->mapToPosition(QPointF(i, (*barSet)[i]), series);
// label->setPos(pos.x() - 5, pos.y() - 20);
// chart->scene()->addItem(label);
// }
//
// chart->setAnimationOptions(enableAnimation ? QChart::SeriesAnimations : QChart::NoAnimation);
// }
//
//protected:
// void paintEvent(QPaintEvent* event) override {
// QPainter painter(this);
// painter.setRenderHint(QPainter::Antialiasing);
//
// int radius = 10;
// QRect r = rect();
//
// painter.setBrush(QColor(50, 55, 60));
// painter.setPen(Qt::NoPen);
// painter.drawRoundedRect(r, radius, radius);
// }
//private:
// QMutex mutex;
//};
class dayNightShiftHistogramWidget : public QWidget {
public:
histogramWidget* dayHistogramWidget;
histogramWidget* nightHistogramWidget;
dayNightShiftHistogramWidget() {
dayHistogramWidget = new histogramWidget("白班(08:30-20:30)");
nightHistogramWidget = new histogramWidget("夜班(20:30-08:30)");
QString ymd = QDate::currentDate().toString("yyyy-MM-dd");
dayHistogramWidget = new histogramWidget(ymd + "白班(08:30-20:30)");
nightHistogramWidget = new histogramWidget(ymd +"夜班(20:30-08:30)");
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@@ -366,15 +216,18 @@ public:
//}
void addDefect(std::vector<std::string>defects) {
bool isDay = isDayShiftNow();
//判断是否切换班次,如切换则清空下个班次的数据
//判断是否切换班次,如切换则清空当前班次的数据
if (lastIsDayState != isDay) {
QString ymd = QDate::currentDate().toString("yyyy-MM-dd");
if (isDay == true) {
nightHistogramWidget->clearBarData();
nightDefectMap.clear();
}
else {
dayHistogramWidget->clearBarData();
dayDefectMap.clear();
dayHistogramWidget->setTitle(ymd + "白班(08:30-20:30)");
}
else {
nightHistogramWidget->clearBarData();
nightDefectMap.clear();
nightHistogramWidget->setTitle(ymd + "夜班(20:30-08:30)");
}
okCnt = 0;
ngCnt = 0;
+1 -2
View File
@@ -13,14 +13,13 @@ private:
// 禁用拷贝构造函数和赋值运算符
appConfig(const appConfig&) = delete;
appConfig& operator=(const appConfig&) = delete;
public:
// 获取单例实例
static appConfig& getInstance() {
static appConfig instance;
return instance;
}
bool exitWithRestart = false;
void parsingSettingJson();
void loadSetting() {
parsingSettingJson();
+21 -2
View File
@@ -9,10 +9,29 @@ static void qtMessageHandler(QtMsgType type, const QMessageLogContext& context,
if (!qtRediretor_Ptr) {
return;
}
QString typeText = "";
switch (type)
{
case QtDebugMsg:
typeText = "DEBUG";
break;
case QtWarningMsg:
typeText = "WARNING";
break;
case QtCriticalMsg:
typeText = "ERROR";
break;
case QtFatalMsg:
typeText = "ERROR";
break;
default:
typeText = "INFO";
break;
}
// 构建格式化的日志消息
// 格式: [文件名:行号] 消息内容
QString outputMessage = QString("[%1:%2] %3")
QString outputMessage = QString("[%1][%2:%3] %4")
.arg(typeText)
.arg(QFileInfo(context.file).fileName())
.arg(context.line)
.arg(msg);
+13 -1
View File
@@ -186,6 +186,11 @@ void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge*
config.missionJson["backend"] = _core->_backEnd.backend->getJson();
config.saveSettingJson();
}, Qt::DirectConnection);
QObject::connect(bridge, &qtFuncBridge::restartInit,[=]() {
appConfig::getInstance().exitWithRestart = true;
QApplication::quit();
});
}
int main(int argc, char* argv[])
@@ -249,5 +254,12 @@ int main(int argc, char* argv[])
if (config.dataBase) delete config.dataBase;
config.dataBase = nullptr;
});
return a.exec();
int qtRes = a.exec();
if (config.exitWithRestart) {
ShowWindow(hWnd, SW_SHOW);
std::cout << "程序将在五秒后重启..." << std::endl;
restartProgram(false,true,5000);
}
return qtRes;
}
+1
View File
@@ -166,6 +166,7 @@ static bool ManHan(std::shared_ptr <detData> data, mfd_detParams* _detParams, yh
}
static bool YuHan(std::shared_ptr <detData> data, mfd_detParams* _detParams, yh_581_address address){
try {
data->service->_missionResultHandle->toBarChart("", true, {"测试"});
std::map<QString, QVariant> sqlMapData;
sqlMapData["项目"] = "预焊";
sqlMapData["相机"] = "相机" + address.triggerAddr;