BaslerCamera.cs 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. using System.Runtime.CompilerServices;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using TeamAAS_VP.Enums;
  11. using TeamAAS_VP.Interfaces;
  12. using Cognex.VisionPro;
  13. using Basler.Pylon;
  14. using System.IO;
  15. using System.Drawing.Imaging;
  16. using System.Drawing;
  17. using System.Diagnostics;
  18. using ControlzEx.Standard;
  19. using System.Windows.Media.Media3D;
  20. using MvCamCtrl.NET;
  21. using TeamAAS_VP.Models;
  22. using Microsoft.Win32;
  23. //using System.Drawing;
  24. //using System.Drawing.Imaging;
  25. namespace TeamAAS_VP.Core.Cameras
  26. {
  27. public class BaslerCamera : Interfaces.ICamera, INotifyPropertyChanged
  28. {
  29. #region 字段
  30. private Basler.Pylon.Camera m_MyCamera;
  31. private Thread m_hReceiveThread;
  32. UInt32 m_nRowStep = 0;
  33. // The pixel data converter is used for converting grabbed images to a pixel format that can be displayed.
  34. private PixelDataConverter converter = new PixelDataConverter();
  35. #endregion
  36. #region 属性
  37. public CameraBrand CameraBrand { get => CameraBrand.Basler_Pylon; }
  38. public string Name { get; private set; }
  39. public Guid ID { get; private set; }
  40. public int Index { get; set; }
  41. public string ManufacturerName { get; private set; }
  42. public bool IsFindByIp { get; private set; }
  43. public string ModelName { get; private set; }
  44. public string SerialNumber { get; private set; }
  45. public string CameraIp { get; private set; }
  46. public CameraType CameraType { get; private set; }
  47. public UInt32 ImageWidth { get; private set; }
  48. public UInt32 ImageHeight { get; private set; }
  49. private bool _IsGrabbing;
  50. /// <summary>
  51. /// 正在采集
  52. /// </summary>
  53. public bool IsGrabbing
  54. {
  55. get { return _IsGrabbing; }
  56. private set { SetProperty(ref _IsGrabbing, value); }
  57. }
  58. private ICogImage _Image;
  59. public ICogImage Image
  60. {
  61. get { return _Image; }
  62. private set { SetProperty(ref _Image, value); }
  63. }
  64. public bool IsConnected { get; private set; }
  65. public ICameraInfo CameraInfo { get; private set; }
  66. /// <summary>
  67. /// 采集用时
  68. /// </summary>
  69. public TimeSpan TotalTime { get; private set; }
  70. /// <summary>
  71. /// 错误信息
  72. /// </summary>
  73. public string ErrorMessage { get; private set; }
  74. #endregion
  75. #region 事件
  76. public event Action<ICogImage, TimeSpan, string> ImageCallbackEvent;
  77. public event Action<Guid, bool> CameraConnectChangedEvent;
  78. #endregion
  79. public BaslerCamera(Guid id, int index, string name, string serialNumber, string cameraip, bool isFindByIp)
  80. {
  81. ID = id;
  82. Name = serialNumber;
  83. Index = index;
  84. CameraIp = cameraip;
  85. SerialNumber = serialNumber;
  86. IsFindByIp = isFindByIp;
  87. List<Basler.Pylon.ICameraInfo> allCameraInfos = Basler.Pylon.CameraFinder.Enumerate();
  88. foreach (ICameraInfo cameraInfo in allCameraInfos)
  89. {
  90. if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("gige"))
  91. {
  92. if (IsFindByIp)
  93. {
  94. if (cameraInfo[CameraInfoKey.DeviceIpAddress] == CameraIp)
  95. {
  96. CameraInfo = cameraInfo;
  97. m_MyCamera = new Basler.Pylon.Camera(cameraInfo);
  98. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo];
  99. ModelName = cameraInfo[CameraInfoKey.ModelName];
  100. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber];
  101. CameraType = CameraType.GIGE;
  102. m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件
  103. m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开
  104. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  105. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  106. //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  107. break;
  108. }
  109. }
  110. else
  111. {
  112. if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber)
  113. {
  114. CameraInfo = cameraInfo;
  115. m_MyCamera = new Basler.Pylon.Camera(cameraInfo);
  116. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo];
  117. ModelName = cameraInfo[CameraInfoKey.ModelName];
  118. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber];
  119. CameraType = CameraType.GIGE;
  120. CameraIp= cameraInfo[CameraInfoKey.DeviceIpAddress];
  121. m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件
  122. m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开
  123. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  124. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  125. //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  126. break;
  127. }
  128. }
  129. }
  130. else
  131. {
  132. if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber)
  133. {
  134. CameraInfo = cameraInfo;
  135. m_MyCamera = new Basler.Pylon.Camera(cameraInfo);
  136. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo];
  137. ModelName = cameraInfo[CameraInfoKey.ModelName];
  138. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber];
  139. CameraType = CameraType.USB;
  140. m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件
  141. m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开
  142. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  143. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  144. //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  145. break;
  146. }
  147. }
  148. }
  149. IsConnected = false;
  150. }
  151. #region 方法
  152. /// <summary>
  153. /// 获取设备
  154. /// </summary>
  155. /// <returns></returns>
  156. public static CameraInfo[] GetDevices()
  157. {
  158. List<CameraInfo> cameras = new List<CameraInfo>();
  159. try
  160. {
  161. if (!CheckSoftwareInstalled().isInstalled)
  162. {
  163. LogHelper.WriteLogInfo("未安装pylon 7");
  164. return cameras.ToArray();
  165. }
  166. List<Basler.Pylon.ICameraInfo> allCameraInfos = Basler.Pylon.CameraFinder.Enumerate();
  167. int i = 0;
  168. foreach (ICameraInfo cameraInfo in allCameraInfos)
  169. {
  170. if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("gige"))
  171. {
  172. cameras.Add(new Models.CameraInfo()
  173. {
  174. CameraNo = i + 1,
  175. CameraName = cameraInfo[CameraInfoKey.FullName],
  176. CameraBrand = CameraBrand.Basler_Pylon,
  177. CameraType = CameraType.GIGE,
  178. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo],
  179. Model = cameraInfo[CameraInfoKey.ModelName],
  180. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber],
  181. CameraIp = cameraInfo[CameraInfoKey.DeviceIpAddress],
  182. IsFindByIp = true,
  183. });
  184. }
  185. else if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("usb"))
  186. {
  187. cameras.Add(new Models.CameraInfo()
  188. {
  189. CameraNo = i + 1,
  190. CameraName = cameraInfo[CameraInfoKey.FullName],
  191. CameraBrand = CameraBrand.Basler_Pylon,
  192. CameraType = CameraType.USB,
  193. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo],
  194. Model = cameraInfo[CameraInfoKey.ModelName],
  195. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber],
  196. CameraIp = "",
  197. });
  198. }
  199. else if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("link"))
  200. {
  201. cameras.Add(new Models.CameraInfo()
  202. {
  203. CameraNo = i + 1,
  204. CameraName = cameraInfo[CameraInfoKey.FullName],
  205. CameraBrand = CameraBrand.Basler_Pylon,
  206. CameraType = CameraType.Link,
  207. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo],
  208. Model = cameraInfo[CameraInfoKey.ModelName],
  209. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber],
  210. CameraIp = "",
  211. });
  212. }
  213. else
  214. {
  215. cameras.Add(new Models.CameraInfo()
  216. {
  217. CameraNo = i + 1,
  218. CameraName = cameraInfo[CameraInfoKey.FullName],
  219. CameraBrand = CameraBrand.Basler_Pylon,
  220. CameraType = CameraType.Unknown,
  221. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo],
  222. Model = cameraInfo[CameraInfoKey.ModelName],
  223. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber],
  224. CameraIp = "",
  225. });
  226. }
  227. i++;
  228. }
  229. }
  230. catch (Exception ex)
  231. {
  232. LogHelper.WriteLogError("搜索巴斯勒相机列表时出错!", ex);
  233. }
  234. return cameras.ToArray();
  235. }
  236. /// <summary>
  237. /// 检查相机软件是否安装
  238. /// </summary>
  239. /// <returns></returns>
  240. public static (bool isInstalled, string version) CheckSoftwareInstalled()
  241. {
  242. string softwareName = "pylon 7 Camera Software";
  243. string softwareVersion = "7.5.0.15658";
  244. string[] registryPaths = new[]
  245. {
  246. @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
  247. @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
  248. };
  249. foreach (var path in registryPaths)
  250. {
  251. using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path))
  252. {
  253. if (key == null) continue;
  254. foreach (string subKeyName in key.GetSubKeyNames())
  255. {
  256. using (RegistryKey subKey = key.OpenSubKey(subKeyName))
  257. {
  258. string displayName = subKey.GetValue("DisplayName")?.ToString();
  259. if (displayName != null && displayName.Contains(softwareName))
  260. {
  261. string version = subKey.GetValue("DisplayVersion")?.ToString();
  262. Version v1 = new Version(version);
  263. Version v2 = new Version(softwareVersion);
  264. if (v1 >= v2)
  265. {
  266. return (true, version);
  267. }
  268. else
  269. {
  270. return (false, version);
  271. }
  272. }
  273. }
  274. }
  275. }
  276. }
  277. return (false, "");
  278. }
  279. /// <summary>
  280. /// 打开相机
  281. /// </summary>
  282. /// <returns></returns>
  283. /// <exception cref="Exception"></exception>
  284. public bool OpenDevice()
  285. {
  286. if (m_MyCamera == null)
  287. {
  288. List<Basler.Pylon.ICameraInfo> allCameraInfos = Basler.Pylon.CameraFinder.Enumerate();
  289. foreach (ICameraInfo cameraInfo in allCameraInfos)
  290. {
  291. if (cameraInfo[CameraInfoKey.DeviceType].ToLower().Contains("gige"))
  292. {
  293. if (IsFindByIp)
  294. {
  295. if (cameraInfo[CameraInfoKey.DeviceIpAddress] == CameraIp)
  296. {
  297. CameraInfo = cameraInfo;
  298. m_MyCamera = new Basler.Pylon.Camera(cameraInfo);
  299. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo];
  300. ModelName = cameraInfo[CameraInfoKey.ModelName];
  301. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber];
  302. CameraType = CameraType.GIGE;
  303. m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件
  304. m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开
  305. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  306. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  307. //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  308. break;
  309. }
  310. }
  311. else
  312. {
  313. if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber)
  314. {
  315. CameraInfo = cameraInfo;
  316. m_MyCamera = new Basler.Pylon.Camera(cameraInfo);
  317. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo];
  318. ModelName = cameraInfo[CameraInfoKey.ModelName];
  319. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber];
  320. CameraType = CameraType.GIGE;
  321. CameraIp = cameraInfo[CameraInfoKey.DeviceIpAddress];
  322. m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件
  323. m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开
  324. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  325. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  326. //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  327. break;
  328. }
  329. }
  330. }
  331. else
  332. {
  333. if (cameraInfo[CameraInfoKey.SerialNumber] == SerialNumber)
  334. {
  335. CameraInfo = cameraInfo;
  336. m_MyCamera = new Basler.Pylon.Camera(cameraInfo);
  337. ManufacturerName = cameraInfo[CameraInfoKey.ManufacturerInfo];
  338. ModelName = cameraInfo[CameraInfoKey.ModelName];
  339. SerialNumber = cameraInfo[CameraInfoKey.SerialNumber];
  340. CameraType = CameraType.USB;
  341. m_MyCamera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue(true); // 激活相机事件
  342. m_MyCamera.CameraOpened += Configuration.AcquireContinuous; // 软触发打开
  343. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  344. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  345. //m_MyCamera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  346. break;
  347. }
  348. }
  349. }
  350. if (m_MyCamera == null)
  351. {
  352. throw new Exception("没有识别到相机");
  353. }
  354. }
  355. if (!m_MyCamera.IsOpen)
  356. {
  357. m_MyCamera.Open();
  358. m_MyCamera.Parameters[PLCamera.TriggerSource].SetValue(PLCamera.TriggerSource.Software);
  359. m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
  360. m_MyCamera.Parameters[PLCamera.TriggerMode].SetValue(PLCamera.TriggerMode.On);
  361. }
  362. IsConnected = m_MyCamera.IsConnected;
  363. return IsConnected;
  364. }
  365. /// <summary>
  366. /// 打开相机异步
  367. /// </summary>
  368. /// <returns></returns>
  369. public Task<bool> OpenDeviceAsync()
  370. {
  371. return Task.Run(() =>
  372. {
  373. return OpenDevice();
  374. });
  375. }
  376. private void M_MyCamera_CameraClosed(object sender, EventArgs e)
  377. {
  378. CameraConnectChangedEvent?.Invoke(ID, false);
  379. }
  380. private void M_MyCamera_CameraOpened(object sender, EventArgs e)
  381. {
  382. CameraConnectChangedEvent?.Invoke(ID, true);
  383. }
  384. /// <summary>
  385. /// 关闭相机
  386. /// </summary>
  387. public void CloseDevice()
  388. {
  389. if (m_MyCamera != null)
  390. {
  391. if (m_MyCamera.IsOpen)
  392. {
  393. m_MyCamera.Close();
  394. m_MyCamera.CameraOpened -= Configuration.AcquireContinuous; // 软触发打开
  395. m_MyCamera.CameraOpened -= M_MyCamera_CameraOpened;
  396. m_MyCamera.CameraClosed -= M_MyCamera_CameraClosed;
  397. IsConnected = m_MyCamera.IsConnected;
  398. m_MyCamera.Dispose();
  399. }
  400. }
  401. }
  402. /// <summary>
  403. /// 采集图像
  404. /// </summary>
  405. /// <returns></returns>
  406. public ICogImage Grab()
  407. {
  408. Stopwatch sw = Stopwatch.StartNew();
  409. if (m_MyCamera == null)
  410. {
  411. throw new Exception("相机未连接");
  412. }
  413. if (!m_MyCamera.IsOpen)
  414. {
  415. m_MyCamera.Open();
  416. m_MyCamera.Parameters[PLCamera.TriggerSource].SetValue(PLCamera.TriggerSource.Software);
  417. m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
  418. m_MyCamera.Parameters[PLCamera.TriggerMode].SetValue(PLCamera.TriggerMode.On);
  419. }
  420. if (!m_MyCamera.StreamGrabber.IsGrabbing)
  421. {
  422. // Start grabbing.
  423. m_MyCamera.StreamGrabber.Start();
  424. }
  425. bool Succeed = false;
  426. IGrabResult grabResult = null;
  427. for (int i = 0; i < 5; i++)
  428. {
  429. try
  430. {
  431. m_MyCamera.ExecuteSoftwareTrigger();
  432. // Wait for an image and then retrieve it. A timeout of 5000 ms is used.
  433. grabResult = m_MyCamera.StreamGrabber.RetrieveResult(1000, TimeoutHandling.ThrowException);
  434. if (grabResult != null && grabResult.GrabSucceeded)
  435. {
  436. ErrorMessage = "";
  437. Succeed = true;
  438. break;
  439. }
  440. else
  441. {
  442. ErrorMessage = grabResult.ErrorDescription;
  443. }
  444. }
  445. catch (Exception ex)
  446. {
  447. ErrorMessage = ex.Message;
  448. m_MyCamera.Close();
  449. m_MyCamera.CameraOpened -= M_MyCamera_CameraOpened;
  450. m_MyCamera.CameraClosed -= M_MyCamera_CameraClosed;
  451. m_MyCamera.Open();
  452. m_MyCamera.Parameters[PLCamera.TriggerSource].SetValue(PLCamera.TriggerSource.Software);
  453. m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
  454. m_MyCamera.Parameters[PLCamera.TriggerMode].SetValue(PLCamera.TriggerMode.On);
  455. IsConnected = m_MyCamera.IsConnected;
  456. }
  457. finally
  458. {
  459. //m_MyCamera.StreamGrabber.Stop();
  460. }
  461. }
  462. if (!Succeed)
  463. {
  464. if (IsConnected)
  465. {
  466. IsConnected = false;
  467. CameraConnectChangedEvent?.Invoke(ID, false);
  468. }
  469. return null;
  470. }
  471. //m_MyCamera.StreamGrabber.Stop();
  472. Image = GrabResult2CogImage(grabResult);
  473. GC.Collect();
  474. grabResult.Dispose();
  475. TotalTime = sw.Elapsed;
  476. return Image;
  477. }
  478. private void InvertColors(IGrabResult result)
  479. {
  480. byte pixelSize = 255;
  481. byte[] data = (byte[])result.PixelData;
  482. for (long i = 0; i < data.Length; i++)
  483. {
  484. data[i] = (byte)((int)pixelSize - (int)data[i]);
  485. }
  486. }
  487. /// <summary>
  488. /// 转换成ICogImage图像
  489. /// </summary>
  490. /// <param name="nHeight"></param>
  491. /// <param name="nWidth"></param>
  492. /// <param name="pImageBuf"></param>
  493. /// <param name="enPixelType"></param>
  494. /// <returns></returns>
  495. public ICogImage ConvertToICogImage(UInt32 nHeight, UInt32 nWidth, IntPtr pImageBuf, Basler.Pylon.PixelType enPixelType)
  496. {
  497. // ch: 显示 || display
  498. try
  499. {
  500. if (enPixelType == Basler.Pylon.PixelType.Mono8)
  501. {
  502. CogImage8Root cogImage8Root = new CogImage8Root();
  503. cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null);
  504. CogImage8Grey cogImage8Grey = new CogImage8Grey();
  505. cogImage8Grey.SetRoot(cogImage8Root);
  506. return cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight);
  507. }
  508. else
  509. {
  510. CogImage8Root image0 = new CogImage8Root();
  511. IntPtr ptr0 = new IntPtr(pImageBuf.ToInt64());
  512. image0.Initialize((int)nWidth, (int)nHeight, ptr0, (int)nWidth, null);
  513. CogImage8Root image1 = new CogImage8Root();
  514. IntPtr ptr1 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep);
  515. image1.Initialize((int)nWidth, (int)nHeight, ptr1, (int)nWidth, null);
  516. CogImage8Root image2 = new CogImage8Root();
  517. IntPtr ptr2 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep * 2);
  518. image2.Initialize((int)nWidth, (int)nHeight, ptr2, (int)nWidth, null);
  519. CogImage24PlanarColor colorImage = new CogImage24PlanarColor();
  520. colorImage.SetRoots(image0, image1, image2);
  521. return colorImage.ScaleImage((int)nWidth, (int)nHeight);
  522. }
  523. }
  524. catch (System.Exception)
  525. {
  526. return null;
  527. }
  528. }
  529. /// <summary>
  530. /// 开始采集图像
  531. /// </summary>
  532. public void StartGrabbing()
  533. {
  534. if (m_MyCamera == null)
  535. {
  536. throw new Exception("相机未连接");
  537. }
  538. if (!m_MyCamera.IsOpen)
  539. {
  540. throw new Exception("相机未打开");
  541. }
  542. m_MyCamera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
  543. //m_MyCamera.StreamGrabber.Start(GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber);
  544. if (IsGrabbing)
  545. return;
  546. if (!m_MyCamera.StreamGrabber.IsGrabbing)
  547. {
  548. // Start grabbing.
  549. m_MyCamera.StreamGrabber.Start();
  550. }
  551. IsGrabbing = true;
  552. m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true };
  553. m_hReceiveThread.Start();
  554. }
  555. /// <summary>
  556. /// 停止采集图像
  557. /// </summary>
  558. public void StopGrabbing()
  559. {
  560. try
  561. {
  562. //m_MyCamera.StreamGrabber.Stop();
  563. IsGrabbing = false;
  564. Thread.Sleep(1000);
  565. if (m_hReceiveThread != null)
  566. {
  567. m_hReceiveThread.Abort();
  568. m_hReceiveThread = null;
  569. }
  570. if (m_MyCamera != null && m_MyCamera.StreamGrabber.IsGrabbing)
  571. {
  572. m_MyCamera.StreamGrabber.Stop();
  573. }
  574. }
  575. catch (Exception)
  576. {
  577. }
  578. }
  579. /// <summary>
  580. /// 设置曝光时间
  581. /// </summary>
  582. /// <param name="ExposureTime"></param>
  583. /// <returns></returns>
  584. public bool SetExposureTime(float ExposureTime)
  585. {
  586. if (m_MyCamera == null)
  587. {
  588. return false;
  589. }
  590. if (m_MyCamera.Parameters.Contains(PLCamera.ExposureTimeAbs))
  591. {
  592. m_MyCamera.Parameters[PLCamera.ExposureTimeAbs].SetValue(ExposureTime);
  593. }
  594. else
  595. m_MyCamera.Parameters[PLCamera.ExposureTime].SetValue(ExposureTime);
  596. return true;
  597. }
  598. /// <summary>
  599. /// 获取曝光时间
  600. /// </summary>
  601. /// <returns></returns>
  602. public float GetExposureTime()
  603. {
  604. if (m_MyCamera == null)
  605. {
  606. return 0;
  607. }
  608. if (m_MyCamera.Parameters.Contains(PLCamera.ExposureTimeAbs))
  609. {
  610. return (float)m_MyCamera.Parameters[PLCamera.ExposureTimeAbs].GetValue();
  611. }
  612. else
  613. return (float)m_MyCamera.Parameters[PLCamera.ExposureTime].GetValue();
  614. }
  615. /// <summary>
  616. /// 设置增益
  617. /// </summary>
  618. /// <param name="Gain"></param>
  619. /// <returns></returns>
  620. public bool SetGain(float Gain)
  621. {
  622. if (m_MyCamera == null)
  623. {
  624. return false;
  625. }
  626. if (m_MyCamera.Parameters.Contains(PLCamera.Gain))
  627. {
  628. m_MyCamera.Parameters[PLCamera.Gain].SetValue(Gain);
  629. }
  630. else if (m_MyCamera.Parameters.Contains(PLCamera.GainRaw))
  631. {
  632. m_MyCamera.Parameters[PLCamera.GainRaw].SetValue((int)Gain);
  633. }
  634. else if (m_MyCamera.Parameters.Contains(PLCamera.GainAbs))
  635. {
  636. m_MyCamera.Parameters[PLCamera.GainAbs].SetValue(Gain);
  637. }
  638. return true;
  639. }
  640. /// <summary>
  641. /// 获取增益
  642. /// </summary>
  643. /// <returns></returns>
  644. public float GetGain()
  645. {
  646. if (m_MyCamera.Parameters.Contains(PLCamera.Gain))
  647. {
  648. return (float)m_MyCamera.Parameters[PLCamera.Gain].GetValue();
  649. }
  650. else
  651. return (float)m_MyCamera.Parameters[PLCamera.GainAbs].GetValue();
  652. }
  653. private void GetStreamThreadProc()
  654. {
  655. while (IsGrabbing)
  656. {
  657. Stopwatch sw = Stopwatch.StartNew();
  658. try
  659. {
  660. if (!m_MyCamera.IsConnected)
  661. {
  662. m_MyCamera.Close();
  663. m_MyCamera.CameraOpened -= M_MyCamera_CameraOpened;
  664. m_MyCamera.CameraClosed -= M_MyCamera_CameraClosed;
  665. m_MyCamera = new Basler.Pylon.Camera(CameraInfo);
  666. m_MyCamera.CameraOpened += M_MyCamera_CameraOpened;
  667. m_MyCamera.CameraClosed += M_MyCamera_CameraClosed;
  668. }
  669. if (!m_MyCamera.IsOpen)
  670. {
  671. m_MyCamera.Open();
  672. IsConnected = m_MyCamera.IsConnected;
  673. }
  674. m_MyCamera.ExecuteSoftwareTrigger();
  675. // Wait for an image and then retrieve it. A timeout of 5000 ms is used.
  676. IGrabResult grabResult = m_MyCamera.StreamGrabber.RetrieveResult(1000, TimeoutHandling.ThrowException);
  677. using (grabResult)
  678. {
  679. // Image grabbed successfully?
  680. if (grabResult != null && grabResult.GrabSucceeded)
  681. {
  682. ErrorMessage = "";
  683. Image = GrabResult2CogImage(grabResult);
  684. TotalTime = sw.Elapsed;
  685. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
  686. }
  687. else
  688. {
  689. TotalTime = sw.Elapsed;
  690. ErrorMessage = grabResult.ErrorDescription;
  691. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
  692. }
  693. }
  694. }
  695. catch (Exception ex)
  696. {
  697. TotalTime = sw.Elapsed;
  698. ImageCallbackEvent?.Invoke(Image, TotalTime, ex.Message);
  699. }
  700. Thread.Sleep(10);
  701. GC.Collect();
  702. }
  703. IsGrabbing = false;
  704. }
  705. /// <summary>
  706. /// 图像是否为彩色
  707. /// </summary>
  708. /// <param name="enType"></param>
  709. /// <returns></returns>
  710. private bool IsColorPixelFormat(Basler.Pylon.PixelType enType)
  711. {
  712. switch (enType)
  713. {
  714. case Basler.Pylon.PixelType.RGB8packed:
  715. case Basler.Pylon.PixelType.BGR8packed:
  716. case Basler.Pylon.PixelType.RGBA8packed:
  717. case Basler.Pylon.PixelType.BGRA8packed:
  718. case Basler.Pylon.PixelType.YUV422packed:
  719. case Basler.Pylon.PixelType.YUV422_YUYV_Packed:
  720. case Basler.Pylon.PixelType.BayerGR8:
  721. case Basler.Pylon.PixelType.BayerRG8:
  722. case Basler.Pylon.PixelType.BayerGB8:
  723. case Basler.Pylon.PixelType.BayerBG8:
  724. case Basler.Pylon.PixelType.BayerGB10:
  725. case Basler.Pylon.PixelType.BayerGB10pp:
  726. case Basler.Pylon.PixelType.BayerBG10:
  727. case Basler.Pylon.PixelType.BayerBG10pp:
  728. case Basler.Pylon.PixelType.BayerRG10:
  729. case Basler.Pylon.PixelType.BayerRG10pp:
  730. case Basler.Pylon.PixelType.BayerGR10:
  731. case Basler.Pylon.PixelType.BayerGR10pp:
  732. case Basler.Pylon.PixelType.BayerGB12:
  733. case Basler.Pylon.PixelType.BayerGB12p:
  734. case Basler.Pylon.PixelType.BayerBG12:
  735. case Basler.Pylon.PixelType.BayerBG12Packed:
  736. case Basler.Pylon.PixelType.BayerRG12:
  737. case Basler.Pylon.PixelType.BayerRG12Packed:
  738. case Basler.Pylon.PixelType.BayerGR12:
  739. case Basler.Pylon.PixelType.BayerGR12Packed:
  740. return true;
  741. default:
  742. return false;
  743. }
  744. }
  745. /// <summary>
  746. /// 图像是否为Mono格式
  747. /// </summary>
  748. /// <param name="enType"></param>
  749. /// <returns></returns>
  750. private bool IsMonoPixelFormat(Basler.Pylon.PixelType enType)
  751. {
  752. switch (enType)
  753. {
  754. case Basler.Pylon.PixelType.Mono8:
  755. case Basler.Pylon.PixelType.Mono10:
  756. case Basler.Pylon.PixelType.Mono10packed:
  757. case Basler.Pylon.PixelType.Mono12:
  758. case Basler.Pylon.PixelType.Mono12packed:
  759. return true;
  760. default:
  761. return false;
  762. }
  763. }
  764. /// <summary>
  765. /// 将从相机获取的图像IGrabResult转换为CogImage图像
  766. /// <paramref name="grabResult"/> 从相机获取的图像 IGrabResult </param>
  767. /// </summary>
  768. private ICogImage GrabResult2CogImage(IGrabResult grabResult)
  769. {
  770. if (grabResult == null) return null;
  771. byte[] pixelData = grabResult.PixelData as byte[];
  772. GCHandle pixelHandle = default;
  773. bool pixelPinned = false;
  774. GCHandle dstHandle = default;
  775. bool dstPinned = false;
  776. ICogImage result = null;
  777. try
  778. {
  779. // 尽量 pin 原始像素数据(如果存在)
  780. if (pixelData != null && pixelData.Length > 0)
  781. {
  782. pixelHandle = GCHandle.Alloc(pixelData, GCHandleType.Pinned);
  783. pixelPinned = true;
  784. }
  785. IntPtr pixelPointer = pixelPinned ? pixelHandle.AddrOfPinnedObject() : IntPtr.Zero;
  786. // 彩色图像处理
  787. if (IsColorPixelFormat(grabResult.PixelTypeValue))
  788. {
  789. // 使用 using 确保 Bitmap 及时释放
  790. using (Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb))
  791. {
  792. BitmapData bmpData = null;
  793. try
  794. {
  795. bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
  796. // 使用成员 converter 将 grabResult 转换到 bitmap 的缓冲区
  797. converter.OutputPixelFormat = PixelType.BGRA8packed;
  798. IntPtr ptrBmp = bmpData.Scan0;
  799. converter.Convert(ptrBmp, Math.Abs(bmpData.Stride) * bitmap.Height, grabResult);
  800. }
  801. finally
  802. {
  803. if (bmpData != null)
  804. {
  805. try { bitmap.UnlockBits(bmpData); } catch { }
  806. }
  807. }
  808. // 构造 Cognex 图像并返回副本(ScaleImage 通常返回独立图像)
  809. CogImage24PlanarColor colorImage = null;
  810. try
  811. {
  812. colorImage = new CogImage24PlanarColor(bitmap);
  813. result = colorImage.ScaleImage(bitmap.Width, bitmap.Height);
  814. }
  815. finally
  816. {
  817. // colorImage 若实现了 IDisposable 则释放(安全检查)
  818. (colorImage as IDisposable)?.Dispose();
  819. }
  820. }
  821. return result;
  822. }
  823. // 单通道(Mono)图像处理
  824. else if (IsMonoPixelFormat(grabResult.PixelTypeValue))
  825. {
  826. Basler.Pylon.PixelType enDstPixelType = Basler.Pylon.PixelType.Mono8;
  827. uint nSaveImageNeedSize = (uint)grabResult.Width * (uint)grabResult.Height;
  828. IntPtr pTemp = IntPtr.Zero;
  829. if (grabResult.PixelTypeValue == Basler.Pylon.PixelType.Mono8)
  830. {
  831. // 直接使用已 pin 的原始数据指针
  832. if (!pixelPinned)
  833. {
  834. // 如果原始不是 byte[],尝试从 grabResult 获取 PixelData(若支持)
  835. byte[] alt = grabResult.PixelData as byte[];
  836. if (alt != null)
  837. {
  838. pixelHandle = GCHandle.Alloc(alt, GCHandleType.Pinned);
  839. pixelPinned = true;
  840. pixelPointer = pixelHandle.AddrOfPinnedObject();
  841. }
  842. }
  843. pTemp = pixelPointer;
  844. }
  845. else
  846. {
  847. // 为转换后的 Mono8 数据分配临时缓冲并 pin
  848. byte[] dstBuffer = new byte[nSaveImageNeedSize];
  849. dstHandle = GCHandle.Alloc(dstBuffer, GCHandleType.Pinned);
  850. dstPinned = true;
  851. pTemp = dstHandle.AddrOfPinnedObject();
  852. // 使用局部的 PixelDataConverter 转换为 Mono8
  853. var pixelConverter = new Basler.Pylon.PixelDataConverter();
  854. pixelConverter.OutputPixelFormat = Basler.Pylon.PixelType.Mono8;
  855. pixelConverter.Convert(pTemp, nSaveImageNeedSize, grabResult);
  856. }
  857. if (pTemp == IntPtr.Zero)
  858. {
  859. return null;
  860. }
  861. // ConvertToICogImage 内部会做 ScaleImage,通常会产生独立拷贝
  862. result = ConvertToICogImage((uint)grabResult.Height, (uint)grabResult.Width, pTemp, enDstPixelType);
  863. return result;
  864. }
  865. return null;
  866. }
  867. finally
  868. {
  869. // 释放所有固定句柄,确保及时释放 pin 状态
  870. try
  871. {
  872. if (dstPinned)
  873. {
  874. dstHandle.Free();
  875. dstPinned = false;
  876. }
  877. }
  878. catch { }
  879. try
  880. {
  881. if (pixelPinned)
  882. {
  883. pixelHandle.Free();
  884. pixelPinned = false;
  885. }
  886. }
  887. catch { }
  888. }
  889. }
  890. #endregion
  891. #region 属性通知
  892. /// <summary>
  893. /// Occurs when a property value changes.
  894. /// </summary>
  895. public event PropertyChangedEventHandler PropertyChanged;
  896. /// <summary>
  897. /// Checks if a property already matches a desired value. Sets the property and
  898. /// notifies listeners only when necessary.
  899. /// </summary>
  900. /// <typeparam name="T">Type of the property.</typeparam>
  901. /// <param name="storage">Reference to a property with both getter and setter.</param>
  902. /// <param name="value">Desired value for the property.</param>
  903. /// <param name="propertyName">Name of the property used to notify listeners. This
  904. /// value is optional and can be provided automatically when invoked from compilers that
  905. /// support CallerMemberName.</param>
  906. /// <returns>True if the value was changed, false if the existing value matched the
  907. /// desired value.</returns>
  908. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
  909. {
  910. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  911. storage = value;
  912. RaisePropertyChanged(propertyName);
  913. return true;
  914. }
  915. /// <summary>
  916. /// Checks if a property already matches a desired value. Sets the property and
  917. /// notifies listeners only when necessary.
  918. /// </summary>
  919. /// <typeparam name="T">Type of the property.</typeparam>
  920. /// <param name="storage">Reference to a property with both getter and setter.</param>
  921. /// <param name="value">Desired value for the property.</param>
  922. /// <param name="propertyName">Name of the property used to notify listeners. This
  923. /// value is optional and can be provided automatically when invoked from compilers that
  924. /// support CallerMemberName.</param>
  925. /// <param name="onChanged">Action that is called after the property value has been changed.</param>
  926. /// <returns>True if the value was changed, false if the existing value matched the
  927. /// desired value.</returns>
  928. protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
  929. {
  930. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  931. storage = value;
  932. onChanged?.Invoke();
  933. RaisePropertyChanged(propertyName);
  934. return true;
  935. }
  936. /// <summary>
  937. /// Raises this object's PropertyChanged event.
  938. /// </summary>
  939. /// <param name="propertyName">Name of the property used to notify listeners. This
  940. /// value is optional and can be provided automatically when invoked from compilers
  941. /// that support <see cref="CallerMemberNameAttribute"/>.</param>
  942. protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  943. {
  944. OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  945. }
  946. /// <summary>
  947. /// Raises this object's PropertyChanged event.
  948. /// </summary>
  949. /// <param name="args">The PropertyChangedEventArgs</param>
  950. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
  951. {
  952. PropertyChanged?.Invoke(this, args);
  953. }
  954. #endregion
  955. }
  956. }