#include "Hd_CameraModule_HIK3.h" #include #include #include #include #include #include #include #pragma execution_character_set("utf-8") //0106 断线重连 void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser0); void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0); void SetExposureTime(float exposureValue, MyData* m_MyData); void SetGain(float GainValue, MyData* m_MyData); QString byteArrayToUnicode(const QByteArray array); //关闭设备 void CloseDevice(MyData* m_MyData); Hd_CameraModule_HIK3* create(int settype) { qDebug() << __FUNCTION__ << " line:" << __LINE__ << "Hd_CameraModule_HIK3 create success!"; return new Hd_CameraModule_HIK3(settype); } void destory(Hd_CameraModule_HIK3* ptr) { if (ptr) { delete ptr; ptr = nullptr; } qDebug() << "[INFO] " << "Hd_CameraModule_HIK3 destory success!"; } //int myIDS[10000] = { 0 }; //类创建 Hd_CameraModule_HIK3::Hd_CameraModule_HIK3(int settype, QObject* parent) : PbGlobalObject(settype, parent) { m_MyData = new MyData(); MyThread* newMyThread = new MyThread(); newMyThread->camera = this; m_MyData->n_mutex = new QMutex(); m_MyData->ifRunning = true; //QFuture myF= QtConcurrent::run(this, &Hd_CameraModule_HIK3::threadCheckCallBack); if (type1 < 15) famliy = PGOFAMLIY::CAMERA2D; else if (type1 == 15) famliy = PGOFAMLIY::CAMERA2_5D; else if (type1 < 100) famliy = PGOFAMLIY::CAMERA3D; //id = myIDS[type1]++; qDebug() << "famliy::" << famliy; } Hd_CameraModule_HIK3::~Hd_CameraModule_HIK3() { //myIDS[type1]--; m_MyData->ifFirst = true; m_MyData->ifRunning = false; m_MyData->m_flag = false; Sleep(10); CloseDevice(m_MyData); if (m_MyData->n_mutex) { delete m_MyData->n_mutex; m_MyData->n_mutex = nullptr; } /*if(m_thread) { m_thread->exit(); m_thread->wait(1); delete m_thread; m_thread = nullptr; }*/ qDebug() << __FUNCTION__ << "line:" << __LINE__ << " delete success!"; } // //Hd_CameraModule_HIK3::Hd_CameraModule_HIK3() //{ // //} // //Hd_CameraModule_HIK3::~Hd_CameraModule_HIK3() //{ // m_thread.camera = nullptr; // ifRunning = false; // m_flag = false; // Sleep(10); // CloseDevice(); // if (n_mutex) // { // delete n_mutex; // n_mutex = nullptr; // } // /*if(m_thread) // { // m_thread->exit(); // m_thread->wait(1); // delete m_thread; // m_thread = nullptr; // }*/ // // qDebug() << "[INFO] " << " delete success!"; //} // //Hd_CameraModule_HIK3* create() //{ // qDebug() << "[INFO] " << "Hd_CameraModule_HIK3 create success!"; // return new Hd_CameraModule_HIK3; //} // //void destory(Hd_CameraModule_HIK3* ptr) //{ // if (ptr) // { // delete ptr; // ptr = nullptr; // } // qDebug() << "[INFO] " << "Hd_CameraModule_HIK3 destory success!"; //} //setParameter之后再调用,返回当前参数 //相机:获取默认参数; //通信:获取初始化示例参数 QMap Hd_CameraModule_HIK3::parameters() { if (m_MyData->ifFirst == true) { m_MyData->ifFirst = false; m_MyData->moduleName= "Hd_CameraModule_HIK3#" + QString::number(id); QJsonObject ExampleObj = load_camera_Example(); QJsonObject cameraObj; QJsonArray ExampleArray = ExampleObj.value("相机模块列表").toArray(); for (int i = 0; i < ExampleArray.size(); i++) { QString name = ExampleArray[i].toObject().value("模块名称").toString(); if (m_MyData->moduleName.split("#")[0] == name) cameraObj = ExampleArray[i].toObject(); } //参数设置的数据 QMap myParasValueMap; myParasValueMap.insert("相机key", "输入SN"); //默认参数显示到界面 QJsonArray ParameterArray = cameraObj.value("相机参数").toArray(); for (int T = 0; T < ParameterArray.size(); T++) { QJsonObject ParameterObj = ParameterArray[T].toObject(); QString ParameterKey = ParameterObj.value("参数名").toString(); QString ParameterValue; QJsonArray ParameterValueArray = ParameterObj.value("相机参数值").toArray(); for (int P = 0; P < ParameterValueArray.size(); P++) { if (P > 0)ParameterValue.append(","); ParameterValue.append(ParameterValueArray[P].toString()); } myParasValueMap.insert(ParameterKey, ParameterValue); } return myParasValueMap; } else return m_MyData->ParasValueMap; } //初始化参数;通信/相机的初始化参数 bool Hd_CameraModule_HIK3::setParameter(const QMap& ParameterMap) { m_MyData->ParasValueMap = ParameterMap; //if (m_module.moduleName.isEmpty()) //m_module.moduleName = getmoduleName();// = ParasValueMap.value() //if(id=) m_MyData->moduleName = "Hd_CameraModule_HIK3#" + QString::number(id); return true; } //初始化(加载模块待内存) bool Hd_CameraModule_HIK3::init() { ////传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... QString initByte = m_MyData->ParasValueMap.value("相机key"); foreach(QString key, m_MyData->ParasValueMap.keys()) { if (key == "相机key") continue; initByte += "+" + key + "#"; QString ParameterValue = m_MyData->ParasValueMap.value(key); initByte += ParameterValue.replace(",", "#"); } this->disconnect(); if (initParas(initByte.toLocal8Bit())) { qDebug() << __FUNCTION__ << " line: " << __LINE__ << " key: " << m_MyData->ParasValueMap.value("相机key") << " initParas success! "; //handdleAI3.0,重置计数,emit trigged(1000); connect(this, &PbGlobalObject::trigged, [=](int Code) { if (Code == 1000) { std::vector mat; QByteArray data="rest_newProductIn"; writeData(mat,data); } }); } else { qCritical() << __FUNCTION__ << " line: " << __LINE__ << " moduleName: " << m_MyData->ParasValueMap.value("相机key") << " initParas failed! "; return false; } //} //else //{ // delete m_lib; // m_lib = nullptr; // return false; //} return true; } //设置数据 //相机:第一张图的参数,QStringList:00 曝光值 增益值; //相机:第N张图的参数,QStringList:非00 曝光值 增益值; bool Hd_CameraModule_HIK3::setData(const std::vector& mats, const QStringList& data) { //foreach(QString kidData,data) //if (kidData.contains("SetExposureTime")) { std::vector ImgS; QByteArray bData; for (int i = 0; i < data.size(); i++) //if(i>0) // bData +=","+ data[i].toLocal8Bit(); //else bData += data[i].toLocal8Bit(); qDebug() << "Hd_CameraModule_All::setData::" << bData; writeData(ImgS, bData); //if (m_module.module_ptr) // m_module.module_ptr->writeData(ImgS, bData); //return true; } foreach(QString kidData, data) if (kidData.contains("SetExposureTime") || kidData.contains("rest_newProductIn")) return true; bool runResult = run(); //m_module.module_ptr->run(); return runResult; } //获取数据 bool Hd_CameraModule_HIK3::data(std::vector& ImgS, QStringList& QStringListdata) { //std::vector ImgS; QByteArray data; //m_module.module_ptr->readData(ImgS, data); readData(ImgS, data); if (!data.isEmpty())QStringListdata.append(byteArrayToUnicode(data)); return true; } QJsonObject Hd_CameraModule_HIK3::load_camera_Example() { QDir dir = QCoreApplication::applicationDirPath(); QString currPath = dir.path(); currPath = "../runtime/Bin_DEVICE"; QString json_cfg_file_path = currPath + "/camera_Example.json"; QJsonObject json_object; try { QJsonParseError jsonError; if (json_cfg_file_path.isEmpty()) { qCritical() << __FUNCTION__ << " line:" << __LINE__ << " JsonPath is null!"; return json_object; } QFile JsonFile; JsonFile.setFileName(json_cfg_file_path); //if (!JsonFile.isReadable()) //{ // qCritical() << __FUNCTION__ << " line:" << __LINE__ << " camera_Example.json not isReadable!"; // //return json_object; //} JsonFile.open(QIODevice::ReadOnly); QByteArray m_Byte = JsonFile.readAll(); if (m_Byte.isEmpty()) { qDebug() << __FUNCTION__ << " line:" << __LINE__ << json_cfg_file_path + " Content is empty"; JsonFile.close(); return json_object; } QJsonDocument jsonDocument(QJsonDocument::fromJson(m_Byte, &jsonError)); if (!jsonDocument.isNull() && jsonError.error == QJsonParseError::NoError) { if (jsonDocument.isObject()) { json_object = jsonDocument.object(); JsonFile.close(); return json_object; } } else { qCritical() << __FUNCTION__ << " line:" << __LINE__ << json_cfg_file_path + " is error!"; } JsonFile.close(); } catch (QString ev) { qCritical() << __FUNCTION__ << " line:" << __LINE__ << " ev:" << ev; } return json_object; } 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; } 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; } } //搜索所有设备 int Hd_CameraModule_HIK3::SearchDevice() { memset(&m_MyData->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_MyData->m_stDevList); for (int i = 0; i < m_MyData->m_stDevList.nDeviceNum; i++) { //SN unsigned char* name = m_MyData->m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber; //userID //unsigned char* name=m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chUserDefinedName; std::string userName = static_cast((LPCSTR)name); if (m_MyData->Username == userName) { m_MyData->index = i; break; } } if (MV_OK != nRet) { return 0; } return -1; } bool Hd_CameraModule_HIK3::connctDevice() { m_MyData->index = -1; SearchDevice(); if (m_MyData->index == -1) { //未匹配到相机 //qDebug() << "[Waring] " << "Hd_CameraModule_HIK3 not match --CameraName:" << QString::fromStdString(Username); return false; } unsigned char* name = m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.chUserDefinedName; std::string userName = static_cast((LPCSTR)name); qDebug() << "[INFO] " << " start" << "--UserName:" << QString::fromStdString(userName); if (m_MyData->handle != NULL) { MV_CC_StopGrabbing(m_MyData->handle); MV_CC_CloseDevice(m_MyData->handle); MV_CC_DestroyHandle(m_MyData->handle); m_MyData->handle = NULL; //此处注释掉的话,软件断开再连接,回调函数不出图 return false; } qDebug() << __FUNCTION__ << " line:" << __LINE__ << "m_MyData->handle:" << m_MyData->handle; //打开相机 int nRet=MV_CC_CreateHandle(&m_MyData->handle, m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]); if (MV_OK != nRet) { //qDebug() << "Set MV_CC_CreateHandle fail! nRet " << nRet; return false; } //自动IP功能:注意,只获取GIGE、USB相机,其它相机不可和HIK相机在同网段。 // ch:判断设备IP是否可达 bool bAccessible=true;// = MV_CC_IsDeviceAccessible(m_stDevList.pDeviceInfo[index], MV_ACCESS_Exclusive); if (m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nNetExport / 256 != m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nCurrentIp / 256)//nCurrentIp相机IP;nNetExport网口IP;判断前3位 bAccessible = false; if (!bAccessible) { unsigned int m_dwIpaddress = m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nNetExport; //nCurrentIp相机IP;nNetExport网口IP unsigned int m_dwNetworkMask = m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nCurrentSubNetMask;//掩码 unsigned int m_dwDefaultGateway = m_dwIpaddress - m_dwIpaddress % 256 + 254;//默认网关是254 for (int i = 2; i < 253; i++)//自动IP { unsigned int auto_dwIpaddress = m_dwIpaddress - m_dwIpaddress % 256 + i; bool ifHas = false; for (int k = 0; k < m_MyData->m_stDevList.nDeviceNum; k++) { unsigned int m_nNetExport = m_MyData->m_stDevList.pDeviceInfo[k]->SpecialInfo.stGigEInfo.nNetExport; unsigned int m_nCurrentIp = m_MyData->m_stDevList.pDeviceInfo[k]->SpecialInfo.stGigEInfo.nCurrentIp; //qDebug() << "k:" << k << " nNetExport:" << m_nNetExport << " nCurrentIp::" << m_nCurrentIp; if (auto_dwIpaddress == m_nNetExport || auto_dwIpaddress == m_nCurrentIp) //IP占用判断 { ifHas = true; break; } } if (ifHas) continue; nRet = MV_GIGE_ForceIpEx(m_MyData->handle, auto_dwIpaddress, m_dwNetworkMask, m_dwDefaultGateway); if (MV_OK == nRet) break; else { MV_CC_DestroyHandle(m_MyData->handle); m_MyData->handle = NULL; nRet = MV_CC_CreateHandle(&m_MyData->handle, m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]); if (MV_OK != nRet) { qDebug() << "Set MV_GIGE_ForceIpEx fail! nRet " << nRet; return false; } } } if (MV_OK != nRet) { //ShowErrorMsg(TEXT("ForceIp fail"), nRet); qDebug() << "Set ForceIp fail! nRet " << nRet; MV_CC_DestroyHandle(m_MyData->handle); m_MyData->handle = NULL; return false; } MV_CC_DestroyHandle(m_MyData->handle); m_MyData->handle = NULL; //ch:需要重新创建句柄,设置为静态IP方式进行保存 m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nCurrentIp = m_dwIpaddress; m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nCurrentSubNetMask = m_dwNetworkMask; m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]->SpecialInfo.stGigEInfo.nDefultGateWay = m_dwDefaultGateway; /*qDebug()<<"m_dwIpaddress "<< QString::number(m_dwIpaddress / (256 * 256 * 256)) + "." + QString::number(m_dwIpaddress / (256 * 256) % 256) + "." + QString::number(m_dwIpaddress / 256 % 256) + "." + QString::number(m_dwIpaddress % 256); qDebug() << "m_dwNetworkMask " << QString::number(m_dwNetworkMask / (256 * 256 * 256)) + "." + QString::number(m_dwNetworkMask / (256 * 256) % 256) + "." + QString::number(m_dwNetworkMask / 256 % 256) + "." + QString::number(m_dwNetworkMask % 256); qDebug() << "m_dwDefaultGateway " << QString::number(m_dwDefaultGateway / (256 * 256 * 256)) + "." + QString::number(m_dwDefaultGateway / (256 * 256) % 256) + "." + QString::number(m_dwDefaultGateway / 256 % 256) + "." + QString::number(m_dwDefaultGateway % 256);*/ nRet = MV_CC_CreateHandle(&m_MyData->handle, m_MyData->m_stDevList.pDeviceInfo[m_MyData->index]); if (MV_OK != nRet) { qDebug() << "MV_CC_CreateHandle fail! nRet " << nRet; //ShowErrorMsg(TEXT("Create handle fail"), nRet); return false; } nRet = MV_GIGE_SetIpConfig(m_MyData->handle, MV_IP_CFG_STATIC); if (MV_OK != nRet)//这里会失败,再试一次。 { qDebug() << "MV_GIGE_SetIpConfig fail! nRet " << nRet; //ShowErrorMsg(TEXT("Set Ip config fail"), nRet); MV_CC_DestroyHandle(m_MyData->handle); m_MyData->handle = NULL; return false; } } nRet = MV_CC_OpenDevice(m_MyData->handle); ////触发模式 if (m_MyData->currentTriggerSource != MV_TRIGGER_SOURCE_SOFTWARE) MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0); else MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); MVCC_ENUMVALUE stEnumValue = { 0 }; MV_CC_GetEnumValue(m_MyData->handle, "TriggerSource", &stEnumValue); //获取当前触发方式 if (m_MyData->currentTriggerSource != stEnumValue.nCurValue) MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", m_MyData->currentTriggerSource); MV_CC_SetEnumValue(m_MyData->handle, "TriggerMode", MV_TRIGGER_MODE_ON); // //加载用户集,相机设置应当UserSet1 //nRet = MV_CC_SetEnumValueByString(handle, "UserSetSelector", "UserSet1"); if (MV_OK != nRet) { //qDebug() << "Set UserSetSelector fail! nRet " << nRet; return false; } // ch:注册抓图回调 | en:Register image callback MV_CC_SetIntValueEx(m_MyData->handle, "GevHeartbeatTimeout", 3000);//心跳日志 qDebug() << __FUNCTION__ << " line:" << __LINE__ << "m_MyData->handle:" << m_MyData->handle; nRet = MV_CC_RegisterImageCallBackEx(m_MyData->handle, ImageCallBackEx, (void*)this);//注册回调 if (MV_OK != nRet) return false; nRet = MV_CC_RegisterExceptionCallBack(m_MyData->handle, ReconnectDevice, (void*)this);//断线重连 if (MV_OK != nRet) return false; MV_CC_StartGrabbing(m_MyData->handle); qDebug() << __FUNCTION__ << " line:" << __LINE__ << "m_MyData->handle:" << m_MyData->handle; return true; } //0106 断线重连 void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser0) { Hd_CameraModule_HIK3* ptr = (Hd_CameraModule_HIK3*)pUser0; ptr->m_MyData->mv_Status = "disconnect"; qDebug() << __FUNCTION__ << " line:" << __LINE__ << "[Error] " << " MV camera disconnects!"; ptr->m_MyData->moduleStatus = false; if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT) { //断开连接 MV_CC_CloseDevice(ptr->m_MyData->handle); int nRet = MV_CC_DestroyHandle(ptr->m_MyData->handle); ptr->m_MyData->handle = NULL; ptr->threadCheckCallBack(1); //newMyThread->runEmit(1, ptr->m_MyData); BOOL bConnected = FALSE; // 初始化随机数生成器 //QRandomGenerator::seed(); while (1) { // 生成一个随机整数 int randomNumber = QRandomGenerator::global()->bounded(500); //多相机无随机时,重连稍慢 Sleep(randomNumber); // 输出到控制台 //qDebug() << "Random Number:" << randomNumber; Sleep(100); if (ptr->connctDevice() == true) { qWarning() << __FUNCTION__ << " line:" << __LINE__ << "[Hd_CameraModule_HIK3] " << " Hd_CameraModule_HIK3 create success again! "; ptr->m_MyData->moduleStatus = true; ptr->threadCheckCallBack(0); //newMyThread->runEmit(0, ptr->m_MyData); //m_thread.runEmit(0); break; } } } } int RGB2BGR(unsigned char* pRgbData, unsigned int nWidth, unsigned int nHeight) { if (NULL == pRgbData) { return MV_E_PARAMETER; } for (unsigned int j = 0; j < nHeight; j++) { for (unsigned int i = 0; i < nWidth; i++) { unsigned char red = pRgbData[j * (nWidth * 3) + i * 3]; pRgbData[j * (nWidth * 3) + i * 3] = pRgbData[j * (nWidth * 3) + i * 3 + 2]; pRgbData[j * (nWidth * 3) + i * 3 + 2] = red; } } return MV_OK; } //cameraIndex,函数指针的map //QMap< QString, QObject*> mMap_cameraIndex_QObject; //注册回调 string对应自身的参数协议 (自定义) void Hd_CameraModule_HIK3::registerCallBackFun(PBGLOBAL_CALLBACK_FUN callBackFun, QObject* m_QObject, const QString& cameraIndex) { m_MyData->n_mutex->lock(); myPBGLOBAL_callBack m_myPBGLOBAL_callBack; m_myPBGLOBAL_callBack.callBackFun = callBackFun; m_myPBGLOBAL_callBack.m_QObject = m_QObject; m_myPBGLOBAL_callBack.cameraIndex = cameraIndex; m_MyData->QQueue_myPBGLOBAL_callBack.enqueue(m_myPBGLOBAL_callBack); m_MyData->n_mutex->unlock(); } //注销回调 string对应自身的参数协议 (自定义)--->注销后还得取消连接状态 void Hd_CameraModule_HIK3::cancelCallBackFun(PBGLOBAL_CALLBACK_FUN callBackFun, QObject* m_QObject, const QString& cameraIndex) { m_MyData->n_mutex->lock(); qDebug() << __FUNCTION__ << " line:" << __LINE__ << "try cancelCallBackFun"; for (int i = 0; i < m_MyData->QQueue_myPBGLOBAL_callBack.size(); i++) { if (m_MyData->QQueue_myPBGLOBAL_callBack[i].callBackFun == NULL) qDebug() << __FUNCTION__ << " line:" << __LINE__ << "QQueue_myPBGLOBAL_callBack[i].callBackFun == NULL"; if(m_MyData->QQueue_myPBGLOBAL_callBack[i].m_QObject ==NULL) qDebug() << __FUNCTION__ << " line:" << __LINE__ << "QQueue_myPBGLOBAL_callBack[i].m_QObject == NULL"; if (m_MyData->QQueue_myPBGLOBAL_callBack[i].callBackFun == callBackFun && m_MyData->QQueue_myPBGLOBAL_callBack[i].m_QObject == m_QObject && m_MyData->QQueue_myPBGLOBAL_callBack[i].cameraIndex == cameraIndex) { qDebug() << __FUNCTION__ << " line:" << __LINE__ << "try QQueue_myPBGLOBAL_callBack.removeAt(i)"; m_MyData->QQueue_myPBGLOBAL_callBack.removeAt(i); break; } } qDebug() << __FUNCTION__ << " line:" << __LINE__ << "try cancelCallBackFun done!"; m_MyData->n_mutex->unlock(); } //回调函数; //经测试,相机像素格式Mono8、RGB8是可以正常转换的,YUV422还需要优化;RGB8格式比YUV422帧率低;BGR格式会导致异色问题 void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0)//this { Hd_CameraModule_HIK3* Data = (Hd_CameraModule_HIK3*)pUser0; Data->m_MyData->n_mutex->lock(); double time_Start = (double)clock(); int frameNum = 0; Data->m_MyData->QQueue_srcImage.clear(); Data->m_MyData->srcImage = cv::Mat(); // ch:像素格式转换 | en:Convert pixel format MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 }; unsigned char* pConvertData = NULL; if (pFrameInfo0) { //获取的是单通道灰度图 if (pFrameInfo0->enPixelType == PixelType_Gvsp_Mono8)//获取当前采集到的图像格式 { Data->m_MyData->srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC1, pData0); } //获取的是BGR8图 else if (pFrameInfo0->enPixelType == PixelType_Gvsp_BGR8_Packed) { Data->m_MyData->srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pData0); } ////获取的是RGB8图 //else if (pFrameInfo0->enPixelType == PixelType_Gvsp_RGB8_Packed) //{ // cv::Mat dst = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pData0); // //cv::cvtColor(matimage, matimage, cv::COLOR_RGB2BGR); // srcImage = cv::Mat::zeros(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3); // std::vector channels; // cv::split(dst, channels);//分割matimage的通道 // std::vector dstchannels; // for (int i = 2; i >= 0; i--) // { // dstchannels.push_back(channels[i]); // } // merge(dstchannels, srcImage); //} else if (IsColor(pFrameInfo0->enPixelType)) //其它格式彩色图 { MvGvspPixelType enDstPixelType = PixelType_Gvsp_Undefined; enDstPixelType = PixelType_Gvsp_BGR8_Packed; 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; 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(Data->m_MyData->handle, &stConvertParam); //Mat mysrcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, stConvertParam.pDstBuffer); //mysrcImage.copyTo(srcImage);//回调需要深拷贝,否则图像会出现重复 Data->m_MyData->srcImage= cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pConvertData); stConvertParam = { 0 }; } } } if(Data->m_MyData->srcImage.empty()) { Data->m_MyData->srcImage = cv::Mat(5, 5, CV_8UC1).setTo(0); } Data->m_MyData->QQueue_srcImage.enqueue(Data->m_MyData->srcImage.clone()); //cv::Mat resizeM; //cv::resize(srcImage, resizeM, cv::Size(), 0.1, 0.1); //cv::imwrite("../runtime/Bin_DEVICE/testImg/"+Username + ".png", resizeM); Data->m_MyData->m_flag = true; Data->m_MyData->callBackNum++; QString tmpDate = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); if (Data->m_MyData->currentTriggerSource == MV_TRIGGER_SOURCE_LINE0)//硬触发,回调 { std::vector mat; mat.push_back(Data->m_MyData->QQueue_srcImage.dequeue()); //触发回调 for (int i = 0; i < Data->m_MyData->QQueue_myPBGLOBAL_callBack.size(); i++) if (Data->m_MyData->QQueue_myPBGLOBAL_callBack[i].cameraIndex == QString::number(Data->m_MyData->imgIndex)) (*Data->m_MyData->QQueue_myPBGLOBAL_callBack[i].callBackFun)(Data->m_MyData->QQueue_myPBGLOBAL_callBack[i].m_QObject, mat); Data->m_MyData->imgIndex++; if (Data->m_MyData->expourseTimeList.size() > 1 && Data->m_MyData->expourseTimeList[Data->m_MyData->imgIndex % Data->m_MyData->expourseTimeList.size()] != Data->m_MyData->expourseTimeList[(Data->m_MyData->imgIndex - 1) % Data->m_MyData->expourseTimeList.size()]) SetExposureTime(Data->m_MyData->expourseTimeList[Data->m_MyData->imgIndex % Data->m_MyData->expourseTimeList.size()], Data->m_MyData); //Sleep(1); if (Data->m_MyData->gainList.size() > 1 && Data->m_MyData->gainList[Data->m_MyData->imgIndex % Data->m_MyData->gainList.size()] != Data->m_MyData->gainList[(Data->m_MyData->imgIndex - 1) % Data->m_MyData->gainList.size()]) SetGain(Data->m_MyData->gainList[Data->m_MyData->imgIndex % Data->m_MyData->gainList.size()], Data->m_MyData); if (Data->m_MyData->imgIndex >= Data->m_MyData->expourseTimeList.size()) Data->m_MyData->imgIndex = 0; } //else // Data->m_MyData->imgIndex++; stConvertParam = { 0 }; free(pConvertData); pConvertData= NULL; Data->m_MyData->n_mutex->unlock(); double time_End = (double)clock(); qDebug() << tmpDate << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getImg,Time:" << (time_End - time_Start) << "ms" << "--CameraName:" << QString::fromStdString(Data->m_MyData->Username) << " imgIndex:" << Data->m_MyData->imgIndex << "nFrameNum : " << frameNum<<" callBackNum::"<< Data->m_MyData->callBackNum; //m_thread.run(); /*QString savePath = "../runtime/Bin_DEVICE/testImg/camera_"+QString::fromStdString(Username) +"_" + QString::number(imgIndex + 1) + ".png"; cv::Mat resizeS; cv::resize(srcImage, resizeS, cv::Size(), 0.1, 0.1); cv::imwrite(savePath.toStdString(), resizeS);*/ } void SetExposureTime(float exposureValue, MyData* m_MyData) { qDebug() << "[INFO] " << "exposureValue:" << exposureValue; MV_CC_SetEnumValue(m_MyData->handle, "ExposureAuto", MV_EXPOSURE_AUTO_MODE_OFF); MV_CC_SetFloatValue(m_MyData->handle, "ExposureTime", exposureValue); } void SetGain(float GainValue, MyData* m_MyData) { qDebug() << "[INFO] " << "GainValue:" << GainValue; MV_CC_SetEnumValue(m_MyData->handle, "GainAuto", 0); MV_CC_SetFloatValue(m_MyData->handle, "Gain", GainValue); } //关闭设备 void CloseDevice(MyData* m_MyData) { MV_CC_StopGrabbing(m_MyData->handle); MV_CC_CloseDevice(m_MyData->handle); MV_CC_DestroyHandle(m_MyData->handle); m_MyData->handle = NULL; //此处注释掉的话,软件断开再连接,回调函数不出图 } void MyThread::runEmit(int code, MyData* m_MyData) { if (camera) camera->threadCheckCallBack(code); } void Hd_CameraModule_HIK3::threadCheckCallBack(int code) { //while (ifRunning) { //if (currentTriggerSource != MV_TRIGGER_SOURCE_SOFTWARE) /* if (m_flag == true) { qDebug() << QThread::currentThreadId()<< " Username::" << QString::fromStdString(Username) << "[INFO] " << "emit trigged,triggedNum:"<< triggedNum++; emit trigged(true); n_mutex->lock(); m_flag = false; n_mutex->unlock(); }*/ if (m_MyData->ifThemoduleStatus != m_MyData->moduleStatus) { qDebug() << "[INFO] " << "moduleStatus changed emit trigged:" << m_MyData->moduleStatus; if(m_MyData->moduleStatus) emit trigged(0); else emit trigged(1); m_MyData->ifThemoduleStatus = m_MyData->moduleStatus; } if(m_MyData->moduleStatus==false) qApp->processEvents(); Sleep(5); } } //从类中读数据到实例对象 bool Hd_CameraModule_HIK3::readData(std::vector &mat,QByteArray &data) { if (m_MyData->QQueue_srcImage.isEmpty())//(!srcImage.data) { qCritical() << __FUNCTION__ << " line:" <<__LINE__ << " srcImage is null"; return false; } m_MyData->n_mutex->lock(); //mat.push_back(srcImage.clone()); //mat.push_back(srcImage);//非深拷贝,显示时或其他使用mat的时间,回调函数进来,改掉了srcImage,导致使用时崩溃。 mat.push_back(m_MyData->QQueue_srcImage.dequeue());// .clone()); //srcImage = cv::Mat(); m_MyData->n_mutex->unlock(); QString qimgIndex = "imgIndex_" + QString::number(m_MyData->imgIndex-1)+"_中文测试"; data = qimgIndex.toLocal8Bit(); QString tmpDate = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); qDebug() << tmpDate << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData--CameraName:" << QString::fromStdString(m_MyData->Username) << "--imgIndex : " << m_MyData->imgIndex-1; return true; } //实例对象把数据写入到类 bool Hd_CameraModule_HIK3::writeData(std::vector &mat,QByteArray &data) { //2024.02.18更新,相机对应的读SN信号时,表示新产品进入,设置初始值 if (data == "rest_newProductIn") { m_MyData->n_mutex->lock(); //根据实际项目,设置初始值:曝光、增益,ROI区域等 { if (m_MyData->expourseTimeList.size() > 0) SetExposureTime(m_MyData->expourseTimeList[0], m_MyData); if (m_MyData->gainList.size() > 0) SetGain(m_MyData->gainList[0], m_MyData); } //srcImage = cv::Mat(); m_MyData->QQueue_srcImage.clear(); m_MyData->n_mutex->unlock(); if (m_MyData->ifRunning == true) { m_MyData->ifBreak = true; Sleep(10); } m_MyData->imgIndex = 0; return true; } //else //{ // //m_flag = false; // //expourseTimeList.clear(); // //gainList.clear(); //} if (data == "ifChangeExpourseAndGain_false") m_MyData->ifChangeExpourseAndGain = false; else m_MyData->ifChangeExpourseAndGain = true; m_MyData->n_mutex->lock(); if (data.contains("SetExposureTime_")) { QByteArrayList dataList = data.split('#'); for (int i = 0; i < dataList.size(); i++) { if (dataList[i].contains("SetExposureTime_")) { int value = byteArrayToUnicode(dataList[i]).split("SetExposureTime_")[1].toInt(); SetExposureTime(value, m_MyData); } if (dataList[i].contains("SetGain_")) { double value = byteArrayToUnicode(dataList[i]).split("SetGain_")[1].toInt(); SetGain(value, m_MyData); } if (dataList[i].contains("TriggerMode_")) { QString value = byteArrayToUnicode(dataList[i]).split("TriggerMode_")[1]; if (value == "软触发" || value == "soft") ////触发模式 { qDebug() << "MV_CC_SetEnumValue MV_TRIGGER_SOURCE_SOFTWARE"; if (m_MyData->currentTriggerSource != MV_TRIGGER_SOURCE_SOFTWARE) { MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); m_MyData->currentTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; } } else if (value == "硬触发" || value == "hard") { qDebug() << "MV_CC_SetEnumValue MV_TRIGGER_SOURCE_LINE0"; if (m_MyData->currentTriggerSource != MV_TRIGGER_SOURCE_LINE0) { MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0); m_MyData->currentTriggerSource = MV_TRIGGER_SOURCE_LINE0; } } else qDebug() << "TriggerMode err ,may Chinese Name!"; MVCC_ENUMVALUE stEnumValue = { 0 }; MV_CC_GetEnumValue(m_MyData->handle, "TriggerSource", &stEnumValue); //获取当前触发方式 if (m_MyData->currentTriggerSource != stEnumValue.nCurValue) MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", m_MyData->currentTriggerSource); } } } //调试模式下,data==ifChangeExpourseAndGain_false;非调试模式运行时,data不包含SetExposureTime_ else if (data != "ifChangeExpourseAndGain_false" && m_MyData->initTriggerSource != m_MyData->currentTriggerSource) { MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", m_MyData->initTriggerSource); m_MyData->currentTriggerSource = m_MyData->initTriggerSource; } m_MyData->n_mutex->unlock(); /*data.append("SetExposureTime_" + ui.spinBox->text() + "#"); data.append("SetGain_" + ui.doubleSpinBox->text() + "#"); data.append("TriggerMode_" + ui.comboBox_triggerMode->currentText());*/ qDebug() << "Hd_CameraModule_HIK3::writeData::" << data; //m_flag = false; //Username = data.toStdString(); return true; } //传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... bool Hd_CameraModule_HIK3::initParas(QByteArray& initData) { QByteArrayList valueList = initData.split('+'); m_MyData->Username = valueList[0]; m_MyData->imgIndex = 0; m_MyData->expourseTimeList.clear(); m_MyData->gainList.clear(); bool ifOk = true; if (m_MyData->handle == NULL) ifOk = connctDevice(); if (ifOk == false) { qDebug() << "try connctDevice again!"<Username); ifOk = connctDevice(); } if (ifOk == false) return false; 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++) m_MyData->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++) m_MyData->gainList.enqueue(gainL[j].toFloat()); } if (valuei.contains("是否为标准通信流程")) { if (valuei.contains("true")) m_MyData->ifStandard = true; } if (valuei.contains("取图超时") || valuei.contains("getImageTimeOut")) { QStringList gainL = valuei.split('#'); if (gainL.size() > 1) m_MyData->getImageTimeOut = gainL[1].toInt(); if (m_MyData->getImageTimeOut < 50) m_MyData->getImageTimeOut = 1000; } if (valuei.contains("OffsetX")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if(valueL[1].toInt()>=0) MV_CC_SetIntValue(m_MyData->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(m_MyData->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(m_MyData->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(m_MyData->handle, "Height", valueL[1].toInt()); } if (valuei.contains("触发方式") || valuei.contains("TriggerMode")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if (valueL[1].toInt() >= 0) if (valueL[1] == "软触发" || valueL[1] == "soft") { MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); m_MyData->currentTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; m_MyData->initTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; } else if (valueL[1] == "硬触发" || valueL[1] == "hard") { MV_CC_SetEnumValue(m_MyData->handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0); m_MyData->currentTriggerSource = MV_TRIGGER_SOURCE_LINE0; m_MyData->initTriggerSource = MV_TRIGGER_SOURCE_LINE0; } } } if (ifOk == true) { if (m_MyData->expourseTimeList.size() > 0) SetExposureTime(m_MyData->expourseTimeList[0], m_MyData); if (m_MyData->gainList.size() > 0) SetGain(m_MyData->gainList[0], m_MyData); } m_MyData->imgIndex = 0; if (ifOk == true) { MVCC_FLOATVALUE mf = { 0 }; MV_CC_GetFloatValue(m_MyData->handle, "ExposureTime", &mf); std::cout << "ExposureTime::" << mf.fCurValue << std::endl; mf = { 0 }; MV_CC_GetFloatValue(m_MyData->handle, "Gain", &mf); std::cout << "Gain::" << mf.fCurValue << std::endl; MVCC_INTVALUE mI = { 0 }; MV_CC_GetIntValue(m_MyData->handle, "OffsetX", &mI); std::cout << "OffsetX::" << mI.nCurValue << std::endl; mI = { 0 }; MV_CC_GetIntValue(m_MyData->handle, "OffsetY", &mI); std::cout << "OffsetY::" << mI.nCurValue << std::endl; mI = { 0 }; MV_CC_GetIntValue(m_MyData->handle, "Width", &mI); std::cout << "Width::" << mI.nCurValue << std::endl; mI = { 0 }; MV_CC_GetIntValue(m_MyData->handle, "Height", &mI); std::cout << "Height::" << mI.nCurValue << std::endl; MVCC_ENUMVALUE me = { 0 }; MV_CC_GetEnumValue(m_MyData->handle,"BalanceWhiteAuto",&me); //自动白平衡 std::cout << "BalanceWhiteAuto::" << me.nCurValue << std::endl; } return ifOk; } bool Hd_CameraModule_HIK3::run() { if (m_MyData->moduleStatus == false) return false; if (m_MyData->imgIndex >= m_MyData->expourseTimeList.size()) m_MyData->imgIndex = 0; //Sleep(100); QString tmpDate = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz"); qDebug() << tmpDate << "[INFO] " << " run start" <Username); bool result = false; m_MyData->ifRunning = true; m_MyData->ifBreak = false; //srcImage.release(); try { //n_mutex->lock(); m_MyData->m_flag = false; //Sleep(2); //n_mutex->unlock(); //m_thread->run(); //start()线程运行,频率高时有低概率无响应; qDebug() << __FUNCTION__ << " line:" << __LINE__ << "m_MyData->handle:" << m_MyData->handle; if (m_MyData->currentTriggerSource == MV_TRIGGER_SOURCE_SOFTWARE) { MV_CC_SetCommandValue(m_MyData->handle, "TriggerSoftware"); qDebug() << "[INFO] " << "TriggerSoftware"; } else qDebug() << "[INFO] " << "TriggerHardware"; //MV_CC_SetCommandValue(handle, "TriggerSoftware"); //Sleep(15); int mytime = 0; qDebug() << "[INFO] " << " waite Img" << QString::fromStdString(m_MyData->Username); while (true) { if (m_MyData->moduleStatus == false || mytime++ > m_MyData->getImageTimeOut || m_MyData->ifBreak == true )//|| m_flag==true) { result = false; break; } m_MyData->n_mutex->lock(); if (m_MyData->m_flag == true) { m_MyData->n_mutex->unlock(); result = true; break; } m_MyData->n_mutex->unlock(); Sleep(1); } Sleep(1); //qDebug() << "[INFO] " << " expourseTimeList " << QString::fromStdString(Username); //软触发,不考虑误触发、漏触发 if (m_MyData->ifChangeExpourseAndGain == true) { m_MyData->imgIndex++; if (m_MyData->expourseTimeList.size() > 1 && m_MyData->expourseTimeList[m_MyData->imgIndex % m_MyData->expourseTimeList.size()] != m_MyData->expourseTimeList[(m_MyData->imgIndex - 1) % m_MyData->expourseTimeList.size()]) SetExposureTime(m_MyData->expourseTimeList[m_MyData->imgIndex % m_MyData->expourseTimeList.size()], m_MyData); //Sleep(1); if (m_MyData->gainList.size() > 1 && m_MyData->gainList[m_MyData->imgIndex % m_MyData->gainList.size()] != m_MyData->gainList[(m_MyData->imgIndex - 1) % m_MyData->gainList.size()]) SetGain(m_MyData->gainList[m_MyData->imgIndex % m_MyData->gainList.size()], m_MyData); //Sleep(1); } /*if (result == false) { QString currPath = "../runtime/Bin_DEVICE/testImg/testImg_"; if (ifChangeExpourseAndGain == true) currPath +=QString::number(imgIndex-1); else currPath += QString::number(imgIndex); currPath += ".jpg"; n_mutex->lock(); srcImage = cv::imread(currPath.toStdString()); n_mutex->unlock(); qDebug() << "取图失败,读取图片:" << currPath; result = true; }*/ } catch (QString ev) { qDebug() << "[Error] " << " ev:" << ev ; } qDebug() << "[INFO] " << __LINE__ << " run end" ; return result; } //相机连接状态:正常连接或断开 bool Hd_CameraModule_HIK3::checkStatus() { //status = moduleStatus; return m_MyData->moduleStatus; } //void MyThread::run() //{ // MV_CC_SetCommandValue(handle, "TriggerSoftware"); //}