diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0d8a775 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "xutility": "cpp" + } +} \ No newline at end of file diff --git a/rpcModule/rpc_finsTcp/json_rpc_server_1_0_0.exe b/rpcModule/rpc_finsTcp/json_rpc_server_1_1_0.exe similarity index 93% rename from rpcModule/rpc_finsTcp/json_rpc_server_1_0_0.exe rename to rpcModule/rpc_finsTcp/json_rpc_server_1_1_0.exe index 2a6898d..ad00ec9 100644 Binary files a/rpcModule/rpc_finsTcp/json_rpc_server_1_0_0.exe and b/rpcModule/rpc_finsTcp/json_rpc_server_1_1_0.exe differ diff --git a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp index 0c2b739..1fe1ee9 100644 --- a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp +++ b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp @@ -8,6 +8,23 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + static QProcess* process = nullptr; static HANDLE jobHandle = nullptr; rpc_finsTcp* create() @@ -61,9 +78,8 @@ bool rpc_finsTcp::readData(std::vector& vec_mat, QByteArray& data) ptr = new JsonRpcClient("127.0.0.1", 9000); read_JsonRpcClient[data] = ptr; } - //auto result = read_JsonRpcClient[data]->call("excuteCli", QJsonArray{ QString(data) }, "finstcp"); - //data = variantListToByteArray(result); - data = ptr->finsReadCall("excuteCli", QString(data), "finstcp"); + QByteArray resp = ptr->finsReadCall("excuteCli", QString(data), "finstcp"); + data = resp; // 已是解码后的原始字节 return true; } bool ifRetryCMD = false; @@ -136,6 +152,8 @@ bool rpc_finsTcp::writeData(std::vector& vec_mat, QByteArray& data){ readDataQueue.append(data); } else { + if (data.contains("null")) + return true; if(data.contains("Heart") == false) qDebug() << data; emit writeCallSignal("excuteCli", QJsonArray{ QString(data) }, "finstcp"); @@ -146,7 +164,7 @@ bool rpc_finsTcp::writeData(std::vector& vec_mat, QByteArray& data){ bool rpc_finsTcp::initParas(QByteArray& data){ - startProcess("./json_rpc_server.exe"); + startProcess("./json_rpc_server_1_1_0.exe"); subThread = new QThread(this); write_JsonRpcClient = new JsonRpcClientWorker(); write_JsonRpcClient->moveToThread(subThread); @@ -220,161 +238,150 @@ bool JsonRpcClient::reconnect() { return false; } } -QVariant jsonToVariant(const nlohmann::json& j) -{ - if (j.is_null()) return QVariant(); - if (j.is_boolean()) return j.get(); - if (j.is_number_integer()) return j.get(); - if (j.is_number_unsigned()) return static_cast(j.get()); - if (j.is_number_float()) return j.get(); - if (j.is_string()) return QString::fromStdString(j.get()); - - if (j.is_array()) { - QVariantList list; - for (const auto& el : j) list.append(jsonToVariant(el)); - return list; - } - - if (j.is_object()) { - QVariantMap map; - for (auto it = j.begin(); it != j.end(); ++it) - map[QString::fromStdString(it.key())] = jsonToVariant(it.value()); - return map; - } - - return QVariant(); // fallback -} QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module) { QMutexLocker locker(&mutex_); if (socket_.state() != QAbstractSocket::ConnectedState) { - qWarning() << "[JsonRpcClient] Socket not connected."; if (!reconnect()) return QVariant(); } - - QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":%2,"id":%3)") - .arg(method) - .arg(QString::fromUtf8(QJsonDocument(params).toJson(QJsonDocument::Compact))) - .arg(idCounter_++); - if (!module.isEmpty()) { - reqStr += QString(R"(,"module":"%1")").arg(module); - } - reqStr += "}"; - - if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) { - qWarning() << "[JsonRpcClient] Write failed."; - return QVariant(); - } - - if (!socket_.waitForReadyRead(10000)) { - qWarning() << "[JsonRpcClient] Read timeout."; - return QVariant(); - } - - QByteArray responseData = socket_.readAll(); - - // 使用 nlohmann json 替代 Qt 解析 - try { - auto respJson = nlohmann::json::parse(responseData.constData(), responseData.constData() + responseData.size()); - - if (respJson.contains("error")) { - qWarning() << "[JsonRpcClient] Error:" << QString::fromStdString(respJson["error"].dump()); - return QVariant(); - } - - return jsonToVariant(respJson["result"]); - } - catch (const nlohmann::json::parse_error& e) { - qWarning() << "[JsonRpcClient] Parse error:" << e.what(); - return QVariant(); - } -} -QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) { - QMutexLocker locker(&mutex_); - if (socket_.state() != QAbstractSocket::ConnectedState) { - qWarning() << "[JsonRpcClient] Socket not connected."; - if (!reconnect()) return QByteArray(); - } - - QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":["%2"],"id":%3)") - .arg(method) - .arg(params) - .arg(idCounter_++); - if (!module.isEmpty()) { - reqStr += QString(R"(,"module":"%1")").arg(module); - } - reqStr += "}"; - - if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) { - qWarning() << "[JsonRpcClient] Write failed."; - return QByteArray(); - } - - if (!socket_.waitForReadyRead(10000)) { - qWarning() << "[JsonRpcClient] Read timeout."; - return QByteArray(); - } - - QByteArray responseData = socket_.readAll(); - - // 仅用QByteArray查找和分割功能解析result数组 - if (responseData.contains("error")) { - qWarning() << "[JsonRpcClient] Error in response:" << responseData; - return QByteArray(); - } - - // 查找 "result": [ 和对应的 ] - int resultPos = responseData.indexOf("\"result\""); - if (resultPos == -1) { - qWarning() << "[JsonRpcClient] No result field in response:" << responseData; - return QByteArray(); - } - int arrayStart = responseData.indexOf('[', resultPos); - int arrayEnd = responseData.indexOf(']', arrayStart); - if (arrayStart == -1 || arrayEnd == -1 || arrayEnd <= arrayStart) { - qWarning() << "[JsonRpcClient] Result array not found or malformed:" << responseData; - return QByteArray(); - } - - QByteArray arrayContent = responseData.mid(arrayStart + 1, arrayEnd - arrayStart - 1); - // 按逗号分割 - QList items = arrayContent.split(','); - - QByteArray result; - for (QByteArray item : items) { - item = item.trimmed(); - bool ok = false; - int val = item.toInt(&ok); - if (ok) { - result.append(static_cast(val)); - } else if (!item.isEmpty()) { - qWarning() << "[JsonRpcClient] Non-integer value in result array:" << item; - return QByteArray(); - } - } - return result; -} -void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) { - if (socket_.state() != QAbstractSocket::ConnectedState) { - qWarning() << "[JsonRpcClient] Socket not connected, trying to reconnect..."; - if (!reconnect()) return; - } - - QJsonObject request{ + int myId = idCounter_++; + QJsonObject req{ {"jsonrpc", "2.0"}, {"method", method}, {"params", params}, - {"id", idCounter_++} + {"id", myId} }; - if (!module.isEmpty()) { - request["module"] = module; + if (!module.isEmpty()) req.insert("module", module); + + QJsonObject resp = sendRequestBuildAndAwait(req); + if (resp.contains("error")) { + qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(resp["error"].toObject()).toJson(QJsonDocument::Compact); + return QVariant(); + } + if (!resp.contains("result")) return QVariant(); + QJsonValue r = resp.value("result"); + if (r.isString()) return r.toString(); + if (r.isDouble()) return r.toDouble(); + if (r.isBool()) return r.toBool(); + if (r.isArray()) return r.toArray().toVariantList(); + if (r.isObject()) return r.toObject().toVariantMap(); + return QVariant(); +} + +QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) { + QMutexLocker locker(&mutex_); + if (socket_.state() != QAbstractSocket::ConnectedState) { + if (!reconnect()) return QByteArray(); + } + int myId = idCounter_++; + QJsonArray p; p.append(params); + QJsonObject req{{"jsonrpc","2.0"},{"method",method},{"params",p},{"id",myId}}; + if (!module.isEmpty()) req.insert("module", module); + + QJsonDocument doc(req); + QByteArray payload = doc.toJson(QJsonDocument::Compact); + if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) { + qWarning() << "[JsonRpcClient] Write failed."; + return QByteArray(); } - QJsonDocument doc(request); - QByteArray data = doc.toJson(QJsonDocument::Compact); - - if (socket_.write(data) == -1 || !socket_.waitForBytesWritten(1000)) { - qWarning() << "[JsonRpcClient] Write failed:" << socket_.errorString(); - return; + QJsonObject respObj; + if (!waitAndReadResponse(myId, respObj)) { + qWarning() << "[JsonRpcClient] Read timeout or parse error."; + return QByteArray(); } + + if (respObj.contains("error")) { + qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(respObj["error"].toObject()).toJson(QJsonDocument::Compact); + return QByteArray(); + } + QString b64 = respObj.value("result").toString(); + QByteArray decoded = QByteArray::fromBase64(b64.toUtf8()); + return decoded; +} + +QList JsonRpcClient::extractJsonFrames(QByteArray& buffer) { + QList frames; + int start = -1; + int braceDepth = 0; + bool inString = false; + char prev = 0; + for (int i = 0; i < buffer.size(); ++i) { + char c = buffer[i]; + if (c == '"' && prev != '\\') inString = !inString; + if (!inString) { + if (c == '{') { + if (braceDepth == 0) start = i; + braceDepth++; + } else if (c == '}') { + braceDepth--; + if (braceDepth == 0 && start != -1) { + int len = i - start + 1; + frames.append(buffer.mid(start, len)); + start = -1; + } + } + } + prev = c; + } + if (braceDepth == 0) { + if (!frames.isEmpty()) { + int lastEnd = buffer.lastIndexOf('}'); + if (lastEnd != -1) buffer = buffer.mid(lastEnd + 1); + } + } else { + if (start > 0) buffer = buffer.mid(start); + } + return frames; +} + +bool JsonRpcClient::waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs) { + QElapsedTimer timer; timer.start(); + while (timer.elapsed() < timeoutMs) { + if (socket_.bytesAvailable() == 0) { + int remain = timeoutMs - (int)timer.elapsed(); + if (!socket_.waitForReadyRead(qMin(remain, 1000))) { + continue; + } + } + QByteArray chunk = socket_.readAll(); + if (!chunk.isEmpty()) recvBuffer_.append(chunk); + auto frames = extractJsonFrames(recvBuffer_); + for (const QByteArray& f : frames) { + QJsonParseError perr; + QJsonDocument jd = QJsonDocument::fromJson(f, &perr); + if (perr.error != QJsonParseError::NoError) { + qWarning() << "[JsonRpcClient] parse frame error:" << perr.errorString(); + continue; + } + if (jd.isArray()) { + for (const QJsonValue& v : jd.array()) { + if (!v.isObject()) continue; + QJsonObject obj = v.toObject(); + if (obj.value("id").toInt() == expectId) { outResp = obj; return true; } + } + } else if (jd.isObject()) { + QJsonObject obj = jd.object(); + if (obj.value("id").toInt() == expectId) { outResp = obj; return true; } + } + } + } + return false; +} + +QJsonObject JsonRpcClient::sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs) { + QByteArray payload = QJsonDocument(req).toJson(QJsonDocument::Compact); + int id = req.value("id").toInt(); + if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) { + return QJsonObject{{"error", QJsonObject{{"code", -1},{"message", "write failed"}}}}; + } + QJsonObject resp; + if (!waitAndReadResponse(id, resp, timeoutMs)) { + return QJsonObject{{"error", QJsonObject{{"code", -2},{"message", "timeout"}}}}; + } + return resp; +} + +void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) { + call(method, params, module); } \ No newline at end of file diff --git a/rpcModule/rpc_finsTcp/rpc_finsTcp.h b/rpcModule/rpc_finsTcp/rpc_finsTcp.h index 90cf3d4..6b512b5 100644 --- a/rpcModule/rpc_finsTcp/rpc_finsTcp.h +++ b/rpcModule/rpc_finsTcp/rpc_finsTcp.h @@ -14,13 +14,12 @@ #include #include -#include +#include #include #include #include #include #include -#include enum connectionStatus { None, Disconnected, @@ -36,13 +35,16 @@ public: QByteArray finsReadCall(const QString& method, const QString& params = "", const QString& module = QString()); bool reconnect(); // 主动重连,或 call() 失败时调用 private: - - QMutex mutex_; // 确保线程安全 + // 解析累计缓冲中的完整 JSON 帧(可能存在粘包/拆包) + QList extractJsonFrames(QByteArray& buffer); + bool waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs = 8000); + QJsonObject sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs = 8000); + QMutex mutex_; // 确保线程安全 QTcpSocket socket_; QString host_; quint16 port_; int idCounter_; - + QByteArray recvBuffer_; // 累计接收缓冲 }; class JsonRpcClientWorker : public QObject { Q_OBJECT diff --git a/src/Core/back/backStruct.h b/src/Core/back/backStruct.h index e52be03..f1d29de 100644 --- a/src/Core/back/backStruct.h +++ b/src/Core/back/backStruct.h @@ -2,20 +2,7 @@ #include #include //#include -typedef dsModuleBase* (*CreateFunction)(); -typedef void (*ReleaseFunction)(dsModuleBase* animal); -typedef struct { - QString m_stationKy; - QString key; // 相机名称 - QString dllPath; // 模块名称 - QString task_thread_index = "-1";// 存储当前算法属于那个任务线程 - QByteArray m_initByte; // 传递初始化参数 - dsModuleBase* module_ptr = nullptr; // 存储模块指针 - ReleaseFunction destory_ptr; // 释放 - cameraStruct _cameraStruct;//外部传入数据 - bool init = false; -}cameraModule; static void createDirectoryIfNotExists(const std::string& path) { // 检查路径是否存在 diff --git a/src/Core/back/cameraManager.cpp b/src/Core/back/cameraManager.cpp index 0df0ab7..2f4231d 100644 --- a/src/Core/back/cameraManager.cpp +++ b/src/Core/back/cameraManager.cpp @@ -28,12 +28,11 @@ static MV_CC_DEVICE_INFO_LIST searchMvDevice() return m_stDevList; } -camera::camera(cameraModule cameraModulePtrIn, int indexIn, qtFuncBridge* bridgeIn) +camera::camera(cameraStruct configIn, int indexIn, qtFuncBridge* bridgeIn) { bridge = bridgeIn; - cameraModulePtr = cameraModulePtrIn; - config = cameraModulePtr._cameraStruct; - cameraName = cameraModulePtr.key; + config = configIn; + cameraName = QString::fromStdString(config.key); index = indexIn; lastUpdateTime.start(); this->start(); @@ -64,21 +63,21 @@ void camera::run() // QPixmap pixmap; // cvMatToQPixMap(data->oriImgs[i], pixmap); // showImgPack* pack = new showImgPack( - // cameraModulePtr._cameraStruct.imageShowList[imgShowCnt].first, - // cameraModulePtr._cameraStruct.imageShowList[imgShowCnt].second + // config._cameraStruct.imageShowList[imgShowCnt].first, + // config._cameraStruct.imageShowList[imgShowCnt].second // ); // pack->img = pixmap; // emit bridge->displayWidget_sendImg(pack); // imgShowCnt++; - // if (imgShowCnt >= cameraModulePtr._cameraStruct.imageShowList.size()) + // if (imgShowCnt >= config._cameraStruct.imageShowList.size()) // imgShowCnt = 0; // } //} //else { // showLost++; - // qDebug() << cameraModulePtr.dllPath << "Lost show"; + // qDebug() << config.dllPath << "Lost show"; //} break; } @@ -89,22 +88,19 @@ void camera::run() QThread::msleep(10); } } - cameraManager::~cameraManager() { for (auto camera : cameras) { delete camera.second; } - for (auto module : camerasVec) { + for (auto& module : _cameraStructs) { dsModuleBase* base_ptr = module.module_ptr; delete base_ptr; } - } -void cameraManager::run() -{ +void cameraManager::run(){ if (initFlag == true) return; #pragma region 加载相机dll @@ -127,25 +123,23 @@ void cameraManager::run() MV_CC_DEVICE_INFO_LIST m_stDevList = searchMvDevice(); QByteArray mvDevices = MV_CC_DeviceInfoListToQByteArray(m_stDevList); - for (auto i = 0; i < camerasVec.size(); i++) { - cameraModule& m_module = camerasVec[i]; - QString dllPath = m_module.dllPath; - QString key = m_module.key; + for (auto i = 0; i < _cameraStructs.size(); i++) { + auto& m_module = _cameraStructs[i]; + QString dllPath = QString::fromStdString(m_module.dllPath); + QString key = QString::fromStdString(m_module.key); //传递初始化参数 QByteArray initByte = m_module.m_initByte; QByteArray m_keyByte = key.toUtf8(); //遍历是否有相同key的相机,如果有直接复制指针 - for (int count = 0; count < camerasVec.size(); count++) - if (!camerasVec[count].key.compare(m_module.key) && count < i) - m_module.module_ptr = camerasVec[count].module_ptr; + for (int count = 0; count < _cameraStructs.size(); count++) + if (!_cameraStructs[count].key.compare(m_module.key) && count < i) + m_module.module_ptr = _cameraStructs[count].module_ptr; m_module.module_ptr->writeData(vec_mat, m_keyByte); //初始化相机 //非海康相机可跳过 - for (int i = 0; i < m_stDevList.nDeviceNum; i++) - { + for (int i = 0; i < m_stDevList.nDeviceNum; i++){ std::string userDefineName = static_cast((LPCSTR)m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chUserDefinedName); std::string serialNumber = static_cast((LPCSTR)m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber); - if (!serialNumber.compare(m_module.key.toStdString()) || !userDefineName.compare(m_module.key.toStdString())) - { + if (!serialNumber.compare(m_module.key) || !userDefineName.compare(m_module.key)){ m_module.module_ptr->writeData(vec_mat, mvDevices); break; } @@ -155,42 +149,35 @@ void cameraManager::run() } status = NotInit; bool initReuslt = true; - for (auto i = 0; i < camerasVec.size(); i++) - { - cameraModule m_module = camerasVec.at(i); - if (m_module.init == true) + for (auto i = 0; i < _cameraStructs.size(); i++){ + auto& cameraStruct = _cameraStructs[i]; + if (cameraStruct.init == true) continue; - QByteArray initByte = m_module.m_initByte; - if (m_module.module_ptr->initParas(initByte)) - { - camera* _camera = new camera(m_module, cameras.size(), bridge); - cameras.insert(std::make_pair(m_module.key.toStdString(), _camera)); - emit bridge->loadingWindow_appendLog("相机" + m_module.key + "初始化成功", "green"); + QByteArray initByte = cameraStruct.m_initByte; + if (cameraStruct.module_ptr->initParas(initByte)){ + camera* _camera = new camera(cameraStruct, cameras.size(), bridge); + cameras.insert(std::make_pair(cameraStruct.key, _camera)); + emit bridge->loadingWindow_appendLog("相机" + QString::fromStdString(cameraStruct.key) + "初始化成功", "green"); qDebug() << "[INFO] " << " initParas success!"; - m_module.init = true; + cameraStruct.init = true; } - else - { + else{ QByteArray errorStr("getStatus"); - m_module.module_ptr->readData(vec_mat, errorStr); + cameraStruct.module_ptr->readData(vec_mat, errorStr); initReuslt = false; - qCritical() << "[Error] " << " moduleName:" << m_module.dllPath << " initParas failed!"; - emit bridge->loadingWindow_appendLog("相机" + m_module.key + "初始化失败->" + errorStr, "red"); + qCritical() << "[Error] " << " moduleName:" << QString::fromStdString(cameraStruct.dllPath) << " initParas failed!"; + emit bridge->loadingWindow_appendLog("相机" + QString::fromStdString(cameraStruct.key) + "初始化失败->" + errorStr, "red"); } } - if (initReuslt == true) - { + if (initReuslt == true){ initFlag = true; status = InitOK; } else status = InitFailure; } -bool cameraManager::loadModule(cameraStruct _cameraStruct) -{ - QString task_thread_index = 0; - try - { +bool cameraManager::loadModule(cameraStruct& _cameraStruct){ + try{ QString keyName = QString::fromStdString(_cameraStruct.key); QString dllPath = QString::fromStdString(_cameraStruct.dllPath);// 相机模块名 QString module_path = "./" + dllPath; @@ -213,8 +200,7 @@ bool cameraManager::loadModule(cameraStruct _cameraStruct) QLibrary* m_lib = new QLibrary(module_path); lib_list.append(m_lib); bool flag = m_lib->load(); - if (!m_lib->isLoaded()) - { + if (!m_lib->isLoaded()){ qDebug() << "[Error] " << " Loaded error:" << m_lib->errorString(); bridge->loadingWindow_appendLog("加载相机模块" + dllPath + "失败->" + m_lib->errorString(), "red"); @@ -223,29 +209,18 @@ bool cameraManager::loadModule(cameraStruct _cameraStruct) CreateFunction createFun = (CreateFunction)m_lib->resolve("create"); ReleaseFunction releaseFun = (ReleaseFunction)m_lib->resolve("destory"); - if (createFun && releaseFun) - { - cameraModule m_module; - m_module.key = keyName; - m_module.m_initByte = QByteArray::fromStdString( _cameraStruct.connectionName); - m_module.dllPath = dllPath; - m_module.module_ptr = createFun(); - m_module.destory_ptr = releaseFun; - m_module._cameraStruct = _cameraStruct; - if (!task_thread_index.isEmpty()) - m_module.task_thread_index = task_thread_index; - - camerasVec.push_back(m_module); + if (createFun && releaseFun){ + _cameraStruct.module_ptr = createFun(); + _cameraStruct.destory_ptr = releaseFun; + _cameraStruct.m_initByte = QByteArray::fromStdString(_cameraStruct.connectionName); } - else - { + else{ delete m_lib; m_lib = nullptr; return false; } } - catch (QString event) - { + catch (QString event){ qCritical() << "[Error] " << " event:" << event; return false; } diff --git a/src/Core/back/cameraManager.h b/src/Core/back/cameraManager.h index 2159f5b..222f225 100644 --- a/src/Core/back/cameraManager.h +++ b/src/Core/back/cameraManager.h @@ -11,57 +11,66 @@ #include #include #include +typedef dsModuleBase* (*CreateFunction)(); +typedef void (*ReleaseFunction)(dsModuleBase* animal); + +struct cameraStruct { + int index; + std::string key; + std::string connectionName;//per Sec + std::string serialNum; + std::string dllPath; + std::vector oriSaveFormat; + std::vector>imageShowList; + + QByteArray m_initByte; // 传递初始化参数 + dsModuleBase* module_ptr = nullptr; // 存储模块指针 + ReleaseFunction destory_ptr; // 释放 + bool init = false; +}; + //硬触发要求在触发相机前给出触发信号 class backEndManager; -class camera : public QThread -{ +class camera : public QThread{ Q_OBJECT public: QTime lastUpdateTime; QString cameraName; int imgShowCnt = 0; - cameraModule cameraModulePtr; cameraStruct config; - camera(cameraModule cameraModulePtrIn, int indexIn, qtFuncBridge* bridgeIn); - ~camera() - { + camera(cameraStruct configIn, int indexIn, qtFuncBridge* bridgeIn); + ~camera(){ runFlag = false; this->terminate(); while (this->isRunning() == true); } void run(); - void stop() - { + void stop(){ runFlag = false; while (this->isRunning() == true); } void getImgQueueSize(); - void captureImage(std::shared_ptr dataIn) - { + void captureImage(std::shared_ptr dataIn){ QMutexLocker locker(&mutex); requestQueue.enqueue(dataIn); //std::thread([this]() {trigger();}).detach(); } //相机操作 - bool trigger() - { - if (!cameraModulePtr.module_ptr->run()) - { + bool trigger(){ + if (!config.module_ptr->run()){ qCritical() << "[Error] " << " m_name:" << cameraName << " run failed!"; return false; } return true; } - double getCameraValue()//点激光相机专用 - { + double getCameraValue(){//点激光相机专用 double value = 0; std::vector camera_mat; QByteArray task_name; int cnt = 0; - while (!cameraModulePtr.module_ptr->readData(camera_mat, task_name)) - { + while (!config.module_ptr->readData(camera_mat, task_name)){ QThread::msleep(10); cnt++; if (cnt > 500) @@ -70,10 +79,9 @@ public: value = task_name.toDouble(); return value; } - void getCameraImg(std::vector& mats,int imgAmountMin) - { + void getCameraImg(std::vector& mats,int imgAmountMin){ QByteArray task_name; - if (!cameraModulePtr.module_ptr->readData(mats, task_name)) { + if (!config.module_ptr->readData(mats, task_name)) { if (mats.size() == 0) { qDebug() << "camera_mat size 0,insert blank image"; mats = std::vector(imgAmountMin, cv::Mat::zeros(100, 100, CV_8UC3)); @@ -81,16 +89,13 @@ public: } qDebug() << __FUNCTION__ << " line:" << __LINE__ << "camera_mat size:" << mats.size(); } - void setDigitalShift(float value) - { + void setDigitalShift(float value){ readData("DigitalShift_" + std::to_string(value)); } - void setExposureTime(float value) - { + void setExposureTime(float value){ readData("exposure_" + std::to_string(value)); } - void setUserSet(int value) - { + void setUserSet(int value){ readData("userset_" + std::to_string(value)); } private: @@ -99,7 +104,7 @@ private: { QByteArray task_name(QByteArray::fromStdString(str)); std::vector camera_mat; - if (!cameraModulePtr.module_ptr->readData(camera_mat, task_name)) + if (!config.module_ptr->readData(camera_mat, task_name)) qCritical() << "[Error] " << "set exposure error!"; } int index = 0; @@ -111,26 +116,22 @@ private: int imgLost = 0;//未取用从而丢失的图片数量 int showLost = 0;//因为窗口刷新速率低而未显示的数量 }; -class cameraManager : public serviceModule -{ +class cameraManager : public serviceModule{ Q_OBJECT public: cameraManager(nlohmann::ordered_json& json, qtFuncBridge* bridgeIn) { bridge = bridgeIn; auto cameraJson = json["CameraSetting"]; - for (auto data : cameraJson) - { + for (auto data : cameraJson){ cameraStruct _cameraStruct; _cameraStruct.key = data["key"]; _cameraStruct.connectionName = data["connectionName"]; _cameraStruct.dllPath = data["dllPath"]; _cameraStruct.oriSaveFormat = data["oriSaveFormat"]; - for (auto& imageShow : data["imageShow"]) - { + for (auto& imageShow : data["imageShow"]){ QString str = QString::fromStdString(imageShow); QStringList l = str.split("#"); - if (l.size() < 2) - { + if (l.size() < 2){ qDebug() << "Imagehsow 格式错误,例:窗口名#类型名"; std::cout << "Imagehsow 格式错误,例:窗口名#类型名" <cameras;//key 相机名 - camera* getCamera(std::string cameraName) - { + camera* getCamera(std::string cameraName){ auto camera = cameras.find(cameraName); if (camera != cameras.end()) return camera->second; return nullptr; } - void stop() - { + void stop(){ for (auto camera : cameras) camera.second->stop(); } @@ -162,17 +159,14 @@ private: std::vector _cameraStructs;//相机配置结构体 qtFuncBridge* bridge; - bool loadModule(cameraStruct _cameraStruct); - std::vectorcamerasVec;//用于初始化和销毁 + bool loadModule(cameraStruct& _cameraStruct); std::vector vec_mat;//没啥用,一直保持为空就好 QList lib_list; std::map m_usedDllPath; public slots: - void cameraTrigger(std::string Name) - { + void cameraTrigger(std::string Name){ auto camera=cameras.find(Name); - if (camera != cameras.end()) - { + if (camera != cameras.end()){ camera->second->trigger(); } } diff --git a/src/Core/back/detData.h b/src/Core/back/detData.h index eb18711..598c3f7 100644 --- a/src/Core/back/detData.h +++ b/src/Core/back/detData.h @@ -82,20 +82,16 @@ public: }; class detDataManager{ public: - detDataManager(triggerManager* in_triggerManager) - :_triggerManager(in_triggerManager){ - - } - std::unordered_map>map; - QMutex dataMutex; + detDataManager(){ + } std::shared_ptr createDetData(QString IN_cameraKeyName,std::string IN_SN, int imgAmountMin,std::vector oriFormat) { QMutexLocker locker(&dataMutex); std::shared_ptr dataPtr(new detData()); dataPtr->cameraKeyName = IN_cameraKeyName.toStdString(); dataPtr->imgSaveNameParameter.push_back(IN_cameraKeyName.toStdString()); dataPtr->oriFormat = oriFormat; - dataPtr->triggerPtr = _triggerManager; + dataPtr->triggerPtr; dataPtr->SNcode = IN_SN; dataPtr->imgAmountMin = imgAmountMin; dataPtr->dManager = this; @@ -131,7 +127,13 @@ public: } return false; } + void setTriggerManager(triggerManager* _triggerManagerIN) { + QMutexLocker locker(&dataMutex); + _triggerManager = _triggerManagerIN; + } private: - triggerManager* _triggerManager; + triggerManager* _triggerManager = nullptr; + QMutex dataMutex; + std::unordered_map>map; }; #pragma once \ No newline at end of file diff --git a/src/Core/back/triggerManager.cpp b/src/Core/back/triggerManager.cpp index 80a52e5..ffc2ca1 100644 --- a/src/Core/back/triggerManager.cpp +++ b/src/Core/back/triggerManager.cpp @@ -11,8 +11,6 @@ triggerManager::triggerManager(detProcess* _detProcessIn, qtFuncBridge* bridgeIn _detProcess = _detProcessIn; dManager = _detProcessIn->_serviceManager._detDataManager; _cameraManager = _detProcessIn->_serviceManager._cameraManager; - //_threadManager = &_detProcessIn->_threadManager; - //_lightSourceManager = &_detProcessIn->_lightSourceManager; for (auto& d : triggerJson["readAllCmd"]) { readAllStruct _struct; _struct.readAllCmd = QByteArray::fromStdString(d); @@ -135,9 +133,24 @@ void triggerManager::decodeCameraCMD(readAllStruct& _struct, QByteArray byte) if (isConnected == true) { lostConnectionCountTimer.start(); std::cout<< "与PLC的连接已断开,正在尝试重连" << std::endl; + std::cout << "错误类型:读取到的数据为空" << std::endl; } if (lostConnectionRePrintTimer.elapsed() > 1000) { - qCritical() << "ERROR:cant read data from Fins,无法从fins读取数据"; + qCritical() << "ERROR:cant read data from Fins data size=0,无法从fins读取数据 数据为空"; + emit bridge->setPlcConnectionError(); + isConnected = false; + lostConnectionRePrintTimer.start(); + } + return; + } + else if (byte.size() != _struct.readLength * 2 && byte.size() != _struct.readLength) { + if (isConnected == true) { + lostConnectionCountTimer.start(); + std::cout << "与PLC的连接已断开,正在尝试重连" << std::endl; + std::cout << "错误类型:读取到的数据大小不匹配" << std::endl; + } + if (lostConnectionRePrintTimer.elapsed() > 1000) { + qCritical() << "ERROR:cant read data from Fins data sizesetPlcConnectionError(); isConnected = false; lostConnectionRePrintTimer.start(); diff --git a/src/Core/detProcess.hpp b/src/Core/detProcess.hpp index 4350402..c1f4a70 100644 --- a/src/Core/detProcess.hpp +++ b/src/Core/detProcess.hpp @@ -16,19 +16,55 @@ public: db(dbIn),bridge(bridgeIn),json(jsonIn){ } + + // 对普通指针的安全删除 + template + void safeDelete(T*& ptr) { + if (ptr) { delete ptr; ptr = nullptr; } + } + + // 尝试对基于 QThread 的 serviceModule 进行关停,然后删除 + void safeShutdownDelete(serviceModule* ptr) { + if (!ptr) return; + // 如果对象正在运行,尝试停止 + if (ptr->isRunning()) { + // 如果存在 stop 槽,则尝试调用 + QMetaObject::invokeMethod(ptr, "stop", Qt::DirectConnection); + // 作为后备,尝试退出事件循环 + QMetaObject::invokeMethod(ptr, "quit", Qt::DirectConnection); + // 等待其退出,给予一定时间 + if (!ptr->wait(2000)) { + // 仍在运行时,作为最后手段强制终止 + ptr->terminate(); + ptr->wait(1000); + } + } + delete ptr; ptr = nullptr; + } + void init() { - _serviceManager._imgSaveThreadManager = new imgSaveThreadManager(json["imgSaveBasePath"]); - _serviceManager._cameraManager = new cameraManager(json, bridge); - _serviceManager._triggerManager = new triggerManager(this, bridge, json["Triggers"]); - _serviceManager._detDataManager = new detDataManager(_serviceManager._triggerManager); + // 创建/重建需要的服务模块,避免重复创建 + if (!_serviceManager._imgSaveThreadManager) { + _serviceManager._imgSaveThreadManager = new imgSaveThreadManager(json["imgSaveBasePath"]); + } + if (!_serviceManager._cameraManager) { + _serviceManager._cameraManager = new cameraManager(json, bridge); + } + if (!_serviceManager._triggerManager) { + _serviceManager._triggerManager = new triggerManager(this, bridge, json["Triggers"]); + } if (initOnce == false) { initOnce = true; _csvWriter = new CsvWriter(db); + _serviceManager._detDataManager = new detDataManager(); _missonResultHandle = new missonResultHandle(bridge); _serviceManager._missonResultHandle = _missonResultHandle; _serviceManager.dataBase = db; _serviceManager._csvWriter = _csvWriter; - _serviceManager._handleAiModelManager = new handleAiModelManager(json, bridge); + // handleAiModelManager 与 CLI 等只在首次初始化创建 + if (!_serviceManager._handleAiModelManager) { + _serviceManager._handleAiModelManager = new handleAiModelManager(json, bridge); + } connect(bridge, &qtFuncBridge::reInitConfig, this, [=]() {reinitConfig(); }); _cliManager = new CLIManager(&_serviceManager, bridge); } @@ -52,15 +88,29 @@ public: // 重新初始化配置 void reinitConfig() { - // 1. 释放已有资源 - if (_serviceManager._imgSaveThreadManager) { delete _serviceManager._imgSaveThreadManager; _serviceManager._imgSaveThreadManager = nullptr; } - if (_serviceManager._cameraManager) { delete _serviceManager._cameraManager; _serviceManager._cameraManager = nullptr; } - if (_serviceManager._triggerManager) { delete _serviceManager._triggerManager; _serviceManager._triggerManager = nullptr; } - //if (_serviceManager._threadManager) { delete _serviceManager._threadManager; _serviceManager._threadManager = nullptr; } - if (_serviceManager._detDataManager) { delete _serviceManager._detDataManager; _serviceManager._detDataManager = nullptr; } + // 1. 优雅停止并释放已有运行中的服务模块 + // 停止并删除线程型模块 + safeShutdownDelete(_serviceManager._cameraManager); + safeShutdownDelete(_serviceManager._triggerManager); + // imgSaveThreadManager 可能不是 QThread,直接删除 + safeDelete(_serviceManager._imgSaveThreadManager); + // handleAiModelManager 可能运行在后台,优雅停止后删除 + if (_serviceManager._handleAiModelManager) { + // try invoking stop if exists + QMetaObject::invokeMethod(_serviceManager._handleAiModelManager, "stop", Qt::DirectConnection); + safeDelete(_serviceManager._handleAiModelManager); + } + // 2. 重新初始化 init(); - this->start(); + + // 3. 如果 detProcess 尚未运行,则启动主线程;如果已在运行,run() 应自行管理子模块的重启 + if (!this->isRunning()) { + this->start(); + } else { + // 已在运行的话,可以发出信号或回调,通知 run 中重载配置(这里仅 log) + qDebug() << "detProcess already running, init refreshed. run() should handle reloading if needed."; + } } // 初始化并运行主流程 void run() { @@ -81,16 +131,7 @@ public: json["missionSettings"], bridge ); _cliManager->initBasicPreset(); - //_threadManager->registerResultHandleCallback( - // [this](std::shared_ptr data) { - // detectionResultHandle(data); - // }); - - //_threadManager->registerProcessAlgoCallback( - // [this](std::shared_ptr data, handleAiModelManager* _handleAiModelManager) { - // return _missionLoader._misson->processAlgo(data, _handleAiModelManager); - // }); - + _serviceManager._detDataManager->setTriggerManager(_serviceManager._triggerManager); emit bridge->initResult(InitOK); } else { diff --git a/src/core/struct.h b/src/core/struct.h index 93b7459..0805c39 100644 --- a/src/core/struct.h +++ b/src/core/struct.h @@ -5,6 +5,7 @@ #include #include #include +#include struct productSignStruct { cv::Rect posRect; @@ -209,15 +210,6 @@ struct triggerStruct std::string writeType; int startPos; }; -struct cameraStruct{ - int index; - std::string key; - std::string connectionName;//per Sec - std::string serialNum; - std::string dllPath; - std::vector oriSaveFormat; - std::vector>imageShowList; -}; struct sqlConfigStruct { diff --git a/src/launcher/appConfig/appConfig.cpp b/src/launcher/appConfig/appConfig.cpp index d23cf46..ff8fa44 100644 --- a/src/launcher/appConfig/appConfig.cpp +++ b/src/launcher/appConfig/appConfig.cpp @@ -19,7 +19,7 @@ void appConfig::parsingSettingJson() softwareTile = settingJson["softwareTile"]; imgSavePath = settingJson["backend"]["imgSaveBasePath"]; //viewer - auto viewerData = settingJson["ImageView"]; + auto viewerData = settingJson["ImageView"]; for (auto data = viewerData.begin(); data != viewerData.end(); data++) { viewerStruct v; diff --git a/subModule/Hd_CameraModule_HIK_hard_GIGE/Hd_CameraModule_HIK_hard_GIGE.cpp b/subModule/Hd_CameraModule_HIK_hard_GIGE/Hd_CameraModule_HIK_hard_GIGE.cpp index dc122c0..7b1a3be 100644 --- a/subModule/Hd_CameraModule_HIK_hard_GIGE/Hd_CameraModule_HIK_hard_GIGE.cpp +++ b/subModule/Hd_CameraModule_HIK_hard_GIGE/Hd_CameraModule_HIK_hard_GIGE.cpp @@ -2,6 +2,14 @@ #include using namespace std; #include +#include +#include +#include +#include + +static std::atomic g_reconnecting(false); +static std::mutex g_reconnect_mutex; + QByteArray mv_Status = "connected";//0106 新增相机断联报警 long long index = 0; //相机序号 void* handle; @@ -174,23 +182,47 @@ 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) + // 如果已有重连线程在运行,则直接返回 + bool expected = false; + if (!g_reconnecting.compare_exchange_strong(expected, true)) { - Sleep(100); - if (connectDevice() == true) - { - qWarning() << "[Hd_CameraModule_HIK] " << " Hd_CameraModule_HIK create success again! "; - moduleStatus = true; - break; - } - + qDebug() << "[Info] reconnect already in progress"; + return; } + + // 启动后台线程负责重连,避免在回调线程中长时间阻塞 + std::thread([]() { + qDebug() << "[Info] start reconnect thread"; + + // 确保设备资源关闭 + CloseDevice(); + + int attempt = 0; + int delay_ms = 500; // 初始延迟 + while (true) + { + attempt++; + qDebug() << "[Info] reconnect attempt:" << attempt; + if (connectDevice()) + { + qWarning() << "[Hd_CameraModule_HIK] reconnect success!"; + moduleStatus = true; + mv_Status = "connected"; + g_reconnecting = false; + break; + } + + // 指数退避,最大 5000ms + std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms)); + delay_ms = delay_ms * 2; + if (delay_ms > 5000) delay_ms = 5000; + + // 在某些场景可能希望退出重连(例如程序关闭),如果未来需要可增加退出条件 + } + }).detach(); } } @@ -312,11 +344,17 @@ Hd_CameraModule_HIK_hard_PCIE::Hd_CameraModule_HIK_hard_PCIE() void CloseDevice() { - unsigned int nRet = MV_CC_StopGrabbing(handle); - CloseHandle(handle); - //nRet = MV_CC_CloseDevice(handle); - //nRet = MV_CC_DestroyHandle(handle); + // 如果 handle 已经为空,直接返回 + if (handle == nullptr) + return; + + // 使用 SDK 正确的停止/关闭/销毁流程,避免使用 CloseHandle 等不匹配的 API + MV_CC_StopGrabbing(handle); + MV_CC_CloseDevice(handle); + MV_CC_DestroyHandle(handle); + handle = nullptr; } + Hd_CameraModule_HIK_hard_PCIE::~Hd_CameraModule_HIK_hard_PCIE() { CloseDevice(); @@ -488,25 +526,9 @@ bool Hd_CameraModule_HIK_hard_PCIE::run() { m_flag = false; int mytime = 0; - if (imgShouldGetIndex < imgShouldGetVec.size()) { - if (imgShouldGetVec[imgShouldGetIndex] == 0) { - n_mutex->lock(); - queuepic.push_back(cv::Mat(200, 200, CV_8UC3, cv::Scalar(0, 0, 255))); //返回空图 - std::cout << "red" << std::endl; - n_mutex->unlock(); - imgShouldGetIndex++; - return true; - } - imgShouldGetIndex++; - } int cnt = 0; while (true) { - /* if (moduleStatus == false || mytime++ > getImageTimeOut || ifBreak == true) - { - result = false; - break; - }*/ n_mutex->lock(); cnt++; if (queuepic.size() > 0) @@ -516,14 +538,14 @@ bool Hd_CameraModule_HIK_hard_PCIE::run() std::cout << "\n gotImg" << std::endl; break; } - if (cnt > 25000) { + if (cnt > 120) { queuepic.push_back(cv::Mat(250, 250, CV_8UC3, cv::Scalar(0, 255, 0))); //返回空图 std::cout << "timeout" << std::endl; n_mutex->unlock(); return true; } n_mutex->unlock(); - QThread::msleep(1); + QThread::msleep(10); } //考虑到误触发、漏触发的图,在这里进行设置。 //需要设置曝光时 diff --git a/subModule/Hd_CameraModule_HIK_soft_GIGE/Hd_CameraModule_HIK_soft_GIGE.cpp b/subModule/Hd_CameraModule_HIK_soft_GIGE/Hd_CameraModule_HIK_soft_GIGE.cpp index ad5c5a1..b5b0ec2 100644 --- a/subModule/Hd_CameraModule_HIK_soft_GIGE/Hd_CameraModule_HIK_soft_GIGE.cpp +++ b/subModule/Hd_CameraModule_HIK_soft_GIGE/Hd_CameraModule_HIK_soft_GIGE.cpp @@ -2,6 +2,11 @@ #include using namespace std; #include +#include +#include +#include +#include + QByteArray mv_Status = "connected";//0106 新增相机断联报警 long long index = 0; //相机序号 void* handle; @@ -9,6 +14,8 @@ string Username = ""; bool m_flag = false; //MV_CC_DEVICE_INFO_LIST m_stDevList;//相机设备 bool moduleStatus = true; +static std::atomic g_reconnecting(false); +static std::mutex g_reconnect_mutex; QQueue queuepic; //data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。 bool ifBreak = false; @@ -168,29 +175,67 @@ void SetGain(float GainValue) MV_CC_SetFloatValue(handle, "Gain", GainValue); } +//关闭设备 +void CloseDevice() +{ + // 如果 handle 已经为空,直接返回 + if (handle == nullptr) + return; + + // 使用 SDK 正确的停止/关闭/销毁流程,避免在回调或其他线程中出错 + MV_CC_StopGrabbing(handle); + MV_CC_CloseDevice(handle); + MV_CC_DestroyHandle(handle); + handle = nullptr; //确保后续可以重新创建 handle +} + //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) + // 如果已有重连线程在运行,则直接返回 + bool expected = false; + if (!g_reconnecting.compare_exchange_strong(expected, true)) { - Sleep(100); - if (connectDevice() == true) - { - qWarning() << "[Hd_CameraModule_HIK] " << " Hd_CameraModule_HIK create success again! "; - moduleStatus = true; - break; - } - + qDebug() << "[Info] reconnect already in progress"; + return; } + + // 启动后台线程负责重连,避免在回调线程中长时间阻塞 + std::thread([]() { + qDebug() << "[Info] start reconnect thread"; + + // 确保设备资源关闭 + CloseDevice(); + + int attempt = 0; + int delay_ms = 500; // 初始延迟 + while (true) + { + attempt++; + qDebug() << "[Info] reconnect attempt:" << attempt; + if (connectDevice()) + { + qWarning() << "[Hd_CameraModule_HIK] reconnect success!"; + moduleStatus = true; + mv_Status = "connected"; + g_reconnecting = false; + break; + } + + // 指数退避,最大 5000ms + std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms)); + delay_ms = delay_ms * 2; + if (delay_ms > 5000) delay_ms = 5000; + + // 在某些场景可能希望退出重连(例如程序关闭),如果未来需要可增加退出条件 + } + }).detach(); } } @@ -308,14 +353,6 @@ Hd_CameraModule_HIK_hard_PCIE::Hd_CameraModule_HIK_hard_PCIE() //m_thread = new MyThread; //m_mutex = new QMutex(); } -//关闭设备 -void CloseDevice() -{ - MV_CC_StopGrabbing(handle); - MV_CC_CloseDevice(handle); - MV_CC_DestroyHandle(handle); - handle = nullptr; //此处注释掉的话,软件断开再连接,回调函数不出图 -} Hd_CameraModule_HIK_hard_PCIE::~Hd_CameraModule_HIK_hard_PCIE() { CloseDevice(); @@ -487,20 +524,8 @@ bool Hd_CameraModule_HIK_hard_PCIE::run() { m_flag = false; int mytime = 0; - if (imgShouldGetIndex < imgShouldGetVec.size()) { - if (imgShouldGetVec[imgShouldGetIndex] == 0) { - n_mutex->lock(); - queuepic.push_back(cv::Mat(200, 200, CV_8UC3, cv::Scalar(0, 0, 255))); //返回空图 - std::cout << "red" << std::endl; - n_mutex->unlock(); - imgShouldGetIndex++; - return true; - } - else - MV_CC_SetCommandValue(handle, "TriggerSoftware"); - imgShouldGetIndex++; - } int cnt = 0; + MV_CC_SetCommandValue(handle, "TriggerSoftware"); while (true) { /* if (moduleStatus == false || mytime++ > getImageTimeOut || ifBreak == true) @@ -517,14 +542,14 @@ bool Hd_CameraModule_HIK_hard_PCIE::run() std::cout << "\n gotImg" << std::endl; break; } - if (cnt > 25000) { + if (cnt > 120) { queuepic.push_back(cv::Mat(250, 250, CV_8UC3, cv::Scalar(0, 255, 0))); //返回空图 std::cout << "timeout" << std::endl; n_mutex->unlock(); return true; } n_mutex->unlock(); - QThread::msleep(1); + QThread::msleep(10); } //考虑到误触发、漏触发的图,在这里进行设置。 //需要设置曝光时