V20251125-2.2.6

修改了CLS切图函数的逻辑,现在会按最初图像的中心点开始切图。
修改算法NG(halconNg)时存图的文件夹名字为algoNG。
修复基恩士相机可能出现丢亮度图的问题。
This commit is contained in:
2025-11-25 00:47:04 +08:00
parent a20069eac5
commit eeffb1dcd6
19 changed files with 2131 additions and 93 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
#include <QDir>
#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
+9 -5
View File
@@ -124,6 +124,8 @@ static std::vector<cv::Mat> 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<cv::Mat> 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<int> starts;
@@ -156,12 +158,14 @@ static std::vector<cv::Mat> 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;
+1 -1
View File
@@ -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);
+43
View File
@@ -0,0 +1,43 @@
#include <iostream>
#include <opencv.hpp>
#include <handleAI.h>
#include <simpleAlgo.h>
#include <global.h>
#include <basic.hpp>
#include <simpleAlgo.h>
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<std::string> 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;
}
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <qstring.h>
#include <qtimer.h>
#include <qdatetime.h>
QString getDateTimeStamp()
{
return QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss");
}
static const std::vector<std::string> saveR = { "OK","NG" };
+8 -2
View File
@@ -1,7 +1,13 @@
#include <baoMo.hpp>
#include <yuhan.hpp>
#include <RLJ.hpp>
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;
}
+61
View File
@@ -0,0 +1,61 @@
#include <iostream>
#include <opencv.hpp>
#include <handleAI.h>
#include <simpleAlgo.h>
#include <global.h>
#include <basic.hpp>
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<std::string> 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<std::vector<cv::Point>> 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;
}
}
@@ -0,0 +1,424 @@
#include <581_Ruanlianjie_hanqian_hanhou.h>
void exceptionResume(std::shared_ptr<detData> 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<detData> 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 <detData> 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,铝</c>
//正确的应该左边铝 右边铜
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 <detData> 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 <detData> 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<std::vector<cv::Point>> contours;
cv::findContours(SegResult, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
std::vector<cv::Rect> 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 <detData> 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 <detData> 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;
}
@@ -0,0 +1,81 @@
#include <missionBase.hpp>
#include <sxGlobal.h>
#include <simpleAlgo.h>
#include <hdevengine/HDevEngineCpp.h>
#include <Halcon.h>
#include <HalconCpp.h>
#include <qmutex.h>
#include <qqueue.h>
#include <opencvPaintAlgo.hpp>
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 <detData> data, hanQianDingWeiParams* _detParams, sx_581_address address);
bool HanHouJianCe2D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx_581_address address);
bool HanHouJianCe3D(std::shared_ptr <detData> data, hanHouJianCe* _detParams, sx_581_address address);
class _581_Ruanlianjie_hanqian_hanhou : public mission {
public:
_581_SX_Single_triggerTemplate<hanQianDingWeiParams> dingwei_1;
_581_SX_Single_triggerTemplate<hanQianDingWeiParams> dingwei_2;
_581_SX_Single_triggerTemplate<hanHouJianCe> jiance_2d_1;
_581_SX_Single_triggerTemplate<hanHouJianCe> jiance_2d_2;
_581_SX_Single_triggerTemplate<hanHouJianCe> jiance_3d_1;
_581_SX_Single_triggerTemplate<hanHouJianCe> jiance_3d_2;
hanQianDingWeiParams hanqiandingweiparams;
std::vector<hanHouJianCe>hanhoujiance2dparams = std::vector<hanHouJianCe>(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
@@ -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})
@@ -99,24 +99,25 @@ static bool BaoMoHou_ShangDaMian(std::shared_ptr <detData> 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>
// <c>* out_Distance[1] : 电芯高度< / c>
// <c>* out_Distance[2] : 上端盖到膜的距离< / c>
// <c>* out_Distance[3] : 中端盖到膜的距离< / c>
// <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>
<c>* out_Distance[1] : 中端盖到膜的距离< / c>
<c>* out_Distance[2] : 下端盖到膜的距离< / c>
<c>* out_Distance[3] : 电芯宽度 < / c>
<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 <detData> 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;
}
+135 -12
View File
@@ -3,20 +3,135 @@
#include <hdevengine/HDevEngineCpp.h>
#include <opencvPaintAlgo.hpp>
#include <yhGlobal.h>
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<detData> 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 <detData> 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<detParams>;
@@ -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;
}
+410 -24
View File
@@ -3,13 +3,382 @@
#include <hdevengine/HDevEngineCpp.h>
#include <opencvPaintAlgo.hpp>
#include <yhGlobal.h>
#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<detData> 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<handdleAI::Bbox> resultBox = pDet->Evaluate(dst); //结果为中心点+宽高
cv::Mat contourImg;
std::vector<std::vector<cv::Point>> 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::vector<cv::Mat>dingGaiHanClsCut(cv::Rect boundingBox, cv::Mat imgInput, cv::Size targetSize = cv::Size(128, 128))
{
std::vector<cv::Mat> 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<cv::Mat>(1, cutImg2Cls(boundingBox, imgInput, targetSize));
}
bool handleAiEvaluate(std::shared_ptr <detData> 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<std::vector<cv::Point>>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 <detData> 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 <detData> 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 <detData> 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<detParams>;
@@ -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<GunYaHou2DParam> dgh_cb_gy_2d_1;
_581_Union_triggerTemplate<GunYaHou2DParam> dgh_cb_gy_2d_2;
_581_Union_triggerTemplate<GunYaHou2DParam> dgh_cb_gy_2d_3;
_581_Union_triggerTemplate<GunYaHou2DParam> dgh_cb_gy_2d_4;
std::vector<GunYaHou2DParam> _GunYaHou2DParam = std::vector<GunYaHou2DParam>(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 <detData>) {
// _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;
}
@@ -78,15 +78,25 @@ public:
bool hanQianCeLiang_Main(std::shared_ptr <detData> 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 <detData> 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 <detData> 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 <detData> 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 <detData> 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 <detData> 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 <detData> 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 <detData> 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 <detData> 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;
}
@@ -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;
@@ -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})
@@ -0,0 +1,567 @@
#include "Hd_CameraModule_3DKeyence.h"
#include <exception>
#include <qthread.h>
#include <QTextCodec>
#include <qqueue.h>
#include <qmutex.h>
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<cv::Mat> 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<std::mutex> 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<QByteArray> &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<cv::Mat> &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<cv::Mat> &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<std::mutex> 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::vector<unsigned short>poits(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;
}
}
@@ -0,0 +1,108 @@
#ifndef Hd_CameraModule_3DKeyence_H
#define Hd_CameraModule_3DKeyence_H
#include <QtCore/qglobal.h>
#include <QByteArray>
#include <QDebug>
#include<iostream>
#include <Windows.h>
#include "LJX8_IF.h"
#include "LJX8_ErrorCode.h"
#include <subModuleBase.h>
#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<cv::Mat>& mats, QByteArray& data);
//实例对象把数据写入到类
bool writeData(std::vector<cv::Mat>& 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<QByteArray>& 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
@@ -0,0 +1,3 @@
基恩士3D相机
初始化格式 IP#DEVICE-ID(手动按照初始化的顺序从0开始递增)#图像宽(X)#图像高(Y)#取图次数#超时时间
192.168.31.1#0#3200#850#1#1000