C# 海康工业相机对接流程、技巧及常见问题
转自: DotNet技术匠
本文只做学术分享,如有侵权,联系删文
前言
在工业自动化视觉检测领域,海康威视工业相机以其高性价比和完善的SDK支持被广泛应用。
本文将基于C#语言,结合海康威视官方SDK,详细介绍工业相机的对接开发流程、关键技术实现及常见问题解决方案。通过实际代码示例,帮助大家快速掌握海康相机的集成开发方法。
开发环境准备
1、SDK安装
下载地址
https://www.hikrobotics.com/cn/machinevision/service/download/?module=0
关键组件
MvCameraControl.dll(核心SDK)
MVS开发工具包(含虚拟相机调试工具)
运行时依赖库(需安装官方Runtime)
2、开发方案选择
方案一 :直接引用DLL(推荐)
需将DLL文件复制到输出目录
需处理32/64位系统兼容性问题
方案二 :源码集成(开发调试更便捷)
直接包含SDK源码文件
可查看方法注释,便于调试
核心代码实现
1、相机初始化与枚举
publicclassCameraHelper
{
privatereadonly ICancheService _cancheService;
publicstring savePathByDB = Path.Combine(Environment.CurrentDirectory, "productPic");
publicCameraHelper(ICancheService cancheService)
{
_cancheService = cancheService;
}
publicstringDeviceListAcq()
{
MyCamera.MV_CC_DEVICE_INFO_LIST m_stDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
int nRet = MyCamera.MV_CC_EnumDevices_NET(
MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE,
ref m_stDeviceList);
if (nRet != 0 || m_stDeviceList.nDeviceNum == 0)
return HK_ErrorCode("未找到设备", nRet);
List cbDeviceList = new List();
for (int i = 0; i < m_stDeviceList.nDeviceNum; i++)
{
var device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(
m_stDeviceList.pDeviceInfo[i],
typeof(MyCamera.MV_CC_DEVICE_INFO));
var cameraInfo = new CameraInfo();
cameraInfo.device = device;
cameraInfo.device_Hik = new MyCamera();
// 初始化相机...
nRet = cameraInfo.device_Hik.MV_CC_CreateDevice_NET(ref device);
if (nRet != MyCamera.MV_OK) continue;
nRet = cameraInfo.device_Hik.MV_CC_OpenDevice_NET();
if (nRet != MyCamera.MV_OK) continue;
// 设置相机参数...
cameraInfo.device_Hik.MV_CC_SetEnumValue_NET(
"AcquisitionMode",
(uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);
cbDeviceList.Add(cameraInfo);
}
_cancheService.UpdateCameraSettingByCache(cbDeviceList);
return"";
}
}
2、触发模式实现
publicstringTriggerMode(CameraInfo cameraInfo)
{
int nRet;
// 停止抓图(如果正在运行)
if (cameraInfo.isStartCatchPic)
{
nRet = cameraInfo.device_Hik.MV_CC_StopGrabbing_NET();
if (nRet != MyCamera.MV_OK)
return HK_ErrorCode("相机关闭抓图失败", nRet);
}
// 开启抓图
nRet = cameraInfo.device_Hik.MV_CC_StartGrabbing_NET();
if (nRet != MyCamera.MV_OK)
return HK_ErrorCode("相机开启抓图失败", nRet);
// 设置触发模式
cameraInfo.device_Hik.MV_CC_SetEnumValue_NET(
"TriggerMode",
(uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
if (cameraInfo.isSoft)
{
// 软触发实现
cameraInfo.device_Hik.MV_CC_SetEnumValue_NET(
"TriggerSource",
(uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
nRet = cameraInfo.device_Hik.MV_CC_SetCommandValue_NET("TriggerSoftware");
if (nRet != MyCamera.MV_OK)
return HK_ErrorCode("相机软触发失败", nRet);
}
else
{
// 硬触发实现
cameraInfo.device_Hik.MV_CC_SetEnumValue_NET(
"TriggerSource",
(uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0);
}
return"";
}
3、图像回调处理
publicvoidImageCallBack(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
{
int nIndex = (int)pUser;
var cameraList = _cancheService.GetCameraListByCache();
lock (cameraList[nIndex].m_BufForSaveImageLock)
{
if (!cameraList[nIndex].isSoft)
{
StartCatchPic(cameraList[nIndex], pFrameInfo, pData);
}
}
}
publicstringStartCatchPic(CameraInfo m_MyCameraInfo, MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pData = default)
{
// 内存分配与数据拷贝
if (m_MyCameraInfo.m_pSaveImageBuf == IntPtr.Zero || pFrameInfo.nFrameLen > m_MyCameraInfo.m_nSaveImageBufSize)
{
// 内存重分配逻辑...
}
CopyMemory(m_MyCameraInfo.m_pSaveImageBuf, pData, pFrameInfo.nFrameLen);
// 保存图像到文件
var fileName = #34;Dev{m_MyCameraInfo.CanmeraId}_ti{m_MyCameraInfo.m_stFrameInfo.nHostTimeStamp}.jpeg";
var stSaveFileParam = new MyCamera.MV_SAVE_IMG_TO_FILE_PARAM
{
enImageType = MyCamera.MV_SAVE_IAMGE_TYPE.MV_Image_Jpeg,
pData = m_MyCameraInfo.m_pSaveImageBuf,
nDataLen = m_MyCameraInfo.m_stFrameInfo.nFrameLen,
pImagePath = Path.Combine(savePathByDB, fileName)
};
int nRet = m_MyCameraInfo.device_Hik.MV_CC_SaveImageToFile_NET(ref stSaveFileParam);
if (nRet != MyCamera.MV_OK)
return HK_ErrorCode("图片保存失败", nRet);
return#34;pack://siteoforigin:,,,/productPic/{fileName}";
}
关键技术
1、内存管理
使用 Marshal.AllocHGlobal
分配非托管内存
必须成对使用 Marshal.Release
释放内存
线程安全处理:通过 lock
保证多线程环境下的内存操作安全
2、错误处理
统一错误码处理: HK_ErrorCode
方法将错误码转换为可读信息
关键错误日志记录:通过
记录操作日志
_cancheService.UpdateLogging
3、性能优化
图像数据缓存:复用内存缓冲区避免频繁分配
异步处理:图像回调与主业务逻辑解耦
常见问题与解决方案
1、DLL加载失败
现象: 无法加载 dll“MvcameraControl.dll”
解决方案
安装官方Runtime
确保32/64位系统与DLL架构匹配
使用Dependency Walker检查依赖项
2、相机无法枚举
检查项
相机IP配置是否正确(GigE相机)
相机是否被其他程序占用
防火墙是否阻止了相机通信
3、触发模式失效
解决方案
确认相机支持所选触发模式
检查触发源设置是否正确
软触发时需先发送触发命令再采集图像
4、图像保存失败
常见原因
保存路径不存在或无权限
内存拷贝不完整(检查 nFrameLen
与实际数据长度)
像素格式不匹配(检查 enPixelType
)
5、错误码解决方案
1、MV_OK 0x00000000 成功,无错误
解析:-2147483648/0x80000000正常状态返回,执行成功
2、MV_E_HANDLE 0x80000000 错误或无效的句
解析:-2147483648/0x80000000 无效句柄,常见问题如下:
用户没有申请句柄,直接调用接口,新手常犯的错误,要引导去学习我们接口使用流程
用户创建了句柄,但是其他地方销毁了句柄,用户没有注意到,需要仔细排查代码
3、MV_E_SUPPORT 0x80000001 不支持的功能
解析:-2147483647/0x80000001
SDK接口的bayer空域降噪、无损压缩、色彩矫正等ISP功能,需要配合CS-Pro系列相机支持
格式转化时,不同格式的相互转化,超出了算法能力集,详情请仔细查阅SDK接口说明
4、MV_E_BUFOVER 0x80000002 缓存已满
解析:-2147483646/0x80000002
常见于gige驱动启动时报错,低版本SDK在某些网卡上面易发,驱动启动失败后,走socket协议发送接收相机数据,效率低,CPU负载大 推荐使用SDK3.5版本解决此问题
5、MV_E_CALLORDER 0x80000003 函数调用顺序有误
解析:-2147483645/0x80000003
sdk接口调用,有一定流程顺序,例如getimagebuffer在startgrabing之前调用,就违反了接口流程,就会报错顺序调用错误 还比如,没有调用startgrabing接口,就去调用频繁调用stopgrabing接口,也会报此错误
6、MV_E_PARAMETER 0x80000004 错误的参数
解析:-2147483644/0x80000004
常见问题: 常见于格式转化、图像保存等需要补充数据结构的接口调用,部分参数传入错误,或者没有传入,这个时候,要去仔细检查参数的传入是否正确
7、MV_E_NODATA 0x80000007 无数据
解析:-2147483641/0x80000007无数据
相机帧率低,用户调用主动取流接口
getimagebuffer/getoneframetimout频率高于相机出图频率,且超时时间短,没有拿到图片,此时应该打印相机帧号,如帧号连续则为正常现象
相机处于触发模式,没有触发信号给到相机,此时,应该排查用户是否给了软触发或者硬触发信号
相机停流,此时,建议打开MVS,观察相机状态
耐心寻找规律,看看是否跟packsize、scpd、取流超时时间不合理所致
8、MV_E_NOENOUGH_BUF 0x8000000A 传入的内存空间不足
解析:-2147483638/0x8000000A
1、用户自行开辟的内存大小,小于当前相机图像所需要的图像大小,例如用mono8的图像大小,接收RGB的图像
2、用户定义的内存大小,中途更换了分辨率更高的相机,导致所需内存较多
3、相机开启了chunk功能,用户开辟缓存大小,仅考虑了图像宽 高 像素格式,没有考虑到chunk
解决方法:
排查内存开辟大小,建议使用相机payloadsize大小
检查相机图像格式
关闭相机chunk等功能
9、MV_E_UNKNOW 0x800000FF 未知的错误
解析:-2147483137/0x800000FF GenICam未知错误
未知错误,形成原因较难分析,建议如下
更新最新版本的sdk
开启sdk日志等级,通过日志分析形成原因
10、MV_E_GC_GENERIC 0x80000100 通用错误
解析:-2147483392/0x80000100
通用接口调用,关键词写错,例如曝光:ExposureTime,拼写错误就会报错
第三方相机链接,例如迈德威视相机链接MVS,也会报通用错误,这是因为迈德威视不是标准的genicam协议的相机导致的
接口类型用错,例如曝光时float型节点,我们使用了一个int型的节点接口进行读写,访问,那么也会报通用错误
11、MV_E_GC_RANGE 0x80000102 值超出范围
解析:-2147483390/0x80000102
接口传入的参数值,超出相机接受范围,例如,曝光存在上下限,图像宽高存在步进,没有按照步进进行设置等等
12、MV_E_GC_ACCESS 0x80000106 节点访问条件有误
解析:-2147483386/0x80000106
常见的问题类型有: 相机节点不存在或者无法访问,例如,自动曝光,在手动曝光情况下,自动曝光节点会被隐藏,或者其他相机存在这个参数,而使用的相机无此参数,例如线扫相机的行频参数等等,还比如说部分相机无此功能,例如event参数,部分相机固件暂不支持用户调用
13、MV_E_GC_TIMEOUT 0x80000107 超时
解析:-2147483385/0x80000107 GVCP命名包回复超时,一般出现在网络环境不好的情况下,此时应该调用接口加大gvcp命令包等待时间(MV_GIGE_GetGvcpTimeout()),持续出现该报错,应该排查网络环境问题
分析:根据海康SDK提示文件:更新官网最新SDK时,设备网络SDK开发包【库文件】里的HCNetSDK.dll、HCCore.dll、PlayCtrl.dll、SuperRender.dll、AudioRender.dll、HCNetSDKCom文件夹等文件均要加载到程序里面,HCNetSDKCom文件夹(包含里面的功能组件dll库文件)需要和HCNetSDK.dll、HCCore.dll一起加载,放在同一个目录下,且HCNetSDKCom文件夹名不能修改。
解决方法:将海康SDK的头文件放到Debug文件夹.exe文件的存放处:
14、MV_E_ACCESS_DENIED 0x80000203 设备无访问权限
解析:-2147483133/0x80000203常见问题有:
相机被其他软件打开占用,关闭其他软件,检查设备管理器中,可能存在的残留进程
代码debug下,心跳时间问题,等待60s后,可以重新打开(此问题参考心跳问题解决方法,可缩短打开时间)
其余问题,例如一上电就打不开相机,需要重新插拔网线、USB线,就是其他问题,需要具体问题,具体分析
15、MV_E_NETER 0x80000206 网络相关错误
解析:-2147483130/0x80000206
此类报错非常常见,主要分以下集中
相机掉线,能够在日志中发现大量的206报错,此时需要去区分掉线原因,结合相机上电时间、心跳时间、相机权限,日志等信息,综合判断
网线异常,导致相机掉线,也需要具体问题分析
16、MV_E_IP_CONFLICT 0x80000221 设备IP冲突
解析:-2147483103/0x80000221,常见于IP设置时,当前ip已经被其他设备使用,需要更换ip重新设置
17、MV_E_USB_READ 0x80000300 读USB出错
解析:-2147482880/0x80000300
USB读取相机信息失败,此类问题较为复制,与USB接口稳定性、线缆长度、电磁环境相关,往往不好分析,可以尝试插拔一下,或者更换USB接口尝试
18、MV_E_USB_WRITE 0x80000301 写USB出错
解析:-2147482879/0x80000301
同0x80000300一样,不好分析,可以尝试插拔一下,或者更换USB接口尝试
19、MV_E_USB_DRIVER 0x80000305 驱动不匹配或者未装驱动
解析: -2147482875/0x80000305
同0x80000300一样,问题复杂,除了更换USB接口外,还可以尝试更换sdk版本
另外一种场景,比较好解决的是,卸载第三方的usb驱动,比如说halcon驱动
20、错误号64:
NET_DVR_LOADPLAYERSDKFAILED 64 载入当前目录下 Player Sdk 出错
分析:该问题为解决错误107时间引出,问题应该在文件放置目录不对或者库文件内容有缺失导致;解决方法:与错误107相同,将其库文件放置到指定目录;必要时:检查调用Play的文件中是否引入头文件,可引入头文件如“PlayM4.h”或“plaympeg4.h”尝试解决。
开发调试建议
1、使用MVS工具测试
海康官方MVS工具可创建虚拟相机
用于验证SDK基本功能是否正常
2、日志分级
_cancheService.UpdateLogging(new Logging
{
Content = #34;操作信息",
Level = LogLevel.Info, // 或Error/Warn
StartTime = DateTime.UtcNow
});
3、性能监控
监控帧率( nFrameRate
参数)
检查数据包大小( GevSCPSPacketSize
)
总结
海康工业相机C#开发的核心流程包括:
1、环境准备:SDK安装与依赖配置
2、相机枚举与初始化: MV_CC_EnumDevices_NET
与 MV_CC_CreateDevice_NET
3、参数设置:曝光时间、增益、ROI等
4、触发模式配置:软触发/硬触发选择
5、图像采集与回调: MV_CC_StartGrabbing_NET
与回调处理
6、资源释放: MV_CC_DestroyDevice_NET
通过本文的代码示例与问题解决方案,大家可以:
作者:WantRemake