#include "Hd_AI_2D3Ddata_module.h" #include #include #include #pragma execution_character_set("utf-8") using namespace cv; using namespace std; //原图保存文件夹 static QString oriImgSaveDir = "F:/ORI/"; //原图class图保存文件夹 static QString classImgSaveDir = "F:/ORIclass/"; //结果保存文件夹 static QString resImgSaveDir = "F:/res/"; //切图的class的width,根据项目实际设置! static int sizeW = 150; //切图的class的height,根据项目实际设置! static int sizeH = 150; //切图的class的width,根据项目实际设置!0为黑,255为白; static int fillColour = 0; //检测线程锁 static QMutex* detect_mutex; //保存线程锁 static QMutex* saveStruct_mutex; //检测线程运行标志 static bool ifdetectThread = false; // 缺陷信息结构体 typedef struct { QString defectName = "";//缺陷名称 cv::Rect defectRect = { 0,0,0,0 };//缺陷位置 cv::Scalar defectScalar = cv::Scalar(0, 0, 0);//画框颜色 double defectArea = 0;//缺陷真实面积 double defectDepth = 0;//缺陷深度/高度,3D信息 }defectInfo; //判断文件是否存在,不存在则创建 bool isFileExist(QString fullFileName) { QFileInfo fileInfo(fullFileName); if (fileInfo.isFile()) { return true; } return false; } void GetStringSize(HDC hdc, const char* str, int* w, int* h) { SIZE size; GetTextExtentPoint32A(hdc, str, strlen(str), &size); if (w != 0) *w = size.cx; 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) { CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3)); int x, y, r, b; //坐标点大于图像宽和高直接返回 if (org.x > dst.cols || org.y > dst.rows) return; x = org.x < 0 ? -org.x : 0; y = org.y < 0 ? -org.y : 0; LOGFONTA lf; lf.lfHeight = -fontsize; //字体高度 lf.lfWidth = 0; //平均宽度 lf.lfEscapement = 0; //字符排列角度 lf.lfOrientation = 0; //字符本身旋转的角度 lf.lfWeight = 5; //设置字体线条的宽度 lf.lfItalic = italic; //斜体 lf.lfUnderline = underline; //下划线 lf.lfStrikeOut = 0; //是否字符中央加横线 lf.lfCharSet = DEFAULT_CHARSET; //字符集 lf.lfOutPrecision = 0; //字体的精确度 lf.lfQuality = PROOF_QUALITY; //字体质量 lf.lfPitchAndFamily = 0; //选择字体的间距和字体家族 strcpy_s(lf.lfFaceName, fn); //字体的名称 HFONT hf = CreateFontIndirectA(&lf); HDC hdc = CreateCompatibleDC(0); HFONT holdfont = (HFONT)SelectObject(hdc, hf); int strBaseW = 0, strBaseH = 0; int singleRow = 0; char buf[1 << 12]; strcpy_s(buf, str); char* bufT[1 << 12]; //这个用于分隔字符串后剩余的字符,可能会超出。 //处理多行 { int nnh = 0; int cw, ch; const char* ln = strtok_s(buf, "\n", bufT); while (ln != 0) { GetStringSize(hdc, ln, &cw, &ch); strBaseW = max(strBaseW, cw); strBaseH = max(strBaseH, ch); ln = strtok_s(0, "\n", bufT); nnh++; } singleRow = strBaseH; strBaseH *= nnh; } if (org.x + strBaseW < 0 || org.y + strBaseH < 0) { SelectObject(hdc, holdfont); DeleteObject(hf); DeleteObject(hdc); return; } r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1; b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1; org.x = org.x < 0 ? 0 : org.x; org.y = org.y < 0 ? 0 : org.y; BITMAPINFO bmp = { 0 }; BITMAPINFOHEADER& bih = bmp.bmiHeader; int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4)); bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = strBaseW; bih.biHeight = strBaseH; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = BI_RGB; bih.biSizeImage = strBaseH * strDrawLineStep; bih.biClrUsed = 0; bih.biClrImportant = 0; void* pDibData = 0; HBITMAP hBmp = CreateDIBSection(hdc, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0); CV_Assert(pDibData != 0); HBITMAP hOldBmp = (HBITMAP)SelectObject(hdc, hBmp); //color.val[2], color.val[1], color.val[0] SetTextColor(hdc, RGB(255, 255, 255)); SetBkColor(hdc, 0); //SetStretchBltMode(hDC, COLORONCOLOR); strcpy_s(buf, str); const char* ln = strtok_s(buf, "\n", bufT); int outTextY = 0; while (ln != 0) { TextOutA(hdc, 0, outTextY, ln, strlen(ln)); outTextY += singleRow; ln = strtok_s(0, "\n", bufT); } uchar* dstData = (uchar*)dst.data; int dstStep = dst.step / sizeof(dstData[0]); unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep; unsigned char* pStr = (unsigned char*)pDibData + x * 3; for (int tty = y; tty <= b; ++tty) { unsigned char* subImg = pImg + (tty - y) * dstStep; unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep; for (int ttx = x; ttx <= r; ++ttx) { for (int n = 0; n < dst.channels(); ++n) { double vtxt = subStr[n] / 255.0; int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n]; subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv); } subStr += 3; subImg += dst.channels(); } } SelectObject(hdc, hOldBmp); SelectObject(hdc, holdfont); DeleteObject(hf); DeleteObject(hBmp); DeleteDC(hdc); } void drawDefects(cv::Mat& sourceMat, QQueue defectInfoList) { for (int i = 0; i < defectInfoList.size(); i++) { defectInfo mdefect = defectInfoList[i]; cv::rectangle(sourceMat, cv::Point(mdefect.defectRect.x, mdefect.defectRect.y), cv::Point(mdefect.defectRect.x + mdefect.defectRect.width, mdefect.defectRect.y + mdefect.defectRect.height), mdefect.defectScalar, 3, 8); QByteArray path_arr = mdefect.defectName.toLocal8Bit(); const char* path = path_arr.data(); putTextZH(sourceMat, path, cv::Point(mdefect.defectRect.x, mdefect.defectRect.y - 50), mdefect.defectScalar, 50, "微软雅黑"); } } //判断文件夹是否存在,不存在则创建 void Hd_AI_2D3Ddata_module::isDirExist(QString fullDirName) { QDir* photo = new QDir; bool exist = photo->exists(fullDirName); if (exist) { //qDebug() << fullDirName << "::已存在"; } else { //创建photo文件夹 //qDebug() << fullDirName << "::不存在,创建"; photo->mkdir(fullDirName); } delete photo; photo = nullptr; } Hd_AI_2D3Ddata_module* create() { qDebug() << "[INFO] " << " Hd_AI_2D3Ddata_module create success!" ; return new Hd_AI_2D3Ddata_module; } void destory(Hd_AI_2D3Ddata_module* ptr) { qDebug() << "[INFO] " << "Hd_AI_2D3Ddata_module destory success!"; if(ptr) { delete ptr; ptr = nullptr; } } Hd_AI_2D3Ddata_module::Hd_AI_2D3Ddata_module() { detect_mutex = new QMutex; saveStruct_mutex = new QMutex; ifdetectThread = false; } Hd_AI_2D3Ddata_module::~Hd_AI_2D3Ddata_module() { ifdetectThread = false; Sleep(10); if (detect_mutex) { delete detect_mutex; detect_mutex = nullptr; } if (saveStruct_mutex) { delete saveStruct_mutex; saveStruct_mutex = nullptr; } /*DestroySegObj(pSeg); DestroyClsObj(pCls);*/ } QByteArray m_writeData; static int defectNums = 0; //static cv::Mat resMat; //从类中读数据到实例对象 bool Hd_AI_2D3Ddata_module::readData(std::vector&vec_mat,QByteArray &data) { detect_mutex->lock(); //qDebug() << __FUNCTION__ << " line:" <<__LINE__ << " data len:" << data.length(); if (resMat.size()>0) { vec_mat.push_back(resMat[0]); resMat.clear(); } else { if(HikMat.size()) vec_mat.push_back(HikMat[0]); //qDebug() << __FUNCTION__ << " line:" << __LINE__ << " resMat.data err:"; } //if (allNum++ % 21 == 20) // data = "2";// resByte.dequeue(); //else //if (allNum++ % 2 == 0) // data = "0*2*3*2";// resByte.dequeue(); //else data = "1";// "0*1*2*3";//1OK,2NG resByte.clear(); ////之后根据结果类修改 //if(resIfNg == true) // data = "NG"; //else data = "OK"; detect_mutex->unlock(); return true; } //从类中读数据到实例对象 bool Hd_AI_2D3Ddata_module::encodeResultValue(QVector append_value,QByteArray &resultByte) { try { std::string sendMsg; 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 ); 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 ); sendMsg.append(m_len); //data x sendMsg.append(value); } resultByte = QByteArray::fromStdString(sendMsg); } catch (QString ev) { qCritical() << "[Error] " << " ev:" << ev; return false; } return true; } //接收数据 bool Hd_AI_2D3Ddata_module::writeData(std::vector& vec_mat, QByteArray &data) { m_writeData = data; //qDebug() << __FUNCTION__ << "line:"<< __LINE__ << " data len" << data.length() ; if(vec_mat.empty()) { qCritical() << "[Error] " << " vec_mat is null !"; return false; } detect_mutex->lock(); HikMat.clear(); HikMat.enqueue(vec_mat[0]); //测试相机的, //while (HikMat[0].cols > 2000)cv::resize(HikMat[0], HikMat[0], cv::Size(), 0.1, 0.1); //or检测:保存路径,拍照面描述,相机key_第几张图,SN_时间戳 //and检测:保存路径,拍照面描述,相机key_第几张图,相机key_第几张图,SN_时间戳,SN_时间戳 //汇总:保存路径,拍照面描述,触发信号_序号列表0,SN_时间戳 QString qstring_data = data; QStringList datalist = qstring_data.split(','); /*saveKey.enqueue("datalist[0]"); Dir2D.enqueue("datalist[1]"); QStringList SN_dataTime; SN_dataTime = datalist[3].split('_'); DateTime1 = "SN_dataTime[1]"; SN.enqueue("SN_dataTime[0]");*/ //qCritical() << __FUNCTION__ << " line: " << __LINE__ << " data:" << qstring_data; detect_mutex->unlock(); //cv::Mat resultDstImg = vec_mat[0].clone();// = pSeg->Evaluate(sourceImg); //返回单通道二值图 图片错误输出Image Error!但不报错。。 //resultDstImg = pSeg->Evaluate(resultDstImg); //resultDstImg.release(); return true; } //初始化 bool Hd_AI_2D3Ddata_module::initParas(QByteArray& byte) { //if(byte.isEmpty()) //{ // qCritical() << "[Error] " << " byte is null!"; // return false; //} //QVector vec_ret; //decodeAiValue(byte,vec_ret); //if(vec_ret.isEmpty()) //{ // qCritical() << "[Error] " << " vec_ret is null!"; // return false; //} ///*pSeg = CreateSegObjS(pSeg_modulePath, 128, gpuId); //pCls = CreateClsObjV3(pCls_modulePath, gpuId, 1);*/ //StationNo = vec_ret.at(0).toInt(); ////InitThreads(StationNo, img2D); ////InitModels(StationNo, img2D); ////运行检测线程 //ifdetectThread = true; ////线程检测:结果类完成时,使用 ////ifThreadRunDetect = true; ////QFuture future1 = QtConcurrent::run(this, &Hd_AI_2D3Ddata_module::detectThread); ////运行存图线程 //QFuture future2 = QtConcurrent::run(this, &Hd_AI_2D3Ddata_module::saveImgThread); ////detectThread(); ////原图总文件夹 //isDirExist(oriImgSaveDir); ////原图class总文件夹 //isDirExist(classImgSaveDir); ////结果图总文件夹 //isDirExist(resImgSaveDir); wstring taskPath = L"task\\haiwai_demo_model1\\haiwai_demo_model1.task"; wcout.imbue(locale("zh_CN")); //bool ret = instance(taskPath, 0); //if (!ret) //{ // //销毁实例 // destroyInstance(); // cout << "run task false\n"; // return false; //} //vector srcMats; //vector results; ////传入图片vector 和 接收结果的容器 //ret = PBTASK_EXPORT::run(srcMats, results);//初始化一下AI模型 //qDebug() << "[INFO] " << " StationNo:" << StationNo << " img2D:" << img2D ; return true; } // 解码 bool Hd_AI_2D3Ddata_module::decodeAiValue(QByteArray byte,QVector &vec_ret) { 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); qDebug() << "[INFO] " << " paramNum:" << paramNum; 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); int len = 0; 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); vec_ret.append(mm_data); byte.remove(0,len); } return true; } //---------检测流程,根据实际项目修改--------- bool Hd_AI_2D3Ddata_module::AIdetect(cv::Mat img2D, QString mysaveKey, QString myDir2D, QString mySN, QString myDataTime) { try { //存图数据加保存队列,加锁,避免数据访问冲突 saveStruct_mutex->lock(); saveImgStruct mySave; Mat sourceImg; sourceImg = img2D.clone(); //img2D.copyTo(sourceImg); //img2D.release(); QString mysaveKey1 = mysaveKey; //"offlineStation1_off_1" saveStruct_mutex->unlock(); QJsonDocument document; QJsonObject obj; obj.insert("result_key", "mysaveKey"); obj.insert("SN", "mySN"); obj.insert("DataTime", "myDataTime"); //QFile csvName("test.csv"); //QStringList lines; //lines << "class,name\n" << "3,4,5,6,7\n" << "a,b,c,d\n"; //if (csvName.open(QIODevice::WriteOnly)) //若文件不存在,会自动创建 //{ // for (int i = 0; i < lines.size(); i++) // csvName.write(lines[i].toStdString().c_str()); // csvName.close(); //} QQueue defectInfoList; //seg后class检测逻辑 /*if (0) { Mat sourceRectangles;// 在原图缺陷位置,边界矩形框出 sourceRectangles = sourceImg.clone(); //sourceImg.copyTo(sourceRectangles); vector> contours; //seg检测 Mat resultDstImg;// = sourceImg.clone();// = pSeg->Evaluate(sourceImg); //返回单通道二值图 图片错误输出Image Error!但不报错。。 resultDstImg = pSeg->Evaluate(sourceImg); //int resultClass = pCls->Evaluate(sourceImg); //类别id //opencv对二值图进行处理 //GaussianBlur(resultDstImg, resultDstImg, Size(3, 3), 1); //缺陷过滤值较大时,可以减少检出数;缺陷较小时,漏检较多 threshold(resultDstImg, resultDstImg, pSeg->m_classes, 255, THRESH_BINARY_INV);//大于部分设为0,小于部分设为255 //findContours(resultDstImg, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); //不识别内部轮廓,有些情况抓到的图像外框? findContours(resultDstImg, contours, cv::noArray(), cv::RETR_TREE, cv::CHAIN_APPROX_NONE); //需要内部轮廓的写法 if (contours.size() == 0) { //printf("Notlabeled\n"); } else { for (int j = 0; j < contours.size(); j++) { Rect rect1 = boundingRect(Mat(contours[j])); //最小缺陷过滤参数,根据项目实际设置! int filterNum = 10; float w = rect1.width * 1.0; float h = rect1.height * 1.0; if ((w / sourceImg.cols > 0.98) || (h / sourceImg.rows > 0.98)) { //抓到图像外框了 //qDebug() << "NG is too big..."; continue; } //且逻辑,有的项目需要或逻辑!! if ((w > filterNum && h > filterNum))//||rect1.area> filterNum*filterNum*1.5) { //class检测mat Mat imgCls; //此段为切图逻辑为: //缺陷外扩5像素; //判断最大边,大于class建网大小的,按照最大边尺寸比例切大图,然后resize为建网大小;最大边小于等于建网大小的,按照建网大小切图; //越界填充 { int startX = rect1.x - 5; int startY = rect1.y - 5; int endX = rect1.x + rect1.width + 5; int endY = rect1.y + rect1.height + 5; //尺寸比例 double maxscaler, scalerX, scalerY; maxscaler = 1.0; scalerX = (endX - startX) * 1.0 / sizeW;//*1.0转为float,避免被取整了 scalerY = (endY - startY) * 1.0 / sizeH; maxscaler = max(maxscaler, max(scalerX, scalerY)); int avgX = (rect1.x + rect1.x + rect1.width) / 2; //中点X位置 int avgY = (rect1.y + rect1.y + rect1.height) / 2;//中点Y位置 startX = avgX - int(maxscaler * sizeW / 2);//强转为int endX = startX + int(maxscaler * sizeW); startY = avgY - int(maxscaler * sizeH / 2); endY = startY + int(maxscaler * sizeH); //判断是否越界,越界要填充的像素个数 int copyTop = max(0, 0 - startY); int copyButton = max(0, endY - sourceImg.rows); int copyLeft = max(0, 0 - startX); int copyRight = max(0, endX - sourceImg.cols); //切图不要越界,会崩溃 Mat imgCut = sourceImg(Range(max(0, startY - copyTop), min(sourceImg.rows, endY - copyButton)), Range(max(0, startX - copyLeft), min(sourceImg.cols, endX - copyRight))); //起始行,终止行;起始列,终止列 //图像扩充 if (sourceImg.channels() == 1) { copyMakeBorder(imgCut, imgCut, copyTop, copyButton, copyLeft, copyRight, BORDER_CONSTANT, fillColour); } else { copyMakeBorder(imgCut, imgCut, copyTop, copyButton, copyLeft, copyRight, BORDER_CONSTANT, Scalar(fillColour, fillColour, fillColour)); } //resize为建网大小 cv::resize(imgCut, imgCls, cv::Size(sizeW, sizeH)); imgCut.release(); } int resultClass = 0; float prob = 1.0; resultClass = pCls->Evaluate(imgCls); //类别id prob = pCls->getProbability(); //可能性 //切图保存,按需 { isDirExist(classImgSaveDir + mysaveKey1 + "/class_" + QString::number(resultClass)); //存图数据入队,按需 addImgToSaveStruct(imgCls, mysaveKey1, classImgSaveDir + mysaveKey1 + "/class_" + QString::number(resultClass) + "/" + mySN + myDataTime + QString::number(j) + ".bmp"); } //此处应添加缺陷计数逻辑 if (resultClass == 0)//OK { ; } else if (resultClass == 1)//划伤Scratch { resIfNg = true; //rectangle(sourceRectangles, rect1.tl(), rect1.br(), Scalar(0, 0, 255), 3, 8); ////可行,必须转一下格式 //{ // QString pathQstr = "划伤"; // QByteArray path_arr = pathQstr.toLocal8Bit(); // const char* path = path_arr.data(); // putTextZH(sourceRectangles, path, cv::Point(rect1.tl().x, rect1.tl().y - 5), Scalar(255, 0, 0), 50, "微软雅黑"); //} defectInfo mdefectInfo; mdefectInfo.defectName = "划伤"; mdefectInfo.defectRect = rect1; mdefectInfo.defectArea = contourArea(contours[j]); mdefectInfo.defectScalar = cv::Scalar(0, 0, 255); defectInfoList.enqueue(mdefectInfo); } else if (resultClass == 2)//碰伤 { resIfNg = true; defectInfo mdefectInfo; mdefectInfo.defectName = "碰伤"; mdefectInfo.defectRect = rect1; mdefectInfo.defectArea = contourArea(contours[j]); mdefectInfo.defectScalar = cv::Scalar(0, 255, 255); defectInfoList.enqueue(mdefectInfo); } imgCls.release(); } else { //cout << "ng is too small<" << filterNum << endl; continue; } } } //cv::Mat resMat = img2D.clone(); sourceRectangles.release(); contours.resize(0); resultDstImg.release(); } */ detect_mutex->lock(); //resMat = sourceImg.clone(); //sourceImg.copyTo(resMat); resMat.push_back(sourceImg); //结果图画框和缺陷,在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++) { defectInfo mdefect = defectInfoList[i]; //resQbyte.push_back(mdefect.defectName.toLocal8Bit()); //中文也可以QString::number(1.1).toUtf8() //resQbyte.push_back(QString::number(mdefect.defectRect.x).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectRect.y).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectRect.width).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectRect.height).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectScalar[0]).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectScalar[1]).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectScalar[2]).toUtf8()); //resQbyte.push_back(QString::number(mdefect.defectArea).toUtf8()); QJsonObject detailObj; detailObj.insert("defectName", "mdefect.defectName"); detailObj.insert("defectRect.x", QString::number(mdefect.defectRect.x)); detailObj.insert("defectRect.y", QString::number(mdefect.defectRect.y)); 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("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))); detaillists.append(detailObj); } //使用完删除 defectInfoList.clear(); //往主界面发 //emit sendResultData(resMat, resQbyte); //resQbyte.clear(); isDirExist(resImgSaveDir + mysaveKey1 + "/"); QString qimgsavePath = resImgSaveDir + mysaveKey1 + "/" + mySN + myDataTime + ".png"; //存图数据入队,按需 if (resMat.size() > 0 ) addImgToSaveStruct(resMat[0], mysaveKey1, resImgSaveDir + mysaveKey1 + "/" + mySN + myDataTime + ".png"); detect_mutex->unlock(); obj.insert("detaillists", detaillists); obj.insert("qimgsavePath", qimgsavePath); document.setObject(obj); //resByte.clear(); QByteArray qa = document.toJson(); //resByte .enqueue(qa); //resMat.release(); sourceImg.release(); mySave.out_Mat.resize(0); mysaveKey1.clear(); qApp->processEvents(); ////原图和结果都往主界面发? //std::vector resMat; //resMat.push_back(img2D); //resMat.push_back(sourceRectangles); //QByteArray resByte = mysaveKey.toLocal8Bit(); //resByte.append(myDir2D.toLocal8Bit()); //resByte.append(mySN.toLocal8Bit()); //resByte.append(myDataTime.toLocal8Bit()); ////往主界面发送图片和数据 ////emit writeData(resMat, resByte); //resMat.resize(0); //resByte.resize(0); } catch (...) { qDebug() << "[Error] " << QString::fromUtf8("检测失败!"); return false; } return true; } //存图加入队列 void Hd_AI_2D3Ddata_module::addImgToSaveStruct(cv::Mat img2D, QString mysaveKey, QString savePath) { //存图数据加保存队列,加锁,避免数据访问冲突 saveStruct_mutex->lock(); saveImgStruct mySave; mySave.out_Mat = img2D.clone(); //img2D.copyTo(mySave.out_Mat); mySave.saveKey = (mysaveKey).toStdString(); mySave.savePath = (savePath).toStdString(); saveStruct.enqueue(mySave); saveStruct_mutex->unlock(); } void Hd_AI_2D3Ddata_module::saveImgThread() { while (1) { if (!ifdetectThread)return; _sleep(1); qApp->processEvents(); if (saveStruct.size() < 1)continue; for (int i = 0; i < saveStruct.size(); i++) { saveStruct_mutex->lock(); saveImgStruct mysaveStruct = saveStruct.dequeue(); saveStruct_mutex->unlock(); //if (mysaveStruct.out_Mat.data)imwrite(mysaveStruct.savePath, mysaveStruct.out_Mat); //std::cout << "savePath::" << mysaveStruct.savePath << std::endl; _sleep(1); } } } //检测线程,应当只运行一次 void Hd_AI_2D3Ddata_module::detectThread() { do { if (!ifdetectThread)return; //此两行代码,避免程序卡死;_sleep的时间根据实际项目调整 _sleep(2); qApp->processEvents(); //取数据加锁,避免数据访问冲突 detect_mutex->lock(); //if (HikMat.size() < 1 || saveKey.size() < 1 || Dir2D.size() < 1 || SN.size() < 1 )//|| DateTime1.size() < 1) //{ // detect_mutex->unlock(); // continue; //} cv::Mat sourceImg1 = HikMat[0];// .dequeue(); QString mysaveKey = "saveKey";// .dequeue(); QString myDir2D = "Dir2D";// .dequeue(); QString mySN = "SN";// .dequeue(); QString myDataTime = "DateTime1"; detect_mutex->unlock(); //判断存图文件夹是否存在,不存在则创建 { //原图总文件夹 isDirExist(oriImgSaveDir + mysaveKey); //原图class总文件夹 isDirExist(classImgSaveDir + mysaveKey); //结果图总文件夹 isDirExist(resImgSaveDir + mysaveKey); } //测试相机的, while (sourceImg1.cols > 2000)cv::resize(sourceImg1, sourceImg1, cv::Size(), 0.5, 0.5); //存图数据入队 //addImgToSaveStruct(sourceImg1, mysaveKey, oriImgSaveDir + mysaveKey + "/" + mySN + myDataTime + ".bmp"); //-------检测流程,根据实际项目修改--------- AIdetect(sourceImg1, mysaveKey, oriImgSaveDir, mySN, myDataTime); //sourceImg1.release(); mysaveKey.clear(); myDir2D.clear(); mySN.clear(); myDataTime.clear(); qApp->processEvents(); } while (ifThreadRunDetect); } bool myMath(double a, double b) { return a > b; } static int runNum = 0; QQueue timeAll_A; QQueue timeAll_B; bool Hd_AI_2D3Ddata_module::run() { defectNums = 0; vector srcMats; clock_t start = 0; clock_t stop = 0; double time = 0; //cv::Mat mat; float prob = 0; if (HikMat.isEmpty()) return true; srcMats.push_back(HikMat[0]); start = clock(); stop = clock(); time = stop - start; timeAll_B.enqueue(time); start = clock(); qSort(timeAll_A.begin(), timeAll_A.end(), myMath); qSort(timeAll_B.begin(), timeAll_B.end(), myMath); timeAll_A.rend(); timeAll_B.rend(); //Sleep(50); //detectThread(); //stop = clock(); qDebug() << __FUNCTION__ << "line:" << __LINE__ << " run start ::runNum::" << runNum<<" cutTime::"<