系列文章目录
提示:这里是该系列文章的所有文章的目录
第一章: (一)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<<"保存原图耗时:"<<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
#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 <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_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<<"相机原图保存路径:"<<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_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<<"相机型号:"<<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:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。