一、简介
1、说明一下
最近,我在开发一个玻璃幕墙检测的项目,这个项目需要使用到海康的相机系统。业务是这样的,相机按着指定的坐标,扫描玻璃幕墙的每块玻璃,通过算法查看是否有损坏的,如果有就发出报警信息,告诉客户。这个项目是有一个同事写好的,我后来重构了一下,但是运行起来,运行若干次,就退悄无声息的退出软件,什么也不提示。通过这个现象,我知道肯定是和硬件交互的时候出了问题,而且抛出任何异常。海康的日志文件也没有显示是什么有价值的东西。
但是,通过努力的查找,调试,排除,终于找到了问题的关键,我们有四个相机,就有四个回调函数,用于处理图像,但是每个相机注册了一个自己的回调,应该是四个相机,设置四个回调,但是回调函数的实例是一个,否则就会出现程序毫无征兆的崩溃。
2、开发平台
开发工具:Visual Studio2022
开发语言:C#
开发平台:Winform 7.0
海康类库:MvCamCtrl.NET
二、详细步骤
这个问题搞了我两天才搞定,但是搞定了,心里舒服了。今天就把思路写下来,自己可以查找,也可以帮助大家。
知道问题的关键点了,解决也就方便了。这也叫难着不会,会的不难。
1、一定要把 MyCamera.cbOutputExdelegate 声明为类的成员。
private MyCamera.cbOutputExdelegate _outputImageDelegate;
1 #region 私有实例字段
2
3 private MyCamera[]? _myCameras;//相机实例的数组。
4 private MyCamera.MV_CC_DEVICE_INFO_LIST _deviceInformationList;//相机信息的列表
5
7 //图片文件的存储路径:根目录/当前扫描时间(作为目录)/相机编号
8 private string? _saveImageBaseDirectory; //图像文件存储的根路径路径。
9 private string? _saveImageOnceTimeDirectory; //单次扫描图像文件的存储路径,目录结构:根目录+当前扫描时间
10 private string[]? _saveImageForCameraDirectory;//最终存储图片文件的路径,目录结构:根目录+当前扫描时间+相机序列号(有多少台相机,就有多少个目录)
11 private IntPtr[]? _imageDisplayHandles;//针对每台相机图像进行显示处理,应为有多台,所以是数据类型是数组。
14 private MyCamera.cbOutputExdelegate _outputImageDelegate;
17 #endregion
2、一定要在构造函数里初始化,当然,如果你可以保证一个实例,就可以放在其他地方,我是为了方便,没有过多的设计。
_outputImageDelegate = new MyCamera.cbOutputExdelegate(SaveImageCallBack);
1 ///
这是附送的方法,异常处理。
1 #region 异常处理
2
3 ///
辅助方法。
1 ///
3、实例化相机,并初始化回调函数。
1 MyCamera.MV_CC_DEVICE_INFO[] _deviceInfoArray = new MyCamera.MV_CC_DEVICE_INFO[localDeviceCount];
2 object? localDeviceInfo = null;
3 MyCamera.MV_CC_DEVICE_INFO device;
4
5 for (int i = 0; i < localDeviceCount; ++i)
6 {
7 if (_deviceInformationList.pDeviceInfo != null && _deviceInformationList.pDeviceInfo.Length > 0)
8 {
9 localDeviceInfo = Marshal.PtrToStructure(_deviceInformationList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
10 if (localDeviceInfo != null)
11 {
12 //获取选择的设备信息
13 device = (MyCamera.MV_CC_DEVICE_INFO)localDeviceInfo;
14
15 //打开设备
16 if (cameras[i] == null)
17 {
18 cameras[i] = new MyCamera();
19 }
20
21 stateCode = cameras[i].MV_CC_CreateDevice_NET(ref device);
22 if (MyCamera.MV_OK != stateCode)
23 {
24 return;
25 }
26
27 stateCode = cameras[i].MV_CC_OpenDevice_NET();
28 if (MyCamera.MV_OK != stateCode)
29 {
30 return;
31 }
32 else
33 {
34 _deviceInfoArray[i] = device;
35 // 探测网络最佳包大小(只对GigE相机有效),我们是USB相机
36 if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
37 {
38 int nPacketSize = cameras[i].MV_CC_GetOptimalPacketSize_NET();
39 if (nPacketSize > 0)
40 {
41 stateCode = cameras[i].MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
42 if (stateCode != MyCamera.MV_OK)
43 {
44 ShowPromptMessage("Warning: Set Packet Size failed {0:x8}", stateCode);
45 }
46 }
47 else
48 {
49 ShowPromptMessage("Warning: Get Packet Size failed {0:x8}", stateCode);
50 }
51 }
52
53 //1、开启设置触发模式
54 SetCameraTriggerMode(cameras[i]);
55 //2、设置具体的触发模式为软触发
56 SetCameraTriggerSource(cameras[i]);
57 cameras[i].MV_CC_RegisterImageCallBackEx_NET(_outputImageDelegate, i);
58 }
59 }
60 }
61 }
4、回调方法的实现。
回调的方法可以根据自己的需求编写,这是我的需求,我的具体编写方法,不能照抄。
1 ///
**三、总结
** 我已经实验过单相机回调没问题了,所以多相机就直接复制了多个回调,因此相机回调还没传到外面的实例,就已经崩了,肯定就是封装的问题。看了海康的多相机demo,相机有4个实例,回调函数只有一个实例,4个相机注册了四次回调,但都是同一个回调实例。这就是我发生错误的根本原因。
好了,问题解决了,又学了点技术,继续努力,苍天不负努力的人。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章