V20260127-2.3.11

存图时会缓存创建文件夹的路径以防重复创建。
悬停在右侧缺陷柱状图时会出现具体缺陷名,
部分逻辑以及保护优化。
This commit is contained in:
2026-01-28 10:49:49 +08:00
parent b354e4a5e7
commit f50bcb30d1
19 changed files with 366 additions and 184 deletions
+2 -2
View File
@@ -11,7 +11,7 @@
#include <QDir>
#pragma execution_character_set("utf-8")
const std::string softwareVersion = "20260122-2.3.10";
const std::string softwareVersion = "20260127-2.3.11";
const std::string euiJsonVersion = "1.0.6";
#define GigaByte 1073741824
#define globalDatabasePth "./sqlDatabase/eui_db.db" //全局数据库路径
@@ -22,7 +22,7 @@ const std::string euiJsonVersion = "1.0.6";
#define imgSaveTreadMaxCount 4 //最大存图线程数
#define jsonRpcEnable false //是否启用JSON RPC服务器
#define minimumWindowSize 1280, 720//最小窗口大小
#define histogramLabelTiltAngle 30 //柱状图标签倾斜角度
#define histogramLabelTiltFontSize 8 //柱状图标签字体大小
#define windowMoveFreshRate 60//窗口移动每秒的刷新率
#define sColor_Blue "51, 56, 69"
#define sColor_BlueWithWhite "64, 68, 81"
+25 -22
View File
@@ -107,12 +107,16 @@ public:
virtual void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) = 0;
};
class TextRendererZH : public TextRendererBase {
class TextRendererZH{
public:
TextRendererZH(const TextRendererZH&) = delete;
TextRendererZH& operator=(const TextRendererZH&) = delete;
TextRendererZH(TextRendererZH&&) noexcept = default;
TextRendererZH& operator=(TextRendererZH&&) noexcept = default;
TextRendererZH(int width, int height, int fontSize = 20, const std::wstring& fontName = L"微软雅黑")
: width_(width), height_(height), fontSize_(fontSize), fontName_(fontName)
{
QMutexLocker locker(&mutex_);
screenDC_ = GetDC(nullptr);
if (!screenDC_) {
throw std::runtime_error("Failed to get screen DC");
@@ -121,12 +125,11 @@ public:
}
~TextRendererZH() {
QMutexLocker locker(&mutex_);
releaseResources();
if (screenDC_) ReleaseDC(nullptr, screenDC_);
}
void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) override {
void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) {
QMutexLocker locker(&mutex_);
if (image.channels() != 3)
@@ -182,45 +185,45 @@ public:
struct contourPaintJob {
std::vector<cv::Point> contour;
cv::Scalar color;
int thikness;
int thickness;
};
void appendPaintJob(std::vector<cv::Point> contour, cv::Scalar color, int thikness) {
void appendPaintJob(std::vector<cv::Point> contour, cv::Scalar color, int thickness) {
QMutexLocker locker(&mutex_);
contourPaintJobs.push_back(contourPaintJob{ contour,color,thikness });
contourPaintJobs.push_back(contourPaintJob{ contour,color,thickness });
}
struct linePaintJob {
cv::Point p1;
cv::Point p2;
cv::Scalar color;
int thikness;
int thickness;
};
void appendPaintJob(cv::Point p1, cv::Point p2, cv::Scalar color, int thikness) {
void appendPaintJob(cv::Point p1, cv::Point p2, cv::Scalar color, int thickness) {
QMutexLocker locker(&mutex_);
linePaintJobs.push_back(linePaintJob{ p1,p2,color,thikness });
linePaintJobs.push_back(linePaintJob{ p1,p2,color,thickness });
}
struct circleAndCorssPaintJob {
cv::Point center;
double radius;
cv::Scalar color;
int thikness;
int thickness;
int type;
};
//type0 圆 type1 十字
void appendPaintJob(cv::Point center, double radius,cv::Scalar color, int thikness,int type) {
void appendPaintJob(cv::Point center, double radius,cv::Scalar color, int thickness,int type) {
QMutexLocker locker(&mutex_);
circleAndCorssPaintJobs.push_back(circleAndCorssPaintJob{ center,radius,color,thikness,type });
circleAndCorssPaintJobs.push_back(circleAndCorssPaintJob{ center,radius,color,thickness,type });
}
struct rectPaintJob {
cv::Rect rect;
cv::Scalar color;
int thikness;
int thickness;
};
void appendPaintJob(cv::Rect rect, cv::Scalar color,int thikness) {
void appendPaintJob(cv::Rect rect, cv::Scalar color,int thickness) {
QMutexLocker locker(&mutex_);
rectPaintJobs.push_back(rectPaintJob{ rect,color,thikness });
rectPaintJobs.push_back(rectPaintJob{ rect,color,thickness });
}
struct textPaintJob {
@@ -233,7 +236,7 @@ public:
textPaintJobs.push_back(textPaintJob{ text,p,color });
}
void excusePaintJobs(cv::Mat& image,double resizeRate = 1.0) {
void executePaintJobs(cv::Mat& image,double resizeRate = 1.0) {
QMutexLocker locker(&mutex_);
if (textPaintJobs.empty() && pointPaintJobs.empty() && circleAndCorssPaintJobs.empty() && rectPaintJobs.empty() && contourPaintJobs.empty() && linePaintJobs.empty()) return;
@@ -253,24 +256,24 @@ public:
// 绘制圆或十字
for (const auto& job : circleAndCorssPaintJobs) {
if(job.type == 0)
cv::circle(image, job.center, job.radius, job.color, job.thikness);
cv::circle(image, job.center, job.radius, job.color, job.thickness);
else
cv::drawMarker(image, job.center, job.color, cv::MARKER_CROSS, job.radius, job.thikness);
cv::drawMarker(image, job.center, job.color, cv::MARKER_CROSS, job.radius, job.thickness);
}
// 绘制点集
for (const auto& job : contourPaintJobs) {
cv::drawContours(image, { job.contour }, 0, job.color, job.thikness);
cv::drawContours(image, { job.contour }, 0, job.color, job.thickness);
}
// 绘制线段
for (const auto& job : linePaintJobs) {
cv::line(image, job.p1, job.p2, job.color, job.thikness);
cv::line(image, job.p1, job.p2, job.color, job.thickness);
}
// 绘制矩形
for (const auto& job : rectPaintJobs) {
cv::rectangle(image, job.rect, job.color, job.thikness);
cv::rectangle(image, job.rect, job.color, job.thickness);
}
// 绘制文本(需要GDI处理)
+1 -1
View File
@@ -150,10 +150,10 @@ public:
camera->clearCache();//清除缓存
std::shared_ptr <detData> data = _serviceManager->_detDataManager->createDetData(
QString::fromStdString(cameraName), sn, oneTriggerCaptrueTimes, camera->config.oriSaveFormat);//创建数据包
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
data->saveObjectName = saveObjectName;
camera->captureImage(data);//拍照
generalDet->asyncProcess(data, address[batteryOffset], ("D" + address[batteryOffset].completeAddr + "_1"));//处理算法 并在取到图片后发送完成信号
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
}
private:
QString saveObjectName = "";
+1 -2
View File
@@ -290,11 +290,10 @@ public:
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]);//处理算法
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
_serviceManager->_triggerManager->writeShort("D" + address[batteryOffset].completeAddr + "_1");//完成信号 根据偏移发送
}
private:
+1 -2
View File
@@ -290,11 +290,10 @@ public:
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]);//处理算法
data->resultImgShowSet.push_back(showImgPack(viewerName, "结果图"));
_serviceManager->_triggerManager->writeShort("D" + address[batteryOffset].completeAddr + "_1");//完成信号 根据偏移发送
}
private:
+4 -4
View File
@@ -12,10 +12,10 @@
#include <paramSyncManager.h>
class Backend : public IBackend {
public:
DataRecorder* _dataRecorder = nullptr;
missionResultHandle* _missionResultHandle = nullptr;
ServiceManager _serviceManager;
paramSyncManager* _paramSyncManager = nullptr;//供客户在UI修改/查看
DataRecorder* _dataRecorder = nullptr;// 数据记录器
missionResultHandle* _missionResultHandle = nullptr;// 任务结果处理器
ServiceManager _serviceManager;//服务类接口
paramSyncManager* _paramSyncManager = nullptr;//检测参数同步类//供客户在UI修改/查看
CLIManager* _cliManager; // 命令行接口管理器
#if jsonRpcEnable
rpc::JsonRpcServer _rpcServer;
+118 -27
View File
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
#include <cctype>
#include <stdexcept>
#include <detData.h>
#include <paramSyncManager.h>
#include <global.h>
@@ -43,7 +44,7 @@ public:
for (int i = 0; i < data->resultSaveText.size(); i++) {
processResult.append("_" + data->resultSaveText[i]);
}
result.replace("{processResult}", processResult);
result.replace("{processResult}", QString::fromStdString(repairWindowsFileName(processResult.toStdString())));
// 替换SN/设备信息占位符
QString snCode = (data->SNcode.size() > 0 && data->SNcode.size() < 50)
@@ -167,6 +168,7 @@ public:
return result;
}
private:
QString defaultPath = "{imgSaveRootDir}/{yyyy-MM-dd}/{saveObjectName}{imageType}/{HH}H/{processResult}/{SN}/";
@@ -174,8 +176,8 @@ private:
};
struct saveJob {
saveJob(std::string jobNameIn) :jobName(jobNameIn) {}
std::string jobName;
QQueue<std::pair<std::string, cv::Mat>> imgQueue;
std::string jobName;// 任务名称
QQueue<std::pair<std::string, cv::Mat>> imgQueue;// 图片队列
};
// 数据库存储线程类
@@ -283,7 +285,6 @@ private:
QMutex queueMutex;
std::atomic<int> pendingCount = 0;
};
class imgSaveThread : public QThread {
public:
@@ -314,20 +315,18 @@ public:
if (job == nullptr) {
break;
}
#if saveImgEnable
imgRemainCount -= job->imgQueue.size();
qDebug() << "saveJob start" << QString::fromStdString(job->jobName) << "remain" << imgRemainCount;
localQueue.swap(job->imgQueue);
// 批量保存
while (!localQueue.isEmpty()) {
auto data = std::move(localQueue.dequeue());
#if saveImgEnable
cv::imwrite(data.first, data.second);
QMutexLocker locker(&threadBufferSizeMutex);
threadBufferSize -= data.second.total() * data.second.elemSize();
#endif
}
#endif
qDebug() << "saveJob end " << QString::fromStdString(job->jobName);
}
}
@@ -381,6 +380,90 @@ private:
int threadIndex = 0, threadBufferSize = 0, imgRemainCount = 0;
QMutex queueMutex, threadBufferSizeMutex;
};
//用于缓存需要创建的文件夹路径,防止重复创建
class LRUCache {
public:
explicit LRUCache(int capacity) : maxCapacity(capacity) {
if (capacity <= 0) {
throw std::invalid_argument("LRU缓存容量必须大于0");
}
}
// 检查字符串是否在缓存中
bool contains(const QString& value) {
QMutexLocker locker(&mutex);
int index = cacheList.indexOf(value);
if (index != -1) {
// 移动到列表头部(最近使用)
cacheList.move(index, 0);
return true;
}
return false;
}
// 添加字符串到缓存
void put(const QString& value) {
QMutexLocker locker(&mutex);
if (value.isEmpty()) {
return; // 不缓存空字符串
}
int index = cacheList.indexOf(value);
if (index != -1) {
// 已存在,移动到头部
cacheList.move(index, 0);
return;
}
// 不存在,需要添加
if (cacheList.size() >= maxCapacity) {
// 缓存已满,移除最久未使用的元素(尾部)
cacheList.removeLast();
}
// 添加新元素到头部
cacheList.prepend(value);
}
// 移除指定元素
bool remove(const QString& value) {
QMutexLocker locker(&mutex);
int index = cacheList.indexOf(value);
if (index != -1) {
cacheList.removeAt(index);
return true;
}
return false;
}
// 获取缓存大小
int size() const {
return cacheList.size();
}
// 获取最大容量
int capacity() const {
return maxCapacity;
}
// 检查是否为空
bool isEmpty() const {
return cacheList.isEmpty();
}
// 清空缓存
void clear() {
QMutexLocker locker(&mutex);
cacheList.clear();
}
private:
QMutex mutex;
int maxCapacity;
QStringList cacheList; // QStringList,头部是最近使用的,尾部是最久未使用的
};
class imgSaveThreadManager {
public:
imgSaveThreadManager(std::string pathIn, paramSyncManager* paramSyncManagerIn)
@@ -391,7 +474,6 @@ public:
saveRes = _paramSyncManager->get("通用设置", "存储结果图", true).toBool();
saveSeg = _paramSyncManager->get("通用设置", "存储Seg图", true).toBool();
saveCls = _paramSyncManager->get("通用设置", "存储Cls图", true).toBool();
//初始化存图线程
QMutexLocker locker(&saveThreadMutexVec);
saveThreads.emplace_back(std::make_unique<imgSaveThread>(saveThreads.size()));
@@ -446,12 +528,32 @@ public:
}
}
try {
std::shared_ptr<saveJob> oriJob(new saveJob("[ORI_JOB]" + data->SNcode));
std::shared_ptr<saveJob> resJob(new saveJob("[RES_JOB]" + data->SNcode));
std::shared_ptr<saveJob> oriJob(new saveJob("[ORI_JOB]" + data->SNcode));
QString resSavePath = _ImageSavePathFormatter.genPath(data, "结果图", data->customPath, data->customImageSaveTemplateParams);//获取文件夹名
if (saveRes == true) {
if (createPathCache.contains(resSavePath) == false) {//不存在此文件夹则创建
createDirectoryIfNotExists(resSavePath);
allDirectoryPaths.push_back(resSavePath);//记录文件夹路径
createPathCache.put(resSavePath);//加入缓存
}
//结果图保存
if (data->getResultImgSize() != 0) {
std::vector<std::string>fileNames = _ImageSavePathFormatter.genFileNames(data, ImageSavePathFormatter::resImg, data->getResultImgVec());//按规则为文件创建命名
packageData(resJob->imgQueue, resSavePath.toLocal8Bit().toStdString(), fileNames, data->getResultImgVec());//打包数据
}
}
QString oriSavePath = _ImageSavePathFormatter.genPath(data, "原图", data->customPath, data->customImageSaveTemplateParams);//获取文件夹名
if (saveOri == true || saveSeg == true || saveCls == true) {
createDirectoryIfNotExists(oriSavePath);//不存在此文件夹则创建
allDirectoryPaths.push_back(oriSavePath);//记录文件夹路径
if (createPathCache.contains(oriSavePath) == false) {//不存在此文件夹则创建
createDirectoryIfNotExists(oriSavePath);
allDirectoryPaths.push_back(oriSavePath);//记录文件夹路径
createPathCache.put(oriSavePath);//加入缓存
}
if (data->getOriImgSize() != 0 && saveOri == true) {
std::vector<std::string>fileNames = _ImageSavePathFormatter.genFileNames(data, ImageSavePathFormatter::oriImg, data->getOriImgVec());//按规则为文件创建命名
packageData(oriJob->imgQueue, oriSavePath.toLocal8Bit().toStdString(), fileNames, data->getOriImgVec());//打包数据
@@ -468,22 +570,10 @@ public:
}
}
QString resSavePath = _ImageSavePathFormatter.genPath(data, "结果图", data->customPath, data->customImageSaveTemplateParams);//获取文件夹名
if (saveRes == true) {
createDirectoryIfNotExists(resSavePath);//不存在此文件夹则创建
allDirectoryPaths.push_back(resSavePath);//记录文件夹路径
//结果图保存
if (data->getResultImgSize() != 0) {
std::vector<std::string>fileNames = _ImageSavePathFormatter.genFileNames(data, ImageSavePathFormatter::resImg, data->getResultImgVec());//按规则为文件创建命名
packageData(resJob->imgQueue, resSavePath.toLocal8Bit().toStdString(), fileNames, data->getResultImgVec());//打包数据
}
}
if (oriJob->imgQueue.size() != 0)
getSaveThread()->addJob(oriJob);
if (resJob->imgQueue.size() != 0)
getSaveThread()->addJob(resJob, imgSaveThread::priority);
if (oriJob->imgQueue.size() != 0)
getSaveThread()->addJob(oriJob);
#pragma region 将存储目录写入数据库中
#if savePathToDataBase
@@ -522,11 +612,12 @@ public:
return saveThreads.back().get();
}
private:
LRUCache createPathCache{ 200 };//用于缓存已经创建过的文件夹路径,防止重复创建
std::unique_ptr<dbSaveThread> dbThread; // 数据库存储线程
QMutex paramTimerMutex; // 保护参数计时器的互斥锁
int maxSaveThreadCount = imgSaveTreadMaxCount;
QMutex saveThreadMutexVec;
std::vector<std::unique_ptr<imgSaveThread>> saveThreads;
std::vector<std::unique_ptr<imgSaveThread>> saveThreads;//存图线程池
bool saveOri = true, saveRes = true, saveSeg = true, saveCls = true;
QElapsedTimer getParamTimer;//防止加锁次数过多导致卡顿
paramSyncManager* _paramSyncManager;
+29 -29
View File
@@ -103,11 +103,14 @@ void triggerManager::receiveCommand() {
for (auto& _struct : readAllCmds) {
QByteArray readByte = _struct.readAllCmd;
mutex.lock();
if (!reciveFinsMsg(readByte))
qCritical() << "[TCP] " << " finstcp_ptr readData error!";
mutex.unlock();
//接收数据
{
QMutexLocker locker(&mutex);
if (!reciveFinsMsg(readByte))
qCritical() << "[TCP] " << " finstcp readData error!";
}
tLocker[_struct.readAllCmd].reFreshLocker(readByte);//经过检查后再触发
//解析数据
decodeCameraCMD(_struct,readByte);
}
@@ -147,10 +150,10 @@ void triggerManager::decodeCameraCMD(readAllStruct& _struct, QByteArray byte)
else if (isConnected == false) {
emit bridge->setPlcConnectionOk();
isConnected = true;
qDebug() << "掉线时间:" << lostConnectionCountTimer.elapsed() / 1000.0 << "秒";
std::cout << "重连成功,经过时间:" << lostConnectionCountTimer.elapsed() / 1000.0 << "秒" << std::endl;
qDebug() << "重连成功,经过时间:" << lostConnectionCountTimer.elapsed() / 1000.0 << "秒";
std::cout << "重连成功,经过时间:" << lostConnectionCountTimer.elapsed() / 1000.0 << "秒" << std::endl;
}
checkCallback(_struct,byte);
checkCallback(_struct, byte);
checkUnionCallback(_struct, byte);
checkPlcValueViewer(_struct, byte);
}
@@ -162,18 +165,17 @@ void triggerManager::checkCallback(readAllStruct _struct, QByteArray& byteArray)
if (checkTrigger(callback.triggerAddress, callback.triggerValue, _struct, byteArray) == true)
{
qDebug() << "func:" << QString::fromStdString(callback.funcName) << "->已触发 " << callback.triggerValue;
std::async(std::launch::async, [callback, byteArray]() mutable {
try {
callback.func(callback.triggerAddress, callback.triggerValue, byteArray); // 执行回调函数
}
catch (const std::exception& e) {
qCritical() << "Error in callback " << QString::fromStdString(callback.funcName) << ": " << QString::fromStdString(e.what());
}
catch (...) {
qCritical() << "Error in callback : unexpected" << QString::fromStdString(callback.funcName);
}
});
try {
callback.func(callback.triggerAddress, callback.triggerValue, byteArray); // 执行回调函数
}
catch (const std::exception& e) {
qCritical() << "Error in callback " << QString::fromStdString(callback.funcName) << ": " << QString::fromStdString(e.what());
}
catch (...) {
qCritical() << "Error in callback : unexpected" << QString::fromStdString(callback.funcName);
};
}
}
}
@@ -216,17 +218,15 @@ void triggerManager::checkUnionCallback(readAllStruct& _struct, QByteArray& byte
}
}
qDebug() << "Union func:" << QString::fromStdString(cb.funcName) << "->已触发 ("<< triggerSource <<")";
std::async(std::launch::async, [cb, copyByte = byteArray, triggerSource]() mutable {
try {
cb.func(triggerSource, copyByte);
}
catch (const std::exception& e) {
qCritical() << "Error in union callback " << QString::fromStdString(cb.funcName) << ": " << QString::fromStdString(e.what()) ;
}
catch (...) {
qCritical() << "Error in union callback : unexpected" << QString::fromStdString(cb.funcName);
}
});
try {
cb.func(triggerSource, byteArray);
}
catch (const std::exception& e) {
qCritical() << "Error in union callback " << QString::fromStdString(cb.funcName) << ": " << QString::fromStdString(e.what()) ;
}
catch (...) {
qCritical() << "Error in union callback : unexpected" << QString::fromStdString(cb.funcName);
};
}
}
@@ -3,6 +3,8 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPainter>
#include <QToolTip>
#include <QCursor>
#include <QGraphicsSimpleTextItem>
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
@@ -111,7 +113,7 @@ private:
chartView->setRenderHint(QPainter::Antialiasing);
mainLayout->addWidget(chartView);
setStyleSheet("QLabel { color: white; }");
setStyleSheet("QLabel { color: white; } QToolTip { color: white; background-color: rgb(40, 45, 50); border: 1px solid rgb(80, 85, 90); }");
}
void initChart() {
@@ -119,6 +121,20 @@ private:
barSet->setColor(QColor(255, 0, 0)); // 红色柱体
barSet->setBorderColor(QColor(255, 255, 255)); // 白色边框
connect(barSet, &QBarSet::hovered, this, [this](bool status, int index) {
QMutexLocker locker(&mutex);
if (!status) {
QToolTip::hideText();
return;
}
if (index < 0 || index >= categories.size())
return;
const QString text = QString::fromUtf8("%1\n数量: %2")
.arg(categories.at(index))
.arg(barSet->at(index));
QToolTip::showText(QCursor::pos(), text, chartView, QRect(), 30000);
});
series = new QBarSeries();
series->append(barSet);
@@ -130,7 +146,6 @@ private:
axisX = new QBarCategoryAxis();
axisX->setLabelsBrush(QBrush(Qt::white));
axisX->setLabelsAngle(histogramLabelTiltAngle); // 设置标签倾斜
chart->addAxis(axisX, Qt::AlignBottom);
series->attachAxis(axisX);
@@ -142,7 +157,7 @@ private:
series->attachAxis(axisY);
chartView->setChart(chart);
chart->setMargins(QMargins(0, 0, 0, 0));
chart->setMargins(QMargins(0, 0, 0, 0));
chart->setBackgroundBrush(QColor(50, 55, 60));
chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
chartView->setContentsMargins(0, 0, 0, 0);
@@ -151,7 +166,7 @@ private:
void updateValueLabels() {
QFont font;
font.setPointSize(10);
font.setPointSize(histogramLabelTiltFontSize);
font.setBold(true);
// 删除旧标签
+4 -1
View File
@@ -1,6 +1,9 @@
#include "qtLogRediretor.h"
#include <QDateTime>
#include <QDebug>
#include <QFileInfo>
#include <thread>
#include <chrono>
// 全局指针,用于消息处理函数
static qtRediretor* qtRediretor_Ptr = nullptr;
@@ -22,7 +25,7 @@ static void qtMessageHandler(QtMsgType type, const QMessageLogContext& context,
typeText = "ERROR";
break;
case QtFatalMsg:
typeText = "ERROR";
typeText = "FATAL";
break;
default:
typeText = "INFO";
+27 -4
View File
@@ -7,6 +7,7 @@
#include <QSharedMemory>
#include <QMessageLogger>//日志
#include <QDebug>
#include <QDateTime>
#include <qmessagebox.h>
#include <qpushbutton.h>
#include <qlineedit.h>
@@ -102,9 +103,10 @@ static bool dumpCallback(const wchar_t* dump_path,
bool succeeded) {
QString dumpFile = QString::fromWCharArray(dump_path) + "\\" + QString::fromWCharArray(minidump_id) + ".dmp";
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
if (succeeded) {
qDebug() << "========== 程序崩溃 ==========";
qDebug() << "========== 程序崩溃 ==========" << timestamp;
qDebug() << "崩溃转储文件已生成:" << dumpFile;
if (exinfo && exinfo->ExceptionRecord) {
@@ -125,19 +127,33 @@ static bool dumpCallback(const wchar_t* dump_path,
default: exceptionType = "未知异常"; break;
}
qDebug() << "异常类型:" << exceptionType;
// 记录更多上下文信息
if (exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
exinfo->ExceptionRecord->NumberParameters >= 2) {
ULONG_PTR operation = exinfo->ExceptionRecord->ExceptionInformation[0];
ULONG_PTR address = exinfo->ExceptionRecord->ExceptionInformation[1];
QString operationType = (operation == 0) ? "读取" : (operation == 1) ? "写入" : "执行";
qDebug() << "访问类型:" << operationType << "地址:" << Qt::hex << Qt::showbase << address;
}
}
// 记录当前线程ID
qDebug() << "崩溃线程ID:" << GetCurrentThreadId();
qDebug() << "==============================";
// 程序崩溃后自动重启
qDebug() << "程序即将自动重启...";
} else {
qDebug() << "========== 崩溃转储失败 ==========" << timestamp;
qDebug() << "生成崩溃转储文件失败!";
qDebug() << "程序即将自动重启...";
qDebug() << "==============================";
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
restartProgram(false, true, 5000);
return succeeded;
}
@@ -317,6 +333,12 @@ int main(int argc, char* argv[])
std::cout << "程序将在五秒后重启..." << std::endl;
restartProgram(false,true,5000);
}
qDebug() << "程序退出,返回值" << qtRes;
if (qtRes != 0) {
qDebug() << "返回值不为0,非正常退出,即将重启程序";
restartProgram(false, true, 5000);
}
QThread::msleep(200);
return qtRes;
}
catch (const std::exception& e) {
@@ -343,4 +365,5 @@ int main(int argc, char* argv[])
restartProgram(false, true, 5000);
return -2;
}
return -99;
}
@@ -131,7 +131,7 @@ halconResult dituo(std::shared_ptr <detData> data, cv::Mat& src, cv::Mat& Paint,
}
//释放存储画图文字
textPainterdefect.excusePaintJobs(Paint);
textPainterdefect.executePaintJobs(Paint);
}
}
CATCH_EXCEPTIONS
@@ -514,8 +514,8 @@ bool ALGO_BaoMoHouCeMian(std::shared_ptr <detData> data, baoMoHouDaMianDetParams
}
else
cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5);
textPainter.excusePaintJobs(Paint);
textPainterCls.excusePaintJobs(Paint);
textPainter.executePaintJobs(Paint);
textPainterCls.executePaintJobs(Paint);
data->service->_missionResultHandle->toBarChart(data->SNcode, defects);
int Rate = (Paint.rows > Paint.cols ? Paint.cols : Paint.rows) / 20;
TextRendererZH textPainter1(Paint.cols, Paint.rows, Rate);
+1 -1
View File
@@ -162,7 +162,7 @@ static bool yuHanQian3D(std::shared_ptr <detData> data, detParams* _detParams, y
data->service->_missionResultHandle->toBarChart(data->SNcode, defects);
Paint = HObject2Mat(out_DisplayImage);
textPainter.excusePaintJobs(Paint);
textPainter.executePaintJobs(Paint);
int rate = MIN(Paint.rows, Paint.cols) / 20;
TextRendererZH textPainter1(Paint.cols, Paint.rows, rate);
textPainter1.putText(Paint, "当前条码:" + data->SNcode, cv::Point(50, Paint.rows - (rate * 2)), cv::Scalar(0, 255, 255));
@@ -195,7 +195,7 @@ bool DianJiaoJianCe(std::shared_ptr <detData> data, dianJiaoParams* _detParams,
_detParams->batteryIsNg = (_detParams->lastResultIsNg == true || plcResult == "2");
_detParams->lastResultIsNg = false;
textPainter.excusePaintJobs(Paint);
textPainter.executePaintJobs(Paint);
Paint.copyTo(_detParams->lastDetImg);
}
else if (address.triggerValue == 4) {
@@ -209,7 +209,7 @@ bool DianJiaoJianCe(std::shared_ptr <detData> data, dianJiaoParams* _detParams,
_detParams->lastResultIsNg = false;
_detParams->batteryIsNg = false;
textPainter.excusePaintJobs(Paint);
textPainter.executePaintJobs(Paint);
if (_detParams->lastDetImg.empty() == false)
cv::hconcat(_detParams->lastDetImg, Paint, Paint);
data->insertResultImg(Paint);
@@ -320,8 +320,8 @@ bool TieJiaoJianCe(std::shared_ptr <detData> data, tieJiaoParams* _detParams, sx
if (plcResult == "2")
_detParams->lastResultIsNg = true;
}
textPainter.excusePaintJobs(Paint);
textPainter2.excusePaintJobs(Paint);
textPainter.executePaintJobs(Paint);
textPainter2.executePaintJobs(Paint);
data->insertResultImg(Paint);
return true;
}
@@ -193,9 +193,9 @@ bool HanQianDingWei(std::shared_ptr <detData> data, hanQianDingWeiParams* _detPa
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈
data->service->_missionResultHandle->toBarChart(data->SNcode, defects);
textPainter.excusePaintJobs(Paint);
textPainter2.excusePaintJobs(Paint);
textPainter3.excusePaintJobs(Paint);
textPainter.executePaintJobs(Paint);
textPainter2.executePaintJobs(Paint);
textPainter3.executePaintJobs(Paint);
TextRendererZH textPainterx(Paint.cols, Paint.rows, 160);
textPainterx.putText(Paint, "SN:" + data->SNcode, cv::Point(3000,0), cv::Scalar(0, 255, 0));
textPainterx.putText(Paint, QDateTime::currentDateTime().toString().toStdString(), cv::Point(3000, 80), cv::Scalar(0, 255, 0));
@@ -215,7 +215,9 @@ struct halconResult_2D {
bool halconOK = false;
};
halconResult_2D HanHou2D_halconEvaluate(const cv::Mat& sourceImg,const cv::Mat& segImg, TextRendererZH* textPainter, int times,
double tongXingDuLimitHigh, double tongXingDuLimitLow, bool tongXingDuLimitEnable) {
double tongXingDuLimitHigh, double tongXingDuLimitLow, bool tongXingDuLimitEnable,
double neiYuanPianYiTongXinDuLimitHigh, double neiYuanPianYiTongXinDuLimitLow, bool neiYuanPianYiTongXinDuEnable,
double waiYuanPianYiTongXinDuLimitHigh, double waiYuanPianYiTongXinDuLimitLow, bool waiYuanPianYiTongXinDuEnable) {
halconResult_2D result;
HDevEngineCpp::HDevProcedure proc("_3_Cal_HY_CC_Distance");
@@ -253,7 +255,15 @@ halconResult_2D HanHou2D_halconEvaluate(const cv::Mat& sourceImg,const cv::Mat&
y1Text = y1Text.substr(0, y1Text.find(".") + 4);
std::string txd1Text = std::to_string(result.neiYuanTongXinDu);
txd1Text = txd1Text.substr(0, txd1Text.find(".") + 4);
textPainter->appendPaintJob("内圆偏移X:" + x1Text + "mm Y:" + y1Text + "mm 同心度" + txd1Text, cv::Point(0, 250), cv::Scalar(0, 255, 0));
if (result.neiYuanTongXinDu > neiYuanPianYiTongXinDuLimitHigh || result.neiYuanTongXinDu < neiYuanPianYiTongXinDuLimitLow) {
textPainter->appendPaintJob("内圆偏移X:" + x1Text + "mm Y:" + y1Text + "mm 同心度" + txd1Text, cv::Point(0, 250), cv::Scalar(0, 255, 0));
result.halconOK = false;
if (waiYuanPianYiTongXinDuEnable == true)
result.isNg = true;
}
else
textPainter->appendPaintJob("内圆偏移X:" + x1Text + "mm Y:" + y1Text + "mm 同心度" + txd1Text, cv::Point(0, 250), cv::Scalar(0, 255, 0));
result.waiYuanPianYi_X = OuterCircle_offset[0].D();
result.waiYuanPianYi_Y = OuterCircle_offset[1].D();
@@ -265,7 +275,14 @@ halconResult_2D HanHou2D_halconEvaluate(const cv::Mat& sourceImg,const cv::Mat&
y2Text = y2Text.substr(0, y2Text.find(".") + 4);
std::string txd2Text = std::to_string(result.waiYuanTongXinDu);
txd2Text = txd2Text.substr(0, txd2Text.find(".") + 4);
textPainter->appendPaintJob("外圆偏移X:" + x2Text + "mm Y:" + y2Text + "mm 同心度:" + txd2Text, cv::Point(0, 450), cv::Scalar(0, 255, 0));
if (result.waiYuanTongXinDu > waiYuanPianYiTongXinDuLimitHigh || result.waiYuanTongXinDu < waiYuanPianYiTongXinDuLimitLow) {
textPainter->appendPaintJob("外圆偏移X:" + x2Text + "mm Y:" + y2Text + "mm 同心度:" + txd2Text, cv::Point(0, 450), cv::Scalar(0, 0, 255));
result.halconOK = false;
if (waiYuanPianYiTongXinDuEnable == true)
result.isNg = true;
}
else
textPainter->appendPaintJob("外圆偏移X:" + x2Text + "mm Y:" + y2Text + "mm 同心度:" + txd2Text, cv::Point(0, 450), cv::Scalar(0, 255, 0));
for (int i = 0; i < out_Circle.Length() / 3; i++) {
textPainter->appendPaintJob(cv::Point(out_Circle[i * 3 + 1].D(), out_Circle[i * 3].D()), out_Circle[i * 3 + 2].D(), cv::Scalar(0, 255, 0), 15,0);
@@ -340,6 +357,17 @@ QByteArray getHanHouJianCe2DSendResult(bool isNg1,bool isNg2) {
bool HanHouJianCe2D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx_581_address address){
try
{
double tongXingDuLimitHigh = data->service->_paramSyncManager->get("焊后", "焊后同心度mm(上限)", 1.8).toDouble();
double tongXingDuLimitLow = data->service->_paramSyncManager->get("焊后", "焊后同心度mm(下限)", 0).toDouble();
bool tongXingDuLimitEnable = data->service->_paramSyncManager->get("焊后", "焊后同心度判定启用", true).toBool();
double neiYuanPianYiTongXinDuLimitHigh = data->service->_paramSyncManager->get("焊后", "内圆偏移同心度mm(上限)", 2.0).toDouble();
double neiYuanPianYiTongXinDuLimitLow = data->service->_paramSyncManager->get("焊后", "内圆偏移同心度mm(下限)", 0).toDouble();
bool neiYuanPianYiTongXinDuEnable = data->service->_paramSyncManager->get("焊后", "内圆偏移同心度判定启用", false).toBool();
double waiYuanPianYiTongXinDuLimitHigh = data->service->_paramSyncManager->get("焊后", "外圆偏移同心度mm(上限)", 1.0).toDouble();
double waiYuanPianYiTongXinDuLimitLow = data->service->_paramSyncManager->get("焊后", "外圆偏移同心度mm(下限)", 0).toDouble();
bool waiYuanPianYiTongXinDuEnable = data->service->_paramSyncManager->get("焊后", "外圆偏移同心度判定启用", false).toBool();
#pragma region 错误处理
if (data->getOriImgSize() < 2) {
@@ -414,11 +442,13 @@ bool HanHouJianCe2D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx
data->insertResultImg(PaintSum);
return true;
}
double tongXingDuLimitHigh = data->service->_paramSyncManager->get("焊后", "焊后同心度mm(上限)", 1.8).toDouble();
double tongXingDuLimitLow = data->service->_paramSyncManager->get("焊后", "焊后同心度mm(下限)", 0).toDouble();
bool tongXingDuLimitEnable = data->service->_paramSyncManager->get("焊后", "焊后同心度判定启用", true).toBool();
auto futrue1 = std::async(std::launch::async, &HanHou2D_halconEvaluate, src1, seg1Ori, &textPainter1, 0, tongXingDuLimitHigh, tongXingDuLimitLow, tongXingDuLimitEnable);
auto futrue2 = std::async(std::launch::async, &HanHou2D_halconEvaluate, src2, seg2Ori, &textPainter2, 2, tongXingDuLimitHigh, tongXingDuLimitLow, tongXingDuLimitEnable);
auto futrue1 = std::async(std::launch::async, &HanHou2D_halconEvaluate, src1, seg1Ori, &textPainter1, 0, tongXingDuLimitHigh, tongXingDuLimitLow, tongXingDuLimitEnable,
neiYuanPianYiTongXinDuLimitHigh, neiYuanPianYiTongXinDuLimitLow, neiYuanPianYiTongXinDuEnable,
waiYuanPianYiTongXinDuLimitHigh, waiYuanPianYiTongXinDuLimitLow, waiYuanPianYiTongXinDuEnable);
auto futrue2 = std::async(std::launch::async, &HanHou2D_halconEvaluate, src2, seg2Ori, &textPainter2, 2, tongXingDuLimitHigh, tongXingDuLimitLow, tongXingDuLimitEnable,
neiYuanPianYiTongXinDuLimitHigh, neiYuanPianYiTongXinDuLimitLow, neiYuanPianYiTongXinDuEnable,
waiYuanPianYiTongXinDuLimitHigh, waiYuanPianYiTongXinDuLimitLow, waiYuanPianYiTongXinDuEnable);
auto futrue3 = std::async(std::launch::async, &HanHou2D_handleAiEvaluate, data, _detParams, src1, &textPainter1, _detParams->seg_rljHanZha1, _detParams->cls_rljHanZha1);
auto futrue4 = std::async(std::launch::async, &HanHou2D_handleAiEvaluate, data, _detParams, src2, &textPainter2, _detParams->seg_rljHanZha2, _detParams->cls_rljHanZha2);
@@ -488,8 +518,8 @@ bool HanHouJianCe2D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx
data->insertClsOriginImg(hanYinClsImg);
data->service->_missionResultHandle->toBarChart(data->SNcode, defects);
textPainter1.excusePaintJobs(Paint1);
textPainter2.excusePaintJobs(Paint2);
textPainter1.executePaintJobs(Paint1);
textPainter2.executePaintJobs(Paint2);
//拼装结果图
cv::Mat PaintSum;
cv::vconcat(Paint1, Paint2, PaintSum);
@@ -525,9 +555,9 @@ bool HanHouJianCe2D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx
struct halconResult_3D {
bool isNg = false;
double hanPanGaoDu = -99;
cv::Point ellipseCenter;
double angle;
cv::Size ellipseSize;
cv::Point ellipseCenter = cv::Point(0,0);
double angle = 0;
cv::Size ellipseSize = cv::Size(0,0);
bool halconOK = false;
};
halconResult_3D HanHou3D_halconEvaluate(const cv::Mat& heightImg, const double& xResolution, const double& yResolution, const double& zResolution
@@ -542,30 +572,42 @@ halconResult_3D HanHou3D_halconEvaluate(const cv::Mat& heightImg, const double&
procedureCall.SetInputCtrlParamTuple("in_XResolution", xResolution);
procedureCall.SetInputCtrlParamTuple("in_YResolution", yResolution);
procedureCall.SetInputCtrlParamTuple("in_ZResolution", zResolution);
procedureCall.SetInputCtrlParamTuple("in_FliePath", "./halconFiles/");
procedureCall.SetInputCtrlParamTuple("in_FilePath", "./halconFiles/hanhou3D/");
procedureCall.Execute();//执行halcon程序
HalconCpp::HTuple out_Height = procedureCall.GetOutputCtrlParamTuple("out_Height");//获取输出控制类变量
HalconCpp::HTuple out_Ellipse = procedureCall.GetOutputCtrlParamTuple("out_Ellipse");//获取输出控制类变量
HalconCpp::HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量
HalconCpp::HTuple out_NGDetails = procedureCall.GetOutputCtrlParamTuple("out_NGDetails");//获取输出控制类变量
qDebug() << "testFlag0";
int flag = out_Flag.D();
if (flag == 1) {
qDebug() << "testFlag1";
double height = out_Height.D();
textPainter->appendPaintJob("焊盘高度:" + std::to_string(height), cv::Point(0, 50), cv::Scalar(0, 255, 0));
result.ellipseCenter = cv::Point(out_Ellipse[0].D(), out_Ellipse[1].D());
result.angle = out_Ellipse[2].D();
result.ellipseSize = cv::Point(out_Ellipse[3].D(), out_Ellipse[4].D());
textPainter->appendPaintJob("焊盘高度:" + std::to_string(height), cv::Point(0, 110), cv::Scalar(0, 255, 0));
qDebug() << "testFlag2";
if (out_Ellipse.Length() == 5) {
result.ellipseCenter = cv::Point(out_Ellipse[0].D(), out_Ellipse[1].D());
result.angle = out_Ellipse[2].D();
result.ellipseSize = cv::Point(out_Ellipse[3].D(), out_Ellipse[4].D());
}
else {
qDebug() << "无椭圆数据 size"<< out_Ellipse.Length();
}
qDebug() << "testFlag3";
}
else {
textPainter->appendPaintJob("算法NG:" + std::to_string(out_NGDetails[0].D()), cv::Point(10, 50), cv::Scalar(0, 0, 255));
qDebug() << "testFlag4";
textPainter->appendPaintJob("算法NG:" + gbkToUtf8(out_NGDetails.ToString().Text()), cv::Point(10, 50), cv::Scalar(0, 0, 255));
result.isNg = true;
result.halconOK = false;
qDebug() << "testFlag5";
}
return result;
}
bool HanHouJianCe3D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx_581_address address) {
try {
bool enable = data->service->_paramSyncManager->get("焊后3D", "焊后3D结果判定启用", false).toBool();;
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果
qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start";
std::vector < std::string> defects = { };
@@ -590,13 +632,13 @@ bool HanHouJianCe3D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx
cv::Mat height1 = data->getOriImg(1);//高度图1
cv::Mat src2 = data->getOriImg(2);//亮度图2
cv::Mat height2 = data->getOriImg(3);//高度图2
TextRendererZH textPainter1(src1.cols, src1.rows, 300), textPainter2(src2.cols, src2.rows, 300);
auto futrue1 = std::async(std::launch::async, &HanHou3D_halconEvaluate, height1,
TextRendererZH textPainter1(src1.cols, src1.rows, 100), textPainter2(src2.cols, src2.rows, 100);
auto result1 = HanHou3D_halconEvaluate(height1,
data->service->_paramSyncManager->get("3D相机1精度","x向精度",0.005).toDouble(),
data->service->_paramSyncManager->get("3D相机1精度", "y向精度", 0.02).toDouble(),
data->service->_paramSyncManager->get("3D相机1精度", "z向精度", 0.0008).toDouble(),
&textPainter1);
auto futrue2 = std::async(std::launch::async, &HanHou3D_halconEvaluate, height1,
auto result2 = HanHou3D_halconEvaluate(height2,
data->service->_paramSyncManager->get("3D相机2精度", "x向精度", 0.005).toDouble(),
data->service->_paramSyncManager->get("3D相机2精度", "y向精度", 0.02).toDouble(),
data->service->_paramSyncManager->get("3D相机2精度", "z向精度", 0.0008).toDouble(),
@@ -608,10 +650,16 @@ bool HanHouJianCe3D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx
cv::cvtColor(Paint1, Paint1, cv::COLOR_GRAY2BGR);
if (Paint2.channels() != 3)
cv::cvtColor(Paint2, Paint2, cv::COLOR_GRAY2BGR);
if(result1.ellipseCenter.x != 0)
cv::ellipse(Paint1, result1.ellipseCenter, result1.ellipseSize, result1.angle, 0, 360, cv::Scalar(0, 255, 0), 3);
if (result2.ellipseCenter.x != 0)
cv::ellipse(Paint2, result2.ellipseCenter, result2.ellipseSize, result2.angle, 0, 360, cv::Scalar(0, 255, 0), 3);
textPainter1.putText(Paint1, "OK", cv::Point(10, 10), cv::Scalar(0, 255, 0));
textPainter1.excusePaintJobs(Paint1);
textPainter1.executePaintJobs(Paint1);
textPainter2.putText(Paint2, "OK", cv::Point(10, 10), cv::Scalar(0, 255, 0));
textPainter1.excusePaintJobs(Paint2);
textPainter2.executePaintJobs(Paint2);
cv::vconcat(Paint1, Paint2, PaintSum);
putSnAndDetTime(PaintSum, data->SNcode, 60);
@@ -125,10 +125,9 @@ bool ALGO_maJiaReRong(std::shared_ptr <detData> data, maJiaParam* _detParams, sx
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//发送异常结果
return false;
}
bool ALGO_hanQianDingWei(std::shared_ptr <detData> data, detParams* _detParams, sx_581_address address) {
static bool ALGO_hanQianDingWei(std::shared_ptr <detData> data, detParams* _detParams, sx_581_address address) {
try {
qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start";
data->service->_triggerManager->writeShort("D100_1_1");
///////////////////取图//处理//////////////////
if (data->getOriImgSize() < 1)
{
@@ -137,6 +136,8 @@ bool ALGO_hanQianDingWei(std::shared_ptr <detData> data, detParams* _detParams,
}
auto sourceImg = data->getOriImg(0);
sourceImg = cv::imread("D:\\testImage\\601\\hanqian.bmp", -1);
QThread::msleep(200);
if (sourceImg.rows == 100) {
cv::Mat Paint;
sourceImg.copyTo(Paint);
@@ -145,31 +146,35 @@ bool ALGO_hanQianDingWei(std::shared_ptr <detData> data, detParams* _detParams,
}
cv::Mat Paint;
sourceImg.copyTo(Paint);
HDevEngineCpp::HDevProcedure proc("HQDW_Color_Inspection");
HDevEngineCpp::HDevProcedureCall procedureCall(proc);
HObject inputImage = MatToHObject(sourceImg);
HTuple in_Resolution(0.040766), in_FilePath("./halconFiles/");
double HeightLeft_jsonvlaue = data->service->_paramSyncManager->get("焊前定位", "焊前左侧Y向高度差", 2.0).toDouble();
double HeightRight_jsonvlaue = data->service->_paramSyncManager->get("焊前定位", "焊前右侧Y向高度差", 2.0).toDouble();
double SlantAngle_jsonvlaue = data->service->_paramSyncManager->get("焊前定位", "焊前盖板上下边缘膜的角度", 0.6).toDouble();
procedureCall.SetInputIconicParamObject("in_Image", inputImage);
procedureCall.SetInputCtrlParamTuple("in_Resolution", in_Resolution);
procedureCall.SetInputCtrlParamTuple("in_FilePath", in_FilePath);
procedureCall.Execute();//执行halcon程序
HTuple out_ColorType, out_Distance, make, out_SlantAngle, out_Height;;
HTuple out_ColorType, out_Distance, make;
HObject out_DisplayImage;
//out_LinePoint = procedureCall.GetOutputCtrlParamTuple("out_LinePoint");//获取输出控制类变量
out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出控制类变量
//out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle");//获取输出控制类变量
out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance");//获取输出控制类变量
out_Height = procedureCall.GetOutputCtrlParamTuple("out_Height");//获取输出控制类变量
out_SlantAngle = procedureCall.GetOutputCtrlParamTuple("out_SlantAngle");//获取输出控制类变量
make = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量
out_DisplayImage = procedureCall.GetOutputIconicParamObject("out_DisplayImage");//获取输出控制类变量
{
HDevEngineCpp::HDevProcedure proc("HQDW_Color_Inspection");
HDevEngineCpp::HDevProcedureCall procedureCall(proc);
HObject inputImage = MatToHObject(sourceImg);
HTuple in_Resolution(0.040766), in_FilePath("./halconFiles/");
double HeightLeft_jsonvlaue = data->service->_paramSyncManager->get("焊前定位", "焊前左侧Y向高度差", 2.0).toDouble();
double HeightRight_jsonvlaue = data->service->_paramSyncManager->get("焊前定位", "焊前右侧Y向高度差", 2.0).toDouble();
double SlantAngle_jsonvlaue = data->service->_paramSyncManager->get("焊前定位", "焊前盖板上下边缘膜的角度", 0.6).toDouble();
procedureCall.SetInputIconicParamObject("in_Image", inputImage);
procedureCall.SetInputCtrlParamTuple("in_Resolution", in_Resolution);
procedureCall.SetInputCtrlParamTuple("in_FilePath", in_FilePath);
procedureCall.Execute();//执行halcon程序
//out_LinePoint = procedureCall.GetOutputCtrlParamTuple("out_LinePoint");//获取输出控制类变量
out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出控制类变量
//out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle");//获取输出控制类变量
out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance");//获取输出控制类变量
//out_Height = procedureCall.GetOutputCtrlParamTuple("out_Height");//获取输出控制类变量
//out_SlantAngle = procedureCall.GetOutputCtrlParamTuple("out_SlantAngle");//获取输出控制类变量
make = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量
out_DisplayImage = procedureCall.GetOutputIconicParamObject("out_DisplayImage");//获取输出控制类变量
}
int flag = make.D();
QString tmpFlag = "1";
// Output(HTuple): out_ColorType, 1, 铜; 2,铝</c>
@@ -187,29 +192,29 @@ bool ALGO_hanQianDingWei(std::shared_ptr <detData> data, detParams* _detParams,
Paint = HObject2Mat(out_DisplayImage);
textPainter.appendPaintJob("膜上边到注液孔:" + std::to_string(out_Distance[0].D()), cv::Point(800, 50), cv::Scalar(0, 255, 0));
textPainter.appendPaintJob("膜下边到注液孔:" + std::to_string(out_Distance[1].D()), cv::Point(800, 350), cv::Scalar(0, 255, 0));
textPainter.excusePaintJobs(Paint);
if (out_Height[0].D() > HeightLeft_jsonvlaue)
textPainter.executePaintJobs(Paint);
/* if (out_Height[0].D() > HeightLeft_jsonvlaue)
{
HeightLeftFlag = 2;
textPainter.putText(Paint, "左侧Y向高度差:" + std::to_string(out_Height[0].D()), cv::Point(800, 650), cv::Scalar(0, 0, 255));
}
else
textPainter.putText(Paint, "左侧Y向高度差:" + std::to_string(out_Height[0].D()), cv::Point(800, 650), cv::Scalar(0, 255, 0));
textPainter.putText(Paint, "左侧Y向高度差:" + std::to_string(out_Height[0].D()), cv::Point(800, 650), cv::Scalar(0, 255, 0));*/
if (out_Height[1].D() > HeightRight_jsonvlaue)
{
HeightRightFlag = 2;
textPainter.putText(Paint, "右侧Y向高度差:" + std::to_string(out_Height[1].D()), cv::Point(800, 950), cv::Scalar(0, 0, 255));
}
else
textPainter.putText(Paint, "右侧Y向高度差:" + std::to_string(out_Height[1].D()), cv::Point(800, 950), cv::Scalar(0, 255, 0));
if (out_SlantAngle.D() > SlantAngle_jsonvlaue)
{
AlgelFlag = 2;
textPainter.putText(Paint, "盖板上下边缘膜的角度:" + std::to_string(out_SlantAngle.D()), cv::Point(800, 1250), cv::Scalar(0, 0, 255));
}
else
textPainter.putText(Paint, "盖板上下边缘膜的角度:" + std::to_string(out_SlantAngle.D()), cv::Point(800, 1250), cv::Scalar(0, 255, 0));
//if (out_Height[1].D() > HeightRight_jsonvlaue)
//{
// HeightRightFlag = 2;
// textPainter.putText(Paint, "右侧Y向高度差:" + std::to_string(out_Height[1].D()), cv::Point(800, 950), cv::Scalar(0, 0, 255));
//}
//else
// textPainter.putText(Paint, "右侧Y向高度差:" + std::to_string(out_Height[1].D()), cv::Point(800, 950), cv::Scalar(0, 255, 0));
//if (out_SlantAngle.D() > SlantAngle_jsonvlaue)
//{
// AlgelFlag = 2;
// textPainter.putText(Paint, "盖板上下边缘膜的角度:" + std::to_string(out_SlantAngle.D()), cv::Point(800, 1250), cv::Scalar(0, 0, 255));
//}
//else
// textPainter.putText(Paint, "盖板上下边缘膜的角度:" + std::to_string(out_SlantAngle.D()), cv::Point(800, 1250), cv::Scalar(0, 255, 0));
int left = out_ColorType[0].D();
if (left == 2)
textPainter.putText(Paint, "铜", cv::Point(0, 3100), cv::Scalar(0, 0, 255));
@@ -244,12 +249,8 @@ bool ALGO_hanQianDingWei(std::shared_ptr <detData> data, detParams* _detParams,
plcResult = "2";
}
data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//发送异常结果
if (plcResult == "2")
data->service->_missionResultHandle->toBarChart(data->SNcode, { "焊前NG" });
else
data->service->_missionResultHandle->toBarChart(data->SNcode, { });
data->service->_missionResultHandle->toBarChart(data->SNcode, { "焊前NG" + data->SNcode});
cv::resize(Paint, Paint, cv::Size(), 0.25, 0.25);
data->insertResultImg(Paint);
@@ -14,7 +14,7 @@ struct hanQianDingWeiSubresult {
double Out_Vale_L_centerUp = -1;//铝(负)极连接片中心的和上极耳水平边缘距离(mm)
double Out_Vale_L_centerDown = -1;//铝(负)极连接片中心的和下极耳水平边缘距离(mm)
double extremumValue = -1;
cv::Point circleCenter;
double radius = 1;
std::vector<double> lines;
+2 -2
View File
@@ -144,8 +144,8 @@ bool hanhou2D(std::shared_ptr <detData> data, hanHou2dParam* _detParams, sx_581_
data->service->_missionResultHandle->toBarChart(data->SNcode, defects);
futrue3.wait();
futrue4.wait();
textPainter1.excusePaintJobs(Paint1);
textPainter2.excusePaintJobs(Paint2);
textPainter1.executePaintJobs(Paint1);
textPainter2.executePaintJobs(Paint2);
cv::Mat PaintSum;
cv::vconcat(Paint1, Paint2, PaintSum);