CameraClass.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  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.SetIntValue("Height", DeviceConfig.Height);
  150. device.Parameters.SetIntValue("OffsetX", DeviceConfig.OffsetX);
  151. device.Parameters.SetIntValue("Width", DeviceConfig.Width);
  152. }
  153. // 设置采集连续模式
  154. device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
  155. device.Parameters.SetEnumValueByString("TriggerMode", "Off");
  156. Blresult = true;
  157. return Blresult;
  158. }
  159. /// <summary>
  160. /// 重新加载指定相机
  161. /// </summary>
  162. /// <param name="CameraSN"></param>
  163. /// <returns></returns>
  164. public bool ReLoadCameraDevice(string CameraSN)
  165. {
  166. bool Blresult = false;
  167. if(device!=null && device.IsConnected)
  168. {
  169. device.Close();
  170. device.Dispose();
  171. }
  172. UpdateCameraList();
  173. List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == CameraSN).ToList();
  174. if (deviceInfos.Count == 0) return Blresult;
  175. IDeviceInfo deviceInfo = deviceInfos.First();
  176. try
  177. {
  178. // 打开设备
  179. device = DeviceFactory.CreateDevice(deviceInfo);
  180. Blresult = true;
  181. }
  182. catch (Exception ex)
  183. {
  184. //FaultLog.RecordErrorMessage("Create Device fail!" + CameraSN + ":" + ex.Message);
  185. SystemAlarm.AlarmAlert(AlarmMessageList.相机实例创建失败,
  186. "Create Device fail!" + CameraSN + ":" + ex.Message,
  187. "相机实例创建失败" + CameraSN + ":" + ex.Message,
  188. "DLL:CameraClass-LoadCamereDevice");
  189. return Blresult;
  190. }
  191. SystemAlarm.AlarmCancel(AlarmMessageList.相机实例创建失败);
  192. int result = device.Open();
  193. if (result != MvError.MV_OK)
  194. {
  195. Blresult = false;
  196. //FaultLog.RecordErrorMessage("Open Device fail!" + CameraSN + ":" + result);
  197. SystemAlarm.AlarmAlert(AlarmMessageList.开启相机失败,
  198. "Open Device fail!" + CameraSN + ":" + result,
  199. "相机实例创建失败" + CameraSN + ":" + result,
  200. "DLL:CameraClass-LoadCamereDevice");
  201. return Blresult;
  202. }
  203. SystemAlarm.AlarmCancel(AlarmMessageList.开启相机失败);
  204. // 判断是否为gige设备
  205. if (device is IGigEDevice)
  206. {
  207. // 转换为gigE设备
  208. IGigEDevice gigEDevice = device as IGigEDevice;
  209. // 探测网络最佳包大小(只对GigE相机有效)
  210. result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
  211. if (result != MvError.MV_OK)
  212. {
  213. //Log("Warning: Get Packet Size failed!", result);
  214. }
  215. else
  216. {
  217. result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
  218. if (result != MvError.MV_OK)
  219. {
  220. //Log("Warning: Set Packet Size failed!", result);
  221. }
  222. }
  223. }
  224. return Blresult;
  225. }
  226. /// <summary>
  227. /// 重新加载相机参数
  228. /// </summary>
  229. /// <param name="RecameraConfig"></param>
  230. /// <returns></returns>
  231. public bool ReLoadCameraConfig(CameraConfig RecameraConfig)
  232. {
  233. bool Blresult = false;
  234. if (device != null && device.IsConnected)
  235. {
  236. //设置从配置文件读取的参数
  237. device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
  238. _cameraNo = RecameraConfig.CamerNo;
  239. if (RecameraConfig.CameraName != deviceModelName.CurValue)
  240. device.Parameters.SetStringValue("DeviceUserID", RecameraConfig.CameraName);
  241. device.Parameters.SetFloatValue("ExposureTime", RecameraConfig.ExposureTimeValue);
  242. device.Parameters.SetIntValue("AcquisitionLineRate", RecameraConfig.AcquistionLineRateValue);
  243. device.Parameters.SetIntValue("Height", RecameraConfig.Height);
  244. device.Parameters.SetIntValue("OffsetX", RecameraConfig.OffsetX);
  245. device.Parameters.SetIntValue("Width", RecameraConfig.Width);
  246. // 设置采集连续模式
  247. device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
  248. device.Parameters.SetEnumValueByString("TriggerMode", "Off");
  249. Blresult = true;
  250. }
  251. return Blresult;
  252. }
  253. /// <summary>
  254. /// 开启相机采集
  255. /// </summary>
  256. public bool StartCamera()
  257. {
  258. return StartReceiveFuntion2();
  259. }
  260. /// <summary>
  261. /// 关闭相机采集
  262. /// </summary>
  263. public void StopCamera()
  264. {
  265. StopReceiveFuntion2();
  266. //StopEventGetImage();
  267. }
  268. /// <summary>
  269. /// 释放相机资源
  270. /// </summary>
  271. public void DisPoseCamera()
  272. {
  273. if (device != null)
  274. {
  275. int result = device.StreamGrabber.StopGrabbing();
  276. device.Close();
  277. device.Dispose();
  278. if (result != MvError.MV_OK)
  279. {
  280. LOG.log(("Stop Grabbing Fail!", result));
  281. }
  282. }
  283. }
  284. public DateTime FromUnixTimestamp(long timestamp, bool isMilliseconds = false)
  285. {
  286. try
  287. {
  288. // 如果未指定单位,尝试自动检测
  289. if (!isMilliseconds)
  290. {
  291. // 如果时间戳看起来像毫秒级(13位数字)
  292. if (timestamp.ToString().Length > 10)
  293. {
  294. isMilliseconds = true;
  295. }
  296. }
  297. if (isMilliseconds)
  298. {
  299. // 验证毫秒级时间戳范围
  300. const long minMilliTimestamp = -62135596800000; // 0001-01-01 00:00:00 UTC
  301. const long maxMilliTimestamp = 253402300799999; // 9999-12-31 23:59:59 UTC
  302. if (timestamp < minMilliTimestamp || timestamp > maxMilliTimestamp)
  303. {
  304. throw new ArgumentOutOfRangeException(nameof(timestamp),
  305. "毫秒级时间戳超出有效范围");
  306. }
  307. DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(timestamp);
  308. return TimeZoneInfo.ConvertTimeFromUtc(origin, TimeZoneInfo.Local);
  309. }
  310. else
  311. {
  312. // 验证秒级时间戳范围
  313. const long minTimestamp = -62135596800;
  314. const long maxTimestamp = 253402300799;
  315. if (timestamp < minTimestamp || timestamp > maxTimestamp)
  316. {
  317. throw new ArgumentOutOfRangeException(nameof(timestamp),
  318. "秒级时间戳超出有效范围");
  319. }
  320. DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp);
  321. return TimeZoneInfo.ConvertTimeFromUtc(origin, TimeZoneInfo.Local);
  322. }
  323. }
  324. catch (ArgumentOutOfRangeException)
  325. {
  326. throw;
  327. }
  328. catch (Exception ex)
  329. {
  330. throw new ArgumentException($"无法转换时间戳 {timestamp}: {ex.Message}", ex);
  331. }
  332. }
  333. /// <summary>
  334. /// 获取一次图片
  335. /// </summary>
  336. /// <param name="IFrameData"></param>
  337. /// <returns></returns>
  338. public bool GetOnceImage(out IFrameOut IFrameData)
  339. {
  340. bool result = false;
  341. int BRet = device.StreamGrabber.GetImageBuffer(100, out IFrameData);
  342. if (BRet == 0 &&
  343. IFrameData != null) result = true;
  344. else return result;
  345. var QutuYanshiTime = (DateTime.Now - FromUnixTimestamp((long)IFrameData.HostTimeStamp)).TotalMilliseconds;
  346. if (QutuYanshiTime > 20)
  347. {
  348. Console.WriteLine($"GetOnceImage-识别延时超过了20ms,耗时{QutuYanshiTime}");
  349. }
  350. if (lastframeNum == -1)
  351. {
  352. lastframeNum = IFrameData.FrameNum;
  353. }
  354. else if (lastframeNum == IFrameData.FrameNum - 1)
  355. {
  356. lastframeNum = IFrameData.FrameNum;
  357. }
  358. else
  359. {
  360. //丢帧记录
  361. LOG.log(string.Format("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
  362. IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum, lastframeNum), 6);
  363. Console.WriteLine("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
  364. IFrameData.Image.Width, IFrameData.Image.Height, IFrameData.FrameNum, lastframeNum);
  365. lastframeNum = IFrameData.FrameNum;
  366. }
  367. return result;
  368. }
  369. /// <summary>
  370. /// 获取相机图像尺寸信息
  371. /// </summary>
  372. /// <returns></returns>
  373. public CameraImageSizeClass GetCamereImageSize()
  374. {
  375. CameraImageSizeClass cameraImageSize =new CameraImageSizeClass();
  376. if(device != null)
  377. {
  378. device.Parameters.GetIntValue("Width", out IIntValue PixWidth);
  379. device.Parameters.GetIntValue("Height", out IIntValue PixHeight);
  380. cameraImageSize.Height = (int)PixHeight.CurValue;
  381. cameraImageSize.Width = (int)PixWidth.CurValue;
  382. }
  383. return cameraImageSize;
  384. }
  385. /// <summary>
  386. /// 获取当前相机的参数生成Config信息
  387. /// </summary>
  388. /// <returns></returns>
  389. public CameraConfig GetConfigValue()
  390. {
  391. CameraConfig result;
  392. device.Parameters.GetFloatValue("ExposureTime", out IFloatValue exposureTime);
  393. device.Parameters.GetIntValue("AcquisitionLineRate", out IIntValue acquisitionLineRate);
  394. device.Parameters.GetIntValue("OffsetX", out IIntValue offsetX);
  395. device.Parameters.GetIntValue("Width", out IIntValue pixWidth);
  396. device.Parameters.GetIntValue("Height", out IIntValue pixHeight);
  397. device.Parameters.GetStringValue("DeviceUserID", out IStringValue deviceUserID);
  398. device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
  399. device.Parameters.GetStringValue("DeviceSerialNumber", out IStringValue deviceSerialNumber);
  400. result = new CameraConfig()
  401. {
  402. CameraSNNum = deviceSerialNumber.CurValue,
  403. ExposureTimeValue = exposureTime.CurValue,
  404. AcquistionLineRateValue = (int)acquisitionLineRate.CurValue,
  405. Width = (int)pixWidth.CurValue,
  406. Height = (int)pixHeight.CurValue,
  407. OffsetX = (int)offsetX.CurValue,
  408. CameraName = deviceUserID.CurValue,
  409. DeviceName = deviceModelName.CurValue,
  410. CamerNo = _cameraNo
  411. };
  412. return result;
  413. }
  414. /// <summary>
  415. /// 保存参数
  416. /// </summary>
  417. public void SaveConfig()
  418. {
  419. CameraConfig camerasConfig = null;
  420. if (!Directory.Exists(".\\Config\\")) Directory.CreateDirectory(".\\Config\\");
  421. XmlStorage.SerializeToXml(camerasConfig, ".\\Config\\CameraConfig.xml");
  422. }
  423. public bool IsLoadCamera()
  424. {
  425. return device != null;
  426. }
  427. public bool IsConnectCamera()
  428. {
  429. if (device == null) return false;
  430. else
  431. {
  432. return device.IsConnected;
  433. }
  434. }
  435. #endregion
  436. #region 私有方法
  437. /// <summary>
  438. /// 开启采集
  439. /// </summary>
  440. private bool StartReceiveFuntion()
  441. {
  442. bool result = false;
  443. try
  444. {
  445. if(device == null) return result;
  446. device.StreamGrabber.SetImageNodeNum(30);
  447. device.StreamGrabber.StartGrabbing();
  448. result = true;
  449. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集开始失败);
  450. }
  451. catch (Exception ex)
  452. {
  453. //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
  454. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集开始失败,
  455. "Start thread failed!, " + ex.Message,
  456. "相机采集开始失败, " + ex.Message,
  457. "DLL:CamerClass-StartReceiveFuntion");
  458. throw;
  459. }
  460. return result;
  461. }
  462. /// <summary>
  463. /// 关闭采集
  464. /// </summary>
  465. private void StopReceiveFuntion()
  466. {
  467. try
  468. {
  469. if (device == null) return;
  470. int ret = device.StreamGrabber.StopGrabbing();
  471. if (ret != MvError.MV_OK)
  472. {
  473. //FaultLog.RecordErrorMessage($"Stop grabbing failed:{ret:x8}");
  474. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  475. $"Stop grabbing failed:{ret:x8}",
  476. $"相机采集停止失败:{ret:x8}",
  477. "DLL:CamerClass-StopReceiveFuntion");
  478. return;
  479. }
  480. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集停止失败);
  481. }
  482. catch (Exception ex)
  483. {
  484. //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
  485. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  486. "Stop thread failed!, " + ex.Message,
  487. "相机采集停止失败, " + ex.Message,
  488. "DLL:CamerClass-StopReceiveFuntion");
  489. throw;
  490. }
  491. }
  492. /// <summary>
  493. /// 开启采集-回调
  494. /// </summary>
  495. private bool StartReceiveFuntion2()
  496. {
  497. bool result = false;
  498. try
  499. {
  500. if (device == null) return result;
  501. device.StreamGrabber.SetImageNodeNum(500);
  502. device.StreamGrabber.FrameGrabedEvent += FrameGrabbedEventHandler;
  503. device.StreamGrabber.StartGrabbing();
  504. result = true;
  505. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集开始失败);
  506. }
  507. catch (Exception ex)
  508. {
  509. //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
  510. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集开始失败,
  511. "Start thread failed!, " + ex.Message,
  512. "相机采集开始失败, " + ex.Message,
  513. "DLL:CamerClass-StartReceiveFuntion");
  514. throw;
  515. }
  516. return result;
  517. }
  518. /// <summary>
  519. /// 关闭采集-回调
  520. /// </summary>
  521. private void StopReceiveFuntion2()
  522. {
  523. try
  524. {
  525. if (device == null) return;
  526. int ret = device.StreamGrabber.StopGrabbing();
  527. device.StreamGrabber.FrameGrabedEvent -= FrameGrabbedEventHandler;
  528. if (ret != MvError.MV_OK)
  529. {
  530. //FaultLog.RecordErrorMessage($"Stop grabbing failed:{ret:x8}");
  531. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  532. $"Stop grabbing failed:{ret:x8}",
  533. $"相机采集停止失败:{ret:x8}",
  534. "DLL:CamerClass-StopReceiveFuntion");
  535. return;
  536. }
  537. SystemAlarm.AlarmCancel(AlarmMessageList.相机采集停止失败);
  538. }
  539. catch (Exception ex)
  540. {
  541. //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
  542. SystemAlarm.AlarmAlert(AlarmMessageList.相机采集停止失败,
  543. "Stop thread failed!, " + ex.Message,
  544. "相机采集停止失败, " + ex.Message,
  545. "DLL:CamerClass-StopReceiveFuntion");
  546. throw;
  547. }
  548. }
  549. /// <summary>
  550. /// 图像抓取事件处理方法
  551. /// </summary>
  552. private void FrameGrabbedEventHandler(object sender, FrameGrabbedEventArgs frameData)
  553. {
  554. // 触发外部注册的事件
  555. FrameGrabbedEvent?.Invoke(this, frameData);
  556. }
  557. #endregion
  558. }
  559. }