CameraClass.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. using MvCameraControl;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading;
  11. namespace CCDCount.DLL
  12. {
  13. public class CameraClass
  14. {
  15. #region 常量
  16. readonly DeviceTLayerType enumTLayerType = DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvUsbDevice
  17. | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvGenTLCXPDevice
  18. | DeviceTLayerType.MvGenTLCameraLinkDevice | DeviceTLayerType.MvGenTLXoFDevice;
  19. #endregion
  20. #region 变量
  21. private List<IDeviceInfo> CamList; // 相机列表
  22. private IDevice device = null; // 相机实例
  23. private bool isGrabbing = false; // 是否正在取图
  24. private Thread receiveThread = null; // 接收图像线程
  25. private ConcurrentQueue<ImageMessageClass> FrameOuts = new ConcurrentQueue<ImageMessageClass>();
  26. private ConcurrentQueue<byte[]> ImageBytes = new ConcurrentQueue<byte[]>(); //图像接受队列
  27. private int OnImageSelectRows = 2;
  28. private long lastframeNum = -1;
  29. #endregion
  30. #region 公共方法
  31. /// <summary>
  32. /// 获取相机列表
  33. /// </summary>
  34. /// <param name="CamList"></param>
  35. /// <returns></returns>
  36. public void GetCameraList(out List<CameraInfoClass> CameraInfoList)
  37. {
  38. CamList = new List<IDeviceInfo>();
  39. CameraInfoList = new List<CameraInfoClass>();
  40. int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out CamList);
  41. if (nRet != MvError.MV_OK)
  42. {
  43. return;
  44. }
  45. else
  46. {
  47. //输出相机名称及SN码以方便选择设备
  48. foreach (var item in CamList)
  49. {
  50. CameraInfoList.Add(new CameraInfoClass
  51. {
  52. DeviceName = item.UserDefinedName == "" ? item.ModelName : item.UserDefinedName,
  53. DeviceSN = item.SerialNumber,
  54. });
  55. }
  56. }
  57. return;
  58. }
  59. /// <summary>
  60. /// 加载指定相机
  61. /// </summary>
  62. /// <param name="DeviceSN"></param>
  63. public bool LoadCamereDevice(string DeviceSN)
  64. {
  65. bool Blresult = false;
  66. List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == DeviceSN).ToList();
  67. if(deviceInfos.Count == 0) return Blresult;
  68. IDeviceInfo deviceInfo = deviceInfos.First();
  69. try
  70. {
  71. // 打开设备
  72. device = DeviceFactory.CreateDevice(deviceInfo);
  73. }
  74. catch (Exception ex)
  75. {
  76. Console.WriteLine("Create Device fail!" + ex.Message);
  77. return Blresult;
  78. }
  79. int result = device.Open();
  80. if (result != MvError.MV_OK)
  81. {
  82. Console.WriteLine("Open Device fail!" + result);
  83. return Blresult;
  84. }
  85. // 判断是否为gige设备
  86. if (device is IGigEDevice)
  87. {
  88. // 转换为gigE设备
  89. IGigEDevice gigEDevice = device as IGigEDevice;
  90. // 探测网络最佳包大小(只对GigE相机有效)
  91. int optionPacketSize;
  92. result = gigEDevice.GetOptimalPacketSize(out optionPacketSize);
  93. if (result != MvError.MV_OK)
  94. {
  95. //Log("Warning: Get Packet Size failed!", result);
  96. }
  97. else
  98. {
  99. result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
  100. if (result != MvError.MV_OK)
  101. {
  102. //Log("Warning: Set Packet Size failed!", result);
  103. }
  104. }
  105. }
  106. // 设置采集连续模式
  107. device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
  108. device.Parameters.SetEnumValueByString("TriggerMode", "Off");
  109. Blresult = true;
  110. return Blresult;
  111. }
  112. /// <summary>
  113. /// 开启相机采集
  114. /// </summary>
  115. public void StartCamera()
  116. {
  117. //StartEventGetImage();
  118. StartReceiveFuntion();
  119. //// 开始采集
  120. if (!isGrabbing)
  121. {
  122. isGrabbing = false;
  123. receiveThread.Join();
  124. Console.WriteLine(string.Format("{0}:采集线程开启失败", "CameraClass-StartCamera"));
  125. return;
  126. }
  127. }
  128. /// <summary>
  129. /// 关闭相机采集
  130. /// </summary>
  131. public void StopCamera()
  132. {
  133. StopReceiveFuntion();
  134. StopEventGetImage();
  135. if(device!=null)
  136. {
  137. int result = device.StreamGrabber.StopGrabbing();
  138. device.Close();
  139. device.Dispose();
  140. if (result != MvError.MV_OK)
  141. {
  142. //Log("Stop Grabbing Fail!", result);
  143. }
  144. }
  145. }
  146. /// <summary>
  147. /// 获取第一张缓存中的图像,并把这个图像从缓存中清楚
  148. /// </summary>
  149. /// <param name="ImageData"></param>
  150. public bool GetOnceImage(out IFrameOut ImageData)
  151. {
  152. bool result = false;
  153. //判断是否可以给图像数据赋值
  154. device.StreamGrabber.GetImageBuffer(1000, out ImageData);
  155. if (ImageData != null)
  156. {
  157. result = true;
  158. }
  159. return result;
  160. }
  161. /// <summary>
  162. /// 获取相机图像尺寸信息
  163. /// </summary>
  164. /// <returns></returns>
  165. public CameraImageSizeClass GetCamereImageSize()
  166. {
  167. CameraImageSizeClass cameraImageSize =new CameraImageSizeClass();
  168. IIntValue PixWidth;
  169. IIntValue PixHeight;
  170. device.Parameters.GetIntValue("Width", out PixWidth);
  171. device.Parameters.GetIntValue("Height", out PixHeight);
  172. cameraImageSize.Height = (int)PixHeight.CurValue;
  173. cameraImageSize.Width = (int)PixWidth.CurValue;
  174. return cameraImageSize;
  175. }
  176. /// <summary>
  177. /// 开启事件获取图像
  178. /// </summary>
  179. public void StartEventGetImage()
  180. {
  181. //ch: 设置合适的缓存节点数量 | en: Setting the appropriate number of image nodes
  182. device.StreamGrabber.SetImageNodeNum(50);
  183. // ch:注册回调函数 | en:Register image callback
  184. device.StreamGrabber.FrameGrabedEvent += FrameGrabedEventHandler;
  185. // ch:开启抓图 || en: start grab image
  186. int ret = device.StreamGrabber.StartGrabbing();
  187. if (ret != MvError.MV_OK)
  188. {
  189. Console.WriteLine(string.Format("Start grabbing failed:{0}", ret));
  190. return;
  191. }
  192. }
  193. /// <summary>
  194. /// 停止事件获取图像
  195. /// </summary>
  196. public void StopEventGetImage()
  197. {
  198. if(device==null) return;
  199. int ret = device.StreamGrabber.StopGrabbing();
  200. if (ret != MvError.MV_OK)
  201. {
  202. Console.WriteLine("Stop grabbing failed:{0:x8}", ret);
  203. return;
  204. }
  205. // ch:注册回调函数 | en:Register image callback
  206. device.StreamGrabber.FrameGrabedEvent -= FrameGrabedEventHandler;
  207. }
  208. /// <summary>
  209. /// 获取当前相机的参数生成Config信息
  210. /// </summary>
  211. /// <returns></returns>
  212. public void GetCamValue()
  213. {
  214. device.Parameters.GetFloatValue("ExposureTime", out IFloatValue exposureTime);
  215. device.Parameters.GetIntValue("AcquisitionLineRate", out IIntValue acquisitionLineRate);
  216. device.Parameters.GetIntValue("OffsetX", out IIntValue offsetX);
  217. device.Parameters.GetIntValue("Height", out IIntValue pixHeight);
  218. device.Parameters.GetIntValue("Width", out IIntValue pixWidth);
  219. Console.WriteLine(pixHeight.Min);
  220. device.Parameters.GetStringValue("DeviceUserID", out IStringValue deviceUserID);
  221. device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
  222. device.Parameters.GetStringValue("DeviceSerialNumber", out IStringValue deviceSerialNumber);
  223. }
  224. #endregion
  225. #region 私有方法
  226. /// <summary>
  227. /// 采集线程
  228. /// </summary>
  229. private void ReceiveThreadProcess()
  230. {
  231. IFrameOut frameOut;
  232. Queue<byte[]> frameDatas;
  233. byte[] data = null;
  234. while (isGrabbing)
  235. {
  236. //bool BRet = FrameOuts.TryDequeue(out frameOut);
  237. bool BRet = GetOnceImage(out frameOut);
  238. if (frameOut!=null && frameOut.Image != null)
  239. {
  240. frameDatas = GetImageRowsData(frameOut.Image);
  241. if (lastframeNum == -1)
  242. {
  243. lastframeNum = frameOut.FrameNum;
  244. }
  245. else if (lastframeNum == frameOut.FrameNum - 1)
  246. {
  247. lastframeNum = frameOut.FrameNum;
  248. }
  249. else
  250. {
  251. //丢帧记录
  252. Console.WriteLine(string.Format("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
  253. frameOut.Image.Width, frameOut.Image.Height, frameOut.FrameNum - 1, lastframeNum), 5);
  254. lastframeNum = frameOut.FrameNum;
  255. }
  256. Console.WriteLine("FrameNum[{0}]", frameOut.FrameNum);
  257. frameOut.Dispose();
  258. }
  259. }
  260. }
  261. /// <summary>
  262. /// 开启采集
  263. /// </summary>
  264. private void StartReceiveFuntion()
  265. {
  266. try
  267. {
  268. device.StreamGrabber.StartGrabbing();
  269. // 标志位置位true
  270. isGrabbing = true;
  271. // 开启线程
  272. receiveThread = new Thread(ReceiveThreadProcess);
  273. receiveThread.Start();
  274. }
  275. catch (Exception ex)
  276. {
  277. Console.WriteLine("Start thread failed!, " + ex.Message);
  278. throw;
  279. }
  280. }
  281. /// <summary>
  282. /// 关闭采集线程
  283. /// </summary>
  284. private void StopReceiveFuntion()
  285. {
  286. try
  287. {
  288. // 标志位设为false
  289. isGrabbing = false;
  290. if(receiveThread != null&&receiveThread.IsAlive)
  291. receiveThread.Join();
  292. }
  293. catch (Exception ex)
  294. {
  295. Console.WriteLine("Start thread failed!, " + ex.Message);
  296. throw;
  297. }
  298. }
  299. /// <summary>
  300. /// 读取图像像素信息(单行)
  301. /// </summary>
  302. /// <param name="frameOut">帧数据</param>
  303. /// <returns></returns>
  304. private byte[] GetImageFristRowsData(IFrameOut frameOut)
  305. {
  306. //创建
  307. byte[] PixelData = new byte[(int)frameOut.Image.Width];
  308. //从相机缓存中拷贝出图像数据
  309. Marshal.Copy(frameOut.Image.PixelDataPtr, PixelData, 0, (int)frameOut.Image.Width);
  310. return PixelData;
  311. }
  312. /// <summary>
  313. /// 读取图像像素信息(多行)
  314. /// </summary>
  315. /// <param name="frameOut"></param>
  316. /// <returns></returns>
  317. private Queue<byte[]> GetImageRowsData(IImage frameOut)
  318. {
  319. //创建
  320. Queue<byte[]> PixelDatas = new Queue<byte[]>();
  321. for (int i = 0;i< OnImageSelectRows;i++)
  322. {
  323. byte[] PixelData = new byte[frameOut.Width];
  324. Marshal.Copy(IntPtr.Add(frameOut.PixelDataPtr,i * (int)frameOut.Width), PixelData, 0, (int)frameOut.Width);
  325. PixelDatas.Enqueue(PixelData.Clone() as byte[]);
  326. PixelData = null;
  327. }
  328. return PixelDatas;
  329. }
  330. /// <summary>
  331. /// 帧获取回调事件
  332. /// </summary>
  333. /// <param name="sender"></param>
  334. /// <param name="e"></param>
  335. private void FrameGrabedEventHandler(object sender, FrameGrabbedEventArgs e)
  336. {
  337. if (lastframeNum == -1)
  338. {
  339. lastframeNum = e.FrameOut.FrameNum;
  340. }
  341. else if (lastframeNum == e.FrameOut.FrameNum - 1)
  342. {
  343. lastframeNum = e.FrameOut.FrameNum;
  344. }
  345. else
  346. {
  347. //丢帧记录
  348. Console.WriteLine(string.Format("lost frame: Width[{0}] , Height[{1}] , FrameNum[{2}] ,Frevous[{3}]",
  349. e.FrameOut.Image.Width, e.FrameOut.Image.Height, e.FrameOut.FrameNum - 1, lastframeNum), 5);
  350. lastframeNum = e.FrameOut.FrameNum;
  351. }
  352. ImageMessageClass imageMessage = new ImageMessageClass()
  353. {
  354. ImageData = e.FrameOut.Image.Clone() as IImage,
  355. FrameNo = (int)e.FrameOut.FrameNum
  356. };
  357. FrameOuts.Enqueue(imageMessage);
  358. }
  359. #endregion
  360. }
  361. public class CameraInfoClass
  362. {
  363. public string DeviceName { get; set; }
  364. public string DeviceSN { get; set; }
  365. }
  366. public class CameraImageSizeClass
  367. {
  368. public int Width { get; set; }
  369. public int Height { get; set; }
  370. }
  371. public class ImageMessageClass
  372. {
  373. public IImage ImageData { get; set; }
  374. public int FrameNo { get; set; }
  375. }
  376. }