BaslerCamera.cs 45 KB

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