diff --git a/BaseModules/Hd_AI_algo_jixing_L/CMakeLists.txt b/BaseModules/Hd_AI_algo_jixing_L/CMakeLists.txt index dae4491..be2265d 100644 --- a/BaseModules/Hd_AI_algo_jixing_L/CMakeLists.txt +++ b/BaseModules/Hd_AI_algo_jixing_L/CMakeLists.txt @@ -3,7 +3,7 @@ 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" "halconAlgo""myTools" ) +set(DLL_NAMES "opencv" "halcon" "halconAlgo" "myTools" "handdleAI") foreach(child ${DLL_NAMES}) LIST(APPEND ENV_INCLUDE ${${child}_include}) LIST(APPEND ENV_LIB ${${child}_lib}) @@ -39,7 +39,7 @@ 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) - +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS network REQUIRED) add_library(${CURRENT_FOLDER} SHARED ${HEAD_FILES} ${SRC_FILES} @@ -58,6 +58,7 @@ set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C target_link_libraries(${CURRENT_FOLDER} PRIVATE ${ENV_TARGET} Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Network ) diff --git a/BaseModules/Hd_AI_algo_jixing_L/Hd_AI_algo_jixing_L.cpp b/BaseModules/Hd_AI_algo_jixing_L/Hd_AI_algo_jixing_L.cpp index a2cc34a..c06812f 100644 --- a/BaseModules/Hd_AI_algo_jixing_L/Hd_AI_algo_jixing_L.cpp +++ b/BaseModules/Hd_AI_algo_jixing_L/Hd_AI_algo_jixing_L.cpp @@ -1,103 +1,151 @@ -#include "Hd_AI_algo_jixing_L.h" +#include "Hd_AI_algo_jiXing_L.h" #include -#include + #include #include #include -#include -#include +#include +#include #include +#include + using namespace cv; - -//原图保存文件夹 -QString oriImgSaveDir = "D:/D601线/超声波预焊机/极性检测CCD/原图/"; +QString resultPlc; +//原图保存文件夹s +QString oriImgSaveDir = "D:/601线/终焊CCD/极性检测CCD/原图/"; //原图class图保存文件夹 -QString classImgSaveDir = "D:/D601线/超声波预焊机/极性检测CCD/class图/"; +QString classImgSaveDir = "D:/601线/终焊CCD/极性检测CCD/class图/"; //结果保存文件夹 -QString resImgSaveDir = "D:/D601线/超声波预焊机/极性检测CCD/结果图/"; - +QString resImgSaveDir = "D:/601线/终焊CCD/极性检测CCD/结果图/"; +int algoResult = 0;//0 OK 1 NG //切图的class的width,根据项目实际设置! - int sizeW = 150; +int sizeW = 150; //切图的class的height,根据项目实际设置! - int sizeH = 150; +int sizeH = 150; //切图的class的width,根据项目实际设置!0为黑,255为白; - int fillColour = 0; -int algoResult; +int fillColour = 0; + //检测线程锁 - QMutex* detect_mutex; +QMutex* detect_mutex; //保存线程锁 - QMutex* saveStruct_mutex; +QMutex* saveStruct_mutex; //检测线程运行标志 - bool ifdetectThread = false; +bool ifdetectThread = false; - QString cameraKey_index = ""; +QString cameraKey_index = ""; - //初始化参数列表 - QByteArrayList initValueList; - static void createDirectoryIfNotExists(const QString& path) { - QDir dir; - dir.mkpath(path); - } - static std::string getCurrentTime() { +//初始化参数列表 +QByteArrayList initValueList; - // 获取当前时间点 - auto now = std::chrono::system_clock::now(); +static void createDirectoryIfNotExists(const QString& path) { + QDir dir; + dir.mkpath(path); +} +static std::string getCurrentTime() { - // 转换为字符串 - auto currentTime = std::chrono::system_clock::to_time_t(now); - auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 100; - std::tm* localTime = std::localtime(¤tTime); - std::stringstream ss; - ss << std::put_time(localTime, "%H-%M-%S") << "-" << std::setfill('0') << std::setw(2) << ms.count(); - return ss.str(); - } - static QString getCurrentDate() - { - QDateTime currentDateTime = QDateTime::currentDateTime(); - return currentDateTime.toString("yyyy-MM-dd"); - } - static QString getCurrentHour() - { - QDateTime currentDateTime = QDateTime::currentDateTime(); - return QString::number(currentDateTime.time().hour()) + "H"; - } - inline std::string utf8_to_gbk(const std::string& str) - { - std::wstring_convert> conv; - std::wstring tmp_wstr = conv.from_bytes(str); - //GBK locale name in windows - const char* GBK_LOCALE_NAME = ".936"; - std::wstring_convert> convert(new std::codecvt_byname(GBK_LOCALE_NAME)); - return convert.to_bytes(tmp_wstr); - } - QString getOriSaveFromat() - { - return oriImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" - + "ORI_" + cameraKey_index + "_" + QString::fromStdString(getCurrentTime()) + ".bmp"; - } - QString getResSaveFromat() - { - return resImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" - + "RES_" + cameraKey_index + "_" + QString::fromStdString(getCurrentTime()) + ".png"; - } - 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; - } + // 获取当前时间点 + auto now = std::chrono::system_clock::now(); + // 转换为字符串 + auto currentTime = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 100; + std::tm* localTime = std::localtime(¤tTime); + std::stringstream ss; + ss << std::put_time(localTime, "%H-%M-%S") << "-" << std::setfill('0') << std::setw(2) << ms.count(); + return ss.str(); +} +static QString getCurrentDate() +{ + QDateTime currentDateTime = QDateTime::currentDateTime(); + return currentDateTime.toString("yyyy-MM-dd"); +} +static QString getCurrentHour() +{ + QDateTime currentDateTime = QDateTime::currentDateTime(); + return QString::number(currentDateTime.time().hour()) + "H"; +} +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; +} +static cv::Rect findMaxAreaContour(cv::Mat src) +{ + int maxIndex = 0, maxArea = 0; + std::vector>contours; + cv::findContours(src, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + if (contours.size() == 0) + return cv::Rect(0, 0, 0, 0); + for (int i = 0; i < contours.size(); i++) + { + int Area = cv::contourArea(contours[i]); + if (Area > maxArea) + { + maxArea = Area; + maxIndex = i; + } + } + if (contours.size() != 0) + return cv::boundingRect(contours[maxIndex]); + return cv::Rect(0, 0, 0, 0); +} +inline std::string utf8_to_gbk(const std::string& str) +{ + std::wstring_convert> conv; + std::wstring tmp_wstr = conv.from_bytes(str); + //GBK locale name in windows + const char* GBK_LOCALE_NAME = ".936"; + std::wstring_convert> convert(new std::codecvt_byname(GBK_LOCALE_NAME)); + return convert.to_bytes(tmp_wstr); +} +void getAllFiles(std::string path, std::vector& files, std::string format) +{ + intptr_t hFile = 0;//文件句柄 + struct _finddata_t fileinfo;//文件信息 + std::string p; + if ((hFile = _findfirst(p.assign(path).append("\\*" + format).c_str(), &fileinfo)) != -1) //文件存在 + { + do + { + if ((fileinfo.attrib & _A_SUBDIR))//判断是否为文件夹 + { + if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)//文件夹名中不含"."和".." + { + files.push_back(p.assign(path).append("\\").append(fileinfo.name)); //保存文件夹名 + getAllFiles(p.assign(path).append("\\").append(fileinfo.name), files, format); //递归遍历文件夹 + } + } + else + { + files.push_back(p.assign(path).append("\\").append(fileinfo.name));//如果不是文件夹,储存文件名 + } + } while (_findnext(hFile, &fileinfo) == 0); + _findclose(hFile); + } +} +QString getOriSaveFormat(QString SN) +{ + QString path = oriImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" + SN + "//"; + createDirectoryIfNotExists(path); + return path + "ORI_" + cameraKey_index + "_" + SN + "_" + QString::fromStdString(getCurrentTime()) + ".bmp"; +} +QString getResSaveFromat(QString SN) +{ + QString path = resImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" + SN + "//"; + createDirectoryIfNotExists(path); + return path + "RES_" + cameraKey_index + "_" + SN + "_" + QString::fromStdString(getCurrentTime()) + ".png"; +} // 缺陷信息结构体 typedef struct { QString defectName = "";//缺陷名称 @@ -232,6 +280,8 @@ void GetStringSize(HDC hdc, const char* str, int* w, int* h) if (h != 0) *h = size.cy; } //在图像写中文,英文也可以写 + + void putTextZH(cv::Mat& dst, const char* str, cv::Point org, cv::Scalar color, int fontsize, const char* fn = "Arial", bool italic = false, bool underline = false) { @@ -397,7 +447,7 @@ void drawDefects(cv::Mat& sourceMat, QQueue defectInfoList) //判断文件夹是否存在,不存在则创建 -void Hd_AI_algo_jixing1::isDirExist(QString fullDirName) +void Hd_AI_algo_jiXing_L::isDirExist(QString fullDirName) { QDir* photo = new QDir; bool exist = photo->exists(fullDirName); @@ -415,28 +465,27 @@ void Hd_AI_algo_jixing1::isDirExist(QString fullDirName) photo = nullptr; } -Hd_AI_algo_jixing1* create() +Hd_AI_algo_jiXing_L* create() { - qDebug() << "[INFO] " << " Hd_AI_algo_jixing1 create success!" ; - return new Hd_AI_algo_jixing1; + qDebug() << "[INFO] " << " Hd_AI_algo_jiXing_L create success!"; + return new Hd_AI_algo_jiXing_L; } -void destory(Hd_AI_algo_jixing1* ptr) +void destory(Hd_AI_algo_jiXing_L* ptr) { - qDebug() << "[INFO] " << "Hd_AI_algo_jixing1 destory success!"; - if(ptr) + qDebug() << "[INFO] " << "Hd_AI_algo_jiXing_L destory success!"; + if (ptr) { delete ptr; ptr = nullptr; } } -Hd_AI_algo_jixing1::Hd_AI_algo_jixing1() +Hd_AI_algo_jiXing_L::Hd_AI_algo_jiXing_L() { detect_mutex = new QMutex; saveStruct_mutex = new QMutex; ifdetectThread = false; - for (int i = 0; i < 4; i++) { QString DirPath = "E:/testImg/source" + QString::number(i); @@ -456,7 +505,7 @@ Hd_AI_algo_jixing1::Hd_AI_algo_jixing1() } } -Hd_AI_algo_jixing1::~Hd_AI_algo_jixing1() +Hd_AI_algo_jiXing_L::~Hd_AI_algo_jiXing_L() { ifdetectThread = false; Sleep(10); @@ -470,70 +519,76 @@ Hd_AI_algo_jixing1::~Hd_AI_algo_jixing1() delete saveStruct_mutex; saveStruct_mutex = nullptr; } + /*DestroySegObj(pSeg); DestroyClsObj(pCls);*/ } //从类中读数据到实例对象 -bool Hd_AI_algo_jixing1::readData(std::vector&vec_mat,QByteArray &data) +bool Hd_AI_algo_jiXing_L::readData(std::vector& vec_mat, QByteArray& data) { detect_mutex->lock(); //qDebug() << __FUNCTION__ << " line:" <<__LINE__ << " data len:" << data.length(); - if (resMat.size()>0) + if (resMat.size() > 0) { vec_mat.push_back(resMat[0]); resMat.clear(); } else { - if(HikMat.size()>0) + if (HikMat.size() > 0) vec_mat.push_back(HikMat[0]); //qDebug() << __FUNCTION__ << " line:" << __LINE__ << " resMat.data err:"; } //if (allNum++ % 2 == 0) // data = "2*3*2";// resByte.dequeue(); //else - data = QByteArray::number(algoResult) + "&" + QByteArray::number(algoResult - 1) + "+" + QByteArray::number(algoResult); + //QByteArray resultCmd = resultCmdSplitStart + + // resultPlc + // + resultCmdSplitEnd; resByte.clear(); + QVariant jiXingJieGuo = (resultPlc == "1") ? "OK" : "NG"; + data = logicUiTransport::encodeAllData(SN,{ resultPlc }, { {"极性检测结果",jiXingJieGuo}}); ////之后根据结果类修改 //if(resIfNg == true) // data = "NG"; //else data = "OK"; detect_mutex->unlock(); /*if(cameraKey_index.contains('_')) - qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getDetectData--CameraName:" + qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getDetectData--CameraName:" << cameraKey_index.split("_")[0] << " imgIndex:" << cameraKey_index.split("_")[1]; else qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getDetectData--CameraName imgIndex:" << cameraKey_index;*/ return true; } //从类中读数据到实例对象 -bool Hd_AI_algo_jixing1::encodeResultValue(QVector append_value,QByteArray &resultByte) +bool Hd_AI_algo_jiXing_L::encodeResultValue(QVector append_value, QByteArray& resultByte) { try { std::string sendMsg; - for(int i = 0 ; i < append_value.size();i++) + for (int i = 0; i < append_value.size(); i++) { std::string value = append_value.at(1); //type int type = 3; std::string m_type; - m_type.insert(0,4,'1'); - memcpy ( (void*)m_type.c_str(),(void*)&type,4 ); + m_type.insert(0, 4, '1'); + memcpy((void*)m_type.c_str(), (void*)&type, 4); sendMsg.append(m_type); //len int len = value.length(); std::string m_len; - m_len.insert(0,4,'1'); - memcpy ( (void*)m_len.c_str(),(void*)&len,4 ); + m_len.insert(0, 4, '1'); + memcpy((void*)m_len.c_str(), (void*)&len, 4); sendMsg.append(m_len); //data x sendMsg.append(value); } resultByte = QByteArray::fromStdString(sendMsg); - } catch (QString ev) + } + catch (QString ev) { qCritical() << "[Error] " << " ev:" << ev; return false; @@ -541,13 +596,14 @@ bool Hd_AI_algo_jixing1::encodeResultValue(QVector append_value,QBy return true; } -int myallNum[4] = {0}; +int myallNum[4] = { 0 }; QMap lastImgMap; //接收数据 -bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &data) +bool Hd_AI_algo_jiXing_L::writeData(std::vector& vec_mat, QByteArray& data) { //qDebug() << __FUNCTION__ << "line:"<< __LINE__ << " data len" << data.length() ; - if(vec_mat.empty()) + + if (vec_mat.empty()) { qCritical() << "[Error] " << " vec_mat is null !"; return false; @@ -555,7 +611,7 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da detect_mutex->lock(); HikMat.clear(); for (int i = 0; i < vec_mat.size(); i++) - HikMat.enqueue(vec_mat[i]); + HikMat.enqueue(vec_mat[i]); QByteArray source_savePath; QByteArray sData = data; @@ -566,8 +622,9 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da cameraKey_index = splitDataList[2]; QByteArray saveDir = splitDataList[0] + "/" + splitDataList[1] + "/"; isDirExist(byteArrayToUnicode(saveDir)); //不存在,创建 - QString sdataTime= QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); + QString sdataTime = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); source_savePath = splitDataList[0] + "/" + splitDataList[1] + "/" + sdataTime.toLocal8Bit() + "-" + splitDataList[2] + "-" + splitDataList[3];// +".bmp"; + SN = splitDataList[3]; } //int index = -1; /*if (sData.contains("offline-camera0")) @@ -592,10 +649,8 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da }*/ - - - createDirectoryIfNotExists(oriImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//"); - addImgToSaveStruct(HikMat[0], "0", getOriSaveFromat());//保存原图 + + addImgToSaveStruct(HikMat[0], "0", getOriSaveFormat(SN));//保存原图 //if (!source_savePath.isEmpty()) //{ // //std::cout << "try savePath::" << savePath.toStdString() << std::endl; @@ -646,7 +701,7 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da /*saveKey.enqueue("datalist[0]"); Dir2D.enqueue("datalist[1]"); - QStringList SN_dataTime; + QStringList SN_dataTime; SN_dataTime = datalist[3].split('_'); DateTime1 = "SN_dataTime[1]"; SN.enqueue("SN_dataTime[0]");*/ @@ -663,7 +718,7 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da //传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... //初始化 -bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) +bool Hd_AI_algo_jiXing_L::initParas(QByteArray& byte) { initValueList = byte.split('+'); QStringList valueiList; @@ -688,13 +743,11 @@ bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) valueiList.append(valuei); } - /*pSeg = CreateSegObjS(pSeg_modulePath, 128, gpuId); pCls = CreateClsObjV3(pCls_modulePath, gpuId, 1);*/ //StationNo = vec_ret.at(0).toInt(); - //InitThreads(StationNo, img2D); //InitModels(StationNo, img2D); @@ -703,9 +756,9 @@ bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) //线程检测:结果类完成时,使用 //ifThreadRunDetect = true; - //QFuture future1 = QtConcurrent::run(this, &Hd_AI_algo_jixing1::detectThread); + //QFuture future1 = QtConcurrent::run(this, &Hd_AI_algo_jiXing_L::detectThread); //运行存图线程 - QFuture future2 = QtConcurrent::run(this, &Hd_AI_algo_jixing1::saveImgThread); + QFuture future2 = QtConcurrent::run(this, &Hd_AI_algo_jiXing_L::saveImgThread); //detectThread(); //原图总文件夹 @@ -715,51 +768,52 @@ bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) //结果图总文件夹 isDirExist(resImgSaveDir); - myEngine.SetProcedurePath("./halconFilesAlgo/AlgoLibrary_628_1.hdpl"); //设置hdvp路径 //qDebug() << "[INFO] " << " StationNo:" << StationNo << " img2D:" << img2D ; + myEngine.SetProcedurePath("./halconFilesAlgo/JX_ColorInspection.hdpl"); //设置hdvp路径 return true; } // 解码 -bool Hd_AI_algo_jixing1::decodeAiValue(QByteArray byte,QVector &vec_ret) +bool Hd_AI_algo_jiXing_L::decodeAiValue(QByteArray byte, QVector& vec_ret) { - if(byte.isEmpty()) + if (byte.isEmpty()) { qCritical() << "[Error] " << " byte is null!"; return false; } /*******************************************/ - byte.remove(0,8); - QByteArray mm_data = byte.mid(0,4); - memcpy((void*)¶mNum,(void*)mm_data.data(), 4); + byte.remove(0, 8); + QByteArray mm_data = byte.mid(0, 4); + memcpy((void*)¶mNum, (void*)mm_data.data(), 4); qDebug() << "[INFO] " << " paramNum:" << paramNum; - byte.remove(0,4); + byte.remove(0, 4); /*******************************************/ while (!byte.isEmpty()) { int type = 0; - QByteArray m_type = byte.mid(0,4); - memcpy((void*)&type,(void*)m_type.data(), 4); - byte.remove(0,4); + QByteArray m_type = byte.mid(0, 4); + memcpy((void*)&type, (void*)m_type.data(), 4); + byte.remove(0, 4); int len = 0; - QByteArray m_len = byte.mid(0,4); - memcpy((void*)&len,(void*)m_len.data(), 4); - byte.remove(0,4); + QByteArray m_len = byte.mid(0, 4); + memcpy((void*)&len, (void*)m_len.data(), 4); + byte.remove(0, 4); - QByteArray mm_data = byte.mid(0,len); + QByteArray mm_data = byte.mid(0, len); vec_ret.append(mm_data); - byte.remove(0,len); + byte.remove(0, len); } return true; } - //---------检测流程,根据实际项目修改--------- -bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDir2D, QString mySN, QString myDataTime) +bool Hd_AI_algo_jiXing_L::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDir2D, QString mySN, QString myDataTime) { try { + + //存图数据加保存队列,加锁,避免数据访问冲突 saveStruct_mutex->lock(); saveImgStruct mySave; @@ -774,7 +828,7 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi QJsonObject obj; obj.insert("result_key", "mysaveKey"); obj.insert("SN", "mySN"); - obj.insert("DataTime", "myDataTime"); + obj.insert("DataTime", "myDa taTime"); //QFile csvName("test.csv"); @@ -786,68 +840,84 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi // csvName.write(lines[i].toStdString().c_str()); // csvName.close(); //} - HDevEngineCpp::HDevProcedure proc("YH_Color_Inspection"); - HDevProcedureCall procedureCall(proc); - QQueue defectInfoList; - + //sourceImg = cv::imread("D:\\mySN15-46-33-86.bmp",-1); + //sourceImg = cv::imread("F:/CCD/TEST/20241024-091531.bmp", -1); cv::Mat Paint; sourceImg.copyTo(Paint); - //极性检测 + if (Paint.channels() == 1) + cvtColor(Paint, Paint, COLOR_GRAY2BGR); + + + HDevEngineCpp::HDevProcedure proc("JX_Inspection"); + HDevProcedureCall procedureCall(proc); + HObject in_Image; - HTuple out_ColorType; - HTuple out_Flag; + HTuple out_Flag, out_ColorType; MatToHObject(sourceImg, &in_Image); - procedureCall.SetInputIconicParamObject("in_Image", in_Image);//设置输入图像类变量 + + procedureCall.SetInputIconicParamObject("in_Image", in_Image);// procedureCall.Execute();//执行halcon程序 - out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出图像类变量 - out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量 - //相机1 OK为铝 NG为铜s + + out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出图像类变量 + out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出控制类变量 + resultPlc = "1"; if (out_Flag.D() == 1) { - if (out_ColorType.D() == 2)//铝 + int res1 = out_ColorType[0].D(); + int res2 = out_ColorType[1].D(); + //1铜 2铝+ + switch (res1) { - putTextHusky(Paint, utf8_to_gbk("铝极").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - //cv::putText(sourceImg, "Aluminium", cv::Point(0, 240), 2, 10, cv::Scalar(0, 255, 0), 10); - cv::putText(Paint, "OK", cv::Point(0, 550), 2, 10, cv::Scalar(0, 255, 0), 10); - algoResult = 1; - //Result = 1 ? 2; - //Result = 1; + case 0: + putTextHusky(Paint, utf8_to_gbk("异常").c_str(), cv::Point(0, 0), cv::Scalar(0, 0, 255), 300); + break; + case 1: + putTextHusky(Paint, utf8_to_gbk("铜").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 500); + break; + case 2: + putTextHusky(Paint, utf8_to_gbk("铝").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 500); + break; } - else if (out_ColorType.D() == 1)//铜 + + switch (res2) { - putTextHusky(Paint, utf8_to_gbk("铜极").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - //cv::putText(sourceImg, "Copper", cv::Point(0, 240), 2, 10, cv::Scalar(0, 255, 0), 10); - cv::putText(Paint, "NG", cv::Point(0, 550), 2, 10, cv::Scalar(0, 0,255), 10); - algoResult = 1; + case 0: + putTextHusky(Paint, utf8_to_gbk("异常").c_str(), cv::Point(0, Paint.rows - 500), cv::Scalar(0, 0, 255), 300); + break; + case 1: + putTextHusky(Paint, utf8_to_gbk("铜").c_str(), cv::Point(0, Paint.rows - 500), cv::Scalar(0, 255, 0), 500); + break; + case 2: + putTextHusky(Paint, utf8_to_gbk("铝").c_str(), cv::Point(0, Paint.rows - 500), cv::Scalar(0, 255, 0), 500); + break; + + } + + //T 为铜OK,L为铝OK + if (res1 == 2 && res2 == 2)//铝ok + { + putTextHusky(Paint, utf8_to_gbk("OK").c_str(), cv::Point(Paint.cols - 800, 0), cv::Scalar(0, 255, 0), 500); } else { - putTextHusky(Paint, utf8_to_gbk("算法异常1").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - // cv::putText(sourceImg, "Algo error1", cv::Point(0, 240), 2, 10, cv::Scalar(0, 0, 255), 10); - //Result = 2; + putTextHusky(Paint, utf8_to_gbk("NG").c_str(), cv::Point(Paint.cols - 800, 0), cv::Scalar(0, 0, 255), 500); + resultPlc = "1"; } } else - { - putTextHusky(Paint, utf8_to_gbk("算法异常1").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - // cv::putText(sourceImg, "Algo error2", cv::Point(0, 240), 2, 10, cv::Scalar(0, 0, 255), 10); - } + putTextHusky(Paint, utf8_to_gbk("NG1").c_str(), cv::Point(0, 50), cv::Scalar(0, 0, 255), 500); + + + QQueue defectInfoList; - /*ho_Image.Clear(); - hv_out_Value.Clear(); - hv_Make.Clear();*/ detect_mutex->lock(); - //resMat = sourceImg.clone(); - //sourceImg.copyTo(resMat); + + + + + resMat.push_back(Paint); - //结果图画框和缺陷,在resMat上绘制 - if (resMat.size() > 0) - drawDefects(resMat[0], defectInfoList); - - //QByteArray,根据实际项目进行解析 - //参数,例:返回结果图;相机关键字(SN或userID)+保存路径+缺陷信息列表(缺陷名称,缺陷位置int(x,y,w,h),画框颜色Scalar(a,b,c),缺陷面积double) - QJsonArray detaillists; //QByteArrayList resQbyte; for (int i = 0; i < defectInfoList.size(); i++) @@ -872,7 +942,7 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi detailObj.insert("defectScalar1", QString::number(mdefect.defectScalar[1])); detailObj.insert("defectScalar2", QString::number(mdefect.defectScalar[2])); detailObj.insert("defectArea", QString::number(mdefect.defectArea)); - detailObj.insert("defectLength", QString::number(sqrt(mdefect.defectRect.width* mdefect.defectRect.width+ mdefect.defectRect.height* mdefect.defectRect.height))); + detailObj.insert("defectLength", QString::number(sqrt(mdefect.defectRect.width * mdefect.defectRect.width + mdefect.defectRect.height * mdefect.defectRect.height))); detaillists.append(detailObj); } @@ -885,14 +955,13 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi //emit sendResultData(resMat, resQbyte); //resQbyte.clear(); - isDirExist(resImgSaveDir + mysaveKey1 + "/"); + //isDirExist(resImgSaveDir + mysaveKey1 + "/"); QString qimgsavePath = resImgSaveDir + mysaveKey1 + "/" + mySN + myDataTime + ".png"; //存图数据入队,按需 - QString sdataTime = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); if (resMat.size() > 0) { createDirectoryIfNotExists(resImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//"); - addImgToSaveStruct(resMat[0], "0", getResSaveFromat());//保存原图 + addImgToSaveStruct(resMat[0], "0", getResSaveFromat(SN));//保存原图 } detect_mutex->unlock(); @@ -936,7 +1005,7 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi } //存图加入队列 -void Hd_AI_algo_jixing1::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QString savePath) +void Hd_AI_algo_jiXing_L::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QString savePath) { //存图数据加保存队列,加锁,避免数据访问冲突 saveStruct_mutex->lock(); @@ -948,7 +1017,7 @@ void Hd_AI_algo_jixing1::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QS saveStruct.enqueue(mySave); saveStruct_mutex->unlock(); } -void Hd_AI_algo_jixing1::saveImgThread() +void Hd_AI_algo_jiXing_L::saveImgThread() { while (1) { @@ -964,7 +1033,7 @@ void Hd_AI_algo_jixing1::saveImgThread() saveImgStruct mysaveStruct = saveStruct.dequeue(); saveStruct_mutex->unlock(); stop = clock(); - if(stop-start >1000) + if (stop - start > 1000) std::cout << "lock stop-start >1000::************************" << stop - start << std::endl; start = clock(); if (mysaveStruct.out_Mat.data) @@ -972,17 +1041,17 @@ void Hd_AI_algo_jixing1::saveImgThread() //std::cout << "savePath::" << mysaveStruct.savePath << std::endl; stop = clock(); if (stop - start > 1000) - std::cout << "imwrite stop-start >1000::--------------------------"<< stop - start << std::endl; + std::cout << "imwrite stop-start >1000::--------------------------" << stop - start << std::endl; _sleep(1); } } } //检测线程,应当只运行一次 -void Hd_AI_algo_jixing1::detectThread() +void Hd_AI_algo_jiXing_L::detectThread() { do { - if (!ifdetectThread)return; + if (!ifdetectThread)return; //此两行代码,避免程序卡死;_sleep的时间根据实际项目调整 _sleep(2); @@ -1012,9 +1081,9 @@ void Hd_AI_algo_jixing1::detectThread() isDirExist(resImgSaveDir + mysaveKey); } - + //测试相机的, - //while (sourceImg1.cols > 2000)cv::resize(sourceImg1, sourceImg1, cv::Size(), 0.5, 0.5); + // while (sourceImg1.cols > 2000)cv::resize(sourceImg1, sourceImg1, cv::Size(), 0.5, 0.5); //存图数据入队 //addImgToSaveStruct(sourceImg1, mysaveKey, oriImgSaveDir + mysaveKey + "/" + mySN + myDataTime + ".bmp"); @@ -1027,14 +1096,14 @@ void Hd_AI_algo_jixing1::detectThread() myDir2D.clear(); mySN.clear(); myDataTime.clear(); - qApp->processEvents(); + qApp->processEvents(); } while (ifThreadRunDetect); - + } static int runNum = 0; -bool Hd_AI_algo_jixing1::run() +bool Hd_AI_algo_jiXing_L::run() { clock_t start, stop; start = clock(); @@ -1042,14 +1111,14 @@ bool Hd_AI_algo_jixing1::run() //Sleep(1000); detectThread(); stop = clock(); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << " run start ::runNum::" << runNum++<<" cutTime::"< #include @@ -15,18 +15,16 @@ #include #include #include - #include #include #include "imgproc/imgproc_c.h" - #include "base.h" - #pragma execution_character_set("utf-8") - #include + using namespace HDevEngineCpp; + //保存图片的结构体 struct saveImgStruct; //{ @@ -35,16 +33,16 @@ struct saveImgStruct; // std::string savePath; //保存路径 //}; -//初始化流程(一次):Hd_AI_algo_jixing1,initParas +//初始化流程(一次):Hd_AI_algo_jiXing_L,initParas //运行流程:writeData主线程把数据传过来,run,readData此线程把数据传主线程 -class Hd_AI_algo_jixing1 :public Base +class Hd_AI_algo_jiXing_L :public Base { Q_OBJECT public: - Hd_AI_algo_jixing1(); - virtual ~Hd_AI_algo_jixing1(); + Hd_AI_algo_jiXing_L(); + virtual ~Hd_AI_algo_jiXing_L(); //从类中读数据到实例对象 - bool readData(std::vector&,QByteArray&); + bool readData(std::vector&, QByteArray&); //实例对象把数据写入到类 bool writeData(std::vector&, QByteArray&); bool initParas(QByteArray&); @@ -53,17 +51,15 @@ public: //线程状态 bool checkStatus();// { return true; }; - bool encodeResultValue(QVector append_value,QByteArray &resultByte); - bool decodeAiValue(QByteArray byte,QVector &vec_ret); + bool encodeResultValue(QVector append_value, QByteArray& resultByte); + bool decodeAiValue(QByteArray byte, QVector& vec_ret); //---------检测流程,根据实际项目修改--------- bool AIdetect(cv::Mat img2D, QString saveKey, QString Dir2D, QString SN, QString DataTime); - - private: HDevEngine myEngine; int allNum = 0; - int StationNo=0; + int StationNo = 0; int img2D = 2; bool moduleStatus = true; @@ -71,13 +67,13 @@ private: //输入图片队列 QQueue HikMat; //输入关键字队列 - QString saveKey="saveKey"; + QString saveKey = "saveKey"; //结果路径文件夹队列 - QString Dir2D="Dir2D"; + QString Dir2D = "Dir2D"; //产品SN队列 - QString SN="SN"; + QString SN = "SN"; //产品时间戳队列 - QString DateTime1="DateTime1"; + QString DateTime1 = "DateTime1"; int paramNum; @@ -94,7 +90,7 @@ private: void detectThread(); //存图线程 void saveImgThread(); - + //保存图片队列 QQueue saveStruct; @@ -107,8 +103,8 @@ private: extern "C" { - Q_DECL_EXPORT Hd_AI_algo_jixing1 * create(); - Q_DECL_EXPORT void destory(Hd_AI_algo_jixing1 * ptr); + Q_DECL_EXPORT Hd_AI_algo_jiXing_L* create(); + Q_DECL_EXPORT void destory(Hd_AI_algo_jiXing_L* ptr); } //保存图片的结构体 struct saveImgStruct diff --git a/BaseModules/Hd_AI_algo_jixing_T/CMakeLists.txt b/BaseModules/Hd_AI_algo_jixing_T/CMakeLists.txt index be21793..be2265d 100644 --- a/BaseModules/Hd_AI_algo_jixing_T/CMakeLists.txt +++ b/BaseModules/Hd_AI_algo_jixing_T/CMakeLists.txt @@ -3,7 +3,7 @@ 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" "halconAlgo" "myTools" ) +set(DLL_NAMES "opencv" "halcon" "halconAlgo" "myTools" "handdleAI") foreach(child ${DLL_NAMES}) LIST(APPEND ENV_INCLUDE ${${child}_include}) LIST(APPEND ENV_LIB ${${child}_lib}) @@ -39,7 +39,7 @@ 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) - +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS network REQUIRED) add_library(${CURRENT_FOLDER} SHARED ${HEAD_FILES} ${SRC_FILES} @@ -58,6 +58,7 @@ set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C target_link_libraries(${CURRENT_FOLDER} PRIVATE ${ENV_TARGET} Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Network ) diff --git a/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.cpp b/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.cpp index cde4eb2..476d007 100644 --- a/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.cpp +++ b/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.cpp @@ -1,33 +1,34 @@ -#include "Hd_AI_algo_jixing_T.h" +#include "Hd_AI_algo_jiXing_T.h" #include -#include + #include #include #include +#include +#include #include -#include -#include -#include +#include + using namespace cv; - -//原图保存文件夹 -QString oriImgSaveDir = "D:/D601线/超声波预焊机/极性检测CCD/原图/"; +QByteArray resultPlc; +//原图保存文件夹s + QString oriImgSaveDir = "D:/601线/终焊CCD/极性检测CCD/原图/"; //原图class图保存文件夹 -QString classImgSaveDir = "D:/D601线/超声波预焊机/极性检测CCD/class图/"; + QString classImgSaveDir = "D:/601线/终焊CCD/极性检测CCD/class图/"; //结果保存文件夹 -QString resImgSaveDir = "D:/D601线/超声波预焊机/极性检测CCD/结果图/"; - + QString resImgSaveDir = "D:/601线/终焊CCD/极性检测CCD/结果图/"; + int algoResult = 0;//0 OK 1 NG //切图的class的width,根据项目实际设置! int sizeW = 150; //切图的class的height,根据项目实际设置! int sizeH = 150; //切图的class的width,根据项目实际设置!0为黑,255为白; int fillColour = 0; -int algoResult; + //检测线程锁 QMutex* detect_mutex; -//保存线程锁 +//保存线程锁 QMutex* saveStruct_mutex; //检测线程运行标志 bool ifdetectThread = false; @@ -36,6 +37,7 @@ int algoResult; //初始化参数列表 QByteArrayList initValueList; + static void createDirectoryIfNotExists(const QString& path) { QDir dir; dir.mkpath(path); @@ -61,16 +63,7 @@ int algoResult; static QString getCurrentHour() { QDateTime currentDateTime = QDateTime::currentDateTime(); - return QString::number(currentDateTime.time().hour()) + "H"; - } - inline std::string utf8_to_gbk(const std::string& str) - { - std::wstring_convert> conv; - std::wstring tmp_wstr = conv.from_bytes(str); - //GBK locale name in windows - const char* GBK_LOCALE_NAME = ".936"; - std::wstring_convert> convert(new std::codecvt_byname(GBK_LOCALE_NAME)); - return convert.to_bytes(tmp_wstr); + return QString::number(currentDateTime.time().hour())+"H"; } QString byteArrayToUnicode(const QByteArray array) { @@ -87,17 +80,72 @@ int algoResult; } return text; } - QString getOriSaveFromat() + static cv::Rect findMaxAreaContour(cv::Mat src) { - return oriImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" - + "ORI_" + cameraKey_index + "_" + QString::fromStdString(getCurrentTime()) + ".bmp"; + int maxIndex = 0, maxArea = 0; + std::vector>contours; + cv::findContours(src, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); + if (contours.size() == 0) + return cv::Rect(0, 0, 0, 0); + for (int i = 0; i < contours.size(); i++) + { + int Area = cv::contourArea(contours[i]); + if (Area > maxArea) + { + maxArea = Area; + maxIndex = i; + } + } + if (contours.size() != 0) + return cv::boundingRect(contours[maxIndex]); + return cv::Rect(0, 0, 0, 0); } - QString getResSaveFromat() + inline std::string utf8_to_gbk(const std::string& str) { - return resImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" - + "RES_" + cameraKey_index + "_" + QString::fromStdString(getCurrentTime()) + ".png"; + std::wstring_convert> conv; + std::wstring tmp_wstr = conv.from_bytes(str); + //GBK locale name in windows + const char* GBK_LOCALE_NAME = ".936"; + std::wstring_convert> convert(new std::codecvt_byname(GBK_LOCALE_NAME)); + return convert.to_bytes(tmp_wstr); + } + void getAllFiles(std::string path, std::vector& files, std::string format) + { + intptr_t hFile = 0;//文件句柄 + struct _finddata_t fileinfo;//文件信息 + std::string p; + if ((hFile = _findfirst(p.assign(path).append("\\*" + format).c_str(), &fileinfo)) != -1) //文件存在 + { + do + { + if ((fileinfo.attrib & _A_SUBDIR))//判断是否为文件夹 + { + if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)//文件夹名中不含"."和".." + { + files.push_back(p.assign(path).append("\\").append(fileinfo.name)); //保存文件夹名 + getAllFiles(p.assign(path).append("\\").append(fileinfo.name), files, format); //递归遍历文件夹 + } + } + else + { + files.push_back(p.assign(path).append("\\").append(fileinfo.name));//如果不是文件夹,储存文件名 + } + } while (_findnext(hFile, &fileinfo) == 0); + _findclose(hFile); + } + } + QString getOriSaveFormat(QString SN) + { + QString path = oriImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" + SN + "//"; + createDirectoryIfNotExists(path); + return path + "ORI_" + cameraKey_index + "_" + SN + "_" + QString::fromStdString(getCurrentTime()) + ".bmp"; + } + QString getResSaveFromat(QString SN) + { + QString path = resImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//" + SN + "//"; + createDirectoryIfNotExists(path); + return path + "RES_" + cameraKey_index + "_" + SN + "_" + QString::fromStdString(getCurrentTime()) + ".png"; } - // 缺陷信息结构体 typedef struct { QString defectName = "";//缺陷名称 @@ -232,6 +280,8 @@ void GetStringSize(HDC hdc, const char* str, int* w, int* h) if (h != 0) *h = size.cy; } //在图像写中文,英文也可以写 + + void putTextZH(cv::Mat& dst, const char* str, cv::Point org, cv::Scalar color, int fontsize, const char* fn = "Arial", bool italic = false, bool underline = false) { @@ -397,7 +447,7 @@ void drawDefects(cv::Mat& sourceMat, QQueue defectInfoList) //判断文件夹是否存在,不存在则创建 -void Hd_AI_algo_jixing1::isDirExist(QString fullDirName) +void Hd_AI_algo_jiXing_T::isDirExist(QString fullDirName) { QDir* photo = new QDir; bool exist = photo->exists(fullDirName); @@ -415,15 +465,15 @@ void Hd_AI_algo_jixing1::isDirExist(QString fullDirName) photo = nullptr; } -Hd_AI_algo_jixing1* create() +Hd_AI_algo_jiXing_T* create() { - qDebug() << "[INFO] " << " Hd_AI_algo_jixing1 create success!" ; - return new Hd_AI_algo_jixing1; + qDebug() << "[INFO] " << " Hd_AI_algo_jiXing_T create success!" ; + return new Hd_AI_algo_jiXing_T; } -void destory(Hd_AI_algo_jixing1* ptr) +void destory(Hd_AI_algo_jiXing_T* ptr) { - qDebug() << "[INFO] " << "Hd_AI_algo_jixing1 destory success!"; + qDebug() << "[INFO] " << "Hd_AI_algo_jiXing_T destory success!"; if(ptr) { delete ptr; @@ -431,12 +481,11 @@ void destory(Hd_AI_algo_jixing1* ptr) } } -Hd_AI_algo_jixing1::Hd_AI_algo_jixing1() +Hd_AI_algo_jiXing_T::Hd_AI_algo_jiXing_T() { detect_mutex = new QMutex; saveStruct_mutex = new QMutex; ifdetectThread = false; - for (int i = 0; i < 4; i++) { QString DirPath = "E:/testImg/source" + QString::number(i); @@ -456,7 +505,7 @@ Hd_AI_algo_jixing1::Hd_AI_algo_jixing1() } } -Hd_AI_algo_jixing1::~Hd_AI_algo_jixing1() +Hd_AI_algo_jiXing_T::~Hd_AI_algo_jiXing_T() { ifdetectThread = false; Sleep(10); @@ -470,11 +519,12 @@ Hd_AI_algo_jixing1::~Hd_AI_algo_jixing1() delete saveStruct_mutex; saveStruct_mutex = nullptr; } + /*DestroySegObj(pSeg); DestroyClsObj(pCls);*/ } //从类中读数据到实例对象 -bool Hd_AI_algo_jixing1::readData(std::vector&vec_mat,QByteArray &data) +bool Hd_AI_algo_jiXing_T::readData(std::vector&vec_mat,QByteArray &data) { detect_mutex->lock(); //qDebug() << __FUNCTION__ << " line:" <<__LINE__ << " data len:" << data.length(); @@ -492,7 +542,8 @@ bool Hd_AI_algo_jixing1::readData(std::vector&vec_mat,QByteArray &data) //if (allNum++ % 2 == 0) // data = "2*3*2";// resByte.dequeue(); //else - data = QByteArray::number(algoResult) + "&" + QByteArray::number(algoResult - 1) + "+" + QByteArray::number(algoResult);//1OK,2NG + QVariant jiXingJieGuo = (resultPlc == "1") ? "OK" : "NG"; + data = logicUiTransport::encodeAllData(SN,{ resultPlc }, { {"极性检测结果",jiXingJieGuo} }); resByte.clear(); ////之后根据结果类修改 //if(resIfNg == true) @@ -507,7 +558,7 @@ bool Hd_AI_algo_jixing1::readData(std::vector&vec_mat,QByteArray &data) return true; } //从类中读数据到实例对象 -bool Hd_AI_algo_jixing1::encodeResultValue(QVector append_value,QByteArray &resultByte) +bool Hd_AI_algo_jiXing_T::encodeResultValue(QVector append_value,QByteArray &resultByte) { try { @@ -544,9 +595,10 @@ bool Hd_AI_algo_jixing1::encodeResultValue(QVector append_value,QBy int myallNum[4] = {0}; QMap lastImgMap; //接收数据 -bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &data) +bool Hd_AI_algo_jiXing_T::writeData(std::vector& vec_mat, QByteArray &data) { //qDebug() << __FUNCTION__ << "line:"<< __LINE__ << " data len" << data.length() ; + if(vec_mat.empty()) { qCritical() << "[Error] " << " vec_mat is null !"; @@ -557,7 +609,7 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da for (int i = 0; i < vec_mat.size(); i++) HikMat.enqueue(vec_mat[i]); - QByteArray source_savePath; + QByteArray source_savePath; QByteArray sData = data; QByteArrayList splitDataList = sData.split(','); if (splitDataList.size() >= 4) @@ -568,6 +620,7 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da isDirExist(byteArrayToUnicode(saveDir)); //不存在,创建 QString sdataTime= QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); source_savePath = splitDataList[0] + "/" + splitDataList[1] + "/" + sdataTime.toLocal8Bit() + "-" + splitDataList[2] + "-" + splitDataList[3];// +".bmp"; + SN = splitDataList[3]; } //int index = -1; /*if (sData.contains("offline-camera0")) @@ -591,11 +644,24 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da savePath = "E:\\testImg\\source3\\" + QString::number(myallNum[3]++) + ".bmp"; }*/ - - - - createDirectoryIfNotExists(oriImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//"); - addImgToSaveStruct(HikMat[0], "0", getOriSaveFromat());//保存原图 + addImgToSaveStruct(HikMat[0], "0", getOriSaveFormat(SN));//保存原图 + //if (!source_savePath.isEmpty()) + //{ + // //std::cout << "try savePath::" << savePath.toStdString() << std::endl; + // //测试相机的, + // //while (HikMat[0].cols > 2000)cv::resize(HikMat[0], HikMat[0], cv::Size(), 0.08, 0.08);' + // for (int i = 0; i < initValueList.size(); i++) + // { + // QString minit = byteArrayToUnicode(initValueList[i]); + // if (initValueList[i].contains(data.split(',')[2].split('_')[0])) + // if (initValueList[i].contains(QString("原图_保存").toLocal8Bit())) + // { + // addImgToSaveStruct(HikMat[0], "0", byteArrayToUnicode(source_savePath + ".bmp"));//保存原图 + // if (HikMat.size() == 2)//3D + // addImgToSaveStruct(HikMat[1], "0", byteArrayToUnicode(source_savePath + ".tif")); + // } + // } + //} //if (myallNum[index] == 1) //{ @@ -646,7 +712,7 @@ bool Hd_AI_algo_jixing1::writeData(std::vector& vec_mat, QByteArray &da //传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... //初始化 -bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) +bool Hd_AI_algo_jiXing_T::initParas(QByteArray& byte) { initValueList = byte.split('+'); QStringList valueiList; @@ -671,13 +737,11 @@ bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) valueiList.append(valuei); } - /*pSeg = CreateSegObjS(pSeg_modulePath, 128, gpuId); pCls = CreateClsObjV3(pCls_modulePath, gpuId, 1);*/ //StationNo = vec_ret.at(0).toInt(); - //InitThreads(StationNo, img2D); //InitModels(StationNo, img2D); @@ -686,9 +750,9 @@ bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) //线程检测:结果类完成时,使用 //ifThreadRunDetect = true; - //QFuture future1 = QtConcurrent::run(this, &Hd_AI_algo_jixing1::detectThread); + //QFuture future1 = QtConcurrent::run(this, &Hd_AI_algo_jiXing_T::detectThread); //运行存图线程 - QFuture future2 = QtConcurrent::run(this, &Hd_AI_algo_jixing1::saveImgThread); + QFuture future2 = QtConcurrent::run(this, &Hd_AI_algo_jiXing_T::saveImgThread); //detectThread(); //原图总文件夹 @@ -698,12 +762,12 @@ bool Hd_AI_algo_jixing1::initParas(QByteArray& byte) //结果图总文件夹 isDirExist(resImgSaveDir); - myEngine.SetProcedurePath("./halconFilesAlgo/AlgoLibrary_628_1.hdpl"); //设置hdvp路径 //qDebug() << "[INFO] " << " StationNo:" << StationNo << " img2D:" << img2D ; + myEngine.SetProcedurePath("./halconFilesAlgo/JX_ColorInspection.hdpl"); //设置hdvp路径 return true; } // 解码 -bool Hd_AI_algo_jixing1::decodeAiValue(QByteArray byte,QVector &vec_ret) +bool Hd_AI_algo_jiXing_T::decodeAiValue(QByteArray byte,QVector &vec_ret) { if(byte.isEmpty()) { @@ -737,12 +801,13 @@ bool Hd_AI_algo_jixing1::decodeAiValue(QByteArray byte,QVector &vec_ } return true; } - //---------检测流程,根据实际项目修改--------- -bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDir2D, QString mySN, QString myDataTime) +bool Hd_AI_algo_jiXing_T::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDir2D, QString mySN, QString myDataTime) { try { + + //存图数据加保存队列,加锁,避免数据访问冲突 saveStruct_mutex->lock(); saveImgStruct mySave; @@ -769,68 +834,84 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi // csvName.write(lines[i].toStdString().c_str()); // csvName.close(); //} - HDevEngineCpp::HDevProcedure proc("YH_Color_Inspection"); - HDevProcedureCall procedureCall(proc); - QQueue defectInfoList; - + //sourceImg = cv::imread("D:\\mySN15-46-33-86.bmp",-1); + //sourceImg = cv::imread("F:/CCD/TEST/20241024-091531.bmp", -1); cv::Mat Paint; sourceImg.copyTo(Paint); - //极性检测 + if(Paint.channels() == 1) + cvtColor(Paint, Paint, COLOR_GRAY2BGR); + + + HDevEngineCpp::HDevProcedure proc("JX_Inspection"); + HDevProcedureCall procedureCall(proc); + HObject in_Image; - HTuple out_ColorType; - HTuple out_Flag; + HTuple out_Flag, out_ColorType; MatToHObject(sourceImg, &in_Image); - procedureCall.SetInputIconicParamObject("in_Image", in_Image);//设置输入图像类变量 + + procedureCall.SetInputIconicParamObject("in_Image", in_Image);// procedureCall.Execute();//执行halcon程序 - out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出图像类变量 - out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出控制类变量 - //相机2 OK为铜 NG为铝 - if (out_Flag.D() == 1) + + out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag");//获取输出图像类变量 + out_ColorType = procedureCall.GetOutputCtrlParamTuple("out_ColorType");//获取输出控制类变量 + resultPlc = "1"; + if(out_Flag.D() == 1) { - if (out_ColorType.D() == 2)//铝 + int res1 = out_ColorType[0].D(); + int res2 = out_ColorType[1].D(); + //1铜 2铝+ + switch (res1) { - putTextHusky(Paint, utf8_to_gbk("铝极").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - //cv::putText(sourceImg, "Aluminium", cv::Point(0, 240), 2, 10, cv::Scalar(0, 255, 0), 10); - cv::putText(Paint, "NG", cv::Point(0, 550), 2, 10, cv::Scalar(0, 0, 255), 10); - algoResult = 1; - //Result = 1 ? 2; - //Result = 1; + case 0: + putTextHusky(Paint, utf8_to_gbk("异常").c_str(), cv::Point(0, 0), cv::Scalar(0, 0, 255), 300); + break; + case 1: + putTextHusky(Paint, utf8_to_gbk("铜").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 500); + break; + case 2: + putTextHusky(Paint, utf8_to_gbk("铝").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 500); + break; } - else if (out_ColorType.D() == 1)//铜 + + switch (res2) { - putTextHusky(Paint, utf8_to_gbk("铜极").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - //cv::putText(sourceImg, "Copper", cv::Point(0, 240), 2, 10, cv::Scalar(0, 255, 0), 10); - cv::putText(Paint, "OK", cv::Point(0, 550), 2, 10, cv::Scalar(0, 255, 0), 10); - algoResult = 1; + case 0: + putTextHusky(Paint, utf8_to_gbk("异常").c_str(), cv::Point(0, Paint.rows - 500), cv::Scalar(0, 0, 255), 300); + break; + case 1: + putTextHusky(Paint, utf8_to_gbk("铜").c_str(), cv::Point(0, Paint.rows - 500), cv::Scalar(0, 255, 0), 500); + break; + case 2: + putTextHusky(Paint, utf8_to_gbk("铝").c_str(), cv::Point(0, Paint.rows - 500), cv::Scalar(0, 255, 0), 500); + break; + + } + + //T 为铜OK,L为铝OK + if (res1 == 1 && res2 == 1)//铜ok + { + putTextHusky(Paint, utf8_to_gbk("OK").c_str(), cv::Point(Paint.cols - 800, 0), cv::Scalar(0, 255, 0), 500); } else { - putTextHusky(Paint, utf8_to_gbk("算法异常1").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - // cv::putText(sourceImg, "Algo error1", cv::Point(0, 240), 2, 10, cv::Scalar(0, 0, 255), 10); - //Result = 2; + putTextHusky(Paint, utf8_to_gbk("NG").c_str(), cv::Point(Paint.cols - 800, 0), cv::Scalar(0, 0, 255), 500); + resultPlc = "1"; } } else - { - putTextHusky(Paint, utf8_to_gbk("算法异常1").c_str(), cv::Point(0, 0), cv::Scalar(0, 255, 0), 300); - // cv::putText(sourceImg, "Algo error2", cv::Point(0, 240), 2, 10, cv::Scalar(0, 0, 255), 10); - } + putTextHusky(Paint, utf8_to_gbk("NG1").c_str(), cv::Point(0, 50), cv::Scalar(0, 0, 255), 500); - /* ho_Image.Clear(); - hv_out_Value.Clear(); - hv_Make.Clear();*/ + QQueue defectInfoList; + + detect_mutex->lock(); - //resMat = sourceImg.clone(); - //sourceImg.copyTo(resMat); + + + + + resMat.push_back(Paint); - //结果图画框和缺陷,在resMat上绘制 - if (resMat.size() > 0) - drawDefects(resMat[0], defectInfoList); - - //QByteArray,根据实际项目进行解析 - //参数,例:返回结果图;相机关键字(SN或userID)+保存路径+缺陷信息列表(缺陷名称,缺陷位置int(x,y,w,h),画框颜色Scalar(a,b,c),缺陷面积double) - QJsonArray detaillists; //QByteArrayList resQbyte; for (int i = 0; i < defectInfoList.size(); i++) @@ -852,7 +933,7 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi detailObj.insert("defectRect.width", QString::number(mdefect.defectRect.width)); detailObj.insert("defectRect.height", QString::number(mdefect.defectRect.height)); detailObj.insert("defectScalar0", QString::number(mdefect.defectScalar[0])); - detailObj.insert("defectScalar1", QString::number(mdefect.defectScalar[1])); + detailObj.insert("defectScalar1", QString::number(mdefect.defectScalar[1])); detailObj.insert("defectScalar2", QString::number(mdefect.defectScalar[2])); detailObj.insert("defectArea", QString::number(mdefect.defectArea)); detailObj.insert("defectLength", QString::number(sqrt(mdefect.defectRect.width* mdefect.defectRect.width+ mdefect.defectRect.height* mdefect.defectRect.height))); @@ -868,14 +949,13 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi //emit sendResultData(resMat, resQbyte); //resQbyte.clear(); - isDirExist(resImgSaveDir + mysaveKey1 + "/"); - QString qimgsavePath = resImgSaveDir + mysaveKey1 + "/" + mySN + myDataTime + ".png"; + //isDirExist(resImgSaveDir + mysaveKey1 + "/"); + QString qimgsavePath = resImgSaveDir + mysaveKey1 + "/" + mySN + myDataTime + ".png"; //存图数据入队,按需 - QString sdataTime = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); - if (resMat.size() > 0) + if (resMat.size() > 0 ) { createDirectoryIfNotExists(resImgSaveDir + getCurrentDate() + "//" + getCurrentHour() + "//"); - addImgToSaveStruct(resMat[0], "0", getResSaveFromat());//保存原图 + addImgToSaveStruct(resMat[0], "0", getResSaveFromat(SN));//保存原图 } detect_mutex->unlock(); @@ -919,7 +999,7 @@ bool Hd_AI_algo_jixing1::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDi } //存图加入队列 -void Hd_AI_algo_jixing1::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QString savePath) +void Hd_AI_algo_jiXing_T::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QString savePath) { //存图数据加保存队列,加锁,避免数据访问冲突 saveStruct_mutex->lock(); @@ -931,7 +1011,7 @@ void Hd_AI_algo_jixing1::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QS saveStruct.enqueue(mySave); saveStruct_mutex->unlock(); } -void Hd_AI_algo_jixing1::saveImgThread() +void Hd_AI_algo_jiXing_T::saveImgThread() { while (1) { @@ -961,7 +1041,7 @@ void Hd_AI_algo_jixing1::saveImgThread() } } //检测线程,应当只运行一次 -void Hd_AI_algo_jixing1::detectThread() +void Hd_AI_algo_jiXing_T::detectThread() { do { @@ -997,7 +1077,7 @@ void Hd_AI_algo_jixing1::detectThread() } //测试相机的, - //while (sourceImg1.cols > 2000)cv::resize(sourceImg1, sourceImg1, cv::Size(), 0.5, 0.5); + // while (sourceImg1.cols > 2000)cv::resize(sourceImg1, sourceImg1, cv::Size(), 0.5, 0.5); //存图数据入队 //addImgToSaveStruct(sourceImg1, mysaveKey, oriImgSaveDir + mysaveKey + "/" + mySN + myDataTime + ".bmp"); @@ -1017,7 +1097,7 @@ void Hd_AI_algo_jixing1::detectThread() } static int runNum = 0; -bool Hd_AI_algo_jixing1::run() +bool Hd_AI_algo_jiXing_T::run() { clock_t start, stop; start = clock(); @@ -1032,7 +1112,7 @@ bool Hd_AI_algo_jixing1::run() return true; } -bool Hd_AI_algo_jixing1::checkStatus() +bool Hd_AI_algo_jiXing_T::checkStatus() { status = moduleStatus; return status; diff --git a/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.h b/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.h index 8e923a0..68df561 100644 --- a/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.h +++ b/BaseModules/Hd_AI_algo_jixing_T/Hd_AI_algo_jixing_T.h @@ -1,5 +1,5 @@ -#ifndef Hd_AI_algo_jixing1_H -#define Hd_AI_algo_jixing1_H +#ifndef Hd_AI_algo_jiXing_T_H +#define Hd_AI_algo_jiXing_T_H #include #include @@ -15,15 +15,13 @@ #include #include #include - #include #include #include "imgproc/imgproc_c.h" - #include "base.h" - #pragma execution_character_set("utf-8") #include + using namespace HDevEngineCpp; @@ -35,14 +33,14 @@ struct saveImgStruct; // std::string savePath; //保存路径 //}; -//初始化流程(一次):Hd_AI_algo_jixing1,initParas +//初始化流程(一次):Hd_AI_algo_jiXing_T,initParas //运行流程:writeData主线程把数据传过来,run,readData此线程把数据传主线程 -class Hd_AI_algo_jixing1 :public Base +class Hd_AI_algo_jiXing_T :public Base { Q_OBJECT public: - Hd_AI_algo_jixing1(); - virtual ~Hd_AI_algo_jixing1(); + Hd_AI_algo_jiXing_T(); + virtual ~Hd_AI_algo_jiXing_T(); //从类中读数据到实例对象 bool readData(std::vector&,QByteArray&); //实例对象把数据写入到类 @@ -57,8 +55,6 @@ public: bool decodeAiValue(QByteArray byte,QVector &vec_ret); //---------检测流程,根据实际项目修改--------- bool AIdetect(cv::Mat img2D, QString saveKey, QString Dir2D, QString SN, QString DataTime); - - private: HDevEngine myEngine; @@ -107,8 +103,8 @@ private: extern "C" { - Q_DECL_EXPORT Hd_AI_algo_jixing1 * create(); - Q_DECL_EXPORT void destory(Hd_AI_algo_jixing1 * ptr); + Q_DECL_EXPORT Hd_AI_algo_jiXing_T * create(); + Q_DECL_EXPORT void destory(Hd_AI_algo_jiXing_T * ptr); } //保存图片的结构体 struct saveImgStruct diff --git a/BaseModules/Hd_LogicDll_module/CMakeLists.txt b/BaseModules/Hd_LogicDll_module/CMakeLists.txt index b935737..a489980 100644 --- a/BaseModules/Hd_LogicDll_module/CMakeLists.txt +++ b/BaseModules/Hd_LogicDll_module/CMakeLists.txt @@ -37,8 +37,8 @@ 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) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Sql REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql REQUIRED) add_compile_options("$<$:/utf-8>") add_compile_options("$<$:/utf-8>") @@ -59,6 +59,7 @@ target_link_libraries(Hd_LogicDll_module PRIVATE ${qt_target_link} ${opencv_target_link} Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Sql ) diff --git a/BaseModules/Hd_LogicDll_module/Logic_taskthread.cpp b/BaseModules/Hd_LogicDll_module/Logic_taskthread.cpp index 42bed7e..8c3ff8a 100644 --- a/BaseModules/Hd_LogicDll_module/Logic_taskthread.cpp +++ b/BaseModules/Hd_LogicDll_module/Logic_taskthread.cpp @@ -810,14 +810,11 @@ bool Logic_taskthread::deleteSnData ( QByteArray byteArray, QVector& sn // 算法结果 写入plc bool Logic_taskthread::writeAiCommond ( QString cameraName,QString camera_name_index,QByteArray byteArray ) { - std::string str = byteArray.toStdString(); - int start = str.find(resultCmdSplitStart) + std::size(resultCmdSplitStart)-1; - int end = str.find(resultCmdSplitEnd)- start; - if (end > 0 && start > 0) - str = str.substr(start,end); - //char split = *generalSplit; - QByteArrayList PLCvec_ret= QByteArray::fromStdString(str).split(*generalSplit); // 存储结果的 - + QByteArrayList PLCvec_ret= logicUiTransport::decodePlcResult(byteArray); // 存储结果的 + std::map CsvAndChartData = + logicUiTransport::decodeCsvAndChartData(byteArray);//发送导表格或者数据库的 + _CsvWriter.addtData(CsvAndChartData["条码"].toString(), CsvAndChartData);//写入csv文件 + if (PLCvec_ret.isEmpty() ) { qCritical() << __FUNCTION__ << " line:" << __LINE__ << " vec_ret is null!"; diff --git a/BaseModules/Hd_LogicDll_module/Logic_taskthread.h b/BaseModules/Hd_LogicDll_module/Logic_taskthread.h index ba62d63..5e9f8c0 100644 --- a/BaseModules/Hd_LogicDll_module/Logic_taskthread.h +++ b/BaseModules/Hd_LogicDll_module/Logic_taskthread.h @@ -10,7 +10,7 @@ #include #include "struct.h" - +#include #pragma execution_character_set("utf-8") //能够正常显示中文字符串 class Logic_taskthread : public QThread { @@ -81,6 +81,7 @@ public: QString CmdHeadShort = "write_short_"; QString CmdHeadString = "write_string_"; private: + CsvWriter _CsvWriter; QQueue taskImageDataPack; QMutex* task_image_lock = nullptr; int mysaveimagethreadindex = -1; diff --git a/HanddleAI/rlib_writeCsv.cpp b/BaseModules/Hd_LogicDll_module/rlib/rlib_writeCsv.cpp similarity index 96% rename from HanddleAI/rlib_writeCsv.cpp rename to BaseModules/Hd_LogicDll_module/rlib/rlib_writeCsv.cpp index dacebba..4ca4869 100644 --- a/HanddleAI/rlib_writeCsv.cpp +++ b/BaseModules/Hd_LogicDll_module/rlib/rlib_writeCsv.cpp @@ -1,2 +1 @@ #include - diff --git a/BaseModules/Hd_LogicDll_module/rlib/rlib_writeCsv.h b/BaseModules/Hd_LogicDll_module/rlib/rlib_writeCsv.h new file mode 100644 index 0000000..aa774f4 --- /dev/null +++ b/BaseModules/Hd_LogicDll_module/rlib/rlib_writeCsv.h @@ -0,0 +1,518 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +class SQLiteDB { +public: + SQLiteDB(const QString& dbPath, const QString& dbName) : m_dbName(dbName), m_dbPath(dbPath) { connect(); } + ~SQLiteDB() {}; + bool connect() { + // 检查数据库文件是否存在 + if (!QFile::exists(m_dbPath + m_dbName + ".db")) { + QDir().mkpath(m_dbPath); + qDebug() << "Database file does not exist. Creating a new database:" << m_dbName; + } + QCoreApplication::addLibraryPath("./"); + // 添加 SQLite 数据库驱动 + m_db = QSqlDatabase::addDatabase("QSQLITE"); + m_db.setDatabaseName(m_dbPath + m_dbName + ".db"); + + // 打开数据库 + if (!m_db.open()) { + qCritical() << "Failed to open or create database:" << m_db.lastError().text(); + return false; + } + + qDebug() << "Connected to SQLite database:" << m_dbPath + m_dbName; + createTable("setting", + { + {"id","INTEGER PRIMARY KEY AUTOINCREMENT"} , + }); + return true; + } + // 关闭数据库连接 + void disconnect() { + if (m_db. isOpen()) { + m_db.close(); + qDebug() << "Database closed."; + } + } + // 执行无返回值的SQL语句(如插入、删除、更新) + bool execute(const QString& queryStr, const QVariantList& args = {}) { + QSqlQuery query; + query.prepare(queryStr); + + for (int i = 0; i < args.size(); ++i) { + query.bindValue(i, args[i]); + } + + if (!query.exec()) { + qCritical() << "SQL error:" << query.lastError().text(); + qCritical() << "Query:" << queryStr; + return false; + } + return true; + } + // 查询数据,返回结果集 + QList> query(const QString& queryStr, const QVariantList& args = {}) { + QList> results; + QSqlQuery query; + query.prepare(queryStr); + + for (int i = 0; i < args.size(); ++i) { + query.bindValue(i, args[i]); + } + + if (!query.exec()) { + qCritical() << "SQL error:" << query.lastError().text(); + qCritical() << "Query:" << queryStr; + return results; + } + + while (query.next()) { + QMap row; + for (int i = 0; i < query.record().count(); ++i) { + row.insert(query.record().fieldName(i), query.value(i)); + } + results.append(row); + } + + return results; + } + // 检查数据库是否已连接 + bool isConnected() const { + return m_db.isOpen(); + } + ////////////////BASE////////////////////// + bool createTable(const QString& tableName, const QList>& columns) { + if (columns.empty()) { + qDebug() << "Create table failed: columns are empty."; + return false; + } + + QStringList columnDefinitions; + for (const auto& pair : columns) { + columnDefinitions << QString("%1 %2").arg(pair.first).arg(pair.second); + } + + // 确保表名被双引号包围,处理特殊字符的表名 + QString sql = QString("CREATE TABLE IF NOT EXISTS \"%1\" (%2)") + .arg(tableName) + .arg(columnDefinitions.join(", ")); + + return execute(sql); + } + + bool dropTable(const QString& tableName) { + QString sql = QString("DROP TABLE IF EXISTS %1").arg(tableName); + return execute(sql); + } + bool tableExists(const QString& tableName) { + // 使用 sqlite_master 查询表是否存在 + QString sql = QString("SELECT name FROM sqlite_master WHERE type='table' AND name='%1';").arg(tableName); + + QList> result = query(sql); + return !result.isEmpty(); // 如果结果不为空,则表示表存在 + } + + bool _insert(const QString& tableName, + const std::map& data) { + // 如果数据为空,返回 false + if (data.empty()) { + qDebug() << "Insert failed: data is empty."; + return false; + } + + // 如果表名为空,返回 false + if (tableName.isEmpty()) { + qDebug() << "Insert failed: tableName is empty."; + return false; + } + + QStringList columns, values; + for (const auto& pair : data) { + columns << pair.first; + // 直接插入数据(明文传输),需要确保数据已经适当转义 + values << "'" + pair.second.toString().replace("'", "''") + "'"; // 处理引号 + } + + // 构造 SQL 查询语句(不使用绑定参数) + QString sql = QString("INSERT INTO \"%1\" (%2) VALUES (%3)") + .arg(tableName) // 使用双引号包围表名,确保兼容特殊字符 + .arg(columns.join(", ")) + .arg(values.join(", ")); + + qDebug() << "Generated SQL: " << sql; + + QSqlQuery query(m_db); + + // 检查数据库连接 + if (!m_db.isOpen()) { + qDebug() << "Database is not open!"; + return false; + } + + // 执行查询并检查错误 + if (!query.exec(sql)) { + qDebug() << "Insert failed:" << query.lastError().text(); + return false; + } + + return true; + } + + bool _update(const QString& tableName, + const std::map& data, + const std::map& conditions) { + if (data.empty() || conditions.empty()) { + qDebug() << "Update failed: data or conditions are empty."; + return false; + } + + QStringList setClauses; + for (const auto& pair : data) { + QString value = pair.second.toString().replace("'", "''"); // 防止单引号注入 + setClauses << QString("%1 = '%2'").arg(pair.first).arg(value); + } + + QStringList whereClauses; + for (const auto& pair : conditions) { + QString conditionValue = pair.second.toString().replace("'", "''"); + whereClauses << QString("%1 = '%2'").arg(pair.first).arg(conditionValue); + } + + // 构造 SQL 查询语句(不使用绑定参数) + QString sql = QString("UPDATE \"%1\" SET %2 WHERE %3") + .arg(tableName) + .arg(setClauses.join(", ")) + .arg(whereClauses.join(" AND ")); + + qDebug() << "Generated SQL: " << sql; + + QSqlQuery query(m_db); + + // 检查数据库连接 + if (!m_db.isOpen()) { + qDebug() << "Database is not open!"; + return false; + } + + // 执行查询并检查错误 + if (!query.exec(sql)) { + qDebug() << "Update failed:" << query.lastError().text(); + return false; + } + + return true; + } + + + bool _delete(const QString& tableName, + const std::map& conditions) { + if (conditions.empty()) { + qDebug() << "Delete failed: conditions are empty."; + return false; + } + + QStringList whereClauses; + for (const auto& pair : conditions) { + whereClauses << QString("%1 = :%2").arg(pair.first).arg(pair.first + "_condition"); + } + + QString sql = QString("DELETE FROM \"%1\" WHERE %2") + .arg(tableName) + .arg(whereClauses.join(" AND ")); + + QSqlQuery query(m_db); + query.prepare(sql); + + // 绑定条件参数 + for (const auto& pair : conditions) { + query.bindValue(":" + pair.first + "_condition", QVariant::fromValue(pair.second)); + } + + if (!query.exec()) { + qDebug() << "Delete failed:" << query.lastError().text(); + return false; + } + + return true; + } + + std::vector> _search(const QString& tableName, + const QStringList& columns, + const std::map& conditions = {}) { + // 如果没有指定列名,则选择所有列 + QStringList selectColumns = columns.isEmpty() ? QStringList("*") : columns; + + // 构建基本的 SQL 查询 + QString sql = QString("SELECT %1 FROM \"%2\"").arg(selectColumns.join(", "), tableName); + + if (!conditions.empty()) { + QStringList whereClauses; + for (const auto& pair : conditions) { + // 直接拼接条件,确保值已经处理好以防 SQL 注入 + QString value = pair.second.toString().replace("'", "''"); // 防止单引号注入 + whereClauses << QString("%1 = '%2'").arg(pair.first).arg(value); + } + sql += " WHERE " + whereClauses.join(" AND "); + } + + qDebug() << "Generated SQL: " << sql; + + QSqlQuery query(m_db); + + // 检查数据库连接 + if (!m_db.isOpen()) { + qDebug() << "Database is not open!"; + return {}; + } + + // 执行查询并检查错误 + if (!query.exec(sql)) { + qDebug() << "Search failed:" << query.lastError().text(); + return {}; + } + + std::vector> results; + while (query.next()) { + std::map row; + for (int i = 0; i < query.record().count(); ++i) { + row[query.record().fieldName(i)] = query.value(i); + } + results.push_back(row); + } + + return results; + } + + ///////////////////EX//FUNC///////////////// + bool exportTableToCSV(const QString& tableName, const QString& filePath, std::mutex& _mutex) { + using namespace std::chrono; // 便于使用 chrono 相关功能 + // 记录开始时间 + auto start = high_resolution_clock::now(); + // 查询表中的所有数据 + std::lock_guard locker(_mutex); + QString csvFileName = filePath + "/" + tableName + ".csv"; + QString sql = QString("SELECT * FROM \"%1\"").arg(tableName); + QSqlQuery query(m_db); + + if (!query.exec(sql)) { + qCritical() << "Query execution failed: " << query.lastError().text(); + return false; + } + + // 如果查询没有返回数据,返回 false + if (!query.next()) { + qDebug() << "No data found in table" << tableName; + return false; + } + + // 打开文件进行写入 + QFile file(csvFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qCritical() << "Failed to open file" << csvFileName; + return false; + } + + QTextStream out(&file); + + // 获取列名顺序 + QSqlRecord record = query.record(); + QStringList columns; + for (int i = 0; i < record.count(); ++i) { + columns << record.fieldName(i); // 保证列名按查询结果顺序提取 + } + + // 写入表头(列名) + out << columns.join(",") << "\n"; // 表头以逗号分隔 + + // 写入数据行 + do { + QStringList values; + for (const auto& column : columns) { + values << query.value(column).toString(); // 获取每列的值,保持列名顺序 + } + out << values.join(",") << "\n"; // 每行数据以逗号分隔 + } while (query.next()); // 循环处理所有数据行 + + file.close(); // 关闭文件 + // 记录结束时间 + auto end = high_resolution_clock::now(); + + // 计算耗时 + auto duration = duration_cast(end - start); + qDebug() << csvFileName << "EXPORT CSV COST: " << duration.count() << "ms"; + return true; + } + + +private: + QString m_dbName; + QString m_dbPath; + QSqlDatabase m_db; +}; + +class CsvWriter : public QThread +{ +public: + CsvWriter(): + _db("./sqlDatabse/", "database") + { + init(); + startAutoExport(60000); + } + void addtData(const QString& snCode ,const std::map& data) { + std::lock_guard locker(_mutex); + auto res = _db._search(getCurrentProcessCsvName(), {}, {{"条码",snCode}}); + if (res.empty() == true)//当前数据为空时查询过去的数据是否为空 + { + auto lastRes = _db._search(getLastProcessCsvName(), {}, { {"条码",snCode} }); + if (lastRes.empty() == true)//过去的数据也为空 则视作现在要插入的数据为全新的数据 + { + std::map insertData = data; + insertData["条码"] = snCode; + insertData["创建时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); + insertData["修改时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); + _db._insert(getCurrentProcessCsvName(), insertData); + } + else//过去的数据不为空 更新到过去的数据上 + { + std::map updateData = data; + updateData["修改时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); + _db._update(getLastProcessCsvName(), updateData, { {"条码",snCode} }); + } + + } + else//当前数据不为空 更新到当前数据上 + { + std::map updateData = data; + updateData["修改时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); + _db._update(getCurrentProcessCsvName(), updateData, { {"条码",snCode} }); + } + } +private: + void run() + { + while (m_running) + { + QThread::msleep(m_intervalMs); + exportCsv(); + } + } + std::mutex _mutex; + SQLiteDB _db; + int m_intervalMs = 60000; + bool m_running = true; + QList> db_InitColumns = { + {"条码", "TEXT NOT NULL PRIMARY KEY"}, + {"创建时间", "TEXT"}, + {"修改时间", "TEXT"}, + { "极性检测结果","TEXT" } + }; + QTimer* timer; + void init() + { + std::lock_guard locker(_mutex); + if (_db.createTable(getLastProcessCsvName(), db_InitColumns)) { + qDebug() << "Table 'users' created successfully."; + } + else { + qDebug() << "Failed to create table 'users'."; + } + if (_db.createTable(getCurrentProcessCsvName(), db_InitColumns)) { + qDebug() << "Table 'users' created successfully."; + } + else { + qDebug() << "Failed to create table 'users'."; + } + } + QString getCurrentProcessCsvName(){ + // 获取当前时间 + QDateTime currentDateTime = QDateTime::currentDateTime(); + + // 获取当前小时和分钟 + int hour = currentDateTime.time().hour(); + int minute = currentDateTime.time().minute(); + + // 判断是否在白班时间范围(8:30到20:30) + bool isDayShift = (hour > 8 || (hour == 8 && minute >= 30)) && (hour < 20 || (hour == 20 && minute <= 30)); + + // 获取当前日期(yyyy-MM-dd格式) + QString dateStr = currentDateTime.toString("yyyy-MM-dd"); + + // 根据时间段返回班次信息 + if (isDayShift) { + return (dateStr + "白班"); + } + else { + return (dateStr + "夜班"); + } + } + QString getLastProcessCsvName(){ + // 获取当前时间 + QDateTime currentDateTime = QDateTime::currentDateTime(); + + // 获取当前小时和分钟 + int hour = currentDateTime.time().hour(); + int minute = currentDateTime.time().minute(); + + // 判断是否在白班时间范围(8:30到20:30) + bool isDayShift = (hour > 8 || (hour == 8 && minute >= 30)) && (hour < 20 || (hour == 20 && minute <= 30)); + + // 获取上一班的日期 + QDateTime lastShiftDateTime; + if (isDayShift) { + // 当前是白班,上一班是前一天的夜班 + lastShiftDateTime = currentDateTime.addDays(-1); + } + else { + // 当前是夜班,上一班是前一天的白班 + lastShiftDateTime = currentDateTime.addDays(-1); + } + + // 获取上一班的日期(yyyy-MM-dd格式) + QString dateStr = lastShiftDateTime.toString("yyyy-MM-dd"); + + // 根据时间段返回班次信息 + if (isDayShift) { + return (dateStr + "夜班"); // 上一班是夜班 + } + else { + return (dateStr + "白班"); // 上一班是白班 + } + } + void startAutoExport(int intervalMs = 60000) { + m_intervalMs = intervalMs; + m_running = true; + this->start(); + } + void stopAutoExport() { + m_running = false; + this->wait(); + } + void exportCsv() + { + _db.exportTableToCSV(getLastProcessCsvName(), "./csv/", _mutex); + _db.exportTableToCSV(getCurrentProcessCsvName(), "./csv/", _mutex); + } +}; + +#pragma once \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b14a71..829e9b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,7 +213,7 @@ if(ON) set(Qt5_DIR ${PROJECT_ROOT_PATH}/env/qt5/lib/cmake/Qt5) set(QT_DIR ${Qt5_DIR}) - set(qtlist "Core" "Widgets" "Network" "Gui" "PrintSupport" "Concurrent" "Charts") + set(qtlist "Core" "Widgets" "Network" "Gui" "PrintSupport" "Concurrent" "Charts" "Sql") find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) message("QT_Version :" Qt${QT_VERSION_MAJOR}) diff --git a/HanddleAI/Qt_epWindow.cpp b/HanddleAI/Qt_epWindow.cpp index bc64eea..1c8561b 100644 --- a/HanddleAI/Qt_epWindow.cpp +++ b/HanddleAI/Qt_epWindow.cpp @@ -1,6 +1,5 @@ #include "Qt_epWindow.h" #include "qapplication.h" -#include #include #pragma execution_character_set("utf-8") diff --git a/HanddleAI/Qt_epWindow.h b/HanddleAI/Qt_epWindow.h index 559f8dc..34a7869 100644 --- a/HanddleAI/Qt_epWindow.h +++ b/HanddleAI/Qt_epWindow.h @@ -34,7 +34,6 @@ #include "QtSaveImgSet.h" //缺陷名称设置 #include "QtDefectSet.h" - #pragma execution_character_set("utf-8") //struct LogListStruct diff --git a/HanddleAI/rlib_writeCsv.h b/HanddleAI/rlib_writeCsv.h deleted file mode 100644 index 8f39b68..0000000 --- a/HanddleAI/rlib_writeCsv.h +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -class CsvWriter -{ -public: - CsvWriter() - { - init(); - } - - //输入 键 和 数值的键值对,键默认为条码 - void WriteToCsv(QString key,std::vector> strList) - { - //查询条码是否存在 - std::lock_guard locker(_mutex); - QTextStream currentCsvStream(currentCsvFile.get()); - auto it = currentKeys->find(key); - if (it != currentKeys->end()) { - QList lines; - while (!currentCsvStream.atEnd()) { - lines.append(currentCsvStream.readLine()); - } - //lines[it->second] - } - /*QByteArray qstr; - for (int cnt = 0; cnt < strList.size() - 1; cnt++) - qstr.append(QByteArray::fromStdString(strList[cnt]) + ","); - qstr.append(QByteArray::fromStdString(strList[strList.size() - 1]) + CRLF);*/ - } - void switchCsvFile(std::string path) - { - //创建文件并检查是否存在 - - } - void timeCheck() - { - - } - - -private: - std::mutex _mutex; - std::shared_ptr lastCsvFile; - std::shared_ptr currentCsvFile; - const char* CRLF = "\r\n"; - QByteArray csvHeaderStr = ""; - - std::unordered_map headers; - const char* keyName = "条码"; - std::unordered_map* lastKeys; - std::unordered_map* currentKeys; - void init() - { - std::lock_guard locker(_mutex); - addHeader("条码"); - addHeader("创建时间"); - addHeader("修改时间"); - { - lastCsvFile = openCsvFile(getLastProcessCsv()); - QTextStream lastCsvStream(lastCsvFile.get()); - while (!lastCsvStream.atEnd()) { - auto line = lastCsvStream.readLine(); - auto lineSplit = line.split(","); - if (lineSplit.size() > 0){ - lastKeys->insert({ lineSplit[0],lastKeys->size() + 1 }); - } - } - } - { - currentCsvFile = openCsvFile(getCurrentProcessCsv()); - QTextStream currentCsvStream(currentCsvFile.get()); - while (!currentCsvStream.atEnd()) { - auto line = currentCsvStream.readLine(); - auto lineSplit = line.split(","); - if (lineSplit.size() > 0) { - currentKeys->insert({ lineSplit[0],currentKeys->size() + 1 }); - } - } - } - } - void addHeader(QString header) { - headers.insert(std::make_pair(header, headers.size())); - if (csvHeaderStr == "") - csvHeaderStr.append(header); - else - csvHeaderStr.append(header + ","); - } - std::string getCurrentProcessCsv(){ - // 获取当前时间 - QDateTime currentDateTime = QDateTime::currentDateTime(); - - // 获取当前小时和分钟 - int hour = currentDateTime.time().hour(); - int minute = currentDateTime.time().minute(); - - // 判断是否在白班时间范围(8:30到20:30) - bool isDayShift = (hour > 8 || (hour == 8 && minute >= 30)) && (hour < 20 || (hour == 20 && minute <= 30)); - - // 获取当前日期(yyyy-MM-dd格式) - QString dateStr = currentDateTime.toString("yyyy-MM-dd"); - - // 根据时间段返回班次信息 - if (isDayShift) { - return (dateStr + "白班").toStdString(); - } - else { - return (dateStr + "夜班").toStdString(); - } - } - std::string getLastProcessCsv(){ - // 获取当前时间 - QDateTime currentDateTime = QDateTime::currentDateTime(); - - // 获取当前小时和分钟 - int hour = currentDateTime.time().hour(); - int minute = currentDateTime.time().minute(); - - // 判断是否在白班时间范围(8:30到20:30) - bool isDayShift = (hour > 8 || (hour == 8 && minute >= 30)) && (hour < 20 || (hour == 20 && minute <= 30)); - - // 获取上一班的日期 - QDateTime lastShiftDateTime; - if (isDayShift) { - // 当前是白班,上一班是前一天的夜班 - lastShiftDateTime = currentDateTime.addDays(-1); - } - else { - // 当前是夜班,上一班是前一天的白班 - lastShiftDateTime = currentDateTime.addDays(-1); - } - - // 获取上一班的日期(yyyy-MM-dd格式) - QString dateStr = lastShiftDateTime.toString("yyyy-MM-dd"); - - // 根据时间段返回班次信息 - if (isDayShift) { - return (dateStr + "夜班").toStdString(); // 上一班是夜班 - } - else { - return (dateStr + "白班").toStdString(); // 上一班是白班 - } - } - std::shared_ptropenCsvFile(std::string path){ - std::shared_ptr CsvFile = std::make_shared(QString::fromStdString(path)); - bool FileExist = CsvFile->exists(); - CsvFile->open(QIODevice::ReadWrite); - if (FileExist == false) - CsvFile->write(csvHeaderStr); - } -}; diff --git a/env/myTools/include/global.h b/env/myTools/include/global.h index 4bcd134..4cb3f8d 100644 --- a/env/myTools/include/global.h +++ b/env/myTools/include/global.h @@ -7,4 +7,100 @@ #define csvSplitStart "[csvSplitStart]" #define csvSplitEnd "[csvSplitEnd]" #define generalSplit "|" -//SAMPLE \ No newline at end of file +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char* packSplit = "|"; // Separator between fields +const char* resultSplitStart = "[resultCmdSplitStart]"; // PLC result start delimiter +const char* resultSplitEnd = "[resultCmdSplitEnd]"; // PLC result end delimiter +const char* csvChartSplitStart = "[csvChartCmdSplitStart]"; // CSV and chart data start delimiter +const char* csvChartSplitEnd = "[csvChartCmdSplitEnd]"; // CSV and chart data end delimiter +namespace logicUiTransport +{ + QByteArray encodeAllData(QString SN,QList plcResult, std::map csvAndChartData) + { + QByteArray encodedData; + + // Encode plcResult list + encodedData.append(resultSplitStart); + for (const auto& item : plcResult) + { + encodedData.append(item.toUtf8() + packSplit); + } + encodedData.append(resultSplitEnd); + + // Encode csvAndChartData map + encodedData.append(csvChartSplitStart); + encodedData.append(QString("条码") + packSplit); + encodedData.append(SN + packSplit); + for (const auto& pair : csvAndChartData) + { + encodedData.append(pair.first.toUtf8() + packSplit); + encodedData.append(pair.second.toString().toUtf8() + packSplit); + } + encodedData.append(csvChartSplitEnd); + + return encodedData; + } + + QByteArrayList decodePlcResult(QByteArray& input) + { + QByteArrayList plcResultList; + + // Find the data between resultSplitStart and resultSplitEnd + int startIndex = input.indexOf(resultSplitStart) + strlen(resultSplitStart); + int endIndex = input.indexOf(resultSplitEnd); + + if (startIndex >= 0 && endIndex >= 0 && endIndex > startIndex) + { + QByteArray plcData = input.mid(startIndex, endIndex - startIndex); + QStringList plcList = QString(plcData).split(packSplit, Qt::SkipEmptyParts); + + // Convert each QString to QByteArray and add to the list + for (const QString& str : plcList) + { + plcResultList.append(str.toUtf8()); + } + } + + return plcResultList; + } + + std::map decodeCsvAndChartData(QByteArray& input) + { + std::map csvAndChartData; + + // Find the data between csvChartSplitStart and csvChartSplitEnd + int startIndex = input.indexOf(csvChartSplitStart) + strlen(csvChartSplitStart); + int endIndex = input.indexOf(csvChartSplitEnd); + + if (startIndex >= 0 && endIndex >= 0 && endIndex > startIndex) + { + QByteArray csvData = input.mid(startIndex, endIndex - startIndex); + QStringList csvList = QString(csvData).split(packSplit, Qt::SkipEmptyParts); + + // Decode key-value pairs + for (int i = 0; i < csvList.size(); i += 2) + { + if (i + 1 < csvList.size()) + { + csvAndChartData[csvList[i]] = QVariant(csvList[i + 1]); + } + } + } + + return csvAndChartData; + } + + +}; + +#pragma once