diff --git a/include/yhGlobal.h b/include/yhGlobal.h index 0038184..52657c6 100644 --- a/include/yhGlobal.h +++ b/include/yhGlobal.h @@ -1,8 +1,9 @@ #pragma once +#include #include #include #include - +#include #pragma region 基础函数 #define CATCH_EXCEPTIONS \ catch (HDevEngineCpp::HDevEngineException& ex) { \ @@ -74,14 +75,15 @@ static bool generalAlgoTest(std::shared_ptr data, detParams* _detParam cv::Mat Paint; QMutex paintMutex; clock_t start, finish; - start = clock(); - + start = clock(); cv::Mat src1 = data->oriImgs[0]; - if (src1.channels() != 3) cv::cvtColor(src1, Paint, cv::COLOR_GRAY2BGR); else src1.copyTo(Paint); + + TextRendererZH textPainter(Paint.cols, Paint.rows, 15); + textPainter.putText(Paint, "划伤", cv::Point(10,10), cv::Scalar(0, 255, 0)); cv::putText(Paint, "pos:" + data->additional["触发地址"].toString().toStdString(), cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0), 2); data->service->_triggerManager->writeShort("D" + address.resultAddr + "_1");//发送结果 data->service->_missionResultHandle->handleAllResult(data->SNcode, !defects.size() > 0, defects);//发送图标操作 diff --git a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp index 8a2a878..ea7e1fa 100644 --- a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp +++ b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp @@ -46,18 +46,30 @@ rpc_finsTcp::rpc_finsTcp(){ ifRun = true; } bool m_IsFinsTcp = false; -rpc_finsTcp::~rpc_finsTcp(){ +rpc_finsTcp::~rpc_finsTcp() { if (subThread) { - subThread->quit(); - subThread->wait(); - delete subThread; + // 断开所有信号槽连接 + subThread->disconnect(); + + // 如果线程在运行,优雅退出 + if (subThread->isRunning()) { + subThread->quit(); + // 最多等待3秒,防止死锁 + if (!subThread->wait(3000)) { + qWarning() << "subThread quit timeout!"; + } + } + // 如果 subThread 没有 parent,则需要手动 delete + if (!subThread->parent()) { + delete subThread; + } subThread = nullptr; } if (write_JsonRpcClient) { delete write_JsonRpcClient; write_JsonRpcClient = nullptr; } - qDebug() << " ~rpc_finsTcp success!"; + qDebug() << " ~rpc_finsTcp success!"; } QQueue readDataQueue; // 从类中读数据到实例对象 diff --git a/src/Core/back/cameraManager.cpp b/src/Core/back/cameraManager.cpp index 2db80b6..2bfb96b 100644 --- a/src/Core/back/cameraManager.cpp +++ b/src/Core/back/cameraManager.cpp @@ -86,11 +86,15 @@ void camera::run(){ } cameraManager::~cameraManager(){ for (auto camera : cameras) { - delete camera.second; + if (camera.second != nullptr) + delete camera.second; } + //QThread::msleep(200); for (auto& module : _cameraStructs) { - dsModuleBase* base_ptr = module.module_ptr; - delete base_ptr; + if (module.module_ptr != nullptr) { + delete module.module_ptr; + module.module_ptr = nullptr; + } } } diff --git a/src/core/back/CLIManager.h b/src/core/back/CLIManager.h index f83a37a..8e8254d 100644 --- a/src/core/back/CLIManager.h +++ b/src/core/back/CLIManager.h @@ -57,7 +57,7 @@ public: for (auto& data : _serviceManager->_triggerManager->triggerCallbackFuncs) { for (auto& callbacks : data.second) { if (callbacks.funcName.find(avoid) != std::string::npos) { - break; + continue; } QString uuid = QUuid::createUuid().toString();; auto commands = basicTriggerPresetGenerate(callbacks.triggerAddress); @@ -73,7 +73,7 @@ public: for (auto& data : _serviceManager->_triggerManager->unionTriggerCallbackFuncs) { for (auto& callbacks : data.second) { if (callbacks.funcName.find(avoid) != std::string::npos) { - break; + continue; } QString uuid = QUuid::createUuid().toString();; auto commands = basicUnionTriggerPresetGenerate(callbacks.triggerAddressAndValue); diff --git a/src/core/back/detCallbackChain.hpp b/src/core/back/detCallbackChain.hpp index 69722a2..05cd572 100644 --- a/src/core/back/detCallbackChain.hpp +++ b/src/core/back/detCallbackChain.hpp @@ -55,6 +55,7 @@ public: emit bridge->displayWidget_sendImg(pack); } } + resultHandle(data); QThread::currentThread()->quit(); } diff --git a/src/launcher/GUI/mainwindow.h b/src/launcher/GUI/mainwindow.h index f509bb2..a680c63 100644 --- a/src/launcher/GUI/mainwindow.h +++ b/src/launcher/GUI/mainwindow.h @@ -47,6 +47,9 @@ public: }; const int topBarHeight = 40; const int buttonWidth = 50; + void registerQuitFunc(std::function quitFunc) { + quitFunction = quitFunc; + } topMenuBar(QMainWindow* mainWindowIN,appConfig* configIN = nullptr,QWidget* parent = nullptr) : QWidget(parent), config(configIN), mainWindow(mainWindowIN){ @@ -190,14 +193,16 @@ public slots: } } void Quit() { - config->saveSettingJson(); qDebug() << "退出应用程序"; + quitFunction(); + config->saveSettingJson(); QApplication::quit(); // 退出应用程序 } private: QMainWindow* mainWindow; QPushButton* maximizeRestoreButton; appConfig* config; + std::function quitFunction; }; class leftMenuBar : public QWidget { public: @@ -265,6 +270,10 @@ public: qtFuncBridge* bridge = nullptr, nlohmann::ordered_json& _jsonIn = nlohmann::ordered_json()); ~MainWindow(); + void registerQuitFunc(std::function quitFunc) { + topBar->registerQuitFunc(quitFunc); + } + //主要控件 QStackedWidget stackedWidgets;//一共三层,加载界面,登录界面,主要界面 QStackedWidget pageWidgets;//主要界面中的页面 diff --git a/src/launcher/appCore.hpp b/src/launcher/appCore.hpp index 1efdb40..115522a 100644 --- a/src/launcher/appCore.hpp +++ b/src/launcher/appCore.hpp @@ -38,9 +38,12 @@ public: return true; } void releaseCore() { - backend->cleanup(); - ReleaseBackend(backend); - backend = nullptr; + if (backend != nullptr) { + backend->cleanup(); + ReleaseBackend(backend); + backend = nullptr; + } + FreeLibrary(hDll); } void excuteCli(const QString& str) { diff --git a/src/launcher/main.cpp b/src/launcher/main.cpp index 6e567b8..ddb28c3 100644 --- a/src/launcher/main.cpp +++ b/src/launcher/main.cpp @@ -19,22 +19,74 @@ #include // TCHAR 相关操作 #include // SHELLEXECUTEINFO 结构体 #include // std::cout (如果需要打印信息) +#include // CreateToolhelp32Snapshot, Process32First, Process32Next +#include // std::filesystem::path #include #pragma region 程序启动功能 -bool appIsRuning() -{ - QSystemSemaphore sema("monkey", 1, QSystemSemaphore::Open); - sema.acquire(); - QSharedMemory mem("DetUi"); - if (mem.create(1) == false) - { - sema.release(); - return false; +// 获取当前exe文件名 +std::string getCurrentExeName() { + char exePath[MAX_PATH]; + GetModuleFileNameA(NULL, exePath, MAX_PATH); + std::filesystem::path path(exePath); + return path.filename().string(); +} + +// 枚举窗口回调函数,用于置顶指定进程的窗口 +BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { + DWORD* targetPid = (DWORD*)lParam; + DWORD windowPid; + GetWindowThreadProcessId(hwnd, &windowPid); + + if (windowPid == *targetPid && IsWindowVisible(hwnd)) { + // 将窗口置顶并激活 + SetForegroundWindow(hwnd); + ShowWindow(hwnd, SW_RESTORE); + return FALSE; // 停止枚举 } - sema.release(); - return true; + return TRUE; // 继续枚举 +} + +// 检查应用是否已在运行,如果是则置顶 +bool appIsRuning(){ + std::string currentExeName = getCurrentExeName(); + DWORD currentPid = GetCurrentProcessId(); + + // 创建进程快照 + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + return true; // 如果无法创建快照,允许启动 + } + + PROCESSENTRY32 pe32; + pe32.dwSize = sizeof(PROCESSENTRY32); + + bool foundOtherInstance = false; + DWORD otherInstancePid = 0; + + // 遍历进程 + if (Process32First(hSnapshot, &pe32)) { + do { + // 比较进程名(忽略大小写) + if (_stricmp(pe32.szExeFile, currentExeName.c_str()) == 0 && + pe32.th32ProcessID != currentPid) { + foundOtherInstance = true; + otherInstancePid = pe32.th32ProcessID; + break; + } + } while (Process32Next(hSnapshot, &pe32)); + } + + CloseHandle(hSnapshot); + + if (foundOtherInstance) { + // 找到其他实例,将其置顶 + EnumWindows(EnumWindowsProc, (LPARAM)&otherInstancePid); + return false; // 返回false表示已有实例在运行 + } + + return true; // 没有其他实例在运行 } #pragma endregion static bool dumpCallback(const wchar_t* dump_path, @@ -170,5 +222,11 @@ int main(int argc, char* argv[]) _core._logService->disableConsole(); }// 隐藏控制台窗口 #endif + w.registerQuitFunc([&]() { + _core._backEnd.releaseCore(); // 释放核心功能 + QThread::msleep(100); + if (config.dataBase) delete config.dataBase; + config.dataBase = nullptr; + }); return a.exec(); } \ No newline at end of file diff --git a/src/mission/581-BaoMo-Cam1234/581-BaoMo.h b/src/mission/581-BaoMo-Cam1234/581-BaoMo.h index 98d1648..913788c 100644 --- a/src/mission/581-BaoMo-Cam1234/581-BaoMo.h +++ b/src/mission/581-BaoMo-Cam1234/581-BaoMo.h @@ -1,5 +1,4 @@ -#include -#include +#include struct _581_BaoMoResult { bool result = true; @@ -221,7 +220,8 @@ static bool ALGO_BaoMoHouDaMian(std::shared_ptr data, //else { // textPainter.putText(Paint, "算法异常", cv::Point(50, 300), cv::Scalar(0, 0, 255)); //} - + data->service->_triggerManager->writeFloat("D" + address.resultAddr + "_1");//发送OK + data->service->_triggerManager->writeFloat("D" + QByteArray::number(address.valueOffsetAddr) + "_0.0123");//发送偏移X data->resultImgs.push_back(Paint); return false; diff --git a/src/mission/581-BaoMo-Cam5678/581-BaoMo.h b/src/mission/581-BaoMo-Cam5678/581-BaoMo.h index aac6b37..950ff17 100644 --- a/src/mission/581-BaoMo-Cam5678/581-BaoMo.h +++ b/src/mission/581-BaoMo-Cam5678/581-BaoMo.h @@ -8,9 +8,9 @@ struct _581_BaoMoResult }; class baoMoHouDaMianDetParams { public: - handleAiModelSeg* seg; - handleAiModelCls* cls; - handleAiModelCls* cls2; + handleAiModelSeg* seg = nullptr; + handleAiModelCls* cls = nullptr; + handleAiModelCls* cls2 = nullptr; }; #pragma region 算法 #include @@ -19,6 +19,8 @@ public: using namespace HDevEngineCpp; std::vector BaoMoHou_DaMianAi(std::shared_ptr data, cv::Mat src, cv::Mat& Paint, baoMoHouDaMianDetParams* _detParams) { + if (_detParams->seg == nullptr || _detParams->cls == nullptr || _detParams->cls2 == nullptr) + return {}; std::vector defects; TextRendererZH textPainter(Paint.cols, Paint.rows, 150); bool huaShangNg = false; @@ -62,7 +64,7 @@ std::vector BaoMoHou_DaMianAi(std::shared_ptr data, cv::M } #pragma endregion #pragma region 算法 -static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address addresss) +static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address address) { qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; @@ -130,6 +132,7 @@ static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianD data->resultImgs.push_back(Paint); data->service->_missionResultHandle->handleAllResult(data->SNcode, !defects.size() > 0, defects); + data->service->_triggerManager->writeFloat("D" + address.resultAddr + "_1");//发送OK return true; } //class _581Baomo_BaoMoHouShangDaMian { @@ -182,7 +185,7 @@ static bool BaoMoHou_ShangDaMian(std::shared_ptr data, baoMoHouDaMianD // qtFuncBridge* bridge; // ServiceManager* _serviceManager = nullptr; //}; -static bool BaoMoHou_XiaDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address addresss) +static bool BaoMoHou_XiaDaMian(std::shared_ptr data, baoMoHouDaMianDetParams* _detParams, yh_581_address address) { qDebug() << "SN" << QString::fromStdString(data->SNcode) << "algo start"; @@ -249,7 +252,7 @@ static bool BaoMoHou_XiaDaMian(std::shared_ptr data, baoMoHouDaMianDet //} data->resultImgs.push_back(Paint); - + data->service->_triggerManager->writeFloat("D" + address.resultAddr + "_1");//发送OK return true; } //class _581Baomo_BaoMoHouXiaDaMian { diff --git a/subModule/Hd_CameraModule_HIK_hard_PCIE.cpp b/subModule/Hd_CameraModule_HIK_hard_PCIE.cpp new file mode 100644 index 0000000..3116cf3 --- /dev/null +++ b/subModule/Hd_CameraModule_HIK_hard_PCIE.cpp @@ -0,0 +1,570 @@ +#include "Hd_CameraModule_HIK_hard_PCIE.h" +#include +using namespace std; +#include +QByteArray mv_Status = "connected";//0106 新增相机断联报警 +long long index = 0; //相机序号 +void* handle; +string Username = ""; +bool m_flag = false; +//MV_CC_DEVICE_INFO_LIST m_stDevList;//相机设备 +bool moduleStatus = true; +QQueue queuepic; +//data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。 +bool ifBreak = false; +//ifRunning减少ifBreak的判断;"rest_newProductIn"时,Logic_camera_thread框架会结束未处理完的相相机取图 +bool ifRunning = false; + +MV_GENTL_DEV_INFO_LIST m_stDevList; // ch:设备信息列表结构体变量,用来存储设备列表 +MV_GENTL_IF_INFO_LIST m_stIFList; +void CloseDevice(); +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; +} +QMutex* n_mutex = new QMutex(); +//cv::Mat srcImage; +//是否为标准通信流程: +//标准通信流程,run函数设置曝光/增益;非标准通信流程(简单通信流程),回调函数设置曝光/增益 +int imgCnt = 0; +bool ifStandard = false; +//相机取图超时时间 +int getImageTimeOut = 3000; +//总取图数 +int imgIndex = 0; +//曝光值列表 +QQueue expourseTimeList; +//增益列表 +QQueue gainList; + +bool IsColor(MvGvspPixelType enType) +{ + switch (enType) + { + case PixelType_Gvsp_RGB8_Packed: + case PixelType_Gvsp_YUV422_Packed: + case PixelType_Gvsp_YUV422_YUYV_Packed: + case PixelType_Gvsp_BayerGR8: + case PixelType_Gvsp_BayerRG8: + case PixelType_Gvsp_BayerGB8: + case PixelType_Gvsp_BayerBG8: + case PixelType_Gvsp_BayerGB10: + case PixelType_Gvsp_BayerGB10_Packed: + case PixelType_Gvsp_BayerBG10: + case PixelType_Gvsp_BayerBG10_Packed: + case PixelType_Gvsp_BayerRG10: + case PixelType_Gvsp_BayerRG10_Packed: + case PixelType_Gvsp_BayerGR10: + case PixelType_Gvsp_BayerGR10_Packed: + case PixelType_Gvsp_BayerGB12: + case PixelType_Gvsp_BayerGB12_Packed: + case PixelType_Gvsp_BayerBG12: + case PixelType_Gvsp_BayerBG12_Packed: + case PixelType_Gvsp_BayerRG12: + case PixelType_Gvsp_BayerRG12_Packed: + case PixelType_Gvsp_BayerGR12: + case PixelType_Gvsp_BayerGR12_Packed: + return true; + default: + return false; + } +} +//0106 断线重连 +void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser); +void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0); +//搜索所有设备 +int SearchDevice() +{ + //MV_CC_Initialize(); + /* MV_CC_DEVICE_INFO_LIST stDeviceList; + memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST)); + unsigned int nnRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE | MV_GENTL_CAMERALINK_DEVICE | MV_GENTL_CXP_DEVICE | MV_GENTL_XOF_DEVICE, &stDeviceList); + return 1;*/ + const char* chCtiPath = "MvFGProducerXoF.cti";//.cti文件路径 + int nRet = 0; + nRet = MV_CC_EnumInterfacesByGenTL(&m_stIFList, chCtiPath); + if (nRet != MV_OK) + { + qDebug() << "EnumInterfacsByGenTL fail"; + return 0; + } + + if (m_stIFList.nInterfaceNum == 0) + { + qDebug() << "No Device"; + return 0; + } + + // ch:枚举子网内所有设备 | en:Enumerate all devices within subnet + for (int p = 0; p < m_stIFList.nInterfaceNum; p++) + { + memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST)); + nRet = MV_CC_EnumDevicesByGenTL(m_stIFList.pIFInfo[p], &m_stDevList); + bool ifHas = false; + for (int i = 0; i < m_stDevList.nDeviceNum; i++) + { + //SN + unsigned char* name = m_stDevList.pDeviceInfo[i]->chSerialNumber; + string userName = static_cast((LPCSTR)name); + if (Username == userName) + { + index = i; + ifHas = true; + break; + } + } + if (ifHas)break; + } + if (MV_OK != nRet) + { + return 0; + } + return -1; +} + +bool connectDevice() +{ + //MV_CC_Initialize(); + index = -1; + SearchDevice(); + if (index == -1) + { + //未匹配到相机 + //qDebug() << "[Waring] " << "Hd_CameraModule_HIK not match --CameraName:" << QString::fromStdString(Username); + return false; + } + unsigned char* name = m_stDevList.pDeviceInfo[index]->chSerialNumber; + string userName = static_cast((LPCSTR)name); + qDebug() << "[INFO] " << " start" << "--UserName:" << QString::fromStdString(userName); + if (handle != NULL) + { + MV_CC_StopGrabbing(handle); + MV_CC_CloseDevice(handle); + MV_CC_DestroyHandle(handle); + } + + //打开相机 + MV_CC_CreateHandleByGenTL(&handle, m_stDevList.pDeviceInfo[index]); + int nRet = MV_CC_OpenDevice(handle); + ////触发模式 + MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0); + MV_CC_SetEnumValue(handle, "TriggerMode", MV_TRIGGER_MODE_ON); + // //加载用户集,相机设置应当UserSet1 + nRet = MV_CC_SetEnumValueByString(handle, "UserSetSelector", "UserSet1"); + if (MV_OK != nRet) + { + qDebug() << "Set UserSetSelector fail! nRet " << nRet; + } + // ch:注册抓图回调 | en:Register image callback + MV_CC_SetIntValueEx(handle, "GevHeartbeatTimeout", 3000);//心跳日志 + + nRet = MV_CC_RegisterImageCallBackEx(handle, ImageCallBackEx, handle);//注册回调 + if (MV_OK != nRet) + return false; + nRet = MV_CC_RegisterExceptionCallBack(handle, ReconnectDevice, NULL);//断线重连 + if (MV_OK != nRet) + return false; + MV_CC_StartGrabbing(handle); + return true; +} +void SetExposureTime(float exposureValue) +{ + qDebug() << "[INFO] " << "exposureValue:" << exposureValue; + MV_CC_SetEnumValue(handle, "ExposureAuto", MV_EXPOSURE_AUTO_MODE_OFF); + MV_CC_SetFloatValue(handle, "ExposureTime", exposureValue); +} + +void SetGain(float GainValue) +{ + qDebug() << "[INFO] " << "GainValue:" << GainValue; + MV_CC_SetEnumValue(handle, "GainAuto", 0); + MV_CC_SetFloatValue(handle, "Gain", GainValue); +} + +//0518 断线重连 +void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser) +{ + mv_Status = "disconnect"; + qDebug() << "[Error] " << " MV camera disconnects!"; + moduleStatus = false; + if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT) + { + //断开连接 + CloseDevice(); + handle = nullptr; + BOOL bConnected = FALSE; + while (1) + { + Sleep(100); + if (connectDevice() == true) + { + qWarning() << "[Hd_CameraModule_HIK] " << " Hd_CameraModule_HIK create success again! "; + moduleStatus = true; + break; + } + + } + } +} + +//0106 断连提示 +void _stdcall ExceptionCB(unsigned int nMesgType, void* pUser) { + mv_Status = "disconnect"; + qDebug() << "[Error] " << " MvCameraTL disconnects!"; +} + + +Hd_CameraModule_HIK_hard_PCIE* create() +{ + qDebug() << "[INFO] " << "Hd_CameraModule_HIK create success!"; + return new Hd_CameraModule_HIK_hard_PCIE; +} + +void destory(Hd_CameraModule_HIK_hard_PCIE* ptr) +{ + if (ptr) + { + delete ptr; + ptr = nullptr; + } + qDebug() << "[INFO] " << "Hd_CameraModule_HIK destory success!"; +} + +//回调函数; +//经测试,相机像素格式Mono8、RGB8是可以正常转换的,YUV422还需要优化;RGB8格式比YUV422帧率低;BGR格式会导致异色问题 +void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0) +{ + Q_UNUSED(pUser0) + int frameNum = 0; + double time_Start = (double)clock(); + n_mutex->lock(); + cv::Mat srcImage = cv::Mat(); + //qDebug() << "[info]" << __FUNCTION__ << " line:" << __LINE__ << "--- start"; + if (pFrameInfo0) + { + //获取的是单通道灰度图 + if (pFrameInfo0->enPixelType == PixelType_Gvsp_Mono8)//获取当前采集到的图像格式 + { + srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC1, pData0); + } + //获取的是RGB8图 + else if (pFrameInfo0->enPixelType == PixelType_Gvsp_BGR8_Packed) + { + srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pData0); + + //cvtColor(srcImage, srcImage, COLOR_RGB2BGR);//导致异色 + } + else if (IsColor(pFrameInfo0->enPixelType)) //其它格式彩色图 + { + MvGvspPixelType enDstPixelType = PixelType_Gvsp_Undefined; + enDstPixelType = PixelType_Gvsp_BGR8_Packed; + unsigned char* pConvertData = NULL; + pConvertData = (unsigned char*)malloc(pFrameInfo0->nWidth * pFrameInfo0->nHeight * 3); + if (NULL == pConvertData) + { + printf("malloc pConvertData fail!\n"); + } + else + { + unsigned int nConvertDataSize = 0; + nConvertDataSize = pFrameInfo0->nWidth * pFrameInfo0->nHeight * 3; + + // ch:像素格式转换 | en:Convert pixel format + MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 }; + + frameNum = pFrameInfo0->nFrameNum; //ch:帧号 | en:frame number + stConvertParam.nWidth = pFrameInfo0->nWidth; //ch:图像宽 | en:image width + stConvertParam.nHeight = pFrameInfo0->nHeight; //ch:图像高 | en:image height + stConvertParam.pSrcData = pData0; //ch:输入数据缓存 | en:input data buffer + stConvertParam.nSrcDataLen = pFrameInfo0->nFrameLen; //ch:输入数据大小 | en:input data size + stConvertParam.enSrcPixelType = pFrameInfo0->enPixelType; //ch:输入像素格式 | en:input pixel format + stConvertParam.enDstPixelType = enDstPixelType; //ch:输出像素格式 | en:output pixel format + stConvertParam.pDstBuffer = pConvertData; //ch:输出数据缓存 | en:output data buffer + stConvertParam.nDstBufferSize = nConvertDataSize; //ch:输出缓存大小 | en:output buffer size + int nRet = MV_CC_ConvertPixelType(handle, &stConvertParam); + + Mat mysrcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, stConvertParam.pDstBuffer); + mysrcImage.copyTo(srcImage); + + free(pConvertData); + pConvertData = NULL; + stConvertParam = { 0 }; + } + } + } + if (srcImage.empty()) + { + srcImage = cv::Mat(5, 5, CV_8UC1).setTo(0); + } + if (ifStandard == false) + { + imgIndex++; + if (expourseTimeList.size() > 1 && expourseTimeList[imgIndex % expourseTimeList.size()] != expourseTimeList[(imgIndex - 1) % expourseTimeList.size()]) + SetExposureTime(expourseTimeList[imgIndex % expourseTimeList.size()]); + if (gainList.size() > 1 && gainList[imgIndex % gainList.size()] != gainList[(imgIndex - 1) % gainList.size()]) + SetGain(gainList[imgIndex % gainList.size()]); + } + queuepic.push_back(srcImage); + m_flag = true; + n_mutex->unlock(); + pData0 = { 0 }; + imgCnt++; + double time_End = (double)clock(); + std::cout << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getImg,Time:" << (time_End - time_Start) << "ms" + << "--CameraName:" << Username << " imgIndex:" << imgCnt << "nFrameNum : " << frameNum << std::endl; + qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getImg,Time:" << (time_End - time_Start) << "ms" + << "--CameraName:" << QString::fromStdString(Username) << " imgIndex:" << imgCnt << "nFrameNum : " << frameNum; +} + +Hd_CameraModule_HIK_hard_PCIE::Hd_CameraModule_HIK_hard_PCIE() +{ + //m_thread = new MyThread; + //m_mutex = new QMutex(); +} +//关闭设备 +void CloseDevice() +{ + if (handle == nullptr) + return; + unsigned int nRet = MV_CC_StopGrabbing(handle); + if (nRet == 0) { + MV_CC_CloseDevice(handle); + MV_CC_DestroyHandle(handle); + } + //nRet = MV_CC_CloseDevice(handle); + //nRet = MV_CC_DestroyHandle(handle); +} +Hd_CameraModule_HIK_hard_PCIE::~Hd_CameraModule_HIK_hard_PCIE() +{ + CloseDevice(); + if (n_mutex) + { + delete n_mutex; + n_mutex = nullptr; + } + + qDebug() << "[INFO] " << " delete success!"; +} +//从类中读数据到实例对象 +bool Hd_CameraModule_HIK_hard_PCIE::readData(std::vector& mat, QByteArray& data) +{ + if (queuepic.isEmpty()) + { + //qCritical() << __FUNCTION__ << " line:" <<__LINE__ << " srcImage is null"; + return false; + } + n_mutex->lock(); + cv::Mat img = queuepic.dequeue(); + mat.push_back(img); + queuepic.clear(); + n_mutex->unlock(); + + qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData--CameraName:" << QString::fromStdString(Username) << "--imgIndex : " << imgIndex; + return true; +} + +//实例对象把数据写入到类;加载模型后会运行此函数 +bool Hd_CameraModule_HIK_hard_PCIE::writeData(std::vector& mat, QByteArray& data) +{ + Q_UNUSED(mat); + QStringList dataList = QString::fromUtf8(data).split("_"); + //2024.02.18更新,相机对应的读SN信号时,表示新产品进入,设置初始值 + if (data == "rest_newProductIn") + { + //根据实际项目,设置初始值:曝光、增益,ROI区域等 + { + if (expourseTimeList.size() > 0) + SetExposureTime(expourseTimeList[0]); + if (gainList.size() > 0) + SetGain(gainList[0]); + } + if (queuepic.size() > 0) + { + n_mutex->lock(); + queuepic.clear(); + n_mutex->unlock(); + std::cout << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << Username << std::endl; + qWarning() << __FUNCTION__ << " line: " << __LINE__ << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << QString::fromStdString(Username); + } + if (ifRunning == true) + { + ifBreak = true; + Sleep(10); + } + imgIndex = 0; + return true; + } + else if (dataList.size() > 1) { + if (dataList[0] == "cameraTriggerSignal") { + imgShouldGetVec.clear(); + imgShouldGetIndex = 0; + for (int i = 1; i < dataList.size(); i++) + imgShouldGetVec.push_back(dataList[i].toInt()); + } + } + else + { + m_flag = false; + expourseTimeList.clear(); + gainList.clear(); + } + //Username= data.toStdString(); + return true; +} +//传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... +bool Hd_CameraModule_HIK_hard_PCIE::initParas(QByteArray& initData) +{ + QByteArrayList valueList = initData.split('+'); + Username = valueList[0]; + imgIndex = 0; + expourseTimeList.clear(); + gainList.clear(); + if (valueList.size() > 1) + for (int i = 1; i < valueList.size(); i++) + { + QString valuei = byteArrayToUnicode(valueList[i]); + //valuei.prepend(valueList[i]); + if (valuei.contains("expourseTime")) + { + QStringList expourseTimeL = valuei.split('#'); + if (expourseTimeL.size() > 1) + for (int j = 1; j < expourseTimeL.size(); j++) + expourseTimeList.enqueue(expourseTimeL[j].toFloat()); + } + if (valuei.contains("gain")) + { + QStringList gainL = valuei.split('#'); + if (gainL.size() > 1) + for (int j = 1; j < gainL.size(); j++) + gainList.enqueue(gainL[j].toFloat()); + } + + if (valuei.contains("是否为标准通信流程")) + { + if (valuei.contains("true")) + ifStandard = true; + } + if (valuei.contains("取图超时")) + { + QStringList gainL = valuei.split('#'); + if (gainL.size() > 1) + getImageTimeOut = gainL[1].toInt(); + if (getImageTimeOut < 50) + getImageTimeOut = 1000; + } + if (valuei.contains("OffsetX")) + { + QStringList valueL = valuei.split('#'); + if (valueL.size() > 1) + if (valueL[1].toInt() >= 0) + MV_CC_SetIntValue(handle, "OffsetX", valueL[1].toInt()); + } + if (valuei.contains("OffsetY")) + { + QStringList valueL = valuei.split('#'); + if (valueL.size() > 1) + if (valueL[1].toInt() >= 0) + MV_CC_SetIntValue(handle, "OffsetY", valueL[1].toInt()); + } + if (valuei.contains("Width")) + { + QStringList valueL = valuei.split('#'); + if (valueL.size() > 1) + if (valueL[1].toInt() >= 0) + MV_CC_SetIntValue(handle, "Width", valueL[1].toInt()); + } + if (valuei.contains("Height")) + { + QStringList valueL = valuei.split('#'); + if (valueL.size() > 1) + if (valueL[1].toInt() >= 0) + MV_CC_SetIntValue(handle, "Height", valueL[1].toInt()); + } + } + + bool ifOk = connectDevice(); + if (ifOk == true) + { + if (expourseTimeList.size() > 0) + SetExposureTime(expourseTimeList[0]); + if (gainList.size() > 0) + SetGain(gainList[0]); + } + imgIndex = 0; + return ifOk; +} + +bool Hd_CameraModule_HIK_hard_PCIE::run() +{ + + qDebug() << "[INFO] " << " run start" << QString::fromStdString(Username); + bool result = false; + ifRunning = true; + ifBreak = false; + try + { + m_flag = false; + int mytime = 0; + int cnt = 0; + while (true) + { + /* if (moduleStatus == false || mytime++ > getImageTimeOut || ifBreak == true) + { + result = false; + break; + }*/ + + cnt++; + if (queuepic.size() > 0) + { + result = true; + std::cout << "\n gotImg" << std::endl; + break; + } + if (cnt > 2000) { + n_mutex->lock(); + //queuepic.push_back(cv::imread("D://Image_20250809202445856.bmp", -1)); + queuepic.push_back(cv::Mat(200, 200, CV_8UC3, cv::Scalar(0, 255, 0))); //返回空图 + std::cout << "timeout" << std::endl; + n_mutex->unlock(); + return true; + } + QThread::msleep(1); + } + //考虑到误触发、漏触发的图,在这里进行设置。 + //需要设置曝光时 + if (ifStandard == true) + { + imgIndex++; + if (expourseTimeList.size() > 1 && expourseTimeList[imgIndex % expourseTimeList.size()] != expourseTimeList[(imgIndex - 1) % expourseTimeList.size()]) + SetExposureTime(expourseTimeList[imgIndex % expourseTimeList.size()]); + if (gainList.size() > 1 && gainList[imgIndex % gainList.size()] != gainList[(imgIndex - 1) % gainList.size()]) + SetGain(gainList[imgIndex % gainList.size()]); + } + } + catch (QString ev) + { + qDebug() << "[Error] " << " ev:" << ev; + } + qDebug() << "[INFO] " << __LINE__ << " run end"; + return result; +} + +//相机连接状态:正常连接或断开 +bool Hd_CameraModule_HIK_hard_PCIE::checkStatus() +{ + //status = moduleStatus; + return moduleStatus; +} + diff --git a/subModule/Hd_CameraModule_HIK_hard_PCIE.h b/subModule/Hd_CameraModule_HIK_hard_PCIE.h new file mode 100644 index 0000000..5bf23b2 --- /dev/null +++ b/subModule/Hd_CameraModule_HIK_hard_PCIE.h @@ -0,0 +1,43 @@ +#ifndef Hd_CameraModule_HIK_hard_PCIE_H +#define Hd_CameraModule_HIK_hard_PCIE_H +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace cv; +#pragma execution_character_set("utf-8") + +class Hd_CameraModule_HIK_hard_PCIE :public dsModuleBase +{ +public: + Hd_CameraModule_HIK_hard_PCIE(); + virtual ~Hd_CameraModule_HIK_hard_PCIE(); + //从类中读数据到实例对象 + bool readData(std::vector& mat, QByteArray& data); + //实例对象把数据写入到类 + bool writeData(std::vector& mat, QByteArray& data); + bool initParas(QByteArray& initData); + bool run(); + bool checkStatus(); +private: + std::vector imgShouldGetVec; + int imgShouldGetIndex = 0; + //MyThread *m_thread = nullptr; + //QMutex* m_mutex; +}; + +extern "C" +{ +Q_DECL_EXPORT Hd_CameraModule_HIK_hard_PCIE * create(); +Q_DECL_EXPORT void destory(Hd_CameraModule_HIK_hard_PCIE * ptr); +} + +#endif // Hd_CameraModule_HIK_hard_H +//Hd_CameraModule_HIK_hard_PCIE