diff --git a/include/global.h b/include/global.h index 09d8078..0ff1cfb 100644 --- a/include/global.h +++ b/include/global.h @@ -11,7 +11,7 @@ #include #pragma execution_character_set("utf-8") -const std::string softwareVersion = "20260112-2.3.6"; +const std::string softwareVersion = "20260112-2.3.7"; const std::string euiJsonVersion = "1.0.6"; #define GigaByte 1073741824 #define globalDatabasePth "./sqlDatabase/eui_db.db" //全局数据库路径 @@ -19,6 +19,8 @@ const std::string euiJsonVersion = "1.0.6"; #define saveImgEnable true//是否存储图片 #define switchToTongYongUi 1 //是否切换到通用UI界面 #define skipLogin 1 //是否跳过登录界面 +#define imgSaveTreadMaxCount 4 //最大存图线程数 +#define jsonRpcEnable false //是否启用JSON RPC服务器 #define sColor_Blue "51, 56, 69" #define sColor_BlueWithWhite "64, 68, 81" #define sColor_BlueWithBlack "46, 50, 52" diff --git a/include/opencvPaintAlgo.hpp b/include/opencvPaintAlgo.hpp index 0b4a501..02cffb7 100644 --- a/include/opencvPaintAlgo.hpp +++ b/include/opencvPaintAlgo.hpp @@ -20,7 +20,34 @@ static void Cross(cv::Mat& image, const cv::Point& center, int length, int thick cv::line(image, verticalStart, verticalEnd, color, thickness); } #pragma endregion +//画箭头 长度为负值时为反方向 +static void drawArrow(cv::Mat& Paint, const cv::Point& start, const int& length, const bool& horizonal, const cv::Scalar& color, const int& thinkess, const int& arrowSize) { + if (horizonal == true) {//线段是否水平 + cv::Point end = cv::Point(start.x + length, start.y); + cv::line(Paint, start, end, color, thinkess); + if (length > 0) {//判断方向 往右 + cv::line(Paint, end, cv::Point(end.x - arrowSize, end.y - arrowSize), color, thinkess); + cv::line(Paint, end, cv::Point(end.x - arrowSize, end.y + arrowSize), color, thinkess); + } + else { + cv::line(Paint, end, cv::Point(end.x + arrowSize, end.y - arrowSize), color, thinkess); + cv::line(Paint, end, cv::Point(end.x + arrowSize, end.y + arrowSize), color, thinkess); + } + } + else {//垂直线段 + cv::Point end = cv::Point(start.x, start.y + length); + cv::line(Paint, start, end, color, thinkess); + if (length > 0) {//判断方向 往下 + cv::line(Paint, end, cv::Point(end.x - arrowSize, end.y - arrowSize), color, thinkess); + cv::line(Paint, end, cv::Point(end.x + arrowSize, end.y - arrowSize), color, thinkess); + } + else { + cv::line(Paint, end, cv::Point(end.x - arrowSize, end.y + arrowSize), color, thinkess); + cv::line(Paint, end, cv::Point(end.x + arrowSize, end.y + arrowSize), color, thinkess); + } + } +} #pragma region 写中文 static std::wstring utf8ToWstring(const std::string& utf8Str) { int len = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0); diff --git a/include/simpleAlgo.h b/include/simpleAlgo.h index d1c69be..e8e66c7 100644 --- a/include/simpleAlgo.h +++ b/include/simpleAlgo.h @@ -39,14 +39,15 @@ static cv::Rect rectPlusRect(cv::Rect world, cv::Rect rect) } static cv::Rect findMaxAreaContour(const cv::Mat& src) { - int maxIndex = 0, maxArea = 0; + int maxIndex = 0; + double maxArea = 0; std::vector>contours; cv::findContours(src, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); if (contours.size() == 0) return cv::Rect(0, 0, 0, 0); for (int i = 0; i < contours.size(); i++) { - int Area = cv::contourArea(contours[i]); + double Area = cv::contourArea(contours[i]); if (Area > maxArea) { maxArea = Area; @@ -59,14 +60,15 @@ static cv::Rect findMaxAreaContour(const cv::Mat& src) } static cv::Rect findMaxAreaContour(const cv::Mat& src, int& indexReturn) { - int maxIndex = 0, maxArea = 0; + int maxIndex = 0; + double maxArea = 0; std::vector>contours; cv::findContours(src, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); if (contours.size() == 0) return cv::Rect(0, 0, 0, 0); for (int i = 0; i < contours.size(); i++) { - int Area = cv::contourArea(contours[i]); + double Area = cv::contourArea(contours[i]); if (Area > maxArea) { maxArea = Area; @@ -78,6 +80,7 @@ static cv::Rect findMaxAreaContour(const cv::Mat& src, int& indexReturn) indexReturn = maxIndex; return cv::boundingRect(contours[maxIndex]); } + return cv::Rect(0, 0, 0, 0); } static cv::Mat cutImg2Cls(cv::Rect boundingBox, cv::Mat imgInput, cv::Size targetSize = cv::Size(128, 128)) @@ -252,7 +255,6 @@ enum MatsToHObjectEnum }; static HalconCpp::HObject MatsToHObject(cv::Mat* img1, cv::Mat* img2, MatsToHObjectEnum type) { - auto start3 = std::chrono::high_resolution_clock::now(); HalconCpp::HObject Hobj; int height = 0; int width = 0; @@ -269,21 +271,15 @@ static HalconCpp::HObject MatsToHObject(cv::Mat* img1, cv::Mat* img2, MatsToHObj } if (img1->type() == CV_8UC1) { - unsigned char* imgData = new unsigned char[width * height]; - memcpy(imgData, img1->data, img1->rows * img1->cols); - memcpy(img1->rows * img1->cols + imgData, img2->data, img1->rows * img1->cols); - GenImage1(&Hobj, "byte", width, height, (Hlong)imgData); - delete[]imgData; - imgData = nullptr; + std::vector imgData(width * height); + memcpy(imgData.data(), img1->data, img1->rows * img1->cols); + memcpy(imgData.data() + img1->rows * img1->cols, img2->data, img1->rows * img1->cols); + GenImage1(&Hobj, "byte", width, height, (Hlong)imgData.data()); } - auto end3 = std::chrono::high_resolution_clock::now(); - auto duration3 = std::chrono::duration_cast(end3 - start3); - std::cout << "Time taken by functionxxx: " << duration3.count() << " milliseconds" << std::endl; return Hobj; } static HalconCpp::HObject MatsToHObject(cv::Mat& img1, cv::Mat& img2, MatsToHObjectEnum type) { - auto start3 = std::chrono::high_resolution_clock::now(); HalconCpp::HObject Hobj; int height = 0; int width = 0; @@ -300,29 +296,11 @@ static HalconCpp::HObject MatsToHObject(cv::Mat& img1, cv::Mat& img2, MatsToHObj } if (img1.type() == CV_8UC1) { - unsigned char* imgData = new unsigned char[width * height]; - //#pragma omp parallel for - //for (int i = 0; i < 2; i++) - //{ - // switch (i) - // { - // case 0: - // memcpy(imgData, img1.data, img1.rows * img1.cols); - // break; - // case 1: - // memcpy(img1.rows * img1.cols + imgData, img2.data, img1.rows * img1.cols); - // break; - // } - //} - memcpy(imgData, img1.data, img1.rows * img1.cols); - memcpy(img1.rows * img1.cols + imgData, img2.data, img1.rows * img1.cols); - GenImage1(&Hobj, "byte", width, height, (Hlong)imgData); - delete[]imgData; - imgData = nullptr; + std::vector imgData(width * height); + memcpy(imgData.data(), img1.data, img1.rows * img1.cols); + memcpy(imgData.data() + img1.rows * img1.cols, img2.data, img1.rows * img1.cols); + GenImage1(&Hobj, "byte", width, height, (Hlong)imgData.data()); } - auto end3 = std::chrono::high_resolution_clock::now(); - auto duration3 = std::chrono::duration_cast(end3 - start3); - std::cout << "Time taken by functionxxx: " << duration3.count() << " milliseconds" << std::endl; return Hobj; } static void MatToHObjectV(cv::Mat& image, HalconCpp::HObject* Hobj) @@ -364,26 +342,7 @@ static void MatToHObjectV(cv::Mat& image, HalconCpp::HObject* Hobj) } else if (image.type() == CV_8UC1) { - //HalconCpp::HImage himage = HalconCpp::HImage(); - - ////uchar* data = new uchar[hgt * wid]; - ////for (i = 0; i < hgt; i++) - ////{ - //// memcpy(data + wid * i, image.data + image.step * i, wid); - ////} - ////gen_image_const - //himage.GenImage1("byte", wid, hgt, image.data); - - //HalconCpp::HString tmpType; - //Hlong tmpW, tmpH; - //void* hImgPt; - //hImgPt = himage.GetImagePointer1(&tmpType, &tmpW, &tmpH); - //GenImage1(&Hobj, "byte", wid, hgt, (Hlong)hImgPt); GenImage1(Hobj, "byte", wid, hgt, (Hlong)image.data); - - /* delete[] data; - data = NULL;*/ - } else if (image.type() == CV_16UC1) { @@ -469,26 +428,7 @@ static HalconCpp::HObject MatToHObject(const cv::Mat& image) } else if (image.type() == CV_8UC1) { - //HalconCpp::HImage himage = HalconCpp::HImage(); - - ////uchar* data = new uchar[hgt * wid]; - ////for (i = 0; i < hgt; i++) - ////{ - //// memcpy(data + wid * i, image.data + image.step * i, wid); - ////} - ////gen_image_const - //himage.GenImage1("byte", wid, hgt, image.data); - - //HalconCpp::HString tmpType; - //Hlong tmpW, tmpH; - //void* hImgPt; - //hImgPt = himage.GetImagePointer1(&tmpType, &tmpW, &tmpH); - //GenImage1(&Hobj, "byte", wid, hgt, (Hlong)hImgPt); GenImage1(&Hobj, "byte", wid, hgt, (Hlong)image.data); - - /* delete[] data; - data = NULL;*/ - } else if (image.type() == CV_16UC1) { @@ -539,14 +479,15 @@ static HalconCpp::HObject MatToHObject(const cv::Mat& image) static double getDistance(cv::Point pointO, cv::Point pointA) { double distance; - distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2); - distance = sqrtf(distance); + distance = std::pow((pointO.x - pointA.x), 2) + std::pow((pointO.y - pointA.y), 2); + distance = std::sqrt(distance); return distance; } //获取点到线段之间的直线距离 static double pointToLineDistance(const cv::Point& point, const cv::Point& lineStart, const cv::Point& lineEnd) { double numerator = std::abs((lineEnd.y - lineStart.y) * point.x - (lineEnd.x - lineStart.x) * point.y + lineEnd.x * lineStart.y - lineEnd.y * lineStart.x); double denominator = std::sqrt(std::pow(lineEnd.y - lineStart.y, 2) + std::pow(lineEnd.x - lineStart.x, 2)); + if (denominator < 1e-10) return 0.0; // 防止除零 return numerator / denominator; } //计算角度,pt2为顶点 @@ -560,11 +501,14 @@ static double calculateAngle(cv::Point pt1, cv::Point pt2, cv::Point pt3) double length1 = norm(vector1); double length2 = norm(vector2); + // 防止除零 + if (length1 < 1e-10 || length2 < 1e-10) return 0.0; + // 计算两个向量的点积 double dotProduct = vector1.dot(vector2); - // 计算夹角的余弦值 - double cosAngle = dotProduct / (length1 * length2); + // 计算夹角的余弦值,限制在[-1, 1]范围内避免浮点误差 + double cosAngle = std::max(-1.0, std::min(1.0, dotProduct / (length1 * length2))); // 计算夹角的弧度 double angleRadians = acos(cosAngle); @@ -689,7 +633,7 @@ static bool isRectOverlap(const cv::Rect& rect1, const cv::Rect& rect2, double t if (thresholdPercent != 0)//如果有阈值 { int maxCnotourArea = std::max(rect1.area(), rect2.area()); - if (intersection.area() / maxCnotourArea < thresholdPercent) + if (maxCnotourArea > 0 && static_cast(intersection.area()) / maxCnotourArea < thresholdPercent) return false; } // 如果重叠区域的面积大于0,则说明两个矩形重叠 diff --git a/include/sql/qSqlBase.h b/include/sql/qSqlBase.h index bf894a5..674610f 100644 --- a/include/sql/qSqlBase.h +++ b/include/sql/qSqlBase.h @@ -451,12 +451,12 @@ private: QString dbPath; }; -class CsvWriter : public QThread { +class DataRecorder : public QThread { public: - CsvWriter(SQLiteDB* dbIn, QList>externalInitDataVec = QList>()) : db(dbIn) { + DataRecorder (SQLiteDB* dbIn, QList>externalInitDataVec = QList>()) : db(dbIn) { db_InitColumns.append(externalInitDataVec); } - ~CsvWriter() { + ~DataRecorder () { // 确保线程安全退出 if (isRunning()) { quit(); diff --git a/include/yhGlobal_601.h b/include/yhGlobal_601.h new file mode 100644 index 0000000..dc7de91 --- /dev/null +++ b/include/yhGlobal_601.h @@ -0,0 +1,303 @@ +#pragma once +#include +#include +#include +#include +#include +#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_601_address { + int triggerAddr = -1; + int snAddr = -1; + QByteArray completeAddr = "-1"; + QByteArray resultAddr = "-1"; + int valueOffsetAddr = -1; + int index = -1; +}; +static yh_601_address generateYh581Address(int startAddr, int offset) {//INPUT:开始地址/电芯地址偏移(0~3) + return yh_601_address{ + startAddr + offset * 2, + startAddr + 6 + offset * 22 , + QByteArray::number(startAddr + 54), + QByteArray::number(startAddr + 56 + offset * 2), + startAddr + 60 + offset * 20, + offset + }; + +} +static std::map generateYh581AddressMap(int startAddr, int cnt) {//INPUT:开始地址/0~3) 数量 + std::map 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 data, yh_601_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 data, detParams* _detParams, yh_601_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 +//此类适用于单相机多触发地址需要联合判断的情况的情况 比如顶盖焊,包膜,入壳机台 +//例触发地址有4个,输入信号为 1 0 0 1 则触发1和4的地址拍照检测,2和3拍照取图并废弃 +class _581_Union_triggerTemplate { +public: + paramTemplte* _detParams; + detCallbackChain* generalDet; + std::string cameraName; + QString viewerName; + std::mapaddress; + int oneTriggerCaptrueTimes = 1; + /// + /// 初始化 + /// + /// 相机名 + /// 窗口名 + /// 开始地址 + /// 触发信号数 + /// 单次触发调用几次相机模块 + /// 参数输入 + /// 默认 + /// 默认 + /// 算法函数 + /// + void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount,int oneTriggerCaptrueTimesIN, + paramTemplte* detParamsIn, ServiceManager* _serviceManagerIn, bSignalHub* bridgeIn, + typename detCallbackChain::processAlgoCallback _processAlgoCallback, + QString saveObjectNameIN = "") { + viewerName = viewerNameIN; + cameraName = cameraNameIn; + _serviceManager = _serviceManagerIn; + _detParams = detParamsIn; + bridge = bridgeIn; + oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN; + + saveObjectName = saveObjectNameIN; + generalDet = new detCallbackChain(_serviceManager, _detParams, bridge); + generalDet->registerProcessAlgoCallback(_processAlgoCallback); + address = generateYh581AddressMap(startAddr, triggerCount); + //联合触发器条件 + std::vector> 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> 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, false, -1); + auto camera = _serviceManager->_cameraManager->getCamera(cameraName); + camera->clearCache(); + std::shared_ptr 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位 + } + //获取图片然后废弃 + void captrueAndDiscard(int batteryOffset, QByteArray& byteArray) { + std::string sn = _serviceManager->_triggerManager->readSnFromQByteArray(byteArray, address[batteryOffset].snAddr, false, false, -1); + auto camera = _serviceManager->_cameraManager->getCamera(cameraName); + std::shared_ptr 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 + "_4");//发个4防止报警 + } +private: + QString saveObjectName = ""; + bSignalHub* bridge; + ServiceManager* _serviceManager = nullptr; +}; + +template +//此类适用于单相机多触发地址单次判断的情况,比如密封钉,三协机台 +//例触发地址有4个,输入信号为 1 0 0 1 则按顺序触发1和4的地址拍照检测,2和3不做处理 +class _581_Single_triggerTemplate { +public: + paramTemplte2* _detParams; + detCallbackChain* generalDet; + std::string cameraName; + QString viewerName; + std::mapaddress; + int oneTriggerCaptrueTimes = 1; + /// + /// 初始化 + /// + /// 相机名 + /// 窗口名 + /// 开始地址 + /// 触发信号数 + /// 单次触发调用几次相机模块 + /// 参数输入 + /// 默认 + /// 默认 + /// 算法函数 + /// + void init(std::string cameraNameIn, QString viewerNameIN, int startAddr, int triggerCount, int oneTriggerCaptrueTimesIN, + paramTemplte2* detParamsIn, ServiceManager* _serviceManagerIn, bSignalHub* bridgeIn, + typename detCallbackChain::processAlgoCallback _processAlgoCallback, + QString saveObjectNameIN = "") { + viewerName = viewerNameIN; + cameraName = cameraNameIn; + _serviceManager = _serviceManagerIn; + _detParams = detParamsIn; + bridge = bridgeIn; + oneTriggerCaptrueTimes = oneTriggerCaptrueTimesIN; + + saveObjectName = saveObjectNameIN; + generalDet = new detCallbackChain(_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, false, -1); + auto camera = _serviceManager->_cameraManager->getCamera(cameraName); + camera->clearCache(); + std::shared_ptr 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[batteryOffset].completeAddr + "_1");//完成信号 根据偏移发送 + } +private: + QString saveObjectName = ""; + bSignalHub* bridge; + ServiceManager* _serviceManager = nullptr; +}; \ No newline at end of file diff --git a/rpcModule/rpc_finsTcp_boost_V2/CMakeLists.txt b/rpcModule/rpc_finsTcp_boost_V2/CMakeLists.txt new file mode 100644 index 0000000..c7632c9 --- /dev/null +++ b/rpcModule/rpc_finsTcp_boost_V2/CMakeLists.txt @@ -0,0 +1,70 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "basler" "opencv") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) + + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC OFF) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "./*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt5::Network + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " model end : " ${CURRENT_FOLDER}:${RUN_TIME}) diff --git a/rpcModule/rpc_finsTcp_boost_V2/json_rpc_server_1_1_3.exe b/rpcModule/rpc_finsTcp_boost_V2/json_rpc_server_1_1_3.exe new file mode 100644 index 0000000..d312cb4 Binary files /dev/null and b/rpcModule/rpc_finsTcp_boost_V2/json_rpc_server_1_1_3.exe differ diff --git a/rpcModule/rpc_finsTcp_boost_V2/readme.txt b/rpcModule/rpc_finsTcp_boost_V2/readme.txt new file mode 100644 index 0000000..515447d --- /dev/null +++ b/rpcModule/rpc_finsTcp_boost_V2/readme.txt @@ -0,0 +1,3 @@ +1.初始化语句修改 +init_192.168.1.101_9600_3 + [ IP ][端口][线程数,最多三个] \ No newline at end of file diff --git a/rpcModule/rpc_finsTcp_boost_V2/rpc_finsTcp.cpp b/rpcModule/rpc_finsTcp_boost_V2/rpc_finsTcp.cpp new file mode 100644 index 0000000..557e715 --- /dev/null +++ b/rpcModule/rpc_finsTcp_boost_V2/rpc_finsTcp.cpp @@ -0,0 +1,483 @@ +#include "rpc_finsTcp.h" +#include "qprocess.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static QProcess* process = nullptr; +static HANDLE jobHandle = nullptr; +rpc_finsTcp* create(){ + qDebug() << "rpc_finsTcp create success!"; + return new rpc_finsTcp; +} + +void destory(rpc_finsTcp* ptr){ + + if (ptr) + { + delete ptr; + ptr = nullptr; + } + qDebug() << " rpc_finsTcp destory success!"; +} + +rpc_finsTcp::rpc_finsTcp(){ + +} + +rpc_finsTcp::~rpc_finsTcp() { + + for (auto& client : write_JsonRpcClients) { + if (client.first) { + // 断开所有信号槽连接 + client.first->disconnect(); + + if (client.first->isRunning()) { + client.first->quit(); + if (!client.first->wait(1000)) { + qWarning() << "subThread quit timeout!"; + } + } + // 如果 subThread 没有 parent,则需要手动 delete + //if (!subThread->parent()) { + // delete subThread; + //} + //subThread = nullptr; + } + if (client.second) { + delete client.second; + client.second = nullptr; + } + } + if (hearBeatThread) { + // 断开所有信号槽连接 + hearBeatThread->disconnect(); + + if (hearBeatThread->isRunning()) { + hearBeatThread->quit(); + if (!hearBeatThread->wait(1000)) { + qWarning() << "subThread quit timeout!"; + } + } + // 如果 subThread 没有 parent,则需要手动 delete + //if (!subThread->parent()) { + // delete subThread; + //} + //subThread = nullptr; + } + if (hearBeatClinet) { + delete hearBeatClinet; + hearBeatClinet = nullptr; + } + qDebug() << " ~rpc_finsTcp success!"; +} +QQueue readDataQueue; +// 从类中读数据到实例对象 +QByteArray variantListToByteArray(const QVariant& var) { + QByteArray byteArray; + + if (var.canConvert()) { + QVariantList list = var.toList(); + byteArray.reserve(list.size()); + + for (const QVariant& item : list) { + // 每个元素转为 uchar 存入 QByteArray + byteArray.append(static_cast(item.toInt())); + } + } + + return byteArray; +} +bool rpc_finsTcp::readData(std::vector& vec_mat, QByteArray& data){ + JsonRpcClient* ptr = read_JsonRpcClient[data]; + if(ptr == nullptr) { + ptr = new JsonRpcClient("127.0.0.1", 9000); + ptr->writeCall("init", QJsonArray{ m_IP,m_port }, "finstcp_read"); + read_JsonRpcClient[data] = ptr; + } + QByteArray resp = ptr->readCall("excuteCli", QString(data), "finstcp_read"); + data = resp; // 已是解码后的原始字节 + return true; +} +bool rpc_finsTcp::writeData(std::vector& vec_mat, QByteArray& data) { + QList m_list = data.split('_'); + if (m_list.size() < 4) + { + qCritical() << data + " m_list.size() != 4;command err"; + return false; + } + QString commond = m_list.at(0); + if (commond == "init") { + m_IP = m_list.at(1); + m_port = m_list.at(2).toInt(); + threadCount = std::min(std::max(m_list.at(3).toInt(),1), 3); + } + else if (data.contains("read")) { + readDataQueue.append(data); + } + else { + if (data.contains("null")) + return true; + if (data.contains("Heart") == true) {//专门的发送心跳线程去发送此数据 + auto request = packageWriteRequest("excuteCli", QJsonArray{ QString(data) }, finsWrite); + emit writeCallSignal(request.requestByte, request.id,data, -1); + return true; + } + //检查是不是复数命令 + QList commands = data.split('#'); + auto request = packageWriteRequest("excuteCli", QJsonArray{ QString(data) }, finsWrite); + emit writeCallSignal(request.requestByte, request.id, data, request.threadId); + + // + } + return true; +} + + +void startProcess(const QString& exePath,bool enableLog = false) {//注意:日志文件很大 + if (process) return; // 避免重复启动 + + process = new QProcess(); + process->setProgram(exePath); + if (enableLog)process->setArguments({ "-l" }); + process->start(); + + if (!process->waitForStarted(1000)) { + qDebug() << "Process failed to start."; + delete process; + process = nullptr; + return; + } + + DWORD pid = process->processId(); + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + + jobHandle = CreateJobObject(nullptr, nullptr); + if (jobHandle == nullptr) { + qDebug() << "Failed to create job object"; + return; + } + + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + SetInformationJobObject(jobHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); + + if (!AssignProcessToJobObject(jobHandle, hProcess)) { + qDebug() << "Failed to assign process to job object"; + } + + CloseHandle(hProcess); +} + +void stopProcess() { + if (process) { + if (process->state() == QProcess::Running) { + process->kill(); + process->waitForFinished(500); + } + delete process; + process = nullptr; + } + + if (jobHandle) { + CloseHandle(jobHandle); + jobHandle = nullptr; + } +} + +void rpc_finsTcp::initClientAndThread(std::pair& pairData,const int& i) { + pairData.first = new QThread(); + pairData.second = new JsonRpcClientWorker(i); + pairData.second->moveToThread(pairData.first); + + QObject::connect(this, &rpc_finsTcp::initRpcClient, + pairData.second, &JsonRpcClientWorker::initClient, Qt::QueuedConnection); + + QObject::connect(this, &rpc_finsTcp::writeCallSignal, + pairData.second, &JsonRpcClientWorker::writeCallSlot, Qt::QueuedConnection); + pairData.first->start(); + + while (pairData.second->connection == None) + QThread::msleep(1); + + if (pairData.second->connection == Disconnected) { + qDebug() << "JsonRpcClientSubThread connection failed! threadId" << i; + } + else if (pairData.second->connection == Connected) { + qDebug() << "JsonRpcClientSubThread connected successfully! threadId" << i; + } +} +void rpc_finsTcp::initHearBeatThread() { + hearBeatThread = new QThread(); + hearBeatClinet = new JsonRpcClientWorker(-1); + hearBeatClinet->moveToThread(hearBeatThread); + + QObject::connect(this, &rpc_finsTcp::initRpcClient, + hearBeatClinet, &JsonRpcClientWorker::initClient, Qt::QueuedConnection); + + QObject::connect(this, &rpc_finsTcp::writeCallSignal, + hearBeatClinet, &JsonRpcClientWorker::writeCallSlot, Qt::QueuedConnection); + hearBeatThread->start(); + while (hearBeatClinet->connection == None) + QThread::msleep(1); + + if (hearBeatClinet->connection == Disconnected) { + qDebug() << "JsonRpcClientSubThread connection failed! heartBeatThread"; + } + else if (hearBeatClinet->connection == Connected) { + qDebug() << "JsonRpcClientSubThread connected successfully! threadId heartBeatThread"; + } +} + +bool rpc_finsTcp::initParas(QByteArray& data){ + startProcess("./json_rpc_server_1_1_3.exe"); + QThread::msleep(500); + write_JsonRpcClients = std::vector>(threadCount); + for (int i = 0; i < write_JsonRpcClients.size(); i++) { + initClientAndThread(write_JsonRpcClients[i],i); + } + //心跳线程 + initHearBeatThread(); + //qDebug() << "返回结果:" << result; + emit initRpcClient(); + for (int i = 0; i < threadCount; i++) { + auto request = packageWriteRequest("init", QJsonArray{ m_IP,m_port }, packageType::finsWrite_1 + i); + emit writeCallSignal(request.requestByte, request.id, "init", -1); + } + return true; + +} + +bool rpc_finsTcp::run(){ + // 没有用到 + //qDebug() << "[info] " << __FUNCTION__ << " line:" << __LINE__ << " success!"; + return true; +} + + +JsonRpcClient::JsonRpcClient(const QString& host, quint16 port) + :host_(host), port_(port), idCounter_(1) { + + socket_.connectToHost(host_, port_); + if (!socket_.waitForConnected(3000)) { + qWarning() << "[JsonRpcClient] Initial connection failed:" << socket_.errorString(); + _connectionStatus = Disconnected; + } + else { + qDebug() << "[JsonRpcClient] Connected to" << host_ << ":" << port_; + _connectionStatus = Connected; + } +} + +bool JsonRpcClient::reconnect() { + if (socket_.state() == QAbstractSocket::ConnectedState) { + return true; + } + + socket_.abort(); // 清理旧连接 + socket_.connectToHost(host_, port_); + if (socket_.waitForConnected(3000)) { + qDebug() << "[JsonRpcClient] Reconnected successfully."; + return true; + } + else { + qWarning() << "[JsonRpcClient] Reconnection failed:" << socket_.errorString(); + return false; + } +} +QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module){ + QMutexLocker locker(&mutex_); + if (socket_.state() != QAbstractSocket::ConnectedState) { + if (!reconnect()) return QVariant(); + } + int myId = idCounter_++; + QJsonObject req{ + {"jsonrpc", "2.0"}, + {"method", method}, + {"params", params}, + {"id", myId} + }; + if (!module.isEmpty()) req.insert("module", module); + + QJsonObject resp = sendRequestBuildAndAwait(req); + if (resp.contains("error")) { + qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(resp["error"].toObject()).toJson(QJsonDocument::Compact); + return QVariant(); + } + if (!resp.contains("result")) return QVariant(); + QJsonValue r = resp.value("result"); + if (r.isString()) return r.toString(); + if (r.isDouble()) return r.toDouble(); + if (r.isBool()) return r.toBool(); + if (r.isArray()) return r.toArray().toVariantList(); + if (r.isObject()) return r.toObject().toVariantMap(); + return QVariant(); +} + +QByteArray JsonRpcClient::readCall(const QString& method, const QString& params, const QString& module) { + auto commands = params.split("_"); + QMutexLocker locker(&mutex_); + if (socket_.state() != QAbstractSocket::ConnectedState) { + if (!reconnect()) return QByteArray(); + } + int myId = idCounter_++; + QJsonArray p; p.append(params); + QJsonObject req{{"jsonrpc","2.0"},{"method",method},{"params",p},{"id",myId}}; + if (!module.isEmpty()) req.insert("module", module); + + QJsonDocument doc(req); + QByteArray payload = doc.toJson(QJsonDocument::Compact); + if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) { + qWarning() << "[JsonRpcClient] Write failed."; + return QByteArray(); + } + + QJsonObject respObj; + if (!waitAndReadResponse(myId, respObj)) { + qWarning() << "[JsonRpcClient] Read timeout or parse error."; + return QByteArray(); + } + QString b64 = respObj.value("result").toString(); + QByteArray decoded = QByteArray::fromBase64(b64.toUtf8()); + if (b64.contains("error") || decoded.size()% commands[3].toInt() != 0) { + qWarning() << "[ERROR]" << b64; + QThread::msleep(500); + return b64.toUtf8(); + } + return decoded; +} + +QList JsonRpcClient::extractJsonFrames(QByteArray& buffer) { + QList frames; + int start = -1; + int braceDepth = 0; + bool inString = false; + char prev = 0; + for (int i = 0; i < buffer.size(); ++i) { + char c = buffer[i]; + if (c == '"' && prev != '\\') inString = !inString; + if (!inString) { + if (c == '{') { + if (braceDepth == 0) start = i; + braceDepth++; + } else if (c == '}') { + braceDepth--; + if (braceDepth == 0 && start != -1) { + int len = i - start + 1; + frames.append(buffer.mid(start, len)); + start = -1; + } + } + } + prev = c; + } + if (braceDepth == 0) { + if (!frames.isEmpty()) { + int lastEnd = buffer.lastIndexOf('}'); + if (lastEnd != -1) buffer = buffer.mid(lastEnd + 1); + } + } else { + if (start > 0) buffer = buffer.mid(start); + } + return frames; +} + +bool JsonRpcClient::waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs) { + QElapsedTimer timer; timer.start(); + while (timer.elapsed() < timeoutMs) { + if (socket_.bytesAvailable() == 0) { + int remain = timeoutMs - (int)timer.elapsed(); + if (!socket_.waitForReadyRead(qMin(remain, 1000))) { + continue; + } + } + QByteArray chunk = socket_.readAll(); + if (!chunk.isEmpty()) recvBuffer_.append(chunk); + auto frames = extractJsonFrames(recvBuffer_); + for (const QByteArray& f : frames) { + QJsonParseError perr; + QJsonDocument jd = QJsonDocument::fromJson(f, &perr); + if (perr.error != QJsonParseError::NoError) { + qWarning() << "[JsonRpcClient] parse frame error:" << perr.errorString(); + continue; + } + if (jd.isArray()) { + for (const QJsonValue& v : jd.array()) { + if (!v.isObject()) continue; + QJsonObject obj = v.toObject(); + if (obj.value("id").toInt() == expectId) { outResp = obj; return true; } + } + } else if (jd.isObject()) { + QJsonObject obj = jd.object(); + if (obj.value("id").toInt() == expectId) { outResp = obj; return true; } + } + } + } + return false; +} + +QJsonObject JsonRpcClient::sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs) { + QByteArray payload = QJsonDocument(req).toJson(QJsonDocument::Compact); + int id = req.value("id").toInt(); + if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) { + return QJsonObject{{"error", QJsonObject{{"code", -1},{"message", "write failed"}}}}; + } + QJsonObject resp; + if (!waitAndReadResponse(id, resp, timeoutMs)) { + return QJsonObject{{"error", QJsonObject{{"code", -2},{"message", "timeout"}}}}; + } + return resp; +} + +void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) { + call(method, params, module); +} + +void JsonRpcClient::writeCall(const QByteArray& requestByte, const int& id) { + QMutexLocker locker(&mutex_); + if (socket_.state() != QAbstractSocket::ConnectedState) { + if (!reconnect()) { + qWarning() << "write failure: no connnection"; + return; + } + } + + QJsonObject resp; + if (socket_.write(requestByte) == -1 || !socket_.waitForBytesWritten(1000)) { + qWarning() << "write failure: failed"; + resp = QJsonObject{ {"error", QJsonObject{{"code", -1},{"message", "write failed"}}} }; + return; + } + + if (!waitAndReadResponse(id, resp, 8000)) { + qWarning() << "write failure: no response"; + return; + } + if (resp.contains("error")) { + qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(resp["error"].toObject()).toJson(QJsonDocument::Compact); + return; + } + return; +} \ No newline at end of file diff --git a/rpcModule/rpc_finsTcp_boost_V2/rpc_finsTcp.h b/rpcModule/rpc_finsTcp_boost_V2/rpc_finsTcp.h new file mode 100644 index 0000000..0883e0b --- /dev/null +++ b/rpcModule/rpc_finsTcp_boost_V2/rpc_finsTcp.h @@ -0,0 +1,177 @@ +#ifndef rpc_finsTcp_H +#define rpc_finsTcp_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +struct jsonRpcRequest { + QByteArray requestByte; + int id, threadId; +}; +enum connectionStatus { + None, + Disconnected, + Connected +}; +class JsonRpcClient : public QObject { + Q_OBJECT +public: + connectionStatus _connectionStatus = None; + JsonRpcClient(const QString& host = "127.0.0.1", quint16 port = 9000); + void writeCall(const QString& method, const QJsonArray& params = {}, const QString& module = QString()); + void writeCall(const QByteArray& requestByte, const int& id); + QVariant call(const QString& method, const QJsonArray& params = {}, const QString& module = QString()); + QByteArray readCall(const QString& method, const QString& params = "", const QString& module = QString()); + bool reconnect(); // 主动重连,或 call() 失败时调用 +private: + // 解析累计缓冲中的完整 JSON 帧(可能存在粘包/拆包) + QList extractJsonFrames(QByteArray& buffer); + bool waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs = 8000); + QJsonObject sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs = 8000); + QMutex mutex_; // 确保线程安全 + QTcpSocket socket_; + QString host_; + quint16 port_; + std::atomic idCounter_; + QByteArray recvBuffer_; // 累计接收缓冲 +}; +class JsonRpcClientWorker : public QObject { + Q_OBJECT +public: + connectionStatus connection; + QQueue readDataQueue; + JsonRpcClientWorker(const int& threadIdIn):threadId(threadIdIn){ + + } +public slots: + void initClient() { + _JsonRpcClient = new JsonRpcClient(); + connection = _JsonRpcClient->_connectionStatus; + } + // void writeCallSlot(const QString& method, const QJsonArray& params, const QString& module = QString(),const int& threadIndex = -1) { + // if (_JsonRpcClient && threadId == threadIndex) { + // if (threadId != -1)qDebug() << params << threadId; + // _JsonRpcClient->call(method, params, module); + // } + //} + void writeCallSlot(const QByteArray& requestByte,const int& id, const QString& logString,const int& threadIndex = -1) { + if (_JsonRpcClient && threadId == threadIndex) { + if (threadId != -1)qDebug() << logString << threadId; + _JsonRpcClient->writeCall(requestByte,id); + } + } +private: + int threadId = 0; + JsonRpcClient* _JsonRpcClient = nullptr; +}; +class rpc_finsTcp :public rpcModuleBase +{ + Q_OBJECT +public: + rpc_finsTcp(); + virtual ~rpc_finsTcp(); + bool readData(std::vector&, QByteArray&);// readData将PLC读取或者发送的返回值发回给主线程,通过全局变量的方式逐条发送 + bool writeData(std::vector&, QByteArray&);// writeData调用PLC的收发,将需要的数据发给寄存器,返回OK/NG + bool initParas(QByteArray&); + bool run(); +signals: + void initRpcClient(); + void writeCallSignal(const QByteArray& requestByte, const int& id, const QString& logString, const int& threadId); + //void writeCallSignal(const QString& method, const QJsonArray& params, const QString& module,const int& threadId); +private: + void initHearBeatThread(); + void initClientAndThread(std::pair&, const int& i); + QMutex mutex; + QMap read_JsonRpcClient; // 存储多个 JsonRpcClient 实例 + std::vector> write_JsonRpcClients; + + JsonRpcClientWorker* hearBeatClinet; + QThread* hearBeatThread; + + QString m_IP; + int m_port,threadCount = 1; + QQueue readDataQueue; + //预打包数据 + std::atomic threadUseIndex; + std::atomic idCounter; + QMutex threadUseCacheMutex; + QMap threadUseCaCheMap; + enum packageType { + finsRead = 0, + finsWrite = 1, + finsWrite_1 = 2, + finsWrite_2 = 3, + finsWrite_3 = 4 + }; + jsonRpcRequest packageWriteRequest(const QString& method, const QJsonArray& params = {}, const int& type = 0) { + jsonRpcRequest request; + int myId = idCounter++; + { + QMutexLocker locker(&threadUseCacheMutex); + std::thread::id currentThreadId = std::this_thread::get_id(); + if (threadUseCaCheMap.contains(currentThreadId)) { + request.threadId = threadUseCaCheMap[currentThreadId]; + } + else { + request.threadId = threadUseIndex++; + if (threadUseIndex >= threadCount) threadUseIndex = 0; + threadUseCaCheMap[currentThreadId] = request.threadId; + } + } + QJsonObject req{ + {"jsonrpc", "2.0"}, + {"method", method}, + {"params", params}, + {"id", myId} + }; + switch (type) + { + case finsRead: + req.insert("module", "finstcp_read"); + break; + case finsWrite: + req.insert("module", "finstcp_write_" + QString::number(request.threadId + 1)); + break; + case finsWrite_1: + req.insert("module", "finstcp_write_1"); + break; + case finsWrite_2 : + req.insert("module", "finstcp_write_2"); + break; + case finsWrite_3 : + req.insert("module", "finstcp_write_3"); + break; + } + + request.requestByte = QJsonDocument(req).toJson(QJsonDocument::Compact); + request.id = myId; + return request; + } +}; +#pragma once + + +extern "C" +{ +Q_DECL_EXPORT rpc_finsTcp * create(); +Q_DECL_EXPORT void destory(rpc_finsTcp * ptr); +} + +#endif // rpc_finsTcp_H diff --git a/src/Core/backendInterface.cpp b/src/Core/backendInterface.cpp index 55341a6..b2d220c 100644 --- a/src/Core/backendInterface.cpp +++ b/src/Core/backendInterface.cpp @@ -25,13 +25,13 @@ void Backend::init(SQLiteDB* db, nlohmann::ordered_json& json) { externalInitDataVec.append(std::make_pair(QString::fromStdString(it.key()), QString::fromStdString(it.value().dump()))); } } - _csvWriter = new CsvWriter(sqlDatabase, externalInitDataVec); + _dataRecorder = new DataRecorder(sqlDatabase, externalInitDataVec); _serviceManager._detDataManager = new detDataManager(); - _missionResultHandle = new missionResultHandle(&_signalHub, _csvWriter); + _missionResultHandle = new missionResultHandle(&_signalHub, _dataRecorder); _serviceManager._missionResultHandle = _missionResultHandle; _serviceManager.dataBase = sqlDatabase; - _serviceManager._csvWriter = _csvWriter; + _serviceManager._dataRecorder = _dataRecorder; _serviceManager._paramSyncManager = _paramSyncManager; //CLI 只在首次初始化创建 //connect(bridge, &bSignalHub::restartInit, this, &Backend::restartInit); @@ -75,7 +75,17 @@ void Backend::run() { ); _cliManager->initBasicPreset(_missionLoader.getmission(backendJson["missionDllPath"])); _serviceManager._detDataManager->setTriggerManager(_serviceManager._triggerManager); - initJsonRpc(); +#if jsonRpcEnable + _rpcServer.registerMethod(QStringLiteral("reloadConfig"), [this](const nlohmann::json&) -> nlohmann::json { + _cliManager->cliCommand("reloadConfig"); + std::cout << "接收到远程命令->重新加载配置文件" << std::endl; + return nlohmann::json{ + {"result", "OK"} + }; + }); + // 检查服务器启动结果 + _rpcServer.start(2367); +#endif emit _signalHub.initResult(InitOK); } else { @@ -98,18 +108,6 @@ void Backend::restartInit() { qDebug() << "detProcess already running, init refreshed. run() should handle reloading if needed."; } } -void Backend::initJsonRpc() { - _rpcServer.registerMethod(QStringLiteral("reloadConfig"), [this](const nlohmann::json&) -> nlohmann::json { - _cliManager->cliCommand("reloadConfig"); - std::cout << "接收到远程命令->重新加载配置文件" << std::endl; - return nlohmann::json{ - {"result", "OK"} - }; - }); - // 检查服务器启动结果 - _rpcServer.start(2367); -} - bool Backend::waitrForInitResult(serviceModule* ptr, int overtimeS) { int overTimeMs = overtimeS * 1000; diff --git a/src/core/backendInterface.h b/src/core/backendInterface.h index ee6747f..238806a 100644 --- a/src/core/backendInterface.h +++ b/src/core/backendInterface.h @@ -12,13 +12,14 @@ #include class Backend : public IBackend { public: - CsvWriter* _csvWriter = nullptr; + DataRecorder* _dataRecorder = nullptr; missionResultHandle* _missionResultHandle = nullptr; ServiceManager _serviceManager; paramSyncManager* _paramSyncManager = nullptr;//供客户在UI修改/查看 CLIManager* _cliManager; // 命令行接口管理器 +#if jsonRpcEnable rpc::JsonRpcServer _rpcServer; - +#endif ~Backend(); //重新初始化时禁止调用此函数 void init(SQLiteDB* db, nlohmann::ordered_json& json) override; @@ -52,9 +53,7 @@ public: } bool waitrForInitResult(serviceModule* ptr, int overtimeS = 999999); - - // 初始化RPC服务器 - void initJsonRpc(); + nlohmann::ordered_json getBackendJson() { backendJson["missionSettings"] = _paramSyncManager->toJson(); return backendJson; diff --git a/src/core/service/CLIManager.h b/src/core/service/CLIManager.h index 703c19a..bd689a0 100644 --- a/src/core/service/CLIManager.h +++ b/src/core/service/CLIManager.h @@ -4,24 +4,6 @@ #include #include -//class algoManager { -//public: -// void registerAlgo(const std::string& algoName, std::function, handleAiModelManager*)> algoFunc) { -// algoMap[algoName] = algoFunc; -// } -// void lstAlgos() const { -// if(algoMap.empty()) { -// std::cout << "No algorithms registered." << std::endl; -// return; -// } -// for (const auto& algo : algoMap) { -// std::cout << "Algorithm: " << algo.first << std::endl; -// } -// } -//private: -// std::unordered_map,handleAiModelManager*)>> algoMap; -//}; - class CLIManager { public: CLIManager(ServiceManager* _serviceManagerIn,bSignalHub* bridgeIn) diff --git a/src/core/service/detCallbackChain.hpp b/src/core/service/detCallbackChain.hpp index 0580fb8..287a524 100644 --- a/src/core/service/detCallbackChain.hpp +++ b/src/core/service/detCallbackChain.hpp @@ -17,10 +17,9 @@ public: : _imgSaveThreadManager(_ServiceManagerIn->_imgSaveThreadManager), _handleAiModels(_customTemplateIn), _triggerManager(_ServiceManagerIn->_triggerManager), - bridge(bridgeIn), _serviceManager(_ServiceManagerIn) - { + bridge(bridgeIn), _serviceManager(_ServiceManagerIn){ - int threadCount = 10 * QThread::idealThreadCount(); + int threadCount = 4 * QThread::idealThreadCount(); QThreadPool::globalInstance()->setMaxThreadCount(threadCount); } @@ -36,33 +35,55 @@ public: } //阻塞启动检测 void process(std::shared_ptr data, addressTemplate address, QByteArray completeSignal = "") { - data->service = _serviceManager; - while (data->getOriImgSize() < data->imgAmountMin) { - QThread::msleep(10); - } - if(completeSignal != "") - _triggerManager->writeShort(completeSignal); - //等待图片满足要求后,储存原图,异步执行算法函数 - qDebug() << "Algo start with UUID:" << data->uuid; - auto resultData = algoEvaluate(data, _handleAiModels, address); - // 确保线程安全退出 - qDebug() << "Processing finished for data with UUID:" << data->uuid; - if (data->getResultImgSize() > 0) { - - for (int i = 0; i < data->getResultImgSize() && i < data->resultImgShowSet.size(); i++) { - auto pack = data->resultImgShowSet[std::min(i, (int)data->resultImgShowSet.size() - 1)]; - cv::Mat img = data->getResultImg(i); - int resizeRate = qMax(img.cols / uiShowImgCompressThreshold, img.rows / uiShowImgCompressThreshold) ; - resizeRate = std::pow(2, resizeRate); - if (resizeRate > 1) { - cv::resize(img, pack.img, cv::Size(img.cols / resizeRate, img.rows / resizeRate), 0, 0, cv::INTER_AREA); + try { + data->service = _serviceManager; + while (data->getOriImgSize() < data->imgAmountMin) { + QThread::msleep(10); + } + if (completeSignal != "") + _triggerManager->writeShort(completeSignal); + //等待图片满足要求后,储存原图,异步执行算法函数 + qDebug() << "Algo start with UUID:" << data->uuid; + auto resultData = algoEvaluate(data, _handleAiModels, address); + // 确保线程安全退出 + qDebug() << "Algo finished with UUID:" << data->uuid; + //结果图过大时压缩显示 + if (data->getResultImgSize() > 0) { + + for (int i = 0; i < data->getResultImgSize() && i < data->resultImgShowSet.size(); i++) { + auto pack = data->resultImgShowSet[std::min(i, (int)data->resultImgShowSet.size() - 1)]; + cv::Mat img = data->getResultImg(i); + int resizeRate = qMax(img.cols / uiShowImgCompressThreshold, img.rows / uiShowImgCompressThreshold); + resizeRate = std::pow(2, resizeRate); + if (resizeRate > 1) { + cv::resize(img, pack.img, cv::Size(img.cols / resizeRate, img.rows / resizeRate), 0, 0, cv::INTER_AREA); + } + else + img.copyTo(pack.img); + emit bridge->displayWidget_sendImg(pack); } - else - img.copyTo(pack.img); - emit bridge->displayWidget_sendImg(pack); - } + } + //统一结果处理 + resultHandle(data); } - resultHandle(data); + catch (HDevEngineCpp::HDevEngineException& ex) { + + qCritical() << "detChain catched->HDevEngineException: " << ex.Message(); + } + catch (HalconCpp::HException& ex) { + + qCritical() << "detChain catched->Halcon Exception Caught!"; + qCritical() << "detChain catched->Error Code: " << ex.ErrorCode(); + qCritical() << "detChain catched->Error Message: " << ex.ErrorMessage(); + } + catch (const std::exception& e) { + + qCritical() << "detChain catched->Caught exception: " << e.what(); + } + catch (...) { + qCritical() << "detChain catched->Caught exception: unexcepted"; + } + qDebug() << "detChain processing completed for UUID:" << data->uuid; } bool algoEvaluate(std::shared_ptr data, customTemplate* customTemplate, addressTemplate address = addressTemplate()) { @@ -73,20 +94,20 @@ public: } catch (HDevEngineCpp::HDevEngineException& ex) { - qCritical() << "detChain catched->HDevEngineException: " << ex.Message(); + qCritical() << "detChainAlgo catched->HDevEngineException: " << ex.Message(); } catch (HalconCpp::HException& ex) { - qCritical() << "detChain catched->Halcon Exception Caught!"; - qCritical() << "detChain catched->Error Code: " << ex.ErrorCode(); - qCritical() << "detChain catched->Error Message: " << ex.ErrorMessage(); + qCritical() << "detChainAlgo catched->Halcon Exception Caught!"; + qCritical() << "detChainAlgo catched->Error Code: " << ex.ErrorCode(); + qCritical() << "detChainAlgo catched->Error Message: " << ex.ErrorMessage(); } catch (const std::exception& e) { - qCritical() << "detChain catched->Caught exception: " << e.what(); + qCritical() << "detChainAlgo catched->Caught exception: " << e.what(); } catch (...) { - qCritical() << "detChain catched->Caught exception: unexcepted"; + qCritical() << "detChainAlgo catched->Caught exception: unexcepted"; } std::chrono::steady_clock::time_point algoEndTime = std::chrono::steady_clock::now(); data->algoTime = std::chrono::duration_cast(algoEndTime - algoStartTime).count(); @@ -108,14 +129,13 @@ public: //计算处理总耗时(CT) QString totalCtStr = data->uuid + QString::fromStdString(data->SNcode) + "algoCT->" + QString::number(data->algoTime) + "ms|SN" + QString::fromStdString(data->SNcode); qDebug() << totalCtStr; - //std::cout << totalCtStr.toStdString() << std::endl; // 将耗时数据等保存入数据库或日志 data->sqlVec.insert({ "CT", QString::number(data->algoTime) + "ms" }); data->sqlVec.insert({ "算法结果", data->halconOK == false ? "NG" : "OK" }); data->sqlVec.insert({ "AI检测结果", data->aiDetOK == false ? "NG" : "OK" }); - data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), data->sqlVec); + data->service->_dataRecorder->addData(QString::fromStdString(data->SNcode), data->sqlVec); // 异步保存检测图像 - std::thread([this,data] {_imgSaveThreadManager->saveImage(data); }).detach(); + _imgSaveThreadManager->saveImage(data); } void registerProcessAlgoCallback(processAlgoCallback func) { diff --git a/src/core/service/detData.h b/src/core/service/detData.h index 627390b..fa1bac5 100644 --- a/src/core/service/detData.h +++ b/src/core/service/detData.h @@ -197,6 +197,7 @@ public: catch (...) { qCritical() << "detData析构崩溃 未知异常 SN: " << QString::fromStdString(SNcode) << " uuid: " << uuid; } + qDebug() << "detData析构 SN: " << QString::fromStdString(SNcode) << " uuid: " << uuid; } }; class detDataManager{ diff --git a/src/core/service/imgSaveThreadManager.h b/src/core/service/imgSaveThreadManager.h index c5587e1..1cbf70a 100644 --- a/src/core/service/imgSaveThreadManager.h +++ b/src/core/service/imgSaveThreadManager.h @@ -10,7 +10,7 @@ #include #include #include - +#include class ImageSavePathFormatter { public: enum imgSaveThreadType { @@ -207,7 +207,7 @@ public: }); while (!localQueue.isEmpty()) { - QString dirPath = localQueue.dequeue(); + QString dirPath = localQueue.dequeue().toUtf8() ; // 查询是否已存在 if (!isPathExists(tableName, dirPath)) { @@ -316,8 +316,8 @@ public: break; } - qDebug() << "saveJob start" << QString::fromStdString(job->jobName) << "remain" << imgRemainCount; imgRemainCount -= job->imgQueue.size(); + qDebug() << "saveJob start" << QString::fromStdString(job->jobName) << "remain" << imgRemainCount; localQueue.swap(job->imgQueue); // 批量保存 while (!localQueue.isEmpty()) { @@ -394,6 +394,7 @@ public: saveCls = _paramSyncManager->get("通用设置", "存储Cls图", true).toBool(); //初始化存图线程 + QMutexLocker locker(&saveThreadMutexVec); saveThreads.emplace_back(std::make_unique(saveThreads.size())); } ~imgSaveThreadManager() { @@ -524,7 +525,7 @@ public: private: std::unique_ptr dbThread; // 数据库存储线程 QMutex paramTimerMutex; // 保护参数计时器的互斥锁 - int maxSaveThreadCount = 4; + int maxSaveThreadCount = imgSaveTreadMaxCount; QMutex saveThreadMutexVec; std::vector> saveThreads; bool saveOri = true, saveRes = true, saveSeg = true, saveCls = true; diff --git a/src/core/service/missionResultHandle.h b/src/core/service/missionResultHandle.h index 2e5aba3..22d6396 100644 --- a/src/core/service/missionResultHandle.h +++ b/src/core/service/missionResultHandle.h @@ -3,9 +3,9 @@ //为了更集中方便的展示检测结果到主页面 class missionResultHandle { public: - missionResultHandle(bSignalHub* qtBridgeIn, CsvWriter* _csvWriterIn){ + missionResultHandle(bSignalHub* qtBridgeIn, DataRecorder* _dataRecorderIn){ qtBridge = qtBridgeIn; - _csvWriter = _csvWriterIn; + _dataRecorder = _dataRecorderIn; } //defectAndNum大于0则为NG,否则为OK @@ -53,7 +53,7 @@ public: emit qtBridge->waveFormAddData(windowName, value); } void addSqlData(QString snCode, std::map data) { - _csvWriter->addData(snCode, data); + _dataRecorder->addData(snCode, data); } private: QMapokNgJudge; @@ -61,6 +61,6 @@ private: QElapsedTimer timer; QMutex mutex; bSignalHub* qtBridge; - CsvWriter* _csvWriter; + DataRecorder* _dataRecorder; }; #pragma once \ No newline at end of file diff --git a/src/core/service/paramSyncManager.h b/src/core/service/paramSyncManager.h index d140d47..02e1ad8 100644 --- a/src/core/service/paramSyncManager.h +++ b/src/core/service/paramSyncManager.h @@ -14,7 +14,6 @@ class paramSyncManager :public QObject{ Q_OBJECT public: - std::vector missionKey; // 构造函数:从JSON数据初始化参数 explicit paramSyncManager(bSignalHub* _signalHub,const nlohmann::ordered_json& json = nlohmann::ordered_json::object() ):_signalHub(_signalHub){ @@ -23,17 +22,15 @@ public: //获取参数值,如果不存在则返回默认值 QVariant get(QString group, QString name, QVariant defaultValue) { QString fullKey; - { - QMutexLocker locker(&globalMutex); - //构建键名(group.name) - fullKey = group + "." + name; - - if (map.contains(fullKey)) { - return map[fullKey]; - } - map.insert(fullKey, defaultValue); + QMutexLocker locker(&globalMutex); + //构建键名(group.name) + fullKey = group + "." + name; + //键存在则返回对应值 + if (map.contains(fullKey)) { + return map[fullKey]; } - + //键不存在则插入默认值并返回 + map.insert(fullKey, defaultValue); emit _signalHub->saveMissionJson(); return defaultValue; } @@ -206,7 +203,7 @@ private: QMap map;//存储当前最新参数值 nlohmann::ordered_json json; mutable QMutex globalMutex; // 保护整个map的全局互斥锁 - + std::vector missionKey;//存储分组列表 // 辅助方法:将JSON值转换为QVariant QVariant jsonToQVariant(const nlohmann::json& json) const { if (json.is_null()) { diff --git a/src/core/service/serviceManager.h b/src/core/service/serviceManager.h index 185da8d..7cac850 100644 --- a/src/core/service/serviceManager.h +++ b/src/core/service/serviceManager.h @@ -12,7 +12,7 @@ public: triggerManager* _triggerManager = nullptr;// 触发管理器 cameraManager* _cameraManager = nullptr; SQLiteDB* dataBase = nullptr; - CsvWriter* _csvWriter = nullptr; + DataRecorder* _dataRecorder = nullptr; missionResultHandle* _missionResultHandle = nullptr; paramSyncManager* _paramSyncManager = nullptr; }; diff --git a/src/core/service/triggerManager.cpp b/src/core/service/triggerManager.cpp index faa2efb..bb996d7 100644 --- a/src/core/service/triggerManager.cpp +++ b/src/core/service/triggerManager.cpp @@ -37,7 +37,7 @@ void triggerManager::run(){ int loopCounter = 0,maxIntervalLog = 0,interval = 0; loopIntervalTimer.start(); while (runFlag){ - reciveCommond(); + receiveCommand(); if (heartTimer.elapsed()> heartBeatIntervalMS) {//心跳 sendFinsMsg(heartBeatCmds[heartBeatCmdCnt++]); if(heartBeatCmdCnt >= heartBeatCmds.size()) @@ -98,7 +98,7 @@ bool triggerManager::connectHost(){ } return false; } -void triggerManager::reciveCommond() { +void triggerManager::receiveCommand() { for (auto& _struct : readAllCmds) { QByteArray readByte = _struct.readAllCmd; @@ -166,7 +166,10 @@ void triggerManager::checkCallback(readAllStruct _struct, QByteArray& byteArray) callback.func(callback.triggerAddress, callback.triggerValue, byteArray); // 执行回调函数 } catch (const std::exception& e) { - std::cerr << "Error in callback " << callback.funcName << ": " << e.what() << std::endl; + qCritical() << "Error in union callback " << QString::fromStdString(callback.funcName) << ": " << QString::fromStdString(e.what()); + } + catch (...) { + qCritical() << "Error in union callback : unexpected" << QString::fromStdString(callback.funcName); } }).detach(); } @@ -217,7 +220,10 @@ void triggerManager::checkUnionCallback(readAllStruct& _struct, QByteArray& byte cb.func(triggerSource, copyByte); } catch (const std::exception& e) { - std::cerr << "Error in union callback " << cb.funcName << ": " << e.what() << std::endl; + qCritical() << "Error in union callback " << QString::fromStdString(cb.funcName) << ": " << QString::fromStdString(e.what()) ; + } + catch (...) { + qCritical() << "Error in union callback : unexpected" << QString::fromStdString(cb.funcName); } }).detach(); } diff --git a/src/core/service/triggerManager.h b/src/core/service/triggerManager.h index 96b08ef..4aac958 100644 --- a/src/core/service/triggerManager.h +++ b/src/core/service/triggerManager.h @@ -234,7 +234,7 @@ public: } #pragma endregion #pragma region 接收数据 - void reciveCommond(); + void receiveCommand(); QVariant read(int dmPos) { QByteArray readByte; mutex.lock(); diff --git a/src/launcher/GUI/uiModule/uiModule_runCommand.h b/src/launcher/GUI/uiModule/uiModule_runCommand.h index 9cede67..6384e22 100644 --- a/src/launcher/GUI/uiModule/uiModule_runCommand.h +++ b/src/launcher/GUI/uiModule/uiModule_runCommand.h @@ -26,7 +26,7 @@ public: for (auto& data : viewerNameAndAddress) { plcViwerLineedits[data.second].push_back(addViewer(data.first)); } - widget->setMaximumHeight(800); + widget->setMaximumHeight(900); } QLabel* addViewer(const QString& viewerName) { //QPalette palette; @@ -138,7 +138,7 @@ protected: } private: - int sizeX = 1000, sizeY = 720; + int sizeX = 1100, sizeY = 720; QListWidget* btnWidgets; // 用 QListView + 模型 替代原来的垂直布局 QListView* plcValueViewerList; diff --git a/src/launcher/main.cpp b/src/launcher/main.cpp index c5cfa91..daa3bdc 100644 --- a/src/launcher/main.cpp +++ b/src/launcher/main.cpp @@ -2,6 +2,7 @@ #include "client/windows/handler/exception_handler.h" #include #include +#include #include #include #include //日志 @@ -21,10 +22,14 @@ #include // std::cout (如果需要打印信息) #include // CreateToolhelp32Snapshot, Process32First, Process32Next #include // std::filesystem::path +#include // std::thread for restart functionality +#include // std::chrono for time operations +#include // std::unique_ptr for smart pointer management #include #include #pragma region 程序启动功能 + // 获取当前exe文件名 std::string getCurrentExeName() { char exePath[MAX_PATH]; @@ -95,7 +100,45 @@ static bool dumpCallback(const wchar_t* dump_path, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool succeeded) { - wprintf(L"Dump created at %s\\%s.dmp\n", dump_path, minidump_id); + + QString dumpFile = QString::fromWCharArray(dump_path) + "\\" + QString::fromWCharArray(minidump_id) + ".dmp"; + + if (succeeded) { + qDebug() << "========== 程序崩溃 =========="; + qDebug() << "崩溃转储文件已生成:" << dumpFile; + + if (exinfo && exinfo->ExceptionRecord) { + DWORD exceptionCode = exinfo->ExceptionRecord->ExceptionCode; + qDebug() << "异常代码:" << Qt::hex << Qt::showbase << exceptionCode; + qDebug() << "异常地址:" << Qt::hex << Qt::showbase << (quintptr)exinfo->ExceptionRecord->ExceptionAddress; + + // 解释常见的异常代码 + QString exceptionType; + switch (exceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: exceptionType = "访问违规 (Access Violation)"; break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: exceptionType = "数组越界 (Array Bounds Exceeded)"; break; + case EXCEPTION_DATATYPE_MISALIGNMENT: exceptionType = "数据类型未对齐 (Datatype Misalignment)"; break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: exceptionType = "浮点除零 (Float Divide by Zero)"; break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: exceptionType = "整数除零 (Integer Divide by Zero)"; break; + case EXCEPTION_STACK_OVERFLOW: exceptionType = "栈溢出 (Stack Overflow)"; break; + case EXCEPTION_ILLEGAL_INSTRUCTION: exceptionType = "非法指令 (Illegal Instruction)"; break; + default: exceptionType = "未知异常"; break; + } + qDebug() << "异常类型:" << exceptionType; + } + qDebug() << "=============================="; + + // 程序崩溃后自动重启 + qDebug() << "程序即将自动重启..."; + + + } else { + qDebug() << "生成崩溃转储文件失败!"; + qDebug() << "程序即将自动重启..."; + + + } + restartProgram(false, true, 5000); return succeeded; } bool checkResourceExists(const QString& resourcePath) { @@ -205,73 +248,99 @@ void connectBackSignals(appCore* _core, MainWindow* _MainWindow, bSignalHub* bri int main(int argc, char* argv[]) { + try { #pragma region 设置显示控制栏 - disableConsoleSelection(); - HWND hWnd = GetConsoleWindow(); - ShowWindow(hWnd, SW_SHOW); + disableConsoleSelection(); + HWND hWnd = GetConsoleWindow(); + ShowWindow(hWnd, SW_SHOW); #pragma endregion #pragma region 启动breakPad崩溃捕获 - std::wstring dumpPath = L"./dumps"; - CreateDirectoryW(dumpPath.c_str(), nullptr); + std::wstring dumpPath = L"./dumps"; + CreateDirectoryW(dumpPath.c_str(), nullptr); - // 初始化 breakpad - google_breakpad::ExceptionHandler eh( - dumpPath, - /*FilterCallback*/ nullptr, - dumpCallback, - /*context*/ nullptr, - /*install_handler*/ true - ); + // 初始化 breakpad + auto eh = std::make_unique( + dumpPath, + /*FilterCallback*/ nullptr, + dumpCallback, + /*context*/ nullptr, + google_breakpad::ExceptionHandler::HANDLER_ALL + ); #pragma endregion - appCore _core; - auto& config = appConfig::getInstance(); - config.consoleHandle = hWnd; - auto bridge = fSignalHub::getInstance(); // 创建 C++ 对象 - //检测是否已运行 - if (appIsRuning() == false) - exit(0); + appCore _core; + auto& config = appConfig::getInstance(); + config.consoleHandle = hWnd; + auto bridge = fSignalHub::getInstance(); // 创建 C++ 对象 + //检测是否已运行 + if (appIsRuning() == false) + exit(0); ////////// #pragma region 注册信号槽变量 - qRegisterMetaType("matPtr"); - qRegisterMetaType("stdString"); - qRegisterMetaType("historyPack"); - qRegisterMetaType("QtGlobalColor"); + qRegisterMetaType("matPtr"); + qRegisterMetaType("stdString"); + qRegisterMetaType("historyPack"); + qRegisterMetaType("QtGlobalColor"); - qRegisterMetaType("showImgPack"); - qRegisterMetaType("initStatus"); - qRegisterMetaType("mat"); - qRegisterMetaType< std::vector*>("vecmatptr"); - qRegisterMetaType>("vectorstring"); - qRegisterMetaType>>("constvpqi"); - qRegisterMetaType("PlcValueViewerStruct"); - qRegisterMetaType>>("vecQStringQVarint"); - qRegisterMetaType>*>("vecQStringQVarintPtr"); + qRegisterMetaType("showImgPack"); + qRegisterMetaType("initStatus"); + qRegisterMetaType("mat"); + qRegisterMetaType< std::vector*>("vecmatptr"); + qRegisterMetaType>("vectorstring"); + qRegisterMetaType>>("constvpqi"); + qRegisterMetaType("PlcValueViewerStruct"); + qRegisterMetaType>>("vecQStringQVarint"); + qRegisterMetaType>*>("vecQStringQVarintPtr"); #pragma endregion - QApplication a(argc, argv); - _core.initDatabase(); // 初始化数据库 - QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath() + "/sqldrivers"); - QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); - MainWindow w(&config,bridge, config.missionJson); - w.show(); - QThread::msleep(100); - // 创建后端对象 - _core._backEnd.loadCore(config.dataBase, config.missionJson["backend"]); // 加载核心功能 - connectFrontSignals(&_core, &w, bridge); // 连接前端UI的信号和槽 - connectBackSignals(&_core, &w, &_core._backEnd.backendPtr->_signalHub); // 连接前端UI的信号和槽 - w.registerQuitFunc([&]() { - auto& config = appConfig::getInstance(); - _core._backEnd.releaseCore(config.missionJson["backend"]); + QApplication a(argc, argv); + _core.initDatabase(); // 初始化数据库 + QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath() + "/sqldrivers"); + QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); + MainWindow w(&config,bridge, config.missionJson); + w.show(); QThread::msleep(100); - if (config.dataBase) delete config.dataBase; - config.dataBase = nullptr; - }); + // 创建后端对象 + _core._backEnd.loadCore(config.dataBase, config.missionJson["backend"]); // 加载核心功能 + connectFrontSignals(&_core, &w, bridge); // 连接前端UI的信号和槽 + connectBackSignals(&_core, &w, &_core._backEnd.backendPtr->_signalHub); // 连接前端UI的信号和槽 + w.registerQuitFunc([&]() { + auto& config = appConfig::getInstance(); + _core._backEnd.releaseCore(config.missionJson["backend"]); + QThread::msleep(100); + if (config.dataBase) delete config.dataBase; + config.dataBase = nullptr; + }); - int qtRes = a.exec(); - if (config.exitWithRestart) { - ShowWindow(hWnd, SW_SHOW); - std::cout << "程序将在五秒后重启..." << std::endl; - restartProgram(false,true,5000); + int qtRes = a.exec(); + if (config.exitWithRestart) { + ShowWindow(hWnd, SW_SHOW); + std::cout << "程序将在五秒后重启..." << std::endl; + restartProgram(false,true,5000); + } + return qtRes; + } + catch (const std::exception& e) { + // C++标准异常处理 + qCritical() << "========== C++异常捕获 =========="; + qCritical() << "异常信息:" << e.what(); + qCritical() << "=============================="; + restartProgram(false, true, 5000); + return -1; + } + catch (const QException& e) { + // Qt异常处理 + qCritical() << "========== Qt异常捕获 =========="; + qCritical() << "Qt异常信息:" << e.what(); + qCritical() << "=============================="; + restartProgram(false, true, 5000); + return -3; + } + catch (...) { + // 捕获所有其他异常 + qCritical() << "========== 未知异常捕获 =========="; + qCritical() << "捕获到未知类型的异常"; + qCritical() << "=============================="; + restartProgram(false, true, 5000); + return -2; } - return qtRes; } \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam1213/581-BaoMo-Cam1213.cpp b/src/mission/581-BaoMo-Cam1213/581-BaoMo-Cam1213.cpp new file mode 100644 index 0000000..e5830f5 --- /dev/null +++ b/src/mission/581-BaoMo-Cam1213/581-BaoMo-Cam1213.cpp @@ -0,0 +1,221 @@ +#include <581-BaoMo-Cam1213.h> + +struct halconResult { + bool isNg = false; + double resultX = -99; + double resultY = -99; + std::vector < std::string> defects; +}; + +void exceptionResume(std::shared_ptr 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->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(-99));//发送结果 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(-99));//发送结果 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_" + QByteArray::number(-99));//发送结果 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_" + QByteArray::number(-99));//发送结果 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1,0,1");//发送结果 + +} +halconResult dituo(std::shared_ptr data, cv::Mat& src, cv::Mat& Paint, bool isLeft,handdleAI::pClassification* cls) { + halconResult result; + try { + //src = cv::imread("D:\\testImg.bmp", -1); + //cv::Mat srcHalf; + //cv::resize(src, srcHalf, cv::Size(0, 0), 0.5, 0.5); + if (src.channels() != 3) + cv::cvtColor(src, Paint, cv::COLOR_GRAY2BGR); + else + src.copyTo(Paint); + TextRendererZH textPainter(Paint.cols, Paint.rows, 50); + + HalconCpp::HObject in_Image = MatToHObject(src); + HDevEngineCpp::HDevProcedure proc("_4_TD_BlueCover_Inspection"); + HDevProcedureCall procedureCall(proc); + + //vs+halcon联调debug + /*HDevEngineCpp::HDevEngine myEngine; + myEngine.StartDebugServer(); + procedureCall.SetWaitForDebugConnection(true);*/ + float resolution = data->service->_paramSyncManager->get("相机精度", QString::fromStdString(data->cameraKeyName) + "精度", 0.046276).toFloat(); + HTuple in_Par, in_FilePath("./halconFiles/"); + double widthThreshold = data->service->_paramSyncManager->get("底托检测", "宽度阈值(mm)", 2.0).toDouble(); + double heightThreshold = data->service->_paramSyncManager->get("底托检测", "宽度阈值(mm)", 2.0).toDouble(); + double areaThreshold = data->service->_paramSyncManager->get("底托检测", "宽度阈值(mm)", 2.0).toDouble(); + in_Par[0] = widthThreshold; + in_Par[1] = heightThreshold; + in_Par[2] = areaThreshold; + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_Par", in_Par); + procedureCall.SetInputCtrlParamTuple("in_FilePath", in_FilePath); + procedureCall.SetInputCtrlParamTuple("in_Resolution", resolution); + procedureCall.Execute(); + HalconCpp::HTupleVector out_VectorX = procedureCall.GetOutputCtrlParamVector("out_VectorX"); + HalconCpp::HTupleVector out_VectorY = procedureCall.GetOutputCtrlParamVector("out_VectorY"); + HalconCpp::HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HalconCpp::HTuple out_NgDetails = procedureCall.GetOutputCtrlParamTuple("out_NgDetails"); + //HTuple out_RecX = procedureCall.GetOutputCtrlParamTuple("out_RecX"); + //HTuple out_RecY = procedureCall.GetOutputCtrlParamTuple("out_RecY"); + int outFlag = out_Flag.D(); + std::vector> clsImgs; + TextRendererZH textPainterdefect(Paint.cols, Paint.rows, 30); + if (outFlag == 0) { + cv::Mat whiteMat = cv::Mat::zeros(cv::Size(src.cols, src.rows), CV_8UC1); + std::vector> contours; + int l1 = out_VectorX.Length(), l2 = out_VectorY.Length(), l3 = out_NgDetails.Length(); + for (int m = 0; m < out_VectorX.Length() && m < out_VectorY.Length() && m < out_NgDetails.Length(); m++) { + HalconCpp::HTuple out_X = out_VectorX[m].ConvertVectorToTuple(); + HalconCpp::HTuple out_Y = out_VectorY[m].ConvertVectorToTuple(); + + std::string ngDetails = (out_NgDetails[m].ToTuple().ToString().Text()); + + //输出的点集不是正常的轮廓点集,把点集在黑图上画出来,在用opencv重新找一遍轮廓 + + std::vector contour; + for (int i = 0; i < out_Y.Length(); i++) + { + contour.push_back(cv::Point(out_X[i].D(), out_Y[i].D())); + whiteMat.at(out_Y[i].D(), out_X[i].D()) = (255); + } + contours.push_back(contour); + + } + for (int i = 0; i < contours.size(); i++) + { + std::string ngDetails = (out_NgDetails[i].ToTuple().ToString().Text()); + ngDetails = gbkToUtf8(ngDetails.substr(1, ngDetails.length() - 2)); + if (data->service->_paramSyncManager->get("底托检测","底托偏移检测启用",false).toBool() == false && ngDetails == "底托偏移") + return result; + cv::Rect rect = cv::boundingRect(contours[i]); + if (rect.width * resolution >= widthThreshold || rect.height * resolution >= heightThreshold) { + cv::rectangle(Paint, rect, cv::Scalar(0, 0, 255), 3); + float realWidth = rect.width; + float realHeight = rect.height; + float realArea = cv::contourArea(contours[i]); + QString DefectStr = "宽:" + QString::number(realWidth * resolution, 'f', 3) + + "mm高:" + QString::number(realHeight * resolution, 'f', 3) + + "mm面积:" + QString::number(realArea * resolution * resolution, 'f', 3); + textPainterdefect.appendPaintJob(DefectStr.toStdString() + ngDetails, cv::Point(rect.x, rect.y), cv::Scalar(0, 255, 255)); + cv::Mat clsImg = src(rect); + cv::resize(clsImg, clsImg, cv::Size(128, 128)); + int clsResult = cls->Evaluate(clsImg); + double prob = cls->getProbability(); + clsImgs.push_back({ "result" + std::to_string(clsResult) + "_prob" + std::to_string(prob),clsImg }); + data->halconOK = false; + result.defects.push_back(ngDetails); + result.isNg = true; + } + + } + //画轮廓 + std::vector> contoursPaint; + cv::findContours(whiteMat, contoursPaint, cv::RETR_TREE, cv::CHAIN_APPROX_NONE); + int maxIndex = 0, maxArea = 0; + for (int i = 0; i < contoursPaint.size(); i++) + { + cv::Rect rect = cv::boundingRect(contoursPaint[i]); + if (rect.width * resolution >= widthThreshold || rect.height * resolution >= heightThreshold) { + cv::drawContours(Paint, contoursPaint, i, cv::Scalar(0, 0, 255), 3); + } + + } + //释放存储画图文字 + textPainterdefect.excusePaintJobs(Paint); + } + } + CATCH_EXCEPTIONS + return result; +} +bool ALGO_BaoMoHouDiBu(std::shared_ptr data, baoMoHouDiBuDetParams* _detParams, yh_581_address address) { + try { + + + QDateTime createTime = QDateTime::currentDateTime(); + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + std::vector < std::string> defects; + + //data->oriImgs.clear(); + + ///////////////////取图//处理////////////////// + if (data->getOriImgSize() < 2) + { + qCritical() << "图片数量不满足要求:" << data->getOriImgSize(); + exceptionResume(data, address, "图片数量不满足要求"); + return false; + } + if (data->getOriImgVec()[0].rows == 100) { + exceptionResume(data, address, "取图超时"); + return false; + } + + cv::Mat Paint, Paint1, Paint2; + bool leftFirst = address.triggerAddr != 20200; + cv::Mat first = data->getOriImg(0); + cv::Mat second = data->getOriImg(1); + //first = cv::imread("D://testImg/dituo (2).bmp", -1); + //second = cv::imread("D://testImg/dituo (1).bmp", -1); + auto feature1 = std::async(std::launch::async, dituo, data, std::ref(first), std::ref(Paint1), leftFirst, _detParams->cls1); + auto feature2 = std::async(std::launch::async, dituo, data, std::ref(second), std::ref(Paint2), ~leftFirst, _detParams->cls2); + + feature1.wait(); + halconResult hResult1 = feature1.get(); + defects.insert(defects.end(), hResult1.defects.begin(), hResult1.defects.end()); + + feature2.wait(); + halconResult hResult2 = feature2.get(); + defects.insert(defects.end(), hResult2.defects.begin(), hResult2.defects.end()); + + if (address.triggerAddr == 20400) + cv::hconcat(Paint2, Paint1, Paint); + else + cv::hconcat(Paint1, Paint2, Paint); + + bool isNG = (hResult1.isNg == true || hResult2.isNg == true); + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + + QByteArray plcResult = "1"; + if (isNG == false) { + textPainter.putText(Paint, "OK", cv::Point(50, 50), cv::Scalar(0, 255, 0)); + } + else + { + textPainter.putText(Paint, "NG", cv::Point(50, 50), cv::Scalar(0, 0, 255)); + if (data->service->_paramSyncManager->get("底托检测", "底托判定启用", false).toBool()) + plcResult = "2"; + } + int Rate = (Paint.rows > Paint.cols ? Paint.cols : Paint.rows) / 20; + TextRendererZH textPainter1(Paint.cols, Paint.rows, Rate); + textPainter1.putText(Paint, "产品条码:" + data->SNcode, cv::Point(50, Paint.rows - Rate), cv::Scalar(0, 255, 255)); + textPainter1.putText(Paint, "获取图像时间:" + createTime.toString("yyyy/MM/dd hh:mm:ss").toStdString(), cv::Point(50, Paint.rows - (Rate * 2)), cv::Scalar(0, 255, 255)); + + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(hResult1.resultX));//发送结果 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(hResult1.resultY));//发送结果 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_" + QByteArray::number(hResult2.resultX));//发送结果 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_" + QByteArray::number(hResult2.resultY));//发送结果 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult + ",0," + plcResult);//发送结果 + data->service->_missionResultHandle->toBarChart(data->SNcode, defects); + data->insertResultImg(Paint); + return true; + } + CATCH_EXCEPTIONS + exceptionResume(data, address, "检测异常"); + return true; +} + +mission* createMission() { + return new _581_BaoMo(); +} +void destroyMission(mission* _mission) { + delete _mission; +} \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam1213/581-BaoMo-Cam1213.h b/src/mission/581-BaoMo-Cam1213/581-BaoMo-Cam1213.h new file mode 100644 index 0000000..da66973 --- /dev/null +++ b/src/mission/581-BaoMo-Cam1213/581-BaoMo-Cam1213.h @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +using namespace HDevEngineCpp; +QMutex writeFileMutex; +QStringList headList({ "条码", "时间","位置","结果","缺陷明细" }); + +class baoMoHouDiBuDetParams { +public: + handdleAI::pClassification* cls1 = nullptr; + handdleAI::pClassification* cls2 = nullptr; +}; +static bool ALGO_BaoMoHouDiBu(std::shared_ptr data, baoMoHouDiBuDetParams* _detParams, yh_581_address address); + +class _581_BaoMo : public mission { +public: + using baoMoHouDiBuTrigger = _581_Single_triggerTemplate; + baoMoHouDiBuTrigger _station_1; + baoMoHouDiBuTrigger _station_2; + + baoMoHouDiBuDetParams _baoMoHouDiBuDetParams1; + baoMoHouDiBuDetParams _baoMoHouDiBuDetParams2; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath(""); + myEngine.SetProcedurePath("./halconAlgo/AlgoLibrary_602.hdpl"); + _baoMoHouDiBuDetParams1.cls1 = handdleAI::CreateClsObjV3("./handleaiModels/dituo_cls.BHD", 0, 1); + _baoMoHouDiBuDetParams1.cls2 = handdleAI::CreateClsObjV3("./handleaiModels/dituo_cls.BHD", 0, 1); + _baoMoHouDiBuDetParams2.cls1 = handdleAI::CreateClsObjV3("./handleaiModels/dituo_cls.BHD", 0, 1); + _baoMoHouDiBuDetParams2.cls2 = handdleAI::CreateClsObjV3("./handleaiModels/dituo_cls.BHD", 0, 1); + } + bool initCustom() { +#pragma region 注册触发器回调 + + _station_1.init("Camera1","包膜后底托位置度检测-左-相机12",20200,1,2, &_baoMoHouDiBuDetParams1,_serviceManager,bridge, ALGO_BaoMoHouDiBu); + _station_2.init("Camera2", "包膜后底托位置度检测-右-相机13",20400,1,2,&_baoMoHouDiBuDetParams2, _serviceManager, bridge, ALGO_BaoMoHouDiBu); +#pragma endregion + return true; + } + + + //9600 +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam1213/CMakeLists.txt b/src/mission/581-BaoMo-Cam1213/CMakeLists.txt new file mode 100644 index 0000000..76e9200 --- /dev/null +++ b/src/mission/581-BaoMo-Cam1213/CMakeLists.txt @@ -0,0 +1,77 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "opencv" "halcon" "handdleAI") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + ${PROJECT_ROOT_PATH}/src/core + ${PROJECT_ROOT_PATH}/src/core/handleAi + ${PROJECT_ROOT_PATH}/src/core/service + ${PROJECT_ROOT_PATH}/src/core/sql + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) +add_compile_options(/utf-8) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC OFF) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ${PROJECT_ROOT_PATH}/include/interface.h + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Network + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " modelx end : " ${CURRENT_FOLDER}:${RUN_TIME}) +message( " header files "${HEAD_FILES}) diff --git a/src/mission/581-BaoMo-Cam91011/581-BaoMo-Cam91011.cpp b/src/mission/581-BaoMo-Cam91011/581-BaoMo-Cam91011.cpp new file mode 100644 index 0000000..dfed6db --- /dev/null +++ b/src/mission/581-BaoMo-Cam91011/581-BaoMo-Cam91011.cpp @@ -0,0 +1,721 @@ +#include <581-BaoMo-Cam91011.h> +#include +mission* createMission() { + return new _581_BaoMo(); +} +void destroyMission(mission* _mission) { + delete _mission; +} + +struct halconResult { + double houdu = -1; + double chonghedu = -1; + bool result = true; + std::string ngText; +}; + +cv::Mat cutLabelImg(cv::Mat pic, int W, int H, cv::Rect rect, int edgeType, int largeType, int color) +{ + cv::Point center; + center.x = rect.x + rect.width / 2; + center.y = rect.y + rect.height / 2; + + if (rect.width <= W && rect.height <= H) + { + if (edgeType == 0) + { + cv::Rect rec = { center.x - W / 2,center.y - H / 2,W,H }; + if (rec.x < 0) + rec.x = 0; + if (rec.y < 0) + rec.y = 0; + if (rec.x + rec.width > pic.cols) + rec.x = pic.cols - rec.width; + if (rec.y + rec.height > pic.rows) + rec.y = pic.rows - rec.height; + + cv::Mat picCut; + pic(rec).copyTo(picCut); + return picCut; + } + else + { + int xDiff = 0; + int yDiff = 0; + + int x, y; + cv::Rect rec; + x = center.x - W / 2; + y = center.y - H / 2; + rec.x = x; + rec.y = y; + rec.width = W; + rec.height = H; + cv::Mat picCut(H, W, pic.type(), cv::Scalar(color, color, color)); + if (x < 0) + { + rec.width += rec.x; + xDiff = 0 - rec.x; + rec.x = 0; + } + if (y < 0) + { + rec.height += rec.y; + yDiff = 0 - rec.y; + rec.y = 0; + } + if (rec.x + rec.width > pic.cols) + rec.width = pic.cols - rec.x; + if (rec.y + rec.height > pic.rows) + rec.height = pic.rows - rec.y; + + pic(rec).copyTo(picCut({ xDiff, yDiff, rec.width, rec.height })); + return picCut; + } + } + else + { + if (largeType == 0) + { + int xDiff = 0; + int yDiff = 0; + float valF = rect.width * 1.0 / rect.height; + float valV = W / H; + int wTem, hTem; + if (valF <= valV) + { + hTem = rect.height; + wTem = valV * hTem; + } + else + { + wTem = rect.width; + hTem = wTem / valV; + } + + cv::Mat picCut(hTem, wTem, pic.type(), cv::Scalar(color, color, color)); + + if (rect.x < 0) + { + rect.width += rect.x; + rect.x = 0; + } + if (rect.y < 0) + { + rect.height += rect.y; + rect.y = 0; + } + if (rect.x + rect.width > pic.cols) + rect.width = pic.cols - rect.x; + if (rect.y + rect.height > pic.rows) + rect.height = pic.rows - rect.y; + + xDiff = (wTem - rect.width) * 1.0 / 2; + yDiff = (hTem - rect.height) * 1.0 / 2; + + pic(rect).copyTo(picCut({ xDiff, yDiff, rect.width, rect.height })); + + cv::resize(picCut, picCut, cv::Size(W, H)); + return picCut; + } + else + { + int xDiff = 0; + int yDiff = 0; + cv::Rect rectTem; + float valF = rect.width * 1.0 / rect.height; + float valV = W / H; + int wTem, hTem; + if (valF <= valV) + { + hTem = rect.height; + wTem = valV * hTem; + } + else + { + wTem = rect.width; + hTem = wTem / valV; + } + rectTem = { rect.x + rect.width / 2 - wTem / 2,rect.y + rect.height / 2 - hTem / 2,wTem,hTem }; + + cv::Mat picCut(hTem, wTem, pic.type(), cv::Scalar(color, color, color)); + + if (rectTem.x < 0) + { + rectTem.width += rectTem.x; + xDiff = 0 - rectTem.x; + rectTem.x = 0; + } + if (rectTem.y < 0) + { + rectTem.height += rectTem.y; + yDiff = 0 - rectTem.y; + rectTem.y = 0; + } + if (rectTem.x + rectTem.width > pic.cols) + rectTem.width = pic.cols - rectTem.x; + if (rectTem.y + rectTem.height > pic.rows) + rectTem.height = pic.rows - rectTem.y; + + pic(rectTem).copyTo(picCut({ xDiff, yDiff, rectTem.width, rectTem.height })); + + cv::resize(picCut, picCut, cv::Size(W, H)); + return picCut; + } + } + + return cv::Mat(); +} + +void ExceptionResume(std::shared_ptr data, yh_581_address address, QString why = "", QString loaction = "") { + 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");//结果反馈 + QStringList resultCsv; + resultCsv << QString::fromStdString(data->SNcode) << QDateTime::currentDateTime().toString("yyyyMMddhhmmss") << loaction << why << "异常"; + //SaveLineToCSv("D:/CCDData/" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".csv", resultCsv); +} +halconResult halconAlgo1_BaoMoHouCeMian_HouDuAndChongHe(std::shared_ptr data, TextRendererZH* textPainter, baoMoHouDaMianDetParams* _detParams, yh_581_address address, cv::Mat& src) { + QElapsedTimer eTimer; + eTimer.start(); + bool isInsideCamera = QString::number(address.triggerAddr).startsWith("198") ? true : false; + halconResult hResult; + cv::Mat forSeg; + cv::resize(src, forSeg, cv::Size(), 0.2, 0.2); + cv::Mat segResult = _detParams->chongHe_seg->Evaluate(forSeg); + data->insertSegOriginImg(segResult); + bool isOK = false; + double Width = -99; + double chonheduMax = -99; + double chonheduMin = -99; + double in_xResolution = 0.001, in_yResolution = 0.001, offset = 0; + if (isInsideCamera) + { + in_xResolution = data->service->_paramSyncManager->get("包膜后侧面", "内侧相机x方向精度", 0.0308812).toDouble(); + in_yResolution = data->service->_paramSyncManager->get("包膜后侧面", "内侧相机y方向精度", 0.029527).toDouble(); + offset = data->service->_paramSyncManager->get("补偿", "内侧相机厚度补偿", 0.00).toDouble(); + } + else + { + in_xResolution = data->service->_paramSyncManager->get("包膜后侧面", "外侧相机x方向精度", 0.0308812).toDouble(); + in_yResolution = data->service->_paramSyncManager->get("包膜后侧面", "外侧相机y方向精度", 0.029527).toDouble(); + offset = data->service->_paramSyncManager->get("补偿", "外侧相机厚度补偿", 0.00).toDouble(); + } + HalconCpp::HObject in_Image = MatToHObject(src); + HalconCpp::HObject in_ImageSeg = MatToHObject(segResult); + HDevEngineCpp::HDevProcedure proc("_4_Cal_Short_Coatingcover_Dist"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputIconicParamObject("in_ImageSeg", in_ImageSeg); + procedureCall.SetInputCtrlParamTuple("in_Compensation", offset); + procedureCall.SetInputCtrlParamTuple("in_xResolution", in_xResolution); + procedureCall.SetInputCtrlParamTuple("in_yResolution", in_yResolution); + procedureCall.Execute(); + HTuple out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance"); + HTuple out_LineCor = procedureCall.GetOutputCtrlParamTuple("out_LineCor"); + HTuple out_PointCor = procedureCall.GetOutputCtrlParamTuple("out_PointCor"); + HTuple out_X = procedureCall.GetOutputCtrlParamTuple("out_X"); + HTuple out_Y = procedureCall.GetOutputCtrlParamTuple("out_Y"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_NgDetails = procedureCall.GetOutputCtrlParamTuple("out_NgDetails"); + int outFlag = out_Flag.D(); + + + double limitHigh = data->service->_paramSyncManager->get("包膜后侧面", "最大厚度阈值(mm)", 200.0).toFloat(); + double limitLow = data->service->_paramSyncManager->get("包膜后侧面", "最小厚度阈值(mm)", 0.0).toFloat(); + + double chonghelimitHigh = data->service->_paramSyncManager->get("包膜后侧面", "蓝膜重叠区最大值(mm)", 30.0).toFloat(); + double chonghelimitLow = data->service->_paramSyncManager->get("包膜后侧面", "蓝膜重叠区最小值(mm)", 2.0).toFloat(); + if (outFlag == 1) { + for (int i = 0; i < out_LineCor.Length() / 4; i++) { + textPainter->appendPaintJob(cv::Point(out_LineCor[i * 4 + 1].D(), out_LineCor[i * 4].D()) / 2, + cv::Point(out_LineCor[i * 4 + 3].D(), out_LineCor[i * 4 + 2].D()) / 2, + cv::Scalar(0, 255, 0), 5); + } + Width = out_Distance[2].D(); + chonheduMin = out_Distance[0].D(); + chonheduMax = out_Distance[1].D(); + hResult.houdu = Width; + hResult.chonghedu = chonheduMax; + QString defectStr = "电芯厚度:" + QString::number(Width, 'f', 3) + "mm"; + if (limitHigh > Width && limitLow < Width) { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 50), cv::Scalar(0, 255, 0)); + isOK = true; + } + else { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 50), cv::Scalar(0, 0, 255)); + hResult.ngText = "厚度判定不良"; + hResult.result = false; + } + + defectStr = "蓝膜重叠区最大值(mm):" + QString::number(out_Distance[1].D(), 'f', 3) + "mm"; + if (out_Distance[1].D() > chonghelimitHigh) + { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 350), cv::Scalar(0, 0, 255)); + hResult.ngText = "重叠区最大值NG"; + hResult.result = false; + } + else + { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 350), cv::Scalar(0, 255, 0)); + } + defectStr = "蓝膜重叠区最小值(mm):" + QString::number(out_Distance[0].D(), 'f', 3) + "mm"; + if (out_Distance[0].D() < chonghelimitLow) + { + hResult.ngText = "重叠区最小值NG"; + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 200), cv::Scalar(0, 0, 255)); + hResult.result = false; + } + else + { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 200), cv::Scalar(0, 255, 0)); + } + for (int i = 0; i < out_X.Length() && i < out_Y.Length(); i++) { + textPainter->appendPaintJob(cv::Point(out_X[i].D(), out_Y[i].D()) / 2, 2, cv::Scalar(0, 255, 0), 2, 0); + } + for (int i = 0; i < out_PointCor.Length() / 2 - 1; i++) { + textPainter->appendPaintJob(cv::Point(out_PointCor[i * 2 + 1].D(), out_PointCor[i * 2].D()) / 2, 2, cv::Scalar(0, 255, 0), 3, 0); + } + } + else { + textPainter->appendPaintJob(gbkToUtf8(out_NgDetails.ToString().Text()), cv::Point(50, 200), cv::Scalar(0, 0, 255)); + data->halconOK = false; + hResult.result = false; + hResult.ngText = gbkToUtf8(out_NgDetails.ToString().Text()); + } + + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(Width)); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(chonheduMin)); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_" + QByteArray::number(chonheduMax)); + + qDebug() << "halconAlgo1_BaoMoHouCeMian_HouDuAndChongHe cost time" << eTimer.elapsed() << "ms"; + return hResult; +} +halconResult halconAlgo1_BaoMoHouCeMian_HouDu(std::shared_ptr data, TextRendererZH* textPainter, yh_581_address address, cv::Mat& src) { + QElapsedTimer eTimer; + eTimer.start(); + bool isInsideCamera = QString::number(address.triggerAddr).startsWith("198") ? true : false; + halconResult hResult; + bool isOK = false; + double Width = -99; + double in_xResolution = 0.001, in_yResolution = 0.001, offset = 0; + if (isInsideCamera) + { + in_xResolution = data->service->_paramSyncManager->get("包膜后侧面", "内侧相机x方向精度", 0.0308812).toDouble(); + in_yResolution = data->service->_paramSyncManager->get("包膜后侧面", "内侧相机y方向精度", 0.029527).toDouble(); + offset = data->service->_paramSyncManager->get("补偿", "内侧相机厚度补偿", 0.00).toDouble(); + } + else + { + in_xResolution = data->service->_paramSyncManager->get("包膜后侧面", "外侧相机x方向精度", 0.0308812).toDouble(); + in_yResolution = data->service->_paramSyncManager->get("包膜后侧面", "外侧相机y方向精度", 0.029527).toDouble(); + offset = data->service->_paramSyncManager->get("补偿", "外侧相机厚度补偿", 0.00).toDouble(); + } + HalconCpp::HObject in_Image = MatToHObject(src); + HDevEngineCpp::HDevProcedure proc("_4_Cal_Short_Coatingcover_Dist_1"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_Compensation", offset); + procedureCall.SetInputCtrlParamTuple("in_xResolution", HTuple(in_xResolution)); + procedureCall.SetInputCtrlParamTuple("in_yResolution", HTuple(in_yResolution)); + procedureCall.Execute(); + HTuple out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance"); + HTuple out_LineCor = procedureCall.GetOutputCtrlParamTuple("out_LineCor"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_NgDetails = procedureCall.GetOutputCtrlParamTuple("out_NgDetails"); + int outFlag = out_Flag.D(); + + + double limitHigh = data->service->_paramSyncManager->get("包膜后侧面", "最大厚度阈值(mm)", 200.0).toFloat(); + double limitLow = data->service->_paramSyncManager->get("包膜后侧面", "最小厚度阈值(mm)", 0.0).toFloat(); + if (outFlag == 1) { + + for (int i = 0; i < out_LineCor.Length() / 4; i++) { + textPainter->appendPaintJob(cv::Point(out_LineCor[i * 4 + 1].D(), out_LineCor[i * 4].D()) / 2, + cv::Point(out_LineCor[i * 4 + 3].D(), out_LineCor[i * 4 + 2].D()) / 2, + cv::Scalar(0, 255, 0), 5); + } + Width = out_Distance.D(); + hResult.houdu = Width; + QString defectStr = "电芯厚度:" + QString::number(Width, 'f', 3) + "mm"; + if (limitHigh > Width && limitLow < Width) { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 50), cv::Scalar(0, 255, 0)); + isOK = true; + } + else { + textPainter->appendPaintJob(defectStr.toStdString(), cv::Point(50, 50), cv::Scalar(0, 0, 255)); + hResult.ngText = "厚度判定不良"; + hResult.result = false; + } + } + else { + + textPainter->appendPaintJob(gbkToUtf8(out_NgDetails.ToString().Text()), cv::Point(50, 200), cv::Scalar(0, 0, 255)); + data->halconOK = false; + hResult.result = false; + hResult.ngText = gbkToUtf8(out_NgDetails.ToString().Text()); + } + + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(Width)); + qDebug() << "halconAlgo1_BaoMoHouCeMian_HouDu cost time" << eTimer.elapsed() << "ms"; + + return hResult; +} +bool halconAlgo1_BaoMoHouCeMian_PoSun(std::shared_ptr data, TextRendererZH* textPainter, TextRendererZH* textPainterCls, yh_581_address address, cv::Mat& src, cv::Mat& Paint, HObject& outImage, handdleAI::pClassification* clsPtr) { + bool isOK = true; + try { + QElapsedTimer eTimer; + eTimer.start(); + HalconCpp::HObject in_Image = MatToHObject(src); + + HTuple in_Parameters; + in_Parameters[0] = data->service->_paramSyncManager->get("包膜后侧面", "灰度管控阈值", 230).toInt(); + in_Parameters[1] = data->service->_paramSyncManager->get("包膜后侧面", "缺陷像素数量管控阈值(pix)", 300000).toInt(); + in_Parameters[2] = data->service->_paramSyncManager->get("包膜后侧面", "缺陷的宽度管控阈值(pix)", 600).toInt(); + in_Parameters[3] = data->service->_paramSyncManager->get("包膜后侧面", "缺陷的高度管控阈值(pix)", 60).toInt(); + + HDevEngineCpp::HDevProcedure proc("_4_TR_TL_BlueCover_Inspection"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputCtrlParamTuple("in_Parameters", in_Parameters); + + procedureCall.Execute(); + int timerPart1 = eTimer.elapsed(); + outImage = procedureCall.GetOutputIconicParamObject("out_DisplayImage"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_NgDetails = procedureCall.GetOutputCtrlParamTuple("out_NgDetails"); + HTuple out_RecX1 = procedureCall.GetOutputCtrlParamTuple("out_RecX1"); + HTuple out_RecY1 = procedureCall.GetOutputCtrlParamTuple("out_RecY1"); + HTuple out_RecX2 = procedureCall.GetOutputCtrlParamTuple("out_RecX2"); + HTuple out_RecY2 = procedureCall.GetOutputCtrlParamTuple("out_RecY2"); + int outFlag = out_Flag.D(); + std::vector> clsImgs; + if (outFlag == 1) { + textPainter->appendPaintJob("破损检测OK", cv::Point(2550, 50), cv::Scalar(0, 255, 0)); + } + else { + //在进行一次CLS复判 + for (int i = 0; i < out_RecY1.Length() && i < out_RecX1.Length() && i < out_RecY2.Length() && i < out_RecX2.Length(); i++) { + cv::Rect rect(out_RecX1[i].D(), out_RecY1[i].D(), out_RecX2[i].D() - out_RecX1[i].D(), out_RecY2[i].D() - out_RecY1[i].D()); + cv::Rect Paintrect(rect.x / 2, rect.y / 2, rect.width / 2, rect.height / 2); + cv::Mat clsImg = cutLabelImg(src, 128, 128, rect, 1, 1, 0); + int clsReult = clsPtr->Evaluate(clsImg); + double prob = clsPtr->getProbability(); + clsImgs.push_back({ "result" + std::to_string(clsReult) + "_prob" + std::to_string(prob),clsImg }); + if (clsReult == 1) { + textPainter->appendPaintJob(Paintrect, cv::Scalar(0, 0, 255), 3); + isOK = false; + } + else + textPainter->appendPaintJob(Paintrect, cv::Scalar(0, 255, 0), 3); + + textPainterCls->appendPaintJob( + "w:" + std::to_string(rect.width) + + " h:" + std::to_string(rect.height) + + " r:" + std::to_string(clsReult) + + " p:" + std::to_string(prob), cv::Point(rect.x, rect.y) / 2, cv::Scalar(0, 255, 255)); + } + if (isOK == false) { + std::string ngDetailStr = gbkToUtf8(out_NgDetails.ToString().Text()); + textPainter->appendPaintJob(ngDetailStr.substr(1, ngDetailStr.length() - 2), cv::Point(2050, 200), cv::Scalar(0, 0, 255)); + textPainter->appendPaintJob("破损检测NG", cv::Point(2550, 50), cv::Scalar(0, 0, 255)); + data->halconOK = false; + } + else { + textPainter->appendPaintJob("破损检测OK", cv::Point(2550, 50), cv::Scalar(0, 255, 0)); + } + } + data->insertClsOriginImg(clsImgs); + qDebug() << "halconAlgo1_BaoMoHouCeMian_PoSun cost time" << eTimer.elapsed() << "ms timerPart1" << timerPart1; + return isOK; + } + CATCH_EXCEPTIONS; + cv::resize(src, Paint, cv::Size(), 0.5, 0.5); + if (src.channels() == 1) + cv::cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); + else + src.copyTo(Paint); + return isOK; +} + +bool ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address address) { + try { + QDateTime createTime = QDateTime::currentDateTime(); + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + QByteArray PlcResult = "1"; + std::vector < std::string> defects; + ///////////////////取图//处理////////////////// + if (data->getOriImgSize() < 1) + { + qCritical() << "图片数量不满足要求:" << data->getOriImgSize(); + return false; + } + cv::Mat Paint; + clock_t start, finish; + start = clock(); + cv::Mat src = data->getOriImg(0); + + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); + TextRendererZH textPainterCls(Paint.cols, Paint.rows, 35); + HObject outImage; + std::future handleAiFuture1 = std::async(std::launch::async, halconAlgo1_BaoMoHouCeMian_PoSun, data, &textPainter, &textPainterCls, address, std::ref(src), std::ref(Paint), std::ref(outImage), _detParams->ceMian_cls); + std::future handleAiFuture2; + if (address.triggerAddr == 19602 || address.triggerAddr == 19800) { + handleAiFuture2 = std::async(std::launch::async, halconAlgo1_BaoMoHouCeMian_HouDuAndChongHe, data, &textPainter, _detParams, address, std::ref(src)); + } + else { + handleAiFuture2 = std::async(std::launch::async, halconAlgo1_BaoMoHouCeMian_HouDu, data, &textPainter, address, std::ref(src)); + } + + //textPainter.putText(Paint, "电芯厚度:" + std::to_string(Width) + "mm", cv::Point(50, 50), cv::Scalar(0, 0, 255)); + + handleAiFuture1.wait(); + bool res1 = handleAiFuture1.get(); + + handleAiFuture2.wait(); + halconResult res2 = handleAiFuture2.get(); + if (res1 == false) { + defects.push_back("侧面破损"); + } + if (res2.result == false) { + defects.push_back(res2.ngText); + } + + if (data->service->_paramSyncManager->get("包膜后侧面", "判定启用", false) == false) + PlcResult = "1"; + + /*if (address.triggerAddr == 19602 || address.triggerAddr == 19800) + { + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr+2) + "_" + QByteArray::number(res2.houdu)); + } + else + { + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(res2.houdu)); + }*/ + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + PlcResult); + Paint = HObject2Mat(outImage); + if (Paint.empty() || Paint.rows == 0) { + if (src.channels() != 3) + cv::cvtColor(src, Paint, cv::COLOR_GRAY2BGR); + else + src.copyTo(Paint); + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + } + else + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + textPainter.excusePaintJobs(Paint); + textPainterCls.excusePaintJobs(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); + textPainter1.putText(Paint, "产品条码:" + data->SNcode, cv::Point(50, Paint.rows - Rate), cv::Scalar(0, 255, 255)); + textPainter1.putText(Paint, "获取图像时间:" + createTime.toString("yyyy/MM/dd hh:mm:ss").toStdString(), cv::Point(50, Paint.rows - (Rate * 2)), cv::Scalar(0, 255, 255)); + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + data->insertResultImg(Paint); + + return true; + } + CATCH_EXCEPTIONS; + ExceptionResume(data, address, "检测异常", "包膜后侧面"); + return true; +} + +bool ALGO_BaoMoHouXiaDaMian(std::shared_ptr data, xiaDaMianParam* _detParams, yh_581_address address) { + try { + QDateTime createTime = QDateTime::currentDateTime(); + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + std::vector < std::string> defects; + ///////////////////取图//处理////////////////// + if (data->getOriImgSize() < 1) + { + qCritical() << "图片数量不满足要求:" << data->getOriImgSize(); + return false; + } + cv::Mat Paint; + clock_t start, finish; + + //data->oriImgs[0] = cv::imread("D:/testImg/xiadamian3.bmp", -1); + + cv::Mat src = data->getOriImg(0); + QMutex mutex; + //data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1"); + cv::Mat afterDingWei; + cv::Rect dingWeiRect; + { + cv::Mat forDingWei; + cv::resize(src, forDingWei, cv::Size(), 0.1, 0.1); + data->insertSegOriginImg(forDingWei); + cv::Mat SegResult = ~_detParams->dinggWei_seg->Evaluate(forDingWei); + //cv::imwrite("D:\\seg\\"+QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz").toStdString() + data->SNcode+".png", SegResult); + dingWeiRect = findMaxAreaContour(SegResult); + dingWeiRect.x *= 10; dingWeiRect.y *= 10; dingWeiRect.width *= 10; dingWeiRect.height *= 10; + src(dingWeiRect).copyTo(afterDingWei); + if (dingWeiRect.width < 3500 || dingWeiRect.height < 3500) { + data->insertSegOriginImg(SegResult); + ExceptionResume(data, address, "定位失败"); + return false; + } + } + cv::resize(afterDingWei, afterDingWei, cv::Size(), 0.5, 0.5); + if (afterDingWei.channels() != 3) + cv::cvtColor(afterDingWei, Paint, cv::COLOR_GRAY2BGR); + else + afterDingWei.copyTo(Paint); + data->insertSegOriginImg(afterDingWei); + handdleAI::pSegmentation* segPtr = (address.triggerAddr == 20000 ? _detParams->qiPao_seg_gpu0 : _detParams->qiPao_seg_gpu1); + handdleAI::pClassification* clsPtr = (address.triggerAddr == 20000 ? _detParams->qiPao_cls_gpu0 : _detParams->qiPao_cls_gpu1); + cv::Mat SegResult = ~segPtr->Evaluate(afterDingWei); + data->insertSegOriginImg(SegResult); + std::vector> contours; + cv::findContours(SegResult, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + bool isNg = false; + double yPix = data->service->_paramSyncManager->get("下大面", "相机y方向精度", 0.08389).toDouble(); + double xPix = data->service->_paramSyncManager->get("下大面", "相机x方向精度", 0.06746).toDouble(); + TextRendererZH textPainterCls(Paint.cols, Paint.rows, 40); + int fillterAndWidth = data->service->_paramSyncManager->get("下大面", "下大面过滤宽度(与)(mm)", 25.00).toDouble() / xPix; + int fillterAndHeight = data->service->_paramSyncManager->get("下大面", "下大面过滤高度(与)(mm)", 25.00).toDouble() / yPix; + int fillterOr = data->service->_paramSyncManager->get("下大面", "下大面过滤(或)(mm)", 50.00).toDouble() / yPix; + float thresholdRate = data->service->_paramSyncManager->get("下大面", "下大面过滤百分比(%)", 50.00).toFloat(); + + float pixArea = 0; + std::vector> drawDefectContours; + std::vector> drawOKContours; + + for (int ii = 0; ii < contours.size(); ii++) { + cv::Rect rect = cv::boundingRect(contours[ii]); + cv::RotatedRect rRect = cv::minAreaRect(contours[ii]); + + float rWidth = rRect.size.width; + float rHeight = rRect.size.height; + if (rWidth > rHeight) { + float tempValue = rWidth; + rWidth = rHeight; + rHeight = tempValue; + } + + float realArea = cv::contourArea(contours[ii]) * yPix * xPix; + float realHeight = rect.height * yPix; + float realWidth = rect.width * xPix; + if (realWidth > fillterAndWidth && realHeight > fillterAndHeight && (realHeight > fillterOr || realWidth > fillterOr)) { + std::vector clsMatVec; + if (rHeight / rWidth > 20) { + clsMatVec = cutImg2ClsVec(rect, afterDingWei); + } + else { + cv::Mat clsMat = cutLabelImg(afterDingWei, 128, 128, rect, 1, 1, 0); + clsMatVec.push_back(clsMat); + } + + for (int mm = 0; mm < clsMatVec.size(); mm++) { + int clsResult = clsPtr->Evaluate(clsMatVec[mm]); + switch (clsResult) { + case 0: { + //OK + break; + } + case 1: { + //长气泡 + pixArea += cv::contourArea(contours[ii]); + drawDefectContours.push_back(contours[ii]); + QString defectStr = "缺陷宽:" + QString::number(realWidth, 'f', 3) + "mm高:" + QString::number(realHeight, 'f', 3) + "mm面积:" + QString::number(realArea, 'f', 3) + "mm²"; + textPainterCls.putText(Paint, defectStr.toStdString(), cv::Point(rect.x + rect.width / 2, rect.y + rect.height / 2), cv::Scalar(0, 255, 0)); + //cv::rectangle(Paint, rect, cv::Scalar(0, 0, 255), 3); + break; + } + case 2: { + //圆气泡 + drawOKContours.push_back(contours[ii]); + break; + } + case 3: { + //白气泡 + drawOKContours.push_back(contours[ii]); + break; + } + case 4: { + //其他 + drawOKContours.push_back(contours[ii]); + break; + } + default: + break; + } + } + + //cv::drawContours(Paint, contours, ii, cv::Scalar(0, 0, 255), 2); + //auto imgs = cutImg2ClsVec(rect, afterDingWei); + //for (int o = 0; o < imgs.size(); o++) { + // data->insertClsOriginImg({ std::make_pair(std::to_string(ii),imgs[o]) }); + // isNg = true; + // data->aiDetOK = false; + // + //} + //QString defectStr = "缺陷宽:" + QString::number(realWidth, 'f', 3) + "mm高:" + QString::number(realHeight, 'f', 3) + "mm面积:" + QString::number(realArea, 'f', 3) + "mm²"; + //textPainterCls.putText(Paint, defectStr.toStdString(), cv::Point(rect.x + rect.width / 2, rect.y + rect.height / 2), cv::Scalar(0, 0, 255));//cv::putText(Paint, std::to_string(ii), cv::Point(rect.x + rect.width / 2, rect.y + rect.height / 2), 1, 2, cv::Scalar(255, 255, 255), 5); + ////cv::rectangle(Paint, rect, cv::Scalar(0, 0, 255), 3); + } + } + + float pixAreaRate = pixArea / (afterDingWei.cols * afterDingWei.rows) * 100; + if (pixAreaRate > thresholdRate) { + for (int nn = 0; nn < drawDefectContours.size(); nn++) { + cv::drawContours(Paint, drawDefectContours, nn, cv::Scalar(0, 0, 255), 2); + cv::rectangle(Paint, cv::boundingRect(drawDefectContours[nn]), cv::Scalar(0, 0, 255), 3); + } + isNg = true; + } + else { + for (int nn = 0; nn < drawDefectContours.size(); nn++) { + cv::drawContours(Paint, drawDefectContours, nn, cv::Scalar(0, 255, 0), 2); + cv::rectangle(Paint, cv::boundingRect(drawDefectContours[nn]), cv::Scalar(0, 255, 0), 3); + } + } + + for (int nn = 0; nn < drawOKContours.size(); nn++) { + cv::drawContours(Paint, drawOKContours, nn, cv::Scalar(0, 255, 0), 2); + } + + int Rate = (Paint.rows > Paint.cols ? Paint.cols : Paint.rows) / 20; + TextRendererZH textPainter1(Paint.cols, Paint.rows, Rate); + textPainter1.putText(Paint, "气泡面积占比:" + QString::number(pixAreaRate, 'f', 2).toStdString() + "%", cv::Point(50, 500), cv::Scalar(0, 255, 255)); + textPainter1.putText(Paint, "产品条码:" + data->SNcode, cv::Point(50, Paint.rows - Rate), cv::Scalar(0, 255, 255)); + textPainter1.putText(Paint, "获取图像时间:" + createTime.toString("yyyy/MM/dd hh:mm:ss").toStdString(), cv::Point(50, Paint.rows - (Rate * 2)), cv::Scalar(0, 255, 255)); + QByteArray plcResult = "1"; + TextRendererZH textPainter(Paint.cols, Paint.rows, 300); + if (isNg == false) + { + textPainter.putText(Paint, "OK", cv::Point(500, 50), cv::Scalar(0, 255, 0)); + //data->service->_missionResultHandle->toBarChart(data->SNcode, isNg, { }); + } + else + { + defects.push_back("包膜下大面气泡"); + textPainter.putText(Paint, "NG", cv::Point(500, 50), cv::Scalar(0, 0, 255)); + plcResult = "2"; + //data->service->_missionResultHandle->toBarChart(data->SNcode, isNg, { "包膜后下大面NG" }); + } + if (data->service->_paramSyncManager->get("下大面", "下大面外观检测启用", false).toBool() == false) + plcResult = "1"; + if (data->service->_paramSyncManager->get("通用设置", "强制OK", false).toBool()) + plcResult = "1"; + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult); + data->service->_missionResultHandle->toBarChart(data->SNcode, defects); + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + data->insertResultImg(Paint); + return true; + } + CATCH_EXCEPTIONS; + ExceptionResume(data, address, "检测异常", "包膜后下大面"); + return true; +} \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam91011/581-BaoMo-Cam91011.h b/src/mission/581-BaoMo-Cam91011/581-BaoMo-Cam91011.h new file mode 100644 index 0000000..3d87099 --- /dev/null +++ b/src/mission/581-BaoMo-Cam91011/581-BaoMo-Cam91011.h @@ -0,0 +1,81 @@ +#include +#include +class baoMoHouDaMianDetParams { +public: + handdleAI::pSegmentation* chongHe_seg; + handdleAI::pClassification* ceMian_cls; +}; +class xiaDaMianParam { +public: + handdleAI::pSegmentation* dinggWei_seg = nullptr; + handdleAI::pSegmentation* qiPao_seg_gpu0 = nullptr; + handdleAI::pSegmentation* qiPao_seg_gpu1 = nullptr; + handdleAI::pClassification* qiPao_cls_gpu0 = nullptr; + handdleAI::pClassification* qiPao_cls_gpu1 = nullptr; +}; +#pragma region 算法 +#include +#include +#include +using namespace HDevEngineCpp; + +static bool ALGO_BaoMoHouXiaDaMian(std::shared_ptr data, xiaDaMianParam* _detParams, yh_581_address address); +static bool ALGO_BaoMoHouCeMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams,yh_581_address address); +#pragma endregion + +class _581_BaoMo : public mission { +public: + using baoMoHouDaMianTrigger = _581_Union_triggerTemplate; + baoMoHouDaMianTrigger _station_1; + baoMoHouDaMianTrigger _station_2; + std::vector < baoMoHouDaMianDetParams> _baoMoHouDaMianDetParams = std::vector < baoMoHouDaMianDetParams>(2); + + _581_Union_triggerTemplate _station_3; + xiaDaMianParam _xiaDaMianParam; + + bool initOnce = false; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgo/AlgoLibrary_602.hdpl"); + if (initOnce == false) { + _xiaDaMianParam.dinggWei_seg = handdleAI::CreateSegObjS("./handleAiModels/xiaDaMianDingWei_seg.BHD",16,0); + _xiaDaMianParam.qiPao_seg_gpu0 = handdleAI::CreateSegObjS("./handleAiModels/qiPao_seg.BHD", 16, 0); + _xiaDaMianParam.qiPao_seg_gpu1 = handdleAI::CreateSegObjS("./handleAiModels/qiPao_seg.BHD", 16, 1); + _xiaDaMianParam.qiPao_cls_gpu0 = handdleAI::CreateClsObjV3("./handleAiModels/qiPao_cls.BHD", 0, 1); + _xiaDaMianParam.qiPao_cls_gpu1 = handdleAI::CreateClsObjV3("./handleAiModels/qiPao_cls.BHD", 1, 1); + + _baoMoHouDaMianDetParams[0].chongHe_seg = handdleAI::CreateSegObjS("./handleAiModels/chongHe_seg.BHD", 16, 0); + _baoMoHouDaMianDetParams[1].chongHe_seg = handdleAI::CreateSegObjS("./handleAiModels/chongHe_seg.BHD", 16, 1); + _baoMoHouDaMianDetParams[0].ceMian_cls = handdleAI::CreateClsObjV3("./handleAiModels/ceMian_cls.BHD", 0, 1); + _baoMoHouDaMianDetParams[1].ceMian_cls = handdleAI::CreateClsObjV3("./handleAiModels/ceMian_cls.BHD", 1, 1); + initOnce = true; + } + } + bool initCustom() { + +#pragma region 注册触发器回调 + + _station_1.init("Camera1","包膜后侧面贴胶错位检测-外-相机9",19600,2,1,&_baoMoHouDaMianDetParams[0], _serviceManager, bridge, ALGO_BaoMoHouCeMian); + + + _station_2.init("Camera2", "包膜后侧面贴胶错位检测-内-相机10",19800,2,1, &_baoMoHouDaMianDetParams[1], _serviceManager, bridge, ALGO_BaoMoHouCeMian); + + + _station_3.init("Camera3", "包膜后外观检测大面相机11(下大面)",20000,2,1, &_xiaDaMianParam, _serviceManager, bridge, ALGO_BaoMoHouXiaDaMian); + +#pragma endregion + return true; + } + void reloadAlgo(QByteArray& byteArray) { + + } + + //9600 + +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam91011/CMakeLists.txt b/src/mission/581-BaoMo-Cam91011/CMakeLists.txt new file mode 100644 index 0000000..76e9200 --- /dev/null +++ b/src/mission/581-BaoMo-Cam91011/CMakeLists.txt @@ -0,0 +1,77 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "opencv" "halcon" "handdleAI") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + ${PROJECT_ROOT_PATH}/src/core + ${PROJECT_ROOT_PATH}/src/core/handleAi + ${PROJECT_ROOT_PATH}/src/core/service + ${PROJECT_ROOT_PATH}/src/core/sql + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) +add_compile_options(/utf-8) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC OFF) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ${PROJECT_ROOT_PATH}/include/interface.h + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Network + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " modelx end : " ${CURRENT_FOLDER}:${RUN_TIME}) +message( " header files "${HEAD_FILES}) diff --git a/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h index 5452974..101e2b7 100644 --- a/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h +++ b/src/mission/581-Mfd_yh_mh_hh/581-Mfd.h @@ -76,17 +76,19 @@ static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; ///////////////////取图//处理////////////////// - if (data->getOriImgSize() != 1) + if (data->getOriImgSize() < 1) { - qCritical() << "图片数量不满足要求:" << data->getOriImgSize(); + exceptionResume(data, address,"图片数量不满足要求"); + qDebug() << "图片数量不满足要求:" << data->getOriImgSize(); return false; } // QDateTime currentimenow = QDateTime::currentDateTime(); + qDebug() << "Start1" << QString::fromStdString(data->SNcode); cv::Mat Paint; cv::Mat src1 = data->getOriImg(0); //src1 = cv::imread("D:\\密封钉CCD存图\\2025-12-14\\满焊CCD原图\\10H\\OK\\相机3孔5\\A100000485_Camera5_0_10-12-45.bmp", -1); - //src1 = cv::imread("D:\\readSnEmpty14-53-27-65_Camera3_0_14-53-27.bmp", -1); + //src1 = cv::imread("D:\\04QCB82602000JG1300507BN_Camera3_ORI_0_04-15-03-197.bmp", -1); if (src1.channels() != 3) cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); else @@ -127,9 +129,11 @@ static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh cameraNumberStr = "4"; FixtureNumber = "8"; } + qDebug() << "Start2" << QString::fromStdString(data->SNcode); data->customPath = "{imgSaveRootDir}/{yyyy-MM-dd}/{saveObjectName}{imageType}/{HH}H/{processResult}/相机" + QString::fromStdString(cameraNumberStr) + "孔" + QString::fromStdString(FixtureNumber); int ManHanbiaoding_Switch = data->service->_paramSyncManager->get("满焊", "模式选择:1标定0生产", 0).toInt(); - data->service->_paramSyncManager->edit("满焊","模式选择:1标定0生产", 0); + if(ManHanbiaoding_Switch == 1) + data->service->_paramSyncManager->edit("满焊","模式选择:1标定0生产", 0); HalconCpp::HObject in_Image = MatToHObject(src1); HDevEngineCpp::HDevProcedure proc("_9_manhan"); @@ -141,9 +145,9 @@ static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh procedureCall.SetInputCtrlParamTuple("in_FilePath1", HTuple(("./halconFiles/template_manHan/" + data->cameraKeyName + "/").c_str())); procedureCall.SetInputCtrlParamTuple("in_FilePath2", HTuple("./halconFiles/base_manHan/")); procedureCall.SetInputCtrlParamTuple("in_LineType", "602"); - qDebug() << "halconStart"; + qDebug() << "halconStart" << QString::fromStdString(data->SNcode); procedureCall.Execute(); - qDebug() << "halconEnd"; + qDebug() << "halconEnd" << QString::fromStdString(data->SNcode); // *output(HTuple) : < / c> // *out_Circle, 圆心坐标(y, x, radius) < / c > // * out_Flag, 算法执行成功标志位, 0 : 算法执行失败 1 : 算法执行成功< / c> @@ -246,7 +250,7 @@ static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh textPainter.putText(Paint, "NG", cv::Point(50, 500), cv::Scalar(0, 0, 255)); sqlMapData["结果"] = "NG"; } - data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), sqlMapData); + data->service->_dataRecorder->addData(QString::fromStdString(data->SNcode), sqlMapData); //int rate = MIN(Paint.cols, Paint.rows) / 20; //TextRendererZH textPainter2(Paint.cols, Paint.rows, rate); @@ -257,7 +261,9 @@ static bool ManHan(std::shared_ptr data, mfd_detParams* _detParams, yh return true; } CATCH_EXCEPTIONS + qDebug() << "error3" << QString::fromStdString(data->SNcode); exceptionResume(data, address, "异常"); + return false; } static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_581_address address) { try { @@ -265,13 +271,13 @@ static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_ sqlMapData["项目"] = "预焊"; sqlMapData["相机"] = "相机" + address.triggerAddr; ///////////////////取图//处理////////////////// - if (data->getOriImgSize() != 1) { - qCritical() << "图片数量不满足要求:" << data->getOriImgSize(); + if (data->getOriImgSize() < 1) { + exceptionResume(data, address, "图片数量不满足要求"); + qDebug() << "图片数量不满足要求:" << data->getOriImgSize(); return false; } /*QDateTime currentimenow = QDateTime::currentDateTime();*/ - cv::Mat Paint; cv::Mat src1 = data->getOriImg(0); //src1 = cv::imread("D:\\04QCB82602000JFCA00600BN_Camera1_0_04-18-02.bmp",-1); @@ -299,14 +305,21 @@ static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_ cameraNumberStr = "2"; FixtureNumber = "4"; } + qDebug() << "Start1" << QString::fromStdString(data->SNcode); data->customPath = "{imgSaveRootDir}/{yyyy-MM-dd}/{saveObjectName}{imageType}/{HH}H/{processResult}/相机" + QString::fromStdString(cameraNumberStr) + "孔" + QString::fromStdString(FixtureNumber);; + qDebug() << "Start2" << QString::fromStdString(data->SNcode); + int pingDing_aoDing_Switch = data->service->_paramSyncManager->get("预焊","1平钉2凹钉", 2).toInt(); int YuHanbiaoding_Switch = data->service->_paramSyncManager->get("预焊","模式选择:1标定0生产", 0).toInt(); - data->service->_paramSyncManager->edit("预焊", "1标定0生产", 0); + if(YuHanbiaoding_Switch == 1) + data->service->_paramSyncManager->edit("预焊", "1标定0生产", 0); double tongXingJuThreshold = data->service->_paramSyncManager->get("预焊", "同心距上限", 0.1).toDouble(); + qDebug() << "Start3" << QString::fromStdString(data->SNcode); HDevEngineCpp::HDevProcedure proc("_9_yuhan"); + qDebug() << "Start4" << QString::fromStdString(data->SNcode); HalconCpp::HObject in_Image = MatToHObject(src1); HDevProcedureCall procedureCall(proc); + qDebug() << "Start5" << QString::fromStdString(data->SNcode); procedureCall.SetInputIconicParamObject("in_Image", in_Image); procedureCall.SetInputCtrlParamTuple("in_ProductionType", YuHanbiaoding_Switch); procedureCall.SetInputCtrlParamTuple("in_Resolution", HTuple(0.0069699)); @@ -316,7 +329,9 @@ static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_ procedureCall.SetInputCtrlParamTuple("in_FilePath2", HTuple("./halconFiles/base_yuhan/")); procedureCall.SetInputCtrlParamTuple("in_NailType", pingDing_aoDing_Switch);//1:平钉 2:凹钉; //procedureCall.SetInputCtrlParamTuple("in_LineType", "602"); + procedureCall.Execute(); + // *output(HTuple) : < / c> // *out_Circle, 圆心坐标(y, x, radius) < / c > // * out_Flag, 算法执行成功标志位, 0 : 算法执行失败 1 : 算法执行成功< / c> @@ -410,7 +425,7 @@ static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_ textPainter.putText(Paint, "NG", cv::Point(50, 950), cv::Scalar(0, 0, 255)); sqlMapData["结果"] = "NG"; } - data->service->_csvWriter->addData(QString::fromStdString(data->SNcode), sqlMapData); + data->service->_dataRecorder->addData(QString::fromStdString(data->SNcode), sqlMapData); //int rate = MIN(Paint.cols, Paint.rows) / 20; //TextRendererZH textPainter2(Paint.cols, Paint.rows, rate); @@ -422,12 +437,14 @@ static bool YuHan(std::shared_ptr data, mfd_detParams* _detParams, yh_ return true; } CATCH_EXCEPTIONS + qDebug() << "error" << QString::fromStdString(data->SNcode); exceptionResume(data, address, "异常"); + return false; } -bool aiEvaluate(std::shared_ptr data, cv::Mat& input,cv::Mat& Paint,cv::Point center,int index, mfd_hh_models* models,cv::Size fillter) { +bool aiEvaluate(std::shared_ptr data, cv::Mat& input,cv::Mat& Paint,int index, mfd_hh_models* models,cv::Size fillter) { try { - HDevEngineCpp::HDevProcedure proc("Crop_Inspection_Image"); + HDevEngineCpp::HDevProcedure proc("_9_Crop_Inspection_Image_HJ"); HalconCpp::HObject in_Image_2D = MatToHObject(input); HDevProcedureCall procedureCall(proc); procedureCall.SetInputIconicParamObject("in_Image", in_Image_2D); @@ -438,7 +455,7 @@ bool aiEvaluate(std::shared_ptr data, cv::Mat& input,cv::Mat& Paint,cv HTuple out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle"); HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); cv::Mat forSeg = HObject2Mat(out_InspectionImage); - forSeg(cv::Rect(center.x - 650, center.y - 650, 1300, 1300)).copyTo(forSeg); + //forSeg(cv::Rect(center.x - 650, center.y - 650, 1300, 1300)).copyTo(forSeg); cv::resize(forSeg, forSeg, cv::Size(), 0.5, 0.5); data->insertSegOriginImg(forSeg); cv::Mat segResult = ~models->seg_hanHou->Evaluate(forSeg); @@ -456,7 +473,7 @@ bool aiEvaluate(std::shared_ptr data, cv::Mat& input,cv::Mat& Paint,cv double prob = models->cls_hanHou->getProbability(); clsImgs.push_back({ "Result" + std::to_string(clsResult) + "_prob" + std::to_string(prob),clsImg }); if (clsResult != 0 && prob > 0.6) { - cv::drawContours(Paint, contours, i, cv::Scalar(0, 0, 255), 3, 8, cv::noArray(), INT_MAX, cv::Point(center.x - 650, center.y - 650)); + cv::drawContours(Paint, contours, i, cv::Scalar(0, 0, 255), 3, 8, cv::noArray(), INT_MAX); std::string text; switch (clsResult) { @@ -473,7 +490,7 @@ bool aiEvaluate(std::shared_ptr data, cv::Mat& input,cv::Mat& Paint,cv text = "焊烟"; break; } - textPainter.putText(Paint, text, cv::Point(center.x - 650, center.y - 800), cv::Scalar(0, 0, 255)); + textPainter.putText(Paint, text, cv::Point(0,0), cv::Scalar(0, 0, 255)); isNg = true; } } @@ -508,7 +525,7 @@ static bool HanHou2D(std::shared_ptr data, mfdHanHouParam* _detParams, segResult = _detParams->models[address.index].seg_hanHouDingWei->Evaluate(forHalcon); data->insertSegOriginImg(segResult); _detParams->waitImage(heightImg); - HDevEngineCpp::HDevProcedure proc("Cal_2D_3D_PostWelding"); + HDevEngineCpp::HDevProcedure proc("_9_Cal_2D_3D_PostWelding"); HDevProcedureCall procedureCall(proc); HalconCpp::HObject in_Image_2D = MatToHObject(forHalcon); @@ -530,42 +547,61 @@ static bool HanHou2D(std::shared_ptr data, mfdHanHouParam* _detParams, OffsetValue.Append(0); procedureCall.SetInputCtrlParamTuple("in_offsetValue", OffsetValue); procedureCall.Execute(); - + qDebug() << "test flagxxx1"; HTuple out_CC_Distance = procedureCall.GetOutputCtrlParamTuple("out_CC_Distance"); + qDebug() << "test flagxxx2"; HTuple out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle"); - HTuple out_DefectHeight = procedureCall.GetOutputCtrlParamTuple("out_DefectHeight"); - HTuple Out_Angle = procedureCall.GetOutputCtrlParamTuple("Out_Angle"); + qDebug() << "test flagxxx3"; + HTuple out_DefectHeight = procedureCall.GetOutputCtrlParamTuple("out_MFDHeight"); + qDebug() << "test flagxxx4"; + HTuple Out_Angle = procedureCall.GetOutputCtrlParamTuple("out_Angle"); + qDebug() << "test flagxxx5"; HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + qDebug() << "test flagxxx6"; + HTuple out_NgDetails = procedureCall.GetOutputCtrlParamTuple("out_NgDetails"); #pragma endregion + qDebug() << "test flag1"; int outFlag = out_Flag.D(); QByteArray plcResult = "1"; TextRendererZH textPainter(Paint.cols, Paint.rows, 100); if (outFlag == 1) { //-1为失败,无结果 cv::Mat forHanddleAi; + qDebug() << "test flag2"; double CC_Distance = out_CC_Distance.D(); - cv::Point2f center1(out_Circle[1].D(), out_Circle[0].D()), center2(out_Circle[4].D(), out_Circle[3].D()); - double radius1 = out_Circle[2].D(), radius2 = out_Circle[5].D(); + qDebug() << "test flag3"; + for (int i = 0; i < out_Circle.Length() / 3; i++) { + cv::Point2f center1(out_Circle[i * 3 + 1].D(), out_Circle[i * 3].D()); + double radius1 = out_Circle[i * 3 + 2].D(); + cv::circle(Paint, center1 / 2, radius1 / 2, cv::Scalar(0, 255, 0), 3); + } + + qDebug() << "test flag5"; double defectHeight = out_DefectHeight.D();//密封钉高度 + qDebug() << "test flag6"; double angle = Out_Angle.D();//密封钉角度 textPainter.putText(Paint, "密封钉高度:" + std::to_string(defectHeight), cv::Point(50, 0), cv::Scalar(0, 255, 0)); textPainter.putText(Paint, "密封钉角度:" + std::to_string(angle), cv::Point(50, 350), cv::Scalar(0, 255, 0)); textPainter.putText(Paint, "密封钉同心距:" + std::to_string(CC_Distance), cv::Point(50, 550), cv::Scalar(0, 255, 0)); - bool result = aiEvaluate(data, src1,Paint, center1, address.index, &_detParams->models[address.index], + + bool result = aiEvaluate(data, src1,Paint, address.index, &_detParams->models[address.index], cv::Size(data->service->_paramSyncManager->get("焊后", "过滤宽(pix)", 50).toDouble(), data->service->_paramSyncManager->get("焊后", "过滤高(pix)", 50).toDouble())); + qDebug() << "test flag7"; if (result == false && data->service->_paramSyncManager->get("焊后", "模型判定启用", false).toBool()) plcResult = "2"; - cv::circle(Paint, center1 / 2, radius1 / 2, cv::Scalar(0, 255, 0), 3); - cv::circle(Paint, center2 / 2, radius2 / 2, cv::Scalar(0, 255, 0), 3); - + + //cv::circle(Paint, center2 / 2, radius2 / 2, cv::Scalar(0, 255, 0), 3); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(CC_Distance));//发送同心距 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(defectHeight));//发送密封钉高度 } else { data->halconOK = false; textPainter.putText(Paint, "NG", cv::Point(50, 300), cv::Scalar(0, 0, 255)); + textPainter.putText(Paint, std::to_string(out_NgDetails.D()), cv::Point(50, 450), cv::Scalar(0, 0, 255)); } data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - data->insertResultImg(Paint); + data->insertResultImg(Paint); return true; } @@ -633,8 +669,8 @@ public: mh_3.init("Camera5", "满焊3", 20400, 2, 1, &_params, _serviceManager, bridge, ManHan, "满焊CCD"); mh_4.init("Camera6", "满焊4", 20600, 2, 1, &_params, _serviceManager, bridge, ManHan, "满焊CCD"); - hh_2D.init("Camera7", "焊后2d", 20800, 4, 1, &_hhParams, _serviceManager, bridge, HanHou2D, "焊后CCD"); - hh_3D.init("Camera8", "焊后3d", 21000, 4, 1, &_hhParams, _serviceManager, bridge, HanHou3D, "焊后CCD"); + hh_2D.init("Camera7", "焊后2d", 20800, 4, 1, &_hhParams, _serviceManager, bridge, HanHou2D, "焊后2D"); + hh_3D.init("Camera8", "焊后3d", 21000, 4, 1, &_hhParams, _serviceManager, bridge, HanHou3D, "焊后3D"); #pragma endregion return true; } diff --git a/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt b/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt index 599e8f5..76e9200 100644 --- a/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt +++ b/src/mission/581-Mfd_yh_mh_hh/CMakeLists.txt @@ -40,8 +40,8 @@ FILE(GLOB UI_FILES "./*.ui") #find_package(Qt5 COMPONENTS Core REQUIRED) -find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Sql REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network REQUIRED) add_library(${CURRENT_FOLDER} SHARED ${HEAD_FILES} @@ -64,7 +64,6 @@ target_link_libraries(${CURRENT_FOLDER} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Network - Qt${QT_VERSION_MAJOR}::Sql ) diff --git a/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.cpp b/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.cpp index 27c789d..73f25c8 100644 --- a/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.cpp +++ b/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.cpp @@ -207,16 +207,16 @@ bool HanQianDingWei(std::shared_ptr data, hanQianDingWeiParams* _detPa qDebug() << "[Error] " << QString::fromUtf8("检测失败!"); return false; } -struct halconResult { +struct halconResult_2D { bool isNg = false; double TongXingDu = -99; double neiYuanPianYi_X = -99, neiYuanPianYi_Y = -99, neiYuanTongXinDu = -99; double waiYuanPianYi_X = -99, waiYuanPianYi_Y = -99, waiYuanTongXinDu = -99; bool halconOK = false; }; -halconResult HanHou2D_halconEvaluate(const cv::Mat& sourceImg,const cv::Mat& segImg, TextRendererZH* textPainter, int times, +halconResult_2D HanHou2D_halconEvaluate(const cv::Mat& sourceImg,const cv::Mat& segImg, TextRendererZH* textPainter, int times, double tongXingDuLimitHigh, double tongXingDuLimitLow, bool tongXingDuLimitEnable) { - halconResult result; + halconResult_2D result; HDevEngineCpp::HDevProcedure proc("_3_Cal_HY_CC_Distance"); HDevEngineCpp::HDevProcedureCall procedureCall(proc); @@ -340,7 +340,6 @@ QByteArray getHanHouJianCe2DSendResult(bool isNg1,bool isNg2) { bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address){ try { - #pragma region 错误处理 if (data->getOriImgSize() < 2) { @@ -362,12 +361,10 @@ bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx return true; } #pragma endregion - data->service->_paramSyncManager->edit("12", "123", 0.8); - return true; cv::Mat src1 = data->getOriImg(0); cv::Mat src2 = data->getOriImg(1); - src1 = cv::imread("D:\\testImage\\rlj_hh_t.bmp",-1); - src2 = cv::imread("D:\\testImage\\L_HANZHA_100u.bmp", -1); + //src1 = cv::imread("D:\\testImage\\T.bmp",-1); + //src2 = cv::imread("D:\\testImage\\L_OK.bmp", -1); cv::Mat Paint1, Paint2; src1.copyTo(Paint1); src2.copyTo(Paint2); @@ -385,17 +382,20 @@ bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx QMutex mutex1, mutex2; cv::resize(src1, forSeg1, cv::Size(), resizeRate, resizeRate); - cv::Mat seg1 = ~_detParams->seg_rljHanYinZhuaQu->Evaluate(forSeg1); - data->insertSegOriginImg(seg1); - cv::Rect tongRect = findMaxAreaContour(seg1); + cv::Mat seg1Ori = _detParams->seg_rljHanYinZhuaQu->Evaluate(forSeg1);//原始SEG 抓取区域为黑色 + cv::Mat seg1Uminus = ~seg1Ori;//取反后的SEG 抓取区域为白色 + data->insertSegOriginImg(seg1Ori); + data->insertSegOriginImg(seg1Uminus); + cv::Rect tongRect = findMaxAreaContour(seg1Uminus); if (tongRect.width < 100 || tongRect.height < 100) { isNg1 = true; } cv::resize(src2, forSeg2, cv::Size(), resizeRate, resizeRate); - cv::Mat seg2 = ~_detParams->seg_rljHanYinZhuaQu->Evaluate(forSeg2); - data->insertSegOriginImg(seg2); - cv::Rect lvRect = findMaxAreaContour(seg2); + cv::Mat seg2Ori = _detParams->seg_rljHanYinZhuaQu->Evaluate(forSeg2);//原始SEG 抓取区域为黑色 + cv::Mat seg2Uminus = ~seg2Ori;//取反后的SEG 抓取区域为白色 + data->insertSegOriginImg(seg2Ori); + cv::Rect lvRect = findMaxAreaContour(seg2Uminus); if (lvRect.width < 100 || lvRect.height < 100) { isNg2 = true; } @@ -417,8 +417,8 @@ bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx 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, ~seg1, &textPainter1, 0, tongXingDuLimitHigh, tongXingDuLimitLow, tongXingDuLimitEnable); - auto futrue2 = std::async(std::launch::async, &HanHou2D_halconEvaluate, src2, ~seg2, &textPainter2, 2, tongXingDuLimitHigh, tongXingDuLimitLow, tongXingDuLimitEnable); + 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 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); @@ -496,21 +496,21 @@ bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx putSnAndDetTime(PaintSum, data->SNcode, 120); data->insertResultImg(PaintSum); #pragma region 处理SQL数据 - data->sqlVec.insert({ "铜-焊印同心度",halconResult1.TongXingDu }); - data->sqlVec.insert({ "铜-内圆同心度",halconResult1.neiYuanTongXinDu }); - data->sqlVec.insert({ "铜-内圆偏移X",halconResult1.neiYuanPianYi_X }); - data->sqlVec.insert({ "铜-内圆偏移Y",halconResult1.neiYuanPianYi_Y }); - data->sqlVec.insert({ "铜-外圆同心度",halconResult1.waiYuanPianYi_X }); - data->sqlVec.insert({ "铜-外圆偏移X",halconResult1.waiYuanPianYi_Y }); - data->sqlVec.insert({ "铜-外圆偏移Y",halconResult1.waiYuanTongXinDu }); + data->sqlVec.insert({ "铜焊印同心度",halconResult1.TongXingDu }); + data->sqlVec.insert({ "铜内圆同心度",halconResult1.neiYuanTongXinDu }); + data->sqlVec.insert({ "铜内圆偏移X",halconResult1.neiYuanPianYi_X }); + data->sqlVec.insert({ "铜内圆偏移Y",halconResult1.neiYuanPianYi_Y }); + data->sqlVec.insert({ "铜外圆同心度",halconResult1.waiYuanPianYi_X }); + data->sqlVec.insert({ "铜外圆偏移X",halconResult1.waiYuanPianYi_Y }); + data->sqlVec.insert({ "铜外圆偏移Y",halconResult1.waiYuanTongXinDu }); - data->sqlVec.insert({ "铝-焊印同心度",halconResult2.TongXingDu }); - data->sqlVec.insert({ "铝-内圆同心度",halconResult2.neiYuanTongXinDu }); - data->sqlVec.insert({ "铝-内圆偏移X",halconResult2.neiYuanPianYi_X }); - data->sqlVec.insert({ "铝-内圆偏移Y",halconResult2.neiYuanPianYi_Y }); - data->sqlVec.insert({ "铝-外圆同心度",halconResult2.waiYuanPianYi_X }); - data->sqlVec.insert({ "铝-外圆偏移X",halconResult2.waiYuanPianYi_Y }); - data->sqlVec.insert({ "铝-外圆偏移Y",halconResult2.waiYuanTongXinDu }); + data->sqlVec.insert({ "铝焊印同心度",halconResult2.TongXingDu }); + data->sqlVec.insert({ "铝内圆同心度",halconResult2.neiYuanTongXinDu }); + data->sqlVec.insert({ "铝内圆偏移X",halconResult2.neiYuanPianYi_X }); + data->sqlVec.insert({ "铝内圆偏移Y",halconResult2.neiYuanPianYi_Y }); + data->sqlVec.insert({ "铝外圆同心度",halconResult2.waiYuanPianYi_X }); + data->sqlVec.insert({ "铝外圆偏移X",halconResult2.waiYuanPianYi_Y }); + data->sqlVec.insert({ "铝外圆偏移Y",halconResult2.waiYuanTongXinDu }); #pragma endregion return true; @@ -522,6 +522,48 @@ bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx } +struct halconResult_3D { + bool isNg = false; + double hanPanGaoDu = -99; + cv::Point ellipseCenter; + double angle; + cv::Size ellipseSize; + bool halconOK = false; +}; +halconResult_3D HanHou3D_halconEvaluate(const cv::Mat& heightImg, const double& xResolution, const double& yResolution, const double& zResolution + , TextRendererZH* textPainter) { + halconResult_3D result; + + HDevEngineCpp::HDevProcedure proc("_3_Inspection_HY_Defect"); + HDevEngineCpp::HDevProcedureCall procedureCall(proc); + + HObject in_ImageH = MatToHObject(heightImg); + procedureCall.SetInputIconicParamObject("in_ImageH", in_ImageH); + procedureCall.SetInputCtrlParamTuple("in_XResolution", xResolution); + procedureCall.SetInputCtrlParamTuple("in_YResolution", yResolution); + procedureCall.SetInputCtrlParamTuple("in_ZResolution", zResolution); + procedureCall.SetInputCtrlParamTuple("in_FliePath", "./halconFiles/"); + 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");//获取输出控制类变量 + int flag = out_Flag.D(); + if (flag == 1) { + + 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()); + } + else { + textPainter->appendPaintJob("算法NG:" + std::to_string(out_NGDetails[0].D()), cv::Point(10, 50), cv::Scalar(0, 0, 255)); + result.isNg = true; + result.halconOK = false; + } + return result; +} bool HanHouJianCe3D(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address) { try { data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 @@ -544,18 +586,39 @@ bool HanHouJianCe3D(std::shared_ptr data, hanHouJianCe* _detParams, sx QMutex paintMutex; clock_t start, finish; start = clock(); - cv::Mat src1 = data->getOriImg(0); - cv::Mat src2 = data->getOriImg(2); - cv::Mat Paint; - cv::vconcat(src1, src2, Paint); - if (src1.channels() != 3) - cv::cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); - putSnAndDetTime(Paint, data->SNcode, 60); - TextRendererZH textPainter(Paint.cols, Paint.rows, 300); - textPainter.putText(Paint, "OK", cv::Point(10, 10), cv::Scalar(0, 255, 0)); + cv::Mat src1 = data->getOriImg(0);//亮度图1 + 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, + 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, + 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(), + &textPainter2); + cv::Mat Paint1, Paint2, PaintSum; + src1.copyTo(Paint1); + src2.copyTo(Paint2); + if (Paint1.channels() != 3) + cv::cvtColor(Paint1, Paint1, cv::COLOR_GRAY2BGR); + if (Paint2.channels() != 3) + cv::cvtColor(Paint2, Paint2, cv::COLOR_GRAY2BGR); + textPainter1.putText(Paint1, "OK", cv::Point(10, 10), cv::Scalar(0, 255, 0)); + textPainter1.excusePaintJobs(Paint1); + textPainter2.putText(Paint2, "OK", cv::Point(10, 10), cv::Scalar(0, 255, 0)); + textPainter1.excusePaintJobs(Paint2); + cv::vconcat(Paint1, Paint2, PaintSum); + putSnAndDetTime(PaintSum, data->SNcode, 60); + + //cv::putText(Paint, "pos:" + data->additional["触发地址"].toString().toStdString(), cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0), 2); //data->service->_missionResultHandle->toBarChart(data->SNcode, !defects.size() > 0, defects);//发送图标操作 - data->insertResultImg(Paint); + data->insertResultImg(PaintSum); return true; } CATCH_EXCEPTIONS diff --git a/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.h b/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.h index 8a72561..591e235 100644 --- a/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.h +++ b/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.h @@ -51,7 +51,7 @@ public: if (initOnce == false) { - /*hanhoujiance2dparams[0].seg_rljHanYinZhuaQu = handdleAI::CreateSegObjS("./handleAiModels/seg_rljHanYinZhuaQu.BHD", 64, 0); + hanhoujiance2dparams[0].seg_rljHanYinZhuaQu = handdleAI::CreateSegObjS("./handleAiModels/seg_rljHanYinZhuaQu.BHD", 64, 0); hanhoujiance2dparams[1].seg_rljHanYinZhuaQu = handdleAI::CreateSegObjS("./handleAiModels/seg_rljHanYinZhuaQu.BHD", 64, 1); hanhoujiance2dparams[0].seg_rljHanZha1 = handdleAI::CreateSegObjS("./handleAiModels/seg_rljHanZha.BHD", 64, 0); @@ -68,7 +68,7 @@ public: hanhoujiance2dparams[1].cls_hanYinTong = handdleAI::CreateClsObjV3("./handleAiModels/cls_hanYinTong.BHD", 1, 1); hanhoujiance2dparams[0].cls_hanYinLv = handdleAI::CreateClsObjV3("./handleAiModels/cls_hanYinLv.BHD", 0, 1); - hanhoujiance2dparams[1].cls_hanYinLv = handdleAI::CreateClsObjV3("./handleAiModels/cls_hanYinLv.BHD", 1, 1);*/ + hanhoujiance2dparams[1].cls_hanYinLv = handdleAI::CreateClsObjV3("./handleAiModels/cls_hanYinLv.BHD", 1, 1); initOnce = true; } } diff --git a/src/mission/581_YuHan_hanqian/581_YuHan_hanqian.cpp b/src/mission/581_YuHan_hanqian/581_YuHan_hanqian.cpp new file mode 100644 index 0000000..3874af8 --- /dev/null +++ b/src/mission/581_YuHan_hanqian/581_YuHan_hanqian.cpp @@ -0,0 +1,8 @@ +#include <581_YuHan_hanqian.h> + +mission* createMission() { + return new _581_YuHan_hanqian(); +} +void destroyMission(mission* _mission) { + delete _mission; +} \ No newline at end of file diff --git a/src/mission/581_YuHan_hanqian/581_YuHan_hanqian.h b/src/mission/581_YuHan_hanqian/581_YuHan_hanqian.h new file mode 100644 index 0000000..2059c63 --- /dev/null +++ b/src/mission/581_YuHan_hanqian/581_YuHan_hanqian.h @@ -0,0 +1,294 @@ +#include +#include +#pragma region 算法 +#include +#include +#include +using namespace HDevEngineCpp; +#pragma endregion +class yuHanHanQianParams { +public: + handdleAI::pSegmentation* segDingWei = nullptr; + + handdleAI::pSegmentation* segJiErFanZhe = nullptr; + handdleAI::pClassification* clsJiErFanZhe = nullptr; + handdleAI::pClassification* clsOverView = nullptr; + bool isTong = true; +}; +void putSnAndDetTime(cv::Mat& Paint,const std::string& sn,int textSize = 30, const std::string& extraText = "") { + TextRendererZH textPainter(Paint.cols, Paint.rows, textSize); + textPainter.putText(Paint, "SN:" + sn + " time:" + QDateTime::currentDateTime().toString().toStdString() + extraText, cv::Point(0, Paint.rows - textSize), cv::Scalar(0, 255, 0)); +} +cv::Rect getImageLocateRect(cv::Mat& src, handdleAI::pSegmentation* seg, double bounus = 0.1) { + cv::Mat tmpImg; + cv::resize(src, tmpImg, cv::Size(), bounus, bounus); + cv::Mat ouput = ~seg->Evaluate(tmpImg); + cv::erode(ouput, ouput, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(15, 15))); + cv::dilate(ouput, ouput, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(15, 15))); + auto rect = findMaxAreaContour(ouput); + rect.x /= bounus; rect.y /= bounus; + rect.width /= bounus; rect.height /= bounus; + return rect; +} +bool handleAiProcess(cv::Mat& seg_detImg, cv::Mat& seg_Paint, + handdleAI::pSegmentation* segPtr, handdleAI::pClassification* clsPtr, + std::vector< std::pair >& clsImgs,double probThreshold,cv::Size fillter = cv::Size(300,300)){ + cv::Mat segResizeImg; + float resizeRate = 1.0; + cv::resize(seg_detImg, segResizeImg, cv::Size(), 1.0 / resizeRate, 1.0 / resizeRate); + cv::Mat seg_ResultImg = ~segPtr->Evaluate(segResizeImg); + cv::resize(seg_ResultImg, seg_ResultImg, cv::Size(), resizeRate, resizeRate); + cv::erode(seg_ResultImg, seg_ResultImg, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(15, 15))); + cv::dilate(seg_ResultImg, seg_ResultImg, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(15, 15))); + std::vector> contours; + cv::findContours(seg_ResultImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + bool finalNg = false; + TextRendererZH textPainter(seg_Paint.cols, seg_Paint.rows, 20); + clsImgs.push_back({ "seg" ,seg_ResultImg }); + for (int i = 0; i < contours.size(); i++) + { + cv::Rect cls_rect = cv::boundingRect(contours[i]); + if (cls_rect.width > fillter.width && cls_rect.height > fillter.height) { + std::vector clsImgVec = cutImg2ClsVec(cls_rect, seg_detImg); + std::vector clsRes;//true ok + bool isNg = false; + double maxNgProb = 0.0; + for (auto& cls : clsImgVec) { + cv::resize(cls, cls, cv::Size(128, 128));//根据需要设定大小 + int Result = clsPtr->Evaluate(cls); + double prob = clsPtr->getProbability(); + if (Result != 0 && prob > probThreshold) { + isNg = true; + maxNgProb = std::max(maxNgProb, prob); + } + clsRes.push_back(Result); + clsImgs.push_back({ "Result" + std::to_string(Result) + "_prob" + std::to_string(prob) ,cls }); + } + { + cv::Mat testCls; + cv::resize(seg_detImg(cls_rect), testCls, cv::Size(128, 128)); + int Result = clsPtr->Evaluate(testCls); + double prob = clsPtr->getProbability(); + if (Result != 0 && prob > probThreshold) { + isNg = true; + maxNgProb = std::max(maxNgProb, prob); + } + clsImgs.push_back({ "testClsResult" + std::to_string(Result) + "_prob" + std::to_string(prob),testCls }); + } + if (isNg == true) { + cv::Scalar color = cv::Scalar(0, 255, 255, 30); + textPainter.putText(seg_Paint, "w" + std::to_string(cls_rect.width) + + " h" + std::to_string(cls_rect.height) + + " a" + std::to_string(cv::contourArea(contours[i])) + + " p" + std::to_string(maxNgProb) + , cv::Point(cls_rect.x, cls_rect.y), cv::Scalar(255, 255, 0)); + cv::rectangle(seg_Paint, cls_rect, color, 4); + drawContours(seg_Paint, contours, i, cv::Scalar(0, 0, 255, 30), 3); + finalNg = true; + } + else { + drawContours(seg_Paint, contours, i, cv::Scalar(0, 255, 0, 30), 3); + } + } + else if (cls_rect.width > 100 && cls_rect.height > 100) { + std::vector clsImgVec = cutImg2ClsVec(cls_rect, seg_detImg); + std::vector clsRes;//true ok + double maxNgProb = 0.0; + for (auto& cls : clsImgVec) { + cv::resize(cls, cls, cv::Size(128, 128));//根据需要设定大小 + int Result = clsPtr->Evaluate(cls); + double prob = clsPtr->getProbability(); + if (Result != 0 && prob > probThreshold) { + maxNgProb = std::max(maxNgProb, prob); + } + clsRes.push_back(Result); + clsImgs.push_back({ "Result" + std::to_string(Result) + "_prob" + std::to_string(prob) ,cls }); + } + { + cv::Mat testCls; + cv::resize(seg_detImg(cls_rect), testCls, cv::Size(128, 128)); + int Result = clsPtr->Evaluate(testCls); + double prob = clsPtr->getProbability(); + if (Result != 0 && prob > probThreshold) { + maxNgProb = std::max(maxNgProb, prob); + } + clsImgs.push_back({ "testClsResult" + std::to_string(Result) + "_prob" + std::to_string(prob),testCls }); + } + } + + } + return finalNg; +} +bool jiErFanZhe(std::shared_ptr data, yuHanHanQianParams* _detParams, sx_581_address address) { + try { + + //存图数据加保存队列,加锁,避免数据访问冲突 + QByteArray plcResult = "1"; + cv::Mat sourceImg; + data->getOriImg(0).copyTo(sourceImg); + //sourceImg = cv::imread("D:\\60A01MB5601FB2B213016_Camera2_ORI_0_04-13-55-889.bmp", -1); + cv::Mat Paint; + cv::resize(sourceImg, sourceImg, cv::Size(), 0.5, 0.5); + sourceImg.copyTo(Paint); + if (Paint.channels() == 1) + cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); + //halconProcess(sourceImg, Paint); + float resizeRate = 2.5; + auto rect = getImageLocateRect(sourceImg, _detParams->segDingWei, 1.0 / resizeRate);//定位 + cv::Mat seg_CutImg; + rect = rect & (cv::Rect(0, 0, sourceImg.cols, sourceImg.rows));//防止越界 + bool isNG = false; + std::vector< std::pair > clsImgs; + if (rect.height > 800 ) {//定位极耳过长过短 + cv::rectangle(Paint, rect, cv::Scalar(0, 0, 255), 4); + isNG = true; + } + else if (rect.width > 400 || rect.height > 400) {//定位成功 + sourceImg(rect).copyTo(seg_CutImg); + data->insertSegOriginImg(seg_CutImg); + + if (data->cameraKeyName == "Camera2" || data->cameraKeyName == "Camera4" || data->cameraKeyName == "Camera6" || data->cameraKeyName == "Camera8") {//底部 + rect.y += 300; + rect.height -= 300; + } + else {//顶部 + rect.y += 150; + rect.height -= 150; + } + + cv::Size fillter; + if (data->cameraKeyName == "Camera3" || data->cameraKeyName == "Camera4" || data->cameraKeyName == "Camera7" || data->cameraKeyName == "Camera8") { + fillter = cv::Size(data->service->_paramSyncManager->get("焊前", "铜过滤1_width", 200).toInt(), + data->service->_paramSyncManager->get("焊前", "铜过滤1_height", 200).toInt()); + } + else if (data->cameraKeyName == "Camera1" || data->cameraKeyName == "Camera2" || data->cameraKeyName == "Camera5" || data->cameraKeyName == "Camera6") { + fillter = cv::Size(data->service->_paramSyncManager->get("焊前", "铝过滤1_width", 200).toInt(), + data->service->_paramSyncManager->get("焊前", "铝过滤1_height", 200).toInt()); + } + isNG = handleAiProcess(sourceImg(rect), Paint(rect), _detParams->segJiErFanZhe, _detParams->clsJiErFanZhe, clsImgs, data->service->_paramSyncManager->get("焊前", "prob", 0.99998).toDouble(), fillter); + + //if (data->cameraKeyName == "Camera3" || data->cameraKeyName == "Camera4" || data->cameraKeyName == "Camera7" || data->cameraKeyName == "Camera8") { + // TextRendererZH textPainter(Paint.cols, Paint.rows, 100); + // int testClsResult = _detParams->clsOverView->Evaluate(testImg1); + // double testClsProb = _detParams->clsOverView->getProbability(); + // if(testClsResult == 0) + // textPainter.putText(Paint, "(仅测试不排废)大图CLS测试结果" + std::to_string(testClsResult) + ",prob" + std::to_string(testClsProb), cv::Point(0, 0), cv::Scalar(0, 255, 0)); + // else + // textPainter.putText(Paint, "(仅测试不排废)大图CLS测试结果" + std::to_string(testClsResult) + ",prob" + std::to_string(testClsProb), cv::Point(0, 0), cv::Scalar(0, 0, 255)); + + // if (testClsResult == 1 && testClsProb > 0.995) { + // data->aiDetOK = false; + // } + //} + + cv::rectangle(Paint, rect, cv::Scalar(0, 255, 255), 4); + data->insertClsOriginImg(clsImgs); + } + else { + isNG = true; + } + TextRendererZH textPainter(Paint.cols, Paint.rows, 300); + if (isNG == false)//OK + { + textPainter.putText(Paint, "OK", cv::Point(100, 50), cv::Scalar(0, 255, 0)); + } + else + { + textPainter.putText(Paint, "NG", cv::Point(100, 50), cv::Scalar(0, 0, 255)); + data->aiDetOK = false; + if (data->cameraKeyName == "Camera1" || data->cameraKeyName == "Camera3" || data->cameraKeyName == "Camera5" || data->cameraKeyName == "Camera7") { + if (data->service->_paramSyncManager->get("极耳翻折", "极耳翻折顶部判定启用", false).toBool() == true) + plcResult = "2"; + } + else { + if (data->service->_paramSyncManager->get("极耳翻折", "极耳翻折底部判定启用", false).toBool() == true) + plcResult = "2"; + } + } + putSnAndDetTime(Paint, data->SNcode,60); + std::vector defects; + if (plcResult == "2")defects.push_back("焊前NG"); + data->service->_missionResultHandle->toBarChart(data->SNcode, defects); + if (data->service->_paramSyncManager->get("通用设置", "强制OK", false).toBool() == true) + plcResult = "1";//强制OK + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 + + + cv::Mat seg_LocateImg; + cv::resize(sourceImg, seg_LocateImg, cv::Size(), 0.4, 0.4); + data->insertSegOriginImg(seg_LocateImg); + data->insertResultImg(Paint); + return true; + + } + CATCH_EXCEPTIONS + + qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode); + cv::Mat Paint; + data->getOriImg(0).copyTo(Paint); + if (Paint.channels() == 1) + cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); + TextRendererZH textPainter(Paint.cols, Paint.rows, 15); + textPainter.putText(Paint, "NG", cv::Point(1000, 50), cv::Scalar(0, 255, 0)); + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + data->insertResultImg(Paint); + data->halconOK = false; + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_2");//结果反馈 + return true; +} +class _581_YuHan_hanqian : public mission { +public: + _581_SX_Single_triggerTemplate< yuHanHanQianParams> in_lv_top_1; + _581_SX_Single_triggerTemplate< yuHanHanQianParams> in_lv_down_2; + _581_SX_Single_triggerTemplate< yuHanHanQianParams> in_tong_top_3; + _581_SX_Single_triggerTemplate< yuHanHanQianParams> in_tong_down_4; + + _581_SX_Single_triggerTemplate< yuHanHanQianParams> out_lv_top_5; + _581_SX_Single_triggerTemplate< yuHanHanQianParams> out_lv_down_6; + _581_SX_Single_triggerTemplate< yuHanHanQianParams> out_tong_top_7; + _581_SX_Single_triggerTemplate< yuHanHanQianParams> out_tong_down_8; + std::vector < yuHanHanQianParams> tongDetParams = std::vector < yuHanHanQianParams>(4); + std::vector < yuHanHanQianParams> lvDetParams = std::vector < yuHanHanQianParams>(4); + bool initOnce = false; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_628_1.hdpl"); + + if (initOnce == false) { + for (auto& params : tongDetParams) { + params.segDingWei = handdleAI::CreateSegObjS("./handleaiModels/yuhan_hanqian/hanqianTong_dingwei_seg.BHD", 16, 0); + params.segJiErFanZhe = handdleAI::CreateSegObjS("./handleaiModels/yuhan_hanqian/hanqian_T-seg.BHD", 16, 0); + params.clsJiErFanZhe = handdleAI::CreateClsObjV3("./handleaiModels/yuhan_hanqian/hanqian_T-cls.BHD", 0, 1); + params.clsOverView = handdleAI::CreateClsObjV3("./handleaiModels/yuhan_hanqian/hanqian_overViewCls_T.BHD", 0, 1); + } + for (auto& params : lvDetParams) { + params.segDingWei = handdleAI::CreateSegObjS("./handleaiModels/yuhan_hanqian/hanqianLv_dingwei_seg.BHD", 16, 1); + params.segJiErFanZhe = handdleAI::CreateSegObjS("./handleaiModels/yuhan_hanqian/hanqian_L-seg.BHD", 16, 1); + params.clsJiErFanZhe = handdleAI::CreateClsObjV3("./handleaiModels/yuhan_hanqian/hanqian_L-cls.BHD", 1, 1); + params.clsOverView = handdleAI::CreateClsObjV3("./handleaiModels/yuhan_hanqian/hanqian_overViewCls_T.BHD", 1, 1); + params.isTong = false; + } + initOnce = true; + } + } + bool initCustom() { +#pragma region 注册触发器回调 + in_lv_top_1.init("Camera1", "极耳翻折-铝-内-相机1(顶部)", { { 682, 1,{760},"683","670",-1} }, 1, &lvDetParams[0], _serviceManager, bridge, jiErFanZhe); + in_lv_down_2.init("Camera2", "极耳翻折-铝-内-相机2(底部)", { { 684, 1,{760},"685","672",-1} }, 1, &lvDetParams[1], _serviceManager, bridge, jiErFanZhe); + in_tong_top_3.init("Camera3", "极耳翻折-铜-内-相机3(顶部)", { { 686,1,{760},"687","674",-1} }, 1, &tongDetParams[0], _serviceManager, bridge, jiErFanZhe); + in_tong_down_4.init("Camera4", "极耳翻折-铜-内-相机4(底部)", { { 688, 1,{760},"689","676",-1} }, 1, &tongDetParams[1], _serviceManager, bridge, jiErFanZhe); + + out_lv_top_5.init("Camera5", "极耳翻折-铝-外-相机5(顶部)", { { 702,1,{720},"703","710",-1} }, 1, &lvDetParams[2], _serviceManager, bridge, jiErFanZhe); + out_lv_down_6.init("Camera6", "极耳翻折-铝-外-相机6(底部)", { { 704, 1,{720},"705","712",-1} }, 1, &lvDetParams[3], _serviceManager, bridge, jiErFanZhe); + out_tong_top_7.init("Camera7", "极耳翻折-铜-外-相机7(顶部)", { { 706, 1,{720},"707","714",-1} }, 1, &tongDetParams[2], _serviceManager, bridge, jiErFanZhe); + out_tong_down_8.init("Camera8", "极耳翻折-铜-外-相机8(底部)", { { 708, 1,{720},"709","716",-1} }, 1, &tongDetParams[3], _serviceManager, bridge, jiErFanZhe); +#pragma endregion + return true; + } +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581_YuHan_hanqian/CMakeLists.txt b/src/mission/581_YuHan_hanqian/CMakeLists.txt new file mode 100644 index 0000000..76e9200 --- /dev/null +++ b/src/mission/581_YuHan_hanqian/CMakeLists.txt @@ -0,0 +1,77 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "opencv" "halcon" "handdleAI") +foreach(child ${DLL_NAMES}) + LIST(APPEND ENV_INCLUDE ${${child}_include}) + LIST(APPEND ENV_LIB ${${child}_lib}) + LIST(APPEND ENV_TARGET ${${child}_target_link}) +endforeach() +message(" ENV_INCLUDE : " ${ENV_INCLUDE} ) +message(" ENV_LIB : " ${ENV_LIB} ) +message(" ENV_TARGET : " ${ENV_TARGET} ) +include_directories( + ${PROJECT_ROOT_PATH}/src/core + ${PROJECT_ROOT_PATH}/src/core/handleAi + ${PROJECT_ROOT_PATH}/src/core/service + ${PROJECT_ROOT_PATH}/src/core/sql + ${ENV_INCLUDE} + ) + +link_directories ( + ${ENV_LIB} + + ) +add_compile_options(/utf-8) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +SET(CMAKE_AUTOUIC OFF) +set(CMAKE_AUTORCC ON) + +FILE(GLOB HEAD_FILES "*.h" ) +FILE(GLOB SRC_FILES "./*.cpp") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network REQUIRED) + +add_library(${CURRENT_FOLDER} SHARED + ${HEAD_FILES} + ${SRC_FILES} + ${UI_FILES} + ${PROJECT_ROOT_PATH}/include/interface.h + ) + + + +set_target_properties(${CURRENT_FOLDER} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + ) + + +target_link_libraries(${CURRENT_FOLDER} PRIVATE + ${ENV_TARGET} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Network + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " modelx end : " ${CURRENT_FOLDER}:${RUN_TIME}) +message( " header files "${HEAD_FILES}) diff --git a/src/mission/601/601_RLJ_DingGai/601_RLJ_DingGai.cpp b/src/mission/601/601_RLJ_DingGai/601_RLJ_DingGai.cpp index 39cc8bb..06cb277 100644 --- a/src/mission/601/601_RLJ_DingGai/601_RLJ_DingGai.cpp +++ b/src/mission/601/601_RLJ_DingGai/601_RLJ_DingGai.cpp @@ -4,6 +4,7 @@ struct PanitJob { cv::Point p; }; + bool ALGO_maJiaReRong(std::shared_ptr data, maJiaParam* _detParams, sx_581_address address) { try { qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; diff --git a/subModule/Hd_CameraModule_HIK_General/Hd_CameraModule_HIK_General.cpp b/subModule/Hd_CameraModule_HIK_General/Hd_CameraModule_HIK_General.cpp index f76c59e..21a4b92 100644 --- a/subModule/Hd_CameraModule_HIK_General/Hd_CameraModule_HIK_General.cpp +++ b/subModule/Hd_CameraModule_HIK_General/Hd_CameraModule_HIK_General.cpp @@ -166,8 +166,8 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser){ return; } - qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 1 seconds before retry..."; - std::this_thread::sleep_for(std::chrono::seconds(1)); + qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 500 ms before retry..."; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } // 如果runFlag为false,线程退出 @@ -332,11 +332,11 @@ bool Hd_CameraModule_HIK_General::writeData(std::vector& mat, QByteArra data = lastError.toUtf8(); return true; } - if (data == "clearCache") { - QMutexLocker locker(n_mutex); - queuepic.clear(); - return true; - } + //if (data == "clearCache") { + // QMutexLocker locker(n_mutex); + // queuepic.clear(); + // return true; + //} if (data.contains("exposure")){ auto commandList = data.split('_'); QMutexLocker locker(n_mutex); diff --git a/subModule/Hd_CameraModule_HIK_General_debouncing/Hd_CameraModule_HIK_General.cpp b/subModule/Hd_CameraModule_HIK_General_debouncing/Hd_CameraModule_HIK_General.cpp index 8786bc3..6d8215b 100644 --- a/subModule/Hd_CameraModule_HIK_General_debouncing/Hd_CameraModule_HIK_General.cpp +++ b/subModule/Hd_CameraModule_HIK_General_debouncing/Hd_CameraModule_HIK_General.cpp @@ -136,23 +136,23 @@ void SetGain(float GainValue) } //断线重连 -void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser){ +void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser) { qDebug() << "[Error] " << " MV camera disconnects!"; - - if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus.load() == CONNECTED){ - + + if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus.load() == CONNECTED) { + // 防止重复启动重连线程 bool expected = false; if (!reconnecting.compare_exchange_strong(expected, true)) { qDebug() << "[Warning] Reconnect already in progress, skipping duplicate request"; return; } - + cameraStatus.store(RECONNECTING); // 启动后台线程负责重连,避免在回调线程中长时间阻塞 std::thread([]() { - qDebug() << QString::fromStdString(Username) << " start reconnect thread"; + qDebug() << QString::fromStdString(Username) << " start reconnect thread"; // 确保设备资源关闭 CloseDevice(); @@ -162,21 +162,21 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser){ qDebug() << QString::fromStdString(Username) << " reconnect attempt:" << times++; if (connectDevice()) { - qWarning() << QString::fromStdString(Username) << " reconnect success!"; + qWarning() << QString::fromStdString(Username) << " reconnect success!"; cameraStatus.store(CONNECTED); reconnecting.store(false); return; } - - qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 1 seconds before retry..."; - std::this_thread::sleep_for(std::chrono::seconds(1)); + + qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 500 ms before retry..."; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - + // 如果runFlag为false,线程退出 qDebug() << "[Info] reconnect thread stopped (runFlag=false)"; cameraStatus.store(DISCONNECTED); reconnecting.store(false); - }).detach(); + }).detach(); } } @@ -320,7 +320,7 @@ bool Hd_CameraModule_HIK_General::readData(std::vector& mat, QByteArray QMutexLocker locker(n_mutex); cv::Mat img = queuepic.dequeue(); mat.push_back(img); - + queuepic.clear(); qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData--CameraName:" << QString::fromStdString(Username) << "--imgIndex : " << imgIndex; return true; } @@ -340,11 +340,11 @@ bool Hd_CameraModule_HIK_General::writeData(std::vector& mat, QByteArra data = lastError.toUtf8(); return true; } - if (data == "clearCache") { + /* if (data == "clearCache") { QMutexLocker locker(n_mutex); queuepic.clear(); return true; - } + }*/ if (data.contains("exposure")) { auto commandList = data.split('_'); QMutexLocker locker(n_mutex); diff --git a/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp b/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp index e4af46a..12d9473 100644 --- a/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp +++ b/subModule/Hd_VirtualCamera/Hd_VirtualCamera.cpp @@ -77,7 +77,7 @@ bool Hd_VirtualCamera::run()//����� } else { vector mats; - mats.push_back(cv::Mat(2096,3200,CV_8UC3,cv::Scalar(0,255,0))); + mats.push_back(cv::Mat(2096,4800,CV_8UC3,cv::Scalar(0,0,0))); queuePic.enqueue(mats); } n_mutex->unlock();