CameraClass.cs 22 KB

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