#include "Hd_CameraModule_HIK_soft.h" #include #include #include #include QByteArray mv_Status = "connected";//0106 新增相机断联报警 //cv::Mat srcImage; int index = -1; //相机序号 void* handle; //相机指针 string Username = ""; bool m_flag = false; MV_CC_DEVICE_INFO_LIST m_stDevList;//相机设备 bool moduleStatus = true; QQueue queuepic; cv::Mat matList[1000] = { cv::Mat() }; //data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。 bool ifBreak = false; //ifRunning减少ifBreak的判断;"rest_newProductIn"时,Logic_camera_thread框架会结束未处理完的相相机取图 bool ifRunning = false; bool ifChangeExpourseAndGain = true; MV_CAM_TRIGGER_SOURCE initTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; MV_CAM_TRIGGER_SOURCE currentTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; 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; } #pragma execution_character_set("utf-8") QMutex* n_mutex;// = new QMutex(); //是否为标准通信流程: //标准通信流程,run函数设置曝光/增益;非标准通信流程(简单通信流程),回调函数设置曝光/增益 bool ifStandard = false; //相机取图超时时间 int getImageTimeOut = 1000; //总取图数 int imgIndex = 0; //曝光值列表 QQueue expourseTimeList; //增益列表 QQueue gainList; //0106 断线重连 void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser); void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0); 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 SearchDevice() { 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); for (int i = 0; i < m_stDevList.nDeviceNum; i++) { //SN unsigned char* name = m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber; //userID //unsigned char* name=m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chUserDefinedName; string userName = static_cast((LPCSTR)name); if (Username == userName) { index = i; break; } } if (MV_OK != nRet) { return 0; } return -1; } bool connctDevice() { index = -1; SearchDevice(); if (index == -1) { //未匹配到相机 qDebug() << "[Waring] " << "Hd_CameraModule_HIK_soft not match --CameraName:" << QString::fromStdString(Username); return false; } unsigned char* name = m_stDevList.pDeviceInfo[index]->SpecialInfo.stGigEInfo.chUserDefinedName; string userName = static_cast((LPCSTR)name); qDebug() << "[INFO] " << " start" << "--UserName:" << QString::fromStdString(userName); if (handle != NULL) { MV_CC_StopGrabbing(handle); MV_CC_CloseDevice(handle); MV_CC_DestroyHandle(handle); } //打开相机 MV_CC_CreateHandle(&handle, m_stDevList.pDeviceInfo[index]); int nRet = MV_CC_OpenDevice(handle); ////触发模式 MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); MV_CC_SetEnumValue(handle, "TriggerMode", MV_TRIGGER_MODE_ON); // //加载用户集,相机设置应当UserSet1 nRet = MV_CC_SetEnumValueByString(handle, "UserSetSelector", "UserSet1"); if (MV_OK != nRet) { qDebug() << "Set UserSetSelector fail! nRet " << nRet; } // ch:注册抓图回调 | en:Register image callback MV_CC_SetIntValueEx(handle, "GevHeartbeatTimeout", 3000);//心跳日志 nRet = MV_CC_RegisterImageCallBackEx(handle, ImageCallBackEx, handle);//注册回调 if (MV_OK != nRet) return false; nRet = MV_CC_RegisterExceptionCallBack(handle, ReconnectDevice, NULL);//断线重连 if (MV_OK != nRet) return false; MV_CC_StartGrabbing(handle); return true; } //0106 断线重连 void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser) { mv_Status = "disconnect"; qDebug() << "[Error] " << " MV camera disconnects!"; moduleStatus = false; if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT) { //断开连接 MV_CC_CloseDevice(handle); int nRet = MV_CC_DestroyHandle(handle); handle = nullptr; BOOL bConnected = FALSE; while (1) { Sleep(100); if (connctDevice() == true) { qWarning() << "[Hd_CameraModule_HIK_soft] " << " Hd_CameraModule_HIK_soft create success again! "; moduleStatus = true; break; } } } } void _stdcall ExceptionCB(unsigned int nMesgType, void* pUser) { mv_Status = "disconnect"; qDebug() << "[Error] " << " MV camera disconnects!"; moduleStatus = false; } 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; } Hd_CameraModule_HIK_soft* create() { qDebug() << "[INFO] " << "Hd_CameraModule_HIK_soft create success!" ; return new Hd_CameraModule_HIK_soft; } void destory(Hd_CameraModule_HIK_soft * ptr) { if(ptr) { delete ptr; ptr = nullptr; } qDebug() << "[INFO] " << "Hd_CameraModule_HIK_soft destory success!"; } //回调函数; //经测试,相机像素格式Mono8、RGB8是可以正常转换的,YUV422还需要优化;RGB8格式比YUV422帧率低;BGR格式会导致异色问题 void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFrameInfo0, void* pUser0) { n_mutex->lock(); double time_Start = (double)clock(); int frameNum = 0; cv::Mat srcImage = cv::Mat(); if (pFrameInfo0) { //获取的是单通道灰度图 if (pFrameInfo0->enPixelType == PixelType_Gvsp_Mono8)//获取当前采集到的图像格式 { srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC1, pData0); } //获取的是RGB8图 else if (pFrameInfo0->enPixelType == PixelType_Gvsp_BGR8_Packed) { srcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, pData0); } ////获取的是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; unsigned char* pConvertData = NULL; pConvertData = (unsigned char*)malloc(pFrameInfo0->nWidth * pFrameInfo0->nHeight * 3); if (NULL == pConvertData) { printf("malloc pConvertData fail!\n"); } else { unsigned int nConvertDataSize = 0; nConvertDataSize = pFrameInfo0->nWidth * pFrameInfo0->nHeight * 3; // ch:像素格式转换 | en:Convert pixel format MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 }; frameNum = pFrameInfo0->nFrameNum; //ch:帧号 | en:frame number stConvertParam.nWidth = pFrameInfo0->nWidth; //ch:图像宽 | en:image width stConvertParam.nHeight = pFrameInfo0->nHeight; //ch:图像高 | en:image height stConvertParam.pSrcData = pData0; //ch:输入数据缓存 | en:input data buffer stConvertParam.nSrcDataLen = pFrameInfo0->nFrameLen; //ch:输入数据大小 | en:input data size stConvertParam.enSrcPixelType = pFrameInfo0->enPixelType; //ch:输入像素格式 | en:input pixel format stConvertParam.enDstPixelType = enDstPixelType; //ch:输出像素格式 | en:output pixel format stConvertParam.pDstBuffer = pConvertData; //ch:输出数据缓存 | en:output data buffer stConvertParam.nDstBufferSize = nConvertDataSize; //ch:输出缓存大小 | en:output buffer size int nRet = MV_CC_ConvertPixelType(handle, &stConvertParam); Mat mysrcImage = cv::Mat(pFrameInfo0->nHeight, pFrameInfo0->nWidth, CV_8UC3, stConvertParam.pDstBuffer); mysrcImage.copyTo(srcImage); free(pConvertData); pConvertData = NULL; stConvertParam = { 0 }; } } } if(srcImage.empty()) { srcImage = cv::Mat(5, 5, CV_8UC1).setTo(0); } m_flag = true; queuepic.push_back(srcImage.clone()); n_mutex->unlock(); pData0 = { 0 }; double time_End = (double)clock(); qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg getImg,Time:" << (time_End - time_Start) << "ms" << "--CameraName:" << QString::fromStdString(Username) << " imgIndex:" << imgIndex << "nFrameNum : " << frameNum; /*QString savePath = "../runtime/Bin_DEVICE/testImg/camera_" + 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) { qDebug() << "[INFO] " << "exposureValue:" << exposureValue; MV_CC_SetEnumValue(handle, "ExposureAuto", MV_EXPOSURE_AUTO_MODE_OFF); MV_CC_SetFloatValue(handle, "ExposureTime", exposureValue); } void SetGain(float GainValue) { qDebug() << "[INFO] " << "GainValue:" << GainValue; MV_CC_SetEnumValue(handle, "GainAuto", 0); MV_CC_SetFloatValue(handle, "Gain", GainValue); } Hd_CameraModule_HIK_soft::Hd_CameraModule_HIK_soft() { n_mutex = new QMutex(); m_thread = new MyThread; } //关闭设备 void CloseDevice() { MV_CC_StopGrabbing(handle); MV_CC_CloseDevice(handle); MV_CC_DestroyHandle(handle); handle = nullptr; //此处注释掉的话,软件断开再连接,回调函数不出图 } Hd_CameraModule_HIK_soft::~Hd_CameraModule_HIK_soft() { m_flag = true; 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!"; } //从类中读数据到实例对象 bool Hd_CameraModule_HIK_soft::readData(std::vector &mat,QByteArray &data) { if (queuepic.isEmpty()) { qCritical() << __FUNCTION__ << " line:" <<__LINE__ << " srcImage is null"; return false; } n_mutex->lock(); cv::Mat img = cv::Mat(); queuepic.dequeue().copyTo(img); mat.push_back(img.clone()); n_mutex->unlock(); QString qimgIndex = "imgIndex_" + QString::number(imgIndex-1)+"_中文测试"; data = qimgIndex.toLocal8Bit(); qDebug() << "[INFO] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData--CameraName:" << QString::fromStdString(Username) << "--imgIndex : " << imgIndex-1; return true; } //实例对象把数据写入到类 bool Hd_CameraModule_HIK_soft::writeData(std::vector &mat,QByteArray &data) { //2024.02.18更新,相机对应的读SN信号时,表示新产品进入,设置初始值 if (data == "rest_newProductIn") { //根据实际项目,设置初始值:曝光、增益,ROI区域等 { if (expourseTimeList.size() > 0) SetExposureTime(expourseTimeList[0]); if (gainList.size() > 0) SetGain(gainList[0]); } if (queuepic.size() > 0) { n_mutex->lock(); queuepic.clear(); n_mutex->unlock(); std::cout << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << Username << std::endl; qWarning() << __FUNCTION__ << " line: " << __LINE__ << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << QString::fromStdString(Username); } if (ifRunning == true) { ifBreak = true; Sleep(10); } imgIndex = 0; return true; } else { m_flag = false; //expourseTimeList.clear(); //gainList.clear(); } if (data == "ifChangeExpourseAndGain_false") ifChangeExpourseAndGain = false; else ifChangeExpourseAndGain = true; 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); } if (dataList[i].contains("SetGain_")) { double value = byteArrayToUnicode(dataList[i]).split("SetGain_")[1].toInt(); SetGain(value); } if (dataList[i].contains("TriggerMode_")) { QString value = byteArrayToUnicode(dataList[i]).split("TriggerMode_")[1]; if (value == "软触发") ////触发模式 { MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); currentTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; } else { MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0); currentTriggerSource = MV_TRIGGER_SOURCE_LINE0; } } } } //调试模式下,data==ifChangeExpourseAndGain_false;非调试模式运行时,data不包含SetExposureTime_ else if (data != "ifChangeExpourseAndGain_false" && initTriggerSource != currentTriggerSource) { MV_CC_SetEnumValue(handle, "TriggerSource", initTriggerSource); currentTriggerSource = initTriggerSource; } /*data.append("SetExposureTime_" + ui.spinBox->text() + "#"); data.append("SetGain_" + ui.doubleSpinBox->text() + "#"); data.append("TriggerMode_" + ui.comboBox_triggerMode->currentText());*/ qDebug() << "Hd_CameraModule_HIK_soft::writeData::" << data; m_flag = false; //Username = data.toStdString(); return true; } //传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1... bool Hd_CameraModule_HIK_soft::initParas(QByteArray& initData) { QByteArrayList valueList = initData.split('+'); Username = valueList[0]; imgIndex = 0; expourseTimeList.clear(); gainList.clear(); bool ifOk = true; if (handle == NULL) 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++) expourseTimeList.enqueue(expourseTimeL[j].toFloat()); } if (valuei.contains("gain")) { QStringList gainL = valuei.split('#'); if (gainL.size() > 1) for (int j = 1; j < gainL.size(); j++) gainList.enqueue(gainL[j].toFloat()); } if (valuei.contains("是否为标准通信流程")) { if (valuei.contains("true")) ifStandard = true; } if (valuei.contains("取图超时")) { QStringList gainL = valuei.split('#'); if (gainL.size() > 1) getImageTimeOut = gainL[1].toInt(); if (getImageTimeOut < 50) getImageTimeOut = 1000; } if (valuei.contains("OffsetX")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if(valueL[1].toInt()>=0) MV_CC_SetIntValue(handle, "OffsetX", valueL[1].toInt()); } if (valuei.contains("OffsetY")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if (valueL[1].toInt() >= 0) MV_CC_SetIntValue(handle, "OffsetY", valueL[1].toInt()); } if (valuei.contains("Width")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if (valueL[1].toInt() >= 0) MV_CC_SetIntValue(handle, "Width", valueL[1].toInt()); } if (valuei.contains("Height")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if (valueL[1].toInt() >= 0) MV_CC_SetIntValue(handle, "Height", valueL[1].toInt()); } if (valuei.contains("触发方式")) { QStringList valueL = valuei.split('#'); if (valueL.size() > 1) if (valueL[1].toInt() >= 0) if (valueL[1] == "软触发") { MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE); currentTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; initTriggerSource = MV_TRIGGER_SOURCE_SOFTWARE; } else { MV_CC_SetEnumValue(handle, "TriggerSource", MV_TRIGGER_SOURCE_LINE0); currentTriggerSource = MV_TRIGGER_SOURCE_LINE0; initTriggerSource = MV_TRIGGER_SOURCE_LINE0; } } } if (ifOk == true) { if (expourseTimeList.size() > 0) SetExposureTime(expourseTimeList[0]); if (gainList.size() > 0) SetGain(gainList[0]); } imgIndex = 0; if (ifOk == true) { MVCC_FLOATVALUE mf = { 0 }; MV_CC_GetFloatValue(handle, "ExposureTime", &mf); std::cout << "ExposureTime::" << mf.fCurValue << std::endl; mf = { 0 }; MV_CC_GetFloatValue(handle, "Gain", &mf); std::cout << "Gain::" << mf.fCurValue << std::endl; MVCC_INTVALUE mI = { 0 }; MV_CC_GetIntValue(handle, "OffsetX", &mI); std::cout << "OffsetX::" << mI.nCurValue << std::endl; mI = { 0 }; MV_CC_GetIntValue(handle, "OffsetY", &mI); std::cout << "OffsetY::" << mI.nCurValue << std::endl; mI = { 0 }; MV_CC_GetIntValue(handle, "Width", &mI); std::cout << "Width::" << mI.nCurValue << std::endl; mI = { 0 }; MV_CC_GetIntValue(handle, "Height", &mI); std::cout << "Height::" << mI.nCurValue << std::endl; MVCC_ENUMVALUE me = { 0 }; MV_CC_GetEnumValue(handle,"BalanceWhiteAuto",&me); //自动白平衡 std::cout << "BalanceWhiteAuto::" << me.nCurValue << std::endl; } return ifOk; } bool Hd_CameraModule_HIK_soft::run() { if (imgIndex == expourseTimeList.size()) imgIndex = 0; //Sleep(100); qDebug() << "[INFO] " << " run start" <lock(); m_flag = false; //Sleep(2); //n_mutex->unlock(); //m_thread->run(); //start()线程运行,频率高时有低概率无响应; if (currentTriggerSource == MV_TRIGGER_SOURCE_SOFTWARE) { MV_CC_SetCommandValue(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(Username); while (true) { if (moduleStatus == false || mytime++ > getImageTimeOut || ifBreak == true )//|| m_flag==true) { result = false; break; } n_mutex->lock(); if (queuepic.size() > 0) { n_mutex->unlock(); result = true; break; } n_mutex->unlock(); Sleep(1); } Sleep(1); //qDebug() << "[INFO] " << " expourseTimeList " << QString::fromStdString(Username); //软触发,不考虑误触发、漏触发 if (ifChangeExpourseAndGain == true) { imgIndex++; if (expourseTimeList.size() > 1 && expourseTimeList[imgIndex % expourseTimeList.size()] != expourseTimeList[(imgIndex - 1) % expourseTimeList.size()]) SetExposureTime(expourseTimeList[imgIndex % expourseTimeList.size()]); //Sleep(1); if (gainList.size() > 1 && gainList[imgIndex % gainList.size()] != gainList[(imgIndex - 1) % gainList.size()]) SetGain(gainList[imgIndex % gainList.size()]); //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"; cv::Mat readMat = cv::imread(currPath.toStdString()); queuepic.push_back(readMat); qDebug() << "取图失败,读取图片:" << currPath; result = true; } } catch (QString ev) { qDebug() << "[Error] " << " ev:" << ev ; } qDebug() << "[INFO] " << __LINE__ << " run end" ; return result; } //相机连接状态:正常连接或断开 bool Hd_CameraModule_HIK_soft::checkStatus() { //status = moduleStatus; return moduleStatus; } void MyThread::run() { MV_CC_SetCommandValue(handle, "TriggerSoftware"); }