系列文章目录
提示:这里是该系列文章的所有文章的目录 第一章: (一)Qt+OpenCV调用海康工业相机SDK示例开发 第二章: (二)Qt多线程实现海康工业相机图像实时采集 第三章: (三)Qt+OpenCV调用海康工业相机SDK抓拍示例
文章目录
系列文章目录前言一、项目配置二、图像采集与保存三、示例完整代码总结
前言
在这系列文章中,讲述了Qt下结合OpenCV与海康工业相机的使用,对前文的功能进行拓展,在这里做了一个使用海康彩色工业相机定时抓拍的示例,并将相关代码展现出来以便大家学习,如有错误之处,欢迎大家批评指正。
项目效果
提示:以下是本篇文章正文内容,下面案例可供参考
一、项目配置
本文示例是在MSVC_64bit下Release构建的,然后引入了海康SDK和OpenCV对应的库,所以项目的pro文件如下: MyCamera.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
#设置字符
contains( CONFIG,"msvc" ):QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
contains( CONFIG,"msvc" ):QMAKE_CFLAGS +=/source-charset:utf-8 /execution-charset:utf-8
SOURCES += \
capturethread.cpp \
cmvcamera.cpp \
main.cpp \
widget.cpp
HEADERS += \
capturethread.h \
cmvcamera.h \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#HikSDK
INCLUDEPATH += $$PWD/SDK/HikSDK/Includes
DEPENDPATH += $$PWD/SDK/HikSDK/Includes
LIBS += -L$$PWD/SDK/HikSDK/Lib/ -lMvCameraControl
#OpenCV
INCLUDEPATH += $$PWD/SDK/OpenCV/Includes
DEPENDPATH += $$PWD/SDK/OpenCV/Includes
LIBS += -L$$PWD/SDK/OpenCV/Lib/ -lopencv_world455
二、图像采集与保存
示例采集的原理: //点击开始采集后,会关闭触发模式,相机就会不断回调,实时显示相机图像 //点击停止采集后,会开启触发模式并设置为软触发,需要调用命令触发回调
在设备打开后,通过点击抓拍按钮开启线程并打开保存标志位,在线程中使用OpenCV的imwrite函数来进行图像的保存。
//抓拍图像
void Widget::on_pb_grab_clicked()
{
if(!m_bOpenDevice)
{
QMessageBox::warning(this,"警告","抓拍失败,请打开设备!");
return;
}
int time = ui->le_time->text().toInt();
int num = ui->le_num->text().toInt();
m_captureThread->setCameraSignal(time,num);
m_captureThread->setSwitchFlag(true);
m_captureThread->setSaveFlag(true);
m_captureThread->start();
}
......
//保存原图
void CaptureThread::saveOriginImage(cv::Mat imageMat)
{
clock_t originClock = -clock();
QString curTime = QTime::currentTime().toString("hhmmss");
QString iamgeName = m_originPath + "GrabImage_" + curTime + ".jpg";
cv::Mat saveMat;
cvtColor(imageMat,saveMat,cv::COLOR_BGR2RGB); //颜色格式转换
imwrite(iamgeName.toStdString(),saveMat);
originClock += clock();
LOGDEBUG<<"保存原图耗时:"< } 三、示例完整代码 示例的功能实现就不多说了,在下面的代码中有详细的注释,这里将完整代码展示出来: 1.cmvcamera.h(直接从海康提供的SDK中复制,进行了一些修改) /************************************************************************/ /* 以C++接口为基础,对常用函数进行二次封装,方便用户使用 */ /************************************************************************/ #ifndef _MV_CAMERA_H_ #define _MV_CAMERA_H_ #include #include #include "MvCameraControl.h" #include "opencv2/opencv.hpp" //会跟系统函数定义冲突 //using namespace cv; #ifndef MV_NULL #define MV_NULL 0 #endif class CMvCamera { public: CMvCamera(); ~CMvCamera(); // ch:获取SDK版本号 | en:Get SDK Version static int GetSDKVersion(); // ch:枚举设备 | en:Enumerate Device static int EnumDevices(unsigned int nTLayerType, MV_CC_DEVICE_INFO_LIST* pstDevList); // ch:判断设备是否可达 | en:Is the device accessible static bool IsDeviceAccessible(MV_CC_DEVICE_INFO* pstDevInfo, unsigned int nAccessMode); // ch:打开设备 | en:Open Device int Open(MV_CC_DEVICE_INFO* pstDeviceInfo); // ch:关闭设备 | en:Close Device int Close(); // ch:判断相机是否处于连接状态 | en:Is The Device Connected bool IsDeviceConnected(); // ch:注册图像数据回调 | en:Register Image Data CallBack int RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser); // ch:注册彩色图像数据回调 int RegisterImageCallBackRGB(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser); // ch:开启抓图 | en:Start Grabbing int StartGrabbing(); // ch:停止抓图 | en:Stop Grabbing int StopGrabbing(); // ch:主动获取一帧图像数据 | en:Get one frame initiatively int GetImageBuffer(MV_FRAME_OUT* pFrame, int nMsec); // ch:释放图像缓存 | en:Free image buffer int FreeImageBuffer(MV_FRAME_OUT* pFrame); // ch:显示一帧图像 | en:Display one frame image int DisplayOneFrame(MV_DISPLAY_FRAME_INFO* pDisplayInfo); // ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image cache nodes in SDK int SetImageNodeNum(unsigned int nNum); // ch:获取设备信息 | en:Get device information int GetDeviceInfo(MV_CC_DEVICE_INFO* pstDevInfo); // ch:获取GEV相机的统计信息 | en:Get detect info of GEV camera int GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT* pMatchInfoNetDetect); // ch:获取U3V相机的统计信息 | en:Get detect info of U3V camera int GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT* pMatchInfoUSBDetect); // ch:获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Int type parameters, such as Width and Height, for details please refer to MvCameraNode.xlsx file under SDK installation directory int GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX *pIntValue); int SetIntValue(IN const char* strKey, IN int64_t nValue); // ch:获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Enum type parameters, such as PixelFormat, for details please refer to MvCameraNode.xlsx file under SDK installation directory int GetEnumValue(IN const char* strKey, OUT MVCC_ENUMVALUE *pEnumValue); int SetEnumValue(IN const char* strKey, IN unsigned int nValue); int SetEnumValueByString(IN const char* strKey, IN const char* sValue); int GetEnumEntrySymbolic(IN const char* strKey, IN MVCC_ENUMENTRY* pstEnumEntry); // ch:获取和设置Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Float type parameters, such as ExposureTime and Gain, for details please refer to MvCameraNode.xlsx file under SDK installation directory int GetFloatValue(IN const char* strKey, OUT MVCC_FLOATVALUE *pFloatValue); int SetFloatValue(IN const char* strKey, IN float fValue); // ch:获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Bool type parameters, such as ReverseX, for details please refer to MvCameraNode.xlsx file under SDK installation directory int GetBoolValue(IN const char* strKey, OUT bool *pbValue); int SetBoolValue(IN const char* strKey, IN bool bValue); // ch:获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件UserSetSave // en:Get String type parameters, such as DeviceUserID, for details please refer to MvCameraNode.xlsx file under SDK installation directory int GetStringValue(IN const char* strKey, MVCC_STRINGVALUE *pStringValue); int SetStringValue(IN const char* strKey, IN const char * strValue); // ch:执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Execute Command once, such as UserSetSave, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CommandExecute(IN const char* strKey); // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) int GetOptimalPacketSize(unsigned int* pOptimalPacketSize); // ch:注册消息异常回调 | en:Register Message Exception CallBack int RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType, void* pUser), void* pUser); // ch:注册单个事件回调 | en:Register Event CallBack int RegisterEventCallBack(const char* pEventName, void(__stdcall* cbEvent)(MV_EVENT_OUT_INFO * pEventInfo, void* pUser), void* pUser); // ch:强制IP | en:Force IP int ForceIp(unsigned int nIP, unsigned int nSubNetMask, unsigned int nDefaultGateWay); // ch:配置IP方式 | en:IP configuration method int SetIpConfig(unsigned int nType); // ch:设置网络传输模式 | en:Set Net Transfer Mode int SetNetTransMode(unsigned int nType); // ch:像素格式转换 | en:Pixel format conversion int ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM* pstCvtParam); // ch:保存图片 | en:save image int SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam); // ch:保存图片为文件 | en:Save the image as a file int SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM* pstParam); // ch:绘制圆形辅助线 | en:Draw circle auxiliary line int DrawCircle(MVCC_CIRCLE_INFO* pCircleInfo); // ch:绘制线形辅助线 | en:Draw lines auxiliary line int DrawLines(MVCC_LINES_INFO* pLinesInfo); //读取相机中的图像 int ReadBuffer(cv::Mat &image); //保存相机中的图像 int SaveBuffer(QByteArray imageName); private: void *m_hDevHandle; }; #endif//_MV_CAMERA_H_ 2.cmvcamera.cpp #include "cmvcamera.h" CMvCamera::CMvCamera() { m_hDevHandle = MV_NULL; } CMvCamera::~CMvCamera() { if (m_hDevHandle) { MV_CC_DestroyHandle(m_hDevHandle); m_hDevHandle = MV_NULL; } } // ch:获取SDK版本号 | en:Get SDK Version int CMvCamera::GetSDKVersion() { return MV_CC_GetSDKVersion(); } // ch:枚举设备 | en:Enumerate Device int CMvCamera::EnumDevices(unsigned int nTLayerType, MV_CC_DEVICE_INFO_LIST* pstDevList) { return MV_CC_EnumDevices(nTLayerType, pstDevList); } // ch:判断设备是否可达 | en:Is the device accessible bool CMvCamera::IsDeviceAccessible(MV_CC_DEVICE_INFO* pstDevInfo, unsigned int nAccessMode) { return MV_CC_IsDeviceAccessible(pstDevInfo, nAccessMode); } // ch:打开设备 | en:Open Device int CMvCamera::Open(MV_CC_DEVICE_INFO* pstDeviceInfo) { if (MV_NULL == pstDeviceInfo) { return MV_E_PARAMETER; } if (m_hDevHandle) { return MV_E_CALLORDER; } int nRet = MV_CC_CreateHandle(&m_hDevHandle, pstDeviceInfo); if (MV_OK != nRet) { return nRet; } nRet = MV_CC_OpenDevice(m_hDevHandle); if (MV_OK != nRet) { MV_CC_DestroyHandle(m_hDevHandle); m_hDevHandle = MV_NULL; } return nRet; } // ch:关闭设备 | en:Close Device int CMvCamera::Close() { if (MV_NULL == m_hDevHandle) { return MV_E_HANDLE; } MV_CC_CloseDevice(m_hDevHandle); int nRet = MV_CC_DestroyHandle(m_hDevHandle); m_hDevHandle = MV_NULL; return nRet; } // ch:判断相机是否处于连接状态 | en:Is The Device Connected bool CMvCamera::IsDeviceConnected() { return MV_CC_IsDeviceConnected(m_hDevHandle); } // ch:注册图像数据回调 | en:Register Image Data CallBack int CMvCamera::RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser) { return MV_CC_RegisterImageCallBackEx(m_hDevHandle, cbOutput, pUser); } // ch:注册彩色图像数据回调 int CMvCamera::RegisterImageCallBackRGB(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser) { return MV_CC_RegisterImageCallBackForRGB(m_hDevHandle, cbOutput, pUser); } // ch:开启抓图 | en:Start Grabbing int CMvCamera::StartGrabbing() { return MV_CC_StartGrabbing(m_hDevHandle); } // ch:停止抓图 | en:Stop Grabbing int CMvCamera::StopGrabbing() { return MV_CC_StopGrabbing(m_hDevHandle); } // ch:主动获取一帧图像数据 | en:Get one frame initiatively int CMvCamera::GetImageBuffer(MV_FRAME_OUT* pFrame, int nMsec) { return MV_CC_GetImageBuffer(m_hDevHandle, pFrame, nMsec); } // ch:释放图像缓存 | en:Free image buffer int CMvCamera::FreeImageBuffer(MV_FRAME_OUT* pFrame) { return MV_CC_FreeImageBuffer(m_hDevHandle, pFrame); } // ch:设置显示窗口句柄 | en:Set Display Window Handle int CMvCamera::DisplayOneFrame(MV_DISPLAY_FRAME_INFO* pDisplayInfo) { return MV_CC_DisplayOneFrame(m_hDevHandle, pDisplayInfo); } // ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image cache nodes in SDK int CMvCamera::SetImageNodeNum(unsigned int nNum) { return MV_CC_SetImageNodeNum(m_hDevHandle, nNum); } // ch:获取设备信息 | en:Get device information int CMvCamera::GetDeviceInfo(MV_CC_DEVICE_INFO* pstDevInfo) { return MV_CC_GetDeviceInfo(m_hDevHandle, pstDevInfo); } // ch:获取GEV相机的统计信息 | en:Get detect info of GEV camera int CMvCamera::GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT* pMatchInfoNetDetect) { if (MV_NULL == pMatchInfoNetDetect) { return MV_E_PARAMETER; } MV_CC_DEVICE_INFO stDevInfo = {0}; GetDeviceInfo(&stDevInfo); if (stDevInfo.nTLayerType != MV_GIGE_DEVICE) { return MV_E_SUPPORT; } MV_ALL_MATCH_INFO struMatchInfo = {0}; struMatchInfo.nType = MV_MATCH_TYPE_NET_DETECT; struMatchInfo.pInfo = pMatchInfoNetDetect; struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_NET_DETECT); memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_NET_DETECT)); return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo); } // ch:获取U3V相机的统计信息 | en:Get detect info of U3V camera int CMvCamera::GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT* pMatchInfoUSBDetect) { if (MV_NULL == pMatchInfoUSBDetect) { return MV_E_PARAMETER; } MV_CC_DEVICE_INFO stDevInfo = {0}; GetDeviceInfo(&stDevInfo); if (stDevInfo.nTLayerType != MV_USB_DEVICE) { return MV_E_SUPPORT; } MV_ALL_MATCH_INFO struMatchInfo = {0}; struMatchInfo.nType = MV_MATCH_TYPE_USB_DETECT; struMatchInfo.pInfo = pMatchInfoUSBDetect; struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_USB_DETECT); memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_USB_DETECT)); return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo); } // ch:获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Int type parameters, such as Width and Height, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CMvCamera::GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX *pIntValue) { return MV_CC_GetIntValueEx(m_hDevHandle, strKey, pIntValue); } int CMvCamera::SetIntValue(IN const char* strKey, IN int64_t nValue) { return MV_CC_SetIntValueEx(m_hDevHandle, strKey, nValue); } // ch:获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Enum type parameters, such as PixelFormat, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CMvCamera::GetEnumValue(IN const char* strKey, OUT MVCC_ENUMVALUE *pEnumValue) { return MV_CC_GetEnumValue(m_hDevHandle, strKey, pEnumValue); } int CMvCamera::SetEnumValue(IN const char* strKey, IN unsigned int nValue) { return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue); } int CMvCamera::SetEnumValueByString(IN const char* strKey, IN const char* sValue) { return MV_CC_SetEnumValueByString(m_hDevHandle, strKey, sValue); } int CMvCamera::GetEnumEntrySymbolic(IN const char* strKey, IN MVCC_ENUMENTRY* pstEnumEntry) { return MV_CC_GetEnumEntrySymbolic(m_hDevHandle, strKey, pstEnumEntry); } // ch:获取和设置Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Float type parameters, such as ExposureTime and Gain, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CMvCamera::GetFloatValue(IN const char* strKey, OUT MVCC_FLOATVALUE *pFloatValue) { return MV_CC_GetFloatValue(m_hDevHandle, strKey, pFloatValue); } int CMvCamera::SetFloatValue(IN const char* strKey, IN float fValue) { return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue); } // ch:获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Get Bool type parameters, such as ReverseX, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CMvCamera::GetBoolValue(IN const char* strKey, OUT bool *pbValue) { return MV_CC_GetBoolValue(m_hDevHandle, strKey, pbValue); } int CMvCamera::SetBoolValue(IN const char* strKey, IN bool bValue) { return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue); } // ch:获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件UserSetSave // en:Get String type parameters, such as DeviceUserID, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CMvCamera::GetStringValue(IN const char* strKey, MVCC_STRINGVALUE *pStringValue) { return MV_CC_GetStringValue(m_hDevHandle, strKey, pStringValue); } int CMvCamera::SetStringValue(IN const char* strKey, IN const char* strValue) { return MV_CC_SetStringValue(m_hDevHandle, strKey, strValue); } // ch:执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件 // en:Execute Command once, such as UserSetSave, for details please refer to MvCameraNode.xlsx file under SDK installation directory int CMvCamera::CommandExecute(IN const char* strKey) { return MV_CC_SetCommandValue(m_hDevHandle, strKey); } // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) int CMvCamera::GetOptimalPacketSize(unsigned int* pOptimalPacketSize) { if (MV_NULL == pOptimalPacketSize) { return MV_E_PARAMETER; } int nRet = MV_CC_GetOptimalPacketSize(m_hDevHandle); if (nRet < MV_OK) { return nRet; } *pOptimalPacketSize = (unsigned int)nRet; return MV_OK; } // ch:注册消息异常回调 | en:Register Message Exception CallBack int CMvCamera::RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType, void* pUser),void* pUser) { return MV_CC_RegisterExceptionCallBack(m_hDevHandle, cbException, pUser); } // ch:注册单个事件回调 | en:Register Event CallBack int CMvCamera::RegisterEventCallBack(const char* pEventName, void(__stdcall* cbEvent)(MV_EVENT_OUT_INFO * pEventInfo, void* pUser), void* pUser) { return MV_CC_RegisterEventCallBackEx(m_hDevHandle, pEventName, cbEvent, pUser); } // ch:强制IP | en:Force IP int CMvCamera::ForceIp(unsigned int nIP, unsigned int nSubNetMask, unsigned int nDefaultGateWay) { return MV_GIGE_ForceIpEx(m_hDevHandle, nIP, nSubNetMask, nDefaultGateWay); } // ch:配置IP方式 | en:IP configuration method int CMvCamera::SetIpConfig(unsigned int nType) { return MV_GIGE_SetIpConfig(m_hDevHandle, nType); } // ch:设置网络传输模式 | en:Set Net Transfer Mode int CMvCamera::SetNetTransMode(unsigned int nType) { return MV_GIGE_SetNetTransMode(m_hDevHandle, nType); } // ch:像素格式转换 | en:Pixel format conversion int CMvCamera::ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM* pstCvtParam) { return MV_CC_ConvertPixelType(m_hDevHandle, pstCvtParam); } // ch:保存图片 | en:save image int CMvCamera::SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam) { return MV_CC_SaveImageEx2(m_hDevHandle, pstParam); } // ch:保存图片为文件 | en:Save the image as a file int CMvCamera::SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM* pstSaveFileParam) { return MV_CC_SaveImageToFile(m_hDevHandle, pstSaveFileParam); } // ch:绘制圆形辅助线 | en:Draw circle auxiliary line int CMvCamera::DrawCircle(MVCC_CIRCLE_INFO* pCircleInfo) { return MV_CC_DrawCircle(m_hDevHandle, pCircleInfo); } // ch:绘制线形辅助线 | en:Draw lines auxiliary line int CMvCamera::DrawLines(MVCC_LINES_INFO* pLinesInfo) { return MV_CC_DrawLines(m_hDevHandle, pLinesInfo); } //读取相机中的图像 int CMvCamera::ReadBuffer(cv::Mat &image) { unsigned int nRecvBufSize = 0; MVCC_INTVALUE_EX stParam; memset(&stParam,0,sizeof(MVCC_INTVALUE_EX)); int nRet = GetIntValue("PayloadSize",&stParam); if(MV_OK != nRet) { return nRet; } nRecvBufSize = stParam.nCurValue; unsigned char* pDate; pDate = (unsigned char *)malloc(nRecvBufSize); MV_FRAME_OUT_INFO_EX stImageInfo; memset(&stImageInfo,0,sizeof(MV_FRAME_OUT_INFO)); nRet = MV_CC_GetOneFrameTimeout(m_hDevHandle,pDate,nRecvBufSize,&stImageInfo,500); if(MV_OK != nRet) { return nRet; } //用于保存图像的缓存 unsigned int nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048; unsigned char* pBufForSaveImage = (unsigned char*)malloc(nBufSizeForSaveImage); //判断是否为黑白图像 bool isMono; cv::Mat getImage; switch(stImageInfo.enPixelType) { case PixelType_Gvsp_Mono8: case PixelType_Gvsp_Mono10: case PixelType_Gvsp_Mono10_Packed: case PixelType_Gvsp_Mono12: case PixelType_Gvsp_Mono12_Packed: isMono=true; break; default: isMono=false; break; } if(isMono) { getImage = cv::Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,pDate); //单色 } else { //转换图像格式为RGB8 MV_CC_PIXEL_CONVERT_PARAM stConvertParam; memset(&stConvertParam,0,sizeof(MV_CC_PIXEL_CONVERT_PARAM)); stConvertParam.nWidth = stImageInfo.nWidth; stConvertParam.nHeight = stImageInfo.nHeight; stConvertParam.pSrcData = pDate; //输入数据缓存 stConvertParam.nSrcDataLen = stImageInfo.nFrameLen; stConvertParam.enSrcPixelType = stImageInfo.enPixelType; //stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; //输出像素格式 stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed; stConvertParam.pDstBuffer = pBufForSaveImage; //输出数据缓存 stConvertParam.nDstBufferSize = nBufSizeForSaveImage; //输出缓存大小 MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam); getImage = cv::Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC3,pBufForSaveImage); } getImage.copyTo(image); getImage.release(); free(pDate); free(pBufForSaveImage); return MV_OK; } //读取保存相机中的图像 int CMvCamera::SaveBuffer(QByteArray imageName) { unsigned int nRecvBufSize = 0; MVCC_INTVALUE_EX stParam; memset(&stParam,0,sizeof(MVCC_INTVALUE_EX)); int nRet = GetIntValue("PayloadSize",&stParam); //获取Integer属性值 if(MV_OK != nRet) { return nRet; } nRecvBufSize = stParam.nCurValue; unsigned char* pDate; pDate = (unsigned char *)malloc(nRecvBufSize); MV_FRAME_OUT_INFO_EX stImageInfo; memset(&stImageInfo,0,sizeof(MV_FRAME_OUT_INFO)); nRet = MV_CC_GetOneFrameTimeout(m_hDevHandle,pDate,nRecvBufSize,&stImageInfo,500); //采用超时机制获取一帧图片 if(MV_OK != nRet) { return nRet; } MV_SAVE_IMG_TO_FILE_PARAM stSaveFileParam; memset(&stSaveFileParam,0,sizeof(MV_SAVE_IMG_TO_FILE_PARAM)); stSaveFileParam.enImageType = MV_Image_Bmp; stSaveFileParam.enPixelType = stImageInfo.enPixelType; stSaveFileParam.nWidth = stImageInfo.nWidth; stSaveFileParam.nHeight = stImageInfo.nHeight; stSaveFileParam.nDataLen = stImageInfo.nFrameLen; stSaveFileParam.pData = pDate; stSaveFileParam.iMethodValue = 0; sprintf_s(stSaveFileParam.pImagePath,256,imageName.data()); //文件名 nRet = SaveImageToFile(&stSaveFileParam); //保存图片为文件 if(MV_OK != nRet) { return nRet; } free(pDate); return MV_OK; } 3.capturethread.h #ifndef CAPTURETHREAD_H #define CAPTURETHREAD_H #include #include #include #include #include #include #include #include #include "cmvcamera.h" #define LOGDEBUG qDebug()< class CaptureThread : public QThread { Q_OBJECT public: explicit CaptureThread(QObject *parent = nullptr); ~CaptureThread(); void initThread(); void setCameraPtr(CMvCamera *camera); void setCameraSignal(int time,int num); void setSavePath(QString originPath); void setSaveFlag(bool saveFlag); void setSwitchFlag(bool switchFlag); void setSoftModeFlag(bool softModeFlag); void setImageBuffer(cv::Mat imageMat); void run(); QImage cvMatToImage(const cv::Mat imageMat); void saveOriginImage(cv::Mat imageMat); signals: void signal_newImage(QImage newImage); private: static void __stdcall ImageCallback(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser); private: CMvCamera *m_cameraPtr = NULL; int m_imageTime; //抓拍间隔时间 int m_imageNum; //抓拍间隔次数 QString m_originPath; //原图保存路径 bool m_saveFlag; //保存图像标志 bool m_switchFlag; //线程开启标志 bool m_softModeFlag; //软触发模式标志 }; #endif // CAPTURETHREAD_H 4.capturethread.cpp #include "capturethread.h" CaptureThread::CaptureThread(QObject *parent) : QThread{parent} { this->initThread(); } CaptureThread::~CaptureThread() { } //初始化图像捕获线程 void CaptureThread::initThread() { m_imageTime = 1000; m_imageNum = 1; m_originPath = ""; m_saveFlag = false; m_switchFlag = false; m_softModeFlag = false; } //设置相机指针 void CaptureThread::setCameraPtr(CMvCamera *camera) { m_cameraPtr = camera; //注册回调函数 int nRet = m_cameraPtr->RegisterImageCallBackRGB(ImageCallback,this); //彩色相机 if(MV_OK != nRet) { LOGDEBUG<<"相机注册回调函数失败"; } else { LOGDEBUG<<"相机注册回调函数成功"; } } //设置相机拍照间隔时间和次数 void CaptureThread::setCameraSignal(int time,int num) { m_imageTime = time*1000; m_imageNum = num; if(m_imageTime <= 0) { m_imageTime = 1000; } if(m_imageNum <= 0) { m_imageNum = 1; } } //设置图像保存路径 void CaptureThread::setSavePath(QString originPath) { m_originPath = originPath; LOGDEBUG<<"相机原图保存路径:"< } //设置是否保存图像 void CaptureThread::setSaveFlag(bool saveFlag) { m_saveFlag = saveFlag; } //设置线程开关 void CaptureThread::setSwitchFlag(bool switchFlag) { m_switchFlag = switchFlag; } //设置软触发 void CaptureThread::setSoftModeFlag(bool softModeFlag) { m_softModeFlag = softModeFlag; } //获取回调返回的图像 void CaptureThread::setImageBuffer(cv::Mat imageMat) { LOGDEBUG<<"获取回调图像"; if(m_saveFlag) { m_saveFlag = false; saveOriginImage(imageMat); } emit signal_newImage(cvMatToImage(imageMat)); } //线程运行 void CaptureThread::run() { static int startNum = 0; while(m_switchFlag) { if(startNum < m_imageNum) { startNum++; if(m_softModeFlag) { m_cameraPtr->CommandExecute("TriggerSoftware"); } m_saveFlag = true; } else { startNum = 0; m_switchFlag = false; } msleep(m_imageTime); } } //cv::Mat转QImage QImage CaptureThread::cvMatToImage(const cv::Mat imageMat) { //颜色转换,opencv默认的彩色图像的颜色空间是BGR //cvtColor(imageMat,imageMat,cv::COLOR_BGR2RGB); QImage myImage; if(imageMat.channels() > 1) { myImage = QImage((const unsigned char*)(imageMat.data),imageMat.cols,imageMat.rows,QImage::Format_RGB888); //彩色图 } else { myImage = QImage((const unsigned char*)(imageMat.data),imageMat.cols,imageMat.rows,QImage::Format_Indexed8); //灰度图 } return myImage; } //保存原图 void CaptureThread::saveOriginImage(cv::Mat imageMat) { clock_t originClock = -clock(); QString curTime = QTime::currentTime().toString("hhmmss"); QString iamgeName = m_originPath + "GrabImage_" + curTime + ".jpg"; cv::Mat saveMat; cvtColor(imageMat,saveMat,cv::COLOR_BGR2RGB); //颜色格式转换 imwrite(iamgeName.toStdString(),saveMat); originClock += clock(); LOGDEBUG<<"保存原图耗时:"< } //回调函数 void __stdcall CaptureThread::ImageCallback(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser) { //LOGDEBUG<<"回调触发"; CaptureThread* pThread = static_cast //创建cv::Mat对象 cv::Mat showMat(pFrameInfo->nHeight,pFrameInfo->nWidth,CV_8UC3,pData); //彩色 //将图像保存到容器中 pThread->setImageBuffer(showMat); } 5.widget.h #ifndef WIDGET_H #define WIDGET_H #include #include #include "capturethread.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void initWidget(); private slots: void slot_displayImage(QImage myImage); void on_pb_find_clicked(); void on_pb_open_clicked(); void on_pb_close_clicked(); void on_pb_set_clicked(); void on_pb_start_clicked(); void on_pb_stop_clicked(); void on_pb_grab_clicked(); private: Ui::Widget *ui; bool m_bOpenDevice; QSize m_showSize; CaptureThread *m_captureThread; MV_CC_DEVICE_INFO_LIST m_stDevList; CMvCamera *m_pcMyCamera = NULL; MV_SAVE_IAMGE_TYPE m_nSaveImageType = MV_Image_Bmp; }; #endif // WIDGET_H 6.widget.cpp #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); initWidget(); } Widget::~Widget() { delete ui; if(m_pcMyCamera) { m_pcMyCamera->Close(); delete m_pcMyCamera; m_pcMyCamera = NULL; } } //初始化 void Widget::initWidget() { //设置窗口属性 this->setWindowTitle("抓图测试"); ui->pb_close->setEnabled(false); ui->pb_stop->setEnabled(false); //初始化变量 m_bOpenDevice = false; m_showSize = QSize(768,512); //生成保存图片的文件夹 QString imagePath = QCoreApplication::applicationDirPath() + "/SaveImage/"; QDir dstDir(imagePath); if(!dstDir.exists()) { if(!dstDir.mkdir(imagePath)) { LOGDEBUG<<"创建图像保存文件夹失败!"; } else { LOGDEBUG<<"创建图像保存文件夹成功!"; } } //初始化线程 m_captureThread = new CaptureThread(); connect(m_captureThread,SIGNAL(signal_newImage(QImage)),this,SLOT(slot_displayImage(QImage)),Qt::BlockingQueuedConnection); m_captureThread->setSavePath(imagePath); } //显示图像 void Widget::slot_displayImage(QImage myImage) { QPixmap newPixmap = QPixmap::fromImage(myImage).scaled(m_showSize,Qt::KeepAspectRatio,Qt::SmoothTransformation); ui->lb_show->setPixmap(newPixmap); } //查找设备 void Widget::on_pb_find_clicked() { ui->cb_devices->clear(); memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST)); //枚举子网内所有设备 int nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,&m_stDevList); if(MV_OK != nRet) { LOGDEBUG<<"设备枚举失败"; return; } for(unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) { MV_CC_DEVICE_INFO* pDeviceInfo = m_stDevList.pDeviceInfo[i]; QString strModelName = ""; if(pDeviceInfo->nTLayerType == MV_USB_DEVICE) { strModelName = (char*)pDeviceInfo->SpecialInfo.stUsb3VInfo.chModelName; } else if(pDeviceInfo->nTLayerType == MV_GIGE_DEVICE) { strModelName = (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chModelName; } else { QMessageBox::warning(this,"警告","未知设备枚举!"); return; } LOGDEBUG<<"相机型号:"< ui->cb_devices->addItem(strModelName); } } //打开设备 void Widget::on_pb_open_clicked() { if(m_bOpenDevice) { return; } QString deviceModel = ui->cb_devices->currentText(); if(deviceModel == "") { QMessageBox::warning(this,"警告","请先查找并选择设备!"); return; } //相机对象 m_pcMyCamera = new CMvCamera; //打开设备 int nIndex = ui->cb_devices->currentIndex(); int nRet = m_pcMyCamera->Open(m_stDevList.pDeviceInfo[nIndex]); if(MV_OK != nRet) { delete m_pcMyCamera; m_pcMyCamera = NULL; QMessageBox::warning(this,"警告","打开设备失败!"); return; } else { LOGDEBUG<<"打开设备成功!"; } //设置为触发模式,触发源为软触发 m_pcMyCamera->SetEnumValue("TriggerMode",1); m_pcMyCamera->SetEnumValue("TriggerSource",7); //设置曝光时间和增益 int exposureTime = ui->le_exposureTime->text().toInt(); int gain = ui->le_gain->text().toInt(); m_pcMyCamera->SetFloatValue("ExposureTime",exposureTime); m_pcMyCamera->SetEnumValue("GainAuto",0); m_pcMyCamera->SetFloatValue("Gain",gain); //相机线程设置,注册回调 m_captureThread->setCameraPtr(m_pcMyCamera); //开启相机采集 m_pcMyCamera->StartGrabbing(); //开启标志位 m_bOpenDevice = true; //使能按键 ui->pb_find->setEnabled(false); ui->pb_open->setEnabled(false); ui->pb_close->setEnabled(true); } //关闭设备 void Widget::on_pb_close_clicked() { if(m_bOpenDevice) { m_bOpenDevice = false; if(m_pcMyCamera) { m_pcMyCamera->Close(); delete m_pcMyCamera; m_pcMyCamera = NULL; } } //使能按键 ui->pb_find->setEnabled(true); ui->pb_open->setEnabled(true); ui->pb_close->setEnabled(false); } //设置 void Widget::on_pb_set_clicked() { if(!m_bOpenDevice) { QMessageBox::warning(this,"警告","设置失败,请打开设备!"); return; } int exposureTime = ui->le_exposureTime->text().toInt(); int gain = ui->le_gain->text().toInt(); //设置曝光时间 m_pcMyCamera->SetFloatValue("ExposureTime",exposureTime); //设置增益前先把自动增益关闭,失败无需返回 m_pcMyCamera->SetEnumValue("GainAuto",0); m_pcMyCamera->SetFloatValue("Gain",gain); //设置显示宽度和高度 int showW = ui->le_w->text().toInt(); int showH = ui->le_h->text().toInt(); if(showW < 768) { showW = 768; ui->le_w->setText("768"); } if(showH < 512) { showH = 512; ui->le_h->setText("512"); } m_showSize = QSize(showW,showH); } //开始采集 //点击开始采集后,会关闭触发模式,相机就会不断回调,实时显示相机图像 void Widget::on_pb_start_clicked() { if(!m_bOpenDevice) { QMessageBox::warning(this,"警告","采集失败,请打开设备!"); return; } //不保存图像 m_captureThread->setSaveFlag(false); //关闭触发模式 m_captureThread->setSoftModeFlag(false); m_pcMyCamera->SetEnumValue("TriggerMode",0); //使能按键 ui->pb_find->setEnabled(false); ui->pb_open->setEnabled(false); ui->pb_close->setEnabled(false); ui->pb_start->setEnabled(false); ui->pb_stop->setEnabled(true); } //停止采集 //点击停止采集后,会开启触发模式并设置为软触发,需要调用命令触发回调 void Widget::on_pb_stop_clicked() { if(!m_bOpenDevice) { QMessageBox::warning(this,"警告","采集失败,请打开设备!"); return; } //设置为触发模式,触发源为软触发 m_captureThread->setSoftModeFlag(true); m_pcMyCamera->SetEnumValue("TriggerMode",1); m_pcMyCamera->SetEnumValue("TriggerSource",7); //使能按键 ui->pb_find->setEnabled(false); ui->pb_open->setEnabled(false); ui->pb_close->setEnabled(true); ui->pb_start->setEnabled(true); ui->pb_stop->setEnabled(false); ui->pb_grab->setEnabled(true); } //抓拍图像 void Widget::on_pb_grab_clicked() { if(!m_bOpenDevice) { QMessageBox::warning(this,"警告","抓拍失败,请打开设备!"); return; } int time = ui->le_time->text().toInt(); int num = ui->le_num->text().toInt(); m_captureThread->setCameraSignal(time,num); m_captureThread->setSwitchFlag(true); m_captureThread->setSaveFlag(true); m_captureThread->start(); } 7.widget.ui 总结 这个示例相较于前文,也是增加了下设置相机曝光时间和增益这两个参数的功能,可以看到也是比较简单的,主要是要了解相机SDK相关的接口,并且海康相机的相关文档和示例也是很详细的,类似这样的开发,我们首先要做的就是从文档中找答案~ hello: 共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。 好文链接
发表评论