diff --git a/include/global.h b/include/global.h index 494593e..26bbe27 100644 --- a/include/global.h +++ b/include/global.h @@ -11,7 +11,7 @@ #include #pragma execution_character_set("utf-8") -const std::string softwareVersion = "20251119-2.2.5"; +const std::string softwareVersion = "20251125-2.2.6"; const std::string euiJsonVersion = "1.0.6"; #define globalDatabasePth "./sqlDatabase/eui_db.db" //全局数据库路径 #define saveImgEnable 1 diff --git a/include/simpleAlgo.h b/include/simpleAlgo.h index 24fd6c8..2e7b1db 100644 --- a/include/simpleAlgo.h +++ b/include/simpleAlgo.h @@ -124,6 +124,8 @@ static std::vector cutImg2ClsVec(cv::Rect boundingBox, cv::Mat imgInput std::cerr << "Invalid bounding box or empty input image." << std::endl; return result; } + if (boundingBox.width < targetSize.width && boundingBox.height < targetSize.height) + return { cutImg2Cls(boundingBox, imgInput, targetSize) }; const int w = boundingBox.width; const int h = boundingBox.height; @@ -139,8 +141,8 @@ static std::vector cutImg2ClsVec(cv::Rect boundingBox, cv::Mat imgInput const bool splitHoriz = (w > h); // 横向长 -> 沿X方向切 const int longSide = splitHoriz ? w : h; const int step = minSide; - const int beginCoord = splitHoriz ? boundingBox.x : boundingBox.y; - const int endCoord = beginCoord + longSide; + const int beginCoord = splitHoriz ? boundingBox.x - targetSize.height / 2 + boundingBox.height / 2 : boundingBox.y - targetSize.width / 2 + boundingBox.width / 2; + const int endCoord = beginCoord + longSide + (splitHoriz ? targetSize.width / 2 : targetSize.height / 2); // 计算切块起点列表 std::vector starts; @@ -156,12 +158,14 @@ static std::vector cutImg2ClsVec(cv::Rect boundingBox, cv::Mat imgInput result.reserve(starts.size()); if (splitHoriz) { + int y = boundingBox.y - targetSize.width / 2 + boundingBox.height / 2; for (int x : starts) { - result.emplace_back(cutImg2Cls(cv::Rect(x, boundingBox.y, minSide, minSide), imgInput, targetSize)); + result.emplace_back(cutImg2Cls(cv::Rect(x, y, minSide, minSide), imgInput, targetSize)); } } else { + int x = boundingBox.x - targetSize.width / 2 + boundingBox.width / 2; for (int y : starts) { - result.emplace_back(cutImg2Cls(cv::Rect(boundingBox.x, y, minSide, minSide), imgInput, targetSize)); + result.emplace_back(cutImg2Cls(cv::Rect(x, y, minSide, minSide), imgInput, targetSize)); } } @@ -395,7 +399,7 @@ static void MatToHObjectV(cv::Mat& image, HalconCpp::HObject* Hobj) } } -static HalconCpp::HObject MatToHObject(cv::Mat& image) +static HalconCpp::HObject MatToHObject(const cv::Mat& image) { HalconCpp::HObject Hobj; int hgt = image.rows; diff --git a/src/core/service/imgSaveThreadManager.h b/src/core/service/imgSaveThreadManager.h index 573e747..58ee8dd 100644 --- a/src/core/service/imgSaveThreadManager.h +++ b/src/core/service/imgSaveThreadManager.h @@ -42,7 +42,7 @@ public: QString processResult; if (!data->aiDetOK && !data->halconOK) processResult = "NG"; else if (!data->aiDetOK) processResult = "aiNG"; - else if (!data->halconOK) processResult = "halconNG"; + else if (!data->halconOK) processResult = "algoNG"; else processResult = "OK"; result.replace("{processResult}", processResult); diff --git a/src/cutImage/RLJ.hpp b/src/cutImage/RLJ.hpp new file mode 100644 index 0000000..633024f --- /dev/null +++ b/src/cutImage/RLJ.hpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +void rlj_hanyin(const std::string path, const std::string format, const std::string outputPath, cv::Size fillter) { + //int + handdleAI::pSegmentation* seg = handdleAI::CreateSegObjS("./cutImgFiles/RLJ_HANYINZHUAQU_SEG.BHD", 1, 0); + //handdleAI::pSegmentation* seg = handdleAI::CreateSegObjS("./cutImgFiles/YUHAN_LV_SEG.BHD", 1, 0); + //handdleAI::pClassification* cls = handdleAI::CreateClsObjV3("./cutImgFiles/YUHAN_LV_CLS.BHD", 0, 1); + + std::vector images; + cv::glob(path + "/*." + format, images, false); + std::cout << "files count" << images.size() << std::endl; + QString timeStamp = getDateTimeStamp(); + for (size_t i = 0; i < images.size(); i++) { + std::string filePath = outputPath + "/" + timeStamp.toStdString() + "/" + std::to_string(i) + "/"; + createDirectoryIfNotExists(QString::fromStdString(filePath)); + cv::Mat srcImage = cv::imread(images[i], -1); + cv::Mat Paint; + if (srcImage.cols == 1) + cv::cvtColor(srcImage, Paint, cv::COLOR_GRAY2BGR); + else + srcImage.copyTo(Paint); + + if (srcImage.empty()) { + std::cout << "ͼƬΪ¿գ¡" << std::endl; + continue; + } + bool isNg = false; + auto SegResult = ~seg->Evaluate(srcImage); + auto rect = findMaxAreaContour(SegResult); + auto clsImg = cutImg2Cls(rect, srcImage, cv::Size(256, 256)); + std::string text = isNg == true ? "NG" : "OK"; + cv::imwrite(filePath + "/ " + getCurrentDateTime() + "RES.bmp", clsImg); + cv::imwrite(filePath + "/ " + text + "Paint.bmp", Paint); + std::cout << i << "/" << images.size() << std::endl; + } +} \ No newline at end of file diff --git a/src/cutImage/basic.hpp b/src/cutImage/basic.hpp new file mode 100644 index 0000000..f7c42ec --- /dev/null +++ b/src/cutImage/basic.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include +#include +QString getDateTimeStamp() +{ + return QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"); +} +static const std::vector saveR = { "OK","NG" }; \ No newline at end of file diff --git a/src/cutImage/main.cpp b/src/cutImage/main.cpp index 2c16816..c983028 100644 --- a/src/cutImage/main.cpp +++ b/src/cutImage/main.cpp @@ -1,7 +1,13 @@ #include - +#include +#include int main(int argc, char* argv[]) { - baomoXiaDMianSiJiaoCut("E:\\imgs", "bmp", "./outputs/" , cv::Size(50, 50)); + //rlj_hanyin("D:\\º¸ӡImage\\11.20\\T\\NG", "bmp", "./outputs/", cv::Size(300, 300)); + //yuhan_hanqian("D:\\testImage\\OK", "bmp", "./outputs/" , cv::Size(300, 300)); + // yuhan_hanqian("D:\\testImg\\L", "bmp", "./outputs/", cv::Size(50, 50)); + cv::Mat img = cv::imread("D:\\testImage\\04QCB82602000JFBN00206BN_Camera3_ORI_0_09-42-34-710.bmp", -1); + //755 4300 60 300 + auto imgs = cutImg2ClsVec(cv::Rect(8120, 4850, 1007, 129), img); return 1; } \ No newline at end of file diff --git a/src/cutImage/yuhan.hpp b/src/cutImage/yuhan.hpp new file mode 100644 index 0000000..bd961ed --- /dev/null +++ b/src/cutImage/yuhan.hpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +void yuhan_hanqian(const std::string path, const std::string format, const std::string outputPath, cv::Size fillter) { + //int + handdleAI::pSegmentation* seg = handdleAI::CreateSegObjS("./cutImgFiles/YUHAN_TONG_SEG.BHD", 1, 0); + handdleAI::pClassification* cls = handdleAI::CreateClsObjV3("./cutImgFiles/YUHAN_TONG_CLS.BHD", 0, 1); + //handdleAI::pSegmentation* seg = handdleAI::CreateSegObjS("./cutImgFiles/YUHAN_LV_SEG.BHD", 1, 0); + //handdleAI::pClassification* cls = handdleAI::CreateClsObjV3("./cutImgFiles/YUHAN_LV_CLS.BHD", 0, 1); + + std::vector images; + cv::glob(path + "/*." + format, images, false); + std::cout << "files count" << images.size() << std::endl; + QString timeStamp = getDateTimeStamp(); + for (size_t i = 0; i < images.size(); i++) { + std::string filePath = outputPath + "/" + timeStamp.toStdString() + "/" + std::to_string(i) + "/"; + createDirectoryIfNotExists(QString::fromStdString(filePath)); + cv::Mat srcImage = cv::imread(images[i], -1); + cv::resize(srcImage, srcImage, cv::Size(), 0.5, 0.5); + cv::Mat Paint; + if (srcImage.cols == 1) + cv::cvtColor(srcImage, Paint, cv::COLOR_GRAY2BGR); + else + srcImage.copyTo(Paint); + + if (srcImage.empty()) { + std::cout << "ͼƬΪ¿գ¡" << std::endl; + continue; + } + bool isNg = false; + cv::Mat SegResult = ~seg->Evaluate(srcImage); + std::vector> contours; + cv::findContours(SegResult, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + for (int ii = 0; ii < contours.size(); ii++) { + cv::Rect rect = cv::boundingRect(contours[ii]); + if (rect.width > fillter.width && rect.height > fillter.height) { + //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); + auto imgs = cutImg2ClsVec(rect, srcImage); + for (int o = 0; o < imgs.size(); o++) { + int r = cls->Evaluate(imgs[o]); + qDebug() << r; + if (r== 1) + isNg = true; + cv::imwrite(filePath + "/" + timeStamp.toStdString() + "_" + std::to_string(i) + "_" + std::to_string(ii) + "_" + std::to_string(o) + saveR[r] + "CLS.bmp", imgs[o]); + } + if(isNg) + cv::rectangle(Paint, rect, cv::Scalar(0, 0, 255), 3); + else + cv::rectangle(Paint, rect, cv::Scalar(0, 255, 0), 3); + } + } + std::string text = isNg == true ? "NG" : "OK"; + cv::imwrite(filePath + "/ " + text + "Paint.bmp", Paint); + std::cout << i << "/" << images.size() << std::endl; + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..8202c43 --- /dev/null +++ b/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.cpp @@ -0,0 +1,424 @@ +#include <581_Ruanlianjie_hanqian_hanhou.h> +void exceptionResume(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address, QString why = "") { + qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode) << why; + cv::Mat Paint; + data->oriImgs[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->resultImgs.push_back(Paint); + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + +} +void exceptionResume(std::shared_ptr data, hanQianDingWeiParams* _detParams, sx_581_address address, QString why = "") { + qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode) << why; + cv::Mat Paint; + data->oriImgs[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->resultImgs.push_back(Paint); + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + +} +bool HanQianDingWei(std::shared_ptr data, hanQianDingWeiParams* _detParams, sx_581_address address){ + try + { + bool zuoLJPtoGaiBanEnable = data->service->_paramSyncManager->get("焊前定位", "左侧连接片和盖板距离判定启用", false).toBool(); + double zuoLJPtoGaiBanMaxThreshold = data->service->_paramSyncManager->get("焊前定位", "左侧连接片和盖板距离(MAX)", 1.8).toDouble(); + double zuoLJPtoGaiBanMinThreshold = data->service->_paramSyncManager->get("焊前定位", "左侧连接片和盖板距离(MIN)", 0.0).toDouble(); + + bool youLJPtoGaiBanEnable = data->service->_paramSyncManager->get("焊前定位", "右侧连接片和盖板距离判定启用", false).toBool(); + double youLJPtoGaiBanMaxThreshold = data->service->_paramSyncManager->get("焊前定位", "右侧连接片和盖板距离(MAX)", 1.8).toDouble(); + double youLJPtoGaiBanMinThreshold = data->service->_paramSyncManager->get("焊前定位", "右侧连接片和盖板距离(MIN)", 0.0).toDouble(); + + QByteArray plcResult = "1"; + //data->oriImgs[0] = cv::imread("D://60A01MB5601FB2P246404_Camera1_0_00-43-53.bmp",-1); + cv::Mat sourceImg = data->oriImgs[0]; + cv::Mat Paint; + sourceImg.copyTo(Paint); + if (Paint.channels() == 1) + cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); + HDevEngineCpp::HDevProcedure proc("_3_HQDW_Inspection"); + HDevEngineCpp::HDevProcedureCall procedureCall(proc); + + HTuple in_Resolution(0.0349425), in_FilePath("./halconFiles/"); + HObject inputImage = MatToHObject(sourceImg); + + procedureCall.SetInputIconicParamObject("in_Image", inputImage); + procedureCall.SetInputCtrlParamTuple("in_Resolution", in_Resolution); + procedureCall.SetInputCtrlParamTuple("in_FilePath", in_FilePath); + procedureCall.Execute();//执行halcon程序 + HTuple out_ColorType; + HTuple out_Distance; + HTuple out_CCDistance; + HTuple make; + HObject out_DisplayImage; + //out_LinePoint = procedureCall.GetOutputCtrlParamTuple("out_LinePoint");//获取输出控制类变量 + out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出控制类变量 + //out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle");//获取输出控制类变量 + out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance");//获取输出控制类变量 + out_CCDistance = procedureCall.GetOutputCtrlParamTuple("out_CCDistance");//获取输出控制类变量 + make = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量 + out_DisplayImage = procedureCall.GetOutputIconicParamObject("out_DisplayImage");//获取输出控制类变量 + int flag = make.D(); + + // Output(HTuple): out_ColorType, 1, 铜; 2,铝 + + //正确的应该左边铝 右边铜 + double value1_1 = 0, value1_2 = 0, value2_1 = 0, value2_2 = 0; + bool jiXingEnable = data->service->_paramSyncManager->get("焊前定位", "焊前极性判定启用", false).toBool(); + if (flag == 1) + { + //circle(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D()), out_Circle[2].D(), cv::Scalar(0, 255, 0), 5); + //for (int i = 0; i < 2 ; i++) + //{ + // cv::line(Paint, cv::Point(out_LinePoint[i * 4 + 1].D(), out_LinePoint[i * 4].D()), + // cv::Point(out_LinePoint[i * 4 + 3].D(), out_LinePoint[i * 4 + 2].D()), + // cv::Scalar(0, 255, 0), 10); + //} + bool isNg = false; + TextRendererZH textPainter(Paint.cols, Paint.rows, 200); + Paint = HObject2Mat(out_DisplayImage); + if (out_Distance.Length() == 3) { + value1_1 = out_Distance[1].D(); + value1_2 = out_Distance[2].D(); + + textPainter.putText(Paint, "铜极+铝极连接片中心距离:" + std::to_string(out_Distance[0].D()) + "mm", cv::Point(0, sourceImg.rows - 950), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "电芯上水平边缘和注液孔的中心圆的距离:" + std::to_string(out_Distance[1].D()) + "mm", cv::Point(0, sourceImg.rows - 750), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "电芯下水平边缘和注液孔的中心圆的距离:" + std::to_string(out_Distance[2].D()) + "mm", cv::Point(0, sourceImg.rows - 550), cv::Scalar(0, 255, 0)); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(out_Distance[0].D())); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr+2) + "_" + QByteArray::number(out_Distance[1].D())); + + data->sqlVec.insert({ "电芯上水平边缘和注液孔的中心圆的距离", out_Distance[1].D() }); + data->sqlVec.insert({ "电芯下水平边缘和注液孔的中心圆的距离", out_Distance[2].D() }); + } + if (out_CCDistance.Length() == 2) { + value2_1 = out_CCDistance[0].D(); + if (zuoLJPtoGaiBanMaxThreshold < value2_1 || zuoLJPtoGaiBanMinThreshold > value2_1) {//NG + textPainter.putText(Paint, "左侧连接片圆心和盖板圆心的距离:" + std::to_string(value2_1) + "mm", cv::Point(0, sourceImg.rows - 350), cv::Scalar(0, 0, 255)); + if (zuoLJPtoGaiBanEnable == true) + isNg = true; + } + else//OK + textPainter.putText(Paint, "左侧连接片圆心和盖板圆心的距离:" + std::to_string(value2_1) + "mm", cv::Point(0, sourceImg.rows - 350), cv::Scalar(0, 255, 0)); + + value2_2 = out_CCDistance[1].D(); + if (youLJPtoGaiBanMaxThreshold < value2_2 || youLJPtoGaiBanMinThreshold > value2_2) {//NG + textPainter.putText(Paint, "右侧连接片圆心和盖板圆心的距离:" + std::to_string(value2_2) + "mm", cv::Point(0, sourceImg.rows - 150), cv::Scalar(0, 0, 255)); + if(youLJPtoGaiBanEnable == true) + isNg = true; + } + else + textPainter.putText(Paint, "右侧连接片圆心和盖板圆心的距离:" + std::to_string(value2_2) + "mm", cv::Point(0, sourceImg.rows - 150), cv::Scalar(0, 255, 0)); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_" + QByteArray::number(out_CCDistance[0].D())); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_" + QByteArray::number(out_Distance[1].D())); + + data->sqlVec.insert({ "左侧连接片圆心和盖板圆心的距离", out_CCDistance[0].D() }); + data->sqlVec.insert({ "右侧连接片圆心和盖板圆心的距离", out_CCDistance[1].D() }); + } + + TextRendererZH textPainter2(Paint.cols, Paint.rows, 600); + int left = out_ColorType[0].D(); + //结果判定,铜在左边,铝在右边 + if (left == 2) + textPainter2.putText(Paint,"铜",cv::Point(0, 1500), cv::Scalar(0, 255, 0)); + else if (left == 1) + textPainter2.putText(Paint,"铝",cv::Point(0, 1500), cv::Scalar(0, 0, 255)); + else + textPainter2.putText(Paint,"异常",cv::Point(0, 1500), cv::Scalar(0, 0, 255)); + + int right = out_ColorType[1].D(); + if (right == 2) + textPainter2.putText(Paint,"铜",cv::Point(Paint.cols - 600, 1500), cv::Scalar(0, 0, 255)); + else if (right == 1) + textPainter2.putText(Paint,"铝",cv::Point(Paint.cols - 600, 1500), cv::Scalar(0, 255, 0)); + else + textPainter2.putText(Paint,"异常",cv::Point(Paint.cols - 600, 1500), cv::Scalar(0, 0, 255)); + + if ((left == 1 || right == 2) && jiXingEnable) + isNg = true; + + TextRendererZH textPainter3(Paint.cols, Paint.rows, 800); + if(isNg == true){ + textPainter3.putText(Paint, "NG", cv::Point(0, 50), cv::Scalar(0, 0, 255)); + plcResult = "2"; + data->halconOK = false; + } + else { + textPainter3.putText(Paint, "OK", cv::Point(0, 50), cv::Scalar(0, 255, 0)); + } + } + else + { + TextRendererZH textPainter4(Paint.cols, Paint.rows, 500); + textPainter4.putText(Paint, "NG", cv::Point(0, 50), cv::Scalar(0, 0, 255));//调机 + plcResult = "2"; + data->halconOK = false; + } + if (data->service->_paramSyncManager->get("通用设置","强制OK", false).toBool()) + plcResult = "1"; + data->resultImgs.push_back(Paint); + sourceImg.release(); + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 + return true; + } + CATCH_EXCEPTIONS + exceptionResume(data, _detParams, address, "检测失败"); + qDebug() << "[Error] " << QString::fromUtf8("检测失败!"); + return false; +} + +bool HanHou2D_halconEvaluate(std::shared_ptr data, const cv::Mat& sourceImg,const cv::Mat& segImg, cv::Mat& Paint, double& hanHouTongXingDu, int times,QMutex* mutex) { + 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(); + HDevEngineCpp::HDevProcedure proc("_3_Cal_HY_CC_Distance"); + HDevEngineCpp::HDevProcedureCall procedureCall(proc); + + HObject in_Image = MatToHObject(sourceImg); + HObject in_ImageSeg = MatToHObject(segImg); + HalconCpp::HTuple in_FliePath("./halconFiles/"), in_Resolution(0.013736); + procedureCall.SetInputIconicParamObject("in_Image", in_Image); + procedureCall.SetInputIconicParamObject("in_ImageSeg", in_ImageSeg); + procedureCall.SetInputCtrlParamTuple("in_FliePath", in_FliePath); + procedureCall.SetInputCtrlParamTuple("in_Resolution", in_Resolution); + procedureCall.Execute();//执行halcon程序 + HalconCpp::HTuple out_CCDistance, out_Circle, out_Flag, out_NgTails; + out_CCDistance = procedureCall.GetOutputCtrlParamTuple("out_CCDistance");//获取输出控制类变量 + out_Circle = procedureCall.GetOutputCtrlParamTuple("out_Circle");//获取输出控制类变量 + out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量 + out_NgTails = procedureCall.GetOutputCtrlParamTuple("out_NgTails");//获取输出控制类变量 + int flag = out_Flag.D(); + bool isNg = false; + TextRendererZH textPainter(Paint.cols, Paint.rows, 300); + QMutexLocker locker(mutex); + if (flag == 1){ + + + double CCDistance = out_CCDistance.D(); + textPainter.putText(Paint, "焊印同心度:" + std::to_string(CCDistance), cv::Point(0, 50), cv::Scalar(0, 255, 0)); + + cv::circle(Paint, cv::Point(out_Circle[1].D(), out_Circle[0].D()), out_Circle[2].D(), cv::Scalar(0, 255, 0), 15); + cv::circle(Paint, cv::Point(out_Circle[4].D(), out_Circle[3].D()), out_Circle[5].D(), cv::Scalar(0, 255, 0), 15); + if (CCDistance > tongXingDuLimitHigh || CCDistance < tongXingDuLimitLow){ + textPainter.putText(Paint, "同心度NG", cv::Point(10, 450), cv::Scalar(0, 0, 255)); + data->halconOK = false; + if(tongXingDuLimitEnable == true) + isNg = true; + } + } + else{ + textPainter.putText(Paint, "焊印抓取NG", cv::Point(10, 150), cv::Scalar(0, 0, 255)); + textPainter.putText(Paint, gbkToUtf8(out_NgTails.ToString().Text()), cv::Point(10, 450), cv::Scalar(0, 0, 255)); + if (tongXingDuLimitEnable == true) + isNg = true; + data->halconOK = false; + } + return isNg; +} +bool HanHou2D_handleAiEvaluate(std::shared_ptr data, hanHouJianCe* _detParams,const cv::Mat& sourceImg, cv::Mat& Paint,QMutex* mutex,cv::Point paintOffset) { + double hanZhaFillterWidth = data->service->_paramSyncManager->get("焊后", "焊渣过滤值宽mm(上限)", 0.1).toDouble()/ 0.013736; + double hanZhaFillterHeight = data->service->_paramSyncManager->get("焊后", "焊渣过滤值高mm(上限)", 0.1).toDouble()/ 0.013736; + bool hanZhaEnable = data->service->_paramSyncManager->get("焊后", "焊渣判定启用", false).toBool(); + + cv::Mat forSeg; + cv::resize(sourceImg, forSeg, cv::Size(), 0.5, 0.5); + + cv::Mat SegResult = ~_detParams->seg_rljHanZha->Evaluate(forSeg); + std::vector> contours; + cv::findContours(SegResult, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + std::vector PaintRects; + bool isNg = false;; + for (int i = 0; i < contours.size(); i++) { + cv::Rect rect = cv::boundingRect(contours[i]); + if (rect.width > hanZhaFillterWidth || rect.height > hanZhaFillterHeight) { + cv::Mat img = cutImg2Cls(rect, forSeg); + bool clsIsNg = false; + int clsRes = _detParams->cls_rljHanZha->Evaluate(img); + if (clsRes == 1) + clsIsNg = true; + if (clsIsNg == true) { + rect.x *= 2; rect.y *= 2; rect.width *= 2; rect.height *= 2; + PaintRects.push_back(rect); + isNg = true; + } + data->clsOriginImgs.push_back({ clsIsNg == true ? "NG" : "OK",img }); + } + } + QMutexLocker locker(mutex); + for (auto& rect : PaintRects) { + cv::rectangle(Paint, rect, cv::Scalar(0, 0, 255), 3); + } + return isNg; +} +bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address){ + try + { + + QString sqlText1 = "焊后同心度结果"; + QString sqlText2 = "焊后铜极同心度"; + QString sqlText3 = "焊后铝极同心度"; + QString sqlText4 = "焊后2dCT"; + data->oriImgs.clear(); + data->oriImgs.push_back(cv::imread("D:\\testImage\\rlj_hh_t.bmp",-1)); + data->oriImgs.push_back(cv::imread("D:\\testImage\\rlj_hh_t.bmp", -1)); + if (data->oriImgs.size() <= 1) { + exceptionResume(data, _detParams, address, "图片数量不满足"); + return true; + } + cv::Mat Paint1, Paint2; + data->oriImgs[0].copyTo(Paint1); + data->oriImgs[1].copyTo(Paint2); + if (Paint1.channels() == 1) { + cvtColor(Paint1, Paint1, cv::COLOR_GRAY2BGR); + } + if (Paint2.channels() == 1) { + cvtColor(Paint2, Paint2, cv::COLOR_GRAY2BGR); + } + QMutex mutex1, mutex2; + HanHou2D_handleAiEvaluate(data, _detParams, data->oriImgs[0], Paint1, &mutex1, cv::Point(0,0)); + QByteArray plcResult = "1"; + double hanHouTongXingDu1 = -1; + double hanHouTongXingDu2 = -1; + cv::Mat forSeg1, forSeg2; + double resizeRate = 0.25; + cv::resize(data->oriImgs[0], forSeg1, cv::Size(), resizeRate, resizeRate); + cv::Mat seg1 = _detParams->seg_rljHanYinZhuaQu->Evaluate(forSeg1); + data->segOriginImgs.push_back(seg1); + cv::Rect tongRect = findMaxAreaContour(~seg1); + //cv::Point tongCenter(tongRect.x + tongRect.width / 2, tongRect.y + tongRect.height / 2); + + cv::resize(data->oriImgs[1], forSeg2, cv::Size(), resizeRate, resizeRate); + cv::Mat seg2 = _detParams->seg_rljHanYinZhuaQu->Evaluate(forSeg2); + data->segOriginImgs.push_back(seg2); + cv::Rect lvRect = findMaxAreaContour(~seg2); + //cv::Point lvCenter(lvRect.x + lvRect.width / 2, lvRect.y + lvRect.height / 2); + + + auto futrue1 = std::async(std::launch::async, &HanHou2D_halconEvaluate, data, data->oriImgs[0], seg1, std::ref(Paint1), std::ref(hanHouTongXingDu1), 0, &mutex1); + auto futrue2 = std::async(std::launch::async, &HanHou2D_halconEvaluate, data, data->oriImgs[1], seg2, std::ref(Paint2), std::ref(hanHouTongXingDu2), 2, &mutex2); + + + //auto futrue3 = std::async(std::launch::async, &HanHou2D_handleAiEvaluate, data, _detParams, data->oriImgs[0], std::ref(Paint1), &mutex1); + //auto futrue4 = std::async(std::launch::async, &HanHou2D_handleAiEvaluate, data, _detParams, data->oriImgs[1], std::ref(Paint2), &mutex2); + + auto tongClsImg = cutImg2Cls(tongRect, forSeg1, cv::Size(256, 256)); + data->clsOriginImgs.push_back({ "HY",tongClsImg }); + + auto lvClsImg = cutImg2Cls(lvRect, forSeg2, cv::Size(256, 256)); + int lvClsRes = _detParams->cls_hanYinLv->Evaluate(lvClsImg); + data->clsOriginImgs.push_back({ "HY",lvClsImg }); + + futrue1.wait(); + futrue2.wait(); + bool isNg1 = futrue1.get(), isNg2 = futrue2.get(); + + //futrue3.wait(); + //futrue4.wait(); + + //futrue3.get(); + //futrue4.get(); + + TextRendererZH textPainter(Paint2.cols, Paint2.rows, 100); + if (lvClsRes == 1) { + textPainter.putText(Paint2, "CLS-NG", cv::Point(0, 350), cv::Scalar(0, 0, 255)); + if (data->service->_paramSyncManager->get("焊后", "焊印CLS判定启用", true).toBool()) { + isNg2 = true; + } + + } + else + textPainter.putText(Paint2, "CLS-OK", cv::Point(0, 350), cv::Scalar(0, 255, 0)); + + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(hanHouTongXingDu1)); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(hanHouTongXingDu2)); + + + + if (isNg1 == true || isNg2 == true) {//判断存图 + data->halconOK = false; + } + + if (isNg1 == false && isNg2 == false) {//都OK发1 + plcResult = "1"; + } + else if (isNg1 == true && isNg2 == false)//第一次NG发2 + plcResult = "2"; + else if (isNg1 == false && isNg2 == true)//第二次NG发3 + plcResult = "3"; + else if (isNg1 == true && isNg2 == true)//两次都NG发4 + plcResult = "4"; + else//为了DEBUG + plcResult = "5"; + //plcResult = "1"; + cv::Mat PaintSum; + cv::vconcat(Paint1, Paint2, PaintSum); + data->resultImgs.push_back(PaintSum); + if (data->service->_paramSyncManager->get("通用设置","强制OK", false).toBool()) + plcResult = "1"; + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult); + return true; + } + CATCH_EXCEPTIONS + exceptionResume(data, _detParams, address, "检测失败"); + qDebug() << "[Error] " << QString::fromUtf8("检测失败!"); + return false; + +} + +bool HanHouJianCe3D(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address) { + try { + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + std::vector < std::string> defects = { }; + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() < 1) + { + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[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->oriImgs[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)); + //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->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + //data->service->_missionResultHandle->toBarChart(data->SNcode, !defects.size() > 0, defects);//发送图标操作 + data->resultImgs.push_back(Paint); + return true; + } + CATCH_EXCEPTIONS + exceptionResume(data, _detParams, address, "检测失败"); + return false; + + +} + + +mission* createMission() { + return new _581_Ruanlianjie_hanqian_hanhou(); +} +void destroyMission(mission* _mission) { + delete _mission; +} 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 new file mode 100644 index 0000000..ec4c3d1 --- /dev/null +++ b/src/mission/581_Ruanlianjie_hanqian_hanhou/581_Ruanlianjie_hanqian_hanhou.h @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace HDevEngineCpp; +using namespace HalconCpp; +class hanQianDingWeiParams { + +}; +class hanHouJianCe { +public: + handdleAI::pSegmentation* seg_rljHanYinZhuaQu = nullptr; + handdleAI::pSegmentation* seg_rljHanZha = nullptr; + handdleAI::pClassification* cls_rljHanZha = nullptr; + handdleAI::pClassification* cls_hanYinLv = nullptr; +}; + +bool HanQianDingWei(std::shared_ptr data, hanQianDingWeiParams* _detParams, sx_581_address address); +bool HanHouJianCe2D(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address); +bool HanHouJianCe3D(std::shared_ptr data, hanHouJianCe* _detParams, sx_581_address address); + +class _581_Ruanlianjie_hanqian_hanhou : public mission { +public: + + _581_SX_Single_triggerTemplate dingwei_1; + _581_SX_Single_triggerTemplate dingwei_2; + + _581_SX_Single_triggerTemplate jiance_2d_1; + _581_SX_Single_triggerTemplate jiance_2d_2; + _581_SX_Single_triggerTemplate jiance_3d_1; + _581_SX_Single_triggerTemplate jiance_3d_2; + + hanQianDingWeiParams hanqiandingweiparams; + std::vectorhanhoujiance2dparams = std::vector(2); + hanHouJianCe hanhoujiance3dparams; + + bool initOnce = false; + void onConfigReloaded() { + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); + + if (initOnce == false) { + + /*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_rljHanZha = handdleAI::CreateSegObjS("./handleAiModels/rlj/seg_rljHanZha.BHD", 64, 0); + //hanhoujiance2dparams[1].seg_rljHanZha = handdleAI::CreateSegObjS("./handleAiModels/seg_rljHanZha.BHD", 64, 1); + + hanhoujiance2dparams[0].cls_rljHanZha = handdleAI::CreateClsObjV3("./handleAiModels/rlj/cls_rljHanZha.BHD", 0, 1); + //hanhoujiance2dparams[1].cls_rljHanZha = handdleAI::CreateClsObjV3("./handleAiModels/cls_rljHanZha.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); + initOnce = true; + } + } + bool initCustom() { +#pragma region 注册触发器回调 + dingwei_1.init("Camera1", "焊前定位-相机1(前)", { { 4900, 1,{4910},"4902","4904",4930} }, 1, &hanqiandingweiparams, _serviceManager, bridge, HanQianDingWei,"焊前定位CCD"); + dingwei_2.init("Camera2", "焊前定位-相机2(后)", { { 5800, 1,{5810},"5802","5804",5830} }, 1, &hanqiandingweiparams, _serviceManager, bridge, HanQianDingWei,"焊前定位CCD"); + + jiance_2d_1.init("Camera3", "焊后检测2D-相机1(前)", { { 5400, 1,{5410},"5402","5404",5430} }, 2, &hanhoujiance2dparams[0], _serviceManager, bridge, HanHouJianCe2D, "焊后检测CCD"); + jiance_3d_1.init("Camera4", "焊后检测3D-相机1(前)", { { 5500, 1,{5510},"5502","5504",5530} }, 1, &hanhoujiance3dparams, _serviceManager, bridge, HanHouJianCe3D,"焊后检测CCD"); + jiance_2d_2.init("Camera5", "焊后检测2D-相机2(后)", { { 5600, 1,{5610},"5602","5604",5630} }, 2, &hanhoujiance2dparams[1], _serviceManager, bridge, HanHouJianCe2D, "焊后检测CCD"); + jiance_3d_2.init("Camera6", "焊后检测3D-相机2(后)", { { 5700, 1,{5710},"5702","5704",5730} }, 1, &hanhoujiance3dparams, _serviceManager, bridge, HanHouJianCe3D,"焊后检测CCD"); +#pragma endregion + return true; + } +}; + + + + + +#pragma once \ No newline at end of file diff --git a/src/mission/581_Ruanlianjie_hanqian_hanhou/CMakeLists.txt b/src/mission/581_Ruanlianjie_hanqian_hanhou/CMakeLists.txt new file mode 100644 index 0000000..76e9200 --- /dev/null +++ b/src/mission/581_Ruanlianjie_hanqian_hanhou/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/BaoMo/581-BaoMo-Cam5678/581-BaoMo-Cam5678.h b/src/mission/BaoMo/581-BaoMo-Cam5678/581-BaoMo-Cam5678.h index 5563a36..d215e71 100644 --- a/src/mission/BaoMo/581-BaoMo-Cam5678/581-BaoMo-Cam5678.h +++ b/src/mission/BaoMo/581-BaoMo-Cam5678/581-BaoMo-Cam5678.h @@ -99,24 +99,25 @@ static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianD HTuple out_Line = procedureCall.GetOutputCtrlParamTuple("out_Line"); HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); int outFlag = out_Flag.D(); + double batteryWidth = -99, batteryHeight = -99, moDaoDingGai = -99; // handleAiFuture.wait(); //auto defects = handleAiFuture.get(); if (outFlag == 1) { - for (int i = 0; i < out_Line.Length() / 4; i++) { - cv::line(Paint, cv::Point(out_Line[i * 4 + 1].D(), out_Line[i * 4].D()) / 2, - cv::Point(out_Line[i * 4 + 3].D(), out_Line[i * 4 + 2].D()) / 2, + //out_Distance[0]: 电芯宽度 < / c> + // * out_Distance[1] : 电芯高度< / c> + // * out_Distance[2] : 上端盖到膜的距离< / c> + // * out_Distance[3] : 中端盖到膜的距离< / c> + // * out_Distance[4] : 下端盖到膜的距离 < / c> + textPainter.putText(Paint, "电芯宽度:" + std::to_string(out_Distance[0].D()) + "mm", cv::Point(50, 150), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "电芯高度:" + std::to_string(out_Distance[1].D()) + "mm", cv::Point(50, 350), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "上端盖到膜的距离:" + std::to_string(out_Distance[2].D()) + "mm", cv::Point(50, 550), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "中端盖到膜的距离:" + std::to_string(out_Distance[3].D()) + "mm", cv::Point(50, 750), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "下端盖到膜的距离:" + std::to_string(out_Distance[4].D()) + "mm", cv::Point(50, 950), cv::Scalar(0, 255, 0)); + for (int i = 0; i < out_Line.Length() / 4 - 1; i++) { + cv::line(Paint, cv::Point(out_Line[i * 4 + 1].D(), out_Line[i * 4].D()), + cv::Point(out_Line[i * 4 + 3].D(), out_Line[i * 4 + 2].D()), cv::Scalar(0, 255, 0), 5); } - /*out_Distance[0]: 上端盖到膜的距离< / c> - * out_Distance[1] : 中端盖到膜的距离< / c> - * out_Distance[2] : 下端盖到膜的距离< / c> - * out_Distance[3] : 电芯宽度 < / c> - * out_Distance[4] : 电芯高度< / c>*/ - textPainter.putText(Paint, "上端盖到膜的距离:" + std::to_string(out_Distance[0].D()) + "mm", cv::Point(50, 150), cv::Scalar(0, 255, 0)); - textPainter.putText(Paint, "中端盖到膜的距离:" + std::to_string(out_Distance[1].D()) + "mm", cv::Point(50, 350), cv::Scalar(0, 255, 0)); - textPainter.putText(Paint, "下端盖到膜的距离:" + std::to_string(out_Distance[2].D()) + "mm", cv::Point(50, 550), cv::Scalar(0, 255, 0)); - textPainter.putText(Paint, "电芯宽度:" + std::to_string(out_Distance[3].D()) + "mm", cv::Point(50, 750), cv::Scalar(0, 255, 0)); - textPainter.putText(Paint, "电芯高度:" + std::to_string(out_Distance[4].D()) + "mm", cv::Point(50, 950), cv::Scalar(0, 255, 0)); } else { data->halconOK = false; @@ -125,8 +126,10 @@ static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianD data->resultImgs.push_back(Paint); //data->service->_missionResultHandle->toBarChart(data->SNcode, !defects.size() > 0, defects); - data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123"); - data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_0.0123"); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + + "_" + QByteArray::number(batteryWidth) + + "_" + QByteArray::number(batteryHeight) + + "_" + QByteArray::number(moDaoDingGai)); data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1"); return true; } diff --git a/src/mission/DGH/581-Dgh-CB-1/581-Dgh-CB-1.h b/src/mission/DGH/581-Dgh-CB-1/581-Dgh-CB-1.h index 7ee9ca9..0ed8884 100644 --- a/src/mission/DGH/581-Dgh-CB-1/581-Dgh-CB-1.h +++ b/src/mission/DGH/581-Dgh-CB-1/581-Dgh-CB-1.h @@ -3,20 +3,135 @@ #include #include #include -struct jiuPiamResult{ - QByteArray result = "2"; - QByteArray x = "1.1"; - QByteArray y = "1.1"; -}; - #pragma region 算法 using namespace HDevEngineCpp; #pragma endregion +void exceptionResume(std::shared_ptr data, detParams* _detParams, yh_581_address address, QString why = "") { + qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode) << why; + cv::Mat Paint; + data->oriImgs[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->resultImgs.push_back(Paint); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_1,1,1,1,1,1,1,1,1,1,1,1,1,1"); + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 +} +static bool yuHanQian3D(std::shared_ptr data, detParams* _detParams, yh_581_address address) { + try { + double heightThreshold = data->service->_paramSyncManager->get("预焊前", "高度/台阶差最大阈值",0.3).toDouble(); + double widthThreshold = data->service->_paramSyncManager->get("预焊前", "缝隙值最大阈值", 0.1).toDouble(); + //data->oriImgs.clear(); + //data->oriImgs.push_back(cv::imread("D://readSnEmpty16-02-21-96_Camera4_0.tiff", -1)); + //data->oriImgs.push_back(cv::imread("D://readSnEmpty16-02-21-96_Camera4_1.tiff", -1)); + if (data->oriImgs.size() < 2) { + exceptionResume(data, _detParams, address, "NG"); + return true; + } + cv::Mat heightImg = data->oriImgs[1]; + cv::Mat lumImg = data->oriImgs[0]; + cv::Mat Paint; + HalconCpp::HObject in_imageH = MatToHObject(heightImg); + HalconCpp::HObject in_imageLum = MatToHObject(lumImg); + HDevEngineCpp::HDevProcedure proc("_6_detect_gap_width_height"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_imageH", in_imageH); + procedureCall.SetInputIconicParamObject("in_imageLum", in_imageLum); + + procedureCall.SetInputCtrlParamTuple("in_xResolution", 0.005); + procedureCall.SetInputCtrlParamTuple("in_yResolution", data->service->_paramSyncManager->get("3D设置", "3D相机Y方向精度",0.177).toFloat()); + procedureCall.SetInputCtrlParamTuple("in_zResolution", 0.0008); + if(address.triggerAddr == 18000 || address.triggerAddr == 18002 || address.triggerAddr == 18400 || address.triggerAddr == 18402) + procedureCall.SetInputCtrlParamTuple("in_Location", "Right"); + else + procedureCall.SetInputCtrlParamTuple("in_Location", "Left"); + procedureCall.Execute(); + HObject out_DisplayImage = procedureCall.GetOutputIconicParamObject("out_DisplayImage"); + + HTuple out_MaxHeight = procedureCall.GetOutputCtrlParamTuple("out_MaxHeight"); + HTuple out_MaxWidth = procedureCall.GetOutputCtrlParamTuple("out_MaxWidth"); + HTuple out_ResultRow = procedureCall.GetOutputCtrlParamTuple("out_ResultRow"); + HTuple out_ResultColumn = procedureCall.GetOutputCtrlParamTuple("out_ResultColumn"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + HTuple out_NgTails = procedureCall.GetOutputCtrlParamTuple("out_NgTails"); + HTuple out_DisplayRows = procedureCall.GetOutputCtrlParamTuple("out_DisplayRows"); + HTuple out_DisplayCols = procedureCall.GetOutputCtrlParamTuple("out_DisplayCols"); + int flag = out_Flag.D(); + TextRendererZH textPainter(Paint.cols, Paint.rows, 75); + Paint = HObject2Mat(out_DisplayImage); + textPainter.putText(Paint, data->SNcode, cv::Point(1600,50), cv::Scalar(0, 255, 0)); + bool isOK = true; + QByteArray gaoDuChaSendText, fengXiSendText; + if (flag == 1) { + int yStart = -25; + for (int i = 0; i < 4 && i < out_DisplayRows.Length(); i++) { + double MaxHeight = std::abs(out_MaxHeight[i].D()); + double MaxWidth = std::abs(out_MaxWidth[i].D()); + + cv::Point displayPos( 1000, out_DisplayRows[i].D() - 50); + textPainter.putText(Paint, "检测区域" + std::to_string(i + 1) + ":", displayPos, cv::Scalar(0, 255, 0)); + + displayPos.x += 280; + if (std::abs(MaxHeight) > std::abs(heightThreshold)) { + textPainter.putText(Paint, "高度/台阶差" + QString::number(MaxHeight, 'f', 3).toStdString() +"mm", displayPos, cv::Scalar(0, 0, 255)); + isOK = false; + } + else + textPainter.putText(Paint, "高度/台阶差" + QString::number(MaxHeight, 'f', 3).toStdString() + "mm", displayPos, cv::Scalar(0, 255, 0)); + + displayPos.x += 600; + if (std::abs(MaxWidth) > std::abs(widthThreshold)) { + textPainter.putText(Paint, "缝隙值" + QString::number(MaxWidth, 'f', 3).toStdString() + "mm", displayPos, cv::Scalar(0, 0, 255)); + isOK = false; + } + else + textPainter.putText(Paint, "缝隙值" + QString::number(MaxWidth, 'f', 3).toStdString() + "mm", displayPos, cv::Scalar(0, 255, 0)); + if (i != 2) { + gaoDuChaSendText += QByteArray::number(MaxHeight) + ","; + fengXiSendText += QByteArray::number(MaxWidth) + ","; + } + } + } + else { + gaoDuChaSendText = "-1,-1,-1,"; + fengXiSendText = "-1,-1,-1,"; + std::string ngDetailStr = gbkToUtf8(out_NgTails.ToString().Text()); + textPainter.putText(Paint, ngDetailStr.substr(1, ngDetailStr.length() - 2), cv::Point(50, 450), cv::Scalar(0, 0, 255)); + for (int i = 0; i < out_ResultRow.Length(); i++) { + cv::circle(Paint, cv::Point(out_ResultRow[i].D(), out_ResultColumn[i].D()),1, cv::Scalar(0, 0, 255), 1); + } + data->halconOK = false; + isOK = false; + } + QByteArray plcResult = "1"; + if (isOK == false) { + textPainter.putText(Paint, "NG", cv::Point(50, 50), cv::Scalar(0, 0, 255)); + plcResult = "2"; + data->halconOK = false; + } + else + textPainter.putText(Paint, "OK", cv::Point(50, 50), cv::Scalar(0, 255, 0)); + if (data->service->_paramSyncManager->get("通用设置", "强制OK", false).toBool()) + plcResult = "1"; + data->resultImgs.push_back(Paint); + data->service->_triggerManager->writeFloat("D" + + QByteArray::number(address.valueOffsetAddr) + "_" + + fengXiSendText + "1,1," + + gaoDuChaSendText + plcResult + "," + plcResult + "," + plcResult + "," + plcResult +"," + plcResult + "," + plcResult);//数值1 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 + return true; + } + CATCH_EXCEPTIONS + exceptionResume(data, _detParams, address, "NG"); + return true; +} class _581_Dgh : public mission { public: using generalTrigger = _581_Union_triggerTemplate; @@ -33,19 +148,27 @@ public: void onConfigReloaded() { HDevEngineCpp::HDevEngine myEngine; - myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); + myEngine.SetProcedurePath("./halconAlgo/AlgoLibrary_602.hdpl"); } bool initCustom() { #pragma region 注册触发器回调 - dgh_cb_yh_3d_1.init("Camera1", "长边预焊前3D-1", 18000,2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_yh_3d_2.init("Camera2", "长边预焊前3D-2", 18200,2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_yh_3d_3.init("Camera3", "长边预焊前3D-3", 18400,2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_yh_3d_4.init("Camera4", "长边预焊前3D-4", 18600,2,1, &_params, _serviceManager, bridge, generalAlgoTest); - + dgh_cb_yh_3d_1.init("Camera1", "长边预焊前3D-1", 18000,2,1, &_params, _serviceManager, bridge, yuHanQian3D); + dgh_cb_yh_3d_1.address[1].valueOffsetAddr += 20; + dgh_cb_yh_3d_2.init("Camera2", "长边预焊前3D-2", 18200,2,1, &_params, _serviceManager, bridge, yuHanQian3D); + dgh_cb_yh_3d_2.address[1].valueOffsetAddr += 20; + dgh_cb_yh_3d_3.init("Camera3", "长边预焊前3D-3", 18400,2,1, &_params, _serviceManager, bridge, yuHanQian3D); + dgh_cb_yh_3d_3.address[1].valueOffsetAddr += 20; + dgh_cb_yh_3d_4.init("Camera4", "长边预焊前3D-4", 18600,2,1, &_params, _serviceManager, bridge, yuHanQian3D); + dgh_cb_yh_3d_4.address[1].valueOffsetAddr += 20; + dgh_cb_mh_3d_1.init("Camera5", "长边满焊前3D-1", 19600,2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_1.address[1].valueOffsetAddr += 20; dgh_cb_mh_3d_2.init("Camera6", "长边满焊前3D-2", 19800,2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_2.address[1].valueOffsetAddr += 20; dgh_cb_mh_3d_3.init("Camera7", "长边满焊前3D-3", 20000,2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_3.address[1].valueOffsetAddr += 20; dgh_cb_mh_3d_4.init("Camera8", "长边满焊前3D-4", 20200,2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_3d_4.address[1].valueOffsetAddr += 20; #pragma endregion return true; } diff --git a/src/mission/DGH/581-Dgh-CB-2/581-Dgh-CB-2.h b/src/mission/DGH/581-Dgh-CB-2/581-Dgh-CB-2.h index f2f4897..ede2e4f 100644 --- a/src/mission/DGH/581-Dgh-CB-2/581-Dgh-CB-2.h +++ b/src/mission/DGH/581-Dgh-CB-2/581-Dgh-CB-2.h @@ -3,13 +3,382 @@ #include #include #include - -#pragma region 算法 - using namespace HDevEngineCpp; +#pragma region 辊压后2D算法 + +class GunYaHou2DParam { +public: + handdleAI::pSegmentation* seg = nullptr; + handdleAI::pClassification* cls = nullptr; + handdleAI::pDetection* det = nullptr; +}; +void exceptionResume(std::shared_ptr data, GunYaHou2DParam* _detParams, yh_581_address address, QString why = "") { + qDebug() << "[Error] " << QString::fromUtf8("检测失败!") << data->uuid << QString::fromStdString(data->SNcode) << why; + cv::Mat Paint; + data->oriImgs[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->resultImgs.push_back(Paint); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_1");//数值1 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_1");//数值2 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_1");//数值3 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_1");//数值4 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 8) + "_1");//数值5 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 10) + "_1");//数值6 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 12) + "_1");//数值7 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 14) + "_1");//数值8 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 16) + "_1");//数值9 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 +} +cv::Mat LocalCutImg_DET(handdleAI::pDetection* pDet, cv::Mat src, float zoom, int checkNameId, cv::Rect& cutRoi) +{ + cv::Mat dst; + cv::resize(src, dst, cv::Size(src.cols / zoom, src.rows / zoom)); + std::vector resultBox = pDet->Evaluate(dst); //结果为中心点+宽高 + + cv::Mat contourImg; + std::vector> contours; + //cv::threshold(dstImg, contourImg, pSeg->m_classes, 255, cv::THRESH_BINARY_INV); + //cv::findContours(contourImg, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + + cv::Mat roiImg; + + if (resultBox.size() <= 0) + { + cv::Mat rstMat = cv::Mat(100, 100, CV_8UC1, cv::Scalar(0, 0, 0)); + cutRoi = cv::Rect(0, 0, 100, 100); + return rstMat; + } + + double maxArea = 0; + int index = -1; + for (int j = 0; j < resultBox.size(); j++) + { + double area = resultBox[j].w * resultBox[j].h; + if (area >= maxArea) + { + maxArea = area; + index = j; + } + } + + /*cv::Rect rect = cv::boundingRect(contours[index]); + cv::rectangle(roiImg, cv::Rect(resultBox[j].x - resultBox[j].w / 2, resultBox[j].y - resultBox[j].h / 2, resultBox[j].w, resultBox[j].h), cv::Scalar(0, 0, 255), 5);*/ + int addpixel = 15; + + cutRoi.x = ((resultBox[index].x - resultBox[index].w / 2) * zoom); + cutRoi.y = ((resultBox[index].y - resultBox[index].h / 2) * zoom); + cutRoi.width = (resultBox[index].w * zoom); + cutRoi.height = (resultBox[index].h * zoom); + //cv::rectangle(src, cutRoi, cv::Scalar(0, 0, 255), 2, 8); + /* cutRoi.x = rect.x * zoom; + cutRoi.y = rect.y * zoom; + cutRoi.width = rect.width * zoom; + cutRoi.height = rect.height * zoom;*/ + + src(cutRoi).copyTo(roiImg); + return roiImg; +} +static std::vectordingGaiHanClsCut(cv::Rect boundingBox, cv::Mat imgInput, cv::Size targetSize = cv::Size(128, 128)) +{ + std::vector result; + int splitCount = std::max(boundingBox.width, boundingBox.height) / std::max(boundingBox.width, boundingBox.height); + //std::cout << "splitCount" << splitCount; + if (splitCount > 2) {//大于2分段裁 + if (boundingBox.width > boundingBox.height) {//宽大于高,横着裁 + for (int i = 0; i < splitCount; i++) { + result.push_back(cutImg2Cls(cv::Rect(boundingBox.x + boundingBox.height * i, boundingBox.y, boundingBox.height, boundingBox.height), imgInput)); + } + result.push_back(cutImg2Cls(cv::Rect(boundingBox.x + boundingBox.width - boundingBox.height, boundingBox.y, boundingBox.height, boundingBox.height), imgInput)); + } + else { + for (int i = 0; i < splitCount; i++) { + result.push_back(cutImg2Cls(cv::Rect(boundingBox.x, boundingBox.y + boundingBox.width * i, boundingBox.width, boundingBox.width), imgInput)); + } + result.push_back(cutImg2Cls(cv::Rect(boundingBox.x, boundingBox.y + boundingBox.height - boundingBox.width, boundingBox.width, boundingBox.width), imgInput)); + } + return result; + } + else + return std::vector(1, cutImg2Cls(boundingBox, imgInput, targetSize)); +} +bool handleAiEvaluate(std::shared_ptr data, GunYaHou2DParam* _detParams, cv::Mat& srcImg, cv::Mat& showImg) { + bool handleAiResultIsOK = true; + clock_t start = clock(); + + + //DET方案 + // cv::Mat imgForDet; + //srcImg.copyTo(imgForDet); + //cv::Rect detRect; + //cv::Mat det_Image = LocalCutImg_DET(_detParams->det, imgForDet, 1, 0, detRect); + + //固定坐标方案 + //cv::Rect detRect(150, 1400, 3800, 300); + //cv::Mat det_Image; + //srcImg(detRect).copyTo(det_Image); + + //cv::rectangle(showImg, detRect, cv::Scalar(0, 255, 255), 2); + //cv::Mat segImg = ~_detParams->seg->Evaluate(det_Image);//一定要取反,因为seg默认抓到的区域为黑色 + //data->segOriginImgs.push_back(det_Image); + cv::Mat det_Image = srcImg; + cv::Mat segImg = ~_detParams->seg->Evaluate(det_Image);//一定要取反,因为seg默认抓到的区域为黑色 + clock_t stop = clock(); + std::vector>contours;//点集 + stop = clock(); + cv::findContours(segImg, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); // 寻找白色区域并储存为点集 + //QMutexLocker lock(showImgLocker);//加锁防止和halcon线程冲突 + int clsResult = 0; + for (int i = 0; i < contours.size(); i++)//遍历点集 + { + cv::Rect rect = cv::boundingRect(contours[i]);//最小外接矩形 + //if( (rect.height > 25 || rect.width > 50) && (rect.height > 10 && rect.width > 10))// 过滤 + if ((rect.height > 40 || rect.width > 100) && (rect.height > 30 && rect.width > 10)) + { + auto clsimgs = dingGaiHanClsCut(rect, det_Image); + bool isNg = false; + int cnt = 0; + for (auto& clsImg : clsimgs) + { + clsResult = _detParams->cls->Evaluate(clsImg);//cls检测 得出的是int型 从0开始 + if (clsResult == 1 || clsResult == 3) { + isNg = true; + } + //addImgToSaveStruct(clsImg, "0", savePath_sorce + "/" + SN + "_cls" + QString::number(clsResult) + "_" + sdataTime_name + ".bmp"); + data->clsOriginImgs.push_back({ std::to_string(clsResult),clsImg }); + cnt++; + drawContours(showImg, contours, i, cv::Scalar(0, 255, 0), 1); + } + if (isNg == true) + { + rectangle(showImg, cv::Rect{ rect.x,rect.y,rect.width ,rect.height }, cv::Scalar(0, 0, 255), 2, 8, 0); + //drawContours(showImg(detRect), contours, i, cv::Scalar(0, 255, 0), 1); + handleAiResultIsOK = false; + } + else + { + if (clsResult == 2) + { + rectangle(showImg, cv::Rect{ rect.x,rect.y,rect.width ,rect.height }, cv::Scalar(0, 255, 255), 2, 8, 0); + //drawContours(showImg(detRect), contours, i, cv::Scalar(0, 255, 0), 1); + } + } + } + else + { + auto clsimgs = dingGaiHanClsCut(rect, det_Image); + int cnt = 0; + for (auto& clsImg : clsimgs) + { + data->clsOriginImgs.push_back({ std::to_string(clsResult),clsImg }); + //addImgToSaveStruct(clsImg, "0", savePath_sorce + "/CSSMALL_" + SN + "_" + sdataTime_name + ".bmp"); + cnt++; + drawContours(showImg, contours, i, cv::Scalar(0, 255, 0), 1); + } + } + } + return handleAiResultIsOK; +} + +static bool GunYaHou2D(std::shared_ptr data, GunYaHou2DParam* _detParams, yh_581_address address) { + try { + //data->oriImgs.clear(); + //data->oriImgs.push_back(cv::imread("D://04QCB82601000JFB50000011_Camera7_0.bmp", -1)); + //data->oriImgs.push_back(cv::imread("D://04QCB82601000JFB50000011_Camera8_0.bmp", -1)); + cv::Mat sourceImg1 = data->oriImgs[0], sourceImg2 = data->oriImgs[1]; + cv::Mat Paint1,Paint2; + sourceImg1.copyTo(Paint1); + sourceImg2.copyTo(Paint2); + if (Paint1.channels() == 1) + cvtColor(Paint1, Paint1, cv::COLOR_GRAY2BGR); + if (Paint2.channels() == 1) + cvtColor(Paint2, Paint2, cv::COLOR_GRAY2BGR); + bool isOK = handleAiEvaluate(data, _detParams, sourceImg1, Paint1); + isOK = handleAiEvaluate(data, _detParams, sourceImg2, Paint2); + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_1");//数值1 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_1");//数值2 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_1");//数值3 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_1");//数值4 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 8) + "_1");//数值5 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 10) + "_1");//数值6 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 12) + "_1");//数值7 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 14) + "_1");//数值8 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 16) + "_1");//数值9 + if (isOK == true) + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + else + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + + { + TextRendererZH textPainter(Paint1.cols, Paint1.rows, 300); + if (isOK == true) { + textPainter.putText(Paint1, "OK", cv::Point(0, 200), cv::Scalar(0, 255, 0)); + } + else { + textPainter.putText(Paint1, "NG", cv::Point(0, 200), cv::Scalar(0, 0, 255)); + data->aiDetOK = false; + data->service->_missionResultHandle->toBarChart(data->SNcode, true, { "焊后NG" }); + qDebug() << QString::fromStdString(data->SNcode) << "is NG"; + } + + cv::resize(Paint1, Paint1, cv::Size(), 0.5, 0.5); + data->resultImgs.push_back(Paint1); + } + { + TextRendererZH textPainter(Paint2.cols, Paint2.rows, 300); + if (isOK == true) { + textPainter.putText(Paint2, "OK", cv::Point(0, 200), cv::Scalar(0, 255, 0)); + } + else { + textPainter.putText(Paint2, "NG", cv::Point(0, 200), cv::Scalar(0, 0, 255)); + data->aiDetOK = false; + data->service->_missionResultHandle->toBarChart(data->SNcode, true, { "焊后NG" }); + qDebug() << QString::fromStdString(data->SNcode) << "is NG"; + } + + cv::resize(Paint2, Paint2, cv::Size(), 0.5, 0.5); + data->resultImgs.push_back(Paint2); + } + return true; + } + CATCH_EXCEPTIONS + exceptionResume(data, _detParams, address, "算法异常"); + return true; +} #pragma endregion +#pragma region 辊压后3D算法 +static bool gunYaHou3D(std::shared_ptr data, detParams* _detParams, yh_581_address address) { + try { + /* double heightThreshold = data->service->_paramSyncManager->get("预焊前", "高度/台阶差最大阈值", 0.3).toDouble(); + double widthThreshold = data->service->_paramSyncManager->get("预焊前", "缝隙值最大阈值", 0.1).toDouble();*/ + //data->oriImgs.clear(); + //data->oriImgs.push_back(cv::imread("D://readSnEmpty16-02-21-96_Camera4_0.tiff", -1)); + //data->oriImgs.push_back(cv::imread("D://readSnEmpty16-02-21-96_Camera4_1.tiff", -1)); + if (data->oriImgs.size() < 2) { + generalExceptionResume(data, address, "NG"); + return true; + } + cv::Mat heightImg = data->oriImgs[1]; + cv::Mat lumImg = data->oriImgs[0]; + cv::Mat Paint; + HalconCpp::HObject in_imageH = MatToHObject(heightImg); + HalconCpp::HObject in_imageLum = MatToHObject(lumImg); + HDevEngineCpp::HDevProcedure proc("_6_Inspection_Defect_3D"); + HDevProcedureCall procedureCall(proc); + procedureCall.SetInputIconicParamObject("in_imageH", in_imageH); + + procedureCall.SetInputCtrlParamTuple("in_xResolution", 0.005); + procedureCall.SetInputCtrlParamTuple("in_yResolution", data->service->_paramSyncManager->get("3D设置", "3D相机Y方向精度", 0.177).toFloat()); + procedureCall.SetInputCtrlParamTuple("in_zResolution", 0.0008); + procedureCall.Execute(); + + HTuple out_DefectHeight = procedureCall.GetOutputCtrlParamTuple("out_DefectHeight"); + HTuple out_DefectRec = procedureCall.GetOutputCtrlParamTuple("out_DefectRec"); + HTuple out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + + int flag = out_Flag.D(); + TextRendererZH textPainter(Paint.cols, Paint.rows, 75); + textPainter.putText(Paint, data->SNcode, cv::Point(1600, 50), cv::Scalar(0, 255, 0)); + bool isOK = true; + QByteArray textSend; + if (flag == 1) { + int yStart = -25; + for (int i = 0; i < out_DefectHeight .Length(); i++) { + double value = out_DefectHeight[i].D(); + cv::Rect rect(out_DefectRec[i * 4], out_DefectRec[i * 4] + 1, out_DefectRec[i * 4 + 2], out_DefectRec[i * 4 + 3]); + textSend += QByteArray::number(value) + ","; + data->halconOK = false; + isOK = false; + } + } + + QByteArray plcResult = "1"; + if (isOK == false) { + textPainter.putText(Paint, "NG", cv::Point(50, 50), cv::Scalar(0, 0, 255)); + plcResult = "2"; + data->halconOK = false; + } + else + textPainter.putText(Paint, "OK", cv::Point(50, 50), cv::Scalar(0, 255, 0)); + + data->resultImgs.push_back(Paint); + data->service->_triggerManager->writeFloat("D" + + QByteArray::number(address.valueOffsetAddr) + "_" + + textSend + "1");//数值1 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 + return true; + } + CATCH_EXCEPTIONS + generalExceptionResume(data, address, "NG"); + return true; +} +#pragma endregion + +static bool generalAlgoTestDuanBian(std::shared_ptr data, detParams* _detParams, yh_581_address address) { + try { + qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; + data->customPath = "{imgSaveRootDir}/{yyyy-MM-dd}/{saveObjectName}{imageType}/{HH}H/{processResult}/"; + std::vector < std::string> defects = { "测试" }; + ///////////////////取图//处理////////////////// + if (data->oriImgs.size() < 1) + { + qCritical() << "图片数量不满足要求:" << data->oriImgs.size(); + return false; + } + if (data->oriImgs[0].rows == 100) { + cv::Mat Paint; + data->oriImgs[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->oriImgs[0]; + if (src1.channels() != 3) + cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); + else + src1.copyTo(Paint); + + TextRendererZH textPainter(Paint.cols, Paint.rows, 15); + textPainter.putText(Paint, "划伤", cv::Point(10, 10), cv::Scalar(0, 255, 0)); + 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->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_1");//数值1 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_1");//数值2 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_1");//数值3 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_1");//数值4 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 8) + "_1");//数值5 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 10) + "_1");//数值6 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 12) + "_1");//数值7 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 14) + "_1");//数值8 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 16) + "_1");//数值9 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 + data->service->_missionResultHandle->toBarChart(data->SNcode, !defects.size() > 0, defects);//发送图标操作 + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + data->resultImgs.push_back(Paint); + return true; + } + CATCH_EXCEPTIONS + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_1");//数值1 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_1");//数值2 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 4) + "_1");//数值3 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 6) + "_1");//数值4 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 8) + "_1");//数值5 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 10) + "_1");//数值6 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 12) + "_1");//数值7 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 14) + "_1");//数值8 + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 16) + "_1");//数值9 + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送异常结果 + return false; +} class _581_Dgh : public mission { public: using generalTrigger = _581_Union_triggerTemplate; @@ -18,41 +387,58 @@ public: generalTrigger dgh_cb_mh_2d_3; generalTrigger dgh_cb_mh_2d_4; - generalTrigger dgh_cb_gy_2d_1; - generalTrigger dgh_cb_gy_2d_2; - generalTrigger dgh_cb_gy_2d_3; - generalTrigger dgh_cb_gy_2d_4; + _581_Union_triggerTemplate dgh_cb_gy_2d_1; + _581_Union_triggerTemplate dgh_cb_gy_2d_2; + _581_Union_triggerTemplate dgh_cb_gy_2d_3; + _581_Union_triggerTemplate dgh_cb_gy_2d_4; + std::vector _GunYaHou2DParam = std::vector(4); generalTrigger dgh_cb_gy_3d_1; generalTrigger dgh_cb_gy_3d_2; generalTrigger dgh_cb_gy_3d_3; generalTrigger dgh_cb_gy_3d_4; detParams _params; - + bool initOnce = false; void onConfigReloaded() { HDevEngineCpp::HDevEngine myEngine; myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_602.hdpl"); + if (initOnce == false) { + for (auto& param : _GunYaHou2DParam) { + param.seg = handdleAI::CreateSegObjS("./handleaiModels/seg_hanhou.BHD", 1, 0); + param.cls = handdleAI::CreateClsObjV3("./handleaiModels/cls_hanhou.BHD", 0, 1); + //param.det = handdleAI::CreateDetObjS("./handleaiModels/det_hanhou.BHD", 1, 0); + } + initOnce = true; + } } bool initCustom() { #pragma region 注册触发器回调 满焊前2D - //generalTrigger::resultHandleCallback resultCallback_general = - // ([=](yh_581_address address, _581_Result, std::shared_ptr ) { - // _serviceManager->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 - // }); - dgh_cb_mh_2d_1.init("Camera1", "长边满焊前2D-1",18800, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_mh_2d_2.init("Camera2", "长边满焊前2D-2", 19000, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_mh_2d_3.init("Camera3", "长边满焊前2D-3", 19200, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_mh_2d_4.init("Camera4", "长边满焊前2D-4", 19400, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_mh_2d_1.init("Camera1", "长边满焊前2D-1",18800, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "满焊前2D"); + dgh_cb_mh_2d_1.address[1].valueOffsetAddr += 20;dgh_cb_mh_2d_1.address[1].valueOffsetAddr += 20; + dgh_cb_mh_2d_2.init("Camera2", "长边满焊前2D-2", 19000, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "满焊前2D"); + dgh_cb_mh_2d_2.address[1].valueOffsetAddr += 20; + dgh_cb_mh_2d_3.init("Camera3", "长边满焊前2D-3", 19200, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "满焊前2D"); + dgh_cb_mh_2d_3.address[1].valueOffsetAddr += 20; + dgh_cb_mh_2d_4.init("Camera4", "长边满焊前2D-4", 19400, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "满焊前2D"); + dgh_cb_mh_2d_4.address[1].valueOffsetAddr += 20; - dgh_cb_gy_2d_1.init("Camera5", "长边滚压后2D-1", 20400, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_2d_2.init("Camera6", "长边滚压后2D-2", 20600, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_2d_3.init("Camera7", "长边滚压后2D-3", 20800, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_2d_4.init("Camera8", "长边滚压后2D-4", 21000, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_2d_1.init("Camera5", "长边辊压后2D-1", 20400, 2,2, &_GunYaHou2DParam[0], _serviceManager, bridge, GunYaHou2D, "辊压后2D"); + dgh_cb_mh_2d_1.address[1].valueOffsetAddr += 20; + dgh_cb_gy_2d_2.init("Camera6", "长边辊压后2D-2", 20600, 2,2, &_GunYaHou2DParam[1], _serviceManager, bridge, GunYaHou2D, "辊压后2D"); + dgh_cb_gy_2d_2.address[1].valueOffsetAddr += 20; + dgh_cb_gy_2d_3.init("Camera7", "长边辊压后2D-3", 20800, 2,2, &_GunYaHou2DParam[2], _serviceManager, bridge, GunYaHou2D, "辊压后2D"); + dgh_cb_gy_2d_3.address[1].valueOffsetAddr += 20; + dgh_cb_gy_2d_4.init("Camera8", "长边辊压后2D-4", 21000, 2,2, &_GunYaHou2DParam[3], _serviceManager, bridge, GunYaHou2D, "辊压后2D"); + dgh_cb_gy_2d_4.address[1].valueOffsetAddr += 20; - dgh_cb_gy_3d_1.init("Camera9", "长边滚压后3D-1", 21200, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_3d_2.init("Camera10", "长边滚压后3D-2", 21400, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_3d_3.init("Camera11", "长边滚压后3D-3", 21600, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); - dgh_cb_gy_3d_4.init("Camera12", "长边滚压后3D-4", 21800, 2,1, &_params, _serviceManager, bridge, generalAlgoTest); + dgh_cb_gy_3d_1.init("Camera9", "长边辊压后3D-1", 21200, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "辊压后3D"); + dgh_cb_gy_3d_1.address[1].valueOffsetAddr += 20; + dgh_cb_gy_3d_2.init("Camera10", "长边辊压后3D-2", 21400, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "辊压后3D"); + dgh_cb_gy_3d_2.address[1].valueOffsetAddr += 20; + dgh_cb_gy_3d_3.init("Camera11", "长边辊压后3D-3", 21600, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "辊压后3D"); + dgh_cb_gy_3d_3.address[1].valueOffsetAddr += 20; + dgh_cb_gy_3d_4.init("Camera12", "长边辊压后3D-4", 21800, 2,1, &_params, _serviceManager, bridge, generalAlgoTestDuanBian, "辊压后3D"); + dgh_cb_gy_3d_4.address[1].valueOffsetAddr += 20; #pragma endregion return true; } diff --git a/src/mission/ZhongHan/581_ZhongHan_hanqian/581_ZhongHan_hanqian.h b/src/mission/ZhongHan/581_ZhongHan_hanqian/581_ZhongHan_hanqian.h index 888720f..edd13b0 100644 --- a/src/mission/ZhongHan/581_ZhongHan_hanqian/581_ZhongHan_hanqian.h +++ b/src/mission/ZhongHan/581_ZhongHan_hanqian/581_ZhongHan_hanqian.h @@ -78,15 +78,25 @@ public: bool hanQianCeLiang_Main(std::shared_ptr data, zhongHanHanQianParams* _detParams, sx_581_address address) { try{ - QByteArray plcResult = "2"; + QByteArray plcResult = "1"; #if 0 - /*img2D = cv::imread("./testImages/CU_1.png", -1); - sourceImg = img2D.clone();*/ - img2D = cv::imread("./testImages/CU.bmp", -1); - sourceImg = img2D(cutROI & cv::Rect(0, 0, img2D.cols, img2D.rows)).clone(); + data->oriImgs[0] = cv::imread("D:\\testImage\\T.bmp", -1); #endif + double xinBaoJianJuLimitHigh = data->service->_paramSyncManager->get("焊前检测","芯包间距(上限)", 72.00).toDouble(); + double xinBaoJianJuLimitLow = data->service->_paramSyncManager->get("焊前检测", "芯包间距(下限)", 68.00).toDouble(); + bool xinBaoJianJuLimitEnable = data->service->_paramSyncManager->get("焊前检测", "芯包间距判定启用", true).toBool(); + + double xinBaoDingBuDaoYuanXinLimitHigh = data->service->_paramSyncManager->get("焊前检测", "芯包顶部到圆心距离(上限)", 35.00).toDouble(); + double xinBaoDingBuDaoYuanXinLimitLow = data->service->_paramSyncManager->get("焊前检测", "芯包顶部到圆心距离(下限)", 33.00).toDouble(); + bool xinBaoDingBuDaoYuanXinLimitEnable = data->service->_paramSyncManager->get("焊前检测", "芯包顶部到圆心距离判定启用", true).toBool(); + + double lianJiePianJianJuLimitHigh = data->service->_paramSyncManager->get("焊前检测", "连接片间距(上限)", 124.00).toDouble(); + double lianJiePianJianJuLimitLow = data->service->_paramSyncManager->get("焊前检测", "连接片间距(下限)", 122.00).toDouble(); + bool lianJiePianJianJuLimitEnable = data->service->_paramSyncManager->get("焊前检测", "连接片间距判定启用", true).toBool(); + cv::Mat sourceImg = data->oriImgs[0]; sourceImg(cv::Rect(2400, 0, 3000, 3648)).copyTo(sourceImg); + data->segOriginImgs.push_back(sourceImg); cv::Mat Paint; sourceImg.copyTo(Paint); if (Paint.channels() == 1) @@ -101,7 +111,7 @@ bool hanQianCeLiang_Main(std::shared_ptr data, zhongHanHanQianParams* HalconCpp::HObject ho_Image_T; HalconCpp::HObject ho_Image_L; - HalconCpp::HTuple in_Resolution = 0.0337797; + HalconCpp::HTuple in_Resolution = 0.032594099; HalconCpp::HTuple in_FilePath = "./halconFiles/ZH_HanYin/"; HalconCpp::HTuple in_LineType = "602"; ho_Image_T = MatToHObject(sourceImg); @@ -158,11 +168,27 @@ bool hanQianCeLiang_Main(std::shared_ptr data, zhongHanHanQianParams* } _detParams->insertResult(_calResult); - textPainter.putText(Paint, "铜(负)极的包膜距离:" + std::to_string(Out_Vale_T_1), cv::Point(50, 50), cv::Scalar(0, 255, 0)); - data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(Out_Vale_T_1));//数据1 + if (Out_Vale_T_1 > xinBaoJianJuLimitHigh || Out_Vale_T_1 < xinBaoJianJuLimitLow) { + + textPainter.putText(Paint, "铜(负)极的包膜距离:" + std::to_string(Out_Vale_T_1), cv::Point(50, 50), cv::Scalar(0, 0, 255)); + if (xinBaoJianJuLimitEnable == true) + plcResult = "2"; + } + else + textPainter.putText(Paint, "铜(负)极的包膜距离:" + std::to_string(Out_Vale_T_1), cv::Point(50, 50), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "铜(负)极连接片中心的和上极耳水平边缘距离:" + std::to_string(Out_Vale_T_2), cv::Point(50, 200), cv::Scalar(0, 255, 0)); textPainter.putText(Paint, "铜(负)极连接片中心的和下极耳水平边缘距离:" + std::to_string(Out_Vale_T_3), cv::Point(50, 350), cv::Scalar(0, 255, 0)); - textPainter.putText(Paint, "铜(负)极和铝(正)极的中心距离:" + std::to_string(extremum_Value), cv::Point(50, 600), cv::Scalar(0, 255, 0)); + + if (extremum_Value > lianJiePianJianJuLimitHigh || extremum_Value < lianJiePianJianJuLimitLow) { + textPainter.putText(Paint, "铜(负)极和铝(正)极的中心距离:" + std::to_string(extremum_Value), cv::Point(50, 600), cv::Scalar(0, 0, 255)); + if (lianJiePianJianJuLimitEnable == true) + plcResult = "2"; + } + else + textPainter.putText(Paint, "铜(负)极和铝(正)极的中心距离:" + std::to_string(extremum_Value), cv::Point(50, 600), cv::Scalar(0, 255, 0)); + + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(Out_Vale_T_1));//数据1 data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(extremum_Value));//数据2 for (int i = 0; i < 5; i++){ cv::line(Paint, cv::Point(out_LinePoint[i * 4 + 1].D(), out_LinePoint[i * 4].D()), @@ -183,11 +209,12 @@ bool hanQianCeLiang_Main(std::shared_ptr data, zhongHanHanQianParams* textPainter.putText(Paint, "NG" + errTails, cv::Point(0, 50), cv::Scalar(0, 255, 0)); data->halconOK = false; } + if (data->service->_paramSyncManager->get("通用设置", "强制OK", false).toBool()) + plcResult = "1";//强制OK + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); - plcResult = "1";//强制OK data->resultImgs.push_back(Paint); - data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 - data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 return true; } CATCH_EXCEPTIONS @@ -201,23 +228,36 @@ bool hanQianCeLiang_Main(std::shared_ptr data, zhongHanHanQianParams* textPainter.putText(Paint, "NG", cv::Point(1000, 50), cv::Scalar(0, 255, 0)); cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); data->resultImgs.push_back(Paint); - data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + 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");//结果反馈 return true; } bool hanQianCeLiang_Sub(std::shared_ptr data, zhongHanHanQianParams* _detParams, sx_581_address address) { try { //测试算法用 - QByteArray plcResult = "2"; + QByteArray plcResult = "1"; { #if 0 - //img2D = cv::imread("./testImages/AL_1.png", -1); - //sourceImg = img2D.clone(); - img2D = cv::imread("./testImages/AL.bmp", -1); - sourceImg = img2D(cutROI & cv::Rect(0, 0, img2D.cols, img2D.rows)).clone(); + data->oriImgs[0] = cv::imread("D:\\testImage\\L.bmp", -1); #endif } + double xinBaoJianJuLimitHigh = data->service->_paramSyncManager->get("焊前检测", "芯包间距(上限)", 72.00).toDouble(); + double xinBaoJianJuLimitLow = data->service->_paramSyncManager->get("焊前检测", "芯包间距(下限)", 68.00).toDouble(); + bool xinBaoJianJuLimitEnable = data->service->_paramSyncManager->get("焊前检测", "芯包间距判定启用", true).toBool(); + + double xinBaoDingBuDaoYuanXinLimitHigh = data->service->_paramSyncManager->get("焊前检测", "芯包顶部到圆心距离(上限)", 35.00).toDouble(); + double xinBaoDingBuDaoYuanXinLimitLow = data->service->_paramSyncManager->get("焊前检测", "芯包顶部到圆心距离(下限)", 33.00).toDouble(); + bool xinBaoDingBuDaoYuanXinLimitEnable = data->service->_paramSyncManager->get("焊前检测", "芯包顶部到圆心距离判定启用", true).toBool(); + + double lianJiePianJianJuLimitHigh = data->service->_paramSyncManager->get("焊前检测", "连接片间距(上限)", 124.00).toDouble(); + double lianJiePianJianJuLimitLow = data->service->_paramSyncManager->get("焊前检测", "连接片间距(下限)", 122.00).toDouble(); + bool lianJiePianJianJuLimitEnable = data->service->_paramSyncManager->get("焊前检测", "连接片间距判定启用", true).toBool(); + cv::Mat sourceImg = data->oriImgs[0]; sourceImg(cv::Rect(0, 0, 3000, 3648)).copyTo(sourceImg); + data->segOriginImgs.push_back(sourceImg); cv::Mat Paint; sourceImg.copyTo(Paint); if (Paint.channels() == 1) @@ -241,11 +281,28 @@ bool hanQianCeLiang_Sub(std::shared_ptr data, zhongHanHanQianParams* _ } if (_calResult.algoFailed == false) { - textPainter.putText(Paint, "铝(正)包膜距离:" + std::to_string(_calResult.Out_Vale_L_1), cv::Point(50, 50), cv::Scalar(0, 255, 0)); - data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(_calResult.Out_Vale_L_1));//数据1 + if (_calResult.Out_Vale_L_1 > xinBaoJianJuLimitHigh || _calResult.Out_Vale_L_1 < xinBaoJianJuLimitLow) { + + textPainter.putText(Paint, "铝(正)包膜距离:" + std::to_string(_calResult.Out_Vale_L_1), cv::Point(50, 50), cv::Scalar(0, 0, 255)); + if (xinBaoJianJuLimitEnable == true) + plcResult = "2"; + } + else + textPainter.putText(Paint, "铝(正)包膜距离:" + std::to_string(_calResult.Out_Vale_L_1), cv::Point(50, 50), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "铝(正)极连接片中心的和上极耳水平边缘距离:" + std::to_string(_calResult.Out_Vale_L_2), cv::Point(50, 200), cv::Scalar(0, 255, 0)); textPainter.putText(Paint, "铝(正)极连接片中心的和下极耳水平边缘距离:" + std::to_string(_calResult.Out_Vale_L_3), cv::Point(50, 350), cv::Scalar(0, 255, 0)); - textPainter.putText(Paint, "铜(负)极和铝(正)极的中心距离:" + std::to_string(_calResult.extremum_Value), cv::Point(50, 600), cv::Scalar(0, 255, 0)); + + if (_calResult.extremum_Value > lianJiePianJianJuLimitHigh || _calResult.extremum_Value < lianJiePianJianJuLimitLow) { + textPainter.putText(Paint, "铜(负)极和铝(正)极的中心距离:" + std::to_string(_calResult.extremum_Value), cv::Point(50, 600), cv::Scalar(0, 0, 255)); + if (lianJiePianJianJuLimitEnable == true) + plcResult = "2"; + } + else + textPainter.putText(Paint, "铜(负)极和铝(正)极的中心距离:" + std::to_string(_calResult.extremum_Value), cv::Point(50, 600), cv::Scalar(0, 255, 0)); + + + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_" + QByteArray::number(_calResult.Out_Vale_L_1));//数据1 data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr + 2) + "_" + QByteArray::number(_calResult.extremum_Value));//数据2 for (int i = 0; i < 5; i++) { cv::line(Paint, cv::Point(_calResult.lines[i * 4 + 1], _calResult.lines[i * 4]), @@ -260,10 +317,13 @@ bool hanQianCeLiang_Sub(std::shared_ptr data, zhongHanHanQianParams* _ textPainter.putText(Paint, "NG:algoError", cv::Point(0, 50), cv::Scalar(0, 255, 0)); plcResult = "2"; } - cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); - plcResult = "1";//强制OK - data->resultImgs.push_back(Paint); + + if (data->service->_paramSyncManager->get("通用设置", "强制OK", false).toBool()) + plcResult = "1";//强制OK + data->service->_triggerManager->writeShort("D" + address.resultAddr + "_" + plcResult);//结果反馈 + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); + data->resultImgs.push_back(Paint); return true; } CATCH_EXCEPTIONS @@ -277,7 +337,10 @@ bool hanQianCeLiang_Sub(std::shared_ptr data, zhongHanHanQianParams* _ textPainter.putText(Paint, "NG", cv::Point(1000, 50), cv::Scalar(0, 255, 0)); cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); data->resultImgs.push_back(Paint); - data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//结果反馈 + 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");//结果反馈 return true; } @@ -299,8 +362,8 @@ public: } bool initCustom() { #pragma region 注册触发器回调 - tong_1.init("Camera1", "焊前定位-相机1", { { 5060, 1,{5070},"5062","5064",5066} }, 1, &detParams, _serviceManager, bridge, hanQianCeLiang_Main); - lv_1.init("Camera2", "焊前定位-相机2", { { 5090, 1,{5100},"5092","5094",5096} }, 1, &detParams, _serviceManager, bridge, hanQianCeLiang_Sub); + tong_1.init("Camera1", "焊前定位-相机1", { { 5060, 1,{5100,5070},"5062","5064",5066} }, 1, &detParams, _serviceManager, bridge, hanQianCeLiang_Main); + lv_1.init("Camera2", "焊前定位-相机2", { { 5090, 1,{5100,5070},"5092","5094",5096} }, 1, &detParams, _serviceManager, bridge, hanQianCeLiang_Sub); #pragma endregion return true; } diff --git a/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp b/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp index 2e1d3fc..e9c40a5 100644 --- a/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp +++ b/subModule/Hd_CameraModule_3DKeyence/Hd_CameraModule_3DKeyence.cpp @@ -124,8 +124,15 @@ void myCallbackFunc(LJX8IF_PROFILE_HEADER* pProfileHeaderArray, WORD* pHeightPro } if (_luminanceBuf[dwUser] <= pLuminanceProfileArray || (unsigned short*)_luminanceBuf[dwUser] >= (WORD*)pLuminanceProfileArray + dwProfileDataCount * dwCount * 2) memcpy(&_luminanceBuf[dwUser][0], pLuminanceProfileArray, dwProfileDataCount * dwCount * 2); - else - qDebug() << __FUNCTION__ << " line:" << __LINE__ << "memcpy _luminanceBuf error"; + else { + try { + memcpy(&_luminanceBuf[dwUser][0], pLuminanceProfileArray, dwProfileDataCount * dwCount * 2); + } + catch (...) { + qCritical() << __FUNCTION__ << " line:" << __LINE__ << "Get luminanceBuf failed!"; + } + } + } _imageAvailable[dwUser] = 1; // 图像获取成功 dwUser 和 deviceId 一致 _lastImageSizeHeight[dwUser] = dwCount; // 扫描的行数, dwCount 和 yImageSize 一致 @@ -414,9 +421,10 @@ bool Hd_CameraModule_3DKeyence::initParas(QByteArray& initData) } // Initialize - if (!InitHighSpeed()) - { + if (!InitHighSpeed()){ qDebug() << __FUNCTION__ << " line:" << __LINE__ << " InitHighSpeed error! " ; + lastError = "初始化高速通讯失败!"; + return false; } return true; } @@ -476,6 +484,7 @@ bool Hd_CameraModule_3DKeyence::run() try { + _imageAvailable[deviceId] = 0; while (imgTakeNum != imgTarget) { int sleepMs = 10; @@ -486,8 +495,8 @@ bool Hd_CameraModule_3DKeyence::run() QThread::msleep(10); if (cnt++ >= timeoutCnt) { - heightMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); - luminanceMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + heightMatS.push_back(cv::Mat(1000, 1000, CV_8UC1, cv::Scalar(0))); + luminanceMatS.push_back(cv::Mat(1000, 1000, CV_8UC1, cv::Scalar(0))); imgTakeNum++; qDebug() << "imgGetERROR insert blank img cameraID:" << camera_name; continue; diff --git a/subModule/Hd_CameraModule_3DKeyence_test/CMakeLists.txt b/subModule/Hd_CameraModule_3DKeyence_test/CMakeLists.txt new file mode 100644 index 0000000..8533141 --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence_test/CMakeLists.txt @@ -0,0 +1,71 @@ +# 获取获取当前目录名 +get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME) +string(TIMESTAMP RUN_TIME) +message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME}) + +set(DLL_NAMES "keyence3D" "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") +FILE(GLOB UI_FILES "./*.ui") + + +#find_package(Qt5 COMPONENTS Core REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core 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 + ) + + +# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY) + + + + +string(TIMESTAMP RUN_TIME) +message( " model end : " ${CURRENT_FOLDER}:${RUN_TIME}) diff --git a/subModule/Hd_CameraModule_3DKeyence_test/Hd_CameraModule_3DKeyence.cpp b/subModule/Hd_CameraModule_3DKeyence_test/Hd_CameraModule_3DKeyence.cpp new file mode 100644 index 0000000..2e1d3fc --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence_test/Hd_CameraModule_3DKeyence.cpp @@ -0,0 +1,567 @@ +#include "Hd_CameraModule_3DKeyence.h" +#include +#include +#include +#include +#include + +int G_xImageSize = 0; // Number of X points. +int G_yImageSize = 0; // Number of Y lines. +//const int MAX_LJXA_XDATANUM = 3200; +//const unsigned int BUFFER_FULL_COUNT = 30000; +// +//int _imageAvailable[MAX_LJXA_DEVICENUM] = { 0 }; +//unsigned short* _luminanceBuf[MAX_LJXA_DEVICENUM] = { 0 }; +//unsigned short* _heightBuf[MAX_LJXA_DEVICENUM] = { 0 }; +//int _lastImageSizeHeight[MAX_LJXA_DEVICENUM]; +int imgTakeNum = 0, imgTarget = 1; +int imgIndex = 0; +int getImageTimeOut = 3000; +QString lastError; +QMutex* m_mutex = nullptr; +std::mutex bufferMutex; +QQueue< cv::Mat> heightMatS;//高度图 +QQueue luminanceMatS;//灰度图 +//data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。 +bool ifBreak = false; +//ifRunning减少ifBreak的判断;"rest_newProductIn"时,Logic_camera_thread框架会结束未处理完的相相机取图 +bool ifRunning = false; +QString byteArrayToUnicode(const QByteArray array) { + + // state用于保存转换状态,它的成员invalidChars,可用来判断是否转换成功 + // 如果转换成功,则值为0,如果值大于0,则说明转换失败 + QTextCodec::ConverterState state; + // 先尝试使用utf-8的方式把QByteArray转换成QString + QString text = QTextCodec::codecForName("UTF-8")->toUnicode(array.constData(), array.size(), &state); + // 如果转换时无效字符数量大于0,说明编码格式不对 + if (state.invalidChars > 0) + { + // 再尝试使用GBK的方式进行转换,一般就能转换正确(当然也可能是其它格式,但比较少见了) + text = QTextCodec::codecForName("GBK")->toUnicode(array); + } + return text; +} + +bool JumpFlag = false; +int yCounts; +void myCallbackFunc(LJX8IF_PROFILE_HEADER* pProfileHeaderArray, WORD* pHeightProfileArray, WORD* pLuminanceProfileArray, DWORD dwLuminanceEnable, DWORD dwProfileDataCount, DWORD dwCount, DWORD dwNotify, DWORD dwUser) +{ + try + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " --> Enter callback function"; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwProfileDataCount = " << dwProfileDataCount; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwCount = " << dwCount; + std::cout << "dwCount->" << dwCount <<" dwProfileDataCount"<< dwProfileDataCount << "dwNotify = " << dwNotify<< std::endl; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwNotify = " << dwNotify; + //if (dwCount < 1000)return; + /* if ((dwNotify != 0) || (dwNotify & 0x10000) != 0) + { + return; + }*/ + std::lock_guard lock(bufferMutex); + if (dwCount == 0) + { + return; + } + if (_imageAvailable[dwUser] == 1) + { + return; + } + + + + // _heightBuf 代表的含义:程序里的高度缓存区,pHeightProfileArray 回调函数里的数据 + // 此处崩溃的可能性:xImageSize 配置文件中设置的值和3D相机调试软件设置的值不一致,会崩溃。 + if (JumpFlag) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "JumpFlag"; + return; + } + if (_heightBuf[dwUser] == NULL) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_heightBuf[dwUser] == NULL"; + _heightBuf[dwUser] = (unsigned short*)malloc(G_yImageSize * MAX_LJXA_XDATANUM * 2); + //return; + } + if (pHeightProfileArray == NULL) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pHeightProfileArray== NULL"; + return; + } + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_heightBuf[dwUser]: " << _heightBuf[dwUser]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pHeightProfileArray: " << pHeightProfileArray; + + //判断内存是否重叠 + if (_heightBuf[dwUser] <= pHeightProfileArray || (unsigned short*)_heightBuf[dwUser] >= (WORD*)pHeightProfileArray + dwProfileDataCount * dwCount * 2) + { + memcpy(&_heightBuf[dwUser][0], pHeightProfileArray, dwProfileDataCount * dwCount * 2); + } + else + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "first memcpy _heightBuf error"; + if (_heightBuf[dwUser] != NULL) + { + free(_heightBuf[dwUser]); + _heightBuf[dwUser] = NULL; + } + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " memcpy _heightBuf again "; + _heightBuf[dwUser] = (unsigned short*)malloc(yCounts * MAX_LJXA_XDATANUM * 2); + memcpy(&_heightBuf[dwUser][0], pHeightProfileArray, dwProfileDataCount * dwCount * 2); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Second memcpy _heightBuf success "; + + } + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_luminanceBuf[dwUser]: " << _luminanceBuf[dwUser]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pLuminanceProfileArray: " << pLuminanceProfileArray; + if (dwLuminanceEnable == 1) + { + if (_luminanceBuf[dwUser] == NULL) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_luminanceBuf[dwUser]== NULL"; + //return; + _luminanceBuf[dwUser] = (unsigned short*)malloc(G_yImageSize * MAX_LJXA_XDATANUM * 2); + } + if (_luminanceBuf[dwUser] <= pLuminanceProfileArray || (unsigned short*)_luminanceBuf[dwUser] >= (WORD*)pLuminanceProfileArray + dwProfileDataCount * dwCount * 2) + memcpy(&_luminanceBuf[dwUser][0], pLuminanceProfileArray, dwProfileDataCount * dwCount * 2); + else + qDebug() << __FUNCTION__ << " line:" << __LINE__ << "memcpy _luminanceBuf error"; + } + _imageAvailable[dwUser] = 1; // 图像获取成功 dwUser 和 deviceId 一致 + _lastImageSizeHeight[dwUser] = dwCount; // 扫描的行数, dwCount 和 yImageSize 一致 + } + catch (std::exception e) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " --> execute callback function error"; + } +} + +int Hd_CameraModule_3DKeyence::LJXA_ACQ_OpenDevice(int lDeviceId, LJX8IF_ETHERNET_CONFIG* EthernetConfig, int HighSpeedPortNo) +{ + int errCode = LJX8IF_EthernetOpen(lDeviceId, EthernetConfig); + + _ethernetConfig[lDeviceId] = *EthernetConfig; + _highSpeedPortNo[lDeviceId] = HighSpeedPortNo; + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Open device ! errCode:" << errCode; + return errCode; +} + +void Hd_CameraModule_3DKeyence::LJXA_ACQ_CloseDevice(int lDeviceId) +{ + LJX8IF_FinalizeHighSpeedDataCommunication(lDeviceId); + LJX8IF_CommunicationClose(lDeviceId); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Close device!"; +} + + +bool Hd_CameraModule_3DKeyence::decodeInitData(QByteArray byteArray,QVector &vector_data) +{ + while (!byteArray.isEmpty()) + { + int type = 0; + QByteArray m_type = byteArray.mid(0,4); + memcpy((void*)&type,(void*)m_type.data(), 4); + byteArray.remove(0,4); + + int len = 0; + QByteArray m_len = byteArray.mid(0,4); + memcpy((void*)&len,(void*)m_len.data(), 4); + byteArray.remove(0,4); + + QByteArray mm_data = byteArray.mid(0,len); + vector_data.append(mm_data); + byteArray.remove(0,len); + } + return true; +} + +Hd_CameraModule_3DKeyence* create() +{ + qDebug() << __FUNCTION__ << "line:" << __LINE__ << " Hd_CameraModule_3DKeyence create success!" ; + return new Hd_CameraModule_3DKeyence; +} + +void destory(Hd_CameraModule_3DKeyence * ptr) +{ + if (ptr) + { + delete ptr; + ptr = nullptr; + } + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Hd_CameraModule_3DKeyence destory success!"; +} + +Hd_CameraModule_3DKeyence::Hd_CameraModule_3DKeyence() +{ + m_mutex = new QMutex; +} + + +Hd_CameraModule_3DKeyence::~Hd_CameraModule_3DKeyence() +{ + if (isopen) + { + isopen = false; + + // Stop HighSpeed + errCode = LJX8IF_StopHighSpeedDataCommunication(deviceId); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Stop HighSpeed errCode:" << errCode; + + LJXA_ACQ_CloseDevice(deviceId); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << " CloseDevice success!"; + if (heightImage) + { + free(heightImage); + + } + if (luminanceImage) + { + free(luminanceImage); + } + } + + // Free memory + if (_heightBuf[deviceId] != NULL) + { + free(_heightBuf[deviceId]); + } + + if (_luminanceBuf[deviceId] != NULL) + { + free(_luminanceBuf[deviceId]); + } + + if (startReq_ptr) + { + delete startReq_ptr; + startReq_ptr = nullptr; + } + + if (profileInfo_ptr) + { + delete profileInfo_ptr; + profileInfo_ptr = nullptr; + } + + if (setParam_Ptr) + { + delete setParam_Ptr; + setParam_Ptr = nullptr; + } + + if (getParam_Ptr) + { + delete getParam_Ptr; + getParam_Ptr = nullptr; + } + if (m_mutex) + { + delete m_mutex; + m_mutex = nullptr; + } + qDebug() << __FUNCTION__ << "line:" << __LINE__ << " delete success!"; +} + +bool Hd_CameraModule_3DKeyence::readData(std::vector &mats,QByteArray &data) +{ + Q_UNUSED(data); + + QMutexLocker locker(m_mutex); + if (luminanceMatS.empty() || heightMatS.empty()) + { + qDebug() << " [Error] " << " srcImage is null"; + return false; + } + for (int i = 0; i < imgTarget; i++) { + if (heightMatS.size() >= 1 && luminanceMatS.size() >= 1) { + mats.push_back(luminanceMatS.dequeue()); + mats.push_back(heightMatS.dequeue()); + } + else { + mats.push_back(cv::Mat(G_xImageSize, G_yImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + mats.push_back(cv::Mat(G_xImageSize, G_yImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + } + } + imgTakeNum = 0; + qCritical() << " [info] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData,deviceId" << deviceId << " imgIndex" << imgIndex; + return true; +} + +bool Hd_CameraModule_3DKeyence::writeData(std::vector &mat,QByteArray &data) +{ + if (data == "clearCahce") { + QMutexLocker locker(m_mutex); + heightMatS.clear(); + luminanceMatS.clear(); + } + //2024.02.18更新,相机对应的读SN信号时,表示新产品进入,设置初始值 + //if (data == "rest_newProductIn") + //{ + // //根据实际项目,设置初始值:曝光、增益,ROI区域等 + // /*{ + // if (expourseTimeList.size() > 0) + // SetExposureTime(expourseTimeList[0]); + // if (gainList.size() > 0) + // SetGain(gainList[0]); + // } + // getImageNum = 0;*/ + // if (luminanceMatS.size() > 0 || heightMatS.size() > 0) + // { + // m_mutex->lock(); + // luminanceMatS.clear(); + // heightMatS.clear(); + // m_mutex->unlock(); + // std::cout << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << camera_name.toStdString() << std::endl; + // qWarning() << __FUNCTION__ << " line: " << __LINE__ << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << camera_name; + // } + // if (ifRunning == true) + // { + // ifBreak = true; + // Sleep(10); + // } + // imgIndex = 0; + // //getImageNum = 0; + // return true; + //} + + + return true; +} + +//传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... +bool Hd_CameraModule_3DKeyence::initParas(QByteArray& initData) +{ + QByteArrayList valueList = initData.split('#'); + if (valueList.size() < 6) { + qDebug() << "[Error] " << " Hd_CameraModule_HIK initParas fail--params error!参数数量不满足"; + lastError = "参数数量不满足"; + return false; + } + EthernetConfig.wPortNo = 24691; + + camera_name = valueList[0]; + auto valueL1 = valueList[0].split('.'); + if (valueL1.size() == 4) + { + EthernetConfig.abyIpAddress[0] = valueL1.at(0).toInt(); + EthernetConfig.abyIpAddress[1] = valueL1.at(1).toInt(); + EthernetConfig.abyIpAddress[2] = valueL1.at(2).toInt(); + EthernetConfig.abyIpAddress[3] = valueL1.at(3).toInt(); + } + + deviceId = valueList[1].toInt(); + + xImageSize = valueList[2].toInt(); + G_xImageSize = valueList[2].toInt(); + + yImageSize = valueList[3].toInt(); + G_yImageSize = valueList[3].toInt(); + + imgTarget = valueList[4].toInt(); + + getImageTimeOut = valueList[5].toInt(); + yCounts = yImageSize; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " camera_name:" << camera_name << " paras init is success!"; + + // 初始化申请空间 20230214 + startReq_ptr = new LJX8IF_HIGH_SPEED_PRE_START_REQ; + profileInfo_ptr = new LJX8IF_PROFILE_INFO; + startReq_ptr->bySendPosition = 2; + + setParam_Ptr = new LJXA_ACQ_SETPARAM; + getParam_Ptr = new LJXA_ACQ_GETPARAM; + + setParam_Ptr->y_linenum = yImageSize; + setParam_Ptr->y_pitch_um = y_pitch_um; + setParam_Ptr->timeout_ms = timeout_ms; + setParam_Ptr->use_external_batchStart = use_external_batchStart; + + // Allocate user memory + heightImage = (unsigned short*)malloc(sizeof(unsigned short) * xImageSize * yImageSize); + luminanceImage = (unsigned short*)malloc(sizeof(unsigned short) * xImageSize * yImageSize); + + errCode = LJXA_ACQ_OpenDevice(deviceId, &EthernetConfig, HighSpeedPortNo); + if ( errCode != LJX8IF_RC_OK ) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Failed to open device "; + //Free user memory + if ( heightImage ) + { + free(heightImage); + } + + if ( luminanceImage ) + { + free(luminanceImage); + } + return false; + } + + isopen = true; + + // Allocate memory + _heightBuf[deviceId] = (unsigned short*)malloc(yImageSize * MAX_LJXA_XDATANUM * 2); + if (_heightBuf[deviceId] == NULL) + { + return LJX8IF_RC_ERR_NOMEMORY; + } + + _luminanceBuf[deviceId] = (unsigned short*)malloc(yImageSize * MAX_LJXA_XDATANUM * 2); + if (_luminanceBuf[deviceId] == NULL) + { + return LJX8IF_RC_ERR_NOMEMORY; + } + + // Initialize + if (!InitHighSpeed()) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " InitHighSpeed error! " ; + } + return true; +} +bool Hd_CameraModule_3DKeyence::InitHighSpeed() +{ + try + { + if ( startReq_ptr == nullptr ) + { + startReq_ptr = new LJX8IF_HIGH_SPEED_PRE_START_REQ; + startReq_ptr->bySendPosition = 2; + qWarning() << __FUNCTION__ << " line: " << __LINE__ << " startReq_ptr is null! "; + } + if ( profileInfo_ptr == nullptr ) + { + profileInfo_ptr = new LJX8IF_PROFILE_INFO; + qWarning() << __FUNCTION__ << " line: " << __LINE__ << " profileInfo_ptr is null! "; + } + errCode = LJX8IF_InitializeHighSpeedDataCommunicationSimpleArray(deviceId, &_ethernetConfig[deviceId], _highSpeedPortNo[deviceId], &myCallbackFunc, yImageSize, deviceId); // 初始化高速通讯 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode:" << errCode; + errCode = LJX8IF_PreStartHighSpeedDataCommunication(deviceId, startReq_ptr, profileInfo_ptr); // 预开始启动高速通信,作用 做预连接 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode:" << errCode; + + // zUnit + errCode = LJX8IF_GetZUnitSimpleArray(deviceId, &zUnit); + if (errCode != 0 || zUnit == 0) + { + qCritical() << __FUNCTION__ << " line:" << __LINE__ << " Failed to acquire zunit! "; + return false; + } + errCode = LJX8IF_StartHighSpeedDataCommunication(deviceId); // 正式开始高速通讯 + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode: " << errCode; + + //Start HighSpeed + _imageAvailable[deviceId] = 0; + _lastImageSizeHeight[deviceId] = 0; + } + catch (const QString ev) + { + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " ev: " << ev; + return false; + } + return true; + +} + +bool Hd_CameraModule_3DKeyence::run() +{ + + ifRunning = true; + ifBreak = false; + if ( !isopen ) + { + qCritical() << __FUNCTION__ << " line:" << __LINE__ << " device is not opened! "; + return false; + } + + try + { + while (imgTakeNum != imgTarget) + { + int sleepMs = 10; + int cnt = 0; + int timeoutCnt = getImageTimeOut / sleepMs; + while (_imageAvailable[deviceId] != 1 ) + { + QThread::msleep(10); + if (cnt++ >= timeoutCnt) + { + heightMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + luminanceMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0))); + imgTakeNum++; + qDebug() << "imgGetERROR insert blank img cameraID:" << camera_name; + continue; + } + } + + + std::lock_guard lock(bufferMutex); + _getParam[deviceId].luminance_enabled = profileInfo_ptr->byLuminanceOutput; + _getParam[deviceId].x_pointnum = profileInfo_ptr->wProfileDataCount; + _getParam[deviceId].y_linenum_acquired = _lastImageSizeHeight[deviceId]; + _getParam[deviceId].x_pitch_um = profileInfo_ptr->lXPitch / 100.0f; + _getParam[deviceId].y_pitch_um = y_pitch_um; + _getParam[deviceId].z_pitch_um = zUnit / 100.0f; + + *getParam_Ptr = _getParam[deviceId]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " getPara Finished: "; + int xDataNum = _getParam[deviceId].x_pointnum; + + unsigned short* dwHeightBuf = (unsigned short*)&_heightBuf[deviceId][0]; + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " dwHeightBuf Init Finished: "; + memcpy(heightImage, dwHeightBuf, xDataNum * yImageSize * 2); + + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Height Img memcpy Finished: "; + std::vectorpoits(xDataNum * yImageSize * 2, 0); + if (_getParam[deviceId].luminance_enabled > 0) + { + unsigned short* dwLuminanceBuf = (unsigned short*)&_luminanceBuf[deviceId][0]; + memcpy(luminanceImage, dwLuminanceBuf, xDataNum * yImageSize * 2); + } + // Free memory + if (_heightBuf[deviceId] != NULL) + { + free(_heightBuf[deviceId]); + _heightBuf[deviceId] = NULL; + } + + if (_luminanceBuf[deviceId] != NULL) + { + free(_luminanceBuf[deviceId]); + _luminanceBuf[deviceId] = NULL; + } + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Free memory Finished: "; + + m_mutex->lock(); + cv::Mat luminanceMat; + if(_lastImageSizeHeight[deviceId] != 0) + luminanceMat = cv::Mat(_lastImageSizeHeight[deviceId], xImageSize, CV_16UC1, luminanceImage); + else + luminanceMat = cv::Mat(yImageSize, xImageSize, CV_16UC1, luminanceImage); + cv::normalize(luminanceMat, luminanceMat, 0, 255, cv::NORM_MINMAX); + cv::convertScaleAbs(luminanceMat, luminanceMat); + + luminanceMatS.enqueue(luminanceMat); + + cv::Mat heightImg; + if (_lastImageSizeHeight[deviceId] != 0) + cv::Mat(_lastImageSizeHeight[deviceId], xImageSize, CV_16UC1, heightImage).copyTo(heightImg); + else + cv::Mat(yImageSize, xImageSize, CV_16UC1, heightImage).copyTo(heightImg); + heightMatS.enqueue(heightImg); + m_mutex->unlock(); + qDebug() << __FUNCTION__ << " line:" << __LINE__ << " success to acquire 3d image! camera_name: " << camera_name; + //Start HighSpeed + _imageAvailable[deviceId] = 0; + _lastImageSizeHeight[deviceId] = 0; + imgTakeNum++; + } + qDebug() << camera_name <<"Finish"; + return true; + } + catch (QString ev) + { + qCritical() << __FUNCTION__ << " line: " << __LINE__ << " ev: " << ev; + return false; + } +} diff --git a/subModule/Hd_CameraModule_3DKeyence_test/Hd_CameraModule_3DKeyence.h b/subModule/Hd_CameraModule_3DKeyence_test/Hd_CameraModule_3DKeyence.h new file mode 100644 index 0000000..ccdf9fc --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence_test/Hd_CameraModule_3DKeyence.h @@ -0,0 +1,108 @@ +#ifndef Hd_CameraModule_3DKeyence_H +#define Hd_CameraModule_3DKeyence_H + +#include +#include +#include +#include +#include + +#include "LJX8_IF.h" +#include "LJX8_ErrorCode.h" + +#include + +#pragma comment(lib, "winmm.lib") +#pragma execution_character_set("utf-8") + +typedef struct { + int y_linenum; + float y_pitch_um; + int timeout_ms; + int use_external_batchStart; +} LJXA_ACQ_SETPARAM; + +typedef struct { + int luminance_enabled; + int x_pointnum; + int y_linenum_acquired; + float x_pitch_um; + float y_pitch_um; + float z_pitch_um; +} LJXA_ACQ_GETPARAM; + + +const int MAX_LJXA_DEVICENUM = 6; +const int MAX_LJXA_XDATANUM = 3200; +const unsigned int BUFFER_FULL_COUNT = 30000; + +static int _imageAvailable[MAX_LJXA_DEVICENUM] = { 0 }; +static unsigned short* _luminanceBuf[MAX_LJXA_DEVICENUM] = { 0 }; +static unsigned short* _heightBuf[MAX_LJXA_DEVICENUM] = { 0 }; +static int _lastImageSizeHeight[MAX_LJXA_DEVICENUM]; + +class Hd_CameraModule_3DKeyence :public dsModuleBase +{ +public: + Hd_CameraModule_3DKeyence(); + virtual ~Hd_CameraModule_3DKeyence(); + //从类中读数据到实例对象 + bool readData(std::vector& mats, QByteArray& data); + //实例对象把数据写入到类 + bool writeData(std::vector& mat, QByteArray& data); + bool initParas(QByteArray& initData); + bool run(); + + int LJXA_ACQ_OpenDevice(int lDeviceId, LJX8IF_ETHERNET_CONFIG* EthernetConfig, int HighSpeedPortNo); + //int LJXA_ACQ_StartAsync(int lDeviceId, LJXA_ACQ_SETPARAM* setParam); + //int LJXA_ACQ_AcquireAsync(int lDeviceId, unsigned short* heightImage, unsigned short* luminanceImage, LJXA_ACQ_SETPARAM* setParam, LJXA_ACQ_GETPARAM* getParam); + void LJXA_ACQ_CloseDevice(int lDeviceId); + + bool decodeInitData(QByteArray byteArray, QVector& vector_data); + bool InitHighSpeed(); +private: + //int LJXA_ACQ_Acquire(int lDeviceId, unsigned short* heightImage, unsigned short* luminanceImage, LJXA_ACQ_SETPARAM* setParam, LJXA_ACQ_GETPARAM* getParam); + LJX8IF_HIGH_SPEED_PRE_START_REQ* startReq_ptr = nullptr; + LJX8IF_PROFILE_INFO* profileInfo_ptr = nullptr; + + // Static variable + LJX8IF_ETHERNET_CONFIG _ethernetConfig[MAX_LJXA_DEVICENUM]; + int _highSpeedPortNo[MAX_LJXA_DEVICENUM]; + + LJXA_ACQ_GETPARAM _getParam[MAX_LJXA_DEVICENUM]; + + int deviceId = 0; // Set "0" if you use only 1 head. + int xImageSize = 0; // Number of X points. + int yImageSize = 0; // Number of Y lines. + float y_pitch_um = 0; // Data pitch of Y data. (e.g. your encoder setting) + int timeout_ms = 0; // Timeout value for the acquiring image (in milisecond). + int use_external_batchStart = 1; // Set "1" if you controll the batch start timing externally. (e.g. terminal input) 0内部触发,1外部触发 + std::string outputFilePath1 = "sample_height.csv"; + std::string outputFilePath2 = "sample_height.tif"; + std::string outputFilePath3 = "sample_luminance.tif"; + + //std::vector< cv::Mat> vector_mat; + unsigned short zUnit = 0; + + unsigned short* heightImage = nullptr; // Height image + unsigned short* luminanceImage = nullptr; // Luminance image + + LJXA_ACQ_SETPARAM* setParam_Ptr = nullptr; + LJXA_ACQ_GETPARAM* getParam_Ptr = nullptr; + int HighSpeedPortNo = 24692; // Port number for high-speed communication + bool isopen = false; + int errCode; + + LJX8IF_ETHERNET_CONFIG EthernetConfig; + + QString camera_name; // 相机名称 + int recontimeout_ms = 3000; +}; + +extern "C" +{ + Q_DECL_EXPORT Hd_CameraModule_3DKeyence* create(); + Q_DECL_EXPORT void destory(Hd_CameraModule_3DKeyence* ptr); +} + +#endif // HD_MVCAMERA_MODULE_H diff --git a/subModule/Hd_CameraModule_3DKeyence_test/readme.txt b/subModule/Hd_CameraModule_3DKeyence_test/readme.txt new file mode 100644 index 0000000..7a69391 --- /dev/null +++ b/subModule/Hd_CameraModule_3DKeyence_test/readme.txt @@ -0,0 +1,3 @@ +基恩士3D相机 +初始化格式 IP#DEVICE-ID(手动按照初始化的顺序从0开始递增)#图像宽(X)#图像高(Y)#取图次数#超时时间 +192.168.31.1#0#3200#850#1#1000 \ No newline at end of file