系列文章目录
提示:这里是该系列文章的所有文章的目录
第一章: (一)Qt+OpenCV调用海康工业相机SDK示例开发
第二章: (二)Qt多线程实现海康工业相机图像实时采集
第三章: (三)Qt+OpenCV调用海康工业相机SDK抓拍示例
文章目录
- 系列文章目录
- 前言
- 一、项目配置
- 二、图像采集与保存
- 三、示例完整代码
- 总结
前言
在这系列文章中,讲述了Qt下结合OpenCV与海康工业相机的使用,对前文的功能进行拓展,在这里做了一个使用海康彩色工业相机定时抓拍的示例,并将相关代码展现出来以便大家学习,如有错误之处,欢迎大家批评指正。
项目效果
提示:以下是本篇文章正文内容,下面案例可供参考
一、项目配置
本文示例是在MSVC_64bit下Release构建的,然后引入了海康SDK和OpenCV对应的库,所以项目的pro文件如下:
MyCamera.pro
QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11DEFINES += 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-8SOURCES += \capturethread.cpp \cmvcamera.cpp \main.cpp \widget.cppHEADERS += \capturethread.h \cmvcamera.h \widget.hFORMS += \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<<"保存原图耗时:"<<originClock<<"ms"; //测试在20ms左右
}
三、示例完整代码
示例的功能实现就不多说了,在下面的代码中有详细的注释,这里将完整代码展示出来:
1.cmvcamera.h(直接从海康提供的SDK中复制,进行了一些修改)
/************************************************************************/
/* 以C++接口为基础,对常用函数进行二次封装,方便用户使用 */
/************************************************************************/#ifndef _MV_CAMERA_H_
#define _MV_CAMERA_H_#include <string.h>
#include <QCoreApplication>
#include "MvCameraControl.h"
#include "opencv2/opencv.hpp"//会跟系统函数定义冲突
//using namespace cv;#ifndef MV_NULL
#define MV_NULL 0
#endifclass CMvCamera
{
public:CMvCamera();~CMvCamera();// ch:获取SDK版本号 | en:Get SDK Versionstatic int GetSDKVersion();// ch:枚举设备 | en:Enumerate Devicestatic int EnumDevices(unsigned int nTLayerType, MV_CC_DEVICE_INFO_LIST* pstDevList);// ch:判断设备是否可达 | en:Is the device accessiblestatic bool IsDeviceAccessible(MV_CC_DEVICE_INFO* pstDevInfo, unsigned int nAccessMode);// ch:打开设备 | en:Open Deviceint Open(MV_CC_DEVICE_INFO* pstDeviceInfo);// ch:关闭设备 | en:Close Deviceint Close();// ch:判断相机是否处于连接状态 | en:Is The Device Connectedbool IsDeviceConnected();// ch:注册图像数据回调 | en:Register Image Data CallBackint 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 Grabbingint StartGrabbing();// ch:停止抓图 | en:Stop Grabbingint StopGrabbing();// ch:主动获取一帧图像数据 | en:Get one frame initiativelyint GetImageBuffer(MV_FRAME_OUT* pFrame, int nMsec);// ch:释放图像缓存 | en:Free image bufferint FreeImageBuffer(MV_FRAME_OUT* pFrame);// ch:显示一帧图像 | en:Display one frame imageint DisplayOneFrame(MV_DISPLAY_FRAME_INFO* pDisplayInfo);// ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image cache nodes in SDKint SetImageNodeNum(unsigned int nNum);// ch:获取设备信息 | en:Get device informationint GetDeviceInfo(MV_CC_DEVICE_INFO* pstDevInfo);// ch:获取GEV相机的统计信息 | en:Get detect info of GEV cameraint GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT* pMatchInfoNetDetect);// ch:获取U3V相机的统计信息 | en:Get detect info of U3V cameraint 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 directoryint 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 directoryint 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 directoryint 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 directoryint 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 directoryint 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 directoryint 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 CallBackint RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType, void* pUser), void* pUser);// ch:注册单个事件回调 | en:Register Event CallBackint RegisterEventCallBack(const char* pEventName, void(__stdcall* cbEvent)(MV_EVENT_OUT_INFO * pEventInfo, void* pUser), void* pUser);// ch:强制IP | en:Force IPint ForceIp(unsigned int nIP, unsigned int nSubNetMask, unsigned int nDefaultGateWay);// ch:配置IP方式 | en:IP configuration methodint SetIpConfig(unsigned int nType);// ch:设置网络传输模式 | en:Set Net Transfer Modeint SetNetTransMode(unsigned int nType);// ch:像素格式转换 | en:Pixel format conversionint ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM* pstCvtParam);// ch:保存图片 | en:save imageint SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam);// ch:保存图片为文件 | en:Save the image as a fileint SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM* pstParam);// ch:绘制圆形辅助线 | en:Draw circle auxiliary lineint DrawCircle(MVCC_CIRCLE_INFO* pCircleInfo);// ch:绘制线形辅助线 | en:Draw lines auxiliary lineint 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{//转换图像格式为RGB8MV_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 <QObject>
#include <QThread>
#include <QImage>
#include <QDir>
#include <QTimer>
#include <QDate>
#include <QDateTime>
#include <QDebug>
#include "cmvcamera.h"#define LOGDEBUG qDebug()<<QTime::currentTime().toString("[hh:mm:ss:zzz]")class CaptureThread : public QThread
{Q_OBJECTpublic: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<<"相机原图保存路径:"<<m_originPath;
}//设置是否保存图像
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<<"保存原图耗时:"<<originClock<<"ms"; //测试在20ms左右
}//回调函数
void __stdcall CaptureThread::ImageCallback(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser)
{//LOGDEBUG<<"回调触发";CaptureThread* pThread = static_cast<CaptureThread *>(pUser);//创建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 <QWidget>
#include <QMessageBox>
#include "capturethread.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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<<"相机型号:"<<strModelName;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:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。