本文出处:https://cloud.tencent.com/developer/article/1730933
使用工业相机采集图像,首先需要对相机的相关参数进行设置。现在项目需要使用SDK进行二次开发。依照以下步骤进行:
1.枚举设备 -> 2.创建句柄 -> 3.打开设备 -> 4.开始抓图 -> 5.获取一帧并保存图像 -> 6.停止抓图 -> 7.关闭设备 -> 8.销毁句柄
第一次使用海康相机SDK,初步按照以下流程进行开发:
第一步: 了解C接口流程。
a.设备连接 b.图像采集显示
设备连接接口流程:
主动取流流程图
回调出流流程图
第二步:学习实例代码,查询C接口定义
1 int MV_CC_EnumDevices(unsigned int nTLayerType, \
MV_CC_DEVICE_INFO_LIST *pstDevList);
参数:
nTLayerType in 传输层协议类型,按位表示,支持复选,可选协议类型如下:
pstDevList out 查找到的设备信息列表
返回值:
成功,返回MV_OK (0);失败,返回错误码。
1 #include "MvCameraControl.h"
2
3 void main()
4 {
5 unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
6
7 MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
8 int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
9 if (MV_OK != nRet)
10 {
11 printf("error: EnumDevices fail [%x]\n", nRet);
12 }
13 }
int MV_CC_CreateHandle(void **handle, const MV_CC_DEVIEC_INFO *pstDevInfo);
参数:
handle out 设备句柄,输出参数;
pstDevInfo in 设备信息版本、MAC地址、传输层类型以及其它设备信息;
返回值:
成功,返回MV_OK (0);失败,返回错误码。
1 #include "MvCameraControl.h"
2
3 void main()
4 {
5 int nRet = -1;
6 void* m_handle = NULL;
7
8 //枚举子网内指定的传输协议对应的所有设备
9 unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
10 MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
11 int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
12 if (MV_OK != nRet)
13 {
14 printf("error: EnumDevices fail [%x]\n", nRet);
15 return;
16 }
17
18 int i = 0;
19 if (m_stDevList.nDeviceNum == 0)
20 {
21 printf("no camera found!\n");
22 return;
23 }
24
25 //选择查找到的第一台在线设备,创建设备句柄
26 int nDeviceIndex = 0;
27
28 MV_CC_DEVICE_INFO m_stDevInfo = {0};
29 memcpy(&m_stDevInfo, m_stDevList.pDeviceInfo[nDeviceIndex], sizeof(MV_CC_DEVICE_INFO));
30
31 nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
32
33 if (MV_OK != nRet)
34 {
35 printf("error: CreateHandle fail [%x]\n", nRet);
36 return;
37 }
38
39 //...其他处理
40
41 //销毁句柄,释放资源
42 nRet = MV_CC_DestroyHandle(m_handle);
43 if (MV_OK != nRet)
44 {
45 printf("error: DestroyHandle fail [%x]\n", nRet);
46 return;
47 }
48 }
int MV_CC_CloseDevice(void *handle);
参数:
handle in 设备句柄,MV_CC_CreateHandle或MV_CC_CreateHandleWithoutLog的out参数。
int MV_CC_DestroyHandle(void *handle);
int MV_CC_RegisterImageCallBackEx(void *handle, const char *pEventName, \
cbEvent cbEvent, void *pUser);
参数:
pEventName in 事件名;
fEventCallBack in 接收Event事件的回调函数
pUser in 用户自定义变量
回调函数
void(__stdcall *cbEvent)(MV_EVENT_OUT_INFO *pEventInfo, void *pUser);
回调函数参数:
pEventInfo out 外部输出Event Info;
pUser out 用户自定义变量;
注意:通过该接口设置事件回调,可以在回调函数里面获取采集、曝光等事件信息。
int MV_CC_StartGrabbing(void *handle);
int MV_CC_GetOneFrame(void *handle, unsigned char *pData, \
unsigned int nDataSize, \
MV_FRAME_OUT_INFO *pFrameInfo
);
参数:
pData in 用于保存图像数据的缓存地址;
nDataSize in 缓存区大小;
pFrameInfo out 获取到的帧信息;
int MV_CC_GetOneFrameTimeout(void *handle, \
unsigned char *pData, \
unsigned int nDataSize, \
MV_FRAME_OUT_INFO_EX *pFrameInfo, \
int nMsec);
参数:
nMsec in 等待超时时间,单位为毫秒;
注意:该接口对于U3V、GIGE相机均可支持。
#include "MvCameraControl.h"
void main()
{
int nRet = -1;
void* m_handle = NULL;
//枚举子网内指定的传输协议对应的所有设备
unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
if (MV_OK != nRet)
{
printf("error: EnumDevices fail [%x]\n", nRet);
return;
}
int i = 0;
if (m_stDevList.nDeviceNum == 0)
{
printf("no camera found!\n");
return;
}
//选择查找到的第一台在线设备,创建设备句柄
int nDeviceIndex = 0;
MV_CC_DEVICE_INFO m_stDevInfo = {0};
memcpy(&m_stDevInfo, m_stDevList.pDeviceInfo[nDeviceIndex], sizeof(MV_CC_DEVICE_INFO));
nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
if (MV_OK != nRet)
{
printf("error: CreateHandle fail [%x]\n", nRet);
return;
}
//连接设备
nRet = MV_CC_OpenDevice(m_handle, nAccessMode, nSwitchoverKey);
if (MV_OK != nRet)
{
printf("error: OpenDevice fail [%x]\n", nRet);
return;
}
//...其他处理
//开始采集图像
nRet = MV_CC_StartGrabbing(m_handle);
if (MV_OK != nRet)
{
printf("error: StartGrabbing fail [%x]\n", nRet);
return;
}
//获取一帧数据的大小
MVCC_INTVALUE stIntvalue = {0};
nRet = MV_CC_GetIntValue(m_handle, "PayloadSize", &stIntvalue);
if (nRet != MV_OK)
{
printf("Get PayloadSize failed! nRet [%x]\n", nRet);
return;
}
int nBufSize = stIntvalue.nCurValue; //一帧数据大小
unsigned int nTestFrameSize = 0;
unsigned char* pFrameBuf = NULL;
pFrameBuf = (unsigned char*)malloc(nBufSize);
MV_FRAME_OUT_INFO_EX stInfo;
memset(&stInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
//上层应用程序需要根据帧率,控制好调用该接口的频率
//此次代码仅供参考,实际应用建议另建线程进行图像帧采集和处理
while(1)
{
if (nTestFrameSize > 99)
{
break;
}
nRet = MV_CC_GetOneFrameTimeout(m_handle, pFrameBuf, nBufSize, &stInfo, 1000);
if (MV_OK != nRet)
{
Sleep(10);
}
else
{
//...图像数据处理
nTestFrameSize++;
}
}
//...其他处理
//停止采集图像
nRet = MV_CC_StopGrabbing(m_handle);
if (MV_OK != nRet)
{
printf("error: StopGrabbing fail [%x]\n", nRet);
return;
}
//关闭设备,释放资源
nRet = MV_CC_CloseDevice(m_handle);
if (MV_OK != nRet)
{
printf("error: CloseDevice fail [%x]\n", nRet);
return;
}
//销毁句柄,释放资源
nRet = MV_CC_DestroyHandle(m_handle);
if (MV_OK != nRet)
{
printf("error: DestroyHandle fail [%x]\n", nRet);
return;
}
}
int MV_CC_GetIntValue(void *handle, const char *strKey, MVCC_INTVALUE *pIntValue);
参数:
strKey in 节点名称;
pIntValue out 获取到的节点值;
可以用来获取需要的节点值。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
day1.20180716
问题记录:
首先,推测是图像数据格式错误
代码摘要:
1 //像素格式转换输入输出参数
2 MV_CC_PIXEL_CONVERT_PARAM stParam;
3 memset(&stParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
4
5 //源数据
6 stParam.pSrcData = m_pFrameBuf; //原始图像数据
7 stParam.nSrcDataLen = stInfo.nFrameLen; //原始图像数据长度
8 stParam.enSrcPixelType = stInfo.enPixelType; //原始图像数据的像素格式
9 stParam.nWidth = stInfo.nWidth; //图像宽
10 stParam.nHeight = stInfo.nHeight; //图像高
11
12 //目标数据
13 stParam.enDstPixelType = PixelType_Gvsp_Mono8; //需要保存的像素格式类型,转换成MONO8格式
14 stParam.nDstBufferSize; //存储节点的大小
15 unsigned char* pImage = (unsigned char*)malloc(stParam.nDstBufferSize);
16 stParam.pDstBuffer; //输出数据缓冲区,存放转换之后的数据
17
18 nRet = MV_CC_ConvertPixelType(m_handle, &stParam);
19 if(MV_OK != nRet)
20 {
21 m_pImgBuf = (unsigned char *)malloc (stParam.nDstBufferSize);
22 memcpy(m_pImgBuf, stParam.pDstBuffer, stParam.nDstBufferSize);
23 break;
24 }
25
26 free(pImage);
27
28
29 显示:
30 gen_image1(&g_img, "byte", g_uiWidth, g_uiHeight, pimgPointer);
31 open_window (0, 0, (Hlong)g_uiWidth, (Hlong)g_uiHeight, (Hlong)g_uiID, "visible", "", &g_window);
32 disp_image(g_img, g_window);
检查图像格式,为单色8位图像,没有错误。
检查halcon接口的创建图像,发现错误定义图像的尺寸大小。
所以,应该在打开相机后查询相机的ROI参数。改正后,单帧图像采集功能正常。
笔记:
强制设置相机网络参数,包括IP地址、子网掩码、默认网关。
int MV_GIGE_ForceIpEx(void *handle, unsigned int nIP, \
unsigned int nSubNetMask, \
unsigned int nDefaultGateWay);
强制设置之后需要重新创建设备句柄,仅支持GigEVision相机。
如果设备未DHCP的状态,调用该接口后设备将会重启~
int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
...
nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
...
// 设置设备网络属性
unsigned int nIP = ...
// 这里。需要知道怎么把IP地址表示为unsigned int
...
nRet = MV_GIGE_ForceIpEx(m_handle, nIP, nSubNetMask, nDefaultGateWay);
...
// 重新创建设备句柄
nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
int MV_GIGE_SetIpConfig(void *handle, unsigned int nType);
参数nType:IP配置方式,定义如下
int MV_CC_SetSDKLogPath(IN const char *pSDKLogPath);
设置好路径后,可以在指定路径下存放sdk日志。
1 ...
2 string strPath = "D:/Hik/SDK";
3 nRet = MV_CC_SetSDKLogPath(strPath.c_str());
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
接下来,做连续采集。