diff --git a/include/opencvPaintAlgo.hpp b/include/opencvPaintAlgo.hpp index aecbc94..1425be1 100644 --- a/include/opencvPaintAlgo.hpp +++ b/include/opencvPaintAlgo.hpp @@ -31,65 +31,162 @@ static std::wstring utf8ToWstring(const std::string& utf8Str) { } // 在图像上绘制中文(仅 Windows,使用 GDI) static void putTextZH(cv::Mat& image, const std::string& text, cv::Point org, int fontSize = 20, cv::Scalar color = cv::Scalar(255, 0, 0)) { - // 创建兼容的位图 - cv::Mat img; - if (image.channels() == 1) - cv::cvtColor(image, img, cv::COLOR_GRAY2BGRA); - else if (image.channels() == 3) - cv::cvtColor(image, img, cv::COLOR_BGR2BGRA); - else if (image.channels() == 4) - img = image.clone(); - else - throw std::runtime_error("Unsupported number of channels"); + if (image.channels() != 3) + throw std::runtime_error("Only supports 3-channel images"); - // 创建 Windows 位图信息 - HDC hdc = GetDC(nullptr); - HDC memDC = CreateCompatibleDC(hdc); - BITMAPINFO bmi; - memset(&bmi, 0, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = img.cols; - bmi.bmiHeader.biHeight = -img.rows; // top-down - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; + // 转为 BGRA + cv::Mat img; + cv::cvtColor(image, img, cv::COLOR_BGR2BGRA); - void* pBits = nullptr; - HBITMAP hBitmap = CreateDIBSection(memDC, &bmi, DIB_RGB_COLORS, &pBits, nullptr, 0); - SelectObject(memDC, hBitmap); - memcpy(pBits, img.data, img.total() * img.elemSize()); + HDC hdc = GetDC(nullptr); + HDC memDC = CreateCompatibleDC(hdc); - // 设置字体 - HFONT hFont = CreateFontW( - fontSize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, - GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, L"微软雅黑"); - SelectObject(memDC, hFont); + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = img.cols; + bmi.bmiHeader.biHeight = -img.rows; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; - // 设置颜色和背景 - SetBkMode(memDC, TRANSPARENT); - SetTextColor(memDC, RGB(color[2], color[1], color[0])); + void* pBits = nullptr; + HBITMAP hBitmap = CreateDIBSection(memDC, &bmi, DIB_RGB_COLORS, &pBits, nullptr, 0); + SelectObject(memDC, hBitmap); + memcpy(pBits, img.data, img.total() * img.elemSize()); - // 输出文字 - std::wstring wtext = utf8ToWstring(text); - TextOutW(memDC, org.x, org.y, wtext.c_str(), static_cast(wtext.length())); + HFONT hFont = CreateFontW(fontSize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, + GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, L"微软雅黑"); + SelectObject(memDC, hFont); - // 拷贝回来 - GetDIBits(memDC, hBitmap, 0, img.rows, img.data, &bmi, DIB_RGB_COLORS); + SetBkMode(memDC, TRANSPARENT); + SetTextColor(memDC, RGB(color[2], color[1], color[0])); - // 转换回原始图像格式 - if (image.channels() == 1) - cv::cvtColor(img, image, cv::COLOR_BGRA2GRAY); - else if (image.channels() == 3) - cv::cvtColor(img, image, cv::COLOR_BGRA2BGR); - else if (image.channels() == 4) - image = img.clone(); + TextOutW(memDC, org.x, org.y, utf8ToWstring(text).c_str(), static_cast(utf8ToWstring(text).length())); - // 清理 - DeleteObject(hFont); - DeleteObject(hBitmap); - DeleteDC(memDC); - ReleaseDC(nullptr, hdc); - } + GetDIBits(memDC, hBitmap, 0, img.rows, img.data, &bmi, DIB_RGB_COLORS); + + cv::cvtColor(img, image, cv::COLOR_BGRA2BGR); + + DeleteObject(hFont); + DeleteObject(hBitmap); + DeleteDC(memDC); + ReleaseDC(nullptr, hdc); +} +class TextRendererBase { +public: + virtual ~TextRendererBase() = default; + virtual void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) = 0; +}; + +class TextRendererZH : public TextRendererBase { +public: + TextRendererZH(int width, int height, int fontSize = 20, const std::wstring& fontName = L"微软雅黑") + : width_(width), height_(height), fontSize_(fontSize), fontName_(fontName) + { + screenDC_ = GetDC(nullptr); + createResources(); + } + + ~TextRendererZH() { + releaseResources(); + if (screenDC_) ReleaseDC(nullptr, screenDC_); + } + + void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) override { + if (image.channels() != 3) + throw std::runtime_error("TextRendererZH only supports 3-channel BGR images."); + + if (image.cols != width_ || image.rows != height_) { + resize(image.cols, image.rows); + } + + cv::Mat img; + cv::cvtColor(image, img, cv::COLOR_BGR2BGRA); + + memcpy(pBits_, img.data, img.total() * img.elemSize()); + + SetBkMode(memDC_, TRANSPARENT); + SetTextColor(memDC_, RGB(color[2], color[1], color[0])); + + std::wstring wtext = utf8ToWstring(text); + TextOutW(memDC_, org.x, org.y, wtext.c_str(), (int)wtext.length()); + + GetDIBits(memDC_, hBitmap_, 0, height_, img.data, &bmi_, DIB_RGB_COLORS); + + cv::cvtColor(img, image, cv::COLOR_BGRA2BGR); + } + + void resize(int width, int height) { + if (width == width_ && height == height_) return; + + releaseResources(); + + width_ = width; + height_ = height; + createResources(); + } + +private: + void createResources() { + memDC_ = CreateCompatibleDC(screenDC_); + + memset(&bmi_, 0, sizeof(bmi_)); + bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi_.bmiHeader.biWidth = width_; + bmi_.bmiHeader.biHeight = -height_; + bmi_.bmiHeader.biPlanes = 1; + bmi_.bmiHeader.biBitCount = 32; + bmi_.bmiHeader.biCompression = BI_RGB; + + hBitmap_ = CreateDIBSection(memDC_, &bmi_, DIB_RGB_COLORS, &pBits_, nullptr, 0); + SelectObject(memDC_, hBitmap_); + + hFont_ = CreateFontW( + fontSize_, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, + GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, fontName_.c_str()); + SelectObject(memDC_, hFont_); + } + + void releaseResources() { + if (hFont_) { + DeleteObject(hFont_); + hFont_ = nullptr; + } + if (hBitmap_) { + DeleteObject(hBitmap_); + hBitmap_ = nullptr; + pBits_ = nullptr; + } + if (memDC_) { + DeleteDC(memDC_); + memDC_ = nullptr; + } + } + + // UTF8 转宽字符串 + static std::wstring utf8ToWstring(const std::string& str) { + if (str.empty()) return {}; + int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); + std::wstring wstrTo(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstrTo[0], size_needed); + return wstrTo; + } + +private: + int width_; + int height_; + int fontSize_; + std::wstring fontName_; + + HDC screenDC_ = nullptr; + HDC memDC_ = nullptr; + HBITMAP hBitmap_ = nullptr; + void* pBits_ = nullptr; + BITMAPINFO bmi_{}; + + HFONT hFont_ = nullptr; +}; #pragma endregion diff --git a/src.zip b/src.zip new file mode 100644 index 0000000..46774e3 Binary files /dev/null and b/src.zip differ diff --git a/src/Core/back/cameraManager.cpp b/src/Core/back/cameraManager.cpp index bf95aa4..925836b 100644 --- a/src/Core/back/cameraManager.cpp +++ b/src/Core/back/cameraManager.cpp @@ -47,9 +47,9 @@ void camera::run() int queueSize = requestQueue.size() ; if (queueSize >0) { - mutex.lock(); + QMutexLocker locker(&mutex); std::shared_ptr data = requestQueue.dequeue(); - data->oriImgMutex.lock(); + QMutexLocker locker2(&data->oriImgMutex); while(1){ getCameraImg(data->oriImgs, data->imgAmountMin); if (data->oriImgs.size() >= data->imgAmountMin){ @@ -76,8 +76,6 @@ void camera::run() showLost++; qDebug() << cameraModulePtr.dllPath << "Lost show"; } - data->oriImgMutex.unlock(); - mutex.unlock(); break; } QThread::msleep(1); diff --git a/src/Core/back/cameraManager.h b/src/Core/back/cameraManager.h index d5dafcc..b12f238 100644 --- a/src/Core/back/cameraManager.h +++ b/src/Core/back/cameraManager.h @@ -38,6 +38,7 @@ public: void getImgQueueSize(); void captureImage(std::shared_ptr dataIn) { + QMutexLocker locker(&mutex); requestQueue.enqueue(dataIn); std::thread([this]() {trigger();}).detach(); diff --git a/src/Core/back/detData.h b/src/Core/back/detData.h index ed419cd..3a720b6 100644 --- a/src/Core/back/detData.h +++ b/src/Core/back/detData.h @@ -114,7 +114,6 @@ public: if (dataPtr == nullptr) qDebug() << "创建新容器失败"; - qDebug() << "创建新容器成功"; return dataPtr; } std::shared_ptr getDetData(QString uuid) diff --git a/src/Core/back/imgSaveThreadManager.h b/src/Core/back/imgSaveThreadManager.h index 52df13a..67b1bc2 100644 --- a/src/Core/back/imgSaveThreadManager.h +++ b/src/Core/back/imgSaveThreadManager.h @@ -9,7 +9,6 @@ enum imgSaveThreadType resImg, segImg, clsImg, - additionalSaveNgImg, tiffOriImg }; class imgSaveThread : public QThread @@ -25,32 +24,36 @@ public: QQueue>imgQueue; void run() { - while (imgQueue.size() > 0 || priorityQueue.size() > 0) + while (true) { - if (priorityQueue.size() > 0) { - mutex.lock(); - std::pair data = priorityQueue.dequeue(); - mutex.unlock(); - qDebug() << "saving priority img " << QString::fromStdString(data.first); - cv::imwrite(data.first, data.second); - data.second.release(); + QQueue> localQueue; + + // 优先处理 priorityQueue + { + QMutexLocker locker(&mutex); + if (!priorityQueue.isEmpty()) { + localQueue.swap(priorityQueue); + } + else if (!imgQueue.isEmpty()) { + localQueue.swap(imgQueue); + } } - else if (imgQueue.size() > 0) { - mutex.lock(); - std::pair data = imgQueue.dequeue(); - mutex.unlock(); + + // 没有任务就跳出 + if (localQueue.isEmpty()) { + break; + } + + // 批量保存 + while (!localQueue.isEmpty()) { + auto data = std::move(localQueue.dequeue()); qDebug() << "saving img " << QString::fromStdString(data.first); - if (data.first.find(".png") != std::string::npos){ - cv::resize(data.second, data.second, cv::Size(), 0.25, 0.25); - cv::imwrite(data.first, data.second, compressionParams); - } - else { - cv::imwrite(data.first, data.second); - } - data.second.release(); + cv::imwrite(data.first, data.second); + // 不需要手动 release(), cv::Mat 会自动析构 } } } + void addData(std::string str, cv::Mat& mat,type type_ = normal) { try @@ -107,7 +110,8 @@ public: std::string imgTypeDirStr;//二级目录,图片类型决定 sample "Result" std::string dateDirStr;//三级目录,日期决定 sample"2024-6-8" std::string hourDirStr;//四级目录,小时段决定 sample "14H" - std::string detailNameStr;//五级目录 主要是SN,如没有sn则可能是相机名称 + std::string okNgStr;//五级目录,OK/NG决定 sample "OK" + std::string detailNameStr;//六级目录 主要是SN,如没有sn则可能是相机名称 #pragma region 赋值 //imgTypeDirStr switch (type) @@ -118,9 +122,6 @@ public: case resImg: imgTypeDirStr = "Result"; break; - case additionalSaveNgImg: - imgTypeDirStr = "NGIMG"; - break; default: imgTypeDirStr = "error"; } @@ -130,7 +131,10 @@ public: dateDirStr = currentDateTime.toString("yyyy-MM-dd").toStdString(); hourDirStr = std::to_string(currentDateTime.time().hour()) + "H//"; } - + if(data->aiDetOK == true && data->halconOK == true) + okNgStr = "OK"; + else + okNgStr = "NG"; //detailNameStr if ((data->SNcode).length() != 0) detailNameStr = data->SNcode; @@ -141,6 +145,7 @@ public: imgTypeDirStr + "/" + dateDirStr + "/" + hourDirStr + "/" + + okNgStr + "/" + detailNameStr + "/"); } std::vector genFileNames(std::shared_ptr data, imgSaveThreadType type, std::string format = "") @@ -173,22 +178,6 @@ public: for (int i = 0; i < data->clsOriginImgs.size(); i++) resultFileNames.push_back(fileName + "CLS_RES" + getCurrentDateTime() + "_" + data->clsOriginImgs[i].first + "_Count" + std::to_string(i) + ".bmp"); break; - case additionalSaveNgImg: - if (data->aiDetOK == false || data->halconOK == false) - { - for (int i = 0; i < data->segOriginImgs.size(); i++) - resultFileNames.push_back(fileName + "NGIMG_segOriginImgs_" + getCurrentDateTime() + "_" + std::to_string(i) + ".png"); - for (int i = 0; i < data->oriImgs.size(); i++) - { - if(data->oriImgs[i].depth() == 2) - resultFileNames.push_back(fileName + "NGIMG_oriImgs_" + getCurrentDateTime() + "_" + std::to_string(i) + ".tiff"); - else - resultFileNames.push_back(fileName + "NGIMG_oriImgs_" + getCurrentDateTime() + "_" + std::to_string(i) + ".png"); - } - for (int i = 0; i < data->resultImgs.size(); i++) - resultFileNames.push_back(fileName + "NGIMG_resultImgs_" + getCurrentDateTime() + "_" + std::to_string(i) + ".jpg"); - } - break; } return resultFileNames; } @@ -211,44 +200,39 @@ public: //结果图保存 std::vectorresFileNames = genFileNames(data, resImg); for (int index = 0; index < resFileNames.size(); index++) - { saveThread.addData(fileSavePath + resFileNames[index], data->resultImgs[index], imgSaveThread::priority); - } //seg - std::string segAndClsPath = fileSavePath + "detImgs//" + getCurrentDateTime() + "//"; std::vectorsegFileNames = genFileNames(data, segImg); - if (segFileNames.size() > 0) - createDirectoryIfNotExists(segAndClsPath);//不存在此文件夹则创建 for (int index = 0; index < segFileNames.size(); index++) - saveThread.addData(segAndClsPath + segFileNames[index], data->segOriginImgs[index]); + saveThread.addData(fileSavePath + segFileNames[index], data->segOriginImgs[index]); //cls std::vectorclsFileNames = genFileNames(data, clsImg); for (int index = 0; index < clsFileNames.size(); index++) - saveThread.addData(segAndClsPath + clsFileNames[index], data->clsOriginImgs[index].second); + saveThread.addData(fileSavePath + clsFileNames[index], data->clsOriginImgs[index].second); //额外储存NG文件夹 - std::string additionalSaveNgImgPath = genDirName(data, additionalSaveNgImg); - std::vectoradditionalSaveNgImgNames = genFileNames(data, additionalSaveNgImg); - if (additionalSaveNgImgNames.size() > 0) - createDirectoryIfNotExists(additionalSaveNgImgPath);//不存在此文件夹则创建 - int additionalSaveNgImgNamesIndex = 0; - for (int index = 0; index < data->segOriginImgs.size()&& additionalSaveNgImgNames.size() > additionalSaveNgImgNamesIndex; index++) - { - saveThread.addData(additionalSaveNgImgPath + additionalSaveNgImgNames[additionalSaveNgImgNamesIndex], data->segOriginImgs[index]); - additionalSaveNgImgNamesIndex++; - } - for (int index = 0; index < data->oriImgs.size() && additionalSaveNgImgNames.size() > additionalSaveNgImgNamesIndex; index++) - { - saveThread.addData(additionalSaveNgImgPath + additionalSaveNgImgNames[additionalSaveNgImgNamesIndex], data->oriImgs[index]); - additionalSaveNgImgNamesIndex++; - } - for (int index = 0; index < data->resultImgs.size() && additionalSaveNgImgNames.size() > additionalSaveNgImgNamesIndex; index++) - { - saveThread.addData(additionalSaveNgImgPath + additionalSaveNgImgNames[additionalSaveNgImgNamesIndex], data->resultImgs[index]); - additionalSaveNgImgNamesIndex++; - } + //std::string additionalSaveNgImgPath = genDirName(data, additionalSaveNgImg); + //std::vectoradditionalSaveNgImgNames = genFileNames(data, additionalSaveNgImg); + //if (additionalSaveNgImgNames.size() > 0) + // createDirectoryIfNotExists(additionalSaveNgImgPath);//不存在此文件夹则创建 + //int additionalSaveNgImgNamesIndex = 0; + //for (int index = 0; index < data->segOriginImgs.size()&& additionalSaveNgImgNames.size() > additionalSaveNgImgNamesIndex; index++) + //{ + // saveThread.addData(additionalSaveNgImgPath + additionalSaveNgImgNames[additionalSaveNgImgNamesIndex], data->segOriginImgs[index]); + // additionalSaveNgImgNamesIndex++; + //} + //for (int index = 0; index < data->oriImgs.size() && additionalSaveNgImgNames.size() > additionalSaveNgImgNamesIndex; index++) + //{ + // saveThread.addData(additionalSaveNgImgPath + additionalSaveNgImgNames[additionalSaveNgImgNamesIndex], data->oriImgs[index]); + // additionalSaveNgImgNamesIndex++; + //} + //for (int index = 0; index < data->resultImgs.size() && additionalSaveNgImgNames.size() > additionalSaveNgImgNamesIndex; index++) + //{ + // saveThread.addData(additionalSaveNgImgPath + additionalSaveNgImgNames[additionalSaveNgImgNamesIndex], data->resultImgs[index]); + // additionalSaveNgImgNamesIndex++; + //} } private: std::string path = ""; diff --git a/src/Core/back/triggerManager.h b/src/Core/back/triggerManager.h index bfab700..b3d06bc 100644 --- a/src/Core/back/triggerManager.h +++ b/src/Core/back/triggerManager.h @@ -208,7 +208,7 @@ public: { if (checkTrigger(callback.triggerAddress, callback.triggerValue, byteArray) == true) { - std::cout << "func:" << callback.funcName << "->triggered" << std::endl; + qDebug() << "func:" << QString::fromStdString(callback.funcName) << "->triggered"; std::thread([callback, byteArray]() mutable { try { callback.func(byteArray); // 执行回调函数 diff --git a/src/core/back/detCallbackChain.hpp b/src/core/back/detCallbackChain.hpp index df0a875..09b8592 100644 --- a/src/core/back/detCallbackChain.hpp +++ b/src/core/back/detCallbackChain.hpp @@ -16,11 +16,40 @@ public: detCallbackChain(imgSaveThreadManager* imgSaveThreadManager = nullptr, handleAiModelsTemplate* _handleAiModelsIn = nullptr) : _imgSaveThreadManager(imgSaveThreadManager), _handleAiModels(_handleAiModelsIn) { + int threadCount = 2 * QThread::idealThreadCount(); + QThreadPool::globalInstance()->setMaxThreadCount(threadCount); + } void ansyncProcess(std::shared_ptr data) { - QtConcurrent::run([this, data]() { +#pragma region 方法1 较慢 + QFuture future = QtConcurrent::run([this, data]() { process(data); }); +#pragma endregion +#pragma region 方法2 较慢 安全 + //QThread* thread = new QThread; + //QObject::connect(thread, &QThread::started, [this, data]() { + // process(data); + // }); + //QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater); + //thread->start(); + //thread->setPriority(QThread::TimeCriticalPriority); +#pragma endregion +#pragma region 方法3 不安全 + /* std::async(std::launch::async, [this, data]() { + process(data); + });*/ +#pragma endregion +#pragma region 方法4 + //std::thread([this, data]() { + // process(data); + // }).detach(); +#pragma endregion +#pragma region 方法5 + //QThreadPool::globalInstance()->start([this, data]() { + // process(data); + // }); +#pragma endregion } void process(std::shared_ptr data) { @@ -28,11 +57,13 @@ public: std::this_thread::sleep_for(std::chrono::milliseconds(1)); } //等待图片满足要求后,储存原图,异步执行算法函数 - std::async(std::launch::async, &imgSaveThreadManager::saveOri, _imgSaveThreadManager, data); + algoEvaluate(data, _handleAiModels); //执行完毕后异步获取储存使用结果 resultHandle(data); - + // 确保线程安全退出 + qDebug() << "Processing finished for data with UUID:" << data->uuid; + QThread::currentThread()->quit(); } bool algoEvaluate(std::shared_ptr data, handleAiModelsTemplate* model) { @@ -67,28 +98,39 @@ public: } void resultHandle(std::shared_ptr data){ - for (auto func : resultHandleCallbacks) - func(data); - detectionResultHandle(data); + std::shared_ptr dataPtr = data; + detDataManager* dManager = data->dManager; + data->dManager->deleteDetData(data->uuid); + try { + detectionResultHandle(data); + for (auto func : resultHandleCallbacks) + func(data); + } + catch (const std::exception& e) + { + std::cout << "Caught exception: " << e.what() << std::endl; + qDebug() << "Caught exception: " << e.what(); + } + catch (...) { + qDebug() << "Caught exception: "; + } + // 删除数据释放资源 + } // 通用的检测结果处理 void detectionResultHandle(std::shared_ptr data) { //计算处理总耗时(CT) - QString totalCtStr = QString::fromStdString(data->SNcode) + QString::fromStdString(data->cameraKeyName) + "\n"; - totalCtStr += "algoCT->" + QString::number(data->algoTime) + "ms"; + QString totalCtStr = "algoCT->" + QString::number(data->algoTime) + "ms"; qDebug() << totalCtStr; - std::cout << totalCtStr.toStdString() << std::endl; + //std::cout << totalCtStr.toStdString() << std::endl; // 将耗时数据保存入数据库或日志 // data->sqlVec.push_back({ "SN", data->SNcode }); // data->sqlVec.push_back({ "totalCt", std::to_string(totalCt.count()) + "ms" }); // 异步保存检测图像 + std::async(std::launch::async, &imgSaveThreadManager::saveOri, _imgSaveThreadManager, data); std::async(std::launch::async, &imgSaveThreadManager::saveRes, _imgSaveThreadManager, data); - - // 删除数据释放资源 - detDataManager* dManager = data->dManager; - data->dManager->deleteDetData(data->uuid); } #pragma region 注册回调函数 @@ -107,5 +149,6 @@ private: std::vector< resultHandleCallback>resultHandleCallbacks; processAlgoCallback _processAlgoCallback; + //std::vector> futures; // 用于存储异步处理的结果 }; #pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/logPageWidget.h b/src/launcher/GUI/front/pages/logPageWidget.h index 79a0a14..9589b8a 100644 --- a/src/launcher/GUI/front/pages/logPageWidget.h +++ b/src/launcher/GUI/front/pages/logPageWidget.h @@ -17,136 +17,129 @@ #include #include #include -class logWidget :public QWidget -{ + +//行数上限 +const int MAX_LOGWIDGET_LINES = 1000; + +class logWidget : public QWidget { public: - enum logType - { - stdConsle, - qtConsle - }; - QVBoxLayout* Layout; - QHBoxLayout* btnLayout; - std::vectorbtns; - QLabel* icon, * Title; - QStackedWidget* widgets; - QTextEdit stdConsoleOutput; - QTextEdit qtConsoleOutput; - logWidget() - { - QPalette palette; - palette.setColor(QPalette::WindowText, Qt::white); - QFont font("微软雅黑", 24, QFont::Bold); + enum logType { + stdConsle, + qtConsle + }; + QVBoxLayout* Layout; + QHBoxLayout* btnLayout; + std::vector btns; + QLabel* icon, * Title; + QStackedWidget* widgets; + QPlainTextEdit stdConsoleOutput; + QPlainTextEdit qtConsoleOutput; - widgets = new QStackedWidget(); - widgets->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - widgets->setMaximumSize(9999, 9999); + logWidget() { + QPalette palette; + palette.setColor(QPalette::WindowText, Qt::white); + QFont font("微软雅黑", 24, QFont::Bold); - this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - this->setMaximumSize(9999, 9999); - this->setObjectName("configSettingWidget"); - //this->setStyleSheet(QString("QWidget {background-color: rgb(%1)}").arg(sColor_Gold)); - //this->showMaximized(); - Layout = new QVBoxLayout(this); - Layout->setContentsMargins(0, 0, 0, 0); - Layout->setAlignment(Qt::AlignLeft | Qt::AlignTop); + widgets = new QStackedWidget(); + widgets->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - Title = new QLabel(u8"日志"); - Title->setFont(font); - Title->setPalette(palette); - Title->setAlignment(Qt::AlignLeft); - Layout->addWidget(Title); + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + this->setObjectName("configSettingWidget"); - btnLayout = new QHBoxLayout(); - btnLayout->setContentsMargins(0, 0, 0, 0); - btnLayout->setAlignment(Qt::AlignLeft); + Layout = new QVBoxLayout(this); + Layout->setContentsMargins(0, 0, 0, 0); + Layout->setAlignment(Qt::AlignLeft | Qt::AlignTop); - Layout->addLayout(btnLayout); + Title = new QLabel(u8"日志"); + Title->setFont(font); + Title->setPalette(palette); + Title->setAlignment(Qt::AlignLeft); + Layout->addWidget(Title); - stdConsoleOutput.setReadOnly(true); - qtConsoleOutput.setReadOnly(true); - addLogWidget(u8"控制台", &stdConsoleOutput, logType::stdConsle); - addLogWidget(u8"QT日志", &qtConsoleOutput, logType::qtConsle); - btns[0]->pressed(); + btnLayout = new QHBoxLayout(); + btnLayout->setContentsMargins(0, 0, 0, 0); + btnLayout->setAlignment(Qt::AlignLeft); + Layout->addLayout(btnLayout); - Layout->addWidget(widgets); - } - void addLogWidget(QString btnText,QTextEdit* textWidget, logType type) - { - QPalette palette; - palette.setColor(QPalette::WindowText, Qt::white); - QFont font("微软雅黑", 13, QFont::Bold); - QFont font2("微软雅黑", 8); - QFont font3("微软雅黑", 16, QFont::Bold); + stdConsoleOutput.setReadOnly(true); + qtConsoleOutput.setReadOnly(true); + stdConsoleOutput.setMaximumBlockCount(MAX_LOGWIDGET_LINES); + qtConsoleOutput.setMaximumBlockCount(MAX_LOGWIDGET_LINES); + stdConsoleOutput.setStyleSheet("background-color: rgb(30,30,30); color: white;"); + qtConsoleOutput.setStyleSheet("background-color: rgb(30,30,30); color: white;"); - //切换配置页面 - int index = btns.size(); - gradientButton* btn = new gradientButton(160, 50, btnText, ""); - btnLayout->addWidget(btn); - btns.push_back(btn); - connect(btn, &QPushButton::clicked, [=]() - { - for (auto btnPtr : btns) - btnPtr->toDefault(); - btn->pressed(); - widgets->setCurrentIndex(index); - }); + addLogWidget(u8"控制台", &stdConsoleOutput, logType::stdConsle); + addLogWidget(u8"QT日志", &qtConsoleOutput, logType::qtConsle); + btns[0]->pressed(); - //页面widget - QWidget* widget = new QWidget(); - widgets->addWidget(widget); - widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + Layout->addWidget(widgets); + } - QVBoxLayout* widgetLayout = new QVBoxLayout(widget); - widgetLayout->setContentsMargins(0, 0, 0, 0); - widgetLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); + void addLogWidget(QString btnText, QPlainTextEdit* textWidget, logType type) { + QPalette palette; + palette.setColor(QPalette::WindowText, Qt::white); + QFont font2("微软雅黑", 8); - QHBoxLayout* toolHLayout = new QHBoxLayout(); - widgetLayout->addLayout(toolHLayout); + int index = btns.size(); + gradientButton* btn = new gradientButton(160, 50, btnText, ""); + btnLayout->addWidget(btn); + btns.push_back(btn); + connect(btn, &QPushButton::clicked, [=]() { + for (auto btnPtr : btns) + btnPtr->toDefault(); + btn->pressed(); + widgets->setCurrentIndex(index); + }); - QLabel* toolName = new QLabel(u8"过滤器"); - toolName->setFont(font2); - toolName->setPalette(palette); - toolHLayout->addWidget(toolName); + QWidget* widget = new QWidget(); + widgets->addWidget(widget); + widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QStringList options = { "Debug","Info","Warning" }; - QComboBox* filterSelector = new QComboBox(); - filterSelector->addItems(options); - toolHLayout->addWidget(filterSelector); + QVBoxLayout* widgetLayout = new QVBoxLayout(widget); + widgetLayout->setContentsMargins(0, 0, 0, 0); + widgetLayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); - QLabel* toolName2 = new QLabel(u8" 正则匹配"); - toolName2->setFont(font2); - toolName2->setPalette(palette); - toolHLayout->addWidget(toolName2); + QHBoxLayout* toolHLayout = new QHBoxLayout(); + widgetLayout->addLayout(toolHLayout); - QLineEdit* lineedit = new QLineEdit(); - toolHLayout->addWidget(lineedit); + QLabel* toolName = new QLabel(u8"过滤器"); + toolName->setFont(font2); + toolName->setPalette(palette); + toolHLayout->addWidget(toolName); + + QStringList options = { "Debug","Info","Warning" }; + QComboBox* filterSelector = new QComboBox(); + filterSelector->addItems(options); + toolHLayout->addWidget(filterSelector); + + QLabel* toolName2 = new QLabel(u8" 正则匹配"); + toolName2->setFont(font2); + toolName2->setPalette(palette); + toolHLayout->addWidget(toolName2); + + QLineEdit* lineedit = new QLineEdit(); + toolHLayout->addWidget(lineedit); + + widgetLayout->addWidget(textWidget); + } + + QString getCurrentDate() { + return QDate::currentDate().toString("yyyy-MM-dd"); + } + + QString getCurrentTime() { + return QTime::currentTime().toString("HH:mm:ss.zzz"); + } - widgetLayout->addWidget(textWidget); - textWidget->setStyleSheet("background-color: rgb(30,30,30);"); - } - QString getCurrentDate() { - QDate currentDate = QDate::currentDate(); - return currentDate.toString("yyyy-MM-dd"); - } - QString getCurrentTime() { - QTime currentTime = QTime::currentTime(); - return currentTime.toString("HH:mm:ss.zzz"); - } public slots: - void recvStdLogMsg(QString logMsg) - { - QString text = "" + getCurrentDate() + " " - "" + getCurrentTime() + " " - "" + logMsg + " "; - stdConsoleOutput.append(text); - } - void recvQtLogMsg(QString logMsg) - { - QString text = "" + getCurrentDate() + " " - "" + getCurrentTime() + " " - "" + logMsg + " "; - qtConsoleOutput.append(text); - } + void recvStdLogMsg(QString logMsg) { + QString text = getCurrentDate() + " " + getCurrentTime() + " " + logMsg; + stdConsoleOutput.appendPlainText(text); + } + + void recvQtLogMsg(QString logMsg) { + QString text = getCurrentDate() + " " + getCurrentTime() + " " + logMsg; + qtConsoleOutput.appendPlainText(text); + } }; #pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/summary_data_page.h b/src/launcher/GUI/front/pages/summary_data_page.h index 1347527..6b953a0 100644 --- a/src/launcher/GUI/front/pages/summary_data_page.h +++ b/src/launcher/GUI/front/pages/summary_data_page.h @@ -19,8 +19,8 @@ public: m_plot(new QCustomPlot(this)) { QString title = QString::fromStdString(json.value("key", "默认标题")); - double limitHigh = json.value("limitHigh", 100.0); - double limitLow = json.value("limitLow", 0.0); + m_limitHigh = json.value("limitHigh", 100.0); + m_limitLow = json.value("limitLow", 0.0); m_maxPoints = json.value("maxPoints", 50); QFont font("微软雅黑", 24, QFont::Bold); @@ -40,29 +40,81 @@ public: m_mainLayout->addWidget(m_plot); m_plot->setBackground(Qt::transparent); + + // 主蓝色曲线 m_plot->addGraph(); m_plot->graph(0)->setPen(QPen(Qt::blue, 2)); m_plot->graph(0)->setScatterStyle(QCPScatterStyle::ssNone); - m_plot->yAxis->setRange(-1,3); - addLimitLines(limitHigh, limitLow); + // 新增红色点图层 + m_plot->addGraph(); + m_plot->graph(1)->setLineStyle(QCPGraph::lsNone); + m_plot->graph(1)->setScatterStyle( + QCPScatterStyle(QCPScatterStyle::ssDisc, QPen(Qt::red), QBrush(Qt::red), 6) + ); + m_plot->xAxis->setBasePen(QPen(Qt::white, 2)); // 坐标轴线 + m_plot->yAxis->setBasePen(QPen(Qt::white, 2)); + + m_plot->xAxis->setTickPen(QPen(Qt::white)); // 刻度线 + m_plot->yAxis->setTickPen(QPen(Qt::white)); + + m_plot->xAxis->setSubTickPen(QPen(Qt::white)); // 次刻度 + m_plot->yAxis->setSubTickPen(QPen(Qt::white)); + + m_plot->xAxis->setTickLabelColor(Qt::white); // 数字标签 + m_plot->yAxis->setTickLabelColor(Qt::white); + + m_plot->xAxis->setLabelColor(Qt::white); // "时间" / "数值" 文字 + m_plot->yAxis->setLabelColor(Qt::white); + + m_plot->yAxis->setRange(m_limitLow - 1, m_limitHigh + 1); + addLimitLines(m_limitHigh, m_limitLow); } void appendData(double value) { m_xData.append(m_timeCounter); m_yData.append(value); + + // 如果超限,添加到红点数据并添加文本 + if (value > m_limitHigh || value < m_limitLow) { + m_xOverLimit.append(m_timeCounter); + m_yOverLimit.append(value); + + auto* textItem = new QCPItemText(m_plot); + textItem->setPositionAlignment(Qt::AlignLeft | Qt::AlignVCenter); + textItem->position->setType(QCPItemPosition::ptPlotCoords); + textItem->position->setCoords(m_timeCounter, value); + textItem->setText(QString::number(value, 'f', 2)); + textItem->setColor(Qt::yellow); + textItem->setFont(QFont("微软雅黑", 8, QFont::Bold)); + m_textItems.append(textItem); + } + ++m_timeCounter; + // 保持窗口大小 if (m_xData.size() > m_maxPoints) { m_xData.removeFirst(); m_yData.removeFirst(); } + if (m_xOverLimit.size() > m_maxPoints) { + m_xOverLimit.removeFirst(); + m_yOverLimit.removeFirst(); + } + + // 清理超出窗口范围的文本 + while (!m_textItems.isEmpty() && m_textItems.first()->position->key() < m_timeCounter - m_maxPoints) { + m_plot->removeItem(m_textItems.first()); + m_textItems.removeFirst(); + } m_plot->graph(0)->setData(m_xData, m_yData); + m_plot->graph(1)->setData(m_xOverLimit, m_yOverLimit); m_plot->xAxis->setRange(qMax(0.0, m_timeCounter - m_maxPoints), m_timeCounter); m_plot->replot(); } + protected: void contextMenuEvent(QContextMenuEvent* event) override { QMenu menu(this); @@ -84,20 +136,31 @@ private slots: private: void applyJsonParams() { m_maxPoints = m_json.value("maxPoints", m_maxPoints); + m_limitHigh = m_json.value("limitHigh", m_limitHigh); + m_limitLow = m_json.value("limitLow", m_limitLow); + m_title->setText(QString::fromStdString(m_json.value("key", m_title->text().toStdString()))); m_plot->clearItems(); - addLimitLines(m_json.value("limitHigh", 100.0), m_json.value("limitLow", 0.0)); + addLimitLines(m_limitHigh, m_limitLow); + + // 更新坐标范围 + m_plot->yAxis->setRange(m_limitLow - 2, m_limitHigh + 2); + + // 清空超限数据 + m_xOverLimit.clear(); + m_yOverLimit.clear(); + m_plot->replot(); } void addLimitLines(double high, double low) { auto* line1 = new QCPItemStraightLine(m_plot); - line1->setPen(QPen(Qt::red, 3, Qt::DashLine)); + line1->setPen(QPen(Qt::green, 1, Qt::DashLine)); line1->point1->setCoords(0, high); line1->point2->setCoords(1, high); auto* line2 = new QCPItemStraightLine(m_plot); - line2->setPen(QPen(Qt::red, 3, Qt::DashLine)); + line2->setPen(QPen(Qt::green, 1, Qt::DashLine)); line2->point1->setCoords(0, low); line2->point2->setCoords(1, low); } @@ -106,12 +169,15 @@ private: QVBoxLayout* m_mainLayout; QLabel* m_title; QCustomPlot* m_plot; - + QList m_textItems; QVector m_xData, m_yData; + QVector m_xOverLimit, m_yOverLimit; // 新增用于红色点 int m_maxPoints = 50; double m_timeCounter = 0; + double m_limitHigh = -1, m_limitLow = 2; }; + class SummuaryDataPage :public QWidget { Q_OBJECT public: diff --git a/src/launcher/logger/logService.cpp b/src/launcher/logger/logService.cpp index 9cdc477..5c1c127 100644 --- a/src/launcher/logger/logService.cpp +++ b/src/launcher/logger/logService.cpp @@ -35,5 +35,4 @@ logService::~logService() { delete _stdConsoleRedirector; delete _qtRediretor; - spdlog::shutdown(); } \ No newline at end of file diff --git a/src/launcher/logger/spdLogSupport.hpp b/src/launcher/logger/spdLogSupport.hpp index 295c461..1808882 100644 --- a/src/launcher/logger/spdLogSupport.hpp +++ b/src/launcher/logger/spdLogSupport.hpp @@ -5,40 +5,36 @@ #include #include #include - #define LOG_DEBUG(logger, msg) \ (logger).LogDebug((msg), __FILE__, __LINE__); class SpdLogger { public: - SpdLogger(const std::string& file_path, const std::string& file_name) { + SpdLogger(std::string& file_path, std::string file_name) { try { - // 使用同步的 daily_logger_st - logger_ = spdlog::daily_logger_st( - file_name, file_path + "/" + file_name + ".log", 0, 0); - logger_->set_level(spdlog::level::debug); - spdlog::flush_every(std::chrono::seconds(1)); + spdlog::init_thread_pool(8192, 5); // 初始化线程池 + logger_ = spdlog::daily_logger_mt( + file_name, file_path + "/" + file_name + ".log", 0, 0); // 日志按天保存 + logger_->set_level(spdlog::level::debug); // 设置日志级别为 Debug + spdlog::flush_every(std::chrono::seconds(1));//每秒写入一次 logger_->set_pattern("[%Y-%m-%d %H:%M:%S] [Thread %t] [%l] %v"); } catch (const std::exception& ex) { std::cout << "Log initialization failed: " << ex.what() << std::endl; } } - void LogDebug(const std::string& msg) { if (logger_) { logger_->debug(msg); } } - - ~SpdLogger() { - // 不再需要显式调用 shutdown(),因为使用的是同步模式 + ~SpdLogger() + { + spdlog::shutdown(); } - private: - std::shared_ptr logger_; + std::shared_ptr logger_; // 日志器实例 }; - #pragma once \ No newline at end of file diff --git a/src/mission/952_15_H_25D/952_15_H_25D.h b/src/mission/952_15_H_25D/952_15_H_25D.h index d12ad09..0593949 100644 --- a/src/mission/952_15_H_25D/952_15_H_25D.h +++ b/src/mission/952_15_H_25D/952_15_H_25D.h @@ -42,45 +42,46 @@ public: #include #include using namespace HDevEngineCpp; -static bool _952_15_H_25D_ALGO_HuaShangAI(cv::Mat& img, handleAIModels* _handleAiModels, cv::Mat& Paint, QMutex& paintMutex) { +static bool _952_15_H_25D_ALGO_HuaShangAI(std::shared_ptr data,cv::Mat& img, handleAIModels* _handleAiModels, cv::Mat& Paint, QMutex& paintMutex) { cv::Mat segImg = ~_handleAiModels->SEG_25D->Evaluate(img); std::vector> contours; cv::findContours(segImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); - bool isNg = false; + bool isOK = true; for (int i = 0; i < contours.size(); i++) { cv::Rect rect = cv::boundingRect(contours[i]); - if (rect.width < _handleAiModels->handleAI_WIDTH || rect.height < _handleAiModels->handleAI_HEIGHT) continue; // 过滤掉小轮廓 + if (rect.width < _handleAiModels->handleAI_WIDTH && rect.height < _handleAiModels->handleAI_HEIGHT) continue; // 过滤掉小轮廓 auto clsImgs = cutImg2ClsVec(rect, img); bool clsIsNg = false; for (auto& clsImg : clsImgs) { int clsResult = _handleAiModels->CLS_25D->Evaluate(clsImg); if (clsResult == 1) { // 假设1表示NG clsIsNg = true; - break; + data->clsOriginImgs.push_back({ std::to_string(i),clsImg }); } } cv::Scalar color = cv::Scalar(0, 255, 0); if (clsIsNg == true) { color = cv::Scalar(0, 0, 255); - isNg = true; - cv::approxPolyDP(contours[i], contours[i], 3, true); // 多边形拟合 - QMutexLocker locker(&paintMutex); + isOK = true; cv::Mat imgTmp; cv::cvtColor(img(rect), imgTmp, cv::COLOR_GRAY2BGR); - imgTmp.copyTo(Paint(rect)); + QMutexLocker locker(&paintMutex); + //imgTmp.copyTo(Paint(rect)); cv::drawContours(Paint, contours, i, color, 2); + cv::putText(Paint, "NG"+std::to_string(i), cv::Point(rect.x + 10, rect.y - 20), cv::FONT_HERSHEY_SIMPLEX, 0.8, color, 2); } else { - QMutexLocker locker(&paintMutex); cv::Mat imgTmp; cv::cvtColor(img(rect), imgTmp, cv::COLOR_GRAY2BGR); + QMutexLocker locker(&paintMutex); imgTmp.copyTo(Paint(rect)); cv::rectangle(Paint, rect, color, 3); } - putTextZH(Paint, "NG", cv::Point(rect.x + 10, rect.y - 20), 25, color); + + //putTextZH(Paint, "NG", cv::Point(rect.x + 10, rect.y - 20), 25, color); } - return isNg; + return isOK; } static bool _952_15_H_Algo(std::shared_ptr data, handleAIModels* _handleAIModels) @@ -103,63 +104,59 @@ static bool _952_15_H_Algo(std::shared_ptr data, handleAIModels* _hand cv::Mat src1 = data->oriImgs[1]; cv::Mat src2 = data->oriImgs[0]; cv::Mat src3 = data->oriImgs[2]; - data->oriImgs[1].copyTo(Paint); if (Paint.channels() != 3) - cv::cvtColor(Paint, Paint, cv::COLOR_GRAY2BGR); - + cv::cvtColor(src2, Paint, cv::COLOR_GRAY2BGR); + else + src2.copyTo(Paint); QMutex paintMutex; - std::future future = std::async(std::launch::async, _952_15_H_25D_ALGO_HuaShangAI, data->oriImgs[2], _handleAIModels, std::ref(Paint), std::ref(paintMutex)); - - HObject in_Image1 = MatToHObject(src1); - HObject in_Image2 = MatToHObject(src2); - HObject in_Image3 = MatToHObject(src3); - procedureCall.SetInputIconicParamObject("in_Image1", in_Image1); - procedureCall.SetInputIconicParamObject("in_Image2", in_Image2); - procedureCall.SetInputIconicParamObject("in_Image3", in_Image3); - procedureCall.SetInputCtrlParamTuple("in_xResolution", HTuple(_handleAIModels->in_xResolution)); - procedureCall.SetInputCtrlParamTuple("in_yResolution", HTuple(_handleAIModels->in_yResolution)); - procedureCall.Execute(); - + std::future future = std::async(std::launch::async, _952_15_H_25D_ALGO_HuaShangAI, data, data->oriImgs[2], _handleAIModels, std::ref(Paint), std::ref(paintMutex)); HTuple out_Distance, out_ResultRows, out_ResultCols, out_Flag, out_LinePonit; + { + HObject in_Image1 = MatToHObject(src1); + HObject in_Image2 = MatToHObject(src2); + HObject in_Image3 = MatToHObject(src3); + procedureCall.SetInputIconicParamObject("in_Image1", in_Image1); + procedureCall.SetInputIconicParamObject("in_Image2", in_Image2); + procedureCall.SetInputIconicParamObject("in_Image3", in_Image3); + procedureCall.SetInputCtrlParamTuple("in_xResolution", HTuple(_handleAIModels->in_xResolution)); + procedureCall.SetInputCtrlParamTuple("in_yResolution", HTuple(_handleAIModels->in_yResolution)); + procedureCall.Execute(); - out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance"); - //out_RightDistance = procedureCall.GetOutputCtrlParamTuple("out_RightDistance"); - out_ResultRows = procedureCall.GetOutputCtrlParamTuple("out_ResultRows"); - out_ResultCols = procedureCall.GetOutputCtrlParamTuple("out_ResultCols"); + out_Distance = procedureCall.GetOutputCtrlParamTuple("out_Distance"); + //out_RightDistance = procedureCall.GetOutputCtrlParamTuple("out_RightDistance"); + out_ResultRows = procedureCall.GetOutputCtrlParamTuple("out_ResultRows"); + out_ResultCols = procedureCall.GetOutputCtrlParamTuple("out_ResultCols"); - //out_Angle = procedureCall.GetOutputCtrlParamTuple("out_Angle"); - out_LinePonit = procedureCall.GetOutputCtrlParamTuple("out_LinePonit"); - - out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + //out_Angle = procedureCall.GetOutputCtrlParamTuple("out_Angle"); + out_LinePonit = procedureCall.GetOutputCtrlParamTuple("out_LinePonit"); + out_Flag = procedureCall.GetOutputCtrlParamTuple("out_Flag"); + } + TextRendererZH textPainter(Paint.cols, Paint.rows, 150); int algoFlag = out_Flag.D(); double LT_Distance = -1, RT_Distance = -1, LD_Distance = -1, RD_Distance = -1, L_Duiqidu = -1, R_Duiqidu = -1; if (algoFlag == 1) // 算法OK { + QMutexLocker locker(&paintMutex); LT_Distance = out_Distance[0].D() + 0.86;//左上 - putTextZH(Paint, "左上留白:" + std::to_string(LT_Distance), cv::Point(100, 200), 150, cv::Scalar(0, 255, 0)); - RT_Distance = out_Distance[1].D() + 0.52;//右上 - putTextZH(Paint, "右上留白:" + std::to_string(RT_Distance), cv::Point(100, 350), 150, cv::Scalar(0, 255, 0)); - LD_Distance = out_Distance[2].D() + 0.86;//左下 - putTextZH(Paint, "左下留白:" + std::to_string(LD_Distance), cv::Point(100, 500), 150, cv::Scalar(0, 255, 0)); - RD_Distance = out_Distance[3].D() + 0.52;//右下 - putTextZH(Paint, "右下留白:" + std::to_string(RD_Distance), cv::Point(100, 650), 150, cv::Scalar(0, 255, 0)); - + L_Duiqidu = std::abs(LT_Distance - LD_Distance); + R_Duiqidu = std::abs(RT_Distance - RD_Distance); + textPainter.putText(Paint, "左上留白:" + std::to_string(LT_Distance), cv::Point(0, 200), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "右上留白:" + std::to_string(RT_Distance), cv::Point(0, 350), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "左下留白:" + std::to_string(LD_Distance), cv::Point(0, 500), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "右下留白:" + std::to_string(RD_Distance), cv::Point(0, 650), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "左对齐度:" + std::to_string(L_Duiqidu), cv::Point(0, 800), cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "右对齐度:" + std::to_string(R_Duiqidu), cv::Point(0, 950), cv::Scalar(0, 255, 0)); int outPointRowsLength = out_ResultRows.Length(); for (int i = 0; i < outPointRowsLength; i++) Cross(Paint, cv::Point(out_ResultCols[i].D(), out_ResultRows[i].D()), 3, 2, cv::Scalar(0, 0, 255)); - - //duiqidu = out_Angle.D(); - L_Duiqidu = std::abs(LT_Distance - LD_Distance); - putTextZH(Paint, "左对齐度:" + std::to_string(L_Duiqidu), cv::Point(100, 800), 150, cv::Scalar(0, 255, 0)); - R_Duiqidu = std::abs(RT_Distance - RD_Distance); - putTextZH(Paint, "右对齐度:" + std::to_string(R_Duiqidu), cv::Point(100, 950), 150, cv::Scalar(0, 255, 0)); + int out_LinePonitLength = out_LinePonit.Length() / 4; for (int i = 0; i < out_LinePonitLength; i++) line(Paint, @@ -171,18 +168,11 @@ static bool _952_15_H_Algo(std::shared_ptr data, handleAIModels* _hand } else // 算法异常 { - putTextZH(Paint, "留白算法NG", - cv::Point(100, 200), 200, cv::Scalar(0, 0, 255)); - + QMutexLocker locker(&paintMutex); + textPainter.putText(Paint, "留白算法NG", cv::Point(0, 200), cv::Scalar(0, 0, 255)); data->halconOK = false; } - data->resultImgs.push_back(Paint); - - //data->resultImgs.push_back(Paint); - // data->sqlVec.push_back({ "Gluewidth",std::to_string(Gluewidth) }); - // data->sqlVec.push_back({ "_2dResult",std::to_string(result) }); - // qDebug() << "[Debug]2D Data:" << "hv_out_Gluewidth ::" << QString::number(Gluewidth) << ",Result" << QString::number(result); data->resultData.insert(std::make_pair("LT_Distance", LT_Distance)); data->resultData.insert(std::make_pair("RT_Distance", RT_Distance)); data->resultData.insert(std::make_pair("LD_Distance", LD_Distance)); @@ -191,13 +181,15 @@ static bool _952_15_H_Algo(std::shared_ptr data, handleAIModels* _hand data->resultData.insert(std::make_pair("R_Duiqidu", R_Duiqidu)); bool futureResult = future.get(); - if (futureResult) { - putTextZH(Paint, "模型检测结果: NG", cv::Point(100, 50), 200, cv::Scalar(0, 0, 255)); + if (futureResult) { + textPainter.putText(Paint, "模型检测结果: NG", cv::Point(0, 50), cv::Scalar(0, 0, 255)); } else { - putTextZH(Paint, "模型检测结果: OK", cv::Point(100, 50), 200, cv::Scalar(0, 255, 0)); + textPainter.putText(Paint, "模型检测结果: OK", cv::Point(0, 50), cv::Scalar(0, 255, 0)); } data->resultData.insert(std::make_pair("aiResultIsNG", futureResult)); + + cv::resize(Paint, Paint, cv::Size(), 0.5, 0.5); // 缩小结果图 data->resultImgs.push_back(Paint); data->aiDetOK = futureResult; // 如果任一检测结果为NG,则整体结果为NG @@ -247,11 +239,14 @@ public: bridge = bridgeIn; _serviceManager = _serviceManagerIN; - parseJson(_missionJson); + #pragma region 初始化外部参数 - + parseJson(_missionJson); + _handleAIModels.SEG_25D = _serviceManagerIN->_handleAiModelManager->getSegModel("SEG_25D"); + _handleAIModels.CLS_25D = _serviceManagerIN->_handleAiModelManager->getClsModel("CLS_25D"); + HDevEngineCpp::HDevEngine myEngine; + myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_952.hdpl"); #pragma endregion - #pragma region 获取相机 _25DCamera_1 = _serviceManager->_cameraManager->getCamera("25D-1"); if (_25DCamera_1 == nullptr) { @@ -279,10 +274,7 @@ public: HouDuan12ResultHandle(data); })); #pragma endregion - _handleAIModels.SEG_25D = _serviceManagerIN->_handleAiModelManager->getSegModel("SEG_25D"); - _handleAIModels.CLS_25D = _serviceManagerIN->_handleAiModelManager->getClsModel("CLS_25D"); - HDevEngineCpp::HDevEngine myEngine; - myEngine.SetProcedurePath("./halconAlgoFiles/AlgoLibrary_952.hdpl"); + return true; } //9200 1 @@ -295,18 +287,17 @@ public: "2.5D-H-1",sn, 3, _25DCamera_1->config.oriSaveFormat);//创建数据包 _25DCamera_1->captureImage(data);//拍照 //data->oriImgs.push_back(cv::imread("I:\\952Code\\CODES\\7.07\\7.07\\baoMoHou\\yh\\2025-07-07-1106069567896\\2025-07-07-11060695678962.5D-H-1_10-57-28-51_Count0.bmp", -1)); - //data->oriImgs.push_back(cv::imread("I:\\952Code\\CODES\\7.07\\7.07\\baoMoHou\\yh\\2025-07-07-1106069567896\\2025-07-07-11060695678962.5D-H-1_10-57-28-51_Count1.bmp", -1)); + // data->oriImgs.push_back(cv::imread("I:\\952Code\\CODES\\7.07\\7.07\\baoMoHou\\yh\\2025-07-07-1106069567896\\2025-07-07-11060695678962.5D-H-1_10-57-28-51_Count1.bmp", -1)); //data->oriImgs.push_back(cv::imread("I:\\952Code\\CODES\\bm\\2025-07-08-09361133675272.5D-H-1_09-27-32-22_Count2.bmp", -1)); - algo_liubai->ansyncProcess(data);//处理算法 + if(houduan1SecondTime == false) data->resultImgShowSet.push_back(new showImgPack("后段1-1", "结果图")); else data->resultImgShowSet.push_back(new showImgPack("后段1-2", "结果图")); houduan1SecondTime = !houduan1SecondTime; - + algo_liubai->ansyncProcess(data);//处理算法 qDebug() << "[ Station 10 ] " << QString::fromUtf8("2.5D-1 后段检测开始 uuid :") << data->uuid << "SN" << QString::fromStdString(sn);; - std::cout << "通道1 SN:" << sn << "检测开始" << std::endl; } //9600 1 @@ -319,16 +310,15 @@ public: std::shared_ptr data = _serviceManager->_detDataManager->createDetData( "2.5D-H-2", sn, 3, _25DCamera_2->config.oriSaveFormat);//创建数据包 _25DCamera_2->captureImage(data);//拍照 - algo_liubai->ansyncProcess(data);//处理算法 + if (houduan2SecondTime == false) data->resultImgShowSet.push_back(new showImgPack("后段2-1", "结果图")); else data->resultImgShowSet.push_back(new showImgPack("后段2-2", "结果图")); houduan2SecondTime = !houduan2SecondTime; - + algo_liubai->ansyncProcess(data);//处理算法 qDebug() << "[ Station 10 ] " << QString::fromUtf8("2.5D-2 后段检测开始 uuid :") << data->uuid << "SN" << QString::fromStdString(sn);; - std::cout << "通道2 SN:" << sn << "检测开始" << std::endl; } void HouDuan12ResultHandle(std::shared_ptr data){ @@ -380,7 +370,7 @@ public: else { qDebug() << "[ Station 10 ] " << QString::fromUtf8("后段检测结果数据为空 SN:") << QString::fromStdString(data->SNcode); } - std::cout << "SN:" << data->SNcode << "检测结束 结果获取完成" << std::endl; + qDebug() << "SN:" << QString::fromStdString(data->SNcode) << "检测结束 结果获取完成" ; } //9400 1 Summary1 diff --git a/subModule/Hd_VirualCamera/Hd_VirualCamera.cpp b/subModule/Hd_VirualCamera/Hd_VirualCamera.cpp index 9d74565..5b64d23 100644 --- a/subModule/Hd_VirualCamera/Hd_VirualCamera.cpp +++ b/subModule/Hd_VirualCamera/Hd_VirualCamera.cpp @@ -67,10 +67,11 @@ bool Hd_VirualCamera::initParas(QByteArray&, nlohmann::json& json) bool Hd_VirualCamera::run()//Èí´¥·¢ { n_mutex->lock(); - if (cameraName == "156112" || cameraName == "162762") { + if (cameraName == "25D-1" || cameraName == "25D-2") { vector mats; - mats.push_back(cv::imread("H:\\testImg\\2.5D-H-1_16-00-14-38_Count0.bmp", -1)); - mats.push_back(cv::imread("H:\\testImg\\2.5D-H-1_16-00-14-38_Count1.tiff", -1)); + mats.push_back(cv::imread("I:\\952Code\\CODES\\16H\\A2250709-162941554918413\\A2250709-1629415549184132.5D-H-2_16-31-32-65_Count0.bmp", -1)); + mats.push_back(cv::imread("I:\\952Code\\CODES\\16H\\A2250709-162941554918413\\A2250709-1629415549184132.5D-H-2_16-31-32-65_Count1.bmp", -1)); + mats.push_back(cv::imread("I:\\952Code\\CODES\\16H\\A2250709-162941554918413\\A2250709-1629415549184132.5D-H-2_16-31-32-65_Count2.bmp", -1)); queuePic.enqueue(mats); } n_mutex->unlock();