CameraClass.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. using CCDCount.DLL.AlarmTools;
  2. using CCDCount.MODEL.CameraClass;
  3. using CCDCount.MODEL.ConfigModel;
  4. using LogClass;
  5. using MvCameraControl;
  6. using System;
  7. using System.Collections.Concurrent;
  8. using System.Collections.Generic;
  9. using System.Diagnostics;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Runtime.InteropServices;
  13. using System.Threading;
  14. namespace CCDCount.DLL
  15. {
  16. public class CameraClass
  17. {
  18. #region 常量
  19. readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
  20. | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice
  21. | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;
  22. #endregion
  23. #region 变量
  24. private List<IDeviceInfo> CamList; // 相机列表
  25. private IDevice device = null; // 相机实例
  26. private long lastframeNum = -1;
  27. public int CamereNo { get { return _cameraNo; } }
  28. private int _cameraNo = -1;
  29. /// <summary>
  30. /// 设备事件委托
  31. /// </summary>
  32. public event EventHandler<FrameGrabbedEventArgs> FrameGrabbedEvent;
  33. #endregion
  34. #region 公共方法
  35. /// <summary>
  36. /// 获取相机列表
  37. /// </summary>
  38. /// <param name="CamList"></param>
  39. /// <returns></returns>
  40. public void GetCameraList(out List<CameraInfoClass> CameraInfoList)
  41. {
  42. CamList = new List<IDeviceInfo>();
  43. CameraInfoList = new List<CameraInfoClass>();
  44. int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out CamList);
  45. if (nRet != MvError.MV_OK)
  46. {
  47. return;
  48. }
  49. else
  50. {
  51. //输出相机名称及SN码以方便选择设备
  52. foreach (var item in CamList)
  53. {
  54. CameraInfoList.Add(new CameraInfoClass
  55. {
  56. //DeviceName = item.UserDefinedName == "" ? item.ModelName : item.UserDefinedName,
  57. DeviceName = item.ModelName,
  58. DeviceSN = item.SerialNumber,
  59. });
  60. }
  61. }
  62. return;
  63. }
  64. /// <summary>
  65. /// 更新相机列表
  66. /// </summary>
  67. public void UpdateCameraList()
  68. {
  69. CamList = new List<IDeviceInfo>();
  70. int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out CamList);
  71. if (nRet != MvError.MV_OK)
  72. {
  73. Console.WriteLine("相机列表更新失败");
  74. return;
  75. }
  76. }
  77. /// <summary>
  78. /// 加载指定相机
  79. /// </summary>
  80. /// <param name="DeviceSN"></param>
  81. public bool LoadCamereDevice(CameraConfig DeviceConfig)
  82. {
  83. bool Blresult = false;
  84. if (device != null && device.IsConnected)
  85. {
  86. device.Close();
  87. device.Dispose();
  88. }
  89. UpdateCameraList();
  90. List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == DeviceConfig.CameraSNNum).ToList();
  91. if(deviceInfos.Count == 0) return Blresult;
  92. IDeviceInfo deviceInfo = deviceInfos.First();
  93. try
  94. {
  95. // 打开设备
  96. device = DeviceFactory.CreateDevice(deviceInfo);
  97. }
  98. catch (Exception ex)
  99. {
  100. //FaultLog.RecordErrorMessage("Create Device fail!" + DeviceConfig.CameraSNNum + ":" + ex.Message);
  101. SystemAlarm.AlarmAlert(AlarmMessageList.相机实例创建失败,
  102. "Create Device fail!" + DeviceConfig.CameraSNNum + ":" + ex.Message,
  103. "相机实例创建失败" + DeviceConfig.CameraSNNum + ":" + ex.Message,
  104. "DLL:CameraClass-LoadCamereDevice");
  105. return Blresult;
  106. }
  107. SystemAlarm.AlarmCancel(AlarmMessageList.相机实例创建失败);
  108. int result = device.Open();
  109. if (result != MvError.MV_OK)
  110. {
  111. //FaultLog.RecordErrorMessage("Open Device fail!" + DeviceConfig.CameraSNNum + ":" + result);
  112. SystemAlarm.AlarmAlert(AlarmMessageList.开启相机失败,
  113. "Open Device fail!" + DeviceConfig.CameraSNNum + ":" + result,
  114. "开启相机失败" + DeviceConfig.CameraSNNum + ":" + result,
  115. "DLL:CameraClass-LoadCamereDevice");
  116. return Blresult;
  117. }
  118. SystemAlarm.AlarmCancel(AlarmMessageList.开启相机失败);
  119. // 判断是否为gige设备
  120. if (device is IGigEDevice)
  121. {
  122. // 转换为gigE设备
  123. IGigEDevice gigEDevice = device as IGigEDevice;
  124. // 探测网络最佳包大小(只对GigE相机有效)
  125. result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
  126. if (result != MvError.MV_OK)
  127. {
  128. //Log("Warning: Get Packet Size failed!", result);
  129. }
  130. else
  131. {
  132. result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
  133. if (result != MvError.MV_OK)
  134. {
  135. //Log("Warning: Set Packet Size failed!", result);
  136. }
  137. }
  138. }
  139. //判断是否从配置文件读取的参数,是则设置参数,否则加载相机默认参数
  140. if(DeviceConfig.IsLoadCanfig)
  141. {
  142. //设置从配置文件读取的参数
  143. device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
  144. _cameraNo = DeviceConfig.CamerNo;
  145. if (DeviceConfig.CameraName != deviceModelName.CurValue)
  146. device.Parameters.SetStringValue("DeviceUserID", DeviceConfig.CameraName);
  147. device.Parameters.SetFloatValue("ExposureTime", DeviceConfig.ExposureTimeValue);
  148. device.Parameters.SetIntValue("AcquisitionLineRate", DeviceConfig.AcquistionLineRateValue);
  149. device.Parameters.GetIntValue("Height", out IIntValue height);
  150. device.Parameters.SetIntValue("Height", height.Min);
  151. device.Parameters.SetIntValue("OffsetX", DeviceConfig.OffsetX);
  152. device.Parameters.SetIntValue("Width", DeviceConfig.Width);
  153. }
  154. // 设置采集连续模式
  155. device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
  156. device.Parameters.SetEnumValueByString("TriggerMode", "Off");
  157. Blresult = true;
  158. return Blresult;
  159. }
  160. /// <summary>
  161. /// 重新加载指定相机
  162. /// </summary>
  163. /// <param name="CameraSN"></param>
  164. /// <returns></returns>
  165. public bool ReLoadCameraDevice(string CameraSN)
  166. {
  167. bool Blresult = false;
  168. if(device!=null && device.IsConnected)
  169. {
  170. device.Close();
  171. device.Dispose();
  172. }
  173. UpdateCameraList();
  174. List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == CameraSN).ToList();
  175. if (deviceInfos.Count == 0) return Blresult;
  176. IDeviceInfo deviceInfo = deviceInfos.First();
  177. try
  178. {
  179. // 打开设备
  180. device = DeviceFactory.CreateDevice(deviceInfo);
  181. Blresult = true;
  182. }
  183. catch (Exception ex)
  184. {
  185. //FaultLog.RecordErrorMessage("Create Device fail!" + CameraSN + ":" + ex.Message);
  186. SystemAlarm.AlarmAlert(AlarmMessageList.相机实例创建失败,
  187. "Create Device fail!" + CameraSN + ":" + ex.Message,
  188. "相机实例创建失败" + CameraSN + ":" + ex.Message,
  189. "DLL:CameraClass-LoadCamereDevice");
  190. return Blresult;
  191. }
  192. SystemAlarm.AlarmCancel(AlarmMessageList.相机实例创建失败);
  193. int result = device.Open();
  194. if (result != MvError.MV_OK)
  195. {
  196. Blresult = false;
  197. //FaultLog.RecordErrorMessage("Open Device fail!" + CameraSN + ":" + result);
  198. SystemAlarm.AlarmAlert(AlarmMessageList.开启相机失败,
  199. "Open Device fail!" + CameraSN + ":" + result,
  200. "相机实例创建失败" + CameraSN + ":" + result,
  201. "DLL:CameraClass-LoadCamereDevice");
  202. return Blresult;
  203. }
  204. SystemAlarm.AlarmCancel(AlarmMessageList.开启相机失败);
  205. // 判断是否为gige设备
  206. if (device is IGigEDevice)
  207. {
  208. // 转换为gigE设备
  209. IGigEDevice gigEDevice = device as IGigEDevice;
  210. // 探测网络最佳包大小(只对GigE相机有效)
  211. result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
  212. if (result != MvError.MV_OK)
  213. {
  214. //Log("Warning: Get Packet Size failed!", result);
  215. }
  216. else
  217. {
  218. result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
  219. if (result != MvError.MV_OK)
  220. {
  221. //Log("Warning: Set Packet Size failed!", result);
  222. }
  223. }
  224. }
  225. return Blresult;
  226. }
  227. /// <summary>
  228. /// 重新加载相机参数
  229. /// </summary>
  230. /// <param name="RecameraConfig"></param>
  231. /// <returns></returns>
  232. public bool ReLoadCameraConfig(CameraConfig RecameraConfig)
  233. {
  234. bool Blresult = false;
  235. if (device != null && device.IsConnected)
  236. {
  237. //设置从配置文件读取的参数
  238. device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
  239. _cameraNo = RecameraConfig.CamerNo;
  240. if (RecameraConfig.CameraName != deviceModelName.CurValue)
  241. device.Parameters.SetStringValue("DeviceUserID", RecameraConfig.CameraName);
  242. device.Parameters.SetFloatValue("ExposureTime", RecameraConfig.ExposureTimeValue);
  243. device.Parameters.SetIntValue("AcquisitionLineRate", RecameraConfig.AcquistionLineRateValue);
  244. device.Parameters.GetIntValue("Height", out IIntValue height);
  245. device.Parameters.SetIntValue("Height", height.Min);
  246. device.Parameters.SetIntValue("OffsetX", RecameraConfig.OffsetX);
  247. device.Parameters.SetIntValue("Width", RecameraConfig.Width);
  248. // 设置采集连续模式
  249. device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
  250. device.Parameters.SetEnumValueByString("TriggerMode", "Off");
  251. Blresult = true;
  252. }
  253. return Blresult;
  254. }
  255. /// <summary>
  256. /// 开启相机采集
  257. /// </summary>
  258. public bool StartCamera()
  259. {
  260. return StartReceiveFuntion2();
  261. }
  262. /// <summary>
  263. /// 关闭相机采集
  264. /// </summary>
  265. public void StopCamera()
  266. {
  267. StopReceiveFuntion2();
  268. //StopEventGetImage();
  269. }
  270. /// <summary>
  271. /// 释放相机资源
  272. /// </summary>
  273. public void DisPoseCamera()
  274. {
  275. if (device != null)
  276. {
  277. int result = device.StreamGrabber.StopGrabbing();
  278. device.Close();
  279. device.Dispose();
  280. if (result != MvError.MV_OK)
  281. {
  282. LOG.log(("Stop Grabbing Fail!", result));
  283. }
  284. }
  285. }
  286. public DateTime FromUnixTimestamp(long timestamp, bool isMilliseconds = false)
  287. {
  288. try
  289. {
  290. // 如果未指定单位,尝试自动检测
  291. if (!isMilliseconds)
  292. {
  293. // 如果时间戳看起来像毫秒级(13位数字)
  294. if (timestamp.ToString().Length > 10)
  295. {
  296. isMilliseconds = true;
  297. }
  298. }
  299. if (isMilliseconds)
  300. {
  301. // 验证毫秒级时间戳范围
  302. const long minMilliTimestamp = -62135596800000; // 0001-01-01 00:00:00 UTC
  303. const long maxMilliTimestamp = 253402300799999; // 9999-12-31 23:59:59 UTC
  304. if (timestamp < minMilliTimestamp || timestamp > maxMilliTimestamp)
  305. {
  306. throw new ArgumentOutOfRangeException(nameof(timestamp),
  307. "毫秒级时间戳超出有效范围");
  308. }
  309. DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(timestamp);
  310. return TimeZoneInfo.ConvertTimeFromUtc(origin, TimeZoneInfo.Local);
  311. }
  312. else
  313. {
  314. // 验证秒级时间戳范围
  315. const long minTimestamp = -62135596800;
  316. const long maxTimestamp = 253402300799;
  317. if (timestamp < minTimestamp || timestamp > maxTimestamp)
  318. {
  319. throw new ArgumentOutOfRangeException(nameof(timestamp),
  320. "秒级时间戳超出有效范围");
  321. }
  322. DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp);
  323. return TimeZoneInfo.ConvertTimeFromUtc(origin, TimeZoneInfo.Local);
  324. }
  325. }
  326. catch (ArgumentOutOfRangeException)
  327. {
  328. throw;
  329. }
  330. catch (Exception ex)
  331. {
  332. throw new ArgumentException($"无法转换时间戳 {timestamp}: {ex.Message}", ex);
  333. }
  334. }
  335. /// <summary>
  336. /// 获取一次图片
  337. /// </summary>
  338. /// <param name="IFrameData"></param>
  339. /// <returns></returns>
  340. public bool GetOnceImage(out IFrameOut IFrameData)
  341. {
  342. bool result = false;
  343. int BRet = device.StreamGrabber.GetImageBuffer(100, out IFrameData);
  344. if (BRet == 0 &&
  345. IFrameData != null) result = true;
  346. else return result;
  347. var QutuYanshiTime = (DateTime.Now - FromUnixTimestamp((long)IFrameData.HostTimeStamp)).TotalMilliseconds;
  348. if (QutuYanshiTime > 20)
  349. {
  350. Console.WriteLine($"GetOnceImage-识别延时超过了20ms,耗时{QutuYanshiTime}");
  351. }
  352. if (lastframeNum == -1)
  353. {
  354. lastframeNum = IFrameData.FrameNum;
  355. }
  356. else if (lastframeNum == IFrameData.FrameNum - 1)
  357. {
  358. lastframeNum = IFrameData.FrameNum;
  359. }
  360. else
  361. {
  362. //丢帧记录
  363. LOG.log(string.Format("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
  364. IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum, lastframeNum), 6);
  365. Console.WriteLine("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
  366. IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum, lastframeNum);
  367. lastframeNum = IFrameData.FrameNum;
  368. }
  369. return result;
  370. }
  371. /// <summary>
  372. /// 获取相机图像尺寸信息
  373. /// </summary>
  374. /// <returns></returns>
  375. public CameraImageSizeClass GetCamereImageSize()
  376. {
  377. CameraImageSizeClass cameraImageSize =new CameraImageSizeClass();
  378. if(device != null)
  379. {
  380. device.Parameters.GetIntValue("Width", out IIntValue PixWidth);
  381. device.Parameters.GetIntValue("Height", out IIntValue PixHeight);
  382. cameraImageSize.Height = (int)PixHeight.CurValue;
  383. cameraImageSize.Width = (int)PixWidth.CurValue;
  384. }
  385. return cameraImageSize;
  386. }
  387. /// <summary>
  388. /// 获取当前相机的参数生成Config信息
  389. /// </summary>
  390. /// <returns></returns>
  391. public CameraConfig GetConfigValue()
  392. {
  393. CameraConfig result;
  394. device.Parameters.GetFloatValue("ExposureTime", out IFloatValue exposureTime);
  395. device.Parameters.GetIntValue("AcquisitionLineRate", out IIntValue acquisitionLineRate);
  396. device.Parameters.GetIntValue("OffsetX", out IIntValue offsetX);
  397. device.Parameters.GetIntValue("Width", out IIntValue pixWidth);
  398. device.Parameters.GetIntValue("Height", out IIntValue pixHeight);
  399. device.Parameters.GetStringValue("DeviceUserID", out IStringValue deviceUserID);
  400. device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
  401. device.Parameters.GetStringValue("DeviceSerialNumber", out IStringValue deviceSerialNumber);
  402. result = new CameraConfig()
  403. {
  404. CameraSNNum = deviceSerialNumber.CurValue,
  405. ExposureTimeValue = exposureTime.CurValue,
  406. AcquistionLineRateValue = (int)acquisitionLineRate.CurValue,
  407. Width = (int)pixWidth.CurValue,
  408. Height = (int)pixHeight.CurValue,
  409. OffsetX = (int)offsetX.CurValue,
  410. CameraName = deviceUserID.CurValue,
  411. DeviceName = deviceModelName.CurValue,
  412. CamerNo = _cameraNo
  413. };
  414. return result;
  415. }
  416. /// <summary>
  417. /// 保存参数
  418. /// </summary>
  419. public void SaveConfig()
  420. {
  421. CameraConfig camerasConfig = null;
  422. if (!Directory.Exists(".\\Config\\")) Directory.CreateDirectory(".\\Config\\");
  423. XmlStorage.SerializeToXml(camerasConfig, ".\\Config\\CameraConfig.xml");
  424. }
  425. public bool IsLoadCamera()
  426. {
  427. return device != null;
  428. }
  429. public bool IsConnectCamera()
  430. {
  431. if (device == null) return false;
  432. else
  433. {
  434. return device.IsConnected;
  435. }
  436. }
  437. #endregion
  438. #region 私有方法
  439. /// <summary>
  440. /// 开启采集
  441. /// </summary>
  442. private bool StartReceiveFuntion()
  443. {
  444. bool result = false;
  445. try
  446. {
  447. if(device == null) return result;
  448. device.StreamGrabber.SetImageNodeNum(30);
  449. device.StreamGrabber.StartGrabbing();
  450. result = true;
  451. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集开始失败);
  452. }
  453. catch (Exception ex)
  454. {
  455. //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
  456. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集开始失败,
  457. "Start thread failed!, " + ex.Message,
  458. "相机采集开始失败, " + ex.Message,
  459. "DLL:CamerClass-StartReceiveFuntion");
  460. throw;
  461. }
  462. return result;
  463. }
  464. /// <summary>
  465. /// 关闭采集
  466. /// </summary>
  467. private void StopReceiveFuntion()
  468. {
  469. try
  470. {
  471. if (device == null) return;
  472. int ret = device.StreamGrabber.StopGrabbing();
  473. if (ret != MvError.MV_OK)
  474. {
  475. //FaultLog.RecordErrorMessage($"Stop grabbing failed:{ret:x8}");
  476. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  477. $"Stop grabbing failed:{ret:x8}",
  478. $"相机采集停止失败:{ret:x8}",
  479. "DLL:CamerClass-StopReceiveFuntion");
  480. return;
  481. }
  482. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集停止失败);
  483. }
  484. catch (Exception ex)
  485. {
  486. //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
  487. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  488. "Stop thread failed!, " + ex.Message,
  489. "相机采集停止失败, " + ex.Message,
  490. "DLL:CamerClass-StopReceiveFuntion");
  491. throw;
  492. }
  493. }
  494. /// <summary>
  495. /// 开启采集-回调
  496. /// </summary>
  497. private bool StartReceiveFuntion2()
  498. {
  499. bool result = false;
  500. try
  501. {
  502. if (device == null) return result;
  503. device.StreamGrabber.SetImageNodeNum(30);
  504. device.StreamGrabber.FrameGrabedEvent += FrameGrabbedEventHandler;
  505. device.StreamGrabber.StartGrabbing();
  506. result = true;
  507. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集开始失败);
  508. }
  509. catch (Exception ex)
  510. {
  511. //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
  512. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集开始失败,
  513. "Start thread failed!, " + ex.Message,
  514. "相机采集开始失败, " + ex.Message,
  515. "DLL:CamerClass-StartReceiveFuntion");
  516. throw;
  517. }
  518. return result;
  519. }
  520. /// <summary>
  521. /// 关闭采集-回调
  522. /// </summary>
  523. private void StopReceiveFuntion2()
  524. {
  525. try
  526. {
  527. if (device == null) return;
  528. int ret = device.StreamGrabber.StopGrabbing();
  529. device.StreamGrabber.FrameGrabedEvent -= FrameGrabbedEventHandler;
  530. if (ret != MvError.MV_OK)
  531. {
  532. //FaultLog.RecordErrorMessage($"Stop grabbing failed:{ret:x8}");
  533. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  534. $"Stop grabbing failed:{ret:x8}",
  535. $"相机采集停止失败:{ret:x8}",
  536. "DLL:CamerClass-StopReceiveFuntion");
  537. return;
  538. }
  539. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集停止失败);
  540. }
  541. catch (Exception ex)
  542. {
  543. //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
  544. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  545. "Stop thread failed!, " + ex.Message,
  546. "相机采集停止失败, " + ex.Message,
  547. "DLL:CamerClass-StopReceiveFuntion");
  548. throw;
  549. }
  550. }
  551. /// <summary>
  552. /// 图像抓取事件处理方法
  553. /// </summary>
  554. private void FrameGrabbedEventHandler(object sender, FrameGrabbedEventArgs frameData)
  555. {
  556. // 触发外部注册的事件
  557. FrameGrabbedEvent?.Invoke(this, frameData);
  558. }
  559. #endregion
  560. }
  561. }