V20260829-2.6.1

完成框架目录和模块重构;新增核心、单例、工具、加密及框架 SDK;统一任务、相机和 RPC 接口,并增加离线检测、相机标定、备份恢复、版本管理、崩溃守护和心跳监控功能。
This commit is contained in:
2026-09-20 16:01:09 +08:00
parent ee97a4ab2c
commit e3f7733316
464 changed files with 55154 additions and 47963 deletions
@@ -3,11 +3,18 @@ get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(TIMESTAMP RUN_TIME)
message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME})
if(NOT TARGET Hd_HikDeviceListCache)
add_subdirectory(
"${CMAKE_CURRENT_LIST_DIR}/../Hd_HikDeviceListCache"
"${CMAKE_CURRENT_BINARY_DIR}/Hd_HikDeviceListCache"
)
endif()
set(DLL_NAMES "mvs" "opencv")
foreach(child ${DLL_NAMES})
foreach(child ${DLL_NAMES})
LIST(APPEND ENV_INCLUDE ${${child}_include})
LIST(APPEND ENV_LIB ${${child}_lib})
LIST(APPEND ENV_TARGET ${${child}_target_link})
LIST(APPEND ENV_TARGET ${${child}_target_link})
endforeach()
message(" ENV_INCLUDE : " ${ENV_INCLUDE} )
message(" ENV_LIB : " ${ENV_LIB} )
@@ -24,7 +31,7 @@ link_directories (
set(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
@@ -46,9 +53,7 @@ add_library(${CURRENT_FOLDER} SHARED
${UI_FILES}
)
set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C
set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE CXX
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}
@@ -57,10 +62,10 @@ set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C
target_link_libraries(${CURRENT_FOLDER} PRIVATE
${ENV_TARGET}
eui::hikDeviceCache
Qt${QT_VERSION_MAJOR}::Core
)
# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY)
@@ -1,4 +1,5 @@
#include "Hd_CameraModule_HIK_General.h"
#include "Hd_CameraModule_HIK_General.h"
#include <HikDevicelistCache.h>
#include <qtimer.h>
using namespace std;
#include <QTextCodec>
@@ -25,7 +26,6 @@ int getImageTimeOut = 3000;
bool runFlag = true;
//总取图数
int imgIndex = 0;
MV_CC_DEVICE_INFO_LIST m_stDevList; // ch:设备信息列表结构体变量,用来存储设备列表
string Username = "";
int cameraIndex = -1;
QString lastError;
@@ -72,20 +72,11 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser);
void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0);
//搜索所有设备
int SearchDevice(){
if (m_stDevList.nDeviceNum == 0) {
memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
// ch:枚举子网内所有设备 | en:Enumerate all devices within subnet
int nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &m_stDevList);
if (MV_OK != nRet)
{
return -1;
}
}
for (int i = 0; i < m_stDevList.nDeviceNum; i++)
const auto deviceInfoList = appHikDeviceListCache().getDeviceInfoList();
for (int i = 0; i < deviceInfoList.nDeviceNum; i++)
{
//SN
unsigned char* name = m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber;
unsigned char* name = deviceInfoList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber;
string userName = static_cast<string>((LPCSTR)name);
if (Username == userName)
{
@@ -93,7 +84,7 @@ int SearchDevice(){
break;
}
name = m_stDevList.pDeviceInfo[i]->SpecialInfo.stUsb3VInfo.chSerialNumber;
name = deviceInfoList.pDeviceInfo[i]->SpecialInfo.stUsb3VInfo.chSerialNumber;
userName = static_cast<string>((LPCSTR)name);
if (Username == userName)
{
@@ -109,11 +100,11 @@ bool connectDevice()
int cameraIndex = SearchDevice();
if (cameraIndex == -1){
//未匹配到相机
qDebug() << "[Waring] " << "Hd_CameraModule_HIK not match --CameraName:" << QString::fromStdString(Username);
qDebug() << "Hd_CameraModule_HIK not match --CameraName:" << QString::fromStdString(Username);
lastError = "找不到相机" + QString::fromStdString(Username);
return false;
}
std::lock_guard<std::mutex> lock(handleMutex);
if (handle != NULL)
{
@@ -123,9 +114,15 @@ bool connectDevice()
handle = NULL;
}
//打开相机
MV_CC_CreateHandle(&handle, m_stDevList.pDeviceInfo[cameraIndex]);
int nRet = MV_CC_OpenDevice(handle);
const auto deviceInfoList = appHikDeviceListCache().getDeviceInfoList();
int nRet = MV_CC_CreateHandle(&handle, deviceInfoList.pDeviceInfo[cameraIndex]);
if (MV_OK != nRet)
{
handle = NULL;
lastError = QString("MV_CC_CreateHandle failed, nRet=0x%1").arg(QString::number(nRet, 16));
return false;
}
nRet = MV_CC_OpenDevice(handle);
////触发模式
if(triggerMode == SOFTWARE)
{
@@ -137,7 +134,7 @@ bool connectDevice()
MV_CC_SetEnumValue(handle, "TriggerMode", MV_TRIGGER_MODE_ON);
MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0);
}
// //加载用户集,相机设置应当UserSet1
nRet = MV_CC_SetEnumValueByString(handle, "UserSetSelector", "UserSet1");
if (MV_OK != nRet)qDebug() << "Set UserSetSelector fail! nRet " << nRet;
@@ -145,24 +142,24 @@ bool connectDevice()
MV_CC_SetIntValueEx(handle, "GevHeartbeatTimeout", 3000);//心跳日志
nRet = MV_CC_RegisterImageCallBackEx(handle, ImageCallBackEx, handle);//注册回调
if (MV_OK != nRet)return false;
if (MV_OK != nRet)return false;
nRet = MV_CC_RegisterExceptionCallBack(handle, ReconnectDevice, NULL);//断线重连
if (MV_OK != nRet)return false;
MV_CC_StartGrabbing(handle);
cameraStatus.store(CONNECTED);
return true;
}
void SetExposureTime(float exposureValue)
{
qDebug() << "[INFO] " << "exposureValue:" << exposureValue;
qDebug() << "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;
qDebug() << "GainValue:" << GainValue;
MV_CC_SetEnumValue(handle, "GainAuto", 0);
MV_CC_SetFloatValue(handle, "Gain", GainValue);
}
@@ -170,17 +167,17 @@ void SetGain(float GainValue)
//断线重连
void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser){
qDebug() << "[Error] " << " MV camera disconnects!";
qDebug() << " MV camera disconnects!";
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus.load() == CONNECTED){
// 防止重复启动重连线程
bool expected = false;
if (!reconnecting.compare_exchange_strong(expected, true)) {
qDebug() << "[Warning] Reconnect already in progress, skipping duplicate request";
qDebug() << "Reconnect already in progress, skipping duplicate request";
return;
}
cameraStatus.store(RECONNECTING);
// 启动后台线程负责重连,避免在回调线程中长时间阻塞
std::thread([]() {
@@ -199,13 +196,13 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser){
reconnecting.store(false);
return;
}
qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 500 ms before retry...";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
// 如果runFlag为false,线程退出
qDebug() << "[Info] reconnect thread stopped (runFlag=false)";
qDebug() << "reconnect thread stopped (runFlag=false)";
cameraStatus.store(DISCONNECTED);
reconnecting.store(false);
}).detach();
@@ -225,15 +222,18 @@ void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFra
//qDebug() << "[info]" << __FUNCTION__ << " line:" << __LINE__ << "--- start";
if (pFrameInfo0)
{
frameNum = pFrameInfo0->nFrameNum; //ch:帧号 | en:frame number
//获取的是单通道灰度图
if (pFrameInfo0->enPixelType == PixelType_Gvsp_Mono8)//获取当前采集到的图像格式
{
srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC1, pData0);
Mat mysrcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC1, pData0);
mysrcImage.copyTo(srcImage);
}
//获取的是RGB8图
else if (pFrameInfo0->enPixelType == PixelType_Gvsp_BGR8_Packed)
{
srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pData0);
Mat mysrcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pData0);
mysrcImage.copyTo(srcImage);
//cvtColor(srcImage, srcImage, COLOR_RGB2BGR);//导致异色
}
@@ -252,10 +252,9 @@ void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFra
unsigned int nConvertDataSize = 0;
nConvertDataSize = pFrameInfo0->nWidth * pFrameInfo0->nHeight * 3;
// ch:像素格式转换 | en:Convert pixel format
// 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
@@ -285,7 +284,7 @@ void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFra
queuepic.dequeue();
pData0 = { 0 };
double time_End = (double)clock();
qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getImg,Time:" << (time_End - time_Start) << "ms"
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " checkImg getImg,Time:" << (time_End - time_Start) << "ms"
<< "--CameraName:" << QString::fromStdString(Username) << " imgIndex:" << imgIndex << "nFrameNum : " << frameNum;
}
@@ -294,7 +293,7 @@ void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFra
void CloseDevice()
{
std::lock_guard<std::mutex> lock(handleMutex);
// 如果 handle 已经为空,直接返回
if (handle == nullptr)
return;
@@ -302,19 +301,19 @@ void CloseDevice()
// 使用 SDK 正确的停止/关闭/销毁流程,避免使用 CloseHandle 等不匹配的 API
int nRet = MV_CC_StopGrabbing(handle);
if (MV_OK != nRet) {
qDebug() << "[Warning] MV_CC_StopGrabbing failed, nRet=" << nRet;
qDebug() << "MV_CC_StopGrabbing failed, nRet=" << nRet;
}
nRet = MV_CC_CloseDevice(handle);
if (MV_OK != nRet) {
qDebug() << "[Warning] MV_CC_CloseDevice failed, nRet=" << nRet;
qDebug() << "MV_CC_CloseDevice failed, nRet=" << nRet;
}
nRet = MV_CC_DestroyHandle(handle);
if (MV_OK != nRet) {
qDebug() << "[Warning] MV_CC_DestroyHandle failed, nRet=" << nRet;
qDebug() << "MV_CC_DestroyHandle failed, nRet=" << nRet;
}
handle = nullptr;
}
Hd_CameraModule_HIK_General::Hd_CameraModule_HIK_General() {
@@ -326,15 +325,15 @@ Hd_CameraModule_HIK_General::~Hd_CameraModule_HIK_General()
// 防止定时线程在资源析构后仍访问队列和互斥锁
callbackCollectTimeoutTimer.stop();
// 等待重连线程结束
int waitCount = 0;
while (reconnecting.load() && waitCount < 50) { // 最多等待5秒
qDebug() << "[Info] Waiting for reconnect thread to finish...";
qDebug() << "Waiting for reconnect thread to finish...";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
waitCount++;
}
CloseDevice();
if (n_mutex)
{
@@ -342,7 +341,7 @@ Hd_CameraModule_HIK_General::~Hd_CameraModule_HIK_General()
n_mutex = nullptr;
}
qDebug() << "[INFO] " << " delete success!";
qDebug() << " delete success!";
}
//从类中读数据到实例对象
bool Hd_CameraModule_HIK_General::readData(std::vector<cv::Mat>& mat, QByteArray& data)
@@ -355,7 +354,7 @@ bool Hd_CameraModule_HIK_General::readData(std::vector<cv::Mat>& mat, QByteArray
QMutexLocker locker(n_mutex);
cv::Mat img = queuepic.dequeue();
mat.push_back(img);
qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData--CameraName:" << QString::fromStdString(Username) << "--imgIndex : " << imgIndex;
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData--CameraName:" << QString::fromStdString(Username) << "--imgIndex : " << imgIndex;
return true;
}
@@ -366,8 +365,8 @@ bool Hd_CameraModule_HIK_General::writeData(std::vector<cv::Mat>& mat, QByteArra
if (data.contains("deviceList")) {
auto result = QByteArrayToMV_CC_DeviceInfoList(data.mid(10));
if (result.nDeviceNum != 0) {
m_stDevList = result;
return true;
appHikDeviceListCache().setDeviceInfoList(result);
return true;
}
}
if (data == "getStatus") {
@@ -392,7 +391,7 @@ bool Hd_CameraModule_HIK_General::initParas(QByteArray& initData)
{
QByteArrayList valueList = initData.split('#');
if (valueList.size() < 3) {
qDebug() << "[Error] " << " Hd_CameraModule_HIK initParas fail--params error!参数数量不满足";
qDebug() << " Hd_CameraModule_HIK initParas fail--params error!参数数量不满足";
lastError = "参数数量不满足";
return false;
}
@@ -406,7 +405,7 @@ bool Hd_CameraModule_HIK_General::initParas(QByteArray& initData)
else if (triggerModeStr == "EMPTY")
triggerMode = EMPTY;
else {
qDebug() << "[Error] " << " Hd_CameraModule_HIK initParas fail--params error!触发模式参数错误";
qDebug() << " Hd_CameraModule_HIK initParas fail--params error!触发模式参数错误";
lastError = "触发模式参数错误";
return false;
}
@@ -419,7 +418,7 @@ bool Hd_CameraModule_HIK_General::initParas(QByteArray& initData)
bool Hd_CameraModule_HIK_General::run()
{
qDebug() << "[INFO] " << " run start" << QString::fromStdString(Username);
qDebug() << " run start" << QString::fromStdString(Username);
if (triggerMode == SOFTWARE)
MV_CC_SetCommandValue(handle, "TriggerSoftware");
try
@@ -441,7 +440,7 @@ bool Hd_CameraModule_HIK_General::run()
}
catch (QString ev)
{
qDebug() << "[Error] " << " ev:" << ev;
qDebug() << " ev:" << ev;
}
return true;
}
@@ -456,7 +455,7 @@ bool Hd_CameraModule_HIK_General::checkStatus()
Hd_CameraModule_HIK_General* create()
{
qDebug() << "[INFO] " << "Hd_CameraModule_HIK create success!";
qDebug() << "Hd_CameraModule_HIK create success!";
return new Hd_CameraModule_HIK_General;
}
@@ -467,5 +466,5 @@ void destory(Hd_CameraModule_HIK_General* ptr)
delete ptr;
ptr = nullptr;
}
qDebug() << "[INFO] " << "Hd_CameraModule_HIK destory success!";
}
qDebug() << "Hd_CameraModule_HIK destory success!";
}
@@ -1,4 +1,4 @@
#ifndef Hd_CameraModule_HIK_General_H
#ifndef Hd_CameraModule_HIK_General_H
#define Hd_CameraModule_HIK_General_H
#include <QtCore/qglobal.h>
#include <MvCameraControl.h>
@@ -69,7 +69,7 @@ public:
bool run();
bool checkStatus();
private:
//MyThread *m_thread = nullptr;
//QMutex* m_mutex;
};
@@ -1,3 +1,4 @@
支持USB设备和网口设备,不支持采集卡设备
初始化格式 "相机序列号#HARDWARE/SOFTWARE/EMPTY#取图超时时间"
SAMPLE: Vir76210850#SOFTWARE#2000
支持USB设备和网口设备,不支持采集卡设备
初始化格式 "相机序列号#HARDWARE/SOFTWARE/EMPTY#取图超时时间"
SAMPLE: Vir76210850#SOFTWARE#2000
4. 海康官方 SDK 日志由 MvLogServer 服务生成;默认使用 MV_CC_CreateHandle。请在 MVS 的“工具 -> 日志查看”中查看和配置日志。